Skip to content

Commit 6eb2a31

Browse files
committed
first try, no texels resident op yet
1 parent 86cbb36 commit 6eb2a31

File tree

9 files changed

+145
-4
lines changed

9 files changed

+145
-4
lines changed

clang/include/clang/Basic/Builtins.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5084,6 +5084,12 @@ def HLSLWaveGetLaneCount : LangBuiltin<"HLSL_LANG"> {
50845084
let Prototype = "unsigned int()";
50855085
}
50865086

5087+
def HLSLCheckAccessFullyMapped : LangBuiltin<"HLSL_LANG"> {
5088+
let Spellings = ["__builtin_hlsl_check_access_fully_mapped"];
5089+
let Attributes = [NoThrow, Const];
5090+
let Prototype = "void(...)";
5091+
}
5092+
50875093
def HLSLClamp : LangBuiltin<"HLSL_LANG"> {
50885094
let Spellings = ["__builtin_hlsl_elementwise_clamp"];
50895095
let Attributes = [NoThrow, Const, CustomTypeChecking];

clang/lib/CodeGen/CGHLSLBuiltins.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,29 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
886886
"Intrinsic WaveGetLaneIndex not supported by target architecture");
887887
}
888888
}
889+
case Builtin::BI__builtin_hlsl_check_access_fully_mapped: {
890+
// We don't define a DXIL intrinsic, instead it is a cast from uint to bool.
891+
switch (CGM.getTarget().getTriple().getArch()) {
892+
case llvm::Triple::dxil: {
893+
Value *Status = EmitScalarExpr(E->getArg(0));
894+
return Builder.CreateICmpNE(
895+
Status, ConstantInt::get(Status->getType(), 0), "BoolCast");
896+
}
897+
898+
case llvm::Triple::spirv: {
899+
// OpImageSparseTexelsResident consumes a uint residency code
900+
Value *Status = EmitScalarExpr(E->getArg(0));
901+
902+
return Builder.CreateIntrinsic(
903+
llvm::Intrinsic::spv_check_access_fully_mapped,
904+
/* Overload types */ {},
905+
/* Arguments */ {Status});
906+
}
907+
default:
908+
llvm_unreachable("Intrinsic CheckAccessFullyMapped not supported by "
909+
"target architecture");
910+
}
911+
}
889912
case Builtin::BI__builtin_hlsl_wave_is_first_lane: {
890913
Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveIsFirstLaneIntrinsic();
891914
return EmitRuntimeCall(

clang/lib/Headers/hlsl/hlsl_intrinsics.h

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -666,9 +666,16 @@ smoothstep(__detail::HLSL_FIXED_VECTOR<float, N> Min,
666666
return __detail::smoothstep_vec_impl(Min, Max, X);
667667
}
668668

669-
inline bool CheckAccessFullyMapped(uint Status) {
670-
return static_cast<bool>(Status);
671-
}
669+
//===----------------------------------------------------------------------===//
670+
// CheckAccessFullyMapped builtins
671+
//===----------------------------------------------------------------------===//
672+
673+
/// \fn bool CheckAccessFullyMapped(uint32 x)
674+
/// \brief Returns true if the x parameter represents a value that indicates
675+
/// to the driver that the memory is resident, false otherwise.
676+
677+
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_check_access_fully_mapped)
678+
bool CheckAccessFullyMapped(uint32_t x);
672679

673680
//===----------------------------------------------------------------------===//
674681
// fwidth builtin

clang/lib/Sema/SemaHLSL.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3304,6 +3304,26 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
33043304
TheCall->setType(ArgTyA);
33053305
break;
33063306
}
3307+
case Builtin::BI__builtin_hlsl_check_access_fully_mapped: {
3308+
if (SemaRef.checkArgCount(TheCall, 1))
3309+
return true;
3310+
Expr *Arg = TheCall->getArg(0);
3311+
QualType ArgTyA = Arg->getType();
3312+
3313+
if (CheckArgTypeMatches(&SemaRef, Arg,
3314+
SemaRef.getASTContext().UnsignedIntTy))
3315+
return true;
3316+
3317+
if (!ArgTyA->isScalarType()) {
3318+
SemaRef.Diag(Arg->getBeginLoc(), diag::err_typecheck_convert_incompatible)
3319+
<< ArgTyA << SemaRef.getASTContext().UnsignedIntTy << 1 << 0 << 0;
3320+
return true;
3321+
}
3322+
3323+
QualType BoolType = getASTContext().BoolTy;
3324+
TheCall->setType(BoolType);
3325+
break;
3326+
}
33073327
case Builtin::BI__builtin_hlsl_wave_active_max:
33083328
case Builtin::BI__builtin_hlsl_wave_active_min:
33093329
case Builtin::BI__builtin_hlsl_wave_active_sum: {
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
2+
// RUN: dxil-pc-shadermodel6.3-library %s -emit-llvm \
3+
// RUN: -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,DX
4+
5+
// RUN: %clang_cc1 -finclude-default-header -x hlsl -triple \
6+
// RUN: spirv-unknown-vulkan-compute %s -emit-llvm \
7+
// RUN: -disable-llvm-passes -o - | FileCheck %s --check-prefixes=CHECK,SPV
8+
9+
// CHECK: test_check_access_fully_mapped
10+
// DX: %[[X_ADDR:.*]] = alloca i32, align 4
11+
// DX: store i32 %x, ptr %[[X_ADDR]], align 4
12+
// DX: %[[X_LOAD:.*]] = load i32, ptr %[[X_ADDR]], align 4
13+
// DX: %[[BoolCast:.*]] = icmp ne i32 %[[X_LOAD]], 0
14+
// DX: ret i1 %[[BoolCast]]
15+
16+
// SPV: %[[X_ADDR:.*]] = alloca i32, align 4
17+
// SPV: store i32 %x, ptr %[[X_ADDR]], align 4
18+
// SPV: %[[X_LOAD:.*]] = loasd i32, ptr %[[X_ADDR]], align 4
19+
// SPV: %[[CAFM:.*]] = call i1 @llvm.spv.check.access.fully.mapped(i32 %[[X_LOAD]])
20+
// SPV: ret i1 %[[CAFM]]
21+
22+
bool test_check_access_fully_mapped(uint x)
23+
{
24+
return CheckAccessFullyMapped(x);
25+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -disable-llvm-passes -verify -verify-ignore-unexpected
2+
3+
void test_too_few_arg()
4+
{
5+
return __builtin_hlsl_check_access_fully_mapped();
6+
// expected-error@-1 {{too few arguments to function call, expected 1, have 0}}
7+
}
8+
9+
void test_too_many_arg(float2 p0)
10+
{
11+
return __builtin_hlsl_check_access_fully_mapped(p0, p0, p0);
12+
// expected-error@-1 {{too many arguments to function call, expected 1, have 3}}
13+
}
14+
15+
bool builtin_bool_to_float_type_promotion(bool p1)
16+
{
17+
return __builtin_hlsl_check_access_fully_mapped(p1);
18+
// expected-error@-1 {{passing 'bool' to parameter of incompatible type 'unsigned int'}}
19+
}
20+
21+
22+
bool2 builtin_check_access_fully_mapped_int2_to_float2_promotion(int2 p1)
23+
{
24+
return __builtin_hlsl_check_access_fully_mapped(p1);
25+
// expected-error@-1 {{passing 'int2' (aka 'vector<int, 2>') to parameter of incompatible type 'unsigned int'}}
26+
}

llvm/include/llvm/IR/IntrinsicsSPIRV.td

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,8 @@ let TargetPrefix = "spv" in {
4141
def int_spv_alloca : Intrinsic<[llvm_any_ty], [llvm_i8_ty], [ImmArg<ArgIndex<0>>]>;
4242
def int_spv_alloca_array : Intrinsic<[llvm_any_ty], [llvm_anyint_ty, llvm_i8_ty], [ImmArg<ArgIndex<1>>]>;
4343
def int_spv_undef : Intrinsic<[llvm_i32_ty], []>;
44-
def int_spv_inline_asm : Intrinsic<[], [llvm_metadata_ty, llvm_metadata_ty, llvm_vararg_ty]>;
44+
def int_spv_inline_asm : Intrinsic<[], [llvm_metadata_ty, llvm_metadata_ty, llvm_vararg_ty]>;
45+
def int_spv_check_access_fully_mapped : Intrinsic<[llvm_i1_ty], [llvm_i32_ty], [IntrNoMem]>;
4546

4647
// Expect, Assume Intrinsics
4748
def int_spv_assume : Intrinsic<[], [llvm_i1_ty]>;

llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3588,6 +3588,17 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
35883588
return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyCoarse);
35893589
case Intrinsic::spv_fwidth:
35903590
return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpFwidth);
3591+
case Intrinsic::spv_check_access_fully_mapped: {
3592+
MachineBasicBlock &BB = *I.getParent();
3593+
Register StatusReg = I.getOperand(1).getReg();
3594+
3595+
return BuildMI(BB, I, I.getDebugLoc(),
3596+
TII.get(SPIRV::OpImageSparseTexelsResident))
3597+
.addDef(ResVReg)
3598+
.addUse(GR.getSPIRVTypeID(ResType))
3599+
.addUse(StatusReg)
3600+
.constrainAllUses(TII, TRI, RBI);
3601+
}
35913602
default: {
35923603
std::string DiagMsg;
35933604
raw_string_ostream OS(DiagMsg);
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s
2+
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
3+
4+
; Make sure SPIRV operation function calls for check access fully mapped are lowered correctly.
5+
6+
; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450"
7+
; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
8+
; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
9+
; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
10+
; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
11+
12+
define noundef i1 @check_access_fully_mapped(i32 %i) {
13+
entry:
14+
; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]]
15+
; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]]
16+
; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_16]]
17+
; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] Step %[[#arg0]] %[[#arg1]]
18+
%hlsl.check_access_fully_mapped = call i1 @llvm.spv.check_access_fully_mapped(i32 %i)
19+
ret i1 %hlsl.check_access_fully_mapped
20+
}
21+
22+
declare i1 @llvm.spv.check_access_fully_mapped(i32)

0 commit comments

Comments
 (0)