-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[HLSL] Implement WaveReadLaneAt
intrinsic
#111010
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
Changes from 2 commits
7008964
e8c5dba
1b0746f
473150d
484b208
dc3fc0b
5a2c594
32f1015
906f105
1fc05b6
f181e27
49edfec
dd73a1e
8a75558
78f7e5d
087191d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18835,6 +18835,22 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: { | |
Intrinsic::ID ID = CGM.getHLSLRuntime().getWaveIsFirstLaneIntrinsic(); | ||
return EmitRuntimeCall(Intrinsic::getDeclaration(&CGM.getModule(), ID)); | ||
} | ||
case Builtin::BI__builtin_hlsl_wave_read_lane_at: { | ||
// Due to the use of variadic arguments we must explicitly retreive them and | ||
// create our function type. | ||
Value *OpExpr = EmitScalarExpr(E->getArg(0)); | ||
Value *OpIndex = EmitScalarExpr(E->getArg(1)); | ||
llvm::FunctionType *FT = llvm::FunctionType::get( | ||
OpExpr->getType(), ArrayRef{OpExpr->getType(), OpIndex->getType()}, | ||
false); | ||
|
||
// Get overloaded name | ||
std::string name = | ||
Intrinsic::getName(CGM.getHLSLRuntime().getWaveReadLaneAtIntrinsic(), | ||
ArrayRef{OpExpr->getType()}, &CGM.getModule()); | ||
return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, name, {}, false, true), | ||
ArrayRef{OpExpr, OpIndex}, "hlsl.wave.read.lane.at"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The string we used for There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think I can change the name to |
||
} | ||
case Builtin::BI__builtin_hlsl_elementwise_sign: { | ||
Value *Op0 = EmitScalarExpr(E->getArg(0)); | ||
llvm::Type *Xty = Op0->getType(); | ||
|
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ | ||
// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -disable-llvm-passes -o - | \ | ||
// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-DXIL | ||
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -x hlsl -triple \ | ||
// RUN: spirv-pc-vulkan-compute %s -emit-llvm -disable-llvm-passes -o - | \ | ||
// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV | ||
|
||
// Test basic lowering to runtime function call. | ||
|
||
// CHECK-LABEL: test_int | ||
int test_int(int expr, uint idx) { | ||
// CHECK-SPIRV: %[[#entry_tok:]] = call token @llvm.experimental.convergence.entry() | ||
|
||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.read.lane.at.i32([[TY]] %[[#]], i32 %[[#]]) | ||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.read.lane.at.i32([[TY]] %[[#]], i32 %[[#]]) | ||
|
||
// CHECK: ret [[TY]] %[[RET]] | ||
return WaveReadLaneAt(expr, idx); | ||
} | ||
|
||
// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.read.lane.at.i32([[TY]], i32) #[[#attr:]] | ||
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.read.lane.at.i32([[TY]], i32) #[[#attr:]] | ||
|
||
// Test basic lowering to runtime function call with array and float value. | ||
|
||
// CHECK-LABEL: test_floatv4 | ||
float4 test_floatv4(float4 expr, uint idx) { | ||
// CHECK-SPIRV: %[[#entry_tok1:]] = call token @llvm.experimental.convergence.entry() | ||
|
||
// CHECK-SPIRV: %[[RET1:.*]] = call [[TY1:.*]] @llvm.spv.wave.read.lane.at.v4f32([[TY1]] %[[#]], i32 %[[#]]) | ||
// CHECK-DXIL: %[[RET1:.*]] = call [[TY1:.*]] @llvm.dx.wave.read.lane.at.v4f32([[TY1]] %[[#]], i32 %[[#]]) | ||
|
||
// CHECK: ret [[TY1]] %[[RET1]] | ||
return WaveReadLaneAt(expr, idx); | ||
} | ||
|
||
// CHECK-DXIL: declare [[TY1]] @llvm.dx.wave.read.lane.at.v4f32([[TY1]], i32) #[[#attr]] | ||
// CHECK-SPIRV: declare [[TY1]] @llvm.spv.wave.read.lane.at.v4f32([[TY1]], i32) #[[#attr]] | ||
|
||
// CHECK: attributes #[[#attr]] = {{{.*}} convergent {{.*}}} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -fnative-half-type -emit-llvm-only -disable-llvm-passes -verify -verify-ignore-unexpected | ||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
bool test_too_few_arg() { | ||
return __builtin_hlsl_wave_read_lane_at(); | ||
// expected-error@-1 {{too few arguments to function call, expected 2, have 0}} | ||
} | ||
|
||
float2 test_too_few_arg_1(float2 p0) { | ||
return __builtin_hlsl_wave_read_lane_at(p0); | ||
// expected-error@-1 {{too few arguments to function call, expected 2, have 1}} | ||
} | ||
|
||
float2 test_too_many_arg(float2 p0) { | ||
return __builtin_hlsl_wave_read_lane_at(p0, p0, p0); | ||
// expected-error@-1 {{too many arguments to function call, expected 2, have 3}} | ||
} | ||
|
||
float3 test_index_type_check(float3 p0, double idx) { | ||
return __builtin_hlsl_wave_read_lane_at(p0, idx); | ||
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'unsigned int'}} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -82,5 +82,6 @@ let TargetPrefix = "spv" in { | |
[llvm_anyint_ty, LLVMScalarOrSameVectorWidth<0, LLVMVectorElementType<0>>], | ||
[IntrNoMem, Commutative] >; | ||
def int_spv_wave_is_first_lane : DefaultAttrsIntrinsic<[llvm_i1_ty], [], [IntrConvergent]>; | ||
def int_spv_wave_read_lane_at : DefaultAttrsIntrinsic<[llvm_any_ty], [LLVMMatchType<0>, llvm_i32_ty], [IntrConvergent]>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Probably should update There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a commit to change the name to |
||
def int_spv_sign : DefaultAttrsIntrinsic<[LLVMScalarOrSameVectorWidth<0, llvm_i32_ty>], [llvm_any_ty]>; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
; RUN: opt -S -dxil-op-lower -mtriple=dxil-pc-shadermodel6.3-compute %s | FileCheck %s | ||
|
||
; Test that for scalar values, WaveReadLaneAt maps down to the DirectX op | ||
|
||
define noundef half @wave_rla_half(half noundef %expr, i32 noundef %idx) #0 { | ||
entry: | ||
; CHECK: call half @dx.op.waveReadLaneAt.f16(i32 117, half %expr, i32 %idx) | ||
%ret = call half @llvm.dx.wave.read.lane.at.f16(half %expr, i32 %idx) | ||
ret half %ret | ||
} | ||
|
||
define noundef float @wave_rla_float(float noundef %expr, i32 noundef %idx) #0 { | ||
entry: | ||
; CHECK: call float @dx.op.waveReadLaneAt.f32(i32 117, float %expr, i32 %idx) | ||
%ret = call float @llvm.dx.wave.read.lane.at(float %expr, i32 %idx) | ||
ret float %ret | ||
} | ||
|
||
define noundef double @wave_rla_double(double noundef %expr, i32 noundef %idx) #0 { | ||
entry: | ||
; CHECK: call double @dx.op.waveReadLaneAt.f64(i32 117, double %expr, i32 %idx) | ||
%ret = call double @llvm.dx.wave.read.lane.at(double %expr, i32 %idx) | ||
ret double %ret | ||
} | ||
|
||
define noundef i1 @wave_rla_i1(i1 noundef %expr, i32 noundef %idx) #0 { | ||
entry: | ||
; CHECK: call i1 @dx.op.waveReadLaneAt.i1(i32 117, i1 %expr, i32 %idx) | ||
%ret = call i1 @llvm.dx.wave.read.lane.at.i1(i1 %expr, i32 %idx) | ||
ret i1 %ret | ||
} | ||
|
||
define noundef i16 @wave_rla_i16(i16 noundef %expr, i32 noundef %idx) #0 { | ||
entry: | ||
; CHECK: call i16 @dx.op.waveReadLaneAt.i16(i32 117, i16 %expr, i32 %idx) | ||
%ret = call i16 @llvm.dx.wave.read.lane.at.i16(i16 %expr, i32 %idx) | ||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ret i16 %ret | ||
} | ||
|
||
define noundef i32 @wave_rla_i32(i32 noundef %expr, i32 noundef %idx) #0 { | ||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
entry: | ||
; CHECK: call i32 @dx.op.waveReadLaneAt.i32(i32 117, i32 %expr, i32 %idx) | ||
%ret = call i32 @llvm.dx.wave.read.lane.at.i32(i32 %expr, i32 %idx) | ||
ret i32 %ret | ||
} | ||
|
||
declare half @llvm.dx.wave.read.lane.at.f16(half, i32) #1 | ||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
declare float @llvm.dx.wave.read.lane.at.f32(float, i32) #1 | ||
declare double @llvm.dx.wave.read.lane.at.f64(double, i32) #1 | ||
|
||
declare i1 @llvm.dx.wave.read.lane.at.i1(i1, i32) #1 | ||
declare i16 @llvm.dx.wave.read.lane.at.i16(i16, i32) #1 | ||
declare i32 @llvm.dx.wave.read.lane.at.i32(i32, i32) #1 | ||
|
||
attributes #0 = { norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } | ||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
attributes #1 = { nocallback nofree nosync nounwind willreturn } |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32v1.3-vulkan-unknown %s -o - | FileCheck %s | ||
; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan-unknown %s -o - -filetype=obj | spirv-val %} | ||
|
||
; Test lowering to spir-v backend | ||
|
||
; CHECK-DAG: %[[#uint:]] = OpTypeInt 32 0 | ||
; CHECK-DAG: %[[#scope:]] = OpConstant %[[#uint]] 2 | ||
; CHECK-DAG: %[[#f32:]] = OpTypeFloat 32 | ||
; CHECK-DAG: %[[#expr:]] = OpFunctionParameter %[[#f32]] | ||
; CHECK-DAG: %[[#idx:]] = OpFunctionParameter %[[#uint]] | ||
|
||
define spir_func void @test_1(float %expr, i32 %idx) #0 { | ||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
entry: | ||
%0 = call token @llvm.experimental.convergence.entry() | ||
; CHECK: %[[#ret:]] = OpGroupNonUniformShuffle %[[#f32]] %[[#expr]] %[[#idx]] %[[#scope]] | ||
%1 = call float @llvm.spv.wave.read.lane.at(float %expr, i32 %idx) [ "convergencectrl"(token %0) ] | ||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
ret void | ||
} | ||
|
||
declare i32 @__hlsl_wave_get_lane_index() #1 | ||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
attributes #0 = { convergent norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } | ||
inbelic marked this conversation as resolved.
Show resolved
Hide resolved
|
||
attributes #1 = { convergent } | ||
|
||
!llvm.module.flags = !{!0, !1} | ||
|
||
!0 = !{i32 1, !"wchar_size", i32 4} | ||
!1 = !{i32 4, !"dx.disable_optimizations", i32 1} |
Uh oh!
There was an error while loading. Please reload this page.