diff options
-rw-r--r-- | llvm/docs/LangRef.rst | 8 | ||||
-rw-r--r-- | llvm/include/llvm/IR/IRBuilder.h | 5 | ||||
-rw-r--r-- | llvm/include/llvm/IR/Operator.h | 6 | ||||
-rw-r--r-- | llvm/lib/Analysis/IVDescriptors.cpp | 3 | ||||
-rw-r--r-- | llvm/lib/AsmParser/LLParser.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 29 | ||||
-rw-r--r-- | llvm/lib/Bitcode/Writer/BitcodeWriter.cpp | 5 | ||||
-rw-r--r-- | llvm/test/Bitcode/compatibility.ll | 21 | ||||
-rw-r--r-- | llvm/unittests/IR/InstructionsTest.cpp | 7 |
9 files changed, 85 insertions, 13 deletions
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst index 87e1b971605..a38356aa27e 100644 --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -10067,7 +10067,7 @@ Syntax: :: - <result> = phi <ty> [ <val0>, <label0>], ... + <result> = phi [fast-math-flags] <ty> [ <val0>, <label0>], ... Overview: """"""""" @@ -10094,6 +10094,12 @@ deemed to occur on the edge from the corresponding predecessor block to the current block (but after any definition of an '``invoke``' instruction's return value on the same edge). +The optional ``fast-math-flags`` marker indicates that the phi has one +or more :ref:`fast-math-flags <fastmath>`. These are optimization hints +to enable otherwise unsafe floating-point optimizations. Fast-math-flags +are only valid for phis that return a floating-point scalar or vector +type. + Semantics: """""""""" diff --git a/llvm/include/llvm/IR/IRBuilder.h b/llvm/include/llvm/IR/IRBuilder.h index e5dcea1d4c0..c3918473eac 100644 --- a/llvm/include/llvm/IR/IRBuilder.h +++ b/llvm/include/llvm/IR/IRBuilder.h @@ -2231,7 +2231,10 @@ public: PHINode *CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name = "") { - return Insert(PHINode::Create(Ty, NumReservedValues), Name); + PHINode *Phi = PHINode::Create(Ty, NumReservedValues); + if (isa<FPMathOperator>(Phi)) + Phi = cast<PHINode>(setFPAttrs(Phi, nullptr /* MDNode* */, FMF)); + return Insert(Phi, Name); } CallInst *CreateCall(FunctionType *FTy, Value *Callee, diff --git a/llvm/include/llvm/IR/Operator.h b/llvm/include/llvm/IR/Operator.h index 8199c65ca8a..608f33c3ed5 100644 --- a/llvm/include/llvm/IR/Operator.h +++ b/llvm/include/llvm/IR/Operator.h @@ -379,13 +379,17 @@ public: return false; switch (Opcode) { + // FIXME: To clean up and correct the semantics of fast-math-flags, FCmp + // should not be treated as a math op, but the other opcodes should. + // This would make things consistent with Select/PHI (FP value type + // determines whether they are math ops and, therefore, capable of + // having fast-math-flags). case Instruction::FCmp: return true; // non math FP Operators (no FMF) case Instruction::ExtractElement: case Instruction::ShuffleVector: case Instruction::InsertElement: - case Instruction::PHI: return false; default: return V->getType()->isFPOrFPVectorTy(); diff --git a/llvm/lib/Analysis/IVDescriptors.cpp b/llvm/lib/Analysis/IVDescriptors.cpp index ce285f82f72..6fb600114bc 100644 --- a/llvm/lib/Analysis/IVDescriptors.cpp +++ b/llvm/lib/Analysis/IVDescriptors.cpp @@ -300,7 +300,8 @@ bool RecurrenceDescriptor::AddReductionVar(PHINode *Phi, RecurrenceKind Kind, ReduxDesc = isRecurrenceInstr(Cur, Kind, ReduxDesc, HasFunNoNaNAttr); if (!ReduxDesc.isRecurrence()) return false; - if (isa<FPMathOperator>(ReduxDesc.getPatternInst())) + // FIXME: FMF is allowed on phi, but propagation is not handled correctly. + if (isa<FPMathOperator>(ReduxDesc.getPatternInst()) && !IsAPhi) FMF &= ReduxDesc.getPatternInst()->getFastMathFlags(); } diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp index eb66a7c82b5..5ea0b7d39c1 100644 --- a/llvm/lib/AsmParser/LLParser.cpp +++ b/llvm/lib/AsmParser/LLParser.cpp @@ -5802,7 +5802,19 @@ int LLParser::ParseInstruction(Instruction *&Inst, BasicBlock *BB, case lltok::kw_extractelement: return ParseExtractElement(Inst, PFS); case lltok::kw_insertelement: return ParseInsertElement(Inst, PFS); case lltok::kw_shufflevector: return ParseShuffleVector(Inst, PFS); - case lltok::kw_phi: return ParsePHI(Inst, PFS); + case lltok::kw_phi: { + FastMathFlags FMF = EatFastMathFlagsIfPresent(); + int Res = ParsePHI(Inst, PFS); + if (Res != 0) + return Res; + if (FMF.any()) { + if (!Inst->getType()->isFPOrFPVectorTy()) + return Error(Loc, "fast-math-flags specified for phi without " + "floating-point scalar or vector return type"); + Inst->setFastMathFlags(FMF); + } + return 0; + } case lltok::kw_landingpad: return ParseLandingPad(Inst, PFS); // Call. case lltok::kw_call: return ParseCall(Inst, PFS, CallInst::TCK_None); diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 89a5b7bdd5b..9c377552b4a 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -4629,31 +4629,48 @@ Error BitcodeReader::parseFunctionBody(Function *F) { InstructionList.push_back(I); break; case bitc::FUNC_CODE_INST_PHI: { // PHI: [ty, val0,bb0, ...] - if (Record.size() < 1 || ((Record.size()-1)&1)) + if (Record.size() < 1) return error("Invalid record"); + // The first record specifies the type. FullTy = getFullyStructuredTypeByID(Record[0]); Type *Ty = flattenPointerTypes(FullTy); if (!Ty) return error("Invalid record"); - PHINode *PN = PHINode::Create(Ty, (Record.size()-1)/2); + // Phi arguments are pairs of records of [value, basic block]. + // There is an optional final record for fast-math-flags if this phi has a + // floating-point type. + size_t NumArgs = (Record.size() - 1) / 2; + if ((Record.size() - 1) % 2 == 1 && !Ty->isFloatingPointTy()) + return error("Invalid record"); + + PHINode *PN = PHINode::Create(Ty, NumArgs); InstructionList.push_back(PN); - for (unsigned i = 0, e = Record.size()-1; i != e; i += 2) { + for (unsigned i = 0; i != NumArgs; i++) { Value *V; // With the new function encoding, it is possible that operands have // negative IDs (for forward references). Use a signed VBR // representation to keep the encoding small. if (UseRelativeIDs) - V = getValueSigned(Record, 1+i, NextValueNo, Ty); + V = getValueSigned(Record, i * 2 + 1, NextValueNo, Ty); else - V = getValue(Record, 1+i, NextValueNo, Ty); - BasicBlock *BB = getBasicBlock(Record[2+i]); + V = getValue(Record, i * 2 + 1, NextValueNo, Ty); + BasicBlock *BB = getBasicBlock(Record[i * 2 + 2]); if (!V || !BB) return error("Invalid record"); PN->addIncoming(V, BB); } I = PN; + + // If there are an even number of records, the final record must be FMF. + if (Record.size() % 2 == 0) { + assert(isa<FPMathOperator>(I) && "Unexpected phi type"); + FastMathFlags FMF = getDecodedFastMathFlags(Record[Record.size() - 1]); + if (FMF.any()) + I->setFastMathFlags(FMF); + } + break; } diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp index 0eea6dc87ce..2818e843b50 100644 --- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2880,6 +2880,11 @@ void ModuleBitcodeWriter::writeInstruction(const Instruction &I, pushValueSigned(PN.getIncomingValue(i), InstID, Vals64); Vals64.push_back(VE.getValueID(PN.getIncomingBlock(i))); } + + uint64_t Flags = getOptimizationFlags(&I); + if (Flags != 0) + Vals64.push_back(Flags); + // Emit a Vals64 vector and exit. Stream.EmitRecord(Code, Vals64, AbbrevToUse); Vals64.clear(); diff --git a/llvm/test/Bitcode/compatibility.ll b/llvm/test/Bitcode/compatibility.ll index b17aeda8ebb..9e7f6ac9917 100644 --- a/llvm/test/Bitcode/compatibility.ll +++ b/llvm/test/Bitcode/compatibility.ll @@ -861,6 +861,27 @@ define void @fastmathflags_vector_select(<2 x i1> %cond, <2 x double> %op1, <2 x ret void } +define void @fastmathflags_phi(i1 %cond, float %f1, float %f2, double %d1, double %d2, half %h1, half %h2) { +entry: + br i1 %cond, label %L1, label %L2 +L1: + br label %exit +L2: + br label %exit +exit: + %p.nnan = phi nnan float [ %f1, %L1 ], [ %f2, %L2 ] + ; CHECK: %p.nnan = phi nnan float [ %f1, %L1 ], [ %f2, %L2 ] + %p.ninf = phi ninf double [ %d1, %L1 ], [ %d2, %L2 ] + ; CHECK: %p.ninf = phi ninf double [ %d1, %L1 ], [ %d2, %L2 ] + %p.contract = phi contract half [ %h1, %L1 ], [ %h2, %L2 ] + ; CHECK: %p.contract = phi contract half [ %h1, %L1 ], [ %h2, %L2 ] + %p.nsz.reassoc = phi reassoc nsz float [ %f1, %L1 ], [ %f2, %L2 ] + ; CHECK: %p.nsz.reassoc = phi reassoc nsz float [ %f1, %L1 ], [ %f2, %L2 ] + %p.fast = phi fast half [ %h2, %L1 ], [ %h1, %L2 ] + ; CHECK: %p.fast = phi fast half [ %h2, %L1 ], [ %h1, %L2 ] + ret void +} + ; Check various fast math flags and floating-point types on calls. declare float @fmf1() diff --git a/llvm/unittests/IR/InstructionsTest.cpp b/llvm/unittests/IR/InstructionsTest.cpp index b2ea3844d33..afd579400ff 100644 --- a/llvm/unittests/IR/InstructionsTest.cpp +++ b/llvm/unittests/IR/InstructionsTest.cpp @@ -1034,13 +1034,16 @@ TEST(InstructionsTest, SkipDebug) { EXPECT_EQ(nullptr, Term->getNextNonDebugInstruction()); } -TEST(InstructionsTest, PhiIsNotFPMathOperator) { +TEST(InstructionsTest, PhiMightNotBeFPMathOperator) { LLVMContext Context; IRBuilder<> Builder(Context); MDBuilder MDHelper(Context); - Instruction *I = Builder.CreatePHI(Builder.getDoubleTy(), 0); + Instruction *I = Builder.CreatePHI(Builder.getInt32Ty(), 0); EXPECT_FALSE(isa<FPMathOperator>(I)); I->deleteValue(); + Instruction *FP = Builder.CreatePHI(Builder.getDoubleTy(), 0); + EXPECT_TRUE(isa<FPMathOperator>(FP)); + FP->deleteValue(); } TEST(InstructionsTest, FNegInstruction) { |