Skip to content

Conversation

@ranapratap55
Copy link
Collaborator

Motivation

https://github.com/NVIDIA/cuda-samples/blob/master/Samples/5_Domain_Specific/dxtc/dxtc.cu

The dxtc.cu cuda-samples includes multiple local headers (CudaMath.h, dds.h, permutations.h) that depend on helper_math.h for float3 operator definitions. Without header injection, these headers fail with standalone hipify-clang because they lack the required operator overloads.

Purpose

Enhances the existing --local-headers and --local-headers-recursive options with header injection fallback mechanism. When direct hipification of a local header fails due to missing type definitions or operator overloads, the header injection method automatically injects preceding system includes from the main source file.

Problem Statement

The initial local header hipification works well for self-contained headers that include all their dependencies. However, many cuda-samples have headers that depend on types and operators defined in preceding includes from the main source file. For example, CudaMath.h in cuda-samples/Samples/5_Domain_Specific/dxtc/ uses float3 operators (+=, *, -) that are defined in helper_math.h, which is included in the dxtc.cu. Few more below
bodysystemcpu_impl.h
MonteCarlo_reduction.cuh
fastWalshTransform_kernel.cuh
bicubicTexture_kernel.cuh

Solution

Implements a hybrid approach:
Existing: First attempts direct hipification, Works for self-contained headers.
Enhanced version: Header Injection, when direct method fails, it collects preceding system header files (#include <...>) from the main source and includes them.

Usage

No change to CLI flags
Non-recursive: hipify-clang --local-headers main.cu -I include/
Recursive: hipify-clang --local-headers-recursive main.cu -I include/

@ranapratap55 ranapratap55 self-assigned this Jan 8, 2026
@ranapratap55 ranapratap55 added fix It fixes bug feature Feature request or implementation labels Jan 8, 2026
@ranapratap55 ranapratap55 changed the title [HIPIFY] Add header injection fallback for local headers hipification [HIPIFY][feature] Add header injection fallback for local headers hipification Jan 8, 2026
@emankov emankov requested review from SyamaAmd and kzhuravl January 8, 2026 18:24
@emankov
Copy link
Collaborator

emankov commented Jan 13, 2026

Cases like CudaMath.h are a different story, as those header files are not self-contained and are not intended to be compiled as separate compilation units. The compilation unit here designed to be compiled is dxtc.cu, which is being correctly compiled by clang.

FMPOV, the problem with missing header files is broader. The root cause is that nvcc automatically pre-includes some CUDA header files at the beginning of ANY compilation unit (not only header files, but also .cu files). They are at least (but probably are not all):

  • cuda_runtime.h (The top-level injection)
  • crt/host_config.h (System check)
  • builtin_types.h (Basic types)
  • device_types.h (enums and structs)
  • host_defines.h (Macro definitions)

And not all of them necessarily need to be included during our hipification process.

Such nvcc behaviour is a design choice by NVIDIA to make writing CUDA device and host code less verbose. It effectively treats CUDA as part of the language environment rather than just an external library, whereas clang reasonably decides that CUDA is a C++ language extension.

nvcc knows which header files are needed for implicit inclusion, and clang doesn't.

So the question is: how should we determine whether to include this or that CUDA header file from the most likely incomplete list above?

@ranapratap55
Copy link
Collaborator Author

ranapratap55 commented Jan 14, 2026

Cases like CudaMath.h are a different story, as those header files are not self-contained and are not intended to be compiled as separate compilation units. The compilation unit here designed to be compiled is dxtc.cu, which is being correctly compiled by clang.

FMPOV, the problem with missing header files is broader. The root cause is that nvcc automatically pre-includes some CUDA header files at the beginning of ANY compilation unit (not only header files, but also .cu files). They are at least (but probably are not all):

yes, you are correct. nvcc pre-includes the CUDA headers and headers like CudaMath.h is not designed to be a standalone compilation. But when users are trying to port using --local-header their project, many real world headers fail because they lack/depend on the main source file context.

I believe we should support users even when their headers have implicit header dependencies (not only properly designed headers).

how should we determine whether to include this or that CUDA header file from the most likely incomplete list above?

This approach avoids this problem because

  • It includes ONLY that are already in main source file
  • Injects only PRECEDING system include files up to the local header's inclusion point
  • Relies on what original developer determined necessary for their specific project

whatever includes the main .cu/cpp file had before including this header - those are what the header needs
for e.g.,

#include<header_1.h>
#include "sample.h"

here we include only header_1.h file for "sample.h". We don't need to know why it is needed just it comes before in main source file.

This feature is a FALLBACK mechanism, not the primary/direct path. Here

  • Direct hipification is tried first (for self-contained headers)
  • Header injection (this approach) only kicks in when direct fails.

I believe this approach works for any project (cuda-samples, etc.,) as we are only injecting original determined headers for that specific project.

@emankov
Copy link
Collaborator

emankov commented Jan 14, 2026

This approach avoids this problem because

Nope. The proposed approach avoids the problems in CUDA samples, where additional header files such as helper_math.h are provided. And it's they who are giving the opportunity to compile the main CU files with other compilers besides nvcc.

The wider problem is that the necessary header file might not be provided at all. And this is the common practice in CUDA, as I tried to explain above.

I believe this approach works for any project (cuda-samples, etc.,) as we are only injecting original determined headers for that specific project.

Can't agree here; the approach won't work for projects that don't provide header files at all.

@ranapratap55
Copy link
Collaborator Author

This approach avoids this problem because

Nope. The proposed approach avoids the problems in CUDA samples, where additional header files such as helper_math.h are provided. And it's they who are giving the opportunity to compile the main CU files with other compilers besides nvcc.

The wider problem is that the necessary header file might not be provided at all. And this is the common practice in CUDA, as I tried to explain above.

I believe this approach works for any project (cuda-samples, etc.,) as we are only injecting original determined headers for that specific project.

Can't agree here; the approach won't work for projects that don't provide header files at all.

You are right. I appreciate you clarifying the distinction.
My approach solves projects like cuda-samples where explicit system includes are provided in the main source file and well-structured projects that follow C++ practices.

This approach does not solve the projects that rely entirely on nvcc's implicit pre-inclusion with no explicit system includes.

I agree this is a limitation. I would like to take this feature as incremental improvement, with understanding that

  • it helps the projects with explicit includes (cuda-samples, etc.)
  • It doesn't help projects relying purely on nvcc's implicit behavior
  • Future work could address the "no includes" case separately

I'm open to take a different approach that you'd suggest.

@emankov
Copy link
Collaborator

emankov commented Jan 21, 2026

On Windows:

`error C2589: '(': illegal token on right side of '::'`:

while compiling LocalHeader.cpp

A possible reason is a Conflict: min/max Macros vs. std::min/std::max

@emankov
Copy link
Collaborator

emankov commented Jan 21, 2026

HeaderInjection.cpp:

  1. Hybrid Approach fragility.
    The code uses a hybrid approach: it creates temporary files on disk to inject headers, then runs the tool on them. This is inefficient (disk IO) and brittle compared to using Clang's VirtualFileSystem to overlay changes in memory.

  2. The use of std::regex to find #include directives and include guards is highly error-prone. It ignores the complexity of the C++ preprocessor (comments, inactive #ifdef blocks, macros). This should be done using Clang's PPCallbacks.

@emankov
Copy link
Collaborator

emankov commented Jan 21, 2026

StderrCapture.h:

  1. Thread Safety: Capturing global stderr by manipulating file descriptors _dup2 is not thread-safe. If the tool is ever parallelized, this will break.

#include "llvm/Support/raw_ostream.h"

using namespace llvm;
using namespace std;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the using namespace is declared, the corresponding namespace prefixes are surplus (below in this and other PR files).

@@ -0,0 +1,163 @@
/*
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain the reason(s) for having this Std Err Capture.

@emankov
Copy link
Collaborator

emankov commented Jan 23, 2026

I'm open to take a different approach that you'd suggest.

I want us to think a bit broader here and come to a solution, partially based on your PR.

What if we implicitly include the "short list" of already-known "hidden" CUDA headers during the hipification of each source CUDA file, as the first step?

  • cuda_runtime.h (The top-level injection)
  • crt/host_config.h (System check)
  • builtin_types.h (Basic types)
  • device_types.h (enums and structs)
  • host_defines.h (Macro definitions)

Will we get some issues in that scenario, performance penalties, etc.?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature Feature request or implementation fix It fixes bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants