diff --git a/llvm/include/llvm/Support/TargetOpcodes.def b/llvm/include/llvm/Support/TargetOpcodes.def index b905576b61791..7c2fd8e30873b 100644 --- a/llvm/include/llvm/Support/TargetOpcodes.def +++ b/llvm/include/llvm/Support/TargetOpcodes.def @@ -643,6 +643,7 @@ HANDLE_TARGET_OPCODE(G_FMA) /// Generic FP multiply and add. Behaves as separate fmul and fadd. HANDLE_TARGET_OPCODE(G_FMAD) +HANDLE_TARGET_OPCODE(G_STRICT_FMAD) /// Generic FP division. HANDLE_TARGET_OPCODE(G_FDIV) diff --git a/llvm/include/llvm/Target/GenericOpcodes.td b/llvm/include/llvm/Target/GenericOpcodes.td index ce4750db88c9a..e81e0b9a1b90b 100644 --- a/llvm/include/llvm/Target/GenericOpcodes.td +++ b/llvm/include/llvm/Target/GenericOpcodes.td @@ -1716,6 +1716,7 @@ def G_STRICT_FREM : ConstrainedInstruction; def G_STRICT_FMA : ConstrainedInstruction; def G_STRICT_FSQRT : ConstrainedInstruction; def G_STRICT_FLDEXP : ConstrainedInstruction; +def G_STRICT_FMAD : ConstrainedInstruction; //------------------------------------------------------------------------------ // Memory intrinsics diff --git a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp index 768e3713f78e2..302f8ed653233 100644 --- a/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp +++ b/llvm/lib/CodeGen/GlobalISel/IRTranslator.cpp @@ -2080,6 +2080,8 @@ static unsigned getConstrainedOpcode(Intrinsic::ID ID) { return TargetOpcode::G_STRICT_FSQRT; case Intrinsic::experimental_constrained_ldexp: return TargetOpcode::G_STRICT_FLDEXP; + case Intrinsic::experimental_constrained_fmuladd: + return TargetOpcode::G_STRICT_FMAD; default: return 0; } diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index f3e036ed1b947..7e3dfca365147 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -4523,6 +4523,7 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) { return Legalized; } case TargetOpcode::G_FMAD: + case TargetOpcode::G_STRICT_FMAD: return lowerFMad(MI); case TargetOpcode::G_FFLOOR: return lowerFFloor(MI); diff --git a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp index 170bddd507e3b..8c0c9de690483 100644 --- a/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp +++ b/llvm/lib/Target/SPIRV/SPIRVLegalizerInfo.cpp @@ -196,6 +196,8 @@ SPIRVLegalizerInfo::SPIRVLegalizerInfo(const SPIRVSubtarget &ST) { getActionDefinitionsBuilder({G_FMA, G_STRICT_FMA}) .legalFor(allFloatScalarsAndVectors); + getActionDefinitionsBuilder(G_STRICT_FMAD).lower(); + getActionDefinitionsBuilder(G_STRICT_FLDEXP) .legalForCartesianProduct(allFloatScalarsAndVectors, allIntScalars); diff --git a/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-fmuladd.ll b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-fmuladd.ll new file mode 100644 index 0000000000000..340f2d78fc21b --- /dev/null +++ b/llvm/test/CodeGen/SPIRV/llvm-intrinsics/constrained-fmuladd.ll @@ -0,0 +1,64 @@ +; RUN: llc -mtriple=spirv64-unknown-unknown %s -o - | FileCheck %s +; RUN: %if spirv-tools %{ llc -mtriple=spirv64-unknown-unknown %s -o - -filetype=obj | spirv-val %} + +; CHECK-DAG: OpDecorate %[[#]] FPRoundingMode RTE +; CHECK-DAG: OpDecorate %[[#]] FPRoundingMode RTZ +; CHECK-DAG: OpDecorate %[[#]] FPRoundingMode RTP +; CHECK-DAG: OpDecorate %[[#]] FPRoundingMode RTN +; CHECK-DAG: OpDecorate %[[#]] FPRoundingMode RTE + +; CHECK: OpFMul %[[#]] %[[#]] %[[#]] +; CHECK: OpFAdd %[[#]] %[[#]] %[[#]] +define spir_kernel void @test_f32(float %a) { +entry: + %r = tail call float @llvm.experimental.constrained.fmuladd.f32( + float %a, float %a, float %a, + metadata !"round.tonearest", metadata !"fpexcept.strict") + ret void +} + +; CHECK: OpFMul %[[#]] %[[#]] %[[#]] +; CHECK: OpFAdd %[[#]] %[[#]] %[[#]] +define spir_kernel void @test_f64(double %a) { +entry: + %r = tail call double @llvm.experimental.constrained.fmuladd.f64( + double %a, double %a, double %a, + metadata !"round.towardzero", metadata !"fpexcept.strict") + ret void +} + +; CHECK: OpFMul %[[#]] %[[#]] %[[#]] +; CHECK: OpFAdd %[[#]] %[[#]] %[[#]] +define spir_kernel void @test_v2f32(<2 x float> %a) { +entry: + %r = tail call <2 x float> @llvm.experimental.constrained.fmuladd.v2f32( + <2 x float> %a, <2 x float> %a, <2 x float> %a, + metadata !"round.upward", metadata !"fpexcept.strict") + ret void +} + +; CHECK: OpFMul %[[#]] %[[#]] %[[#]] +; CHECK: OpFAdd %[[#]] %[[#]] %[[#]] +define spir_kernel void @test_v4f32(<4 x float> %a) { +entry: + %r = tail call <4 x float> @llvm.experimental.constrained.fmuladd.v4f32( + <4 x float> %a, <4 x float> %a, <4 x float> %a, + metadata !"round.downward", metadata !"fpexcept.strict") + ret void +} + +; CHECK: OpFMul %[[#]] %[[#]] %[[#]] +; CHECK: OpFAdd %[[#]] %[[#]] %[[#]] +define spir_kernel void @test_v2f64(<2 x double> %a) { +entry: + %r = tail call <2 x double> @llvm.experimental.constrained.fmuladd.v2f64( + <2 x double> %a, <2 x double> %a, <2 x double> %a, + metadata !"round.tonearest", metadata !"fpexcept.strict") + ret void +} + +declare float @llvm.experimental.constrained.fmuladd.f32(float, float, float, metadata, metadata) +declare double @llvm.experimental.constrained.fmuladd.f64(double, double, double, metadata, metadata) +declare <2 x float> @llvm.experimental.constrained.fmuladd.v2f32(<2 x float>, <2 x float>, <2 x float>, metadata, metadata) +declare <4 x float> @llvm.experimental.constrained.fmuladd.v4f32(<4 x float>, <4 x float>, <4 x float>, metadata, metadata) +declare <2 x double> @llvm.experimental.constrained.fmuladd.v2f64(<2 x double>, <2 x double>, <2 x double>, metadata, metadata)