[IR] Add AllowContract to FastMathFlags

-ffp-contract=fast does not currently work with LTO because it's passed as a
TargetOption to the backend rather than in the IR. This adds it to
FastMathFlags.

This is toward fixing PR25721

Differential Revision: https://reviews.llvm.org/D31164

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@298939 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Adam Nemet 2017-03-28 20:11:52 +00:00
parent d707b92e85
commit 5c57c1108e
13 changed files with 79 additions and 2 deletions

View File

@ -2194,6 +2194,10 @@ otherwise unsafe floating point transformations.
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

View File

@ -345,6 +345,9 @@ public:
/// 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.

View File

@ -172,12 +172,15 @@ private:
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;
@ -193,6 +196,7 @@ public:
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
@ -200,12 +204,16 @@ public:
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) {
@ -257,6 +265,12 @@ private:
(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) {
@ -300,6 +314,12 @@ public:
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);

View File

@ -548,6 +548,7 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(ninf);
KEYWORD(nsz);
KEYWORD(arcp);
KEYWORD(contract);
KEYWORD(fast);
KEYWORD(nuw);
KEYWORD(nsw);

View File

@ -193,6 +193,10 @@ namespace llvm {
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;

View File

@ -98,6 +98,7 @@ enum Kind {
kw_ninf,
kw_nsz,
kw_arcp,
kw_contract,
kw_fast,
kw_nuw,
kw_nsw,

View File

@ -971,6 +971,8 @@ static FastMathFlags getDecodedFastMathFlags(unsigned Val) {
FMF.setNoSignedZeros();
if (0 != (Val & FastMathFlags::AllowReciprocal))
FMF.setAllowReciprocal();
if (0 != (Val & FastMathFlags::AllowContract))
FMF.setAllowContract(true);
return FMF;
}

View File

@ -1336,6 +1336,8 @@ static uint64_t getOptimizationFlags(const Value *V) {
Flags |= FastMathFlags::NoSignedZeros;
if (FPMO->hasAllowReciprocal())
Flags |= FastMathFlags::AllowReciprocal;
if (FPMO->hasAllowContract())
Flags |= FastMathFlags::AllowContract;
}
return Flags;

View File

@ -1073,6 +1073,8 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
Out << " nsz";
if (FPO->hasAllowReciprocal())
Out << " arcp";
if (FPO->hasAllowContract())
Out << " contract";
}
}

View File

@ -204,6 +204,11 @@ bool Instruction::hasAllowReciprocal() const {
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();

View File

@ -74,6 +74,18 @@ entry:
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:

View File

@ -760,6 +760,8 @@ define void @fastmathflags(float %op1, float %op2) {
; 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

View File

@ -207,7 +207,26 @@ TEST_F(IRBuilderTest, FastMathFlags) {
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);