Index: llvm/trunk/docs/LangRef.rst =================================================================== --- llvm/trunk/docs/LangRef.rst +++ llvm/trunk/docs/LangRef.rst @@ -10067,7 +10067,7 @@ :: - = phi [ , ], ... + = phi [fast-math-flags] [ , ], ... Overview: """"""""" @@ -10094,6 +10094,12 @@ 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 `. 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: """""""""" Index: llvm/trunk/include/llvm/IR/IRBuilder.h =================================================================== --- llvm/trunk/include/llvm/IR/IRBuilder.h +++ llvm/trunk/include/llvm/IR/IRBuilder.h @@ -2231,7 +2231,10 @@ PHINode *CreatePHI(Type *Ty, unsigned NumReservedValues, const Twine &Name = "") { - return Insert(PHINode::Create(Ty, NumReservedValues), Name); + PHINode *Phi = PHINode::Create(Ty, NumReservedValues); + if (isa(Phi)) + Phi = cast(setFPAttrs(Phi, nullptr /* MDNode* */, FMF)); + return Insert(Phi, Name); } CallInst *CreateCall(FunctionType *FTy, Value *Callee, Index: llvm/trunk/include/llvm/IR/Operator.h =================================================================== --- llvm/trunk/include/llvm/IR/Operator.h +++ llvm/trunk/include/llvm/IR/Operator.h @@ -379,13 +379,17 @@ 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(); Index: llvm/trunk/lib/Analysis/IVDescriptors.cpp =================================================================== --- llvm/trunk/lib/Analysis/IVDescriptors.cpp +++ llvm/trunk/lib/Analysis/IVDescriptors.cpp @@ -300,7 +300,8 @@ ReduxDesc = isRecurrenceInstr(Cur, Kind, ReduxDesc, HasFunNoNaNAttr); if (!ReduxDesc.isRecurrence()) return false; - if (isa(ReduxDesc.getPatternInst())) + // FIXME: FMF is allowed on phi, but propagation is not handled correctly. + if (isa(ReduxDesc.getPatternInst()) && !IsAPhi) FMF &= ReduxDesc.getPatternInst()->getFastMathFlags(); } Index: llvm/trunk/lib/AsmParser/LLParser.cpp =================================================================== --- llvm/trunk/lib/AsmParser/LLParser.cpp +++ llvm/trunk/lib/AsmParser/LLParser.cpp @@ -5802,7 +5802,19 @@ 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); Index: llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp +++ llvm/trunk/lib/Bitcode/Reader/BitcodeReader.cpp @@ -4629,31 +4629,48 @@ 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(I) && "Unexpected phi type"); + FastMathFlags FMF = getDecodedFastMathFlags(Record[Record.size() - 1]); + if (FMF.any()) + I->setFastMathFlags(FMF); + } + break; } Index: llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp +++ llvm/trunk/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2880,6 +2880,11 @@ 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(); Index: llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp +++ llvm/trunk/lib/CodeGen/CodeGenPrepare.cpp @@ -5951,7 +5951,7 @@ // If branch conversion isn't desirable, exit early. if (DisableSelectToBranch || OptSize || !TLI) return false; - +TLI->isSelectSupported(<#SelectSupportKind#>) // Find all consecutive select instructions that share the same condition. SmallVector ASI; ASI.push_back(SI); Index: llvm/trunk/test/Bitcode/compatibility.ll =================================================================== --- llvm/trunk/test/Bitcode/compatibility.ll +++ llvm/trunk/test/Bitcode/compatibility.ll @@ -861,6 +861,27 @@ 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() Index: llvm/trunk/unittests/IR/InstructionsTest.cpp =================================================================== --- llvm/trunk/unittests/IR/InstructionsTest.cpp +++ llvm/trunk/unittests/IR/InstructionsTest.cpp @@ -1034,13 +1034,16 @@ 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(I)); I->deleteValue(); + Instruction *FP = Builder.CreatePHI(Builder.getDoubleTy(), 0); + EXPECT_TRUE(isa(FP)); + FP->deleteValue(); } TEST(InstructionsTest, FNegInstruction) {