ROCm/HIP headers break the GNU `__noinline__` attribute

Issue #550 resolved
Dan Bonachea created an issue

ROCm/HIP headers break the GNU __noinline__ attribute, which is used by the UPC++ headers when support was detected in the underlying compiler (which includes most relevant C++ compilers, including the clang compiler backing hipcc). When the ROCm hipcc compiler processes the HIP headers, the problem leads to a fatal compiler error. This is visible in the following example:

spock$ cat hello_upcxx.cpp 
#include <hip/hip_runtime_api.h>
#include <upcxx/upcxx.hpp>

int main() {
  upcxx::init();

  upcxx::finalize();
  return 0;
}

spock$ hipcc `upcxx-meta CXXFLAGS` `upcxx-meta CPPFLAGS` -c hello_upcxx.cpp
In file included from hello_upcxx.cpp:2:
In file included from /gpfs/alpine/world-shared/csc296/spock/upcxx-hip-native/2022.3.0/amd/PrgEnv-amd-8.2.0-4.5.0/include/upcxx/upcxx.hpp:5:
In file included from /gpfs/alpine/world-shared/csc296/spock/upcxx-hip-native/2022.3.0/amd/PrgEnv-amd-8.2.0-4.5.0/include/upcxx/allocate.hpp:8:
In file included from /gpfs/alpine/world-shared/csc296/spock/upcxx-hip-native/2022.3.0/amd/PrgEnv-amd-8.2.0-4.5.0/include/upcxx/backend.hpp:5:
In file included from /gpfs/alpine/world-shared/csc296/spock/upcxx-hip-native/2022.3.0/amd/PrgEnv-amd-8.2.0-4.5.0/include/upcxx/future.hpp:4:
In file included from /gpfs/alpine/world-shared/csc296/spock/upcxx-hip-native/2022.3.0/amd/PrgEnv-amd-8.2.0-4.5.0/include/upcxx/future/core.hpp:7:
In file included from /gpfs/alpine/world-shared/csc296/spock/upcxx-hip-native/2022.3.0/amd/PrgEnv-amd-8.2.0-4.5.0/include/upcxx/lpc.hpp:5:
/gpfs/alpine/world-shared/csc296/spock/upcxx-hip-native/2022.3.0/amd/PrgEnv-amd-8.2.0-4.5.0/include/upcxx/intru_queue.hpp:313:11: error: 
      use of undeclared identifier 'noinline'; did you mean 'inline'?
      int UPCXXI_ATTRIB_NOINLINE
          ^
/gpfs/alpine/world-shared/csc296/spock/upcxx-hip-native/2022.3.0/amd/PrgEnv-amd-8.2.0-4.5.0/upcxx.opt.gasnet_seq.ucx/gen_include/upcxx/upcxx_config.hpp:12:47: note: 
      expanded from macro 'UPCXXI_ATTRIB_NOINLINE'
#define UPCXXI_ATTRIB_NOINLINE __attribute__((__noinline__)) 
                                              ^
/opt/rocm-4.5.0/hip/include/hip/amd_detail/host_defines.h:50:37: note: expanded from macro '__noinline__'
#define __noinline__ __attribute__((noinline))
                                    ^

and in the simpler pure C++ example:

spock$ cat simple.cpp 
#include <hip/hip_runtime_api.h>

void __attribute__((__noinline__)) foo() {}

int main() {
  return 0;
}
spock$ hipcc -c simple.cpp   
simple.cpp:3:21: error: use of undeclared identifier 'noinline'; did you mean 'inline'?
void __attribute__((__noinline__)) foo() {}
                    ^
/opt/rocm-4.5.0/hip/include/hip/amd_detail/host_defines.h:50:37: note: expanded from macro '__noinline__'
#define __noinline__ __attribute__((noinline))
                                    ^
simple.cpp:3:21: error: type name does not allow function specifier to be specified
/opt/rocm-4.5.0/hip/include/hip/amd_detail/host_defines.h:50:37: note: expanded from macro '__noinline__'
#define __noinline__ __attribute__((noinline))
                                    ^
simple.cpp:3:21: error: expected expression
/opt/rocm-4.5.0/hip/include/hip/amd_detail/host_defines.h:50:46: note: expanded from macro '__noinline__'
#define __noinline__ __attribute__((noinline))
                                             ^
3 errors generated when compiling for gfx908.

The problem is a name collision between the GNU __noinline__ attribute name, and the poorly-named CUDA/HIP __noinline__ kernel marker. ROCm has chosen to implement this kernel marker in include/hip/hcc_detail/host_defines.h using a fragile macro definition (which breaks subsequent use of the GNU function attribute) instead deploying of a proper solution to resolve the ambiguity in the parser (as nvcc presumably does). The hack in the ROCm header basically amounts to:

#if defined(__clang__) && defined(__HIP__)
#define __noinline__ __attribute__((noinline))
#else 
#define __noinline__
#endif

which breaks all uses of the __noinline__ GNU attribute in client code, leading to a compile error under hipcc and silent removal of the attribute under other compilers.

This problem has been confirmed to affect all ROCm versions in 4.[1235] and 5.0.[02], all of which use this mostly unchanged fragile preprocessor hack.

Comments (2)

  1. Dan Bonachea reporter

    Potential workaround for UPC++ versions <= 2022.3.0:

    #include <hip/hip_runtime_api.h> // ROCm headers
    
    // workaround issue 550 by disabling __noinline__
    #undef  __noinline__
    #define __noinline__
    
    #include <upcxx/upcxx.hpp> // UPC++ header
    

    However this is probably only useful along with a workaround to related issue 549

    Proposed resolution to both issues in PR 435

  2. Dan Bonachea reporter

    issue 550: ROCm/HIP headers break the GNU __noinline__ attribute

    Workaround the ROCm/HIP header which breaks the GNU __noinline__ function attribute in a way that leads to compile errors with hipcc.

    The workaround is to detect the presence of the header containing the objectionable macro definition and disable our own use of the attribute which the header has corrupted.

    Resolves issue #550

    → <<cset 5045fb008ad3>>

  3. Log in to comment