Skip to content
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
996c2e1
Build DeviceRTL with spirv backend
fineg74 Nov 25, 2025
5e746a8
Merge branch 'main' into l0RTL
fineg74 Dec 7, 2025
3587050
Merge remote-tracking branch 'origin/main' into l0RTL
fineg74 Jan 6, 2026
84def59
Address PR comments
fineg74 Jan 7, 2026
5b6f225
Fix formatting issues
fineg74 Jan 7, 2026
dc78bad
Address PR comments
fineg74 Jan 8, 2026
e98cf56
Fix formatting
fineg74 Jan 9, 2026
40dfa28
Allow build of DeviceRTL for SPIRV backend
fineg74 Jan 9, 2026
2922a82
Fix format
fineg74 Jan 9, 2026
a18c339
Fix formatting
fineg74 Jan 9, 2026
ae099ba
Fix format
fineg74 Jan 9, 2026
db04823
Merge remote-tracking branch 'origin/main' into l0RTL
fineg74 Jan 9, 2026
802a65e
Add TODO comment
fineg74 Jan 9, 2026
f2dbfa2
Fix format
fineg74 Jan 9, 2026
101fccd
Fix test failure
fineg74 Jan 9, 2026
7584cad
Merge remote-tracking branch 'origin/main' into l0RTL
fineg74 Jan 9, 2026
a660034
Reenable attributes after backend fixes
fineg74 Jan 9, 2026
b79e42a
Address PR comments
fineg74 Jan 9, 2026
488209c
Address PR comments
fineg74 Jan 10, 2026
c5ac596
Addressed PR comments
fineg74 Jan 10, 2026
6366e0c
Address PR comments
fineg74 Jan 10, 2026
e090887
Update openmp/device/CMakeLists.txt
fineg74 Jan 10, 2026
d50579f
Merge remote-tracking branch 'origin/main' into l0RTL
fineg74 Jan 19, 2026
7cc3270
Update the branch with support for variadics
fineg74 Jan 19, 2026
af38777
REmove spurious changes
fineg74 Jan 19, 2026
4bd07fd
Applied different work around for a build break
fineg74 Jan 19, 2026
4ad7138
Fix formatting
fineg74 Jan 19, 2026
e66a4e4
Address PR comments
fineg74 Jan 21, 2026
867d96a
Merge remote-tracking branch 'origin/main' into l0RTL
fineg74 Jan 23, 2026
f92b77e
Address PR comments
fineg74 Jan 24, 2026
7e5e695
Fix formatting
fineg74 Jan 24, 2026
bb719be
Use c++ style attributes
fineg74 Jan 24, 2026
b9875fd
Merge remote-tracking branch 'origin/main' into l0RTL
fineg74 Jan 26, 2026
e2cc882
Cleanup based on trunk rebase
fineg74 Jan 26, 2026
5e20646
Fix formatting
fineg74 Jan 27, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions clang/lib/Headers/spirvintrin.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,10 @@ _Pragma("omp begin declare variant match(device = {arch(spirv64)})");
// Attribute to declare a function as a kernel.
#define __gpu_kernel __attribute__((device_kernel, visibility("protected")))

#ifdef __cplusplus
template <typename... Args> int __spirv_ocl_printf(Args...);
#endif

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This doesn't belong here

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This belongs next to the usage

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

// Returns the number of workgroups in the 'x' dimension of the grid.
_DEFAULT_FN_ATTRS static __inline__ uint32_t __gpu_num_blocks_x(void) {
return __builtin_spirv_num_workgroups(0);
Expand Down
4 changes: 2 additions & 2 deletions openmp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ else()
endif()

# Use the current compiler target to determine the appropriate runtime to build.
if("${LLVM_DEFAULT_TARGET_TRIPLE}" MATCHES "^amdgcn|^nvptx" OR
"${CMAKE_CXX_COMPILER_TARGET}" MATCHES "^amdgcn|^nvptx")
if("${LLVM_DEFAULT_TARGET_TRIPLE}" MATCHES "^amdgcn|^nvptx|^spirv64" OR
"${CMAKE_CXX_COMPILER_TARGET}" MATCHES "^amdgcn|^nvptx|^spirv64")
add_subdirectory(device)
else()
add_subdirectory(module)
Expand Down
23 changes: 19 additions & 4 deletions openmp/device/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,18 @@ set(src_files
${CMAKE_CURRENT_SOURCE_DIR}/src/Workshare.cpp
)

list(APPEND compile_options -flto)
if(NOT "${LLVM_DEFAULT_TARGET_TRIPLE}" MATCHES "^spirv" AND
NOT "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "^spirv")
list(APPEND compile_options -flto)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

We should be using -flto.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

endif()
list(APPEND compile_options -fvisibility=hidden)
list(APPEND compile_options -Wno-unknown-cuda-version)
list(APPEND compile_options -nogpulib)
list(APPEND compile_options -nostdlibinc)
list(APPEND compile_options -fno-rtti)
list(APPEND compile_options -fno-exceptions)
list(APPEND compile_options -fconvergent-functions)
list(APPEND compile_options -Wno-unknown-cuda-version)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Unnecessary reordering

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

if(LLVM_DEFAULT_TARGET_TRIPLE)
list(APPEND compile_options --target=${LLVM_DEFAULT_TARGET_TRIPLE})
endif()
Expand All @@ -52,6 +56,10 @@ elseif("${LLVM_DEFAULT_TARGET_TRIPLE}" MATCHES "^nvptx" OR
"${CMAKE_CXX_COMPILER_TARGET}" MATCHES "^nvptx")
set(target_name "nvptx")
list(APPEND compile_options --cuda-feature=+ptx63)
elseif("${LLVM_DEFAULT_TARGET_TRIPLE}" MATCHES "^spirv64" OR
"${CMAKE_CXX_COMPILER_TARGET}" MATCHES "^spirv64")
set(target_name "spirv")
list(APPEND compile_options -emit-llvm -c)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

You should be setting the link options to emit-llvm, not manually putting in -c.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Also the -emit-llvm is what -flto is supposed to do.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

fixed

endif()

# Trick to combine these into a bitcode file via the linker's LTO pass.
Expand All @@ -74,8 +82,15 @@ target_include_directories(libompdevice PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/../../libc
${CMAKE_CURRENT_SOURCE_DIR}/../../offload/include)
target_compile_options(libompdevice PRIVATE ${compile_options})
target_link_options(libompdevice PRIVATE
"-flto" "-r" "-nostdlib" "-Wl,--lto-emit-llvm")
if(NOT "${LLVM_DEFAULT_TARGET_TRIPLE}" MATCHES "^spirv" AND
NOT "${CMAKE_CXX_COMPILER_TARGET}" MATCHES "^spirv")
target_link_options(libompdevice PRIVATE
"-flto" "-r" "-nostdlib" "-Wl,--lto-emit-llvm")
else()
target_link_options(libompdevice PRIVATE
"-nostdlib" "-emit-llvm" "-Wl")
Comment thread
jhuber6 marked this conversation as resolved.
Outdated
Comment thread
fineg74 marked this conversation as resolved.
Outdated
endif()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Why aren't we building the device RTL in LTO, as we do for the rest?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

SPIRV backend doesn't support lto

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hm, what is the issue? We rely on LTO for performance, and without I doubt we can be competitive.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The library will get linked in and optimized somehow I'm sure, but the library itself gets no individual optimization step together. That definitely hurts performance, but the individual files are optimized so it's likely not catastrophic.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The problem is currently SPIR-V uses an out of tree linker spirv-link, and nobody hooked up the driver to call lld instead of spirv-link if LTO is enabled. I will try to tackle that after I finish the couple of tasks I have now, but yeah right now LTO isn't hooked up.


if(LLVM_DEFAULT_TARGET_TRIPLE)
target_link_options(libompdevice PRIVATE "--target=${LLVM_DEFAULT_TARGET_TRIPLE}")
endif()
Expand Down
9 changes: 8 additions & 1 deletion openmp/device/include/DeviceTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,14 @@ struct IdentTy {

using __kmpc_impl_lanemask_t = LaneMaskTy;

using ParallelRegionFnTy = void *;
#ifdef __SPIRV__
const uint32_t ProgramAS = 9;
using FnPtrTy = __attribute__((address_space(ProgramAS))) void *;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

C++ attributes please

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Using attributes in [[]] form causes compilation error

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

__attribute__ is much more permissive, you're probably putting it in the wrong spot https://godbolt.org/z/qcqnxafGb

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes. FnPtrTy is used as a type since SPIRV backend has issues that are related to address space of parameters. Since the issue is related to SPIRV only and to minimize code changes FnPtrTy was introduced as a type of pointer with attribute for SPIRV, and as a regular pointer for the rest. The correct use of c++ attributes requires to put it after a variable, while attribute can be put before type which makes it easier to use.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This deserves a comment, I mean the AS stuff above.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Added comments in the code

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Do the C++ attributes not work? And just make this constexpr or put the 9 directly in the attribute. Honestly I'm surprised that SPiR-V bothers with this at all, I can't imagine a single case it would make sense for a function to be something that isn't global.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The C++ attributes do not work because in this case they are placed in incorrect place. I believe we have discussed it couple of weeks back. I replaced the constant with the actual value. Regarding why we need a special address space for function better to check with @sarnex as he originally introduced it.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This doesn't work? https://godbolt.org/z/T94q8jz5q

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

That worked. Thanks, fixed

#else
using FnPtrTy = void *;
#endif

using ParallelRegionFnTy = FnPtrTy;
Comment on lines +134 to +144

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

C++ style attributes [[...]]].


using CriticalNameTy = int32_t[8];

Expand Down
10 changes: 10 additions & 0 deletions openmp/device/include/LibC.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,17 @@

namespace ompx {

// SPIR-V backend does not support variadic functions except for

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I have #175076 up but will need some SPIR-V people to look at it.

// __spirv_ocl_printf. This is to provide a workaround to use
// regular printf that is used in the code.
#if defined(__SPIRV__)
template <size_t N, typename... Args>
int printf(const char (&Format)[N], Args... args) {
return __spirv_ocl_printf(Format, args...);
}
#else
int printf(const char *Format, ...);
#endif

} // namespace ompx

Expand Down
2 changes: 1 addition & 1 deletion openmp/device/include/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -219,7 +219,7 @@ lookup32(ValueKind Kind, bool IsReadonly, IdentTy *Ident, bool ForceTeamState) {
__builtin_unreachable();
}

[[gnu::always_inline, gnu::flatten]] inline void *&
[[gnu::always_inline, gnu::flatten]] inline FnPtrTy &
lookupPtr(ValueKind Kind, bool IsReadonly, bool ForceTeamState) {
switch (Kind) {
case state::VK_ParallelRegionFn:
Expand Down
2 changes: 1 addition & 1 deletion openmp/device/src/Allocator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ using namespace allocator;
// Provide a default implementation of malloc / free for AMDGPU platforms built
// without 'libc' support.
extern "C" {
#if defined(__AMDGPU__) && !defined(OMPTARGET_HAS_LIBC)
#if (defined(__AMDGPU__) || defined(__SPIRV__)) && !defined(OMPTARGET_HAS_LIBC)
[[gnu::weak]] void *malloc(size_t Size) { return allocator::alloc(Size); }
[[gnu::weak]] void free(void *Ptr) { allocator::free(Ptr); }
#else
Expand Down
5 changes: 4 additions & 1 deletion openmp/device/src/LibC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,21 @@ extern "C" {
for (size_t I = 0; I < count; ++I)
dstc[I] = C;
}

#if !defined(__SPIRV__)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hopefully my PR will resolve this

[[gnu::weak]] int printf(const char *Format, ...) {
__builtin_va_list vlist;
__builtin_va_start(vlist, Format);
return ::vprintf(Format, vlist);
}
#endif
}

#if !defined(__SPIRV__)
namespace ompx {
[[clang::no_builtin("printf")]] int printf(const char *Format, ...) {
__builtin_va_list vlist;
__builtin_va_start(vlist, Format);
return ::vprintf(Format, vlist);
}
} // namespace ompx
#endif
10 changes: 5 additions & 5 deletions openmp/device/src/Parallelism.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ uint32_t determineNumberOfThreads(int32_t NumThreadsClause) {

// Invoke an outlined parallel function unwrapping arguments (up to 32).
[[clang::always_inline]] void invokeMicrotask(int32_t global_tid,
int32_t bound_tid, void *fn,
int32_t bound_tid, FnPtrTy fn,
void **args, int64_t nargs) {
switch (nargs) {
#include "generated_microtask_cases.gen"
Expand All @@ -84,7 +84,7 @@ extern "C" {

[[clang::always_inline]] void __kmpc_parallel_spmd(IdentTy *ident,
int32_t num_threads,
void *fn, void **args,
FnPtrTy fn, void **args,
const int64_t nargs) {
uint32_t TId = mapping::getThreadIdInBlock();
uint32_t NumThreads = determineNumberOfThreads(num_threads);
Expand Down Expand Up @@ -142,8 +142,8 @@ extern "C" {

[[clang::always_inline]] void
__kmpc_parallel_60(IdentTy *ident, int32_t, int32_t if_expr,
int32_t num_threads, int proc_bind, void *fn,
void *wrapper_fn, void **args, int64_t nargs,
int32_t num_threads, int proc_bind, FnPtrTy fn,
FnPtrTy wrapper_fn, void **args, int64_t nargs,
int32_t nt_strict) {
uint32_t TId = mapping::getThreadIdInBlock();

Expand Down Expand Up @@ -261,7 +261,7 @@ __kmpc_parallel_60(IdentTy *ident, int32_t, int32_t if_expr,
1u, true, ident,
/*ForceTeamState=*/true);
state::ValueRAII ParallelRegionFnRAII(state::ParallelRegionFn, wrapper_fn,
(void *)nullptr, true, ident,
(FnPtrTy) nullptr, true, ident,
/*ForceTeamState=*/true);
state::ValueRAII ActiveLevelRAII(icv::ActiveLevel, 1u, 0u, true, ident,
/*ForceTeamState=*/true);
Expand Down
57 changes: 57 additions & 0 deletions openmp/device/src/Synchronization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,63 @@ void setCriticalLock(omp_lock_t *Lock) { setLock(Lock); }
#endif
///}

#if defined(__SPIRV__)

uint32_t atomicInc(uint32_t *Address, uint32_t Val, atomic::OrderingTy Ordering,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This bit was changed in a previous PR to use the __scoped_atomic_fetch_uinc builtin. This apparently fails on SPIR-V. Best solution, fix the backend because the default lowering should be a CAS loop. Faster solution, just copy the handling for the atomic multiply just below it and put an ifdef __SPIRV__ around the builtin and manual CAS loop.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Copied the implementation for spirv backend until backend is fixed

atomic::MemScopeTy MemScope) {
uint32_t old;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Style, Old

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

while (true) {
old = atomic::load(Address, Ordering, MemScope);
if (old >= Val) {
if (atomic::cas(Address, old, 0, Ordering, Ordering))
break;
} else if (atomic::cas(Address, old, old + 1, Ordering, Ordering))
break;
}
return old;
}

void namedBarrierInit() {} // TODO
void namedBarrier() {} // TODO

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Can you trap here for now?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

void fenceTeam(atomic::OrderingTy Ordering) {
return __scoped_atomic_thread_fence(Ordering, atomic::workgroup);
}

void fenceKernel(atomic::OrderingTy Ordering) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I should probably make these common, I thought I did that already.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I made #177710 hopefully this will let us simplify some of this if it lands without issue

return __scoped_atomic_thread_fence(Ordering, atomic::device);
}

void fenceSystem(atomic::OrderingTy Ordering) {
return __scoped_atomic_thread_fence(Ordering, atomic::system);
}

void syncWarp(__kmpc_impl_lanemask_t mask) { __gpu_sync_lane(mask); }
void syncThreads(atomic::OrderingTy Ordering) { __gpu_sync_threads(); }
void unsetLock(omp_lock_t *Lock) {
atomic::store((int32_t *)Lock, 0, atomic::seq_cst);
}
int testLock(omp_lock_t *Lock) {
return atomic::add((int32_t *)Lock, 0, atomic::seq_cst);
}
void initLock(omp_lock_t *Lock) { unsetLock(Lock); }
void destroyLock(omp_lock_t *Lock) { unsetLock(Lock); }
void setLock(omp_lock_t *Lock) {
int32_t *lock_ptr = (int32_t *)Lock;
bool acquired = false;
int32_t expected;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Style. Please review your patches for style before posting them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed

while (!acquired) {
expected = 0;
if (expected == atomic::load(lock_ptr, atomic::seq_cst))
acquired =
atomic::cas(lock_ptr, expected, 1, atomic::seq_cst, atomic::seq_cst);
}
}

void unsetCriticalLock(omp_lock_t *Lock) { unsetLock(Lock); }
void setCriticalLock(omp_lock_t *Lock) { setLock(Lock); }
void syncThreadsAligned(atomic::OrderingTy Ordering) { syncThreads(Ordering); }
#endif

} // namespace impl

void synchronize::init(bool IsSPMD) {
Expand Down
Loading