From: Adam Nemet Date: Tue, 28 Mar 2017 20:11:52 +0000 (+0000) Subject: [IR] Add AllowContract to FastMathFlags X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=5c57c1108edaf065bc7d288d6024cad3aec3204a;p=llvm [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 --- diff --git a/docs/LangRef.rst b/docs/LangRef.rst index e7a6f6bd5de..4e574567430 100644 --- a/docs/LangRef.rst +++ b/docs/LangRef.rst @@ -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 diff --git a/include/llvm/IR/Instruction.h b/include/llvm/IR/Instruction.h index c256b53e00a..90c3175122f 100644 --- a/include/llvm/IR/Instruction.h +++ b/include/llvm/IR/Instruction.h @@ -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. diff --git a/include/llvm/IR/Operator.h b/include/llvm/IR/Operator.h index 9696754792e..997a85340c2 100644 --- a/include/llvm/IR/Operator.h +++ b/include/llvm/IR/Operator.h @@ -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); diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 752942fc9fc..49a8ce4bed0 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -548,6 +548,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(ninf); KEYWORD(nsz); KEYWORD(arcp); + KEYWORD(contract); KEYWORD(fast); KEYWORD(nuw); KEYWORD(nsw); diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index 7dae33480ed..3a794142172 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -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; diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index 048aeee90b3..33f8e63daa0 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -98,6 +98,7 @@ enum Kind { kw_ninf, kw_nsz, kw_arcp, + kw_contract, kw_fast, kw_nuw, kw_nsw, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 4bb0e9fb472..4198d8f7c10 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -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; } diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index b1200587e62..1bdb439086a 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -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; diff --git a/lib/IR/AsmWriter.cpp b/lib/IR/AsmWriter.cpp index ca00b1703cb..3afa3986052 100644 --- a/lib/IR/AsmWriter.cpp +++ b/lib/IR/AsmWriter.cpp @@ -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"; } } diff --git a/lib/IR/Instruction.cpp b/lib/IR/Instruction.cpp index d2114dc24af..c26699eab4e 100644 --- a/lib/IR/Instruction.cpp +++ b/lib/IR/Instruction.cpp @@ -204,6 +204,11 @@ bool Instruction::hasAllowReciprocal() const { return cast(this)->hasAllowReciprocal(); } +bool Instruction::hasAllowContract() const { + assert(isa(this) && "getting fast-math flag on invalid op"); + return cast(this)->hasAllowContract(); +} + FastMathFlags Instruction::getFastMathFlags() const { assert(isa(this) && "getting fast-math flag on invalid op"); return cast(this)->getFastMathFlags(); diff --git a/test/Assembler/fast-math-flags.ll b/test/Assembler/fast-math-flags.ll index f0d3ecc761d..4ef3607e1d0 100644 --- a/test/Assembler/fast-math-flags.ll +++ b/test/Assembler/fast-math-flags.ll @@ -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: diff --git a/test/Bitcode/compatibility.ll b/test/Bitcode/compatibility.ll index f1a883e53ad..b1f52bbe059 100644 --- a/test/Bitcode/compatibility.ll +++ b/test/Bitcode/compatibility.ll @@ -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 diff --git a/unittests/IR/IRBuilderTest.cpp b/unittests/IR/IRBuilderTest.cpp index 5b27fd66360..830ae958769 100644 --- a/unittests/IR/IRBuilderTest.cpp +++ b/unittests/IR/IRBuilderTest.cpp @@ -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(FC)); + FAdd = cast(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(FC)); + FAdd = cast(FC); + EXPECT_TRUE(FAdd->hasAllowContract()); + + Builder.clearFastMathFlags(); + // Test a call with FMF. auto CalleeTy = FunctionType::get(Type::getFloatTy(Ctx), /*isVarArg=*/false);