Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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 @@ -4933,6 +4933,12 @@ def HLSLResourceHandleFromImplicitBinding : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void(...)";
}

def HLSLResourceNonUniformIndex : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_nonuniformindex"];
let Attributes = [NoThrow];
let Prototype = "uint32_t(uint32_t)";
}

def HLSLAll : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_all"];
let Attributes = [NoThrow, Const];
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/CodeGen/CGHLSLBuiltins.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,13 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
SmallVector<Value *> Args{OrderID, SpaceOp, RangeOp, IndexOp, Name};
return Builder.CreateIntrinsic(HandleTy, IntrinsicID, Args);
}
case Builtin::BI__builtin_hlsl_resource_nonuniformindex: {
Value *IndexOp = EmitScalarExpr(E->getArg(0));
llvm::Type *RetTy = ConvertType(E->getType());
return Builder.CreateIntrinsic(
RetTy, CGM.getHLSLRuntime().getNonUniformResourceIndexIntrinsic(),
ArrayRef<Value *>{IndexOp});
}
case Builtin::BI__builtin_hlsl_all: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
return Builder.CreateIntrinsic(
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ class CGHLSLRuntime {
resource_handlefrombinding)
GENERATE_HLSL_INTRINSIC_FUNCTION(CreateHandleFromImplicitBinding,
resource_handlefromimplicitbinding)
GENERATE_HLSL_INTRINSIC_FUNCTION(NonUniformResourceIndex,
resource_nonuniformindex)
GENERATE_HLSL_INTRINSIC_FUNCTION(BufferUpdateCounter, resource_updatecounter)
GENERATE_HLSL_INTRINSIC_FUNCTION(GroupMemoryBarrierWithGroupSync,
group_memory_barrier_with_group_sync)
Expand Down
25 changes: 25 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,6 +422,31 @@ constexpr int4 D3DCOLORtoUBYTE4(float4 V) {
return __detail::d3d_color_to_ubyte4_impl(V);
}

//===----------------------------------------------------------------------===//
// NonUniformResourceIndex builtin
//===----------------------------------------------------------------------===//

/// \fn uint NonUniformResourceIndex(uint I)
/// \brief A compiler hint to indicate that a resource index varies across
/// threads.
// / within a wave (i.e., it is non-uniform).
/// \param I [in] Resource array index
///
/// The return value is the \Index parameter.
///
/// When indexing into an array of shader resources (e.g., textures, buffers),
/// some GPU hardware and drivers require the compiler to know whether the index
/// is uniform (same for all threads) or non-uniform (varies per thread).
///
/// Using NonUniformResourceIndex explicitly marks an index as non-uniform, .
/// disabling certain assumptions or optimizations that could lead to incorrect
/// behavior when dynamically accessing resource arrays with non-uniform
/// indices.

constexpr uint32_t NonUniformResourceIndex(uint32_t Index) {
return __builtin_hlsl_resource_nonuniformindex(Index);
}

//===----------------------------------------------------------------------===//
// reflect builtin
//===----------------------------------------------------------------------===//
Expand Down
38 changes: 38 additions & 0 deletions clang/test/CodeGenHLSL/resources/NonUniformResourceIndex.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.3-compute -emit-llvm -disable-llvm-passes -o - %s \
// RUN: | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,DXIL
// RUN: %clang_cc1 -finclude-default-header -triple spirv-pc-vulkan1.3-compute -emit-llvm -disable-llvm-passes -o - %s \
// RUN: | llvm-cxxfilt | FileCheck %s --check-prefixes=CHECK,SPV

RWBuffer<float> A[10];

[numthreads(4,1,1)]
void main(uint GI : SV_GroupID) {
// CHECK: %[[GI:.*]] = load i32, ptr %GI.addr
// CHECK: %[[NURI_1:.*]] = call {{.*}} i32 @hlsl::NonUniformResourceIndex(unsigned int)(i32 noundef %[[GI]])
// CHECK: call void @hlsl::RWBuffer<float>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}}, i32 noundef 0, i32 noundef 0, i32 noundef 10, i32 noundef %[[NURI_1]], ptr noundef @A.str)
float a = A[NonUniformResourceIndex(GI)][0];

// CHECK: %[[GI:.*]] = load i32, ptr %GI.addr
// CHECK: %[[ADD:.*]] = add i32 %[[GI]], 1
// CHECK: %[[NURI_2:.*]] = call {{.*}} i32 @hlsl::NonUniformResourceIndex(unsigned int)(i32 noundef %[[ADD]])
// CHECK: %[[MOD:.*]] = urem i32 %[[NURI_2]], 10
// CHECK: call void @hlsl::RWBuffer<float>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}}, i32 noundef 0, i32 noundef 0, i32 noundef 10, i32 noundef %[[MOD]], ptr noundef @A.str)
float b = A[NonUniformResourceIndex(GI + 1) % 10][0];

// CHECK: %[[GI:.*]] = load i32, ptr %GI.addr
// CHECK: %[[NURI_3:.*]] = call {{.*}} i32 @hlsl::NonUniformResourceIndex(unsigned int)(i32 noundef %[[GI]])
// CHECK: %[[MUL:.*]] = mul i32 3, %[[NURI_3]]
// CHECK: %[[ADD2:.*]] = add i32 10, %[[MUL]]
// CHECK: call void @hlsl::RWBuffer<float>::__createFromImplicitBinding(unsigned int, unsigned int, int, unsigned int, char const*)
// CHECK-SAME: (ptr {{.*}}, i32 noundef 0, i32 noundef 0, i32 noundef 10, i32 noundef %[[ADD2]], ptr noundef @A.str)
float c = A[10 + 3 * NonUniformResourceIndex(GI)][0];
A[0][0] = a + b + c;
}

// CHECK: define {{.*}} i32 @hlsl::NonUniformResourceIndex(unsigned int)(i32 noundef %Index)
// CHECK: %[[INDEX1:.*]] = load i32, ptr %Index.addr, align 4
// DXIL: %[[INDEX2:.*]] = call i32 @llvm.dx.resource.nonuniformindex(i32 %[[INDEX1]])
// SPV: %[[INDEX2:.*]] = call i32 @llvm.spv.resource.nonuniformindex(i32 %[[INDEX1]])
// CHECK: ret i32 %[[INDEX2]]