-
Notifications
You must be signed in to change notification settings - Fork 16.1k
[SPIR-V] Add clang builtin for subgroup shuffles #174655
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-clang @llvm/pr-subscribers-clang-codegen Author: Joseph Huber (jhuber6) ChangesSummary: I don't know SPIR-V very well so let me know if this is the proper Full diff: https://github.com/llvm/llvm-project/pull/174655.diff 5 Files Affected:
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}}
+}
|
|
@llvm/pr-subscribers-backend-spir-v Author: Joseph Huber (jhuber6) ChangesSummary: I don't know SPIR-V very well so let me know if this is the proper Full diff: https://github.com/llvm/llvm-project/pull/174655.diff 5 Files Affected:
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}}
+}
|
|
Apparently |
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 |
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.
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.
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.
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
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.
|
Random question, why are the intrinsics called |
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.
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.
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. |
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.
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 |
🐧 Linux x64 Test Results
✅ The build succeeded and all tests passed. |
🪟 Windows x64 Test Results
✅ 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
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.
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.
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.
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.
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.
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.
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.
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.
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.
…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.
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)
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)
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.
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.
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.
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.