24 changes: 20 additions & 4 deletions llvm/include/llvm/IR/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -308,10 +308,15 @@ class Instruction : public User,
/// Determine whether the exact flag is set.
bool isExact() const;

/// Set or clear the unsafe-algebra flag on this instruction, which must be an
/// Set or clear all fast-math-flags on this instruction, which must be an
/// operator which supports this flag. See LangRef.html for the meaning of
/// this flag.
void setHasUnsafeAlgebra(bool B);
void setFast(bool B);

/// Set or clear the reassociation flag on this instruction, which must be
/// an operator which supports this flag. See LangRef.html for the meaning of
/// this flag.
void setHasAllowReassoc(bool B);

/// Set or clear the no-nans flag on this instruction, which must be an
/// operator which supports this flag. See LangRef.html for the meaning of
Expand All @@ -333,6 +338,11 @@ class Instruction : public User,
/// this flag.
void setHasAllowReciprocal(bool B);

/// Set or clear the approximate-math-functions flag on this instruction,
/// which must be an operator which supports this flag. See LangRef.html for
/// the meaning of this flag.
void setHasApproxFunc(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.
Expand All @@ -343,8 +353,11 @@ class Instruction : public User,
/// LangRef.html for the meaning of these flags.
void copyFastMathFlags(FastMathFlags FMF);

/// Determine whether the unsafe-algebra flag is set.
bool hasUnsafeAlgebra() const;
/// Determine whether all fast-math-flags are set.
bool isFast() const;

/// Determine whether the allow-reassociation flag is set.
bool hasAllowReassoc() const;

/// Determine whether the no-NaNs flag is set.
bool hasNoNaNs() const;
Expand All @@ -361,6 +374,9 @@ class Instruction : public User,
/// Determine whether the allow-contract flag is set.
bool hasAllowContract() const;

/// Determine whether the approximate-math-functions flag is set.
bool hasApproxFunc() 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.
Expand Down
113 changes: 71 additions & 42 deletions llvm/include/llvm/IR/Operator.h
Original file line number Diff line number Diff line change
Expand Up @@ -163,52 +163,61 @@ class FastMathFlags {

unsigned Flags = 0;

FastMathFlags(unsigned F) : Flags(F) { }
FastMathFlags(unsigned F) {
// If all 7 bits are set, turn this into -1. If the number of bits grows,
// this must be updated. This is intended to provide some forward binary
// compatibility insurance for the meaning of 'fast' in case bits are added.
if (F == 0x7F) Flags = ~0U;
else Flags = F;
}

public:
/// This is how the bits are used in Value::SubclassOptionalData so they
/// should fit there too.
// This is how the bits are used in Value::SubclassOptionalData so they
// should fit there too.
// WARNING: We're out of space. SubclassOptionalData only has 7 bits. New
// functionality will require a change in how this information is stored.
enum {
UnsafeAlgebra = (1 << 0),
AllowReassoc = (1 << 0),
NoNaNs = (1 << 1),
NoInfs = (1 << 2),
NoSignedZeros = (1 << 3),
AllowReciprocal = (1 << 4),
AllowContract = (1 << 5)
AllowContract = (1 << 5),
ApproxFunc = (1 << 6)
};

FastMathFlags() = default;

/// Whether any flag is set
bool any() const { return Flags != 0; }
bool none() const { return Flags == 0; }
bool all() const { return Flags == ~0U; }

/// Set all the flags to false
void clear() { Flags = 0; }
void set() { Flags = ~0U; }

/// Flag queries
bool allowReassoc() const { return 0 != (Flags & AllowReassoc); }
bool noNaNs() const { return 0 != (Flags & NoNaNs); }
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); }
bool allowContract() const { return 0 != (Flags & AllowContract); }
bool approxFunc() const { return 0 != (Flags & ApproxFunc); }
/// 'Fast' means all bits are set.
bool isFast() const { return all(); }

/// Flag setters
void setAllowReassoc() { Flags |= AllowReassoc; }
void setNoNaNs() { Flags |= NoNaNs; }
void setNoInfs() { Flags |= NoInfs; }
void setNoSignedZeros() { Flags |= NoSignedZeros; }
void setAllowReciprocal() { Flags |= AllowReciprocal; }
// TODO: Change the other set* functions to take a parameter?
void setAllowContract(bool B) {
Flags = (Flags & ~AllowContract) | B * AllowContract;
}
void setUnsafeAlgebra() {
Flags |= UnsafeAlgebra;
setNoNaNs();
setNoInfs();
setNoSignedZeros();
setAllowReciprocal();
setAllowContract(true);
}
void setApproxFunc() { Flags |= ApproxFunc; }
void setFast() { set(); }

void operator&=(const FastMathFlags &OtherFlags) {
Flags &= OtherFlags.Flags;
Expand All @@ -221,18 +230,21 @@ class FPMathOperator : public Operator {
private:
friend class Instruction;

void setHasUnsafeAlgebra(bool B) {
/// 'Fast' means all bits are set.
void setFast(bool B) {
setHasAllowReassoc(B);
setHasNoNaNs(B);
setHasNoInfs(B);
setHasNoSignedZeros(B);
setHasAllowReciprocal(B);
setHasAllowContract(B);
setHasApproxFunc(B);
}

void setHasAllowReassoc(bool B) {
SubclassOptionalData =
(SubclassOptionalData & ~FastMathFlags::UnsafeAlgebra) |
(B * FastMathFlags::UnsafeAlgebra);

// Unsafe algebra implies all the others
if (B) {
setHasNoNaNs(true);
setHasNoInfs(true);
setHasNoSignedZeros(true);
setHasAllowReciprocal(true);
}
(SubclassOptionalData & ~FastMathFlags::AllowReassoc) |
(B * FastMathFlags::AllowReassoc);
}

void setHasNoNaNs(bool B) {
Expand Down Expand Up @@ -265,6 +277,12 @@ class FPMathOperator : public Operator {
(B * FastMathFlags::AllowContract);
}

void setHasApproxFunc(bool B) {
SubclassOptionalData =
(SubclassOptionalData & ~FastMathFlags::ApproxFunc) |
(B * FastMathFlags::ApproxFunc);
}

/// Convenience function for setting multiple fast-math flags.
/// FMF is a mask of the bits to set.
void setFastMathFlags(FastMathFlags FMF) {
Expand All @@ -278,42 +296,53 @@ class FPMathOperator : public Operator {
}

public:
/// Test whether this operation is permitted to be
/// algebraically transformed, aka the 'A' fast-math property.
bool hasUnsafeAlgebra() const {
return (SubclassOptionalData & FastMathFlags::UnsafeAlgebra) != 0;
/// Test if this operation allows all non-strict floating-point transforms.
bool isFast() const {
return ((SubclassOptionalData & FastMathFlags::AllowReassoc) != 0 &&
(SubclassOptionalData & FastMathFlags::NoNaNs) != 0 &&
(SubclassOptionalData & FastMathFlags::NoInfs) != 0 &&
(SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0 &&
(SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0 &&
(SubclassOptionalData & FastMathFlags::AllowContract) != 0 &&
(SubclassOptionalData & FastMathFlags::ApproxFunc) != 0);
}

/// Test if this operation may be simplified with reassociative transforms.
bool hasAllowReassoc() const {
return (SubclassOptionalData & FastMathFlags::AllowReassoc) != 0;
}

/// Test whether this operation's arguments and results are to be
/// treated as non-NaN, aka the 'N' fast-math property.
/// Test if this operation's arguments and results are assumed not-NaN.
bool hasNoNaNs() const {
return (SubclassOptionalData & FastMathFlags::NoNaNs) != 0;
}

/// Test whether this operation's arguments and results are to be
/// treated as NoN-Inf, aka the 'I' fast-math property.
/// Test if this operation's arguments and results are assumed not-infinite.
bool hasNoInfs() const {
return (SubclassOptionalData & FastMathFlags::NoInfs) != 0;
}

/// Test whether this operation can treat the sign of zero
/// as insignificant, aka the 'S' fast-math property.
/// Test if this operation can ignore the sign of zero.
bool hasNoSignedZeros() const {
return (SubclassOptionalData & FastMathFlags::NoSignedZeros) != 0;
}

/// Test whether this operation is permitted to use
/// reciprocal instead of division, aka the 'R' fast-math property.
/// Test if this operation can use reciprocal multiply instead of division.
bool hasAllowReciprocal() const {
return (SubclassOptionalData & FastMathFlags::AllowReciprocal) != 0;
}

/// Test whether this operation is permitted to
/// be floating-point contracted.
/// Test if this operation can be floating-point contracted (FMA).
bool hasAllowContract() const {
return (SubclassOptionalData & FastMathFlags::AllowContract) != 0;
}

/// Test if this operation allows approximations of math library functions or
/// intrinsics.
bool hasApproxFunc() const {
return (SubclassOptionalData & FastMathFlags::ApproxFunc) != 0;
}

/// Convenience function for getting all the fast-math flags
FastMathFlags getFastMathFlags() const {
return FastMathFlags(SubclassOptionalData);
Expand Down
6 changes: 2 additions & 4 deletions llvm/include/llvm/Transforms/Utils/LoopUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -331,15 +331,13 @@ class InductionDescriptor {
/// not have the "fast-math" property. Such operation requires a relaxed FP
/// mode.
bool hasUnsafeAlgebra() {
return InductionBinOp &&
!cast<FPMathOperator>(InductionBinOp)->hasUnsafeAlgebra();
return InductionBinOp && !cast<FPMathOperator>(InductionBinOp)->isFast();
}

/// Returns induction operator that does not have "fast-math" property
/// and requires FP unsafe mode.
Instruction *getUnsafeAlgebraInst() {
if (!InductionBinOp ||
cast<FPMathOperator>(InductionBinOp)->hasUnsafeAlgebra())
if (!InductionBinOp || cast<FPMathOperator>(InductionBinOp)->isFast())
return nullptr;
return InductionBinOp;
}
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/AsmParser/LLLexer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,8 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(nsz);
KEYWORD(arcp);
KEYWORD(contract);
KEYWORD(reassoc);
KEYWORD(afn);
KEYWORD(fast);
KEYWORD(nuw);
KEYWORD(nsw);
Expand Down
4 changes: 3 additions & 1 deletion llvm/lib/AsmParser/LLParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ namespace llvm {
FastMathFlags FMF;
while (true)
switch (Lex.getKind()) {
case lltok::kw_fast: FMF.setUnsafeAlgebra(); Lex.Lex(); continue;
case lltok::kw_fast: FMF.setFast(); Lex.Lex(); continue;
case lltok::kw_nnan: FMF.setNoNaNs(); Lex.Lex(); continue;
case lltok::kw_ninf: FMF.setNoInfs(); Lex.Lex(); continue;
case lltok::kw_nsz: FMF.setNoSignedZeros(); Lex.Lex(); continue;
Expand All @@ -202,6 +202,8 @@ namespace llvm {
FMF.setAllowContract(true);
Lex.Lex();
continue;
case lltok::kw_reassoc: FMF.setAllowReassoc(); Lex.Lex(); continue;
case lltok::kw_afn: FMF.setApproxFunc(); Lex.Lex(); continue;
default: return FMF;
}
return FMF;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/AsmParser/LLToken.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,8 @@ enum Kind {
kw_nsz,
kw_arcp,
kw_contract,
kw_reassoc,
kw_afn,
kw_fast,
kw_nuw,
kw_nsw,
Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Bitcode/Reader/BitcodeReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1046,8 +1046,8 @@ static Comdat::SelectionKind getDecodedComdatSelectionKind(unsigned Val) {

static FastMathFlags getDecodedFastMathFlags(unsigned Val) {
FastMathFlags FMF;
if (0 != (Val & FastMathFlags::UnsafeAlgebra))
FMF.setUnsafeAlgebra();
if (0 != (Val & FastMathFlags::AllowReassoc))
FMF.setAllowReassoc();
if (0 != (Val & FastMathFlags::NoNaNs))
FMF.setNoNaNs();
if (0 != (Val & FastMathFlags::NoInfs))
Expand All @@ -1058,6 +1058,8 @@ static FastMathFlags getDecodedFastMathFlags(unsigned Val) {
FMF.setAllowReciprocal();
if (0 != (Val & FastMathFlags::AllowContract))
FMF.setAllowContract(true);
if (0 != (Val & FastMathFlags::ApproxFunc))
FMF.setApproxFunc();
return FMF;
}

Expand Down
6 changes: 4 additions & 2 deletions llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1321,8 +1321,8 @@ static uint64_t getOptimizationFlags(const Value *V) {
if (PEO->isExact())
Flags |= 1 << bitc::PEO_EXACT;
} else if (const auto *FPMO = dyn_cast<FPMathOperator>(V)) {
if (FPMO->hasUnsafeAlgebra())
Flags |= FastMathFlags::UnsafeAlgebra;
if (FPMO->hasAllowReassoc())
Flags |= FastMathFlags::AllowReassoc;
if (FPMO->hasNoNaNs())
Flags |= FastMathFlags::NoNaNs;
if (FPMO->hasNoInfs())
Expand All @@ -1333,6 +1333,8 @@ static uint64_t getOptimizationFlags(const Value *V) {
Flags |= FastMathFlags::AllowReciprocal;
if (FPMO->hasAllowContract())
Flags |= FastMathFlags::AllowContract;
if (FPMO->hasApproxFunc())
Flags |= FastMathFlags::ApproxFunc;
}

return Flags;
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/ExpandReductions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ bool expandReductions(Function &F, const TargetTransformInfo *TTI) {
// and it can't be handled by generating this shuffle sequence.
// TODO: Implement scalarization of ordered reductions here for targets
// without native support.
if (!II->getFastMathFlags().unsafeAlgebra())
if (!II->getFastMathFlags().isFast())
continue;
Vec = II->getArgOperand(1);
break;
Expand Down
10 changes: 5 additions & 5 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2585,7 +2585,7 @@ static bool isVectorReductionOp(const User *I) {
case Instruction::FAdd:
case Instruction::FMul:
if (const FPMathOperator *FPOp = dyn_cast<const FPMathOperator>(Inst))
if (FPOp->getFastMathFlags().unsafeAlgebra())
if (FPOp->getFastMathFlags().isFast())
break;
LLVM_FALLTHROUGH;
default:
Expand Down Expand Up @@ -2631,7 +2631,7 @@ static bool isVectorReductionOp(const User *I) {

if (Inst->getOpcode() == OpCode || isa<PHINode>(U)) {
if (const FPMathOperator *FPOp = dyn_cast<const FPMathOperator>(Inst))
if (!isa<PHINode>(FPOp) && !FPOp->getFastMathFlags().unsafeAlgebra())
if (!isa<PHINode>(FPOp) && !FPOp->getFastMathFlags().isFast())
return false;
UsersToVisit.push_back(U);
} else if (const ShuffleVectorInst *ShufInst =
Expand Down Expand Up @@ -2725,7 +2725,7 @@ void SelectionDAGBuilder::visitBinary(const User &I, unsigned OpCode) {
Flags.setNoInfs(FMF.noInfs());
Flags.setNoNaNs(FMF.noNaNs());
Flags.setNoSignedZeros(FMF.noSignedZeros());
Flags.setUnsafeAlgebra(FMF.unsafeAlgebra());
Flags.setUnsafeAlgebra(FMF.isFast());

SDValue BinNodeValue = DAG.getNode(OpCode, getCurSDLoc(), Op1.getValueType(),
Op1, Op2, Flags);
Expand Down Expand Up @@ -7959,13 +7959,13 @@ void SelectionDAGBuilder::visitVectorReduce(const CallInst &I,

switch (Intrinsic) {
case Intrinsic::experimental_vector_reduce_fadd:
if (FMF.unsafeAlgebra())
if (FMF.isFast())
Res = DAG.getNode(ISD::VECREDUCE_FADD, dl, VT, Op2);
else
Res = DAG.getNode(ISD::VECREDUCE_STRICT_FADD, dl, VT, Op1, Op2);
break;
case Intrinsic::experimental_vector_reduce_fmul:
if (FMF.unsafeAlgebra())
if (FMF.isFast())
Res = DAG.getNode(ISD::VECREDUCE_FMUL, dl, VT, Op2);
else
Res = DAG.getNode(ISD::VECREDUCE_STRICT_FMUL, dl, VT, Op1, Op2);
Expand Down
8 changes: 6 additions & 2 deletions llvm/lib/IR/AsmWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1108,10 +1108,12 @@ static void writeAtomicRMWOperation(raw_ostream &Out,

static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
if (const FPMathOperator *FPO = dyn_cast<const FPMathOperator>(U)) {
// Unsafe algebra implies all the others, no need to write them all out
if (FPO->hasUnsafeAlgebra())
// 'Fast' is an abbreviation for all fast-math-flags.
if (FPO->isFast())
Out << " fast";
else {
if (FPO->hasAllowReassoc())
Out << " reassoc";
if (FPO->hasNoNaNs())
Out << " nnan";
if (FPO->hasNoInfs())
Expand All @@ -1122,6 +1124,8 @@ static void WriteOptimizationInfo(raw_ostream &Out, const User *U) {
Out << " arcp";
if (FPO->hasAllowContract())
Out << " contract";
if (FPO->hasApproxFunc())
Out << " afn";
}
}

Expand Down
30 changes: 25 additions & 5 deletions llvm/lib/IR/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,9 +146,14 @@ bool Instruction::isExact() const {
return cast<PossiblyExactOperator>(this)->isExact();
}

void Instruction::setHasUnsafeAlgebra(bool B) {
void Instruction::setFast(bool B) {
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
cast<FPMathOperator>(this)->setHasUnsafeAlgebra(B);
cast<FPMathOperator>(this)->setFast(B);
}

void Instruction::setHasAllowReassoc(bool B) {
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
cast<FPMathOperator>(this)->setHasAllowReassoc(B);
}

void Instruction::setHasNoNaNs(bool B) {
Expand All @@ -171,6 +176,11 @@ void Instruction::setHasAllowReciprocal(bool B) {
cast<FPMathOperator>(this)->setHasAllowReciprocal(B);
}

void Instruction::setHasApproxFunc(bool B) {
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
cast<FPMathOperator>(this)->setHasApproxFunc(B);
}

void Instruction::setFastMathFlags(FastMathFlags FMF) {
assert(isa<FPMathOperator>(this) && "setting fast-math flag on invalid op");
cast<FPMathOperator>(this)->setFastMathFlags(FMF);
Expand All @@ -181,9 +191,14 @@ void Instruction::copyFastMathFlags(FastMathFlags FMF) {
cast<FPMathOperator>(this)->copyFastMathFlags(FMF);
}

bool Instruction::hasUnsafeAlgebra() const {
bool Instruction::isFast() const {
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
return cast<FPMathOperator>(this)->hasUnsafeAlgebra();
return cast<FPMathOperator>(this)->isFast();
}

bool Instruction::hasAllowReassoc() const {
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
return cast<FPMathOperator>(this)->hasAllowReassoc();
}

bool Instruction::hasNoNaNs() const {
Expand Down Expand Up @@ -211,6 +226,11 @@ bool Instruction::hasAllowContract() const {
return cast<FPMathOperator>(this)->hasAllowContract();
}

bool Instruction::hasApproxFunc() const {
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
return cast<FPMathOperator>(this)->hasApproxFunc();
}

FastMathFlags Instruction::getFastMathFlags() const {
assert(isa<FPMathOperator>(this) && "getting fast-math flag on invalid op");
return cast<FPMathOperator>(this)->getFastMathFlags();
Expand Down Expand Up @@ -579,7 +599,7 @@ bool Instruction::isAssociative() const {
switch (Opcode) {
case FMul:
case FAdd:
return cast<FPMathOperator>(this)->hasUnsafeAlgebra();
return cast<FPMathOperator>(this)->isFast();
default:
return false;
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AMDGPU/AMDGPUCodeGenPrepare.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -400,7 +400,7 @@ bool AMDGPUCodeGenPrepare::visitFDiv(BinaryOperator &FDiv) {
return false;

FastMathFlags FMF = FPOp->getFastMathFlags();
bool UnsafeDiv = HasUnsafeFPMath || FMF.unsafeAlgebra() ||
bool UnsafeDiv = HasUnsafeFPMath || FMF.isFast() ||
FMF.allowReciprocal();

// With UnsafeDiv node will be optimized to just rcp and mul.
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/AMDGPU/AMDGPULibCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ bool AMDGPULibCalls::parseFunctionName(const StringRef& FMangledName,

bool AMDGPULibCalls::isUnsafeMath(const CallInst *CI) const {
if (auto Op = dyn_cast<FPMathOperator>(CI))
if (Op->hasUnsafeAlgebra())
if (Op->isFast())
return true;
const Function *F = CI->getParent()->getParent();
Attribute Attr = F->getFnAttribute("unsafe-fp-math");
Expand Down
8 changes: 4 additions & 4 deletions llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ Value *FAddCombine::performFactorization(Instruction *I) {
return nullptr;

FastMathFlags Flags;
Flags.setUnsafeAlgebra();
Flags.setFast();
if (I0) Flags &= I->getFastMathFlags();
if (I1) Flags &= I->getFastMathFlags();

Expand Down Expand Up @@ -511,7 +511,7 @@ Value *FAddCombine::performFactorization(Instruction *I) {
}

Value *FAddCombine::simplify(Instruction *I) {
assert(I->hasUnsafeAlgebra() && "Should be in unsafe mode");
assert(I->isFast() && "Expected 'fast' instruction");

// Currently we are not able to handle vector type.
if (I->getType()->isVectorTy())
Expand Down Expand Up @@ -1386,7 +1386,7 @@ Instruction *InstCombiner::visitFAdd(BinaryOperator &I) {
if (Value *V = SimplifySelectsFeedingBinaryOp(I, LHS, RHS))
return replaceInstUsesWith(I, V);

if (I.hasUnsafeAlgebra()) {
if (I.isFast()) {
if (Value *V = FAddCombine(Builder).simplify(&I))
return replaceInstUsesWith(I, V);
}
Expand Down Expand Up @@ -1736,7 +1736,7 @@ Instruction *InstCombiner::visitFSub(BinaryOperator &I) {
if (Value *V = SimplifySelectsFeedingBinaryOp(I, Op0, Op1))
return replaceInstUsesWith(I, V);

if (I.hasUnsafeAlgebra()) {
if (I.isFast()) {
if (Value *V = FAddCombine(Builder).simplify(&I))
return replaceInstUsesWith(I, V);
}
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2017,7 +2017,7 @@ Instruction *InstCombiner::visitCallInst(CallInst &CI) {
}
case Intrinsic::fmuladd: {
// Canonicalize fast fmuladd to the separate fmul + fadd.
if (II->hasUnsafeAlgebra()) {
if (II->isFast()) {
BuilderTy::FastMathFlagGuard Guard(Builder);
Builder.setFastMathFlags(II->getFastMathFlags());
Value *Mul = Builder.CreateFMul(II->getArgOperand(0),
Expand Down
11 changes: 6 additions & 5 deletions llvm/lib/Transforms/InstCombine/InstCombineMulDivRem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,7 +487,7 @@ static void detectLog2OfHalf(Value *&Op, Value *&Y, IntrinsicInst *&Log2) {
IntrinsicInst *II = dyn_cast<IntrinsicInst>(Op);
if (!II)
return;
if (II->getIntrinsicID() != Intrinsic::log2 || !II->hasUnsafeAlgebra())
if (II->getIntrinsicID() != Intrinsic::log2 || !II->isFast())
return;
Log2 = II;

Expand All @@ -498,7 +498,8 @@ static void detectLog2OfHalf(Value *&Op, Value *&Y, IntrinsicInst *&Log2) {
Instruction *I = dyn_cast<Instruction>(OpLog2Of);
if (!I)
return;
if (I->getOpcode() != Instruction::FMul || !I->hasUnsafeAlgebra())

if (I->getOpcode() != Instruction::FMul || !I->isFast())
return;

if (match(I->getOperand(0), m_SpecificFP(0.5)))
Expand Down Expand Up @@ -601,7 +602,7 @@ Value *InstCombiner::foldFMulConst(Instruction *FMulOrDiv, Constant *C,
}

if (R) {
R->setHasUnsafeAlgebra(true);
R->setFast(true);
InsertNewInstWith(R, *InsertBefore);
}

Expand All @@ -622,7 +623,7 @@ Instruction *InstCombiner::visitFMul(BinaryOperator &I) {
SQ.getWithInstruction(&I)))
return replaceInstUsesWith(I, V);

bool AllowReassociate = I.hasUnsafeAlgebra();
bool AllowReassociate = I.isFast();

// Simplify mul instructions with a constant RHS.
if (isa<Constant>(Op1)) {
Expand Down Expand Up @@ -1341,7 +1342,7 @@ Instruction *InstCombiner::visitFDiv(BinaryOperator &I) {
if (Instruction *R = FoldOpIntoSelect(I, SI))
return R;

bool AllowReassociate = I.hasUnsafeAlgebra();
bool AllowReassociate = I.isFast();
bool AllowReciprocal = I.hasAllowReciprocal();

if (Constant *Op1C = dyn_cast<Constant>(Op1)) {
Expand Down
12 changes: 5 additions & 7 deletions llvm/lib/Transforms/Scalar/Reassociate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,7 @@ XorOpnd::XorOpnd(Value *V) {
static BinaryOperator *isReassociableOp(Value *V, unsigned Opcode) {
if (V->hasOneUse() && isa<Instruction>(V) &&
cast<Instruction>(V)->getOpcode() == Opcode &&
(!isa<FPMathOperator>(V) ||
cast<Instruction>(V)->hasUnsafeAlgebra()))
(!isa<FPMathOperator>(V) || cast<Instruction>(V)->isFast()))
return cast<BinaryOperator>(V);
return nullptr;
}
Expand All @@ -156,8 +155,7 @@ static BinaryOperator *isReassociableOp(Value *V, unsigned Opcode1,
if (V->hasOneUse() && isa<Instruction>(V) &&
(cast<Instruction>(V)->getOpcode() == Opcode1 ||
cast<Instruction>(V)->getOpcode() == Opcode2) &&
(!isa<FPMathOperator>(V) ||
cast<Instruction>(V)->hasUnsafeAlgebra()))
(!isa<FPMathOperator>(V) || cast<Instruction>(V)->isFast()))
return cast<BinaryOperator>(V);
return nullptr;
}
Expand Down Expand Up @@ -565,7 +563,7 @@ static bool LinearizeExprTree(BinaryOperator *I,
assert((!isa<Instruction>(Op) ||
cast<Instruction>(Op)->getOpcode() != Opcode
|| (isa<FPMathOperator>(Op) &&
!cast<Instruction>(Op)->hasUnsafeAlgebra())) &&
!cast<Instruction>(Op)->isFast())) &&
"Should have been handled above!");
assert(Op->hasOneUse() && "Has uses outside the expression tree!");

Expand Down Expand Up @@ -2017,8 +2015,8 @@ void ReassociatePass::OptimizeInst(Instruction *I) {
if (I->isCommutative())
canonicalizeOperands(I);

// Don't optimize floating point instructions that don't have unsafe algebra.
if (I->getType()->isFPOrFPVectorTy() && !I->hasUnsafeAlgebra())
// Don't optimize floating-point instructions unless they are 'fast'.
if (I->getType()->isFPOrFPVectorTy() && !I->isFast())
return;

// Do not reassociate boolean (i1) expressions. We want to preserve the
Expand Down
12 changes: 6 additions & 6 deletions llvm/lib/Transforms/Utils/LoopUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,7 @@ RecurrenceDescriptor::isRecurrenceInstr(Instruction *I, RecurrenceKind Kind,
InstDesc &Prev, bool HasFunNoNaNAttr) {
bool FP = I->getType()->isFloatingPointTy();
Instruction *UAI = Prev.getUnsafeAlgebraInst();
if (!UAI && FP && !I->hasUnsafeAlgebra())
if (!UAI && FP && !I->isFast())
UAI = I; // Found an unsafe (unvectorizable) algebra instruction.

switch (I->getOpcode()) {
Expand Down Expand Up @@ -660,11 +660,11 @@ Value *RecurrenceDescriptor::createMinMaxOp(IRBuilder<> &Builder,
break;
}

// We only match FP sequences with unsafe algebra, so we can unconditionally
// We only match FP sequences that are 'fast', so we can unconditionally
// set it on any generated instructions.
IRBuilder<>::FastMathFlagGuard FMFG(Builder);
FastMathFlags FMF;
FMF.setUnsafeAlgebra();
FMF.setFast();
Builder.setFastMathFlags(FMF);

Value *Cmp;
Expand Down Expand Up @@ -768,7 +768,7 @@ Value *InductionDescriptor::transform(IRBuilder<> &B, Value *Index,

// Floating point operations had to be 'fast' to enable the induction.
FastMathFlags Flags;
Flags.setUnsafeAlgebra();
Flags.setFast();

Value *MulExp = B.CreateFMul(StepValue, Index);
if (isa<Instruction>(MulExp))
Expand Down Expand Up @@ -1338,7 +1338,7 @@ Optional<unsigned> llvm::getLoopEstimatedTripCount(Loop *L) {
static Value *addFastMathFlag(Value *V) {
if (isa<FPMathOperator>(V)) {
FastMathFlags Flags;
Flags.setUnsafeAlgebra();
Flags.setFast();
cast<Instruction>(V)->setFastMathFlags(Flags);
}
return V;
Expand Down Expand Up @@ -1401,7 +1401,7 @@ Value *llvm::createSimpleTargetReduction(
RD::MinMaxRecurrenceKind MinMaxKind = RD::MRK_Invalid;
// TODO: Support creating ordered reductions.
FastMathFlags FMFUnsafe;
FMFUnsafe.setUnsafeAlgebra();
FMFUnsafe.setFast();

switch (Opcode) {
case Instruction::Add:
Expand Down
37 changes: 18 additions & 19 deletions llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1111,7 +1111,7 @@ Value *LibCallSimplifier::optimizePow(CallInst *CI, IRBuilder<> &B) {
// Example: x = 1000, y = 0.001.
// pow(exp(x), y) = pow(inf, 0.001) = inf, whereas exp(x*y) = exp(1).
auto *OpC = dyn_cast<CallInst>(Op1);
if (OpC && OpC->hasUnsafeAlgebra() && CI->hasUnsafeAlgebra()) {
if (OpC && OpC->isFast() && CI->isFast()) {
LibFunc Func;
Function *OpCCallee = OpC->getCalledFunction();
if (OpCCallee && TLI->getLibFunc(OpCCallee->getName(), Func) &&
Expand All @@ -1136,7 +1136,7 @@ Value *LibCallSimplifier::optimizePow(CallInst *CI, IRBuilder<> &B) {
LibFunc_sqrtl)) {
// If -ffast-math:
// pow(x, -0.5) -> 1.0 / sqrt(x)
if (CI->hasUnsafeAlgebra()) {
if (CI->isFast()) {
IRBuilder<>::FastMathFlagGuard Guard(B);
B.setFastMathFlags(CI->getFastMathFlags());

Expand All @@ -1157,7 +1157,7 @@ Value *LibCallSimplifier::optimizePow(CallInst *CI, IRBuilder<> &B) {
LibFunc_sqrtl)) {

// In -ffast-math, pow(x, 0.5) -> sqrt(x).
if (CI->hasUnsafeAlgebra()) {
if (CI->isFast()) {
IRBuilder<>::FastMathFlagGuard Guard(B);
B.setFastMathFlags(CI->getFastMathFlags());

Expand Down Expand Up @@ -1196,7 +1196,7 @@ Value *LibCallSimplifier::optimizePow(CallInst *CI, IRBuilder<> &B) {
return B.CreateFDiv(ConstantFP::get(CI->getType(), 1.0), Op1, "powrecip");

// In -ffast-math, generate repeated fmul instead of generating pow(x, n).
if (CI->hasUnsafeAlgebra()) {
if (CI->isFast()) {
APFloat V = abs(Op2C->getValueAPF());
// We limit to a max of 7 fmul(s). Thus max exponent is 32.
// This transformation applies to integer exponents only.
Expand Down Expand Up @@ -1284,9 +1284,9 @@ Value *LibCallSimplifier::optimizeFMinFMax(CallInst *CI, IRBuilder<> &B) {

IRBuilder<>::FastMathFlagGuard Guard(B);
FastMathFlags FMF;
if (CI->hasUnsafeAlgebra()) {
// Unsafe algebra sets all fast-math-flags to true.
FMF.setUnsafeAlgebra();
if (CI->isFast()) {
// If the call is 'fast', then anything we create here will also be 'fast'.
FMF.setFast();
} else {
// At a minimum, no-nans-fp-math must be true.
if (!CI->hasNoNaNs())
Expand Down Expand Up @@ -1317,13 +1317,13 @@ Value *LibCallSimplifier::optimizeLog(CallInst *CI, IRBuilder<> &B) {
if (UnsafeFPShrink && hasFloatVersion(Name))
Ret = optimizeUnaryDoubleFP(CI, B, true);

if (!CI->hasUnsafeAlgebra())
if (!CI->isFast())
return Ret;
Value *Op1 = CI->getArgOperand(0);
auto *OpC = dyn_cast<CallInst>(Op1);

// The earlier call must also be unsafe in order to do these transforms.
if (!OpC || !OpC->hasUnsafeAlgebra())
// The earlier call must also be 'fast' in order to do these transforms.
if (!OpC || !OpC->isFast())
return Ret;

// log(pow(x,y)) -> y*log(x)
Expand All @@ -1333,7 +1333,7 @@ Value *LibCallSimplifier::optimizeLog(CallInst *CI, IRBuilder<> &B) {

IRBuilder<>::FastMathFlagGuard Guard(B);
FastMathFlags FMF;
FMF.setUnsafeAlgebra();
FMF.setFast();
B.setFastMathFlags(FMF);

LibFunc Func;
Expand Down Expand Up @@ -1365,11 +1365,11 @@ Value *LibCallSimplifier::optimizeSqrt(CallInst *CI, IRBuilder<> &B) {
Callee->getIntrinsicID() == Intrinsic::sqrt))
Ret = optimizeUnaryDoubleFP(CI, B, true);

if (!CI->hasUnsafeAlgebra())
if (!CI->isFast())
return Ret;

Instruction *I = dyn_cast<Instruction>(CI->getArgOperand(0));
if (!I || I->getOpcode() != Instruction::FMul || !I->hasUnsafeAlgebra())
if (!I || I->getOpcode() != Instruction::FMul || !I->isFast())
return Ret;

// We're looking for a repeated factor in a multiplication tree,
Expand All @@ -1391,8 +1391,7 @@ Value *LibCallSimplifier::optimizeSqrt(CallInst *CI, IRBuilder<> &B) {
Value *OtherMul0, *OtherMul1;
if (match(Op0, m_FMul(m_Value(OtherMul0), m_Value(OtherMul1)))) {
// Pattern: sqrt((x * y) * z)
if (OtherMul0 == OtherMul1 &&
cast<Instruction>(Op0)->hasUnsafeAlgebra()) {
if (OtherMul0 == OtherMul1 && cast<Instruction>(Op0)->isFast()) {
// Matched: sqrt((x * x) * z)
RepeatOp = OtherMul0;
OtherOp = Op1;
Expand Down Expand Up @@ -1437,8 +1436,8 @@ Value *LibCallSimplifier::optimizeTan(CallInst *CI, IRBuilder<> &B) {
if (!OpC)
return Ret;

// Both calls must allow unsafe optimizations in order to remove them.
if (!CI->hasUnsafeAlgebra() || !OpC->hasUnsafeAlgebra())
// Both calls must be 'fast' in order to remove them.
if (!CI->isFast() || !OpC->isFast())
return Ret;

// tan(atan(x)) -> x
Expand Down Expand Up @@ -2167,10 +2166,10 @@ Value *LibCallSimplifier::optimizeCall(CallInst *CI) {

// Command-line parameter overrides instruction attribute.
// This can't be moved to optimizeFloatingPointLibCall() because it may be
// used by the intrinsic optimizations.
// used by the intrinsic optimizations.
if (EnableUnsafeFPShrink.getNumOccurrences() > 0)
UnsafeFPShrink = EnableUnsafeFPShrink;
else if (isa<FPMathOperator>(CI) && CI->hasUnsafeAlgebra())
else if (isa<FPMathOperator>(CI) && CI->isFast())
UnsafeFPShrink = true;

// First, check for intrinsics.
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -385,7 +385,7 @@ static unsigned getReciprocalPredBlockProb() { return 2; }
static Value *addFastMathFlag(Value *V) {
if (isa<FPMathOperator>(V)) {
FastMathFlags Flags;
Flags.setUnsafeAlgebra();
Flags.setFast();
cast<Instruction>(V)->setFastMathFlags(Flags);
}
return V;
Expand Down Expand Up @@ -2720,7 +2720,7 @@ Value *InnerLoopVectorizer::getStepVector(Value *Val, int StartIdx, Value *Step,

// Floating point operations had to be 'fast' to enable the induction.
FastMathFlags Flags;
Flags.setUnsafeAlgebra();
Flags.setFast();

Value *MulOp = Builder.CreateFMul(Cv, Step);
if (isa<Instruction>(MulOp))
Expand Down Expand Up @@ -5396,7 +5396,7 @@ bool LoopVectorizationLegality::canVectorizeInstrs() {
// operations, shuffles, or casts, as they don't change precision or
// semantics.
} else if (I.getType()->isFloatingPointTy() && (CI || I.isBinaryOp()) &&
!I.hasUnsafeAlgebra()) {
!I.isFast()) {
DEBUG(dbgs() << "LV: Found FP op with unsafe algebra.\n");
Hints->setPotentiallyUnsafe();
}
Expand Down
4 changes: 2 additions & 2 deletions llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4880,7 +4880,7 @@ class HorizontalReduction {
case RK_Min:
case RK_Max:
return Opcode == Instruction::ICmp ||
cast<Instruction>(I->getOperand(0))->hasUnsafeAlgebra();
cast<Instruction>(I->getOperand(0))->isFast();
case RK_UMin:
case RK_UMax:
assert(Opcode == Instruction::ICmp &&
Expand Down Expand Up @@ -5232,7 +5232,7 @@ class HorizontalReduction {
Value *VectorizedTree = nullptr;
IRBuilder<> Builder(ReductionRoot);
FastMathFlags Unsafe;
Unsafe.setUnsafeAlgebra();
Unsafe.setFast();
Builder.setFastMathFlags(Unsafe);
unsigned i = 0;

Expand Down
32 changes: 28 additions & 4 deletions llvm/test/Assembler/fast-math-flags.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
@vec = external global <3 x float>
@arr = external global [3 x float]

declare float @foo(float)

define float @none(float %x, float %y) {
entry:
; CHECK: %vec = load <3 x float>, <3 x float>* @vec
Expand Down Expand Up @@ -86,6 +88,28 @@ entry:
ret float %c
}

; CHECK: @reassoc(
define float @reassoc(float %x, float %y) {
; CHECK: %a = fsub reassoc float %x, %y
%a = fsub reassoc float %x, %y
; CHECK: %b = fmul reassoc float %x, %y
%b = fmul reassoc float %x, %y
; CHECK: %c = call reassoc float @foo(float %b)
%c = call reassoc float @foo(float %b)
ret float %c
}

; CHECK: @afn(
define float @afn(float %x, float %y) {
; CHECK: %a = fdiv afn float %x, %y
%a = fdiv afn float %x, %y
; CHECK: %b = frem afn float %x, %y
%b = frem afn float %x, %y
; CHECK: %c = call afn float @foo(float %b)
%c = call afn float @foo(float %b)
ret float %c
}

; CHECK: no_nan_inf
define float @no_nan_inf(float %x, float %y) {
entry:
Expand Down Expand Up @@ -130,10 +154,10 @@ entry:
; CHECK: %arr = load [3 x float], [3 x float]* @arr
%arr = load [3 x float], [3 x float]* @arr

; CHECK: %a = fadd nnan ninf float %x, %y
%a = fadd ninf nnan float %x, %y
; CHECK: %a_vec = fadd nnan <3 x float> %vec, %vec
%a_vec = fadd nnan <3 x float> %vec, %vec
; CHECK: %a = fadd nnan ninf afn float %x, %y
%a = fadd ninf nnan afn float %x, %y
; CHECK: %a_vec = fadd reassoc nnan <3 x float> %vec, %vec
%a_vec = fadd reassoc nnan <3 x float> %vec, %vec
; CHECK: %b = fsub fast float %x, %y
%b = fsub nnan nsz fast float %x, %y
; CHECK: %b_vec = fsub nnan <3 x float> %vec, %vec
Expand Down
4 changes: 3 additions & 1 deletion llvm/test/Bitcode/compatibility-3.6.ll
Original file line number Diff line number Diff line change
Expand Up @@ -612,7 +612,9 @@ define void @fastmathflags(float %op1, float %op2) {
%f.arcp = fadd arcp float %op1, %op2
; CHECK: %f.arcp = fadd arcp float %op1, %op2
%f.fast = fadd fast float %op1, %op2
; CHECK: %f.fast = fadd fast float %op1, %op2
; 'fast' used to be its own bit, but this changed in Oct 2017.
; The binary test file does not have the newer 'contract' and 'afn' bits set, so this is not fully 'fast'.
; CHECK: %f.fast = fadd reassoc nnan ninf nsz arcp float %op1, %op2
ret void
}

Expand Down
4 changes: 3 additions & 1 deletion llvm/test/Bitcode/compatibility-3.7.ll
Original file line number Diff line number Diff line change
Expand Up @@ -656,7 +656,9 @@ define void @fastmathflags(float %op1, float %op2) {
%f.arcp = fadd arcp float %op1, %op2
; CHECK: %f.arcp = fadd arcp float %op1, %op2
%f.fast = fadd fast float %op1, %op2
; CHECK: %f.fast = fadd fast float %op1, %op2
; 'fast' used to be its own bit, but this changed in Oct 2017.
; The binary test file does not have the newer 'contract' and 'afn' bits set, so this is not fully 'fast'.
; CHECK: %f.fast = fadd reassoc nnan ninf nsz arcp float %op1, %op2
ret void
}

Expand Down
8 changes: 6 additions & 2 deletions llvm/test/Bitcode/compatibility-3.8.ll
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,9 @@ define void @fastmathflags(float %op1, float %op2) {
%f.arcp = fadd arcp float %op1, %op2
; CHECK: %f.arcp = fadd arcp float %op1, %op2
%f.fast = fadd fast float %op1, %op2
; CHECK: %f.fast = fadd fast float %op1, %op2
; 'fast' used to be its own bit, but this changed in Oct 2017.
; The binary test file does not have the newer 'contract' and 'afn' bits set, so this is not fully 'fast'.
; CHECK: %f.fast = fadd reassoc nnan ninf nsz arcp float %op1, %op2
ret void
}

Expand All @@ -700,7 +702,9 @@ declare <4 x double> @fmf3()
; CHECK-LABEL: fastMathFlagsForCalls(
define void @fastMathFlagsForCalls(float %f, double %d1, <4 x double> %d2) {
%call.fast = call fast float @fmf1()
; CHECK: %call.fast = call fast float @fmf1()
; 'fast' used to be its own bit, but this changed in Oct 2017.
; The binary test file does not have the newer 'contract' and 'aml' bits set, so this is not fully 'fast'.
; CHECK: %call.fast = call reassoc nnan ninf nsz arcp float @fmf1()

; Throw in some other attributes to make sure those stay in the right places.

Expand Down
8 changes: 6 additions & 2 deletions llvm/test/Bitcode/compatibility-3.9.ll
Original file line number Diff line number Diff line change
Expand Up @@ -758,7 +758,9 @@ define void @fastmathflags(float %op1, float %op2) {
%f.arcp = fadd arcp float %op1, %op2
; CHECK: %f.arcp = fadd arcp float %op1, %op2
%f.fast = fadd fast float %op1, %op2
; CHECK: %f.fast = fadd fast float %op1, %op2
; 'fast' used to be its own bit, but this changed in Oct 2017.
; The binary test file does not have the newer 'contract' and 'afn' bits set, so this is not fully 'fast'.
; CHECK: %f.fast = fadd reassoc nnan ninf nsz arcp float %op1, %op2
ret void
}

Expand All @@ -771,7 +773,9 @@ declare <4 x double> @fmf3()
; CHECK-LABEL: fastMathFlagsForCalls(
define void @fastMathFlagsForCalls(float %f, double %d1, <4 x double> %d2) {
%call.fast = call fast float @fmf1()
; CHECK: %call.fast = call fast float @fmf1()
; 'fast' used to be its own bit, but this changed in Oct 2017.
; The binary test file does not have the newer 'contract' and 'afn' bits set, so this is not fully 'fast'.
; CHECK: %call.fast = call reassoc nnan ninf nsz arcp float @fmf1()

; Throw in some other attributes to make sure those stay in the right places.

Expand Down
8 changes: 6 additions & 2 deletions llvm/test/Bitcode/compatibility-4.0.ll
Original file line number Diff line number Diff line change
Expand Up @@ -757,8 +757,10 @@ 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
; 'fast' used to be its own bit, but this changed in Oct 2017.
; The binary test file does not have the newer 'contract' and 'afn' bits set, so this is not fully 'fast'.
%f.fast = fadd fast float %op1, %op2
; CHECK: %f.fast = fadd fast float %op1, %op2
; CHECK: %f.fast = fadd reassoc nnan ninf nsz arcp float %op1, %op2
ret void
}

Expand All @@ -771,7 +773,9 @@ declare <4 x double> @fmf3()
; CHECK-LABEL: fastMathFlagsForCalls(
define void @fastMathFlagsForCalls(float %f, double %d1, <4 x double> %d2) {
%call.fast = call fast float @fmf1()
; CHECK: %call.fast = call fast float @fmf1()
; 'fast' used to be its own bit, but this changed in Oct 2017.
; The binary test file does not have the newer 'contract' and 'afn' bits set, so this is not fully 'fast'.
; CHECK: %call.fast = call reassoc nnan ninf nsz arcp float @fmf1()

; Throw in some other attributes to make sure those stay in the right places.

Expand Down
8 changes: 6 additions & 2 deletions llvm/test/Bitcode/compatibility-5.0.ll
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,9 @@ define void @fastmathflags(float %op1, float %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
; 'fast' used to be its own bit, but this changed in Oct 2017.
; The binary test file does not have the newer 'afn' bit set, so this is not fully 'fast'.
; CHECK: %f.fast = fadd reassoc nnan ninf nsz arcp contract float %op1, %op2
ret void
}

Expand All @@ -778,7 +780,9 @@ declare <4 x double> @fmf3()
; CHECK-LABEL: fastMathFlagsForCalls(
define void @fastMathFlagsForCalls(float %f, double %d1, <4 x double> %d2) {
%call.fast = call fast float @fmf1()
; CHECK: %call.fast = call fast float @fmf1()
; 'fast' used to be its own bit, but this changed in Oct 2017.
; The binary test file does not have the newer 'afn' bit set, so this is not fully 'fast'.
; CHECK: %call.fast = call reassoc nnan ninf nsz arcp contract float @fmf1()

; Throw in some other attributes to make sure those stay in the right places.

Expand Down
4 changes: 4 additions & 0 deletions llvm/test/Bitcode/compatibility.ll
Original file line number Diff line number Diff line change
Expand Up @@ -775,6 +775,10 @@ define void @fastmathflags(float %op1, float %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.afn = fadd afn float %op1, %op2
; CHECK: %f.afn = fadd afn float %op1, %op2
%f.reassoc = fadd reassoc float %op1, %op2
; CHECK: %f.reassoc = fadd reassoc float %op1, %op2
%f.fast = fadd fast float %op1, %op2
; CHECK: %f.fast = fadd fast float %op1, %op2
ret void
Expand Down
51 changes: 47 additions & 4 deletions llvm/unittests/IR/IRBuilderTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -144,39 +144,64 @@ TEST_F(IRBuilderTest, FastMathFlags) {
FastMathFlags FMF;
Builder.setFastMathFlags(FMF);

// By default, no flags are set.
F = Builder.CreateFAdd(F, F);
EXPECT_FALSE(Builder.getFastMathFlags().any());
ASSERT_TRUE(isa<Instruction>(F));
FAdd = cast<Instruction>(F);
EXPECT_FALSE(FAdd->hasNoNaNs());
EXPECT_FALSE(FAdd->hasNoInfs());
EXPECT_FALSE(FAdd->hasNoSignedZeros());
EXPECT_FALSE(FAdd->hasAllowReciprocal());
EXPECT_FALSE(FAdd->hasAllowContract());
EXPECT_FALSE(FAdd->hasAllowReassoc());
EXPECT_FALSE(FAdd->hasApproxFunc());

FMF.setUnsafeAlgebra();
// Set all flags in the instruction.
FAdd->setFast(true);
EXPECT_TRUE(FAdd->hasNoNaNs());
EXPECT_TRUE(FAdd->hasNoInfs());
EXPECT_TRUE(FAdd->hasNoSignedZeros());
EXPECT_TRUE(FAdd->hasAllowReciprocal());
EXPECT_TRUE(FAdd->hasAllowContract());
EXPECT_TRUE(FAdd->hasAllowReassoc());
EXPECT_TRUE(FAdd->hasApproxFunc());

// All flags are set in the builder.
FMF.setFast();
Builder.setFastMathFlags(FMF);

F = Builder.CreateFAdd(F, F);
EXPECT_TRUE(Builder.getFastMathFlags().any());
EXPECT_TRUE(Builder.getFastMathFlags().all());
ASSERT_TRUE(isa<Instruction>(F));
FAdd = cast<Instruction>(F);
EXPECT_TRUE(FAdd->hasNoNaNs());
EXPECT_TRUE(FAdd->isFast());

// Now, try it with CreateBinOp
F = Builder.CreateBinOp(Instruction::FAdd, F, F);
EXPECT_TRUE(Builder.getFastMathFlags().any());
ASSERT_TRUE(isa<Instruction>(F));
FAdd = cast<Instruction>(F);
EXPECT_TRUE(FAdd->hasNoNaNs());
EXPECT_TRUE(FAdd->isFast());

F = Builder.CreateFDiv(F, F);
EXPECT_TRUE(Builder.getFastMathFlags().any());
EXPECT_TRUE(Builder.getFastMathFlags().UnsafeAlgebra);
EXPECT_TRUE(Builder.getFastMathFlags().all());
ASSERT_TRUE(isa<Instruction>(F));
FDiv = cast<Instruction>(F);
EXPECT_TRUE(FDiv->hasAllowReciprocal());

// Clear all FMF in the builder.
Builder.clearFastMathFlags();

F = Builder.CreateFDiv(F, F);
ASSERT_TRUE(isa<Instruction>(F));
FDiv = cast<Instruction>(F);
EXPECT_FALSE(FDiv->hasAllowReciprocal());


// Try individual flags.
FMF.clear();
FMF.setAllowReciprocal();
Builder.setFastMathFlags(FMF);
Expand Down Expand Up @@ -225,7 +250,25 @@ TEST_F(IRBuilderTest, FastMathFlags) {
FAdd = cast<Instruction>(FC);
EXPECT_TRUE(FAdd->hasAllowContract());

FMF.setApproxFunc();
Builder.clearFastMathFlags();
Builder.setFastMathFlags(FMF);
// Now 'aml' and 'contract' are set.
F = Builder.CreateFMul(F, F);
FAdd = cast<Instruction>(F);
EXPECT_TRUE(FAdd->hasApproxFunc());
EXPECT_TRUE(FAdd->hasAllowContract());
EXPECT_FALSE(FAdd->hasAllowReassoc());

FMF.setAllowReassoc();
Builder.clearFastMathFlags();
Builder.setFastMathFlags(FMF);
// Now 'aml' and 'contract' and 'reassoc' are set.
F = Builder.CreateFMul(F, F);
FAdd = cast<Instruction>(F);
EXPECT_TRUE(FAdd->hasApproxFunc());
EXPECT_TRUE(FAdd->hasAllowContract());
EXPECT_TRUE(FAdd->hasAllowReassoc());

// Test a call with FMF.
auto CalleeTy = FunctionType::get(Type::getFloatTy(Ctx),
Expand Down