Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1983,6 +1983,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; @@ -4118,10 +4134,22 @@ cast(I)->setIsExact(true); } else if (isa(I)) { FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]); + if (SetNoFEnvFMF) { + // Enable optimizations for older bitcode, when these flags were not + // available. + FMF.setNoExceptions(); + FMF.setNoRounding(); + } if (FMF.any()) I->setFastMathFlags(FMF); } - + } else if (SetNoFEnvFMF && isa(I)) { + FastMathFlags FMF; + // Enable optimizations for older bitcode, when these flags were not + // available. + FMF.setNoExceptions(); + FMF.setNoRounding(); + I->setFastMathFlags(FMF); } break; } 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 @@ -1067,6 +1067,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 }