Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1816,8 +1816,8 @@ LLVM IR floating-point binary ops (:ref:`fadd `, :ref:`fsub `, :ref:`fmul `, :ref:`fdiv `, -:ref:`frem `) have the following flags that can be set to enable -otherwise unsafe floating point operations +:ref:`frem `, :ref:`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 @@ -6892,7 +6892,7 @@ :: - = fcmp , ; yields i1 or :result + = fcmp [fast-math flags]* , ; yields i1 or :result Overview: """"""""" @@ -6975,6 +6975,15 @@ #. ``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 `, 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 domain of input arguments; namely +``nnan``, ``ninf``, and ``nsz``. See :ref:`fastmath` for more information. + Example: """""""" @@ -6985,9 +6994,6 @@ = fcmp olt float 4.0, 5.0 ; yields: result=true = fcmp ueq double 1.0, 2.0 ; yields: result=false -Note that the code generator does not yet support vector types with the -``fcmp`` instruction. - .. _i_phi: '``phi``' Instruction Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -1398,47 +1398,61 @@ 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, @@ -1449,11 +1463,12 @@ 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(LHS)) if (Constant *RC = dyn_cast(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); } //===--------------------------------------------------------------------===// Index: include/llvm/IR/Operator.h =================================================================== --- include/llvm/IR/Operator.h +++ include/llvm/IR/Operator.h @@ -305,7 +305,8 @@ 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(V) && classof(cast(V)); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -4497,8 +4497,17 @@ 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: Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -704,6 +704,21 @@ } } +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; @@ -3494,17 +3509,7 @@ if (Record[OpNum] & (1 << bitc::PEO_EXACT)) cast(I)->setIsExact(true); } else if (isa(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); } @@ -3761,14 +3766,25 @@ 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; } Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1744,13 +1744,17 @@ 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(I).getPredicate()); + uint64_t Flags = GetOptimizationFlags(&I); + if (Flags != 0) + Vals.push_back(Flags); break; + } case Instruction::Ret: { Index: test/Bitcode/fcmp-fast.ll =================================================================== --- /dev/null +++ test/Bitcode/fcmp-fast.ll @@ -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 +} Index: unittests/IR/IRBuilderTest.cpp =================================================================== --- unittests/IR/IRBuilderTest.cpp +++ unittests/IR/IRBuilderTest.cpp @@ -131,8 +131,8 @@ 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); @@ -191,6 +191,24 @@ Builder.clearFastMathFlags(); + FC = Builder.CreateFCmpOEQ(F, F); + ASSERT_TRUE(isa(FC)); + FCmp = cast(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(FC)); + FCmp = cast(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(F));