diff --git a/llvm/lib/Target/SPIRV/SPIRVCombine.td b/llvm/lib/Target/SPIRV/SPIRVCombine.td index fde56c4d3632a..991a5de1c4e83 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 [{ Helper.applySPIRVDistance(*${root}); }]) >; +def vector_select_to_faceforward_lowering : GICombineRule < + (defs root:$root), + (match (wip_match_opcode G_SELECT):$root, + [{ return Helper.matchSelectToFaceForward(*${root}); }]), + (apply [{ Helper.applySPIRVFaceForward(*${root}); }]) +>; + 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/SPIRVCombinerHelper.cpp b/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.cpp index 267794c1e0bc5..3315c7b2b7bc3 100644 --- a/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.cpp @@ -58,3 +58,106 @@ void SPIRVCombinerHelper::applySPIRVDistance(MachineInstr &MI) const { MI.eraseFromParent(); } + +/// This match is part of a combine that +/// rewrites select(fcmp(dot(I, Ng), 0), N, -N) to faceforward(N, I, Ng) +/// (vXf32 (g_select +/// (g_fcmp +/// (g_intrinsic dot(vXf32 I) (vXf32 Ng) +/// 0) +/// (vXf32 N) +/// (vXf32 g_fneg (vXf32 N)))) +/// -> +/// (vXf32 (g_intrinsic faceforward +/// (vXf32 N) (vXf32 I) (vXf32 Ng))) +/// +/// This only works for Vulkan targets. +/// +bool SPIRVCombinerHelper::matchSelectToFaceForward(MachineInstr &MI) const { + if (!STI.isShader()) + return false; + + // Match overall select pattern. + Register CondReg, TrueReg, FalseReg; + if (!mi_match(MI.getOperand(0).getReg(), MRI, + m_GISelect(m_Reg(CondReg), m_Reg(TrueReg), m_Reg(FalseReg)))) + return false; + + // Match the FCMP condition. + Register DotReg, CondZeroReg; + CmpInst::Predicate Pred; + if (!mi_match(CondReg, MRI, + m_GFCmp(m_Pred(Pred), m_Reg(DotReg), m_Reg(CondZeroReg))) || + Pred != CmpInst::FCMP_OLT) + return false; + + // Check if FCMP is a comparison between a dot product and 0. + MachineInstr *DotInstr = MRI.getVRegDef(DotReg); + if (DotInstr->getOpcode() != TargetOpcode::G_INTRINSIC || + cast(DotInstr)->getIntrinsicID() != Intrinsic::spv_fdot) { + Register DotOperand1, DotOperand2; + // Check for scalar dot product. + if (!mi_match(DotReg, MRI, + m_GFMul(m_Reg(DotOperand1), m_Reg(DotOperand2))) || + !MRI.getType(DotOperand1).isScalar() || + !MRI.getType(DotOperand2).isScalar()) + return false; + } + + const ConstantFP *ZeroVal; + if (!mi_match(CondZeroReg, MRI, m_GFCst(ZeroVal)) || !ZeroVal->isZero()) + return false; + + // Check if select's false operand is the negation of the true operand. + auto AreNegatedConstants = [&](Register TrueReg, Register FalseReg) { + const ConstantFP *TrueVal, *FalseVal; + if (!mi_match(TrueReg, MRI, m_GFCst(TrueVal)) || + !mi_match(FalseReg, MRI, m_GFCst(FalseVal))) + return false; + APFloat TrueValNegated = TrueVal->getValue(); + TrueValNegated.changeSign(); + return FalseVal->getValue().compare(TrueValNegated) == APFloat::cmpEqual; + }; + + if (!mi_match(FalseReg, MRI, m_GFNeg(m_SpecificReg(TrueReg))) && + !mi_match(TrueReg, MRI, m_GFNeg(m_SpecificReg(FalseReg)))) { + // Check if they're constant opposites. + MachineInstr *TrueInstr = MRI.getVRegDef(TrueReg); + MachineInstr *FalseInstr = MRI.getVRegDef(FalseReg); + if (TrueInstr->getOpcode() == TargetOpcode::G_BUILD_VECTOR && + FalseInstr->getOpcode() == TargetOpcode::G_BUILD_VECTOR && + TrueInstr->getNumOperands() == FalseInstr->getNumOperands()) { + for (unsigned I = 1; I < TrueInstr->getNumOperands(); ++I) + if (!AreNegatedConstants(TrueInstr->getOperand(I).getReg(), + FalseInstr->getOperand(I).getReg())) + return false; + } else if (!AreNegatedConstants(TrueReg, FalseReg)) + return false; + } + + return true; +} + +void SPIRVCombinerHelper::applySPIRVFaceForward(MachineInstr &MI) const { + // Extract the operands for N, I, and Ng from the match criteria. + Register CondReg, TrueReg, DotReg, DotOperand1, DotOperand2; + if (!mi_match(MI.getOperand(0).getReg(), MRI, + m_GISelect(m_Reg(CondReg), m_Reg(TrueReg), m_Reg()))) + return; + if (!mi_match(CondReg, MRI, m_GFCmp(m_Pred(), m_Reg(DotReg), m_Reg()))) + return; + MachineInstr *DotInstr = MRI.getVRegDef(DotReg); + if (!mi_match(DotReg, MRI, m_GFMul(m_Reg(DotOperand1), m_Reg(DotOperand2)))) { + DotOperand1 = DotInstr->getOperand(2).getReg(); + DotOperand2 = DotInstr->getOperand(3).getReg(); + } + + Register ResultReg = MI.getOperand(0).getReg(); + Builder.setInstrAndDebugLoc(MI); + Builder.buildIntrinsic(Intrinsic::spv_faceforward, ResultReg) + .addUse(TrueReg) // N + .addUse(DotOperand1) // I + .addUse(DotOperand2); // Ng + + MI.eraseFromParent(); +} diff --git a/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.h b/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.h index 0b39d3408aab6..3118cdc744b8f 100644 --- a/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.h +++ b/llvm/lib/Target/SPIRV/SPIRVCombinerHelper.h @@ -31,6 +31,8 @@ class SPIRVCombinerHelper : public CombinerHelper { bool matchLengthToDistance(MachineInstr &MI) const; void applySPIRVDistance(MachineInstr &MI) const; + bool matchSelectToFaceForward(MachineInstr &MI) const; + void applySPIRVFaceForward(MachineInstr &MI) const; }; } // end namespace llvm 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..65f4368fc480e --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/GlobalISel/InstCombine/prelegalizercombiner-select-to-faceforward.mir @@ -0,0 +1,133 @@ +# RUN: llc -verify-machineinstrs -O0 -mtriple spirv-vulkan1.3-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 + %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>) +--- +name: faceforward_instcombine_float_constants +tracksRegLiveness: true +legalized: true +body: | + bb.1.entry: + ; CHECK-LABEL: name: faceforward_instcombine_float_constants + ; CHECK-NOT: %9:_(s32) = G_FCONSTANT float 0.000000e+00 + ; CHECK-NOT: %13:_(s32) = G_FCONSTANT float -1.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:id(s32) = G_SELECT %10:_(s1), %12:_, %13:_ + ; CHECK: %7:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK: %11:id(s32) = G_INTRINSIC intrinsic(@llvm.spv.faceforward), %7(s32), %3(s32), %4(s32) + ; CHECK: OpReturnValue %11(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, 1868783476, 1635021678, 7566446 + %9:_(s32) = G_FCONSTANT float 0.000000e+00 + %12:_(s32) = G_FCONSTANT float 1.000000e+00 + %13:_(s32) = G_FCONSTANT float -1.000000e+00 + %8:_(s32) = G_FMUL %1:fid, %2:fid + %10:_(s1) = G_FCMP floatpred(olt), %8:_(s32), %9:_ + %11:id(s32) = G_SELECT %10:_(s1), %12:_, %13:_ + OpReturnValue %11:id(s32) +--- +name: faceforward_instcombine_float4_constants +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: %16:_(s32) = G_FCONSTANT float -1.000000e+00 + ; CHECK-NOT: %15:_(<4 x s32>) = G_BUILD_VECTOR %16:_(s32), %16:_(s32), %16:_(s32), %16:_(s32) + ; 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:id(<4 x s32>) = G_SELECT %11:_(s1), %13:_, %15:_ + ; CHECK: %8:_(s32) = G_FCONSTANT float 1.000000e+00 + ; CHECK: %9:_(<4 x s32>) = G_BUILD_VECTOR %8(s32), %8(s32), %8(s32), %8(s32) + ; CHECK: %14:id(<4 x s32>) = G_INTRINSIC intrinsic(@llvm.spv.faceforward), %9(<4 x s32>), %4(<4 x s32>), %5(<4 x s32>) + ; CHECK: OpReturnValue %14(<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, 1667183732, 1953721967, 1937010273, 0 + %10:_(s32) = G_FCONSTANT float 0.000000e+00 + %14:_(s32) = G_FCONSTANT float 1.000000e+00 + %13:_(<4 x s32>) = G_BUILD_VECTOR %14:_(s32), %14:_(s32), %14:_(s32), %14:_(s32) + %16:_(s32) = G_FCONSTANT float -1.000000e+00 + %15:_(<4 x s32>) = G_BUILD_VECTOR %16:_(s32), %16:_(s32), %16:_(s32), %16:_(s32) + %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:id(<4 x s32>) = G_SELECT %11:_(s1), %13:_, %15:_ + OpReturnValue %12: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 df11694703f82..ef6057f52c413 100644 --- a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/faceforward.ll +++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/faceforward.ll @@ -1,62 +1,122 @@ -; 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 --target-env spv1.4 %} - -; FIXME(#136344): Change --target-env to vulkan1.3 and update this test accordingly once the issue is resolved. - -; Make sure SPIRV operation function calls for faceforward are lowered correctly. - -; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450" -; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16 -; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4 -; 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) { -entry: - ; CHECK: %[[#]] = OpFunction %[[#float_16]] None %[[#]] - ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#float_16]] - ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#float_16]] - ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#float_16]] - ; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] FaceForward %[[#arg0]] %[[#arg1]] %[[#arg2]] - %spv.faceforward = call half @llvm.spv.faceforward.f16(half %a, half %b, half %c) - ret half %spv.faceforward -} - -define noundef float @faceforward_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]] - %spv.faceforward = call float @llvm.spv.faceforward.f32(float %a, float %b, float %c) - 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) { -entry: - ; CHECK: %[[#]] = OpFunction %[[#vec4_float_16]] None %[[#]] - ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#vec4_float_16]] - ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_16]] - ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#vec4_float_16]] - ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] FaceForward %[[#arg0]] %[[#arg1]] %[[#arg2]] - %spv.faceforward = call <4 x half> @llvm.spv.faceforward.v4f16(<4 x half> %a, <4 x half> %b, <4 x half> %c) - 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) { -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.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 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>) +; 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. + +; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "GLSL.std.450" +; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16 +; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4 +; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32 +; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4 + +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]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#float_16]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#float_16]] + ; CHECK: %[[#]] = OpExtInst %[[#float_16]] %[[#op_ext_glsl]] FaceForward %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.faceforward = call half @llvm.spv.faceforward.f16(half %a, half %b, half %c) + ret half %spv.faceforward +} + +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]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#float_32]] + ; CHECK: %[[#]] = OpExtInst %[[#float_32]] %[[#op_ext_glsl]] FaceForward %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.faceforward = call float @llvm.spv.faceforward.f32(float %a, float %b, float %c) + ret float %spv.faceforward +} + +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]] + ; CHECK: %[[#arg1:]] = OpFunctionParameter %[[#vec4_float_16]] + ; CHECK: %[[#arg2:]] = OpFunctionParameter %[[#vec4_float_16]] + ; CHECK: %[[#]] = OpExtInst %[[#vec4_float_16]] %[[#op_ext_glsl]] FaceForward %[[#arg0]] %[[#arg1]] %[[#arg2]] + %spv.faceforward = call <4 x half> @llvm.spv.faceforward.v4f16(<4 x half> %a, <4 x half> %b, <4 x half> %c) + ret <4 x half> %spv.faceforward +} + +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]] + ; 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.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 +} + +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 + } + +define internal noundef float @faceforward_instcombine_float_constants(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 %[[#]] %[[#arg1]] %[[#arg2]] + %fmul = fmul float %b, %c + %fcmp = fcmp olt float %fmul, 0.000000e+00 + %select = select i1 %fcmp, float 1.000000e+00, float -1.000000e+00 + ret float %select +} + +define internal noundef <4 x float> @faceforward_instcombine_float4_constants(<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 %[[#]] %[[#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 + %select = select i1 %fcmp, <4 x float> , <4 x float> + 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>) + diff --git a/llvm/test/CodeGen/SPIRV/opencl/faceforward.ll b/llvm/test/CodeGen/SPIRV/opencl/faceforward.ll new file mode 100644 index 0000000000000..4da57f80058e1 --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/opencl/faceforward.ll @@ -0,0 +1,29 @@ +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: llc -verify-machineinstrs -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} +; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %} + +; Make sure we don't pattern match to faceforward in OpenCL. + +; CHECK-DAG: %[[#op_ext_glsl:]] = OpExtInstImport "OpenCL.std" + +; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32 +; CHECK-DAG: %[[#bool:]] = OpTypeBool +; CHECK-DAG: %[[#zero:]] = OpConstantNull %[[#float_32]] + +define internal noundef float @faceforward_no_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: %[[#fmul:]] = OpFMul %[[#float_32]] %[[#arg1]] %[[#arg2]] + ; CHECK: %[[#fcmp:]] = OpFOrdLessThan %[[#bool]] %[[#fmul]] %[[#zero]] + ; CHECK: %[[#fneg:]] = OpFNegate %[[#float_32]] %[[#arg0]] + ; CHECK: %[[#select:]] = OpSelect %[[#float_32]] %[[#fcmp]] %[[#arg0]] %[[#fneg]] + %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 + }