-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[HLSL] Implement the fwidth intrinsic for DXIL and SPIR-V target
#161378
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 1 commit
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 |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple dxil-pc-shadermodel6.3-library %s \ | ||
| // RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \ | ||
| // RUN: FileCheck %s --check-prefixes=CHECK | ||
| // RUN: %clang_cc1 -finclude-default-header -x hlsl -triple spirv-pc-vulkan-compute %s \ | ||
| // RUN: -emit-llvm -disable-llvm-passes -fnative-half-type -o - | \ | ||
| // RUN: FileCheck %s --check-prefixes=CHECK-SPIRV | ||
|
|
||
| // CHECK-LABEL: define {{.*}} half @_ZN4hlsl8__detail11fwidth_implIDhEET_S2_ | ||
| // CHECK: %hlsl.ddx.coarse = call {{.*}} half @llvm.dx.ddx.coarse.f16(half %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} half @llvm.fabs.f16(half %{{.*}}) | ||
| // CHECK: %hlsl.ddy.coarse = call {{.*}} half @llvm.dx.ddy.coarse.f16(half %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} half @llvm.fabs.f16(half %{{.*}}) | ||
| // CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}} | ||
| // CHECK: ret half %{{.*}} | ||
| // CHECK-LABEL-SPIRV: half @_Z15test_f16_fwidthDh | ||
| // CHECK-SPIRV: %spv.fwidth = call {{.*}} half @llvm.spv.fwidth.f16(half %{{.*}}) | ||
| // CHECK-SPIRV: ret half %spv.fwidth | ||
| half test_f16_fwidth(half val) { | ||
| return fwidth(val); | ||
| } | ||
|
|
||
| // CHECK-LABEL: define {{.*}} <2 x half> @_ZN4hlsl8__detail11fwidth_implIDv2_DhEET_S3_ | ||
| // CHECK: %hlsl.ddx.coarse = call {{.*}} <2 x half> @llvm.dx.ddx.coarse.v2f16(<2 x half> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <2 x half> @llvm.fabs.v2f16(<2 x half> %{{.*}}) | ||
| // CHECK: %hlsl.ddy.coarse = call {{.*}} <2 x half> @llvm.dx.ddy.coarse.v2f16(<2 x half> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <2 x half> @llvm.fabs.v2f16(<2 x half> %{{.*}}) | ||
| // CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}} | ||
| // CHECK: ret <2 x half> %{{.*}} | ||
| // CHECK-LABEL-SPIRV: <2 x half> @_Z16test_f16_fwidth2Dv2_Dh | ||
| // CHECK-SPIRV: %spv.fwidth = call {{.*}} <2 x half> @llvm.spv.fwidth.v2f16(<2 x half> %{{.*}}) | ||
| // CHECK-SPIRV: ret <2 x half> %spv.fwidth | ||
| half2 test_f16_fwidth2(half2 val) { | ||
| return fwidth(val); | ||
| } | ||
|
|
||
| // CHECK-LABEL: define {{.*}} <3 x half> @_ZN4hlsl8__detail11fwidth_implIDv3_DhEET_S3_ | ||
| // CHECK: %hlsl.ddx.coarse = call {{.*}} <3 x half> @llvm.dx.ddx.coarse.v3f16(<3 x half> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <3 x half> @llvm.fabs.v3f16(<3 x half> %{{.*}}) | ||
| // CHECK: %hlsl.ddy.coarse = call {{.*}} <3 x half> @llvm.dx.ddy.coarse.v3f16(<3 x half> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <3 x half> @llvm.fabs.v3f16(<3 x half> %{{.*}}) | ||
| // CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}} | ||
| // CHECK: ret <3 x half> %{{.*}} | ||
| // CHECK-LABEL-SPIRV: <3 x half> @_Z16test_f16_fwidth3Dv3_Dh | ||
| // CHECK-SPIRV: %spv.fwidth = call {{.*}} <3 x half> @llvm.spv.fwidth.v3f16(<3 x half> %{{.*}}) | ||
| // CHECK-SPIRV: ret <3 x half> %spv.fwidth | ||
| half3 test_f16_fwidth3(half3 val) { | ||
| return fwidth(val); | ||
| } | ||
|
|
||
| // CHECK-LABEL: define {{.*}} <4 x half> @_ZN4hlsl8__detail11fwidth_implIDv4_DhEET_S3_ | ||
| // CHECK: %hlsl.ddx.coarse = call {{.*}} <4 x half> @llvm.dx.ddx.coarse.v4f16(<4 x half> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <4 x half> @llvm.fabs.v4f16(<4 x half> %{{.*}}) | ||
| // CHECK: %hlsl.ddy.coarse = call {{.*}} <4 x half> @llvm.dx.ddy.coarse.v4f16(<4 x half> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <4 x half> @llvm.fabs.v4f16(<4 x half> %{{.*}}) | ||
| // CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}} | ||
| // CHECK: ret <4 x half> %{{.*}} | ||
| // CHECK-LABEL-SPIRV: <4 x half> @_Z16test_f16_fwidth4Dv4_Dh | ||
| // CHECK-SPIRV: %spv.fwidth = call {{.*}} <4 x half> @llvm.spv.fwidth.v4f16(<4 x half> %{{.*}}) | ||
| // CHECK-SPIRV: ret <4 x half> %spv.fwidth | ||
| half4 test_f16_fwidth4(half4 val) { | ||
| return fwidth(val); | ||
| } | ||
|
|
||
| // CHECK-LABEL: define {{.*}} float @_ZN4hlsl8__detail11fwidth_implIfEET_S2_ | ||
| // CHECK: %hlsl.ddx.coarse = call {{.*}} float @llvm.dx.ddx.coarse.f32(float %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} float @llvm.fabs.f32(float %{{.*}}) | ||
| // CHECK: %hlsl.ddy.coarse = call {{.*}} float @llvm.dx.ddy.coarse.f32(float %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} float @llvm.fabs.f32(float %{{.*}}) | ||
| // CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}} | ||
| // CHECK: ret float %{{.*}} | ||
| // CHECK-LABEL-SPIRV: float @_Z15test_f32_fwidthf | ||
| // CHECK-SPIRV: %spv.fwidth = call {{.*}} float @llvm.spv.fwidth.f32(float %{{.*}}) | ||
| // CHECK-SPIRV: ret float %spv.fwidth | ||
| float test_f32_fwidth(float val) { | ||
| return fwidth(val); | ||
| } | ||
|
|
||
| // CHECK-LABEL: define {{.*}} <2 x float> @_ZN4hlsl8__detail11fwidth_implIDv2_fEET_S3_ | ||
| // CHECK: %hlsl.ddx.coarse = call {{.*}} <2 x float> @llvm.dx.ddx.coarse.v2f32(<2 x float> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <2 x float> @llvm.fabs.v2f32(<2 x float> %{{.*}}) | ||
| // CHECK: %hlsl.ddy.coarse = call {{.*}} <2 x float> @llvm.dx.ddy.coarse.v2f32(<2 x float> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <2 x float> @llvm.fabs.v2f32(<2 x float> %{{.*}}) | ||
| // CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}} | ||
| // CHECK: ret <2 x float> %{{.*}} | ||
| // CHECK-LABEL-SPIRV: <2 x float> @_Z16test_f32_fwidth2Dv2_f | ||
| // CHECK-SPIRV: %spv.fwidth = call {{.*}} <2 x float> @llvm.spv.fwidth.v2f32(<2 x float> %{{.*}}) | ||
| // CHECK-SPIRV: ret <2 x float> %spv.fwidth | ||
| float2 test_f32_fwidth2(float2 val) { | ||
| return fwidth(val); | ||
| } | ||
|
|
||
| // CHECK-LABEL: define {{.*}} <3 x float> @_ZN4hlsl8__detail11fwidth_implIDv3_fEET_S3_ | ||
| // CHECK: %hlsl.ddx.coarse = call {{.*}} <3 x float> @llvm.dx.ddx.coarse.v3f32(<3 x float> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <3 x float> @llvm.fabs.v3f32(<3 x float> %{{.*}}) | ||
| // CHECK: %hlsl.ddy.coarse = call {{.*}} <3 x float> @llvm.dx.ddy.coarse.v3f32(<3 x float> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <3 x float> @llvm.fabs.v3f32(<3 x float> %{{.*}}) | ||
| // CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}} | ||
| // CHECK: ret <3 x float> %{{.*}} | ||
| // CHECK-LABEL-SPIRV: <3 x float> @_Z16test_f32_fwidth3Dv3_f | ||
| // CHECK-SPIRV: %spv.fwidth = call {{.*}} <3 x float> @llvm.spv.fwidth.v3f32(<3 x float> %{{.*}}) | ||
| // CHECK-SPIRV: ret <3 x float> %spv.fwidth | ||
| float3 test_f32_fwidth3(float3 val) { | ||
| return fwidth(val); | ||
| } | ||
|
|
||
| // CHECK-LABEL: define {{.*}} <4 x float> @_ZN4hlsl8__detail11fwidth_implIDv4_fEET_S3_ | ||
| // CHECK: %hlsl.ddx.coarse = call {{.*}} <4 x float> @llvm.dx.ddx.coarse.v4f32(<4 x float> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <4 x float> @llvm.fabs.v4f32(<4 x float> %{{.*}}) | ||
| // CHECK: %hlsl.ddy.coarse = call {{.*}} <4 x float> @llvm.dx.ddy.coarse.v4f32(<4 x float> %{{.*}}) | ||
| // CHECK: %{{.*}} = call {{.*}} <4 x float> @llvm.fabs.v4f32(<4 x float> %{{.*}}) | ||
| // CHECK: %{{.*}} = fadd {{.*}} %{{.*}}, %{{.*}} | ||
| // CHECK: ret <4 x float> %{{.*}} | ||
| // CHECK-LABEL-SPIRV: <4 x float> @_Z16test_f32_fwidth4Dv4_f | ||
| // CHECK-SPIRV: %spv.fwidth = call {{.*}} <4 x float> @llvm.spv.fwidth.v4f32(<4 x float> %{{.*}}) | ||
| // CHECK-SPIRV: ret <4 x float> %spv.fwidth | ||
| float4 test_f32_fwidth4(float4 val) { | ||
| return fwidth(val); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| // RUN: %clang_cc1 -O1 -triple spirv-pc-vulkan-compute %s -emit-llvm -o - | FileCheck %s | ||
|
|
||
| typedef _Float16 half; | ||
| typedef half half2 __attribute__((ext_vector_type(2))); | ||
| typedef half half3 __attribute__((ext_vector_type(3))); | ||
| typedef half half4 __attribute__((ext_vector_type(4))); | ||
| typedef float float2 __attribute__((ext_vector_type(2))); | ||
| typedef float float3 __attribute__((ext_vector_type(3))); | ||
| typedef float float4 __attribute__((ext_vector_type(4))); | ||
|
|
||
| // CHECK: [[fwidth0:%.*]] = tail call half @llvm.spv.fwidth.f16(half {{%.*}}) | ||
| // CHECK: ret half [[fwidth0]] | ||
| half test_fwidth_half(half X) { return __builtin_spirv_fwidth(X); } | ||
|
|
||
| // CHECK: [[fwidth0:%.*]] = tail call <2 x half> @llvm.spv.fwidth.v2f16(<2 x half> {{%.*}}) | ||
| // CHECK: ret <2 x half> [[fwidth0]] | ||
| half2 test_fwidth_half2(half2 X) { return __builtin_spirv_fwidth(X); } | ||
|
|
||
| // CHECK: [[fwidth0:%.*]] = tail call <3 x half> @llvm.spv.fwidth.v3f16(<3 x half> {{%.*}}) | ||
| // CHECK: ret <3 x half> [[fwidth0]] | ||
| half3 test_fwidth_half3(half3 X) { return __builtin_spirv_fwidth(X); } | ||
|
|
||
| // CHECK: [[fwidth0:%.*]] = tail call <4 x half> @llvm.spv.fwidth.v4f16(<4 x half> {{%.*}}) | ||
| // CHECK: ret <4 x half> [[fwidth0]] | ||
| half4 test_fwidth_half4(half4 X) { return __builtin_spirv_fwidth(X); } | ||
|
|
||
| // CHECK: [[fwidth0:%.*]] = tail call float @llvm.spv.fwidth.f32(float {{%.*}}) | ||
| // CHECK: ret float [[fwidth0]] | ||
| float test_fwidth_float(float X) { return __builtin_spirv_fwidth(X); } | ||
|
|
||
| // CHECK: [[fwidth1:%.*]] = tail call <2 x float> @llvm.spv.fwidth.v2f32(<2 x float> {{%.*}}) | ||
| // CHECK: ret <2 x float> [[fwidth1]] | ||
| float2 test_fwidth_float2(float2 X) { return __builtin_spirv_fwidth(X); } | ||
|
|
||
| // CHECK: [[fwidth2:%.*]] = tail call <3 x float> @llvm.spv.fwidth.v3f32(<3 x float> {{%.*}}) | ||
| // CHECK: ret <3 x float> [[fwidth2]] | ||
| float3 test_fwidth_float3(float3 X) { return __builtin_spirv_fwidth(X); } | ||
|
|
||
| // CHECK: [[fwidth3:%.*]] = tail call <4 x float> @llvm.spv.fwidth.v4f32(<4 x float> {{%.*}}) | ||
| // CHECK: ret <4 x float> [[fwidth3]] | ||
| float4 test_fwidth_float4(float4 X) { return __builtin_spirv_fwidth(X); } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| // RUN: %clang_cc1 %s -triple spirv-pc-vulkan-compute -verify | ||
|
|
||
| typedef float float2 __attribute__((ext_vector_type(2))); | ||
|
|
||
| void test_too_few_arg() | ||
| { | ||
| return __builtin_spirv_fwidth(); | ||
| // expected-error@-1 {{too few arguments to function call, expected 1, have 0}} | ||
| } | ||
|
|
||
| float test_too_many_arg(float p0) { | ||
| return __builtin_spirv_fwidth(p0, p0); | ||
| // expected-error@-1 {{too many arguments to function call, expected 1, have 2}} | ||
| } | ||
|
|
||
| float test_int_scalar_inputs(int p0) { | ||
| return __builtin_spirv_fwidth(p0); | ||
| // expected-error@-1 {{1st argument must be a scalar or vector of floating-point types (was 'int')}} | ||
| } | ||
|
|
||
| float test_mismatched_return(float2 p0) { | ||
| return __builtin_spirv_fwidth(p0); | ||
| // expected-error@-1 {{returning 'float2' (vector of 2 'float' values) from a function with incompatible result type 'float'}} | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -328,8 +328,8 @@ class SPIRVInstructionSelector : public InstructionSelector { | |
| MachineInstr &I) const; | ||
| bool selectFrexp(Register ResVReg, const SPIRVType *ResType, | ||
| MachineInstr &I) const; | ||
| bool selectDpdCoarse(Register ResVReg, const SPIRVType *ResType, | ||
| MachineInstr &I, const unsigned DPdOpCode) const; | ||
| bool selectDerivativeInst(Register ResVReg, const SPIRVType *ResType, | ||
| MachineInstr &I, const unsigned DPdOpCode) const; | ||
| // Utilities | ||
| std::pair<Register, bool> | ||
| buildI32Constant(uint32_t Val, MachineInstr &I, | ||
|
|
@@ -3143,10 +3143,9 @@ bool SPIRVInstructionSelector::wrapIntoSpecConstantOp( | |
| return Result; | ||
| } | ||
|
|
||
| bool SPIRVInstructionSelector::selectDpdCoarse(Register ResVReg, | ||
| const SPIRVType *ResType, | ||
| MachineInstr &I, | ||
| const unsigned DPdOpCode) const { | ||
| bool SPIRVInstructionSelector::selectDerivativeInst( | ||
| Register ResVReg, const SPIRVType *ResType, MachineInstr &I, | ||
| const unsigned DPdOpCode) const { | ||
| // TODO: This should check specifically for Fragment Execution Model, but STI | ||
| // doesn't provide that information yet. See #167562 | ||
| errorIfInstrOutsideShader(I); | ||
|
|
@@ -3584,10 +3583,13 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg, | |
| return selectExtInst(ResVReg, ResType, I, GL::UnpackHalf2x16); | ||
| } | ||
| case Intrinsic::spv_ddx_coarse: { | ||
| return selectDpdCoarse(ResVReg, ResType, I, SPIRV::OpDPdxCoarse); | ||
| return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdxCoarse); | ||
| } | ||
| case Intrinsic::spv_ddy_coarse: { | ||
| return selectDpdCoarse(ResVReg, ResType, I, SPIRV::OpDPdyCoarse); | ||
| return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpDPdyCoarse); | ||
| } | ||
| case Intrinsic::spv_fwidth: { | ||
| return selectDerivativeInst(ResVReg, ResType, I, SPIRV::OpFwidth); | ||
|
Comment on lines
3587
to
3590
Member
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. This file is inconsistent but some of these single return case statements don't have curly braces |
||
| } | ||
| default: { | ||
| std::string DiagMsg; | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| ; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-vulkan %s -o - | FileCheck %s | ||
| ; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-vulkan %s -o - -filetype=obj | spirv-val %} | ||
|
|
||
| ; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32 | ||
| ; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16 | ||
|
|
||
| ; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4 | ||
| ; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4 | ||
|
|
||
| define noundef float @fwidth_float(float noundef %a) { | ||
| entry: | ||
| ; CHECK: %[[#float_32_arg:]] = OpFunctionParameter %[[#float_32]] | ||
| ; CHECK: %[[#]] = OpFwidth %[[#float_32]] %[[#float_32_arg]] | ||
| %elt.fwidth = call float @llvm.spv.fwidth.f32(float %a) | ||
| ret float %elt.fwidth | ||
| } | ||
|
|
||
| define noundef half @fwidth_half(half noundef %a) { | ||
| entry: | ||
| ; CHECK: %[[#float_16_arg:]] = OpFunctionParameter %[[#float_16]] | ||
| ; CHECK: %[[#converted:]] = OpFConvert %[[#float_32]] %[[#float_16_arg]] | ||
| ; CHECK: %[[#fwidth:]] = OpFwidth %[[#float_32]] %[[#converted]] | ||
| ; CHECK: %[[#]] = OpFConvert %[[#float_16]] %[[#fwidth]] | ||
| %elt.fwidth = call half @llvm.spv.fwidth.f16(half %a) | ||
| ret half %elt.fwidth | ||
| } | ||
|
|
||
| define noundef <4 x float> @fwidth_float_vector(<4 x float> noundef %a) { | ||
| entry: | ||
| ; CHECK: %[[#vec4_float_32_arg:]] = OpFunctionParameter %[[#vec4_float_32]] | ||
| ; CHECK: %[[#]] = OpFwidth %[[#vec4_float_32]] %[[#vec4_float_32_arg]] | ||
| %elt.fwidth = call <4 x float> @llvm.spv.fwidth.v4f32(<4 x float> %a) | ||
| ret <4 x float> %elt.fwidth | ||
| } | ||
|
|
||
| define noundef <4 x half> @fwidth_half_vector(<4 x half> noundef %a) { | ||
| entry: | ||
| ; CHECK: %[[#vec4_float_16_arg:]] = OpFunctionParameter %[[#vec4_float_16]] | ||
| ; CHECK: %[[#converted:]] = OpFConvert %[[#vec4_float_32]] %[[#vec4_float_16_arg]] | ||
| ; CHECK: %[[#fwidth:]] = OpFwidth %[[#vec4_float_32]] %[[#converted]] | ||
| ; CHECK: %[[#]] = OpFConvert %[[#vec4_float_16]] %[[#fwidth]] | ||
| %elt.fwidth = call <4 x half> @llvm.spv.fwidth.v4f16(<4 x half> %a) | ||
| ret <4 x half> %elt.fwidth | ||
| } | ||
|
|
||
| declare float @llvm.spv.fwidth.f32(float) | ||
| declare half @llvm.spv.fwidth.f16(half) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it is a bit odd this is compute
-triple spirv-pc-vulkan-computebut I suppose this is fine since we are doing-emit-llvm.