Skip to content

Conversation

@jhuber6
Copy link
Contributor

@jhuber6 jhuber6 commented Jan 6, 2026

Summary:
This is an attempt to begin filling out some missing pieces to allow
more generic compute code to use SPIR-V flavored builtins. This should
provide the basic shuffle operation. The next most important one is the
ballot, but I don't think we have an IR intrinsic for that yet.

I don't know SPIR-V very well so let me know if this is the proper
function with the proper semantic checks.

@llvmbot llvmbot added clang Clang issues not falling into any other category clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:codegen IR generation bugs: mangling, exceptions, etc. backend:SPIR-V labels Jan 6, 2026
@llvmbot
Copy link
Member

llvmbot commented Jan 6, 2026

@llvm/pr-subscribers-clang

@llvm/pr-subscribers-clang-codegen

Author: Joseph Huber (jhuber6)

Changes

Summary:
This is an attempt to begin filling out some missing pieces to allow
more generic compute code to use SPIR-V flavored builtins. This should
provide the basic shuffle operation. The next most important one is the
ballot, but I don't think we have an IR intrinsic for that yet.

I don't know SPIR-V very well so let me know if this is the proper
function with the proper semantic checks.


Full diff: https://github.com/llvm/llvm-project/pull/174655.diff

5 Files Affected:

  • (modified) clang/include/clang/Basic/BuiltinsSPIRVCommon.td (+2)
  • (modified) clang/lib/CodeGen/TargetBuiltins/SPIR.cpp (+9)
  • (modified) clang/lib/Sema/SemaSPIRV.cpp (+26)
  • (modified) clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c (+8)
  • (modified) clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c (+6)
diff --git a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
index d2ef6f99a0502..e31758b889d3d 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
@@ -21,3 +21,5 @@ def subgroup_local_invocation_id : SPIRVBuiltin<"uint32_t()", [NoThrow, Const]>;
 def distance : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
 def length : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
 def smoothstep : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
+
+def subgroup_shuffle : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
index 9b0ca3eb0035a..1ea23e8c2195f 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
@@ -109,6 +109,15 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
     Call->addRetAttr(llvm::Attribute::AttrKind::NoUndef);
     return Call;
   }
+  case SPIRV::BI__builtin_spirv_subgroup_shuffle: {
+    Value *X = EmitScalarExpr(E->getArg(0));
+    Value *Y = EmitScalarExpr(E->getArg(1));
+    assert(E->getArg(1)->getType()->hasIntegerRepresentation());
+    return Builder.CreateIntrinsic(
+        /*ReturnType=*/getTypes().ConvertType(E->getArg(0)->getType()),
+        Intrinsic::spv_wave_readlane, ArrayRef<Value *>{X, Y}, nullptr,
+        "spv.shuffle");
+  }
   case SPIRV::BI__builtin_spirv_num_workgroups:
     return Builder.CreateIntrinsic(
         /*ReturnType=*/getTypes().ConvertType(E->getType()),
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index fa30e149c209a..5f3dd71f28c67 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -380,6 +380,32 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI,
     TheCall->setType(RetTy);
     break;
   }
+  case SPIRV::BI__builtin_spirv_subgroup_shuffle: {
+    if (SemaRef.checkArgCount(TheCall, 2))
+      return true;
+
+    ExprResult A = TheCall->getArg(0);
+    QualType ArgTyA = A.get()->getType();
+    if (!ArgTyA->isIntegerType() && !ArgTyA->isFloatingType()) {
+      SemaRef.Diag(A.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+          << /* ordinal */ 1 << /* scalar */ 1 << /* no int */ 0
+          << /* no fp */ 0 << ArgTyA;
+      return true;
+    }
+
+    ExprResult B = TheCall->getArg(1);
+    QualType ArgTyB = B.get()->getType();
+    if (!ArgTyB->isIntegerType()) {
+      SemaRef.Diag(B.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+          << /* ordinal */ 2 << /* scalar */ 1 << /* int */ 1 << /* no fp */ 0
+          << ArgTyB;
+      return true;
+    }
+
+    QualType RetTy = ArgTyA;
+    TheCall->setType(RetTy);
+    break;
+  }
   }
   return false;
 }
diff --git a/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c b/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
index bff850b3622b9..7142dbbc2be73 100644
--- a/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
+++ b/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
@@ -104,3 +104,11 @@
 [[clang::sycl_external]] unsigned int test_subgroup_local_invocation_id() {
     return __builtin_spirv_subgroup_local_invocation_id();
 }
+
+// CHECK: @{{.*}}test_subgroup_shuffle{{.*}}(
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    tail call float @llvm.spv.wave.readlane.f32(float %f, i32 %i)
+//
+[[clang::sycl_external]] float test_subgroup_shuffle(float f, int i) {
+    return __builtin_spirv_subgroup_shuffle(f, i);
+}
diff --git a/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c b/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
index 0d98a552bb1b9..43b2de4e31485 100644
--- a/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
+++ b/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
@@ -75,3 +75,9 @@ void test_subgroup_local_invocation_id() {
   __builtin_spirv_subgroup_local_invocation_id();
   __builtin_spirv_subgroup_local_invocation_id(0); // expected-error{{too many arguments to function call, expected 0, have 1}}
 }
+
+void test_subgroup_shuffle(int i, float f, int *p) {
+  __builtin_spirv_subgroup_shuffle(f, i);
+  __builtin_spirv_subgroup_shuffle(p, i); // expected-error{{1st argument must be a scalar type}}
+  __builtin_spirv_subgroup_shuffle(i, f); // expected-error{{2nd argument must be a scalar integer}}
+}

@llvmbot
Copy link
Member

llvmbot commented Jan 6, 2026

@llvm/pr-subscribers-backend-spir-v

Author: Joseph Huber (jhuber6)

Changes

Summary:
This is an attempt to begin filling out some missing pieces to allow
more generic compute code to use SPIR-V flavored builtins. This should
provide the basic shuffle operation. The next most important one is the
ballot, but I don't think we have an IR intrinsic for that yet.

I don't know SPIR-V very well so let me know if this is the proper
function with the proper semantic checks.


Full diff: https://github.com/llvm/llvm-project/pull/174655.diff

5 Files Affected:

  • (modified) clang/include/clang/Basic/BuiltinsSPIRVCommon.td (+2)
  • (modified) clang/lib/CodeGen/TargetBuiltins/SPIR.cpp (+9)
  • (modified) clang/lib/Sema/SemaSPIRV.cpp (+26)
  • (modified) clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c (+8)
  • (modified) clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c (+6)
diff --git a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
index d2ef6f99a0502..e31758b889d3d 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
@@ -21,3 +21,5 @@ def subgroup_local_invocation_id : SPIRVBuiltin<"uint32_t()", [NoThrow, Const]>;
 def distance : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
 def length : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
 def smoothstep : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
+
+def subgroup_shuffle : SPIRVBuiltin<"void(...)", [NoThrow, Const, CustomTypeChecking]>;
diff --git a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
index 9b0ca3eb0035a..1ea23e8c2195f 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
@@ -109,6 +109,15 @@ Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
     Call->addRetAttr(llvm::Attribute::AttrKind::NoUndef);
     return Call;
   }
+  case SPIRV::BI__builtin_spirv_subgroup_shuffle: {
+    Value *X = EmitScalarExpr(E->getArg(0));
+    Value *Y = EmitScalarExpr(E->getArg(1));
+    assert(E->getArg(1)->getType()->hasIntegerRepresentation());
+    return Builder.CreateIntrinsic(
+        /*ReturnType=*/getTypes().ConvertType(E->getArg(0)->getType()),
+        Intrinsic::spv_wave_readlane, ArrayRef<Value *>{X, Y}, nullptr,
+        "spv.shuffle");
+  }
   case SPIRV::BI__builtin_spirv_num_workgroups:
     return Builder.CreateIntrinsic(
         /*ReturnType=*/getTypes().ConvertType(E->getType()),
diff --git a/clang/lib/Sema/SemaSPIRV.cpp b/clang/lib/Sema/SemaSPIRV.cpp
index fa30e149c209a..5f3dd71f28c67 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -380,6 +380,32 @@ bool SemaSPIRV::CheckSPIRVBuiltinFunctionCall(const TargetInfo &TI,
     TheCall->setType(RetTy);
     break;
   }
+  case SPIRV::BI__builtin_spirv_subgroup_shuffle: {
+    if (SemaRef.checkArgCount(TheCall, 2))
+      return true;
+
+    ExprResult A = TheCall->getArg(0);
+    QualType ArgTyA = A.get()->getType();
+    if (!ArgTyA->isIntegerType() && !ArgTyA->isFloatingType()) {
+      SemaRef.Diag(A.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+          << /* ordinal */ 1 << /* scalar */ 1 << /* no int */ 0
+          << /* no fp */ 0 << ArgTyA;
+      return true;
+    }
+
+    ExprResult B = TheCall->getArg(1);
+    QualType ArgTyB = B.get()->getType();
+    if (!ArgTyB->isIntegerType()) {
+      SemaRef.Diag(B.get()->getBeginLoc(), diag::err_builtin_invalid_arg_type)
+          << /* ordinal */ 2 << /* scalar */ 1 << /* int */ 1 << /* no fp */ 0
+          << ArgTyB;
+      return true;
+    }
+
+    QualType RetTy = ArgTyA;
+    TheCall->setType(RetTy);
+    break;
+  }
   }
   return false;
 }
diff --git a/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c b/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
index bff850b3622b9..7142dbbc2be73 100644
--- a/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
+++ b/clang/test/CodeGenSPIRV/Builtins/ids_and_ranges.c
@@ -104,3 +104,11 @@
 [[clang::sycl_external]] unsigned int test_subgroup_local_invocation_id() {
     return __builtin_spirv_subgroup_local_invocation_id();
 }
+
+// CHECK: @{{.*}}test_subgroup_shuffle{{.*}}(
+// CHECK-NEXT:  [[ENTRY:.*:]]
+// CHECK-NEXT:    tail call float @llvm.spv.wave.readlane.f32(float %f, i32 %i)
+//
+[[clang::sycl_external]] float test_subgroup_shuffle(float f, int i) {
+    return __builtin_spirv_subgroup_shuffle(f, i);
+}
diff --git a/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c b/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
index 0d98a552bb1b9..43b2de4e31485 100644
--- a/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
+++ b/clang/test/SemaSPIRV/BuiltIns/ids_and_ranges.c
@@ -75,3 +75,9 @@ void test_subgroup_local_invocation_id() {
   __builtin_spirv_subgroup_local_invocation_id();
   __builtin_spirv_subgroup_local_invocation_id(0); // expected-error{{too many arguments to function call, expected 0, have 1}}
 }
+
+void test_subgroup_shuffle(int i, float f, int *p) {
+  __builtin_spirv_subgroup_shuffle(f, i);
+  __builtin_spirv_subgroup_shuffle(p, i); // expected-error{{1st argument must be a scalar type}}
+  __builtin_spirv_subgroup_shuffle(i, f); // expected-error{{2nd argument must be a scalar integer}}
+}

@jhuber6
Copy link
Contributor Author

jhuber6 commented Jan 6, 2026

Apparently __builtin_hlsl_wave_read_lane_at exists, but we probably want the generic version. I'm not familiar with HLSL, is there a reason we define these as HLSL builtins first?

@farzonl
Copy link
Member

farzonl commented Jan 6, 2026

Apparently __builtin_hlsl_wave_read_lane_at exists, but we probably want the generic version. I'm not familiar with HLSL, is there a reason we define these as HLSL builtins first?

The team could look into this case, but the answer is usually because we use builtins as alias for codegen that needs to support multiple targets. A secondary more minor reason is it gives us tighter control of sema rules.

@jhuber6
Copy link
Contributor Author

jhuber6 commented Jan 7, 2026

Apparently __builtin_hlsl_wave_read_lane_at exists, but we probably want the generic version. I'm not familiar with HLSL, is there a reason we define these as HLSL builtins first?

The team could look into this case, but the answer is usually because we use builtins as alias for codegen that needs to support multiple targets. A secondary more minor reason is it gives us tighter control of sema rules.

Alright, I'm mostly just interested in a basis set of SPIR-V builtins that will let me port some existing code. I think the only missing one if this one works is a ballot function. Everything else complicated can be made from that. I see an intrinsic for int_spv_wave_active_countbits which returns the popcount of the ballot's result. Is there a reason we don't have one for a regular ballot? Seeing as the subgroup size is unknown to SPIR-V (as far as I know) I can see this being difficult to define. The result is a vector, but what size would that be? Sorry I don't know who contributes to the SPIR-V stuff, mostly just trying to unify compute handling between the three "real" GPU targets.

jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 7, 2026
Summary:
This patch adds an LLVM intrinsic and lowering for a subgroup ballot and
a corresponding clang builtin. This uses the already present support but
provides in a way accessible to other targets. With this and
llvm#174655 we should be able to
most of the basic functions, like shuffling, active masks, and
reductions. More work will be needed for canonicalizing / exposing the
SPIR-V functions, but these are the fundamental builtins I need.
jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 7, 2026
Summary:
This patch adds an LLVM intrinsic and lowering for a subgroup ballot and
a corresponding clang builtin. This uses the already present support but
provides in a way accessible to other targets. With this and
llvm#174655 we should be able to
most of the basic functions, like shuffling, active masks, and
reductions. More work will be needed for canonicalizing / exposing the
SPIR-V functions, but these are the fundamental builtins I need.
jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 7, 2026
Summary:
This patch adds an LLVM intrinsic and lowering for a subgroup ballot and
a corresponding clang builtin. This uses the already present support but
provides in a way accessible to other targets. With this and
llvm#174655 we should be able to
most of the basic functions, like shuffling, active masks, and
reductions. More work will be needed for canonicalizing / exposing the
SPIR-V functions, but these are the fundamental builtins I need.
@github-actions
Copy link

github-actions bot commented Jan 8, 2026

✅ With the latest revision this PR passed the C/C++ code formatter.

@jhuber6 jhuber6 requested a review from sarnex January 8, 2026 04:11
jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 8, 2026
Summary:
llvm#174862 and
llvm#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.
@jhuber6
Copy link
Contributor Author

jhuber6 commented Jan 8, 2026

Random question, why are the intrinsics called spv.wave when the spec seems to use subgroup? I wasn't sure if I should keep that convention or change it in #174862

jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 8, 2026
Summary:
This patch adds an LLVM intrinsic and lowering for a subgroup ballot and
a corresponding clang builtin. This uses the already present support but
provides in a way accessible to other targets. With this and
llvm#174655 we should be able to
most of the basic functions, like shuffling, active masks, and
reductions. More work will be needed for canonicalizing / exposing the
SPIR-V functions, but these are the fundamental builtins I need.
jhuber6 added a commit that referenced this pull request Jan 8, 2026
Summary:
This patch adds an LLVM intrinsic and lowering for a subgroup ballot and
a corresponding clang builtin. This uses the already present support but
provides in a way accessible to other targets. With this and
#174655 we should be able to
most of the basic functions, like shuffling, active masks, and
reductions. More work will be needed for canonicalizing / exposing the
SPIR-V functions, but these are the fundamental builtins I need.
@farzonl
Copy link
Member

farzonl commented Jan 8, 2026

Random question, why are the intrinsics called spv.wave when the spec seems to use subgroup? I wasn't sure if I should keep that convention or change it in #174862

subgroup (SPIRV), wave (DX), warp (Nvidia), wavefront (AMD). Are all the same thing. We picked wave because its the only one that seems to be used as an api-level name and not a harware unit. It was also the only one that shares a name with a harware unit.

More importantly the intrinsic toggling we are doing is very basic between DirectX and SPIRV so the intrinsic names need to match.

llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Jan 8, 2026
Summary:
This patch adds an LLVM intrinsic and lowering for a subgroup ballot and
a corresponding clang builtin. This uses the already present support but
provides in a way accessible to other targets. With this and
llvm/llvm-project#174655 we should be able to
most of the basic functions, like shuffling, active masks, and
reductions. More work will be needed for canonicalizing / exposing the
SPIR-V functions, but these are the fundamental builtins I need.
@farzonl
Copy link
Member

farzonl commented Jan 8, 2026

Random question, why are the intrinsics called spv.wave when the spec seems to use subgroup? I wasn't sure if I should keep that convention or change it in #174862

More importantly the intrinsic toggling we are doing is very basic between DirectX and SPIRV so the intrinsic names need to match.

It mostly became this way because when we started spirv in the frontend wasn't a thing yet.

It doesn't have to stay this way in clang/lib/CodeGen/CGHLSLRuntime.h there is a macro GENERATE_HLSL_INTRINSIC_FUNCTION we could make a GENERATE_HLSL_INTRINSIC_FUNCTION_DEFAULT that uses the same IntrinsicPostfix name for both spirv and directx but then for these cases where we want some intrinsics to be subgroup vs wave we have GENERATE_HLSL_INTRINSIC_FUNCTION a spvPostfix adn dxpostfix name.

@github-actions
Copy link

github-actions bot commented Jan 8, 2026

🐧 Linux x64 Test Results

  • 112563 tests passed
  • 4604 tests skipped

✅ The build succeeded and all tests passed.

@github-actions
Copy link

github-actions bot commented Jan 8, 2026

🪟 Windows x64 Test Results

  • 53365 tests passed
  • 2220 tests skipped

✅ The build succeeded and all tests passed.

Summary:
This is an attempt to begin filling out some missing pieces to allow
more generic compute code to use SPIR-V flavored builtins. This should
provide the basic shuffle operation. The next most important one is the
ballot, but I don't think we have an IR intrinsic for that yet.

I don't know SPIR-V very well so let me know if this is the proper
function with the proper semantic checks.

Sema test

nit

Update sema checking for int argument
@jhuber6 jhuber6 merged commit c02da3d into llvm:main Jan 8, 2026
10 checks passed
jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 8, 2026
Summary:
llvm#174862 and
llvm#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.
jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 9, 2026
Summary:
llvm#174862 and
llvm#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.
jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 9, 2026
Summary:
llvm#174862 and
llvm#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.
jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 9, 2026
Summary:
llvm#174862 and
llvm#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.
jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 9, 2026
Summary:
llvm#174862 and
llvm#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.
jhuber6 added a commit to jhuber6/llvm-project that referenced this pull request Jan 9, 2026
Summary:
llvm#174862 and
llvm#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.
kshitijvp pushed a commit to kshitijvp/llvm-project that referenced this pull request Jan 9, 2026
Summary:
This patch adds an LLVM intrinsic and lowering for a subgroup ballot and
a corresponding clang builtin. This uses the already present support but
provides in a way accessible to other targets. With this and
llvm#174655 we should be able to
most of the basic functions, like shuffling, active masks, and
reductions. More work will be needed for canonicalizing / exposing the
SPIR-V functions, but these are the fundamental builtins I need.
kshitijvp pushed a commit to kshitijvp/llvm-project that referenced this pull request Jan 9, 2026
Summary:
This is an attempt to begin filling out some missing pieces to allow
more generic compute code to use SPIR-V flavored builtins. This should
provide the basic shuffle operation. The next most important one is the
ballot, but I don't think we have an IR intrinsic for that yet.

I don't know SPIR-V very well so let me know if this is the proper
function with the proper semantic checks.
jhuber6 added a commit that referenced this pull request Jan 9, 2026
Summary:
#174862 and
#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Jan 9, 2026
…910)

Summary:
llvm/llvm-project#174862 and
llvm/llvm-project#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.
navaneethshan pushed a commit to qualcomm/cpullvm-toolchain that referenced this pull request Jan 14, 2026
Summary:
This patch adds an LLVM intrinsic and lowering for a subgroup ballot and
a corresponding clang builtin. This uses the already present support but
provides in a way accessible to other targets. With this and
llvm/llvm-project#174655 we should be able to
most of the basic functions, like shuffling, active masks, and
reductions. More work will be needed for canonicalizing / exposing the
SPIR-V functions, but these are the fundamental builtins I need.

(cherry picked from commit f8b68c7)
navaneethshan pushed a commit to qualcomm/cpullvm-toolchain that referenced this pull request Jan 14, 2026
Summary:
llvm/llvm-project#174862 and
llvm/llvm-project#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.

(cherry picked from commit 5c43243)
Priyanshu3820 pushed a commit to Priyanshu3820/llvm-project that referenced this pull request Jan 18, 2026
Summary:
This patch adds an LLVM intrinsic and lowering for a subgroup ballot and
a corresponding clang builtin. This uses the already present support but
provides in a way accessible to other targets. With this and
llvm#174655 we should be able to
most of the basic functions, like shuffling, active masks, and
reductions. More work will be needed for canonicalizing / exposing the
SPIR-V functions, but these are the fundamental builtins I need.
Priyanshu3820 pushed a commit to Priyanshu3820/llvm-project that referenced this pull request Jan 18, 2026
Summary:
This is an attempt to begin filling out some missing pieces to allow
more generic compute code to use SPIR-V flavored builtins. This should
provide the basic shuffle operation. The next most important one is the
ballot, but I don't think we have an IR intrinsic for that yet.

I don't know SPIR-V very well so let me know if this is the proper
function with the proper semantic checks.
Priyanshu3820 pushed a commit to Priyanshu3820/llvm-project that referenced this pull request Jan 18, 2026
Summary:
llvm#174862 and
llvm#174655 provided the intrinsics
required to get the fundamental operations working for these. This patch
sets up the basic support (as far as I know).

This should be the first step towards allowing SPIR-V to build things
like the LLVM libc and the OpenMP Device Runtime Library. The
implementations here are intentionally inefficient, such as not using
the dedicated SPIR-V opcode for read firstlane. This is just to start
and hopefully start testing things later.

Would appreciate someone more familiar with  the backend double-checking
these.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

backend:SPIR-V clang:codegen IR generation bugs: mangling, exceptions, etc. clang:frontend Language frontend issues, e.g. anything involving "Sema" clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants