diff --git a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h index 4eb7b8f45c85a..e1996fd3e30ed 100644 --- a/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h +++ b/clang/lib/Headers/hlsl/hlsl_intrinsic_helpers.h @@ -127,11 +127,7 @@ template constexpr vector lit_impl(T NDotL, T NDotH, T M) { } template constexpr T faceforward_impl(T N, T I, T Ng) { -#if (__has_builtin(__builtin_spirv_faceforward)) - return __builtin_spirv_faceforward(N, I, Ng); -#else return select(dot(I, Ng) < 0, N, -N); -#endif } template constexpr T ldexp_impl(T X, T Exp) { diff --git a/clang/test/CodeGenHLSL/builtins/faceforward.hlsl b/clang/test/CodeGenHLSL/builtins/faceforward.hlsl index d2ece57aba4ae..f12f75f384964 100644 --- a/clang/test/CodeGenHLSL/builtins/faceforward.hlsl +++ b/clang/test/CodeGenHLSL/builtins/faceforward.hlsl @@ -12,8 +12,11 @@ // CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, half %{{.*}}, half %fneg.i // CHECK: ret half %hlsl.select.i // SPVCHECK-LABEL: test_faceforward_half -// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef half @llvm.spv.faceforward.f16(half %{{.*}}, half %{{.*}}, half %{{.*}}) -// SPVCHECK: ret half %spv.faceforward.i +// SPVCHECK: %hlsl.dot.i = fmul reassoc nnan ninf nsz arcp afn half %{{.*}}, %{{.*}} +// SPVCHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000 +// SPVCHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn half %{{.*}} +// SPVCHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, half %{{.*}}, half %fneg.i +// SPVCHECK: ret half %hlsl.select.i half test_faceforward_half(half N, half I, half Ng) { return faceforward(N, I, Ng); } // CHECK-LABEL: test_faceforward_half2 @@ -23,8 +26,11 @@ half test_faceforward_half(half N, half I, half Ng) { return faceforward(N, I, N // CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <2 x half> %{{.*}}, <2 x half> %fneg.i // CHECK: ret <2 x half> %hlsl.select.i // SPVCHECK-LABEL: test_faceforward_half2 -// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <2 x half> @llvm.spv.faceforward.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}, <2 x half> %{{.*}}) -// SPVCHECK: ret <2 x half> %spv.faceforward.i +// SPVCHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v2f16(<2 x half> %{{.*}}, <2 x half> %{{.*}}) +// SPVCHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000 +// SPVCHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <2 x half> %{{.*}} +// SPVCHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <2 x half> %{{.*}}, <2 x half> %fneg.i +// SPVCHECK: ret <2 x half> %hlsl.select.i half2 test_faceforward_half2(half2 N, half2 I, half2 Ng) { return faceforward(N, I, Ng); } // CHECK-LABEL: test_faceforward_half3 @@ -34,8 +40,11 @@ half2 test_faceforward_half2(half2 N, half2 I, half2 Ng) { return faceforward(N, // CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <3 x half> %{{.*}}, <3 x half> %fneg.i // CHECK: ret <3 x half> %hlsl.select.i // SPVCHECK-LABEL: test_faceforward_half3 -// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <3 x half> @llvm.spv.faceforward.v3f16(<3 x half> %{{.*}}, <3 x half> %{{.*}}, <3 x half> %{{.*}}) -// SPVCHECK: ret <3 x half> %spv.faceforward.i +// SPVCHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v3f16(<3 x half> %{{.*}}, <3 x half> %{{.*}}) +// SPVCHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000 +// SPVCHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <3 x half> %{{.*}} +// SPVCHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <3 x half> %{{.*}}, <3 x half> %fneg.i +// SPVCHECK: ret <3 x half> %hlsl.select.i half3 test_faceforward_half3(half3 N, half3 I, half3 Ng) { return faceforward(N, I, Ng); } // CHECK-LABEL: test_faceforward_half4 @@ -45,8 +54,11 @@ half3 test_faceforward_half3(half3 N, half3 I, half3 Ng) { return faceforward(N, // CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <4 x half> %{{.*}}, <4 x half> %fneg.i // CHECK: ret <4 x half> %hlsl.select.i // SPVCHECK-LABEL: test_faceforward_half4 -// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <4 x half> @llvm.spv.faceforward.v4f16(<4 x half> %{{.*}}, <4 x half> %{{.*}}, <4 x half> %{{.*}}) -// SPVCHECK: ret <4 x half> %spv.faceforward.i +// SPVCHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn half @llvm.spv.fdot.v4f16(<4 x half> %{{.*}}, <4 x half> %{{.*}}) +// SPVCHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt half %hlsl.dot.i, 0xH0000 +// SPVCHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <4 x half> %{{.*}} +// SPVCHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <4 x half> %{{.*}}, <4 x half> %fneg.i +// SPVCHECK: ret <4 x half> %hlsl.select.i half4 test_faceforward_half4(half4 N, half4 I, half4 Ng) { return faceforward(N, I, Ng); } // CHECK-LABEL: test_faceforward_float @@ -56,8 +68,11 @@ half4 test_faceforward_half4(half4 N, half4 I, half4 Ng) { return faceforward(N, // CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, float %{{.*}}, float %fneg.i // CHECK: ret float %hlsl.select.i // SPVCHECK-LABEL: test_faceforward_float -// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef float @llvm.spv.faceforward.f32(float %{{.*}}, float %{{.*}}, float %{{.*}}) -// SPVCHECK: ret float %spv.faceforward.i +// SPVCHECK: %hlsl.dot.i = fmul reassoc nnan ninf nsz arcp afn float %{{.*}}, %{{.*}} +// SPVCHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00 +// SPVCHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn float %{{.*}} +// SPVCHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, float %{{.*}}, float %fneg.i +// SPVCHECK: ret float %hlsl.select.i float test_faceforward_float(float N, float I, float Ng) { return faceforward(N, I, Ng); } // CHECK-LABEL: test_faceforward_float2 @@ -67,8 +82,11 @@ float test_faceforward_float(float N, float I, float Ng) { return faceforward(N, // CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <2 x float> %{{.*}}, <2 x float> %fneg.i // CHECK: ret <2 x float> %hlsl.select.i // SPVCHECK-LABEL: test_faceforward_float2 -// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <2 x float> @llvm.spv.faceforward.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}) -// SPVCHECK: ret <2 x float> %spv.faceforward.i +// SPVCHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.spv.fdot.v2f32(<2 x float> %{{.*}}, <2 x float> %{{.*}}) +// SPVCHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00 +// SPVCHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <2 x float> %{{.*}} +// SPVCHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <2 x float> %{{.*}}, <2 x float> %fneg.i +// SPVCHECK: ret <2 x float> %hlsl.select.i float2 test_faceforward_float2(float2 N, float2 I, float2 Ng) { return faceforward(N, I, Ng); } // CHECK-LABEL: test_faceforward_float3 @@ -78,8 +96,11 @@ float2 test_faceforward_float2(float2 N, float2 I, float2 Ng) { return faceforwa // CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <3 x float> %{{.*}}, <3 x float> %fneg.i // CHECK: ret <3 x float> %hlsl.select.i // SPVCHECK-LABEL: test_faceforward_float3 -// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <3 x float> @llvm.spv.faceforward.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}}, <3 x float> %{{.*}}) -// SPVCHECK: ret <3 x float> %spv.faceforward.i +// SPVCHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.spv.fdot.v3f32(<3 x float> %{{.*}}, <3 x float> %{{.*}}) +// SPVCHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00 +// SPVCHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <3 x float> %{{.*}} +// SPVCHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <3 x float> %{{.*}}, <3 x float> %fneg.i +// SPVCHECK: ret <3 x float> %hlsl.select.i float3 test_faceforward_float3(float3 N, float3 I, float3 Ng) { return faceforward(N, I, Ng); } // CHECK-LABEL: test_faceforward_float4 @@ -89,6 +110,9 @@ float3 test_faceforward_float3(float3 N, float3 I, float3 Ng) { return faceforwa // CHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <4 x float> %{{.*}}, <4 x float> %fneg.i // CHECK: ret <4 x float> %hlsl.select.i // SPVCHECK-LABEL: test_faceforward_float4 -// SPVCHECK: %spv.faceforward.i = call reassoc nnan ninf nsz arcp afn noundef <4 x float> @llvm.spv.faceforward.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}, <4 x float> %{{.*}}) -// SPVCHECK: ret <4 x float> %spv.faceforward.i +// SPVCHECK: %hlsl.dot.i = call reassoc nnan ninf nsz arcp afn float @llvm.spv.fdot.v4f32(<4 x float> %{{.*}}, <4 x float> %{{.*}}) +// SPVCHECK: %cmp.i = fcmp reassoc nnan ninf nsz arcp afn olt float %hlsl.dot.i, 0.000000e+00 +// SPVCHECK: %fneg.i = fneg reassoc nnan ninf nsz arcp afn <4 x float> %{{.*}} +// SPVCHECK: %hlsl.select.i = select reassoc nnan ninf nsz arcp afn i1 %cmp.i, <4 x float> %{{.*}}, <4 x float> %fneg.i +// SPVCHECK: ret <4 x float> %hlsl.select.i float4 test_faceforward_float4(float4 N, float4 I, float4 Ng) { return faceforward(N, I, Ng); } diff --git a/llvm/lib/Target/SPIRV/SPIRVCombine.td b/llvm/lib/Target/SPIRV/SPIRVCombine.td index 6f726e024de52..78a57146e61d2 100644 --- a/llvm/lib/Target/SPIRV/SPIRVCombine.td +++ b/llvm/lib/Target/SPIRV/SPIRVCombine.td @@ -15,8 +15,15 @@ def vector_length_sub_to_distance_lowering : GICombineRule < (apply [{ applySPIRVDistance(*${root}, MRI, B); }]) >; +def vector_select_to_faceforward_lowering : GICombineRule < + (defs root:$root), + (match (wip_match_opcode G_SELECT):$root, + [{ return matchSelectToFaceForward(*${root}, MRI); }]), + (apply [{ applySPIRVFaceForward(*${root}, MRI, B); }]) +>; + def SPIRVPreLegalizerCombiner : GICombiner<"SPIRVPreLegalizerCombinerImpl", - [vector_length_sub_to_distance_lowering]> { + [vector_length_sub_to_distance_lowering, vector_select_to_faceforward_lowering]> { let CombineAllMethodName = "tryCombineAllImpl"; } diff --git a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp index c96ee6b02491a..732945645ed85 100644 --- a/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVPreLegalizerCombiner.cpp @@ -50,6 +50,18 @@ namespace { #include "SPIRVGenPreLegalizeGICombiner.inc" #undef GET_GICOMBINER_TYPES +static void removeAllUses(Register Reg, MachineRegisterInfo &MRI, + SPIRVGlobalRegistry *GR) { + SmallVector UsesToErase( + llvm::make_pointer_range(MRI.use_instructions(Reg))); + + // calling eraseFromParent too early invalidates the iterator. + for (auto *MIToErase : UsesToErase) { + GR->invalidateMachineInstr(MIToErase); + MIToErase->eraseFromParent(); + } +} + /// This match is part of a combine that /// rewrites length(X - Y) to distance(X, Y) /// (f32 (g_intrinsic length @@ -98,21 +110,110 @@ void applySPIRVDistance(MachineInstr &MI, MachineRegisterInfo &MRI, SPIRVGlobalRegistry *GR = MI.getMF()->getSubtarget().getSPIRVGlobalRegistry(); - auto RemoveAllUses = [&](Register Reg) { - SmallVector UsesToErase( - llvm::make_pointer_range(MRI.use_instructions(Reg))); - - // calling eraseFromParent to early invalidates the iterator. - for (auto *MIToErase : UsesToErase) { - GR->invalidateMachineInstr(MIToErase); - MIToErase->eraseFromParent(); - } - }; - RemoveAllUses(SubDestReg); // remove all uses of FSUB Result + removeAllUses(SubDestReg, MRI, GR); // remove all uses of FSUB Result GR->invalidateMachineInstr(SubInstr); SubInstr->eraseFromParent(); // remove FSUB instruction } +/// This match is part of a combine that +/// rewrites select(fcmp(dot(I, Ng), 0), N, 0 - N) to faceforward(N, I, Ng) +/// (vXf32 (g_select +/// (g_fcmp +/// (g_intrinsic dot(vXf32 I) (vXf32 Ng) +/// 0) +/// (vXf32 N) +/// (vXf32 g_fsub (0) (vXf32 N)))) +/// -> +/// (vXf32 (g_intrinsic faceforward +/// (vXf32 N) (vXf32 I) (vXf32 Ng))) +/// +/// This only works for Vulkan targets. +/// +bool matchSelectToFaceForward(MachineInstr &MI, MachineRegisterInfo &MRI) { + const SPIRVSubtarget &ST = MI.getMF()->getSubtarget(); + if (!ST.isVulkanEnv()) + return false; + + if (MI.getOpcode() != TargetOpcode::G_SELECT) + return false; + + // Check if select's condition is a comparison between a dot product and 0. + Register CondReg = MI.getOperand(1).getReg(); + MachineInstr *CondInstr = MRI.getVRegDef(CondReg); + if (!CondInstr || CondInstr->getOpcode() != TargetOpcode::G_FCMP) + return false; + + Register DotReg = CondInstr->getOperand(2).getReg(); + MachineInstr *DotInstr = MRI.getVRegDef(DotReg); + if ((DotInstr->getOpcode() != TargetOpcode::G_INTRINSIC || + cast(DotInstr)->getIntrinsicID() != Intrinsic::spv_fdot)) { + if (DotInstr->getOpcode() != TargetOpcode::G_FMUL) + return false; + Register DotOperand1 = DotInstr->getOperand(1).getReg(); + Register DotOperand2 = DotInstr->getOperand(2).getReg(); + if (MRI.getType(DotOperand1).isVector() || + MRI.getType(DotOperand2).isVector()) + return false; + } + + Register CondZeroReg = CondInstr->getOperand(3).getReg(); + MachineInstr *CondZeroInstr = MRI.getVRegDef(CondZeroReg); + if (CondZeroInstr->getOpcode() != TargetOpcode::G_FCONSTANT || + !CondZeroInstr->getOperand(1).getFPImm()->isZero()) + return false; + + // Check if select's false operand is the negation of the true operand. + Register TrueReg = MI.getOperand(2).getReg(); + Register FalseReg = MI.getOperand(3).getReg(); + MachineInstr *FalseInstr = MRI.getVRegDef(FalseReg); + if (FalseInstr->getOpcode() != TargetOpcode::G_FNEG) + return false; + if (TrueReg != FalseInstr->getOperand(1).getReg()) + return false; + + return true; +} +void applySPIRVFaceForward(MachineInstr &MI, MachineRegisterInfo &MRI, + MachineIRBuilder &B) { + + // Extract the operands for N, I, and Ng from the match criteria. + Register CondReg = MI.getOperand(1).getReg(); + MachineInstr *CondInstr = MRI.getVRegDef(CondReg); + Register DotReg = CondInstr->getOperand(2).getReg(); + MachineInstr *DotInstr = MRI.getVRegDef(DotReg); + Register DotOperand1, DotOperand2; + if (DotInstr->getOpcode() == TargetOpcode::G_FMUL) { + DotOperand1 = DotInstr->getOperand(1).getReg(); + DotOperand2 = DotInstr->getOperand(2).getReg(); + } else { + DotOperand1 = DotInstr->getOperand(2).getReg(); + DotOperand2 = DotInstr->getOperand(3).getReg(); + } + Register TrueReg = MI.getOperand(2).getReg(); + + // Remove the original `select` instruction. + Register ResultReg = MI.getOperand(0).getReg(); + DebugLoc DL = MI.getDebugLoc(); + MachineBasicBlock &MBB = *MI.getParent(); + MachineBasicBlock::iterator InsertPt = MI.getIterator(); + + // Build the `spv_faceforward` intrinsic. + MachineInstrBuilder NewInstr = + BuildMI(MBB, InsertPt, DL, B.getTII().get(TargetOpcode::G_INTRINSIC)); + NewInstr + .addDef(ResultReg) // Result register + .addIntrinsicID(Intrinsic::spv_faceforward) // Intrinsic ID + .addUse(TrueReg) // Operand N + .addUse(DotOperand1) // Operand I + .addUse(DotOperand2); // Operand Ng + + SPIRVGlobalRegistry *GR = + MI.getMF()->getSubtarget().getSPIRVGlobalRegistry(); + removeAllUses(CondReg, MRI, GR); // remove all uses of FCMP Result + GR->invalidateMachineInstr(CondInstr); + CondInstr->eraseFromParent(); // remove FCMP instruction +} + class SPIRVPreLegalizerCombinerImpl : public Combiner { protected: const CombinerHelper Helper; diff --git a/llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-select-to-faceforward.mir b/llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-select-to-faceforward.mir new file mode 100644 index 0000000000000..dc7cc03e11613 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-select-to-faceforward.mir @@ -0,0 +1,65 @@ +# RUN: llc -verify-machineinstrs -O0 -mtriple spirv-unknown-unknown -run-pass=spirv-prelegalizer-combiner %s -o - | FileCheck %s +# REQUIRES: asserts +--- +name: faceforward_instcombine_float +tracksRegLiveness: true +legalized: true +body: | + bb.1.entry: + ; CHECK-LABEL: name: faceforward_instcombine_float + ; CHECK-NOT: %9:_(s32) = G_FCONSTANT float 0.000000e+00 + ; CHECK-NOT: %8:_(s32) = G_FMUL %1:fid, %2:fid + ; CHECK-NOT: %10:_(s1) = G_FCMP floatpred(olt), %8:_(s32), %9:_ + ; CHECK-NOT: %11:_(s32) = G_FNEG %0:fid + ; CHECK-NOT: %12:id(s32) = G_SELECT %10:_(s1), %0:fid, %11:_ + ; CHECK: %10:id(s32) = G_INTRINSIC intrinsic(@llvm.spv.faceforward), %2(s32), %3(s32), %4(s32) + ; CHECK: OpReturnValue %10(s32) + %3:type(s64) = OpTypeFloat 32 + %5:type(s64) = OpTypeFunction %3:type(s64), %3:type(s64), %3:type(s64), %3:type(s64) + OpName %0:fid(s32), 97 + OpName %1:fid(s32), 98 + OpName %2:fid(s32), 99 + %4:iid(s64) = OpFunction %3:type(s64), 0, %5:type(s64) + %0:fid(s32) = OpFunctionParameter %3:type(s64) + %1:fid(s32) = OpFunctionParameter %3:type(s64) + %2:fid(s32) = OpFunctionParameter %3:type(s64) + OpName %4:iid(s64), 1701011814, 2003988326, 1600418401, 1953721961, 1651339107, 1600482921, 1634692198, 116 + %9:_(s32) = G_FCONSTANT float 0.000000e+00 + %8:_(s32) = G_FMUL %1:fid, %2:fid + %10:_(s1) = G_FCMP floatpred(olt), %8:_(s32), %9:_ + %11:_(s32) = G_FNEG %0:fid + %12:id(s32) = G_SELECT %10:_(s1), %0:fid, %11:_ + OpReturnValue %12:id(s32) +--- +name: faceforward_instcombine_float4 +tracksRegLiveness: true +legalized: true +body: | + bb.1.entry: + ; CHECK-LABEL: name: faceforward_instcombine_float4 + ; CHECK-NOT: %10:_(s32) = G_FCONSTANT float 0.000000e+00 + ; CHECK-NOT: %9:_(s32) = G_INTRINSIC intrinsic(@llvm.spv.fdot), %1:vfid(<4 x s32>), %2:vfid(<4 x s32>) + ; CHECK-NOT: %11:_(s1) = G_FCMP floatpred(olt), %9:_(s32), %10:_ + ; CHECK-NOT: %12:_(<4 x s32>) = G_FNEG %0:vfid + ; CHECK-NOT: %13:id(<4 x s32>) = G_SELECT %11:_(s1), %0:vfid, %12:_ + ; CHECK: %11:id(<4 x s32>) = G_INTRINSIC intrinsic(@llvm.spv.faceforward), %3(<4 x s32>), %4(<4 x s32>), %5(<4 x s32>) + ; CHECK: OpReturnValue %11(<4 x s32>) + %4:type(s64) = OpTypeVector %3:type(s64), 4 + %6:type(s64) = OpTypeFunction %4:type(s64), %4:type(s64), %4:type(s64), %4:type(s64) + %3:type(s64) = OpTypeFloat 32 + OpName %0:vfid(<4 x s32>), 97 + OpName %1:vfid(<4 x s32>), 98 + OpName %2:vfid(<4 x s32>), 99 + %5:iid(s64) = OpFunction %4:type(s64), 0, %6:type(s64) + %0:vfid(<4 x s32>) = OpFunctionParameter %4:type(s64) + %1:vfid(<4 x s32>) = OpFunctionParameter %4:type(s64) + %2:vfid(<4 x s32>) = OpFunctionParameter %4:type(s64) + OpName %5:iid(s64), 1701011814, 2003988326, 1600418401, 1953721961, 1651339107, 1600482921, 1634692198, 13428 + OpDecorate %5:iid(s64), 41, 1701011814, 2003988326, 1600418401, 1953721961, 1651339107, 1600482921, 1634692198, 13428, 0 + %10:_(s32) = G_FCONSTANT float 0.000000e+00 + %9:_(s32) = G_INTRINSIC intrinsic(@llvm.spv.fdot), %1:vfid(<4 x s32>), %2:vfid(<4 x s32>) + %11:_(s1) = G_FCMP floatpred(olt), %9:_(s32), %10:_ + %12:_(<4 x s32>) = G_FNEG %0:vfid + %13:id(<4 x s32>) = G_SELECT %11:_(s1), %0:vfid, %12:_ + OpReturnValue %13:id(<4 x s32>) + diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/faceforward.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/faceforward.ll index 22742169506f2..6811f95bbab17 100644 --- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/faceforward.ll +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/faceforward.ll @@ -1,7 +1,5 @@ -; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s -; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val --target-env spv1.4 %} - -; FIXME(#136344): Change --target-env to vulkan1.3 and update this test accordingly once the issue is resolved. +; RUN: llc -O0 -verify-machineinstrs -mtriple=spirv-vulkan1.3-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-vulkan1.3-unknown %s -o - -filetype=obj | spirv-val --target-env vulkan1.3 %} ; Make sure SPIRV operation function calls for faceforward are lowered correctly. @@ -11,7 +9,7 @@ ; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32 ; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4 -define noundef half @faceforward_half(half noundef %a, half noundef %b, half noundef %c) { +define internal noundef half @faceforward_half(half noundef %a, half noundef %b, half noundef %c) { entry: ; CHECK: %[[#]] = OpFunction %[[#float_16]] None %[[#]] ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_16]] @@ -22,7 +20,7 @@ entry: ret half %spv.faceforward } -define noundef float @faceforward_float(float noundef %a, float noundef %b, float noundef %c) { +define internal noundef float @faceforward_float(float noundef %a, float noundef %b, float noundef %c) { entry: ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]] ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_32]] @@ -33,7 +31,7 @@ entry: ret float %spv.faceforward } -define noundef <4 x half> @faceforward_half4(<4 x half> noundef %a, <4 x half> noundef %b, <4 x half> noundef %c) { +define internal noundef <4 x half> @faceforward_half4(<4 x half> noundef %a, <4 x half> noundef %b, <4 x half> noundef %c) { entry: ; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]] ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]] @@ -44,7 +42,7 @@ entry: ret <4 x half> %spv.faceforward } -define noundef <4 x float> @faceforward_float4(<4 x float> noundef %a, <4 x float> noundef %b, <4 x float> noundef %c) { +define internal noundef <4 x float> @faceforward_float4(<4 x float> noundef %a, <4 x float> noundef %b, <4 x float> noundef %c) { entry: ; CHECK: %[[#]] = OpFunction %[[#vec4_float_32]] None %[[#]] ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]] @@ -55,8 +53,44 @@ entry: ret <4 x float> %spv.faceforward } +define internal noundef float @faceforward_instcombine_float(float noundef %a, float noundef %b, float noundef %c) { +entry: + ; CHECK: %[[#]] = OpFunction %[[#float_32]] None %[[#]] + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] FaceForward %[[#arg0]] %[[#arg1]] %[[#arg2]] + %fmul= fmul float %b, %c + %fcmp = fcmp olt float %fmul, 0.000000e+00 + %fneg = fneg float %a + %select = select i1 %fcmp, float %a, float %fneg + ret float %select + } + +define internal noundef <4 x float> @faceforward_instcombine_float4(<4 x float> noundef %a, <4 x float> noundef %b, <4 x float> noundef %c) { +entry: + ; CHECK: %[[#]] = OpFunction %[[#vec4_float_32]] None %[[#]] + ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_32]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_32]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#vec4_float_32]] + ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_32]] %[[#op_ext_glsl]] FaceForward %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.fdot = call float @llvm.spv.fdot.v4f32(<4 x float> %b, <4 x float> %c) + %fcmp = fcmp olt float %spv.fdot, 0.000000e+00 + %fneg = fneg <4 x float> %a + %select = select i1 %fcmp, <4 x float> %a, <4 x float> %fneg + ret <4 x float> %select + } + +; The other fucntions are the test, but a entry point is required to have a valid SPIR-V module. +define void @main() #1 { +entry: + ret void +} + declare half @llvm.spv.faceforward.f16(half, half, half) declare float @llvm.spv.faceforward.f32(float, float, float) declare <4 x half> @llvm.spv.faceforward.v4f16(<4 x half>, <4 x half>, <4 x half>) declare <4 x float> @llvm.spv.faceforward.v4f32(<4 x float>, <4 x float>, <4 x float>) + +attributes #1 = { convergent noinline norecurse "hlsl.numthreads"="1,1,1" "hlsl.shader"="compute" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } diff --git a/llvm/test/CodeGen/SPIRV/opencl/faceforward-error.ll b/llvm/test/CodeGen/SPIRV/opencl/faceforward-error.ll new file mode 100644 index 0000000000000..9334e0977347a --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/opencl/faceforward-error.ll @@ -0,0 +1,13 @@ +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s +; RUN: not llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK: LLVM ERROR: %{{.*}} = G_INTRINSIC intrinsic(@llvm.spv.faceforward), %{{.*}}, %{{.*}}, %{{.*}} is only supported with the GLSL extended instruction set. + +define noundef <4 x float> @faceforward_float4(<4 x float> noundef %a, <4 x float> noundef %b, <4 x float> noundef %c) { +entry: + %spv.faceforward = call <4 x float> @llvm.spv.faceforward.v4f32(<4 x float> %a, <4 x float> %b, <4 x float> %c) + ret <4 x float> %spv.faceforward +} + +declare <4 x float> @llvm.spv.faceforward.v4f32(<4 x float>, <4 x float>, <4 x float>) +