https://github.com/jhuber6 updated 
https://github.com/llvm/llvm-project/pull/174655

>From f590d17d6a1540fc3fdc03fc3e6fc6dfa18c964f Mon Sep 17 00:00:00 2001
From: Joseph Huber <[email protected]>
Date: Tue, 6 Jan 2026 15:36:15 -0600
Subject: [PATCH] [SPIR-V] Add clang builtin for subgroup shuffles

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
---
 .../clang/Basic/BuiltinsSPIRVCommon.td        |  1 +
 clang/lib/CodeGen/TargetBuiltins/SPIR.cpp     |  8 +++++
 clang/lib/Sema/SemaSPIRV.cpp                  | 36 +++++++++++++++++++
 clang/test/CodeGenSPIRV/Builtins/subgroup.c   | 10 +++++-
 .../test/SemaSPIRV/BuiltIns/subgroup-errors.c | 12 +++++++
 5 files changed, 66 insertions(+), 1 deletion(-)

diff --git a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td 
b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
index 495851ed1727a..7765cf0e5dbc9 100644
--- a/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
+++ b/clang/include/clang/Basic/BuiltinsSPIRVCommon.td
@@ -23,3 +23,4 @@ def length : SPIRVBuiltin<"void(...)", [NoThrow, Const]>;
 def smoothstep : SPIRVBuiltin<"void(...)", [NoThrow, Const, 
CustomTypeChecking]>;
 
 def subgroup_ballot : SPIRVBuiltin<"_ExtVector<4, uint32_t>(bool)", [NoThrow, 
Const]>;
+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..ff7b5fefedd19 100644
--- a/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
+++ b/clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
@@ -109,6 +109,14 @@ 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, {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..8c2af5053bde2 100644
--- a/clang/lib/Sema/SemaSPIRV.cpp
+++ b/clang/lib/Sema/SemaSPIRV.cpp
@@ -380,6 +380,42 @@ 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 =
+        SemaRef.DefaultFunctionArrayLvalueConversion(TheCall->getArg(0));
+    if (A.isInvalid())
+      return true;
+    TheCall->setArg(0, A.get());
+
+    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 =
+        SemaRef.DefaultFunctionArrayLvalueConversion(TheCall->getArg(1));
+    if (B.isInvalid())
+      return true;
+
+    QualType Uint32Ty =
+        SemaRef.getASTContext().getIntTypeForBitwidth(32,
+                                                      /*Signed=*/false);
+    ExprResult ResB = SemaRef.PerformImplicitConversion(
+        B.get(), Uint32Ty, AssignmentAction::Passing);
+    if (ResB.isInvalid())
+      return true;
+    TheCall->setArg(1, ResB.get());
+
+    QualType RetTy = ArgTyA;
+    TheCall->setType(RetTy);
+    break;
+  }
   }
   return false;
 }
diff --git a/clang/test/CodeGenSPIRV/Builtins/subgroup.c 
b/clang/test/CodeGenSPIRV/Builtins/subgroup.c
index 2ae2013c3c23e..05f272c32786a 100644
--- a/clang/test/CodeGenSPIRV/Builtins/subgroup.c
+++ b/clang/test/CodeGenSPIRV/Builtins/subgroup.c
@@ -10,6 +10,14 @@ typedef unsigned __attribute__((ext_vector_type(4))) int4;
 // CHECK: @{{.*}}test_subgroup_shuffle{{.*}}(
 // CHECK-NEXT:  [[ENTRY:.*:]]
 // CHECK-NEXT:    tail call <4 x i32> @llvm.spv.wave.ballot(i1 %i)
-[[clang::sycl_external]] int4 test_subgroup_shuffle(_Bool i) {
+[[clang::sycl_external]] int4 test_subgroup_ballot(_Bool i) {
     return __builtin_spirv_subgroup_ballot(i);
 }
+
+// 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/subgroup-errors.c 
b/clang/test/SemaSPIRV/BuiltIns/subgroup-errors.c
index 5ef9f499efd31..ea41121b58c59 100644
--- a/clang/test/SemaSPIRV/BuiltIns/subgroup-errors.c
+++ b/clang/test/SemaSPIRV/BuiltIns/subgroup-errors.c
@@ -11,3 +11,15 @@ void ballot(_Bool c) {
   x = __builtin_spirv_subgroup_ballot(x); // expected-error{{parameter of 
incompatible type}}
   int y = __builtin_spirv_subgroup_ballot(c); // expected-error{{with an 
expression of incompatible type}}
 }
+
+void shuffle() {
+  int x = 0;
+  long long l = 0;
+  float f = 0;
+  int [[clang::ext_vector_type(1)]] v;
+  (void)__builtin_spirv_subgroup_shuffle(x, x);
+  (void)__builtin_spirv_subgroup_shuffle(f, f);
+  (void)__builtin_spirv_subgroup_shuffle(x, x, x); // expected-error{{too many 
arguments to function call, expected 2, have 3}}
+  (void)__builtin_spirv_subgroup_shuffle(v, f); // expected-error{{1st 
argument must be a scalar type}}
+  (void)__builtin_spirv_subgroup_shuffle(f, v); // expected-error{{to 
parameter of incompatible type}}
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to