mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-01-31 12:41:49 +01:00
Add support for fast-math flags to the FCmp instruction.
FCmp behaves a lot like a floating-point binary operator in many ways, and can benefit from fast-math information. Flags such as nsz and nnan can affect if this fcmp (in combination with a select) can be treated as a fminnum/fmaxnum operation. This adds backwards-compatible bitcode support, IR parsing and writing, LangRef changes and IRBuilder changes. I'll need to audit InstSimplify and InstCombine in a followup to find places where flags should be copied. llvm-svn: 241901
This commit is contained in:
parent
11ffb4756d
commit
4008b8e3dc
@ -1837,8 +1837,8 @@ Fast-Math Flags
|
||||
|
||||
LLVM IR floating-point binary ops (:ref:`fadd <i_fadd>`,
|
||||
:ref:`fsub <i_fsub>`, :ref:`fmul <i_fmul>`, :ref:`fdiv <i_fdiv>`,
|
||||
:ref:`frem <i_frem>`) have the following flags that can be set to enable
|
||||
otherwise unsafe floating point operations
|
||||
:ref:`frem <i_frem>`, :ref:`fcmp <i_fcmp>`) have the following flags that can
|
||||
be set to enable otherwise unsafe floating point operations
|
||||
|
||||
``nnan``
|
||||
No NaNs - Allow optimizations to assume the arguments and result are not
|
||||
@ -7573,7 +7573,7 @@ Syntax:
|
||||
|
||||
::
|
||||
|
||||
<result> = fcmp <cond> <ty> <op1>, <op2> ; yields i1 or <N x i1>:result
|
||||
<result> = fcmp [fast-math flags]* <cond> <ty> <op1>, <op2> ; yields i1 or <N x i1>:result
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
@ -7656,6 +7656,15 @@ always yields an :ref:`i1 <t_integer>` result, as follows:
|
||||
#. ``uno``: yields ``true`` if either operand is a QNAN.
|
||||
#. ``true``: always yields ``true``, regardless of operands.
|
||||
|
||||
The ``fcmp`` instruction can also optionally take any number of
|
||||
:ref:`fast-math flags <fastmath>`, which are optimization hints to enable
|
||||
otherwise unsafe floating point optimizations.
|
||||
|
||||
Any set of fast-math flags are legal on an ``fcmp`` instruction, but the
|
||||
only flags that have any effect on its semantics are those that allow
|
||||
assumptions to be made about the values of input arguments; namely
|
||||
``nnan``, ``ninf``, and ``nsz``. See :ref:`fastmath` for more information.
|
||||
|
||||
Example:
|
||||
""""""""
|
||||
|
||||
|
@ -1382,47 +1382,61 @@ public:
|
||||
return CreateICmp(ICmpInst::ICMP_SLE, LHS, RHS, Name);
|
||||
}
|
||||
|
||||
Value *CreateFCmpOEQ(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_OEQ, LHS, RHS, Name);
|
||||
Value *CreateFCmpOEQ(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_OEQ, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpOGT(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_OGT, LHS, RHS, Name);
|
||||
Value *CreateFCmpOGT(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_OGT, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpOGE(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_OGE, LHS, RHS, Name);
|
||||
Value *CreateFCmpOGE(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_OGE, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpOLT(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_OLT, LHS, RHS, Name);
|
||||
Value *CreateFCmpOLT(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_OLT, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpOLE(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_OLE, LHS, RHS, Name);
|
||||
Value *CreateFCmpOLE(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_OLE, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpONE(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_ONE, LHS, RHS, Name);
|
||||
Value *CreateFCmpONE(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_ONE, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpORD(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_ORD, LHS, RHS, Name);
|
||||
Value *CreateFCmpORD(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_ORD, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpUNO(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_UNO, LHS, RHS, Name);
|
||||
Value *CreateFCmpUNO(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_UNO, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpUEQ(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_UEQ, LHS, RHS, Name);
|
||||
Value *CreateFCmpUEQ(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_UEQ, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpUGT(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_UGT, LHS, RHS, Name);
|
||||
Value *CreateFCmpUGT(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_UGT, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpUGE(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_UGE, LHS, RHS, Name);
|
||||
Value *CreateFCmpUGE(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_UGE, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpULT(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_ULT, LHS, RHS, Name);
|
||||
Value *CreateFCmpULT(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_ULT, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpULE(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_ULE, LHS, RHS, Name);
|
||||
Value *CreateFCmpULE(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_ULE, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
Value *CreateFCmpUNE(Value *LHS, Value *RHS, const Twine &Name = "") {
|
||||
return CreateFCmp(FCmpInst::FCMP_UNE, LHS, RHS, Name);
|
||||
Value *CreateFCmpUNE(Value *LHS, Value *RHS, const Twine &Name = "",
|
||||
MDNode *FPMathTag = nullptr) {
|
||||
return CreateFCmp(FCmpInst::FCMP_UNE, LHS, RHS, Name, FPMathTag);
|
||||
}
|
||||
|
||||
Value *CreateICmp(CmpInst::Predicate P, Value *LHS, Value *RHS,
|
||||
@ -1433,11 +1447,12 @@ public:
|
||||
return Insert(new ICmpInst(P, LHS, RHS), Name);
|
||||
}
|
||||
Value *CreateFCmp(CmpInst::Predicate P, Value *LHS, Value *RHS,
|
||||
const Twine &Name = "") {
|
||||
const Twine &Name = "", MDNode *FPMathTag = nullptr) {
|
||||
if (Constant *LC = dyn_cast<Constant>(LHS))
|
||||
if (Constant *RC = dyn_cast<Constant>(RHS))
|
||||
return Insert(Folder.CreateFCmp(P, LC, RC), Name);
|
||||
return Insert(new FCmpInst(P, LHS, RHS), Name);
|
||||
return Insert(AddFPMathAttributes(new FCmpInst(P, LHS, RHS),
|
||||
FPMathTag, FMF), Name);
|
||||
}
|
||||
|
||||
//===--------------------------------------------------------------------===//
|
||||
|
@ -305,7 +305,8 @@ public:
|
||||
float getFPAccuracy() const;
|
||||
|
||||
static inline bool classof(const Instruction *I) {
|
||||
return I->getType()->isFPOrFPVectorTy();
|
||||
return I->getType()->isFPOrFPVectorTy() ||
|
||||
I->getOpcode() == Instruction::FCmp;
|
||||
}
|
||||
static inline bool classof(const Value *V) {
|
||||
return isa<Instruction>(V) && classof(cast<Instruction>(V));
|
||||
|
@ -4534,8 +4534,17 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB,
|
||||
case lltok::kw_and:
|
||||
case lltok::kw_or:
|
||||
case lltok::kw_xor: return ParseLogical(Inst, PFS, KeywordVal);
|
||||
case lltok::kw_icmp:
|
||||
case lltok::kw_fcmp: return ParseCompare(Inst, PFS, KeywordVal);
|
||||
case lltok::kw_icmp: return ParseCompare(Inst, PFS, KeywordVal);
|
||||
case lltok::kw_fcmp: {
|
||||
FastMathFlags FMF = EatFastMathFlagsIfPresent();
|
||||
int Res = ParseCompare(Inst, PFS, KeywordVal);
|
||||
if (Res != 0)
|
||||
return Res;
|
||||
if (FMF.any())
|
||||
Inst->setFastMathFlags(FMF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Casts.
|
||||
case lltok::kw_trunc:
|
||||
case lltok::kw_zext:
|
||||
|
@ -697,6 +697,21 @@ static Comdat::SelectionKind getDecodedComdatSelectionKind(unsigned Val) {
|
||||
}
|
||||
}
|
||||
|
||||
static FastMathFlags getDecodedFastMathFlags(unsigned Val) {
|
||||
FastMathFlags FMF;
|
||||
if (0 != (Val & FastMathFlags::UnsafeAlgebra))
|
||||
FMF.setUnsafeAlgebra();
|
||||
if (0 != (Val & FastMathFlags::NoNaNs))
|
||||
FMF.setNoNaNs();
|
||||
if (0 != (Val & FastMathFlags::NoInfs))
|
||||
FMF.setNoInfs();
|
||||
if (0 != (Val & FastMathFlags::NoSignedZeros))
|
||||
FMF.setNoSignedZeros();
|
||||
if (0 != (Val & FastMathFlags::AllowReciprocal))
|
||||
FMF.setAllowReciprocal();
|
||||
return FMF;
|
||||
}
|
||||
|
||||
static void upgradeDLLImportExportLinkage(llvm::GlobalValue *GV, unsigned Val) {
|
||||
switch (Val) {
|
||||
case 5: GV->setDLLStorageClass(GlobalValue::DLLImportStorageClass); break;
|
||||
@ -3472,17 +3487,7 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
|
||||
if (Record[OpNum] & (1 << bitc::PEO_EXACT))
|
||||
cast<BinaryOperator>(I)->setIsExact(true);
|
||||
} else if (isa<FPMathOperator>(I)) {
|
||||
FastMathFlags FMF;
|
||||
if (0 != (Record[OpNum] & FastMathFlags::UnsafeAlgebra))
|
||||
FMF.setUnsafeAlgebra();
|
||||
if (0 != (Record[OpNum] & FastMathFlags::NoNaNs))
|
||||
FMF.setNoNaNs();
|
||||
if (0 != (Record[OpNum] & FastMathFlags::NoInfs))
|
||||
FMF.setNoInfs();
|
||||
if (0 != (Record[OpNum] & FastMathFlags::NoSignedZeros))
|
||||
FMF.setNoSignedZeros();
|
||||
if (0 != (Record[OpNum] & FastMathFlags::AllowReciprocal))
|
||||
FMF.setAllowReciprocal();
|
||||
FastMathFlags FMF = getDecodedFastMathFlags(Record[OpNum]);
|
||||
if (FMF.any())
|
||||
I->setFastMathFlags(FMF);
|
||||
}
|
||||
@ -3739,14 +3744,25 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
|
||||
unsigned OpNum = 0;
|
||||
Value *LHS, *RHS;
|
||||
if (getValueTypePair(Record, OpNum, NextValueNo, LHS) ||
|
||||
popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS) ||
|
||||
OpNum+1 != Record.size())
|
||||
popValue(Record, OpNum, NextValueNo, LHS->getType(), RHS))
|
||||
return error("Invalid record");
|
||||
|
||||
unsigned PredVal = Record[OpNum];
|
||||
bool IsFP = LHS->getType()->isFPOrFPVectorTy();
|
||||
FastMathFlags FMF;
|
||||
if (IsFP && Record.size() > OpNum+1)
|
||||
FMF = getDecodedFastMathFlags(Record[++OpNum]);
|
||||
|
||||
if (OpNum+1 != Record.size())
|
||||
return error("Invalid record");
|
||||
|
||||
if (LHS->getType()->isFPOrFPVectorTy())
|
||||
I = new FCmpInst((FCmpInst::Predicate)Record[OpNum], LHS, RHS);
|
||||
I = new FCmpInst((FCmpInst::Predicate)PredVal, LHS, RHS);
|
||||
else
|
||||
I = new ICmpInst((ICmpInst::Predicate)Record[OpNum], LHS, RHS);
|
||||
I = new ICmpInst((ICmpInst::Predicate)PredVal, LHS, RHS);
|
||||
|
||||
if (FMF.any())
|
||||
I->setFastMathFlags(FMF);
|
||||
InstructionList.push_back(I);
|
||||
break;
|
||||
}
|
||||
|
@ -1759,13 +1759,17 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
|
||||
pushValue(I.getOperand(2), InstID, Vals, VE);
|
||||
break;
|
||||
case Instruction::ICmp:
|
||||
case Instruction::FCmp:
|
||||
case Instruction::FCmp: {
|
||||
// compare returning Int1Ty or vector of Int1Ty
|
||||
Code = bitc::FUNC_CODE_INST_CMP2;
|
||||
PushValueAndType(I.getOperand(0), InstID, Vals, VE);
|
||||
pushValue(I.getOperand(1), InstID, Vals, VE);
|
||||
Vals.push_back(cast<CmpInst>(I).getPredicate());
|
||||
uint64_t Flags = GetOptimizationFlags(&I);
|
||||
if (Flags != 0)
|
||||
Vals.push_back(Flags);
|
||||
break;
|
||||
}
|
||||
|
||||
case Instruction::Ret:
|
||||
{
|
||||
|
23
test/Bitcode/fcmp-fast.ll
Normal file
23
test/Bitcode/fcmp-fast.ll
Normal file
@ -0,0 +1,23 @@
|
||||
; RUN: llvm-as < %s | llvm-dis > %t0
|
||||
; RUN: opt -S < %s > %t1
|
||||
; RUN: diff %t0 %t1
|
||||
; RUN: FileCheck < %t1 %s
|
||||
|
||||
; Make sure flags on fcmp instructions are serialized/deserialized properly.
|
||||
|
||||
define i1 @foo(float %a, float %b, double %c, double %d) {
|
||||
; CHECK: %plain = fcmp ueq float %a, %b
|
||||
%plain = fcmp ueq float %a, %b
|
||||
; CHECK: %fast = fcmp fast olt float %a, %b
|
||||
%fast = fcmp fast olt float %a, %b
|
||||
; CHECK: %nsz = fcmp nsz uge float %a, %b
|
||||
%nsz = fcmp nsz uge float %a, %b
|
||||
; CHECK: %nnan = fcmp nnan nsz oge double %c, %d
|
||||
%nnan = fcmp nnan nsz oge double %c, %d
|
||||
|
||||
%dce1 = or i1 %plain, %fast
|
||||
%dce2 = or i1 %dce1, %nsz
|
||||
%dce3 = or i1 %dce2, %nnan
|
||||
|
||||
ret i1 %dce3
|
||||
}
|
@ -130,8 +130,8 @@ TEST_F(IRBuilderTest, GetIntTy) {
|
||||
|
||||
TEST_F(IRBuilderTest, FastMathFlags) {
|
||||
IRBuilder<> Builder(BB);
|
||||
Value *F;
|
||||
Instruction *FDiv, *FAdd;
|
||||
Value *F, *FC;
|
||||
Instruction *FDiv, *FAdd, *FCmp;
|
||||
|
||||
F = Builder.CreateLoad(GV);
|
||||
F = Builder.CreateFAdd(F, F);
|
||||
@ -190,6 +190,24 @@ TEST_F(IRBuilderTest, FastMathFlags) {
|
||||
|
||||
Builder.clearFastMathFlags();
|
||||
|
||||
FC = Builder.CreateFCmpOEQ(F, F);
|
||||
ASSERT_TRUE(isa<Instruction>(FC));
|
||||
FCmp = cast<Instruction>(FC);
|
||||
EXPECT_FALSE(FCmp->hasAllowReciprocal());
|
||||
|
||||
FMF.clear();
|
||||
FMF.setAllowReciprocal();
|
||||
Builder.SetFastMathFlags(FMF);
|
||||
|
||||
FC = Builder.CreateFCmpOEQ(F, F);
|
||||
EXPECT_TRUE(Builder.getFastMathFlags().any());
|
||||
EXPECT_TRUE(Builder.getFastMathFlags().AllowReciprocal);
|
||||
ASSERT_TRUE(isa<Instruction>(FC));
|
||||
FCmp = cast<Instruction>(FC);
|
||||
EXPECT_TRUE(FCmp->hasAllowReciprocal());
|
||||
|
||||
Builder.clearFastMathFlags();
|
||||
|
||||
// To test a copy, make sure that a '0' and a '1' change state.
|
||||
F = Builder.CreateFDiv(F, F);
|
||||
ASSERT_TRUE(isa<Instruction>(F));
|
||||
|
Loading…
x
Reference in New Issue
Block a user