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
