Index: llvm/include/llvm/Analysis/InstructionSimplify.h =================================================================== --- llvm/include/llvm/Analysis/InstructionSimplify.h +++ llvm/include/llvm/Analysis/InstructionSimplify.h @@ -157,23 +157,34 @@ const SimplifyQuery &Q); /// Given operands for an FAdd, fold the result or return null. -Value *SimplifyFAddInst(Value *LHS, Value *RHS, FastMathFlags FMF, - const SimplifyQuery &Q); +Value * +SimplifyFAddInst(Value *LHS, Value *RHS, FastMathFlags FMF, + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven); /// Given operands for an FSub, fold the result or return null. -Value *SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF, - const SimplifyQuery &Q); +Value * +SimplifyFSubInst(Value *LHS, Value *RHS, FastMathFlags FMF, + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven); /// Given operands for an FMul, fold the result or return null. -Value *SimplifyFMulInst(Value *LHS, Value *RHS, FastMathFlags FMF, - const SimplifyQuery &Q); +Value * +SimplifyFMulInst(Value *LHS, Value *RHS, FastMathFlags FMF, + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven); /// Given operands for the multiplication of a FMA, fold the result or return /// null. In contrast to SimplifyFMulInst, this function will not perform /// simplifications whose unrounded results differ when rounded to the argument /// type. Value *SimplifyFMAFMul(Value *LHS, Value *RHS, FastMathFlags FMF, - const SimplifyQuery &Q); + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven); /// Given operands for a Mul, fold the result or return null. Value *SimplifyMulInst(Value *LHS, Value *RHS, const SimplifyQuery &Q); @@ -185,8 +196,11 @@ Value *SimplifyUDivInst(Value *LHS, Value *RHS, const SimplifyQuery &Q); /// Given operands for an FDiv, fold the result or return null. -Value *SimplifyFDivInst(Value *LHS, Value *RHS, FastMathFlags FMF, - const SimplifyQuery &Q); +Value * +SimplifyFDivInst(Value *LHS, Value *RHS, FastMathFlags FMF, + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven); /// Given operands for an SRem, fold the result or return null. Value *SimplifySRemInst(Value *LHS, Value *RHS, const SimplifyQuery &Q); @@ -195,8 +209,11 @@ Value *SimplifyURemInst(Value *LHS, Value *RHS, const SimplifyQuery &Q); /// Given operands for an FRem, fold the result or return null. -Value *SimplifyFRemInst(Value *LHS, Value *RHS, FastMathFlags FMF, - const SimplifyQuery &Q); +Value * +SimplifyFRemInst(Value *LHS, Value *RHS, FastMathFlags FMF, + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven); /// Given operands for a Shl, fold the result or return null. Value *SimplifyShlInst(Value *Op0, Value *Op1, bool isNSW, bool isNUW, Index: llvm/include/llvm/IR/FPEnv.h =================================================================== --- llvm/include/llvm/IR/FPEnv.h +++ llvm/include/llvm/IR/FPEnv.h @@ -52,5 +52,11 @@ /// For any ExceptionBehavior enumerator, returns a string valid as /// input in constrained intrinsic exception behavior metadata. Optional ExceptionBehaviorToStr(fp::ExceptionBehavior); + +/// Returns true if the exception handling behavior and rounding mode +/// match what is used in the default floating point environment. +inline bool IsDefaultFPEnvironment(fp::ExceptionBehavior eb, RoundingMode rm) { + return eb == fp::ebIgnore && rm == RoundingMode::NearestTiesToEven; +} } #endif Index: llvm/lib/Analysis/InstructionSimplify.cpp =================================================================== --- llvm/lib/Analysis/InstructionSimplify.cpp +++ llvm/lib/Analysis/InstructionSimplify.cpp @@ -4808,9 +4808,10 @@ /// Perform folds that are common to any floating-point operation. This implies /// transforms based on undef/NaN because the operation itself makes no /// difference to the result. -static Constant *simplifyFPOp(ArrayRef Ops, - FastMathFlags FMF, - const SimplifyQuery &Q) { +static Constant *simplifyFPOp(ArrayRef Ops, FastMathFlags FMF, + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior, + RoundingMode Rounding) { for (Value *V : Ops) { bool IsNan = match(V, m_NaN()); bool IsInf = match(V, m_Inf()); @@ -4824,22 +4825,34 @@ if (FMF.noInfs() && (IsInf || IsUndef)) return PoisonValue::get(V->getType()); - if (IsUndef || IsNan) - return propagateNaN(cast(V)); + if (IsDefaultFPEnvironment(ExBehavior, Rounding)) { + if (IsUndef || IsNan) + return propagateNaN(cast(V)); + } else if (ExBehavior != fp::ebStrict) { + if (IsNan) + return propagateNaN(cast(V)); + } } return nullptr; } /// Given operands for an FAdd, see if we can fold the result. If not, this /// returns null. -static Value *SimplifyFAddInst(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q, unsigned MaxRecurse) { - if (Constant *C = foldOrCommuteConstant(Instruction::FAdd, Op0, Op1, Q)) - return C; +static Value * +SimplifyFAddInst(Value *Op0, Value *Op1, FastMathFlags FMF, + const SimplifyQuery &Q, unsigned MaxRecurse, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven) { + if (IsDefaultFPEnvironment(ExBehavior, Rounding)) + if (Constant *C = foldOrCommuteConstant(Instruction::FAdd, Op0, Op1, Q)) + return C; - if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q)) + if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q, ExBehavior, Rounding)) return C; + if (!IsDefaultFPEnvironment(ExBehavior, Rounding)) + return nullptr; + // fadd X, -0 ==> X if (match(Op1, m_NegZeroFP())) return Op0; @@ -4879,14 +4892,21 @@ /// Given operands for an FSub, see if we can fold the result. If not, this /// returns null. -static Value *SimplifyFSubInst(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q, unsigned MaxRecurse) { - if (Constant *C = foldOrCommuteConstant(Instruction::FSub, Op0, Op1, Q)) - return C; +static Value * +SimplifyFSubInst(Value *Op0, Value *Op1, FastMathFlags FMF, + const SimplifyQuery &Q, unsigned MaxRecurse, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven) { + if (IsDefaultFPEnvironment(ExBehavior, Rounding)) + if (Constant *C = foldOrCommuteConstant(Instruction::FSub, Op0, Op1, Q)) + return C; - if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q)) + if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q, ExBehavior, Rounding)) return C; + if (!IsDefaultFPEnvironment(ExBehavior, Rounding)) + return nullptr; + // fsub X, +0 ==> X if (match(Op1, m_PosZeroFP())) return Op0; @@ -4925,10 +4945,15 @@ } static Value *SimplifyFMAFMul(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q, unsigned MaxRecurse) { - if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q)) + const SimplifyQuery &Q, unsigned MaxRecurse, + fp::ExceptionBehavior ExBehavior, + RoundingMode Rounding) { + if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q, ExBehavior, Rounding)) return C; + if (!IsDefaultFPEnvironment(ExBehavior, Rounding)) + return nullptr; + // fmul X, 1.0 ==> X if (match(Op1, m_FPOne())) return Op0; @@ -4958,43 +4983,65 @@ } /// Given the operands for an FMul, see if we can fold the result -static Value *SimplifyFMulInst(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q, unsigned MaxRecurse) { - if (Constant *C = foldOrCommuteConstant(Instruction::FMul, Op0, Op1, Q)) - return C; +static Value * +SimplifyFMulInst(Value *Op0, Value *Op1, FastMathFlags FMF, + const SimplifyQuery &Q, unsigned MaxRecurse, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven) { + if (IsDefaultFPEnvironment(ExBehavior, Rounding)) + if (Constant *C = foldOrCommuteConstant(Instruction::FMul, Op0, Op1, Q)) + return C; // Now apply simplifications that do not require rounding. - return SimplifyFMAFMul(Op0, Op1, FMF, Q, MaxRecurse); + return SimplifyFMAFMul(Op0, Op1, FMF, Q, MaxRecurse, ExBehavior, Rounding); } Value *llvm::SimplifyFAddInst(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q) { - return ::SimplifyFAddInst(Op0, Op1, FMF, Q, RecursionLimit); + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior, + RoundingMode Rounding) { + return ::SimplifyFAddInst(Op0, Op1, FMF, Q, RecursionLimit, ExBehavior, + Rounding); } - Value *llvm::SimplifyFSubInst(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q) { - return ::SimplifyFSubInst(Op0, Op1, FMF, Q, RecursionLimit); + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior, + RoundingMode Rounding) { + return ::SimplifyFSubInst(Op0, Op1, FMF, Q, RecursionLimit, ExBehavior, + Rounding); } Value *llvm::SimplifyFMulInst(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q) { - return ::SimplifyFMulInst(Op0, Op1, FMF, Q, RecursionLimit); + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior, + RoundingMode Rounding) { + return ::SimplifyFMulInst(Op0, Op1, FMF, Q, RecursionLimit, ExBehavior, + Rounding); } Value *llvm::SimplifyFMAFMul(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q) { - return ::SimplifyFMAFMul(Op0, Op1, FMF, Q, RecursionLimit); -} + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior, + RoundingMode Rounding) { + return ::SimplifyFMAFMul(Op0, Op1, FMF, Q, RecursionLimit, ExBehavior, + Rounding); +} + +static Value * +SimplifyFDivInst(Value *Op0, Value *Op1, FastMathFlags FMF, + const SimplifyQuery &Q, unsigned, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven) { + if (IsDefaultFPEnvironment(ExBehavior, Rounding)) + if (Constant *C = foldOrCommuteConstant(Instruction::FDiv, Op0, Op1, Q)) + return C; -static Value *SimplifyFDivInst(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q, unsigned) { - if (Constant *C = foldOrCommuteConstant(Instruction::FDiv, Op0, Op1, Q)) + if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q, ExBehavior, Rounding)) return C; - if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q)) - return C; + if (!IsDefaultFPEnvironment(ExBehavior, Rounding)) + return nullptr; // X / 1.0 -> X if (match(Op1, m_FPOne())) @@ -5029,17 +5076,27 @@ } Value *llvm::SimplifyFDivInst(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q) { - return ::SimplifyFDivInst(Op0, Op1, FMF, Q, RecursionLimit); -} + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior, + RoundingMode Rounding) { + return ::SimplifyFDivInst(Op0, Op1, FMF, Q, RecursionLimit, ExBehavior, + Rounding); +} + +static Value * +SimplifyFRemInst(Value *Op0, Value *Op1, FastMathFlags FMF, + const SimplifyQuery &Q, unsigned, + fp::ExceptionBehavior ExBehavior = fp::ebIgnore, + RoundingMode Rounding = RoundingMode::NearestTiesToEven) { + if (IsDefaultFPEnvironment(ExBehavior, Rounding)) + if (Constant *C = foldOrCommuteConstant(Instruction::FRem, Op0, Op1, Q)) + return C; -static Value *SimplifyFRemInst(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q, unsigned) { - if (Constant *C = foldOrCommuteConstant(Instruction::FRem, Op0, Op1, Q)) + if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q, ExBehavior, Rounding)) return C; - if (Constant *C = simplifyFPOp({Op0, Op1}, FMF, Q)) - return C; + if (!IsDefaultFPEnvironment(ExBehavior, Rounding)) + return nullptr; // Unlike fdiv, the result of frem always matches the sign of the dividend. // The constant match may include undef elements in a vector, so return a full @@ -5057,8 +5114,11 @@ } Value *llvm::SimplifyFRemInst(Value *Op0, Value *Op1, FastMathFlags FMF, - const SimplifyQuery &Q) { - return ::SimplifyFRemInst(Op0, Op1, FMF, Q, RecursionLimit); + const SimplifyQuery &Q, + fp::ExceptionBehavior ExBehavior, + RoundingMode Rounding) { + return ::SimplifyFRemInst(Op0, Op1, FMF, Q, RecursionLimit, ExBehavior, + Rounding); } //=== Helper functions for higher up the class hierarchy. @@ -5704,12 +5764,24 @@ } return nullptr; } + case Intrinsic::experimental_constrained_fma: { + Value *Op0 = Call->getArgOperand(0); + Value *Op1 = Call->getArgOperand(1); + Value *Op2 = Call->getArgOperand(2); + auto *FPI = cast(Call); + if (Value *V = simplifyFPOp({Op0, Op1, Op2}, {}, Q, + FPI->getExceptionBehavior().getValue(), + FPI->getRoundingMode().getValue())) + return V; + return nullptr; + } case Intrinsic::fma: case Intrinsic::fmuladd: { Value *Op0 = Call->getArgOperand(0); Value *Op1 = Call->getArgOperand(1); Value *Op2 = Call->getArgOperand(2); - if (Value *V = simplifyFPOp({ Op0, Op1, Op2 }, {}, Q)) + if (Value *V = simplifyFPOp({Op0, Op1, Op2}, {}, Q, fp::ebIgnore, + RoundingMode::NearestTiesToEven)) return V; return nullptr; } @@ -5761,6 +5833,46 @@ return nullptr; } + case Intrinsic::experimental_constrained_fadd: { + auto *FPI = cast(Call); + return SimplifyFAddInst(FPI->getArgOperand(0), FPI->getArgOperand(1), + FPI->getFastMathFlags(), Q, + FPI->getExceptionBehavior().getValue(), + FPI->getRoundingMode().getValue()); + break; + } + case Intrinsic::experimental_constrained_fsub: { + auto *FPI = cast(Call); + return SimplifyFSubInst(FPI->getArgOperand(0), FPI->getArgOperand(1), + FPI->getFastMathFlags(), Q, + FPI->getExceptionBehavior().getValue(), + FPI->getRoundingMode().getValue()); + break; + } + case Intrinsic::experimental_constrained_fmul: { + auto *FPI = cast(Call); + return SimplifyFMulInst(FPI->getArgOperand(0), FPI->getArgOperand(1), + FPI->getFastMathFlags(), Q, + FPI->getExceptionBehavior().getValue(), + FPI->getRoundingMode().getValue()); + break; + } + case Intrinsic::experimental_constrained_fdiv: { + auto *FPI = cast(Call); + return SimplifyFDivInst(FPI->getArgOperand(0), FPI->getArgOperand(1), + FPI->getFastMathFlags(), Q, + FPI->getExceptionBehavior().getValue(), + FPI->getRoundingMode().getValue()); + break; + } + case Intrinsic::experimental_constrained_frem: { + auto *FPI = cast(Call); + return SimplifyFRemInst(FPI->getArgOperand(0), FPI->getArgOperand(1), + FPI->getFastMathFlags(), Q, + FPI->getExceptionBehavior().getValue(), + FPI->getRoundingMode().getValue()); + break; + } default: return nullptr; } Index: llvm/lib/Transforms/Utils/Local.cpp =================================================================== --- llvm/lib/Transforms/Utils/Local.cpp +++ llvm/lib/Transforms/Utils/Local.cpp @@ -473,6 +473,14 @@ return false; } + + if (auto *FPI = dyn_cast(I)) { + Optional ExBehavior = FPI->getExceptionBehavior(); + if (ExBehavior.hasValue()) + return (ExBehavior.getValue() != fp::ebStrict); + else + return true; + } } if (isAllocLikeFn(I, TLI)) Index: llvm/test/Transforms/InstSimplify/X86/fp-nan-strictfp.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstSimplify/X86/fp-nan-strictfp.ll @@ -0,0 +1,464 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -mtriple=x86_64-- -instsimplify -S | FileCheck %s + +; +; constrained fadd +; + +define float @fadd_nan_op0_strict(float %x) #0 { +; CHECK-LABEL: @fadd_nan_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0:[0-9]+]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float 0x7FF8000000000000, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fadd_nan_op0_maytrap(float %x) #0 { +; CHECK-LABEL: @fadd_nan_op0_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fadd.f32(float 0x7FF8000000000000, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fadd_nan_op0_upward(float %x) #0 { +; CHECK-LABEL: @fadd_nan_op0_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fadd.f32(float 0x7FF8000000000000, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fadd_nan_op0_defaultfp(float %x) #0 { +; CHECK-LABEL: @fadd_nan_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fadd.f32(float 0x7FF8000000000000, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fadd_nan_op1_strict(float %x) #0 { +; CHECK-LABEL: @fadd_nan_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fadd_nan_op1_maytrap(float %x) #0 { +; CHECK-LABEL: @fadd_nan_op1_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fadd_nan_op1_upward(float %x) #0 { +; CHECK-LABEL: @fadd_nan_op1_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fadd_nan_op1_defaultfp(float %x) #0 { +; CHECK-LABEL: @fadd_nan_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +; +; constrained fsub +; + +define float @fsub_nan_op0_strict(float %x) { +; CHECK-LABEL: @fsub_nan_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float 0x7FF8000000000000, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fsub_nan_op0_maytrap(float %x) { +; CHECK-LABEL: @fsub_nan_op0_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fsub.f32(float 0x7FF8000000000000, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fsub_nan_op0_upward(float %x) { +; CHECK-LABEL: @fsub_nan_op0_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fsub.f32(float 0x7FF8000000000000, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fsub_nan_op0_defaultfp(float %x) { +; CHECK-LABEL: @fsub_nan_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fsub.f32(float 0x7FF8000000000000, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fsub_nan_op1_strict(float %x) { +; CHECK-LABEL: @fsub_nan_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fsub_nan_op1_maytrap(float %x) { +; CHECK-LABEL: @fsub_nan_op1_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fsub_nan_op1_upward(float %x) { +; CHECK-LABEL: @fsub_nan_op1_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fsub_nan_op1_defaultfp(float %x) { +; CHECK-LABEL: @fsub_nan_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +; +; constrained fmul +; + +define float @fmul_nan_op0_strict(float %x) { +; CHECK-LABEL: @fmul_nan_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float 0x7FF8000000000000, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fmul_nan_op0_maytrap(float %x) { +; CHECK-LABEL: @fmul_nan_op0_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fmul.f32(float 0x7FF8000000000000, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fmul_nan_op0_upward(float %x) { +; CHECK-LABEL: @fmul_nan_op0_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fmul.f32(float 0x7FF8000000000000, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fmul_nan_op0_defaultfp(float %x) { +; CHECK-LABEL: @fmul_nan_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fmul.f32(float 0x7FF8000000000000, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fmul_nan_op1_strict(float %x) { +; CHECK-LABEL: @fmul_nan_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fmul_nan_op1_maytrap(float %x) { +; CHECK-LABEL: @fmul_nan_op1_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fmul_nan_op1_upward(float %x) { +; CHECK-LABEL: @fmul_nan_op1_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fmul_nan_op1_defaultfp(float %x) { +; CHECK-LABEL: @fmul_nan_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +; +; constrained fdiv +; + +define float @fdiv_nan_op0_strict(float %x) { +; CHECK-LABEL: @fdiv_nan_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float 0x7FF8000000000000, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fdiv_nan_op0_maytrap(float %x) { +; CHECK-LABEL: @fdiv_nan_op0_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float 0x7FF8000000000000, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fdiv_nan_op0_upward(float %x) { +; CHECK-LABEL: @fdiv_nan_op0_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float 0x7FF8000000000000, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fdiv_nan_op0_defaultfp(float %x) { +; CHECK-LABEL: @fdiv_nan_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float 0x7FF8000000000000, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fdiv_nan_op1_strict(float %x) { +; CHECK-LABEL: @fdiv_nan_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fdiv_nan_op1_maytrap(float %x) { +; CHECK-LABEL: @fdiv_nan_op1_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fdiv_nan_op1_upward(float %x) { +; CHECK-LABEL: @fdiv_nan_op1_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fdiv_nan_op1_defaultfp(float %x) { +; CHECK-LABEL: @fdiv_nan_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +; +; constrained frem +; + +define float @frem_nan_op0_strict(float %x) { +; CHECK-LABEL: @frem_nan_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float 0x7FF8000000000000, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @frem_nan_op0_maytrap(float %x) { +; CHECK-LABEL: @frem_nan_op0_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.frem.f32(float 0x7FF8000000000000, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @frem_nan_op0_upward(float %x) { +; CHECK-LABEL: @frem_nan_op0_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.frem.f32(float 0x7FF8000000000000, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @frem_nan_op0_defaultfp(float %x) { +; CHECK-LABEL: @frem_nan_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.frem.f32(float 0x7FF8000000000000, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @frem_nan_op1_strict(float %x) { +; CHECK-LABEL: @frem_nan_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @frem_nan_op1_maytrap(float %x) { +; CHECK-LABEL: @frem_nan_op1_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @frem_nan_op1_upward(float %x) { +; CHECK-LABEL: @frem_nan_op1_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @frem_nan_op1_defaultfp(float %x) { +; CHECK-LABEL: @frem_nan_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +; +; constrained fma +; + +define float @fma_nan_op0_strict(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float 0x7FF8000000000000, float [[X:%.*]], float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float 0x7FF8000000000000, float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fma_nan_op0_maytrap(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op0_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float 0x7FF8000000000000, float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fma_nan_op0_upward(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op0_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float 0x7FF8000000000000, float %x, float %y, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_nan_op0_defaultfp(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float 0x7FF8000000000000, float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_nan_op1_strict(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float 0x7FF8000000000000, float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float 0x7FF8000000000000, float %y, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fma_nan_op1_maytrap(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op1_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float 0x7FF8000000000000, float %y, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fma_nan_op1_upward(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op1_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float 0x7FF8000000000000, float %y, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_nan_op1_defaultfp(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float 0x7FF8000000000000, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_nan_op2_strict(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op2_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fma_nan_op2_maytrap(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op2_maytrap( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fma_nan_op2_upward(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op2_upward( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_nan_op2_defaultfp(float %x, float %y) { +; CHECK-LABEL: @fma_nan_op2_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.frem.f32(float, float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.fma.f32(float, float, float, metadata, metadata) #0 + +attributes #0 = { strictfp } Index: llvm/test/Transforms/InstSimplify/fp-undef-poison-strictfp.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstSimplify/fp-undef-poison-strictfp.ll @@ -0,0 +1,947 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; TODO: the instructions with poison operands should return poison + +; +; constrained fadd +; + +define float @fadd_undef_op0_strict(float %x) #0 { +; CHECK-LABEL: @fadd_undef_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float undef, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0:[0-9]+]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float undef, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fadd_undef_op0_maytrap(float %x) #0 { +; CHECK-LABEL: @fadd_undef_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float undef, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float undef, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fadd_undef_op0_upward(float %x) #0 { +; CHECK-LABEL: @fadd_undef_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float undef, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float undef, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fadd_undef_op0_defaultfp(float %x) #0 { +; CHECK-LABEL: @fadd_undef_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fadd.f32(float undef, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fadd_poison_op0_strict(float %x) #0 { +; CHECK-LABEL: @fadd_poison_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float poison, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float poison, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fadd_poison_op0_maytrap(float %x) #0 { +; CHECK-LABEL: @fadd_poison_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float poison, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float poison, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fadd_poison_op0_upward(float %x) #0 { +; CHECK-LABEL: @fadd_poison_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float poison, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float poison, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fadd_poison_op0_defaultfp(float %x) #0 { +; CHECK-LABEL: @fadd_poison_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fadd.f32(float poison, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fadd_undef_op1_strict(float %x) #0 { +; CHECK-LABEL: @fadd_undef_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fadd_undef_op1_maytrap(float %x) #0 { +; CHECK-LABEL: @fadd_undef_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fadd_undef_op1_upward(float %x) #0 { +; CHECK-LABEL: @fadd_undef_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fadd_undef_op1_defaultfp(float %x) #0 { +; CHECK-LABEL: @fadd_undef_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fadd_poison_op1_strict(float %x) #0 { +; CHECK-LABEL: @fadd_poison_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fadd_poison_op1_maytrap(float %x) #0 { +; CHECK-LABEL: @fadd_poison_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fadd_poison_op1_upward(float %x) #0 { +; CHECK-LABEL: @fadd_poison_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fadd_poison_op1_defaultfp(float %x) #0 { +; CHECK-LABEL: @fadd_poison_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fadd.f32(float %x, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +; +; constrained fsub +; + +define float @fsub_undef_op0_strict(float %x) { +; CHECK-LABEL: @fsub_undef_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float undef, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float undef, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fsub_undef_op0_maytrap(float %x) { +; CHECK-LABEL: @fsub_undef_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float undef, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float undef, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fsub_undef_op0_upward(float %x) { +; CHECK-LABEL: @fsub_undef_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float undef, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float undef, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fsub_undef_op0_defaultfp(float %x) { +; CHECK-LABEL: @fsub_undef_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fsub.f32(float undef, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fsub_poison_op0_strict(float %x) { +; CHECK-LABEL: @fsub_poison_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float poison, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float poison, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fsub_poison_op0_maytrap(float %x) { +; CHECK-LABEL: @fsub_poison_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float poison, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float poison, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fsub_poison_op0_upward(float %x) { +; CHECK-LABEL: @fsub_poison_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float poison, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float poison, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fsub_poison_op0_defaultfp(float %x) { +; CHECK-LABEL: @fsub_poison_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fsub.f32(float poison, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fsub_undef_op1_strict(float %x) { +; CHECK-LABEL: @fsub_undef_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fsub_undef_op1_maytrap(float %x) { +; CHECK-LABEL: @fsub_undef_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fsub_undef_op1_upward(float %x) { +; CHECK-LABEL: @fsub_undef_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fsub_undef_op1_defaultfp(float %x) { +; CHECK-LABEL: @fsub_undef_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fsub_poison_op1_strict(float %x) { +; CHECK-LABEL: @fsub_poison_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fsub_poison_op1_maytrap(float %x) { +; CHECK-LABEL: @fsub_poison_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fsub_poison_op1_upward(float %x) { +; CHECK-LABEL: @fsub_poison_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fsub_poison_op1_defaultfp(float %x) { +; CHECK-LABEL: @fsub_poison_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +; +; constrained fmul +; + +define float @fmul_undef_op0_strict(float %x) { +; CHECK-LABEL: @fmul_undef_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float undef, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float undef, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fmul_undef_op0_maytrap(float %x) { +; CHECK-LABEL: @fmul_undef_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float undef, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float undef, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fmul_undef_op0_upward(float %x) { +; CHECK-LABEL: @fmul_undef_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float undef, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float undef, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fmul_undef_op0_defaultfp(float %x) { +; CHECK-LABEL: @fmul_undef_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fmul.f32(float undef, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fmul_poison_op0_strict(float %x) { +; CHECK-LABEL: @fmul_poison_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float poison, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float poison, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fmul_poison_op0_maytrap(float %x) { +; CHECK-LABEL: @fmul_poison_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float poison, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float poison, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fmul_poison_op0_upward(float %x) { +; CHECK-LABEL: @fmul_poison_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float poison, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float poison, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fmul_poison_op0_defaultfp(float %x) { +; CHECK-LABEL: @fmul_poison_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fmul.f32(float poison, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fmul_undef_op1_strict(float %x) { +; CHECK-LABEL: @fmul_undef_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fmul_undef_op1_maytrap(float %x) { +; CHECK-LABEL: @fmul_undef_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fmul_undef_op1_upward(float %x) { +; CHECK-LABEL: @fmul_undef_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fmul_undef_op1_defaultfp(float %x) { +; CHECK-LABEL: @fmul_undef_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fmul_poison_op1_strict(float %x) { +; CHECK-LABEL: @fmul_poison_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fmul_poison_op1_maytrap(float %x) { +; CHECK-LABEL: @fmul_poison_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fmul_poison_op1_upward(float %x) { +; CHECK-LABEL: @fmul_poison_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fmul_poison_op1_defaultfp(float %x) { +; CHECK-LABEL: @fmul_poison_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fmul.f32(float %x, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +; +; constrained fdiv +; + +define float @fdiv_undef_op0_strict(float %x) { +; CHECK-LABEL: @fdiv_undef_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float undef, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float undef, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fdiv_undef_op0_maytrap(float %x) { +; CHECK-LABEL: @fdiv_undef_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float undef, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float undef, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fdiv_undef_op0_upward(float %x) { +; CHECK-LABEL: @fdiv_undef_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float undef, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float undef, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fdiv_undef_op0_defaultfp(float %x) { +; CHECK-LABEL: @fdiv_undef_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float undef, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fdiv_poison_op0_strict(float %x) { +; CHECK-LABEL: @fdiv_poison_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float poison, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float poison, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fdiv_poison_op0_maytrap(float %x) { +; CHECK-LABEL: @fdiv_poison_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float poison, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float poison, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fdiv_poison_op0_upward(float %x) { +; CHECK-LABEL: @fdiv_poison_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float poison, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float poison, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fdiv_poison_op0_defaultfp(float %x) { +; CHECK-LABEL: @fdiv_poison_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float poison, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fdiv_undef_op1_strict(float %x) { +; CHECK-LABEL: @fdiv_undef_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fdiv_undef_op1_maytrap(float %x) { +; CHECK-LABEL: @fdiv_undef_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fdiv_undef_op1_upward(float %x) { +; CHECK-LABEL: @fdiv_undef_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fdiv_undef_op1_defaultfp(float %x) { +; CHECK-LABEL: @fdiv_undef_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fdiv_poison_op1_strict(float %x) { +; CHECK-LABEL: @fdiv_poison_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fdiv_poison_op1_maytrap(float %x) { +; CHECK-LABEL: @fdiv_poison_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fdiv_poison_op1_upward(float %x) { +; CHECK-LABEL: @fdiv_poison_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fdiv_poison_op1_defaultfp(float %x) { +; CHECK-LABEL: @fdiv_poison_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +; +; constrained frem +; + +define float @frem_undef_op0_strict(float %x) { +; CHECK-LABEL: @frem_undef_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float undef, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float undef, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @frem_undef_op0_maytrap(float %x) { +; CHECK-LABEL: @frem_undef_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float undef, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float undef, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @frem_undef_op0_upward(float %x) { +; CHECK-LABEL: @frem_undef_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float undef, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float undef, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @frem_undef_op0_defaultfp(float %x) { +; CHECK-LABEL: @frem_undef_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.frem.f32(float undef, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @frem_poison_op0_strict(float %x) { +; CHECK-LABEL: @frem_poison_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float poison, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float poison, float %x, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @frem_poison_op0_maytrap(float %x) { +; CHECK-LABEL: @frem_poison_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float poison, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float poison, float %x, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @frem_poison_op0_upward(float %x) { +; CHECK-LABEL: @frem_poison_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float poison, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float poison, float %x, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @frem_poison_op0_defaultfp(float %x) { +; CHECK-LABEL: @frem_poison_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.frem.f32(float poison, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @frem_undef_op1_strict(float %x) { +; CHECK-LABEL: @frem_undef_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @frem_undef_op1_maytrap(float %x) { +; CHECK-LABEL: @frem_undef_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @frem_undef_op1_upward(float %x) { +; CHECK-LABEL: @frem_undef_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @frem_undef_op1_defaultfp(float %x) { +; CHECK-LABEL: @frem_undef_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @frem_poison_op1_strict(float %x) { +; CHECK-LABEL: @frem_poison_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @frem_poison_op1_maytrap(float %x) { +; CHECK-LABEL: @frem_poison_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @frem_poison_op1_upward(float %x) { +; CHECK-LABEL: @frem_poison_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @frem_poison_op1_defaultfp(float %x) { +; CHECK-LABEL: @frem_poison_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.frem.f32(float %x, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +; +; constrained fma +; + +define float @fma_undef_op0_strict(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float undef, float [[X:%.*]], float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float undef, float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fma_undef_op0_maytrap(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float undef, float [[X:%.*]], float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float undef, float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fma_undef_op0_upward(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float undef, float [[X:%.*]], float [[Y:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float undef, float %x, float %y, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_undef_op0_defaultfp(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float undef, float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_poison_op0_strict(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op0_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float poison, float [[X:%.*]], float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float poison, float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fma_poison_op0_maytrap(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op0_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float poison, float [[X:%.*]], float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float poison, float %x, float %y, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fma_poison_op0_upward(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op0_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float poison, float [[X:%.*]], float [[Y:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float poison, float %x, float %y, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_poison_op0_defaultfp(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op0_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float poison, float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_undef_op1_strict(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float undef, float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float undef, float %y, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fma_undef_op1_maytrap(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float undef, float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float undef, float %y, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fma_undef_op1_upward(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float undef, float [[Y:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float undef, float %y, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_undef_op1_defaultfp(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float undef, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_poison_op1_strict(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op1_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float poison, float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float poison, float %y, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fma_poison_op1_maytrap(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op1_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float poison, float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float poison, float %y, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fma_poison_op1_upward(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op1_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float poison, float [[Y:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float poison, float %y, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_poison_op1_defaultfp(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op1_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float poison, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_undef_op2_strict(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op2_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float undef, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fma_undef_op2_maytrap(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op2_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float undef, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fma_undef_op2_upward(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op2_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float undef, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_undef_op2_defaultfp(float %x, float %y) { +; CHECK-LABEL: @fma_undef_op2_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_poison_op2_strict(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op2_strict( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float poison, metadata !"round.dynamic", metadata !"fpexcept.strict") #0 + ret float %r +} + +define float @fma_poison_op2_maytrap(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op2_maytrap( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float poison, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #0 + ret float %r +} + +define float @fma_poison_op2_upward(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op2_upward( +; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]] +; CHECK-NEXT: ret float [[R]] +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float poison, metadata !"round.upward", metadata !"fpexcept.ignore") #0 + ret float %r +} + +define float @fma_poison_op2_defaultfp(float %x, float %y) { +; CHECK-LABEL: @fma_poison_op2_defaultfp( +; CHECK-NEXT: ret float 0x7FF8000000000000 +; + %r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0 + ret float %r +} + +declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.frem.f32(float, float, metadata, metadata) #0 +declare float @llvm.experimental.constrained.fma.f32(float, float, float, metadata, metadata) #0 + +attributes #0 = { strictfp }