-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[SPIR-V] [HLSL] Add CheckAccessFullyMapped HLSL function. #169398
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
base: main
Are you sure you want to change the base?
Conversation
|
@llvm/pr-subscribers-llvm-ir @llvm/pr-subscribers-backend-x86 Author: Joshua Batista (bob80905) ChangesThis PR adds support for CheckAccessFullyMapped. The DXIL lowering emits a comparison to 0, and a bool true if it isn't 0. Fixes #99204 Full diff: https://github.com/llvm/llvm-project/pull/169398.diff 9 Files Affected:
diff --git a/clang/include/clang/Basic/Builtins.td b/clang/include/clang/Basic/Builtins.td
index 7530aebdcb581..a9b660a3d7da5 100644
--- a/clang/include/clang/Basic/Builtins.td
+++ b/clang/include/clang/Basic/Builtins.td
@@ -5084,6 +5084,12 @@ def HLSLWaveGetLaneCount : LangBuiltin<"HLSL_LANG"> {
let Prototype = "unsigned int()";
}
+def HLSLCheckAccessFullyMapped : LangBuiltin<"HLSL_LANG"> {
+ let Spellings = ["__builtin_hlsl_check_access_fully_mapped"];
+ let Attributes = [NoThrow, Const];
+ let Prototype = "void(...)";
+}
+
def HLSLClamp : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_elementwise_clamp"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
diff --git a/clang/lib/CodeGen/CGHLSLBuiltins.cpp b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
index 5ae3fed099cd4..9de98d5aa8494 100644
--- a/clang/lib/CodeGen/CGHLSLBuiltins.cpp
+++ b/clang/lib/CodeGen/CGHLSLBuiltins.cpp
@@ -886,6 +886,29 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
"Intrinsic WaveGetLaneIndex not supported by target architecture");
}
}
+ case Builtin::BI__builtin_hlsl_check_access_fully_mapped: {
+ // We don't define a DXIL intrinsic, instead it is a cast from uint to bool.
+ switch (CGM.getTarget().getTriple().getArch()) {
+ case llvm::Triple::dxil: {
+ Value *Status = EmitScalarExpr(E->getArg(0));
+ return Builder.CreateICmpNE(
+ Status, ConstantInt::get(Status->getType(), 0), "BoolCast");
+ }
+
+ case llvm::Triple::spirv: {
+ // OpImageSparseTexelsResident consumes a uint residency code
+ Value *Status = EmitScalarExpr(E->getArg(0));
+
+ return Builder.CreateIntrinsic(
+ llvm::Intrinsic::spv_check_access_fully_mapped,
+ /* Overload types */ {},
+ /* Arguments */ {Status});
+ }
+ default:
+ llvm_unreachable("Intrinsic CheckAccessFullyMapped not supported by "
+ "target architecture");
+ }
+ }
case Builtin::BI__builtin_hlsl_wave_is_first_lane: {
Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveIsFirstLaneIntrinsic();
return EmitRuntimeCall(
diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsics.h b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
index a538be5ebd099..c473306037755 100644
--- a/clang/lib/Headers/hlsl/hlsl_intrinsics.h
+++ b/clang/lib/Headers/hlsl/hlsl_intrinsics.h
@@ -666,9 +666,16 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
return __detail::smoothstep_vec_impl(Min, Max, X);
}
-inline bool CheckAccessFullyMapped(uint Status) {
- return static_cast<bool>(Status);
-}
+//===----------------------------------------------------------------------===//
+// CheckAccessFullyMapped builtins
+//===----------------------------------------------------------------------===//
+
+/// \fn bool CheckAccessFullyMapped(uint32 x)
+/// \brief Returns true if the x parameter represents a value that indicates
+/// to the driver that the memory is resident, false otherwise.
+
+_HLSL_BUILTIN_ALIAS(__builtin_hlsl_check_access_fully_mapped)
+bool CheckAccessFullyMapped(uint32_t x);
//===----------------------------------------------------------------------===//
// fwidth builtin
diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp
index 0a164a7b5bbbd..2bfee3be4baa5 100644
--- a/clang/lib/Sema/SemaHLSL.cpp
+++ b/clang/lib/Sema/SemaHLSL.cpp
@@ -3304,6 +3304,26 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
TheCall->setType(ArgTyA);
break;
}
+ case Builtin::BI__builtin_hlsl_check_access_fully_mapped: {
+ if (SemaRef.checkArgCount(TheCall, 1))
+ return true;
+ Expr *Arg = TheCall->getArg(0);
+ QualType ArgTyA = Arg->getType();
+
+ if (CheckArgTypeMatches(&SemaRef, Arg,
+ SemaRef.getASTContext().UnsignedIntTy))
+ return true;
+
+ if (!ArgTyA->isScalarType()) {
+ SemaRef.Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
+ << ArgTyA << SemaRef.getASTContext().UnsignedIntTy << 1 << 0 << 0;
+ return true;
+ }
+
+ QualType BoolType = getASTContext().BoolTy;
+ TheCall->setType(BoolType);
+ break;
+ }
case Builtin::BI__builtin_hlsl_wave_active_max:
case Builtin::BI__builtin_hlsl_wave_active_min:
case Builtin::BI__builtin_hlsl_wave_active_sum: {
diff --git a/clang/test/CodeGenHLSL/builtins/checkaccessfullymapped.hlsl b/clang/test/CodeGenHLSL/builtins/checkaccessfullymapped.hlsl
new file mode 100644
index 0000000000000..178d98c1e36b4
--- /dev/null
+++ b/clang/test/CodeGenHLSL/builtins/checkaccessfullymapped.hlsl
@@ -0,0 +1,25 @@
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm \
+// RUN: -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,DX
+
+// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
+// RUN: spirv-unknown-vulkan-compute %s -emit-llvm \
+// RUN: -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,SPV
+
+// CHECK: test_check_access_fully_mapped
+// DX: %[[X_ADDR:.*]] = alloca i32, align 4
+// DX: store i32 %x, ptr %[[X_ADDR]], align 4
+// DX: %[[X_LOAD:.*]] = load i32, ptr %[[X_ADDR]], align 4
+// DX: %[[BoolCast:.*]] = icmp ne i32 %[[X_LOAD]], 0
+// DX: ret i1 %[[BoolCast]]
+
+// SPV: %[[X_ADDR:.*]] = alloca i32, align 4
+// SPV: store i32 %x, ptr %[[X_ADDR]], align 4
+// SPV: %[[X_LOAD:.*]] = loasd i32, ptr %[[X_ADDR]], align 4
+// SPV: %[[CAFM:.*]] = call i1 @llvm.spv.check.access.fully.mapped(i32 %[[X_LOAD]])
+// SPV: ret i1 %[[CAFM]]
+
+bool test_check_access_fully_mapped(uint x)
+{
+ return CheckAccessFullyMapped(x);
+}
diff --git a/clang/test/SemaHLSL/BuiltIns/checkaccessfullymapped-errors.hlsl b/clang/test/SemaHLSL/BuiltIns/checkaccessfullymapped-errors.hlsl
new file mode 100644
index 0000000000000..b429ce846f5b9
--- /dev/null
+++ b/clang/test/SemaHLSL/BuiltIns/checkaccessfullymapped-errors.hlsl
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -disable-llvm-passes -verify -verify-ignore-unexpected
+
+void test_too_few_arg()
+{
+ return __builtin_hlsl_check_access_fully_mapped();
+ // expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
+}
+
+void test_too_many_arg(float2 p0)
+{
+ return __builtin_hlsl_check_access_fully_mapped(p0, p0, p0);
+ // expected-error@-1 {{too many arguments to function call, expected 1, have 3}}
+}
+
+bool builtin_bool_to_float_type_promotion(bool p1)
+{
+ return __builtin_hlsl_check_access_fully_mapped(p1);
+ // expected-error@-1 {{passing 'bool' to parameter of incompatible type 'unsigned int'}}
+}
+
+
+bool2 builtin_check_access_fully_mapped_int2_to_float2_promotion(int2 p1)
+{
+ return __builtin_hlsl_check_access_fully_mapped(p1);
+ // expected-error@-1 {{passing 'int2' (aka 'vector<int, 2>') to parameter of incompatible type 'unsigned int'}}
+}
diff --git a/llvm/include/llvm/IR/IntrinsicsSPIRV.td b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
index 366f8cf36d75c..182c02560e816 100644
--- a/llvm/include/llvm/IR/IntrinsicsSPIRV.td
+++ b/llvm/include/llvm/IR/IntrinsicsSPIRV.td
@@ -41,7 +41,8 @@ let TargetPrefix = "spv" in {
def int_spv_alloca : Intrinsic<[llvm_any_ty], [llvm_i8_ty], [ImmArg<ArgIndex<0>>]>;
def int_spv_alloca_array : Intrinsic<[llvm_any_ty], [llvm_anyint_ty, llvm_i8_ty], [ImmArg<ArgIndex<1>>]>;
def int_spv_undef : Intrinsic<[llvm_i32_ty], []>;
- def int_spv_inline_asm : Intrinsic<[], [llvm_metadata_ty, llvm_metadata_ty, llvm_vararg_ty]>;
+ def int_spv_inline_asm : Intrinsic<[], [llvm_metadata_ty, llvm_metadata_ty, llvm_vararg_ty]>;
+ def int_spv_check_access_fully_mapped : Intrinsic<[llvm_i1_ty], [llvm_i32_ty], [IntrNoMem]>;
// Expect, Assume Intrinsics
def int_spv_assume : Intrinsic<[], [llvm_i1_ty]>;
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index d3fc08eb56cb3..103233fbd0df1 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -3588,6 +3588,17 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
case Intrinsic::spv_fwidth:
return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpFwidth);
+ case Intrinsic::spv_check_access_fully_mapped: {
+ MachineBasicBlock &BB = *I.getParent();
+ Register StatusReg = I.getOperand(1).getReg();
+
+ return BuildMI(BB, I, I.getDebugLoc(),
+ TII.get(SPIRV::OpImageSparseTexelsResident))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(ResType))
+ .addUse(StatusReg)
+ .constrainAllUses(TII, TRI, RBI);
+ }
default: {
std::string DiagMsg;
raw_string_ostream OS(DiagMsg);
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/check_access_fully_mapped.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/check_access_fully_mapped.ll
new file mode 100644
index 0000000000000..47f9235c8dc69
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/check_access_fully_mapped.ll
@@ -0,0 +1,22 @@
+; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+
+; Make sure SPIRV operation function calls for check access fully mapped are lowered correctly.
+
+; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+
+define noundef i1 @check_access_fully_mapped(i32 %i) {
+entry:
+ ; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]]
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]]
+ ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_16]]
+ ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Step %[[#arg0]] %[[#arg1]]
+ %hlsl.check_access_fully_mapped = call i1 @llvm.spv.check_access_fully_mapped(i32 %i)
+ ret i1 %hlsl.check_access_fully_mapped
+}
+
+declare i1 @llvm.spv.check_access_fully_mapped(i32)
|
🐧 Linux x64 Test Results
Failed Tests(click on a test name to see its output) LLVMLLVM.CodeGen/SPIRV/hlsl-intrinsics/check_access_fully_mapped.llClangClang.CodeGenHLSL/builtins/checkaccessfullymapped.hlslIf these failures are unrelated to your changes (for example tests are broken or flaky at HEAD), please open an issue at https://github.com/llvm/llvm-project/issues and add the |
This PR adds support for CheckAccessFullyMapped. The DXIL lowering emits a comparison to 0, and a bool true if it isn't 0.
The SPIR-V lowering emits OpImageSparseTexelsResident.
Fixes #99204