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);
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);
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,
/// For any ExceptionBehavior enumerator, returns a string valid as
/// input in constrained intrinsic exception behavior metadata.
Optional<StringRef> 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
/// transforms based on poison/undef/NaN because the operation itself makes no
/// difference to the result.
static Constant *simplifyFPOp(ArrayRef<Value *> Ops, FastMathFlags FMF,
- const SimplifyQuery &Q) {
+ const SimplifyQuery &Q,
+ fp::ExceptionBehavior ExBehavior,
+ RoundingMode Rounding) {
// Poison is independent of anything else. It always propagates from an
// operand to a math result.
if (any_of(Ops, [](Value *V) { return match(V, m_Poison()); }))
if (FMF.noInfs() && (IsInf || IsUndef))
return PoisonValue::get(V->getType());
- if (IsUndef || IsNan)
- return propagateNaN(cast<Constant>(V));
+ if (isDefaultFPEnvironment(ExBehavior, Rounding)) {
+ if (IsUndef || IsNan)
+ return propagateNaN(cast<Constant>(V));
+ } else if (ExBehavior != fp::ebStrict) {
+ if (IsNan)
+ return propagateNaN(cast<Constant>(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;
/// 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;
}
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;
}
/// 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()))
}
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
}
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.
}
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<ConstrainedFPIntrinsic>(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;
}
return nullptr;
}
+ case Intrinsic::experimental_constrained_fadd: {
+ auto *FPI = cast<ConstrainedFPIntrinsic>(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<ConstrainedFPIntrinsic>(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<ConstrainedFPIntrinsic>(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<ConstrainedFPIntrinsic>(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<ConstrainedFPIntrinsic>(Call);
+ return SimplifyFRemInst(FPI->getArgOperand(0), FPI->getArgOperand(1),
+ FPI->getFastMathFlags(), Q,
+ FPI->getExceptionBehavior().getValue(),
+ FPI->getRoundingMode().getValue());
+ break;
+ }
default:
return nullptr;
}
return false;
}
+
+ if (auto *FPI = dyn_cast<ConstrainedFPIntrinsic>(I)) {
+ Optional<fp::ExceptionBehavior> ExBehavior = FPI->getExceptionBehavior();
+ return ExBehavior.getValue() != fp::ebStrict;
+ }
}
if (isAllocLikeFn(I, TLI))
define float @fadd_nan_op0_maytrap(float %x) #0 {
; CHECK-LABEL: @fadd_nan_op0_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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_maytrap(float %x) #0 {
; CHECK-LABEL: @fadd_nan_op1_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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
define float @fsub_nan_op0_maytrap(float %x) {
; CHECK-LABEL: @fsub_nan_op0_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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_maytrap(float %x) {
; CHECK-LABEL: @fsub_nan_op1_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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
define float @fmul_nan_op0_maytrap(float %x) {
; CHECK-LABEL: @fmul_nan_op0_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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_maytrap(float %x) {
; CHECK-LABEL: @fmul_nan_op1_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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
define float @fdiv_nan_op0_maytrap(float %x) {
; CHECK-LABEL: @fdiv_nan_op0_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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_maytrap(float %x) {
; CHECK-LABEL: @fdiv_nan_op1_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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
define float @frem_nan_op0_maytrap(float %x) {
; CHECK-LABEL: @frem_nan_op0_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float 0x7FF8000000000000, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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_maytrap(float %x) {
; CHECK-LABEL: @frem_nan_op1_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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
define float @fma_nan_op0_maytrap(float %x, float %y) {
; CHECK-LABEL: @fma_nan_op0_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float 0x7FF8000000000000, float [[X:%.*]], float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float 0x7FF8000000000000, float [[X:%.*]], float [[Y:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float 0x7FF8000000000000, float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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_maytrap(float %x, float %y) {
; CHECK-LABEL: @fma_nan_op1_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float 0x7FF8000000000000, float [[Y:%.*]], metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float 0x7FF8000000000000, float [[Y:%.*]], metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float 0x7FF8000000000000, float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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_maytrap(float %x, float %y) {
; CHECK-LABEL: @fma_nan_op2_maytrap(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float 0x7FF8000000000000, metadata !"round.dynamic", metadata !"fpexcept.maytrap") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float 0x7FF8000000000000, metadata !"round.upward", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float 0x7FF8000000000000, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+;; x * 0 ==> 0 when no-nans and no-signed-zero
+define float @mul_zero_1(float %a) #0 {
+; CHECK-LABEL: @mul_zero_1(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %b = call nsz nnan float @llvm.experimental.constrained.fmul.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %b
+}
+
+define float @mul_zero_2(float %a) #0 {
+; CHECK-LABEL: @mul_zero_2(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %b = call fast float @llvm.experimental.constrained.fmul.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %b
+}
+
+define <2 x float> @mul_zero_nsz_nnan_vec_undef(<2 x float> %a) #0 {
+; CHECK-LABEL: @mul_zero_nsz_nnan_vec_undef(
+; CHECK-NEXT: ret <2 x float> zeroinitializer
+;
+ %b = call nsz nnan <2 x float> @llvm.experimental.constrained.fmul.v2f32(<2 x float> %a, <2 x float><float 0.0, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %b
+}
+
+;; x * 0 =/=> 0 when there could be nans or -0
+define float @no_mul_zero_1(float %a) #0 {
+; CHECK-LABEL: @no_mul_zero_1(
+; CHECK-NEXT: [[B:%.*]] = call nsz float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: ret float [[B]]
+;
+ %b = call nsz float @llvm.experimental.constrained.fmul.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %b
+}
+
+define float @no_mul_zero_2(float %a) #0 {
+; CHECK-LABEL: @no_mul_zero_2(
+; CHECK-NEXT: [[B:%.*]] = call nnan float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[B]]
+;
+ %b = call nnan float @llvm.experimental.constrained.fmul.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %b
+}
+
+define float @no_mul_zero_3(float %a) #0 {
+; CHECK-LABEL: @no_mul_zero_3(
+; CHECK-NEXT: [[B:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[B]]
+;
+ %b = call float @llvm.experimental.constrained.fmul.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %b
+}
+
+; -X + X --> 0.0 (with nnan on the fadd)
+
+define float @fadd_binary_fnegx(float %x) #0 {
+; CHECK-LABEL: @fadd_binary_fnegx(
+; CHECK-NEXT: [[NEGX:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call nnan float @llvm.experimental.constrained.fadd.f32(float [[NEGX]], float [[X]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %negx = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call nnan float @llvm.experimental.constrained.fadd.f32(float %negx, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+define float @fadd_unary_fnegx(float %x) #0 {
+; CHECK-LABEL: @fadd_unary_fnegx(
+; CHECK-NEXT: ret float 0.000000e+00
+;
+ %negx = fneg float %x
+ %r = call nnan float @llvm.experimental.constrained.fadd.f32(float %negx, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+; X + -X --> 0.0 (with nnan on the fadd)
+
+define <2 x float> @fadd_binary_fnegx_commute_vec(<2 x float> %x) #0 {
+; CHECK-LABEL: @fadd_binary_fnegx_commute_vec(
+; CHECK-NEXT: [[NEGX:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[X]], <2 x float> [[NEGX]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[R]]
+;
+ %negx = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.0, float -0.0>, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> %negx, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %r
+}
+
+define <2 x float> @fadd_unary_fnegx_commute_vec(<2 x float> %x) #0 {
+; CHECK-LABEL: @fadd_unary_fnegx_commute_vec(
+; CHECK-NEXT: ret <2 x float> zeroinitializer
+;
+ %negx = fneg <2 x float> %x
+ %r = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> %negx, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %r
+}
+
+define <2 x float> @fadd_fnegx_commute_vec_undef(<2 x float> %x) #0 {
+; CHECK-LABEL: @fadd_fnegx_commute_vec_undef(
+; CHECK-NEXT: [[NEGX:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.000000e+00>, <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[X]], <2 x float> [[NEGX]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[R]]
+;
+ %negx = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.0>, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call nnan <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> %negx, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %r
+}
+
+; https://bugs.llvm.org/show_bug.cgi?id=26958
+; https://bugs.llvm.org/show_bug.cgi?id=27151
+
+define float @fadd_binary_fneg_nan(float %x) #0 {
+; CHECK-LABEL: @fadd_binary_fneg_nan(
+; CHECK-NEXT: [[T:%.*]] = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[COULD_BE_NAN:%.*]] = call ninf float @llvm.experimental.constrained.fadd.f32(float [[T]], float [[X]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[COULD_BE_NAN]]
+;
+ %t = call nnan float @llvm.experimental.constrained.fsub.f32(float -0.0, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %could_be_nan = call ninf float @llvm.experimental.constrained.fadd.f32(float %t, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %could_be_nan
+}
+
+define float @fadd_unary_fneg_nan(float %x) #0 {
+; CHECK-LABEL: @fadd_unary_fneg_nan(
+; CHECK-NEXT: [[T:%.*]] = fneg nnan float [[X:%.*]]
+; CHECK-NEXT: [[COULD_BE_NAN:%.*]] = call ninf float @llvm.experimental.constrained.fadd.f32(float [[T]], float [[X]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[COULD_BE_NAN]]
+;
+ %t = fneg nnan float %x
+ %could_be_nan = call ninf float @llvm.experimental.constrained.fadd.f32(float %t, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %could_be_nan
+}
+
+define float @fadd_binary_fneg_nan_commute(float %x) #0 {
+; CHECK-LABEL: @fadd_binary_fneg_nan_commute(
+; CHECK-NEXT: [[T:%.*]] = call nnan ninf float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[COULD_BE_NAN:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X]], float [[T]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[COULD_BE_NAN]]
+;
+ %t = call nnan ninf float @llvm.experimental.constrained.fsub.f32(float -0.0, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %could_be_nan = call float @llvm.experimental.constrained.fadd.f32(float %x, float %t, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %could_be_nan
+}
+
+define float @fadd_unary_fneg_nan_commute(float %x) #0 {
+; CHECK-LABEL: @fadd_unary_fneg_nan_commute(
+; CHECK-NEXT: [[T:%.*]] = fneg nnan ninf float [[X:%.*]]
+; CHECK-NEXT: [[COULD_BE_NAN:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X]], float [[T]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[COULD_BE_NAN]]
+;
+ %t = fneg nnan ninf float %x
+ %could_be_nan = call float @llvm.experimental.constrained.fadd.f32(float %x, float %t, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %could_be_nan
+}
+
+; X + (0.0 - X) --> 0.0 (with nnan on the fadd)
+
+define float @fadd_fsub_nnan_ninf(float %x) #0 {
+; CHECK-LABEL: @fadd_fsub_nnan_ninf(
+; CHECK-NEXT: [[SUB:%.*]] = call nnan ninf float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[ZERO:%.*]] = call nnan ninf float @llvm.experimental.constrained.fadd.f32(float [[X]], float [[SUB]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[ZERO]]
+;
+ %sub = call nnan ninf float @llvm.experimental.constrained.fsub.f32(float 0.0, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %zero = call nnan ninf float @llvm.experimental.constrained.fadd.f32(float %x, float %sub, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %zero
+}
+
+; (0.0 - X) + X --> 0.0 (with nnan on the fadd)
+
+define <2 x float> @fadd_fsub_nnan_ninf_commute_vec(<2 x float> %x) #0 {
+; CHECK-LABEL: @fadd_fsub_nnan_ninf_commute_vec(
+; CHECK-NEXT: [[SUB:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[ZERO:%.*]] = call nnan ninf <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[SUB]], <2 x float> [[X]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[ZERO]]
+;
+ %sub = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %zero = call nnan ninf <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %sub, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %zero
+}
+
+; 'ninf' is not required because 'nnan' allows us to assume
+; that X is not INF or -INF (adding opposite INFs would be NaN).
+
+define float @fadd_fsub_nnan(float %x) #0 {
+; CHECK-LABEL: @fadd_fsub_nnan(
+; CHECK-NEXT: [[SUB:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[ZERO:%.*]] = call nnan float @llvm.experimental.constrained.fadd.f32(float [[SUB]], float [[X]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[ZERO]]
+;
+ %sub = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %zero = call nnan float @llvm.experimental.constrained.fadd.f32(float %sub, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %zero
+}
+
+; fsub nnan x, x ==> 0.0
+define float @fsub_x_x(float %a) #0 {
+; X - X ==> 0
+; CHECK-LABEL: @fsub_x_x(
+; CHECK-NEXT: [[NO_ZERO1:%.*]] = call ninf float @llvm.experimental.constrained.fsub.f32(float [[A:%.*]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[NO_ZERO2:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[A]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[NO_ZERO:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[NO_ZERO1]], float [[NO_ZERO2]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[NO_ZERO]]
+;
+ %zero1 = call nnan float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+
+; Dont fold
+ %no_zero1 = call ninf float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %no_zero2 = call float @llvm.experimental.constrained.fsub.f32(float %a, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %no_zero = call float @llvm.experimental.constrained.fadd.f32(float %no_zero1, float %no_zero2, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+
+; Should get folded
+ %ret = call nsz float @llvm.experimental.constrained.fadd.f32(float %no_zero, float %zero1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+
+ ret float %ret
+}
+
+; fsub nsz 0.0, (fsub 0.0, X) ==> X
+define float @fsub_0_0_x(float %a) #0 {
+; CHECK-LABEL: @fsub_0_0_x(
+; CHECK-NEXT: [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[RET:%.*]] = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[RET]]
+;
+ %t1 = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %ret
+}
+
+; fsub nsz 0.0, (fneg X) ==> X
+define float @fneg_x(float %a) #0 {
+; CHECK-LABEL: @fneg_x(
+; CHECK-NEXT: ret float [[A:%.*]]
+;
+ %t1 = fneg float %a
+ %ret = call nsz float @llvm.experimental.constrained.fsub.f32(float 0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %ret
+}
+
+define <2 x float> @fsub_0_0_x_vec_undef1(<2 x float> %a) #0 {
+; CHECK-LABEL: @fsub_0_0_x_vec_undef1(
+; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float 0.000000e+00, float undef>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[RET:%.*]] = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[RET]]
+;
+ %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float 0.0, float undef>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %ret
+}
+
+define <2 x float> @fneg_x_vec_undef1(<2 x float> %a) #0 {
+; CHECK-LABEL: @fneg_x_vec_undef1(
+; CHECK-NEXT: ret <2 x float> [[A:%.*]]
+;
+ %t1 = fneg <2 x float> %a
+ %ret = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float 0.0, float undef>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %ret
+}
+
+define <2 x float> @fsub_0_0_x_vec_undef2(<2 x float> %a) #0 {
+; CHECK-LABEL: @fsub_0_0_x_vec_undef2(
+; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[RET:%.*]] = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.000000e+00>, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[RET]]
+;
+ %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> zeroinitializer, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.0>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %ret
+}
+
+; fadd nsz X, 0 ==> X
+
+define <2 x float> @fadd_zero_nsz_vec(<2 x float> %x) #0 {
+; CHECK-LABEL: @fadd_zero_nsz_vec(
+; CHECK-NEXT: ret <2 x float> [[X:%.*]]
+;
+ %r = call nsz <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> zeroinitializer, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %r
+}
+
+define <2 x float> @fadd_zero_nsz_vec_undef(<2 x float> %x) #0 {
+; CHECK-LABEL: @fadd_zero_nsz_vec_undef(
+; CHECK-NEXT: ret <2 x float> [[X:%.*]]
+;
+ %r = call nsz <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> <float 0.0, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %r
+}
+
+define float @nofold_fadd_x_0(float %a) #0 {
+; Dont fold
+; CHECK-LABEL: @nofold_fadd_x_0(
+; CHECK-NEXT: [[NO_ZERO1:%.*]] = call ninf float @llvm.experimental.constrained.fadd.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[NO_ZERO2:%.*]] = call nnan float @llvm.experimental.constrained.fadd.f32(float [[A]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[NO_ZERO:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[NO_ZERO1]], float [[NO_ZERO2]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[NO_ZERO]]
+;
+ %no_zero1 = call ninf float @llvm.experimental.constrained.fadd.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %no_zero2 = call nnan float @llvm.experimental.constrained.fadd.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %no_zero = call float @llvm.experimental.constrained.fadd.f32(float %no_zero1, float %no_zero2, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %no_zero
+}
+
+define float @fold_fadd_nsz_x_0(float %a) #0 {
+; CHECK-LABEL: @fold_fadd_nsz_x_0(
+; CHECK-NEXT: ret float [[A:%.*]]
+;
+ %add = call nsz float @llvm.experimental.constrained.fadd.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %add
+}
+
+; 'nsz' does not guarantee that -0.0 does not occur, so this does not simplify.
+
+define float @fold_fadd_cannot_be_neg0_nsz_src_x_0(float %a, float %b) #0 {
+; CHECK-LABEL: @fold_fadd_cannot_be_neg0_nsz_src_x_0(
+; CHECK-NEXT: [[NSZ:%.*]] = call nsz float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float [[B:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[ADD:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[NSZ]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %nsz = call nsz float @llvm.experimental.constrained.fmul.f32(float %a, float %b, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %add = call float @llvm.experimental.constrained.fadd.f32(float %nsz, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %add
+}
+
+define float @fold_fadd_cannot_be_neg0_fabs_src_x_0(float %a) #0 {
+; CHECK-LABEL: @fold_fadd_cannot_be_neg0_fabs_src_x_0(
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %fabs = call float @llvm.fabs.f32(float %a)
+ %add = call float @llvm.experimental.constrained.fadd.f32(float %fabs, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %add
+}
+
+; 'nsz' does not guarantee that -0.0 does not occur, so this does not simplify.
+
+define float @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0(float %a, float %b) #0 {
+; CHECK-LABEL: @fold_fadd_cannot_be_neg0_sqrt_nsz_src_x_0(
+; CHECK-NEXT: [[NSZ:%.*]] = call nsz float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float [[B:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[SQRT:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[NSZ]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[ADD:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[SQRT]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %nsz = call nsz float @llvm.experimental.constrained.fmul.f32(float %a, float %b, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %sqrt = call float @llvm.experimental.constrained.sqrt.f32(float %nsz, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %add = call float @llvm.experimental.constrained.fadd.f32(float %sqrt, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %add
+}
+
+; 'nsz' does not guarantee that -0.0 does not occur, so this does not simplify.
+
+define float @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0(float %a, float %b) #0 {
+; CHECK-LABEL: @fold_fadd_cannot_be_neg0_canonicalize_nsz_src_x_0(
+; CHECK-NEXT: [[NSZ:%.*]] = call nsz float @llvm.experimental.constrained.fmul.f32(float [[A:%.*]], float [[B:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[CANON:%.*]] = call float @llvm.canonicalize.f32(float [[NSZ]])
+; CHECK-NEXT: [[ADD:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[CANON]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[ADD]]
+;
+ %nsz = call nsz float @llvm.experimental.constrained.fmul.f32(float %a, float %b, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %canon = call float @llvm.canonicalize.f32(float %nsz)
+ %add = call float @llvm.experimental.constrained.fadd.f32(float %canon, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %add
+}
+
+; fdiv nsz nnan 0, X ==> 0
+; 0 / X -> 0
+
+define double @fdiv_zero_by_x(double %x) #0 {
+; CHECK-LABEL: @fdiv_zero_by_x(
+; CHECK-NEXT: ret double 0.000000e+00
+;
+ %r = call nnan nsz double @llvm.experimental.constrained.fdiv.f64(double 0.0, double %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret double %r
+}
+
+define <2 x double> @fdiv_zero_by_x_vec_undef(<2 x double> %x) #0 {
+; CHECK-LABEL: @fdiv_zero_by_x_vec_undef(
+; CHECK-NEXT: ret <2 x double> zeroinitializer
+;
+ %r = call nnan nsz <2 x double> @llvm.experimental.constrained.fdiv.v2f64(<2 x double> <double 0.0, double undef>, <2 x double> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x double> %r
+}
+
+; 0 % X -> 0
+; nsz is not necessary - frem result always has the sign of the dividend
+
+define double @frem_zero_by_x(double %x) #0 {
+; CHECK-LABEL: @frem_zero_by_x(
+; CHECK-NEXT: ret double 0.000000e+00
+;
+ %r = call nnan double @llvm.experimental.constrained.frem.f64(double 0.0, double %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret double %r
+}
+
+define <2 x double> @frem_poszero_by_x_vec_undef(<2 x double> %x) #0 {
+; CHECK-LABEL: @frem_poszero_by_x_vec_undef(
+; CHECK-NEXT: ret <2 x double> zeroinitializer
+;
+ %r = call nnan <2 x double> @llvm.experimental.constrained.frem.v2f64(<2 x double> <double 0.0, double undef>, <2 x double> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x double> %r
+}
+
+; -0 % X -> -0
+; nsz is not necessary - frem result always has the sign of the dividend
+
+define double @frem_negzero_by_x(double %x) #0 {
+; CHECK-LABEL: @frem_negzero_by_x(
+; CHECK-NEXT: ret double -0.000000e+00
+;
+ %r = call nnan double @llvm.experimental.constrained.frem.f64(double -0.0, double %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret double %r
+}
+
+define <2 x double> @frem_negzero_by_x_vec_undef(<2 x double> %x) #0 {
+; CHECK-LABEL: @frem_negzero_by_x_vec_undef(
+; CHECK-NEXT: ret <2 x double> <double -0.000000e+00, double -0.000000e+00>
+;
+ %r = call nnan <2 x double> @llvm.experimental.constrained.frem.v2f64(<2 x double> <double undef, double -0.0>, <2 x double> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x double> %r
+}
+
+define float @fdiv_self(float %f) #0 {
+; CHECK-LABEL: @fdiv_self(
+; CHECK-NEXT: ret float 1.000000e+00
+;
+ %div = call nnan float @llvm.experimental.constrained.fdiv.f32(float %f, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %div
+}
+
+define float @fdiv_self_invalid(float %f) #0 {
+; CHECK-LABEL: @fdiv_self_invalid(
+; CHECK-NEXT: [[DIV:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[F:%.*]], float [[F]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[DIV]]
+;
+ %div = call float @llvm.experimental.constrained.fdiv.f32(float %f, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %div
+}
+
+define float @fdiv_neg1(float %f) #0 {
+; CHECK-LABEL: @fdiv_neg1(
+; CHECK-NEXT: [[NEG:%.*]] = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[DIV:%.*]] = call nnan float @llvm.experimental.constrained.fdiv.f32(float [[NEG]], float [[F]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[DIV]]
+;
+ %neg = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %div = call nnan float @llvm.experimental.constrained.fdiv.f32(float %neg, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %div
+}
+
+define float @fdiv_neg2(float %f) #0 {
+; CHECK-LABEL: @fdiv_neg2(
+; CHECK-NEXT: [[NEG:%.*]] = call fast float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[DIV:%.*]] = call nnan float @llvm.experimental.constrained.fdiv.f32(float [[NEG]], float [[F]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[DIV]]
+;
+ %neg = call fast float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %div = call nnan float @llvm.experimental.constrained.fdiv.f32(float %neg, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %div
+}
+
+define float @fdiv_neg_invalid(float %f) #0 {
+; CHECK-LABEL: @fdiv_neg_invalid(
+; CHECK-NEXT: [[NEG:%.*]] = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[DIV:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[NEG]], float [[F]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[DIV]]
+;
+ %neg = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %div = call float @llvm.experimental.constrained.fdiv.f32(float %neg, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %div
+}
+
+define float @fdiv_neg_swapped1(float %f) #0 {
+; CHECK-LABEL: @fdiv_neg_swapped1(
+; CHECK-NEXT: [[NEG:%.*]] = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[DIV:%.*]] = call nnan float @llvm.experimental.constrained.fdiv.f32(float [[F]], float [[NEG]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[DIV]]
+;
+ %neg = call fast float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %div = call nnan float @llvm.experimental.constrained.fdiv.f32(float %f, float %neg, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %div
+}
+
+define float @fdiv_neg_swapped2(float %f) #0 {
+; CHECK-LABEL: @fdiv_neg_swapped2(
+; CHECK-NEXT: [[NEG:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[DIV:%.*]] = call nnan float @llvm.experimental.constrained.fdiv.f32(float [[F]], float [[NEG]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[DIV]]
+;
+ %neg = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %div = call nnan float @llvm.experimental.constrained.fdiv.f32(float %f, float %neg, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %div
+}
+
+define <2 x float> @fdiv_neg_vec_undef_elt(<2 x float> %f) #0 {
+; CHECK-LABEL: @fdiv_neg_vec_undef_elt(
+; CHECK-NEXT: [[NEG:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float 0.000000e+00, float undef>, <2 x float> [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[DIV:%.*]] = call nnan <2 x float> @llvm.experimental.constrained.fdiv.v2f32(<2 x float> [[F]], <2 x float> [[NEG]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[DIV]]
+;
+ %neg = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float 0.000000e+00, float undef>, <2 x float> %f, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %div = call nnan <2 x float> @llvm.experimental.constrained.fdiv.v2f32(<2 x float> %f, <2 x float> %neg, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %div
+}
+
+; PR21126: http://llvm.org/bugs/show_bug.cgi?id=21126
+; With loose math, sqrt(X) * sqrt(X) is just X.
+
+declare double @llvm.sqrt.f64(double)
+
+define double @sqrt_squared(double %f) #0 {
+; CHECK-LABEL: @sqrt_squared(
+; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.experimental.constrained.sqrt.f64(double [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
+; CHECK-NEXT: [[MUL:%.*]] = call reassoc nnan nsz double @llvm.experimental.constrained.fmul.f64(double [[SQRT]], double [[SQRT]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret double [[MUL]]
+;
+ %sqrt = call double @llvm.experimental.constrained.sqrt.f64(double %f, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+ %mul = call reassoc nnan nsz double @llvm.experimental.constrained.fmul.f64(double %sqrt, double %sqrt, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret double %mul
+}
+
+; Negative tests for the above transform: we need all 3 of those flags.
+
+define double @sqrt_squared_not_fast_enough1(double %f) #0 {
+; CHECK-LABEL: @sqrt_squared_not_fast_enough1(
+; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.experimental.constrained.sqrt.f64(double [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
+; CHECK-NEXT: [[MUL:%.*]] = call nnan nsz double @llvm.experimental.constrained.fmul.f64(double [[SQRT]], double [[SQRT]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret double [[MUL]]
+;
+ %sqrt = call double @llvm.experimental.constrained.sqrt.f64(double %f, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+ %mul = call nnan nsz double @llvm.experimental.constrained.fmul.f64(double %sqrt, double %sqrt, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret double %mul
+}
+
+define double @sqrt_squared_not_fast_enough2(double %f) #0 {
+; CHECK-LABEL: @sqrt_squared_not_fast_enough2(
+; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.experimental.constrained.sqrt.f64(double [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
+; CHECK-NEXT: [[MUL:%.*]] = call reassoc nnan double @llvm.experimental.constrained.fmul.f64(double [[SQRT]], double [[SQRT]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret double [[MUL]]
+;
+ %sqrt = call double @llvm.experimental.constrained.sqrt.f64(double %f, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+ %mul = call reassoc nnan double @llvm.experimental.constrained.fmul.f64(double %sqrt, double %sqrt, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret double %mul
+}
+
+define double @sqrt_squared_not_fast_enough3(double %f) #0 {
+; CHECK-LABEL: @sqrt_squared_not_fast_enough3(
+; CHECK-NEXT: [[SQRT:%.*]] = call double @llvm.experimental.constrained.sqrt.f64(double [[F:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore")
+; CHECK-NEXT: [[MUL:%.*]] = call reassoc nsz double @llvm.experimental.constrained.fmul.f64(double [[SQRT]], double [[SQRT]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret double [[MUL]]
+;
+ %sqrt = call double @llvm.experimental.constrained.sqrt.f64(double %f, metadata !"round.tonearest", metadata !"fpexcept.ignore")
+ %mul = call reassoc nsz double @llvm.experimental.constrained.fmul.f64(double %sqrt, double %sqrt, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret double %mul
+}
+
+declare float @llvm.fabs.f32(float)
+declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata) #0
+declare double @llvm.experimental.constrained.sqrt.f64(double, metadata, metadata) #0
+declare float @llvm.canonicalize.f32(float)
+
+declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) #0
+declare <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0
+
+declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) #0
+declare <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0
+
+declare float @llvm.experimental.constrained.fmul.f32(float, float, metadata, metadata) #0
+declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata) #0
+declare <2 x float> @llvm.experimental.constrained.fmul.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0
+
+declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) #0
+declare double @llvm.experimental.constrained.fdiv.f64(double, double, metadata, metadata) #0
+declare <2 x float> @llvm.experimental.constrained.fdiv.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0
+declare <2 x double> @llvm.experimental.constrained.fdiv.v2f64(<2 x double>, <2 x double>, metadata, metadata) #0
+
+declare double @llvm.experimental.constrained.frem.f64(double, double, metadata, metadata) #0
+declare <2 x double> @llvm.experimental.constrained.frem.v2f64(<2 x double>, <2 x double>, metadata, metadata) #0
+
+attributes #0 = { strictfp }
+
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+define float @fdiv_constant_fold() #0 {
+; CHECK-LABEL: @fdiv_constant_fold(
+; CHECK-NEXT: ret float 1.500000e+00
+;
+ %f = call float @llvm.experimental.constrained.fdiv.f32(float 3.0, float 2.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+
+ ret float %f
+}
+
+define float @fdiv_constant_fold_strict() #0 {
+; CHECK-LABEL: @fdiv_constant_fold_strict(
+; CHECK-NEXT: [[F:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float 3.000000e+00, float 2.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: ret float [[F]]
+;
+ %f = call float @llvm.experimental.constrained.fdiv.f32(float 3.0, float 2.0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0
+
+ ret float %f
+}
+
+define float @frem_constant_fold() #0 {
+; CHECK-LABEL: @frem_constant_fold(
+; CHECK-NEXT: ret float 1.500000e+00
+;
+ %f = call float @llvm.experimental.constrained.fdiv.f32(float 3.0, float 2.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %f
+}
+
+define float @frem_constant_fold_strict() #0 {
+; CHECK-LABEL: @frem_constant_fold_strict(
+; CHECK-NEXT: [[F:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float 3.000000e+00, float 2.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.strict") #[[ATTR0]]
+; CHECK-NEXT: ret float [[F]]
+;
+ %f = call float @llvm.experimental.constrained.fdiv.f32(float 3.0, float 2.0, metadata !"round.tonearest", metadata !"fpexcept.strict") #0
+ ret float %f
+}
+
+define double @fmul_fdiv_common_operand(double %x, double %y) #0 {
+; CHECK-LABEL: @fmul_fdiv_common_operand(
+; CHECK-NEXT: [[M:%.*]] = call double @llvm.experimental.constrained.fmul.f64(double [[X:%.*]], double [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[D:%.*]] = call reassoc nnan double @llvm.experimental.constrained.fdiv.f64(double [[M]], double [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret double [[D]]
+;
+ %m = call double @llvm.experimental.constrained.fmul.f64(double %x, double %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %d = call reassoc nnan double @llvm.experimental.constrained.fdiv.f64(double %m, double %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret double %d
+}
+
+; Negative test - the fdiv must be reassociative and not allow NaNs.
+
+define double @fmul_fdiv_common_operand_too_strict(double %x, double %y) #0 {
+; CHECK-LABEL: @fmul_fdiv_common_operand_too_strict(
+; CHECK-NEXT: [[M:%.*]] = call fast double @llvm.experimental.constrained.fmul.f64(double [[X:%.*]], double [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[D:%.*]] = call reassoc double @llvm.experimental.constrained.fdiv.f64(double [[M]], double [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret double [[D]]
+;
+ %m = call fast double @llvm.experimental.constrained.fmul.f64(double %x, double %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %d = call reassoc double @llvm.experimental.constrained.fdiv.f64(double %m, double %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret double %d
+}
+
+; Commute the fmul operands. Use a vector type to verify that works too.
+
+define <2 x float> @fmul_fdiv_common_operand_commute_vec(<2 x float> %x, <2 x float> %y) #0 {
+; CHECK-LABEL: @fmul_fdiv_common_operand_commute_vec(
+; CHECK-NEXT: [[M:%.*]] = call <2 x float> @llvm.experimental.constrained.fmul.v2f32(<2 x float> [[Y:%.*]], <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[D:%.*]] = call fast <2 x float> @llvm.experimental.constrained.fdiv.v2f32(<2 x float> [[M]], <2 x float> [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[D]]
+;
+ %m = call <2 x float> @llvm.experimental.constrained.fmul.v2f32(<2 x float> %y, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %d = call fast <2 x float> @llvm.experimental.constrained.fdiv.v2f32(<2 x float> %m, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %d
+}
+
+declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata) #0
+declare <2 x float> @llvm.experimental.constrained.fmul.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0
+
+declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) #0
+declare double @llvm.experimental.constrained.fdiv.f64(double, double, metadata, metadata) #0
+declare <2 x float> @llvm.experimental.constrained.fdiv.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0
+
+declare float @llvm.experimental.constrained.frem.f32(float, float, metadata, metadata) #0
+
+attributes #0 = { strictfp }
+
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -instsimplify -S | FileCheck %s
+
+; fneg (fsub -0.0, X) ==> X
+define float @fsub_-0_x(float %a) #0 {
+; CHECK-LABEL: @fsub_-0_x(
+; CHECK-NEXT: [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0:[0-9]+]]
+; CHECK-NEXT: [[RET:%.*]] = fneg float [[T1]]
+; CHECK-NEXT: ret float [[RET]]
+;
+ %t1 = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = fneg float %t1
+ ret float %ret
+}
+
+define <2 x float> @fsub_-0_x_vec(<2 x float> %a) #0 {
+; CHECK-LABEL: @fsub_-0_x_vec(
+; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[RET:%.*]] = fneg <2 x float> [[T1]]
+; CHECK-NEXT: ret <2 x float> [[RET]]
+;
+ %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = fneg <2 x float> %t1
+ ret <2 x float> %ret
+}
+
+define <2 x float> @fsub_-0_x_vec_undef_elts(<2 x float> %a) #0 {
+; CHECK-LABEL: @fsub_-0_x_vec_undef_elts(
+; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float undef>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[RET:%.*]] = fneg <2 x float> [[T1]]
+; CHECK-NEXT: ret <2 x float> [[RET]]
+;
+ %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float undef>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = fneg <2 x float> %t1
+ ret <2 x float> %ret
+}
+
+define <2 x float> @fsub_negzero_vec_undef_elts(<2 x float> %x) #0 {
+; CHECK-LABEL: @fsub_negzero_vec_undef_elts(
+; CHECK-NEXT: [[R:%.*]] = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.000000e+00>, <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[R]]
+;
+ %r = call nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float undef, float -0.0>, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %r
+}
+
+; fsub -0.0, (fsub -0.0, X) ==> X
+define float @fsub_-0_-0_x(float %a) #0 {
+; CHECK-LABEL: @fsub_-0_-0_x(
+; CHECK-NEXT: [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[RET]]
+;
+ %t1 = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %ret
+}
+
+; fsub -0.0, (fneg X) ==> X
+define float @fneg_x(float %a) #0 {
+; CHECK-LABEL: @fneg_x(
+; CHECK-NEXT: ret float [[A:%.*]]
+;
+ %t1 = fneg float %a
+ %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %ret
+}
+
+define <2 x float> @fsub_-0_-0_x_vec(<2 x float> %a) #0 {
+; CHECK-LABEL: @fsub_-0_-0_x_vec(
+; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float -0.000000e+00>, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[RET]]
+;
+ %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %ret
+}
+
+define <2 x float> @fneg_x_vec(<2 x float> %a) #0 {
+; CHECK-LABEL: @fneg_x_vec(
+; CHECK-NEXT: ret <2 x float> [[A:%.*]]
+;
+ %t1 = fneg <2 x float> %a
+ %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float -0.0>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %ret
+}
+
+define <2 x float> @fsub_-0_-0_x_vec_undef_elts(<2 x float> %a) #0 {
+; CHECK-LABEL: @fsub_-0_-0_x_vec_undef_elts(
+; CHECK-NEXT: [[T1:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float undef, float -0.000000e+00>, <2 x float> [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> <float -0.000000e+00, float undef>, <2 x float> [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[RET]]
+;
+ %t1 = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float undef, float -0.0>, <2 x float> %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float undef>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %ret
+}
+
+define <2 x float> @fneg_x_vec_undef_elts(<2 x float> %a) #0 {
+; CHECK-LABEL: @fneg_x_vec_undef_elts(
+; CHECK-NEXT: ret <2 x float> [[A:%.*]]
+;
+ %t1 = fneg <2 x float> %a
+ %ret = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float><float -0.0, float undef>, <2 x float> %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %ret
+}
+
+; fsub -0.0, (fsub 0.0, X) != X
+define float @fsub_-0_0_x(float %a) #0 {
+; CHECK-LABEL: @fsub_-0_0_x(
+; CHECK-NEXT: [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[RET]]
+;
+ %t1 = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %ret
+}
+
+; fsub 0.0, (fsub -0.0, X) != X
+define float @fsub_0_-0_x(float %a) #0 {
+; CHECK-LABEL: @fsub_0_-0_x(
+; CHECK-NEXT: [[T1:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float -0.000000e+00, float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float 0.000000e+00, float [[T1]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[RET]]
+;
+ %t1 = call float @llvm.experimental.constrained.fsub.f32(float -0.0, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %ret = call float @llvm.experimental.constrained.fsub.f32(float 0.0, float %t1, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %ret
+}
+
+; fsub X, 0 ==> X
+define float @fsub_x_0(float %x) #0 {
+; CHECK-LABEL: @fsub_x_0(
+; CHECK-NEXT: ret float [[X:%.*]]
+;
+ %r = call float @llvm.experimental.constrained.fsub.f32(float %x, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+define <2 x float> @fsub_x_0_vec_undef(<2 x float> %x) #0 {
+; CHECK-LABEL: @fsub_x_0_vec_undef(
+; CHECK-NEXT: ret <2 x float> [[X:%.*]]
+;
+ %r = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %x, <2 x float><float undef, float 0.0>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %r
+}
+
+; fadd X, -0 ==> X
+define float @fadd_x_n0(float %a) #0 {
+; CHECK-LABEL: @fadd_x_n0(
+; CHECK-NEXT: ret float [[A:%.*]]
+;
+ %ret = call float @llvm.experimental.constrained.fadd.f32(float %a, float -0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %ret
+}
+
+define <2 x float> @fadd_x_n0_vec_undef_elt(<2 x float> %a) #0 {
+; CHECK-LABEL: @fadd_x_n0_vec_undef_elt(
+; CHECK-NEXT: ret <2 x float> [[A:%.*]]
+;
+ %ret = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %a, <2 x float> <float -0.0, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %ret
+}
+
+; fadd X, 0 ==> X
+define float @fadd_x_p0(float %a) #0 {
+; CHECK-LABEL: @fadd_x_p0(
+; CHECK-NEXT: [[RET:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[A:%.*]], float 0.000000e+00, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[RET]]
+;
+ %ret = call float @llvm.experimental.constrained.fadd.f32(float %a, float 0.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %ret
+}
+
+define <2 x float> @fadd_x_p0_vec_undef_elt(<2 x float> %a) #0 {
+; CHECK-LABEL: @fadd_x_p0_vec_undef_elt(
+; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[A:%.*]], <2 x float> <float 0.000000e+00, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[RET]]
+;
+ %ret = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %a, <2 x float> <float 0.0, float undef>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %ret
+}
+
+; fmul X, 1.0 ==> X
+define double @fmul_X_1(double %a) #0 {
+; CHECK-LABEL: @fmul_X_1(
+; CHECK-NEXT: ret double [[A:%.*]]
+;
+ %b = call double @llvm.experimental.constrained.fmul.f64(double 1.0, double %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret double %b
+}
+
+; Originally PR2642
+define <4 x float> @fmul_X_1_vec(<4 x float> %x) {
+; CHECK-LABEL: @fmul_X_1_vec(
+; CHECK-NEXT: ret <4 x float> [[X:%.*]]
+;
+ %m = call <4 x float> @llvm.experimental.constrained.fmul.v4f32(<4 x float> %x, <4 x float> <float 1.0, float 1.0, float 1.0, float 1.0>, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <4 x float> %m
+}
+
+; fdiv X, 1.0 ==> X
+define float @fdiv_x_1(float %a) #0 {
+; CHECK-LABEL: @fdiv_x_1(
+; CHECK-NEXT: ret float [[A:%.*]]
+;
+ %ret = call float @llvm.experimental.constrained.fdiv.f32(float %a, float 1.0, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+
+ ret float %ret
+}
+
+
+; The fabs can't be eliminated because llvm.experimental.constrained.sqrt.f32 may return -0 or NaN with
+; an arbitrary sign bit.
+define float @fabs_sqrt(float %a) #0 {
+; CHECK-LABEL: @fabs_sqrt(
+; CHECK-NEXT: [[SQRT:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %sqrt = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %fabs = call float @llvm.fabs.f32(float %sqrt)
+ ret float %fabs
+}
+
+; The fabs can't be eliminated because the nnan sqrt may still return -0.
+define float @fabs_sqrt_nnan(float %a) #0 {
+; CHECK-LABEL: @fabs_sqrt_nnan(
+; CHECK-NEXT: [[SQRT:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %sqrt = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %fabs = call float @llvm.fabs.f32(float %sqrt)
+ ret float %fabs
+}
+
+; The fabs can't be eliminated because the nsz sqrt may still return NaN.
+define float @fabs_sqrt_nsz(float %a) #0 {
+; CHECK-LABEL: @fabs_sqrt_nsz(
+; CHECK-NEXT: [[SQRT:%.*]] = call nsz float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %sqrt = call nsz float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %fabs = call float @llvm.fabs.f32(float %sqrt)
+ ret float %fabs
+}
+
+; The fabs can be eliminated because we're nsz and nnan.
+define float @fabs_sqrt_nnan_nsz(float %a) #0 {
+; CHECK-LABEL: @fabs_sqrt_nnan_nsz(
+; CHECK-NEXT: [[SQRT:%.*]] = call nnan nsz float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %sqrt = call nnan nsz float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %fabs = call float @llvm.fabs.f32(float %sqrt)
+ ret float %fabs
+}
+
+; The second fabs can be eliminated because the operand to sqrt cannot be -0.
+define float @fabs_sqrt_nnan_fabs(float %a) #0 {
+; CHECK-LABEL: @fabs_sqrt_nnan_fabs(
+; CHECK-NEXT: [[B:%.*]] = call float @llvm.fabs.f32(float [[A:%.*]])
+; CHECK-NEXT: [[SQRT:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[B]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SQRT]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %b = call float @llvm.fabs.f32(float %a)
+ %sqrt = call nnan float @llvm.experimental.constrained.sqrt.f32(float %b, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %fabs = call float @llvm.fabs.f32(float %sqrt)
+ ret float %fabs
+}
+
+; Y - (Y - X) --> X
+
+define float @fsub_fsub_common_op(float %x, float %y) #0 {
+; CHECK-LABEL: @fsub_fsub_common_op(
+; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+define <2 x float> @fsub_fsub_common_op_vec(<2 x float> %x, <2 x float> %y) #0 {
+; CHECK-LABEL: @fsub_fsub_common_op_vec(
+; CHECK-NEXT: [[S:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[Y:%.*]], <2 x float> [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[Y]], <2 x float> [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[R]]
+;
+ %s = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %y, <2 x float> %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %y, <2 x float> %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %r
+}
+
+; Negative test - fsub is not commutative.
+; Y - (X - Y) --> (Y - X) + Y (canonicalized)
+
+define float @fsub_fsub_wrong_common_op(float %x, float %y) #0 {
+; CHECK-LABEL: @fsub_fsub_wrong_common_op(
+; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+; Negative test - negated operand needed.
+; (Y - X) - Y --> -X
+
+define float @fsub_fsub_common_op_wrong_commute(float %x, float %y) #0 {
+; CHECK-LABEL: @fsub_fsub_common_op_wrong_commute(
+; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+; Negative test - fsub is not commutative.
+; (X - Y) - Y --> ?
+
+define float @fsub_fsub_wrong_common_op_wrong_commute(float %x, float %y) #0 {
+; CHECK-LABEL: @fsub_fsub_wrong_common_op_wrong_commute(
+; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+; (Y + X) - Y --> X
+
+define float @fadd_fsub_common_op(float %x, float %y) #0 {
+; CHECK-LABEL: @fadd_fsub_common_op(
+; CHECK-NEXT: [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[A]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %a = call float @llvm.experimental.constrained.fadd.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %a, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+; (X + Y) - Y --> X
+
+define <2 x float> @fadd_fsub_common_op_commute_vec(<2 x float> %x, <2 x float> %y) #0 {
+; CHECK-LABEL: @fadd_fsub_common_op_commute_vec(
+; CHECK-NEXT: [[A:%.*]] = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[A]], <2 x float> [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[R]]
+;
+ %a = call <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %x, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %a, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %r
+}
+
+; Negative test - negated operand needed.
+; Y - (Y + X) --> -X
+
+define float @fadd_fsub_common_op_wrong_commute(float %x, float %y) #0 {
+; CHECK-LABEL: @fadd_fsub_common_op_wrong_commute(
+; CHECK-NEXT: [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %a = call float @llvm.experimental.constrained.fadd.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+; Negative test - negated operand needed.
+; Y - (X + Y) --> -X
+
+define float @fadd_fsub_common_op_wrong_commute_commute(float %x, float %y) #0 {
+; CHECK-LABEL: @fadd_fsub_common_op_wrong_commute_commute(
+; CHECK-NEXT: [[A:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float [[Y]], float [[A]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %a = call float @llvm.experimental.constrained.fadd.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz float @llvm.experimental.constrained.fsub.f32(float %y, float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+; Y + (X - Y) --> X
+
+define <2 x float> @fsub_fadd_common_op_vec(<2 x float> %x, <2 x float> %y) #0 {
+; CHECK-LABEL: @fsub_fadd_common_op_vec(
+; CHECK-NEXT: [[S:%.*]] = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> [[X:%.*]], <2 x float> [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> [[Y]], <2 x float> [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret <2 x float> [[R]]
+;
+ %s = call <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float> %x, <2 x float> %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float> %y, <2 x float> %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret <2 x float> %r
+}
+
+; (X - Y) + Y --> X
+
+define float @fsub_fadd_common_op_commute(float %x, float %y) #0 {
+; CHECK-LABEL: @fsub_fadd_common_op_commute(
+; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %s = call float @llvm.experimental.constrained.fsub.f32(float %x, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+; Negative test.
+; Y + (Y - X) --> ?
+
+define float @fsub_fadd_common_op_wrong_commute(float %x, float %y) #0 {
+; CHECK-LABEL: @fsub_fadd_common_op_wrong_commute(
+; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[Y]], float [[S]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %y, float %s, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+; Negative test.
+; (Y - X) + Y --> ?
+
+define float @fsub_fadd_common_op_wrong_commute_commute(float %x, float %y) #0 {
+; CHECK-LABEL: @fsub_fadd_common_op_wrong_commute_commute(
+; CHECK-NEXT: [[S:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[Y:%.*]], float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[R:%.*]] = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float [[S]], float [[Y]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: ret float [[R]]
+;
+ %s = call float @llvm.experimental.constrained.fsub.f32(float %y, float %x, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %r = call reassoc nsz float @llvm.experimental.constrained.fadd.f32(float %s, float %y, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ ret float %r
+}
+
+; Originally PR46627 - https://bugs.llvm.org/show_bug.cgi?id=46627
+
+define float @maxnum_with_poszero_op(float %a) #0 {
+; CHECK-LABEL: @maxnum_with_poszero_op(
+; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[A:%.*]], float 0.000000e+00, metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %max = call float @llvm.experimental.constrained.maxnum.f32(float %a, float 0.0, metadata !"fpexcept.ignore") #0
+ %fabs = call float @llvm.fabs.f32(float %max)
+ ret float %fabs
+}
+
+define float @maxnum_with_poszero_op_commute(float %a) #0 {
+; CHECK-LABEL: @maxnum_with_poszero_op_commute(
+; CHECK-NEXT: [[SQRT:%.*]] = call float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float 0.000000e+00, float [[SQRT]], metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %sqrt = call float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %max = call float @llvm.experimental.constrained.maxnum.f32(float 0.0, float %sqrt, metadata !"fpexcept.ignore") #0
+ %fabs = call float @llvm.fabs.f32(float %max)
+ ret float %fabs
+}
+
+define float @maxnum_with_negzero_op(float %a) #0 {
+; CHECK-LABEL: @maxnum_with_negzero_op(
+; CHECK-NEXT: [[NNAN:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABSA:%.*]] = call float @llvm.fabs.f32(float [[NNAN]])
+; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float -0.000000e+00, float [[FABSA]], metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %nnan = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %fabsa = call float @llvm.fabs.f32(float %nnan)
+ %max = call float @llvm.experimental.constrained.maxnum.f32(float -0.0, float %fabsa, metadata !"fpexcept.ignore") #0
+ %fabs = call float @llvm.fabs.f32(float %max)
+ ret float %fabs
+}
+
+define float @maxnum_with_negzero_op_commute(float %a) #0 {
+; CHECK-LABEL: @maxnum_with_negzero_op_commute(
+; CHECK-NEXT: [[NNAN:%.*]] = call nnan float @llvm.experimental.constrained.sqrt.f32(float [[A:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABSA:%.*]] = call float @llvm.fabs.f32(float [[NNAN]])
+; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[FABSA]], float -0.000000e+00, metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %nnan = call nnan float @llvm.experimental.constrained.sqrt.f32(float %a, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
+ %fabsa = call float @llvm.fabs.f32(float %nnan)
+ %max = call float @llvm.experimental.constrained.maxnum.f32(float %fabsa, float -0.0, metadata !"fpexcept.ignore") #0
+ %fabs = call float @llvm.fabs.f32(float %max)
+ ret float %fabs
+}
+
+; If an operand is strictly greater than 0.0, we know the sign of the result of maxnum.
+
+define float @maxnum_with_pos_one_op(float %a) #0 {
+; CHECK-LABEL: @maxnum_with_pos_one_op(
+; CHECK-NEXT: [[MAX:%.*]] = call float @llvm.experimental.constrained.maxnum.f32(float [[A:%.*]], float 1.000000e+00, metadata !"fpexcept.ignore") #[[ATTR0]]
+; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[MAX]])
+; CHECK-NEXT: ret float [[FABS]]
+;
+ %max = call float @llvm.experimental.constrained.maxnum.f32(float %a, float 1.0, metadata !"fpexcept.ignore") #0
+ %fabs = call float @llvm.fabs.f32(float %max)
+ ret float %fabs
+}
+
+declare float @llvm.fabs.f32(float)
+declare <2 x float> @llvm.fabs.v2f32(<2 x float>)
+
+declare float @llvm.experimental.constrained.fadd.f32(float, float, metadata, metadata) #0
+declare <2 x float> @llvm.experimental.constrained.fadd.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0
+
+declare float @llvm.experimental.constrained.fsub.f32(float, float, metadata, metadata) #0
+declare <2 x float> @llvm.experimental.constrained.fsub.v2f32(<2 x float>, <2 x float>, metadata, metadata) #0
+
+declare double @llvm.experimental.constrained.fmul.f64(double, double, metadata, metadata) #0
+declare <4 x float> @llvm.experimental.constrained.fmul.v4f32(<4 x float>, <4 x float>, metadata, metadata) #0
+
+declare float @llvm.experimental.constrained.fdiv.f32(float, float, metadata, metadata) #0
+
+declare float @llvm.experimental.constrained.maxnum.f32(float, float, metadata) #0
+declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata) #0
+
+attributes #0 = { strictfp }
define float @fadd_undef_op0_defaultfp(float %x) #0 {
; CHECK-LABEL: @fadd_undef_op0_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float undef, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float poison, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%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_defaultfp(float %x) #0 {
; CHECK-LABEL: @fadd_undef_op1_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fadd.f32(float [[X:%.*]], float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%r = call float @llvm.experimental.constrained.fadd.f32(float %x, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
ret float %r
define float @fsub_undef_op0_defaultfp(float %x) {
; CHECK-LABEL: @fsub_undef_op0_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float undef, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float poison, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%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_defaultfp(float %x) {
; CHECK-LABEL: @fsub_undef_op1_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fsub.f32(float [[X:%.*]], float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%r = call float @llvm.experimental.constrained.fsub.f32(float %x, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
ret float %r
define float @fmul_undef_op0_defaultfp(float %x) {
; CHECK-LABEL: @fmul_undef_op0_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float undef, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float poison, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%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_defaultfp(float %x) {
; CHECK-LABEL: @fmul_undef_op1_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fmul.f32(float [[X:%.*]], float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%r = call float @llvm.experimental.constrained.fmul.f32(float %x, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
ret float %r
define float @fdiv_undef_op0_defaultfp(float %x) {
; CHECK-LABEL: @fdiv_undef_op0_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float undef, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float poison, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%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_defaultfp(float %x) {
; CHECK-LABEL: @fdiv_undef_op1_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fdiv.f32(float [[X:%.*]], float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%r = call float @llvm.experimental.constrained.fdiv.f32(float %x, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
ret float %r
define float @frem_undef_op0_defaultfp(float %x) {
; CHECK-LABEL: @frem_undef_op0_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float undef, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float poison, float [[X:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%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_defaultfp(float %x) {
; CHECK-LABEL: @frem_undef_op1_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.frem.f32(float [[X:%.*]], float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%r = call float @llvm.experimental.constrained.frem.f32(float %x, float poison, metadata !"round.tonearest", 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: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float undef, float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float poison, float [[X:%.*]], float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%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_defaultfp(float %x, float %y) {
; CHECK-LABEL: @fma_undef_op1_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float undef, float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float poison, float [[Y:%.*]], metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%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_defaultfp(float %x, float %y) {
; CHECK-LABEL: @fma_undef_op2_defaultfp(
-; CHECK-NEXT: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float undef, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; 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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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]]
+; CHECK-NEXT: ret float poison
;
%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: [[R:%.*]] = call float @llvm.experimental.constrained.fma.f32(float [[X:%.*]], float [[Y:%.*]], float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #[[ATTR0]]
-; CHECK-NEXT: ret float [[R]]
+; CHECK-NEXT: ret float poison
;
%r = call float @llvm.experimental.constrained.fma.f32(float %x, float %y, float poison, metadata !"round.tonearest", metadata !"fpexcept.ignore") #0
ret float %r