Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
23 changes: 23 additions & 0 deletions clang/lib/CodeGen/CGHLSLBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
13 changes: 10 additions & 3 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
25 changes: 25 additions & 0 deletions clang/test/CodeGenHLSL/builtins/checkaccessfullymapped.hlsl
Original file line number Diff line number Diff line change
@@ -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);
}
26 changes: 26 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/checkaccessfullymapped-errors.hlsl
Original file line number Diff line number Diff line change
@@ -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'}}
}
3 changes: 2 additions & 1 deletion llvm/include/llvm/IR/IntrinsicsSPIRV.td
Original file line number Diff line number Diff line change
Expand Up @@ -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]>;
Expand Down
11 changes: 11 additions & 0 deletions llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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)
Loading