Allow Reciprocal - Allow optimizations to use the reciprocal of an
argument rather than perform division.
+``contract``
+ Allow floating-point contraction (e.g. fusing a multiply followed by an
+ addition into a fused multiply-and-add).
+
``fast``
Fast - Allow algebraically equivalent transformations that may
dramatically change results in floating point (e.g. reassociate). This
/// Determine whether the allow-reciprocal flag is set.
bool hasAllowReciprocal() const;
+ /// Determine whether the allow-contract flag is set.
+ bool hasAllowContract() const;
+
/// Convenience function for getting all the fast-math flags, which must be an
/// operator which supports these flags. See LangRef.html for the meaning of
/// these flags.
FastMathFlags(unsigned F) : Flags(F) { }
public:
+ /// This is how the bits are used in Value::SubclassOptionalData so they
+ /// should fit there too.
enum {
UnsafeAlgebra = (1 << 0),
NoNaNs = (1 << 1),
NoInfs = (1 << 2),
NoSignedZeros = (1 << 3),
- AllowReciprocal = (1 << 4)
+ AllowReciprocal = (1 << 4),
+ AllowContract = (1 << 5)
};
FastMathFlags() = default;
bool noInfs() const { return 0 != (Flags & NoInfs); }
bool noSignedZeros() const { return 0 != (Flags & NoSignedZeros); }
bool allowReciprocal() const { return 0 != (Flags & AllowReciprocal); }
+ bool allowContract() const { return 0 != (Flags & AllowContract); }
bool unsafeAlgebra() const { return 0 != (Flags & UnsafeAlgebra); }
/// Flag setters
void setNoInfs() { Flags |= NoInfs; }
void setNoSignedZeros() { Flags |= NoSignedZeros; }
void setAllowReciprocal() { Flags |= AllowReciprocal; }
+ void setAllowContract(bool B) {
+ Flags = (Flags & ~AllowContract) | B * AllowContract;
+ }
void setUnsafeAlgebra() {
Flags |= UnsafeAlgebra;
setNoNaNs();
setNoInfs();
setNoSignedZeros();
setAllowReciprocal();
+ setAllowContract(true);
}
void operator&=(const FastMathFlags &OtherFlags) {
(B * FastMathFlags::AllowReciprocal);
}
+ void setHasAllowContract(bool B) {
+ SubclassOptionalData =
+ (SubclassOptionalData & ~FastMathFlags::AllowContract) |
+ (B * FastMathFlags::AllowContract);
+ }
+
/// Convenience function for setting multiple fast-math flags.
/// FMF is a mask of the bits to set.
void setFastMathFlags(FastMathFlags FMF) {
return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0;
}
+ /// Test whether this operation is permitted to
+ /// be floating-point contracted.
+ bool hasAllowContract() const {
+ return (SubclassOptionalData & FastMathFlags::AllowContract) != 0;
+ }
+
/// Convenience function for getting all the fast-math flags
FastMathFlags getFastMathFlags() const {
return FastMathFlags(SubclassOptionalData);
KEYWORD(ninf);
KEYWORD(nsz);
KEYWORD(arcp);
+ KEYWORD(contract);
KEYWORD(fast);
KEYWORD(nuw);
KEYWORD(nsw);
case lltok::kw_ninf: FMF.setNoInfs(); Lex.Lex(); continue;
case lltok::kw_nsz: FMF.setNoSignedZeros(); Lex.Lex(); continue;
case lltok::kw_arcp: FMF.setAllowReciprocal(); Lex.Lex(); continue;
+ case lltok::kw_contract:
+ FMF.setAllowContract(true);
+ Lex.Lex();
+ continue;
default: return FMF;
}
return FMF;
kw_ninf,
kw_nsz,
kw_arcp,
+ kw_contract,
kw_fast,
kw_nuw,
kw_nsw,
FMF.setNoSignedZeros();
if (0 != (Val & FastMathFlags::AllowReciprocal))
FMF.setAllowReciprocal();
+ if (0 != (Val & FastMathFlags::AllowContract))
+ FMF.setAllowContract(true);
return FMF;
}
Flags |= FastMathFlags::NoSignedZeros;
if (FPMO->hasAllowReciprocal())
Flags |= FastMathFlags::AllowReciprocal;
+ if (FPMO->hasAllowContract())
+ Flags |= FastMathFlags::AllowContract;
}
return Flags;
Out << " nsz";
if (FPO->hasAllowReciprocal())
Out << " arcp";
+ if (FPO->hasAllowContract())
+ Out << " contract";
}
}
return cast<FPMathOperator>(this)->hasAllowReciprocal();
}
+bool Instruction::hasAllowContract() const {
+ assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
+ return cast<FPMathOperator>(this)->hasAllowContract();
+}
+
FastMathFlags Instruction::getFastMathFlags() const {
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
return cast<FPMathOperator>(this)->getFastMathFlags();
ret float %e
}
+; CHECK: @contract(
+define float @contract(float %x, float %y) {
+entry:
+; CHECK: %a = fsub contract float %x, %y
+ %a = fsub contract float %x, %y
+; CHECK: %b = fadd contract float %x, %y
+ %b = fadd contract float %x, %y
+; CHECK: %c = fmul contract float %a, %b
+ %c = fmul contract float %a, %b
+ ret float %c
+}
+
; CHECK: no_nan_inf
define float @no_nan_inf(float %x, float %y) {
entry:
; CHECK: %f.nsz = fadd nsz float %op1, %op2
%f.arcp = fadd arcp float %op1, %op2
; CHECK: %f.arcp = fadd arcp float %op1, %op2
+ %f.contract = fadd contract float %op1, %op2
+ ; CHECK: %f.contract = fadd contract float %op1, %op2
%f.fast = fadd fast float %op1, %op2
; CHECK: %f.fast = fadd fast float %op1, %op2
ret void
EXPECT_TRUE(FCmp->hasAllowReciprocal());
Builder.clearFastMathFlags();
-
+
+ // Test FP-contract
+ FC = Builder.CreateFAdd(F, F);
+ ASSERT_TRUE(isa<Instruction>(FC));
+ FAdd = cast<Instruction>(FC);
+ EXPECT_FALSE(FAdd->hasAllowContract());
+
+ FMF.clear();
+ FMF.setAllowContract(true);
+ Builder.setFastMathFlags(FMF);
+
+ FC = Builder.CreateFAdd(F, F);
+ EXPECT_TRUE(Builder.getFastMathFlags().any());
+ EXPECT_TRUE(Builder.getFastMathFlags().AllowContract);
+ ASSERT_TRUE(isa<Instruction>(FC));
+ FAdd = cast<Instruction>(FC);
+ EXPECT_TRUE(FAdd->hasAllowContract());
+
+ Builder.clearFastMathFlags();
+
// Test a call with FMF.
auto CalleeTy = FunctionType::get(Type::getFloatTy(Ctx),
/*isVarArg=*/false);