Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1993,6 +1993,12 @@ Allow Reciprocal - Allow optimizations to use the reciprocal of an argument rather than perform division. +``nexc`` + No Exceptions - Assume that floating-point exceptions are not observed. + +``nrnd`` + No Rounding - Assume that the rounding-mode is round-to-nearest (ties even). + ``fast`` Fast - Allow algebraically equivalent transformations that may dramatically change results in floating point (e.g. reassociate). This Index: include/llvm/IR/Instruction.h =================================================================== --- include/llvm/IR/Instruction.h +++ include/llvm/IR/Instruction.h @@ -242,6 +242,16 @@ /// this flag. void setHasAllowReciprocal(bool B); + /// Set or clear the no-exceptions flag on this instruction, which must be an + /// operator which supports this flag. See LangRef.html for the meaning of + /// this flag. + void setHasNoExceptions(bool B); + + /// Set or clear the no-rounding flag on this instruction, which must be an + /// operator which supports this flag. See LangRef.html for the meaning of + /// this flag. + void setHasNoRounding(bool B); + /// Convenience function for setting multiple fast-math flags on this /// instruction, which must be an operator which supports these flags. See /// LangRef.html for the meaning of these flags. @@ -267,6 +277,12 @@ /// Determine whether the allow-reciprocal flag is set. bool hasAllowReciprocal() const; + /// Determine whether the no-exceptions flag is set. + bool hasNoExceptions() const; + + /// Determine whether the no-rounding flag is set. + bool hasNoRounding() 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. Index: include/llvm/IR/Operator.h =================================================================== --- include/llvm/IR/Operator.h +++ include/llvm/IR/Operator.h @@ -173,7 +173,9 @@ NoNaNs = (1 << 1), NoInfs = (1 << 2), NoSignedZeros = (1 << 3), - AllowReciprocal = (1 << 4) + AllowReciprocal = (1 << 4), + NoExceptions = (1 << 5), + NoRounding = (1 << 6) }; FastMathFlags() : Flags(0) @@ -191,18 +193,24 @@ bool noSignedZeros() const { return 0 != (Flags & NoSignedZeros); } bool allowReciprocal() const { return 0 != (Flags & AllowReciprocal); } bool unsafeAlgebra() const { return 0 != (Flags & UnsafeAlgebra); } + bool noExceptions() const { return 0 != (Flags & NoExceptions); } + bool noRounding() const { return 0 != (Flags & NoRounding); } /// Flag setters void setNoNaNs() { Flags |= NoNaNs; } void setNoInfs() { Flags |= NoInfs; } void setNoSignedZeros() { Flags |= NoSignedZeros; } void setAllowReciprocal() { Flags |= AllowReciprocal; } + void setNoExceptions() { Flags |= NoExceptions; } + void setNoRounding() { Flags |= NoRounding; } void setUnsafeAlgebra() { Flags |= UnsafeAlgebra; setNoNaNs(); setNoInfs(); setNoSignedZeros(); setAllowReciprocal(); + setNoExceptions(); + setNoRounding(); } void operator&=(const FastMathFlags &OtherFlags) { @@ -250,6 +258,16 @@ (SubclassOptionalData & ~FastMathFlags::AllowReciprocal) | (B * FastMathFlags::AllowReciprocal); } + void setHasNoExceptions(bool B) { + SubclassOptionalData = + (SubclassOptionalData & ~FastMathFlags::NoExceptions) | + (B * FastMathFlags::NoExceptions); + } + void setHasNoRounding(bool B) { + SubclassOptionalData = + (SubclassOptionalData & ~FastMathFlags::NoRounding) | + (B * FastMathFlags::NoRounding); + } /// Convenience function for setting multiple fast-math flags. /// FMF is a mask of the bits to set. @@ -294,6 +312,18 @@ return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0; } + /// Test whether this operation can be optimized even if its runtime + /// semantics regarding floating-point exceptions won't be preserved. + bool hasNoExceptions() const { + return (SubclassOptionalData & FastMathFlags::NoExceptions) != 0; + } + + /// Test whether this operation can be optimized assuming use of + /// round-to-nearest (ties even) rounding mode at run-time. + bool hasNoRounding() const { + return (SubclassOptionalData & FastMathFlags::NoRounding) != 0; + } + /// Convenience function for getting all the fast-math flags FastMathFlags getFastMathFlags() const { return FastMathFlags(SubclassOptionalData); Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -548,6 +548,8 @@ KEYWORD(ninf); KEYWORD(nsz); KEYWORD(arcp); + KEYWORD(nexc); + KEYWORD(nrnd); KEYWORD(fast); KEYWORD(nuw); KEYWORD(nsw); Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -198,6 +198,8 @@ 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_nexc: FMF.setNoExceptions(); Lex.Lex(); continue; + case lltok::kw_nrnd: FMF.setNoRounding(); Lex.Lex(); continue; default: return FMF; } return FMF; Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -68,6 +68,8 @@ kw_ninf, kw_nsz, kw_arcp, + kw_nexc, + kw_nrnd, kw_fast, kw_nuw, kw_nsw, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -225,6 +225,12 @@ /// not need this flag. bool UseRelativeIDs = false; + /// Indicates that floating-point environment flags must be set to values + /// that correspond to behaviour before addition of nexc and nrnd fast-math + /// flags (i.e., enable aggressive optimizations of operations on + /// floating-point values). + bool SetNoFEnvFMF = false; + /// True if all functions will be materialized, negating the need to process /// (e.g.) blockaddress forward references. bool WillMaterializeAllForwardRefs = false; @@ -854,6 +860,10 @@ FMF.setNoSignedZeros(); if (0 != (Val & FastMathFlags::AllowReciprocal)) FMF.setAllowReciprocal(); + if (0 != (Val & FastMathFlags::NoExceptions)) + FMF.setNoExceptions(); + if (0 != (Val & FastMathFlags::NoRounding)) + FMF.setNoRounding(); return FMF; } @@ -3381,16 +3391,22 @@ case bitc::MODULE_CODE_VERSION: { // VERSION: [version#] if (Record.size() < 1) return error("Invalid record"); - // Only version #0 and #1 are supported so far. + // Only version #0 -- #2 are supported so far. unsigned module_version = Record[0]; switch (module_version) { default: return error("Invalid value"); case 0: UseRelativeIDs = false; + SetNoFEnvFMF = true; break; case 1: UseRelativeIDs = true; + SetNoFEnvFMF = true; + break; + case 2: + UseRelativeIDs = true; + SetNoFEnvFMF = false; break; } break; @@ -4101,6 +4117,7 @@ return error("Invalid record"); I = BinaryOperator::Create((Instruction::BinaryOps)Opc, LHS, RHS); InstructionList.push_back(I); + FastMathFlags FMF; if (OpNum < Record.size()) { if (Opc == Instruction::Add || Opc == Instruction::Sub || @@ -4117,12 +4134,17 @@ if (Record[OpNum] & (1 << bitc::PEO_EXACT)) cast(I)->setIsExact(true); } else if (isa(I)) { - FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); - if (FMF.any()) - I->setFastMathFlags(FMF); + FMF = getDecodedFastMathFlags(Record[OpNum]); } - } + if (SetNoFEnvFMF && isa(I)) { + // Enable optimizations for older bitcode, when these flags were not + // available. + FMF.setNoExceptions(); + FMF.setNoRounding(); + } + if (FMF.any()) + I->setFastMathFlags(FMF); break; } case bitc::FUNC_CODE_INST_CAST: { // CAST: [opval, opty, destty, castopc] Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -818,6 +818,10 @@ Flags |= FastMathFlags::NoSignedZeros; if (FPMO->hasAllowReciprocal()) Flags |= FastMathFlags::AllowReciprocal; + if (FPMO->hasNoExceptions()) + Flags |= FastMathFlags::NoExceptions; + if (FPMO->hasNoRounding()) + Flags |= FastMathFlags::NoRounding; } return Flags; @@ -2886,7 +2890,7 @@ Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3); SmallVector Vals; - unsigned CurVersion = 1; + unsigned CurVersion = 2; Vals.push_back(CurVersion); Stream.EmitRecord(bitc::MODULE_CODE_VERSION, Vals); @@ -3080,7 +3084,7 @@ Stream.EnterSubblock(bitc::MODULE_BLOCK_ID, 3); SmallVector Vals; - unsigned CurVersion = 1; + unsigned CurVersion = 2; Vals.push_back(CurVersion); Stream.EmitRecord(bitc::MODULE_CODE_VERSION, Vals); Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1069,6 +1069,10 @@ Out << " nsz"; if (FPO->hasAllowReciprocal()) Out << " arcp"; + if (FPO->hasNoExceptions()) + Out << " nexc"; + if (FPO->hasNoRounding()) + Out << " nrnd"; } } Index: lib/IR/Instruction.cpp =================================================================== --- lib/IR/Instruction.cpp +++ lib/IR/Instruction.cpp @@ -130,6 +130,22 @@ cast(this)->setHasAllowReciprocal(B); } +/// Set or clear the no-exceptions flag on this instruction, which must be an +/// operator which supports this flag. See LangRef.html for the meaning of this +/// flag. +void Instruction::setHasNoExceptions(bool B) { + assert(isa(this) && "setting fast-math flag on invalid op"); + cast(this)->setHasNoExceptions(B); +} + +/// Set or clear the no-rounding flag on this instruction, which must be an +/// operator which supports this flag. See LangRef.html for the meaning of this +/// flag. +void Instruction::setHasNoRounding(bool B) { + assert(isa(this) && "setting fast-math flag on invalid op"); + cast(this)->setHasNoRounding(B); +} + /// Convenience function for setting all the fast-math flags on this /// instruction, which must be an operator which supports these flags. See /// LangRef.html for the meaning of these flats. @@ -173,6 +189,18 @@ return cast(this)->hasAllowReciprocal(); } +/// Determine whether the no-exceptions flag is set. +bool Instruction::hasNoExceptions() const { + assert(isa(this) && "getting fast-math flag on invalid op"); + return cast(this)->hasNoExceptions(); +} + +/// Determine whether the no-rounding flag is set. +bool Instruction::hasNoRounding() const { + assert(isa(this) && "getting fast-math flag on invalid op"); + return cast(this)->hasNoRounding(); +} + /// 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. Index: test/Assembler/fast-math-flags.ll =================================================================== --- test/Assembler/fast-math-flags.ll +++ test/Assembler/fast-math-flags.ll @@ -138,6 +138,14 @@ %e = frem nnan nsz float %x, %y ; CHECK: %e_vec = frem nnan <3 x float> %vec, %vec %e_vec = frem nnan <3 x float> %vec, %vec +; CHECK: %f = fmul fast float %x, %y + %f = fmul nexc nrnd fast float %x, %y +; CHECK: %f_vec = frem fast <3 x float> %vec, %vec + %f_vec = frem nexc nrnd fast <3 x float> %vec, %vec +; CHECK: %g = fmul nexc nrnd float %x, %y + %g = fmul nexc nrnd float %x, %y +; CHECK: %g_vec = frem nexc nrnd <3 x float> %vec, %vec + %g_vec = frem nexc nrnd <3 x float> %vec, %vec ; CHECK: ret float %e ret float %e } Index: test/Bitcode/binaryFloatInstructions.3.2.ll =================================================================== --- test/Bitcode/binaryFloatInstructions.3.2.ll +++ test/Bitcode/binaryFloatInstructions.3.2.ll @@ -7,115 +7,115 @@ define void @fadd(float %x1, double %x2 ,half %x3, fp128 %x4, x86_fp80 %x5, ppc_fp128 %x6){ entry: -; CHECK: %res1 = fadd float %x1, %x1 - %res1 = fadd float %x1, %x1 +; CHECK: %res1 = fadd nexc nrnd float %x1, %x1 + %res1 = fadd nexc nrnd float %x1, %x1 -; CHECK-NEXT: %res2 = fadd double %x2, %x2 - %res2 = fadd double %x2, %x2 +; CHECK-NEXT: %res2 = fadd nexc nrnd double %x2, %x2 + %res2 = fadd nexc nrnd double %x2, %x2 -; CHECK-NEXT: %res3 = fadd half %x3, %x3 - %res3 = fadd half %x3, %x3 +; CHECK-NEXT: %res3 = fadd nexc nrnd half %x3, %x3 + %res3 = fadd nexc nrnd half %x3, %x3 -; CHECK-NEXT: %res4 = fadd fp128 %x4, %x4 - %res4 = fadd fp128 %x4, %x4 +; CHECK-NEXT: %res4 = fadd nexc nrnd fp128 %x4, %x4 + %res4 = fadd nexc nrnd fp128 %x4, %x4 -; CHECK-NEXT: %res5 = fadd x86_fp80 %x5, %x5 - %res5 = fadd x86_fp80 %x5, %x5 +; CHECK-NEXT: %res5 = fadd nexc nrnd x86_fp80 %x5, %x5 + %res5 = fadd nexc nrnd x86_fp80 %x5, %x5 -; CHECK-NEXT: %res6 = fadd ppc_fp128 %x6, %x6 - %res6 = fadd ppc_fp128 %x6, %x6 +; CHECK-NEXT: %res6 = fadd nexc nrnd ppc_fp128 %x6, %x6 + %res6 = fadd nexc nrnd ppc_fp128 %x6, %x6 ret void } define void @faddFloatVec(<2 x float> %x1, <3 x float> %x2 ,<4 x float> %x3, <8 x float> %x4, <16 x float> %x5){ entry: -; CHECK: %res1 = fadd <2 x float> %x1, %x1 - %res1 = fadd <2 x float> %x1, %x1 +; CHECK: %res1 = fadd nexc nrnd <2 x float> %x1, %x1 + %res1 = fadd nexc nrnd <2 x float> %x1, %x1 -; CHECK-NEXT: %res2 = fadd <3 x float> %x2, %x2 - %res2 = fadd <3 x float> %x2, %x2 +; CHECK-NEXT: %res2 = fadd nexc nrnd <3 x float> %x2, %x2 + %res2 = fadd nexc nrnd <3 x float> %x2, %x2 -; CHECK-NEXT: %res3 = fadd <4 x float> %x3, %x3 - %res3 = fadd <4 x float> %x3, %x3 +; CHECK-NEXT: %res3 = fadd nexc nrnd <4 x float> %x3, %x3 + %res3 = fadd nexc nrnd <4 x float> %x3, %x3 -; CHECK-NEXT: %res4 = fadd <8 x float> %x4, %x4 - %res4 = fadd <8 x float> %x4, %x4 +; CHECK-NEXT: %res4 = fadd nexc nrnd <8 x float> %x4, %x4 + %res4 = fadd nexc nrnd <8 x float> %x4, %x4 -; CHECK-NEXT: %res5 = fadd <16 x float> %x5, %x5 - %res5 = fadd <16 x float> %x5, %x5 +; CHECK-NEXT: %res5 = fadd nexc nrnd <16 x float> %x5, %x5 + %res5 = fadd nexc nrnd <16 x float> %x5, %x5 ret void } define void @faddDoubleVec(<2 x double> %x1, <3 x double> %x2 ,<4 x double> %x3, <8 x double> %x4, <16 x double> %x5){ entry: -; CHECK: %res1 = fadd <2 x double> %x1, %x1 - %res1 = fadd <2 x double> %x1, %x1 +; CHECK: %res1 = fadd nexc nrnd <2 x double> %x1, %x1 + %res1 = fadd nexc nrnd <2 x double> %x1, %x1 -; CHECK-NEXT: %res2 = fadd <3 x double> %x2, %x2 - %res2 = fadd <3 x double> %x2, %x2 +; CHECK-NEXT: %res2 = fadd nexc nrnd <3 x double> %x2, %x2 + %res2 = fadd nexc nrnd <3 x double> %x2, %x2 -; CHECK-NEXT: %res3 = fadd <4 x double> %x3, %x3 - %res3 = fadd <4 x double> %x3, %x3 +; CHECK-NEXT: %res3 = fadd nexc nrnd <4 x double> %x3, %x3 + %res3 = fadd nexc nrnd <4 x double> %x3, %x3 -; CHECK-NEXT: %res4 = fadd <8 x double> %x4, %x4 - %res4 = fadd <8 x double> %x4, %x4 +; CHECK-NEXT: %res4 = fadd nexc nrnd <8 x double> %x4, %x4 + %res4 = fadd nexc nrnd <8 x double> %x4, %x4 -; CHECK-NEXT: %res5 = fadd <16 x double> %x5, %x5 - %res5 = fadd <16 x double> %x5, %x5 +; CHECK-NEXT: %res5 = fadd nexc nrnd <16 x double> %x5, %x5 + %res5 = fadd nexc nrnd <16 x double> %x5, %x5 ret void } define void @faddHalfVec(<2 x half> %x1, <3 x half> %x2 ,<4 x half> %x3, <8 x half> %x4, <16 x half> %x5){ entry: -; CHECK: %res1 = fadd <2 x half> %x1, %x1 - %res1 = fadd <2 x half> %x1, %x1 +; CHECK: %res1 = fadd nexc nrnd <2 x half> %x1, %x1 + %res1 = fadd nexc nrnd <2 x half> %x1, %x1 -; CHECK-NEXT: %res2 = fadd <3 x half> %x2, %x2 - %res2 = fadd <3 x half> %x2, %x2 +; CHECK-NEXT: %res2 = fadd nexc nrnd <3 x half> %x2, %x2 + %res2 = fadd nexc nrnd <3 x half> %x2, %x2 -; CHECK-NEXT: %res3 = fadd <4 x half> %x3, %x3 - %res3 = fadd <4 x half> %x3, %x3 +; CHECK-NEXT: %res3 = fadd nexc nrnd <4 x half> %x3, %x3 + %res3 = fadd nexc nrnd <4 x half> %x3, %x3 -; CHECK-NEXT: %res4 = fadd <8 x half> %x4, %x4 - %res4 = fadd <8 x half> %x4, %x4 +; CHECK-NEXT: %res4 = fadd nexc nrnd <8 x half> %x4, %x4 + %res4 = fadd nexc nrnd <8 x half> %x4, %x4 -; CHECK-NEXT: %res5 = fadd <16 x half> %x5, %x5 - %res5 = fadd <16 x half> %x5, %x5 +; CHECK-NEXT: %res5 = fadd nexc nrnd <16 x half> %x5, %x5 + %res5 = fadd nexc nrnd <16 x half> %x5, %x5 ret void } define void @fsub(float %x1){ entry: -; CHECK: %res1 = fsub float %x1, %x1 - %res1 = fsub float %x1, %x1 +; CHECK: %res1 = fsub nexc nrnd float %x1, %x1 + %res1 = fsub nexc nrnd float %x1, %x1 ret void } define void @fmul(float %x1){ entry: -; CHECK: %res1 = fmul float %x1, %x1 - %res1 = fmul float %x1, %x1 +; CHECK: %res1 = fmul nexc nrnd float %x1, %x1 + %res1 = fmul nexc nrnd float %x1, %x1 ret void } define void @fdiv(float %x1){ entry: -; CHECK: %res1 = fdiv float %x1, %x1 - %res1 = fdiv float %x1, %x1 +; CHECK: %res1 = fdiv nexc nrnd float %x1, %x1 + %res1 = fdiv nexc nrnd float %x1, %x1 ret void } define void @frem(float %x1){ entry: -; CHECK: %res1 = frem float %x1, %x1 - %res1 = frem float %x1, %x1 +; CHECK: %res1 = frem nexc nrnd float %x1, %x1 + %res1 = frem nexc nrnd float %x1, %x1 ret void } Index: test/Bitcode/compatibility-3.6.ll =================================================================== --- test/Bitcode/compatibility-3.6.ll +++ test/Bitcode/compatibility-3.6.ll @@ -604,13 +604,13 @@ ;; Fast Math Flags define void @fastmathflags(float %op1, float %op2) { %f.nnan = fadd nnan float %op1, %op2 - ; CHECK: %f.nnan = fadd nnan float %op1, %op2 + ; CHECK: %f.nnan = fadd nnan nexc nrnd float %op1, %op2 %f.ninf = fadd ninf float %op1, %op2 - ; CHECK: %f.ninf = fadd ninf float %op1, %op2 + ; CHECK: %f.ninf = fadd ninf nexc nrnd float %op1, %op2 %f.nsz = fadd nsz float %op1, %op2 - ; CHECK: %f.nsz = fadd nsz float %op1, %op2 + ; CHECK: %f.nsz = fadd nsz nexc nrnd float %op1, %op2 %f.arcp = fadd arcp float %op1, %op2 - ; CHECK: %f.arcp = fadd arcp float %op1, %op2 + ; CHECK: %f.arcp = fadd arcp nexc nrnd float %op1, %op2 %f.fast = fadd fast float %op1, %op2 ; CHECK: %f.fast = fadd fast float %op1, %op2 ret void Index: test/Bitcode/compatibility-3.7.ll =================================================================== --- test/Bitcode/compatibility-3.7.ll +++ test/Bitcode/compatibility-3.7.ll @@ -648,13 +648,13 @@ ;; Fast Math Flags define void @fastmathflags(float %op1, float %op2) { %f.nnan = fadd nnan float %op1, %op2 - ; CHECK: %f.nnan = fadd nnan float %op1, %op2 + ; CHECK: %f.nnan = fadd nnan nexc nrnd float %op1, %op2 %f.ninf = fadd ninf float %op1, %op2 - ; CHECK: %f.ninf = fadd ninf float %op1, %op2 + ; CHECK: %f.ninf = fadd ninf nexc nrnd float %op1, %op2 %f.nsz = fadd nsz float %op1, %op2 - ; CHECK: %f.nsz = fadd nsz float %op1, %op2 + ; CHECK: %f.nsz = fadd nsz nexc nrnd float %op1, %op2 %f.arcp = fadd arcp float %op1, %op2 - ; CHECK: %f.arcp = fadd arcp float %op1, %op2 + ; CHECK: %f.arcp = fadd arcp nexc nrnd float %op1, %op2 %f.fast = fadd fast float %op1, %op2 ; CHECK: %f.fast = fadd fast float %op1, %op2 ret void Index: test/Bitcode/constantsTest.3.2.ll =================================================================== --- test/Bitcode/constantsTest.3.2.ll +++ test/Bitcode/constantsTest.3.2.ll @@ -30,8 +30,8 @@ %res3 = add i32 0, 0 ;float -; CHECK-NEXT: %res4 = fadd float 0.000000e+00, 0.000000e+00 - %res4 = fadd float 0.0, 0.0 +; CHECK-NEXT: %res4 = fadd nexc nrnd float 0.000000e+00, 0.000000e+00 + %res4 = fadd nexc nrnd float 0.0, 0.0 ret void }