Index: include/llvm-c/Core.h =================================================================== --- include/llvm-c/Core.h +++ include/llvm-c/Core.h @@ -134,7 +134,10 @@ LLVMCatchRet = 62, LLVMCatchPad = 63, LLVMCleanupPad = 64, - LLVMCatchSwitch = 65 + LLVMCatchSwitch = 65, + + /* Freeze operator */ + LLVMFreeze = 66 } LLVMOpcode; typedef enum { @@ -1251,7 +1254,8 @@ macro(ZExtInst) \ macro(ExtractValueInst) \ macro(LoadInst) \ - macro(VAArgInst) + macro(VAArgInst) \ + macro(FreezeInst) /** * @defgroup LLVMCCoreValueGeneral General APIs @@ -3044,6 +3048,8 @@ LLVMValueRef LLVMBuildInsertValue(LLVMBuilderRef, LLVMValueRef AggVal, LLVMValueRef EltVal, unsigned Index, const char *Name); +LLVMValueRef LLVMBuildFreeze(LLVMBuilderRef, LLVMValueRef Val, + const char *Name); LLVMValueRef LLVMBuildIsNull(LLVMBuilderRef, LLVMValueRef Val, const char *Name); Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -497,6 +497,7 @@ // 53 is unused. // 54 is unused. FUNC_CODE_OPERAND_BUNDLE = 55, // OPERAND_BUNDLE: [tag#, value...] + FUNC_CODE_INST_FREEZE = 56, // FREEZE: [opty, opval] }; enum UseListCodes { Index: include/llvm/CodeGen/GlobalISel/IRTranslator.h =================================================================== --- include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -348,6 +348,9 @@ bool translateUserOp2(const User &U, MachineIRBuilder &MIRBuilder) { return false; } + bool translateFreeze(const User &U, MachineIRBuilder &MIRBuilder) { + return false; + } /// @} Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -1770,6 +1770,10 @@ return Insert(LandingPadInst::Create(Ty, NumClauses), Name); } + Value *CreateFreeze(Value *V, const Twine &Name = "") { + return Insert(new FreezeInst(V), Name); + } + //===--------------------------------------------------------------------===// // Utility creation methods //===--------------------------------------------------------------------===// Index: include/llvm/IR/InstVisitor.h =================================================================== --- include/llvm/IR/InstVisitor.h +++ include/llvm/IR/InstVisitor.h @@ -209,6 +209,7 @@ RetTy visitFuncletPadInst(FuncletPadInst &I) { DELEGATE(Instruction); } RetTy visitCleanupPadInst(CleanupPadInst &I) { DELEGATE(FuncletPadInst); } RetTy visitCatchPadInst(CatchPadInst &I) { DELEGATE(FuncletPadInst); } + RetTy visitFreezeInst(FreezeInst &I) { DELEGATE(Instruction); } // Handle the special instrinsic instruction classes. RetTy visitDbgDeclareInst(DbgDeclareInst &I) { DELEGATE(DbgInfoIntrinsic);} Index: include/llvm/IR/Instruction.def =================================================================== --- include/llvm/IR/Instruction.def +++ include/llvm/IR/Instruction.def @@ -198,7 +198,8 @@ HANDLE_OTHER_INST(62, ExtractValue, ExtractValueInst)// extract from aggregate HANDLE_OTHER_INST(63, InsertValue, InsertValueInst) // insert into aggregate HANDLE_OTHER_INST(64, LandingPad, LandingPadInst) // Landing pad instruction. - LAST_OTHER_INST(64) +HANDLE_OTHER_INST(65, Freeze, FreezeInst) // Freeze instruction. + LAST_OTHER_INST(65) #undef FIRST_TERM_INST #undef HANDLE_TERM_INST Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -5149,6 +5149,44 @@ } }; +//===----------------------------------------------------------------------===// +// FreezeInst Class +//===----------------------------------------------------------------------===// + +/// This class represents a freeze function that returns random concrete +/// value if an operand is either a poison value or an undef value +class FreezeInst : public UnaryInstruction { +protected: + // Note: Instruction needs to be a friend here to call cloneImpl. + friend class Instruction; + + /// Clone an identical FreezeInst + FreezeInst *cloneImpl() const; + +public: + /// Constructor with insert-before-instruction semantics + FreezeInst( + Value *S, ///< The value to freeze + const Twine &NameStr = "", ///< A name for the new instruction + Instruction *InsertBefore = nullptr ///< Where to insert the new instruction + ); + + /// Constructor with insert-at-end-of-block semantics + FreezeInst( + Value *S, ///< The value to freeze + const Twine &NameStr, ///< A name for the new instruction + BasicBlock *InsertAtEnd ///< The block to insert the instruction into + ); + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const Instruction *I) { + return I->getOpcode() == Freeze; + } + static inline bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } +}; + } // end namespace llvm #endif // LLVM_IR_INSTRUCTIONS_H Index: include/llvm/IR/PatternMatch.h =================================================================== --- include/llvm/IR/PatternMatch.h +++ include/llvm/IR/PatternMatch.h @@ -1008,6 +1008,25 @@ return L; } +template struct FreezeClass_match { + Op_t Op; + + FreezeClass_match(const Op_t &OpMatch) : Op(OpMatch) {} + + template bool match(OpTy *V) { + if (auto *O = dyn_cast(V)) + return O->getOpcode() == Instruction::Freeze && + Op.match(O->getOperand(0)); + return false; + } +}; + +/// \brief Matches Freeze. +template +inline FreezeClass_match m_Freeze(const OpTy &Op) { + return FreezeClass_match(Op); +} + //===----------------------------------------------------------------------===// // Matchers for control flow. // Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -787,6 +787,8 @@ INSTKEYWORD(catchpad, CatchPad); INSTKEYWORD(cleanuppad, CleanupPad); + INSTKEYWORD(freeze, Freeze); + #undef INSTKEYWORD #define DWKEYWORD(TYPE, TOKEN) \ Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -505,6 +505,7 @@ int ParseGetElementPtr(Instruction *&I, PerFunctionState &PFS); int ParseExtractValue(Instruction *&I, PerFunctionState &PFS); int ParseInsertValue(Instruction *&I, PerFunctionState &PFS); + bool ParseFreeze(Instruction *&I, PerFunctionState &PFS); // Use-list order directives. bool ParseUseListOrder(PerFunctionState *PFS = nullptr); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -5154,6 +5154,7 @@ case lltok::kw_shufflevector: return ParseShuffleVector(Inst, PFS); case lltok::kw_phi: return ParsePHI(Inst, PFS); case lltok::kw_landingpad: return ParseLandingPad(Inst, PFS); + case lltok::kw_freeze: return ParseFreeze(Inst, PFS); // Call. case lltok::kw_call: return ParseCall(Inst, PFS, CallInst::TCK_None); case lltok::kw_tail: return ParseCall(Inst, PFS, CallInst::TCK_Tail); @@ -5940,6 +5941,21 @@ return false; } +/// ParseFreeze +/// ::= 'freeze' Type Value +bool LLParser::ParseFreeze(Instruction *&Inst, PerFunctionState &PFS) { + LocTy Loc; + Value *Op; + if (ParseTypeAndValue(Op, Loc, PFS)) + return true; + + if (!Op->getType()->isIntegerTy()) + return Error(Loc,"cannot freeze non-integer type"); + + Inst = new FreezeInst(Op); + return false; +} + /// ParseCall /// ::= 'call' OptionalFastMathFlags OptionalCallingConv /// OptionalAttrs Type Value ParameterList OptionalAttrs Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -328,6 +328,8 @@ kw_insertvalue, kw_blockaddress, + kw_freeze, + // Metadata types. kw_distinct, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -4532,6 +4532,21 @@ OperandBundles.emplace_back(BundleTags[Record[0]], std::move(Inputs)); continue; } + + case bitc::FUNC_CODE_INST_FREEZE: { // FREEZE: [opty,opval] + unsigned OpNum = 0; + Value *Op = nullptr; + if (getValueTypePair(Record, OpNum, NextValueNo, Op)) + return error("Invalid record"); + if (OpNum != Record.size()) + return error("Invalid record"); + if (!Op->getType()->isIntegerTy()) + return error("Invalid type for value"); + + I = new FreezeInst(Op); + InstructionList.push_back(I); + break; + } } // Add instruction to end of current BB. If there is no current BB, reject Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -2768,6 +2768,10 @@ pushValue(I.getOperand(0), InstID, Vals); // valist. Vals.push_back(VE.getTypeID(I.getType())); // restype. break; + case Instruction::Freeze: + Code = bitc::FUNC_CODE_INST_FREEZE; + pushValueAndType(I.getOperand(0), InstID, Vals); + break; } Stream.EmitRecord(Code, Vals, AbbrevToUse); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.h @@ -889,6 +889,7 @@ void visitAtomicStore(const StoreInst &I); void visitLoadFromSwiftError(const LoadInst &I); void visitStoreToSwiftError(const StoreInst &I); + void visitFreeze(const FreezeInst &I); void visitInlineAsm(ImmutableCallSite CS); const char *visitIntrinsicCall(const CallInst &I, unsigned Intrinsic); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -9826,3 +9826,8 @@ lowerWorkItem(W, SI.getCondition(), SwitchMBB, DefaultMBB); } } + +void SelectionDAGBuilder::visitFreeze(const FreezeInst &I) { + SDValue N = getValue(I.getOperand(0)); + setValue(&I, N); +} Index: lib/CodeGen/TargetLoweringBase.cpp =================================================================== --- lib/CodeGen/TargetLoweringBase.cpp +++ lib/CodeGen/TargetLoweringBase.cpp @@ -1825,6 +1825,7 @@ case ExtractValue: return ISD::MERGE_VALUES; case InsertValue: return ISD::MERGE_VALUES; case LandingPad: return 0; + case Freeze: return 0; } llvm_unreachable("Unknown instruction type encountered!"); Index: lib/IR/Core.cpp =================================================================== --- lib/IR/Core.cpp +++ lib/IR/Core.cpp @@ -3010,6 +3010,11 @@ Index, Name)); } +LLVMValueRef LLVMBuildFreeze(LLVMBuilderRef B, LLVMValueRef Val, + const char *Name) { + return wrap(unwrap(B)->CreateFreeze(unwrap(Val), Name)); +} + LLVMValueRef LLVMBuildIsNull(LLVMBuilderRef B, LLVMValueRef Val, const char *Name) { return wrap(unwrap(B)->CreateIsNull(unwrap(Val), Name)); Index: lib/IR/Instruction.cpp =================================================================== --- lib/IR/Instruction.cpp +++ lib/IR/Instruction.cpp @@ -340,6 +340,7 @@ case InsertValue: return "insertvalue"; case LandingPad: return "landingpad"; case CleanupPad: return "cleanuppad"; + case Freeze: return "freeze"; default: return " "; } Index: lib/IR/Instructions.cpp =================================================================== --- lib/IR/Instructions.cpp +++ lib/IR/Instructions.cpp @@ -3754,6 +3754,22 @@ } //===----------------------------------------------------------------------===// +// FreezeInst Implementation +//===----------------------------------------------------------------------===// + +FreezeInst::FreezeInst(Value *S, + const Twine &Name, Instruction *InsertBefore) + : UnaryInstruction(S->getType(), Freeze, S, InsertBefore) { + setName(Name); +} + +FreezeInst::FreezeInst(Value *S, + const Twine &Name, BasicBlock *InsertAtEnd) + : UnaryInstruction(S->getType(), Freeze, S, InsertAtEnd) { + setName(Name); +} + +//===----------------------------------------------------------------------===// // cloneImpl() implementations //===----------------------------------------------------------------------===// @@ -3956,3 +3972,7 @@ LLVMContext &Context = getContext(); return new UnreachableInst(Context); } + +FreezeInst *FreezeInst::cloneImpl() const { + return new FreezeInst(getOperand(0)); +} Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -485,6 +485,7 @@ void visitFuncletPadInst(FuncletPadInst &FPI); void visitCatchSwitchInst(CatchSwitchInst &CatchSwitch); void visitCleanupReturnInst(CleanupReturnInst &CRI); + void visitFreezeInst(FreezeInst &FI); void verifyCallSite(CallSite CS); void verifySwiftErrorCallSite(CallSite CS, const Value *SwiftErrorVal); @@ -3685,6 +3686,13 @@ visitTerminatorInst(CRI); } +void Verifier::visitFreezeInst(FreezeInst &FI) { + Assert(FI.getOperand(0)->getType()->isIntegerTy(), + "Cannot freeze non-integer type!", &FI); + + visitInstruction(FI); +} + void Verifier::verifyDominatesUse(Instruction &I, unsigned i) { Instruction *Op = cast(I.getOperand(i)); // If the we have an invalid invoke, don't try to compute the dominance. Index: test/Bindings/llvm-c/freeze.ll =================================================================== --- /dev/null +++ test/Bindings/llvm-c/freeze.ll @@ -0,0 +1,10 @@ +; RUN: llvm-as < %s | llvm-dis > %t.orig +; RUN: llvm-as < %s | llvm-c-test --echo > %t.echo +; RUN: diff -w %t.orig %t.echo + +define i32 @f(i32 %arg) { + %1 = freeze i32 %arg + %2 = freeze i32 10 + %3 = freeze i32 %1 + ret i32 %1 +} Index: test/Bitcode/compatibility.ll =================================================================== --- test/Bitcode/compatibility.ll +++ test/Bitcode/compatibility.ll @@ -1257,6 +1257,11 @@ tail call ghccc nonnull i32* @f.nonnull() minsize ; CHECK: tail call ghccc nonnull i32* @f.nonnull() #7 + freeze i32 %op1 + ; CHECK: freeze i32 %op1 + freeze i32 10 + ; CHECK: freeze i32 10 + ret void } Index: test/Bitcode/freeze-float.ll =================================================================== --- /dev/null +++ test/Bitcode/freeze-float.ll @@ -0,0 +1,7 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK: freeze-float.ll:[[@LINE+2]]:15: error: cannot freeze non-integer type +define float @float(float %x) { + %y = freeze float %x + ret float %y +} Index: test/Bitcode/freeze-pointer.ll =================================================================== --- /dev/null +++ test/Bitcode/freeze-pointer.ll @@ -0,0 +1,7 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK: freeze-pointer.ll:[[@LINE+2]]:15: error: cannot freeze non-integer type +define i32* @ptr(i32* %x) { + %y = freeze i32* %x + ret i32* %y +} Index: test/Bitcode/freeze-vector.ll =================================================================== --- /dev/null +++ test/Bitcode/freeze-vector.ll @@ -0,0 +1,7 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +; CHECK: freeze-vector.ll:[[@LINE+2]]:15: error: cannot freeze non-integer type +define <2 x i32> @vec(<2 x i32> %x) { + %y = freeze <2 x i32> %x + ret <2 x i32> %y +} Index: tools/llvm-c-test/echo.cpp =================================================================== --- tools/llvm-c-test/echo.cpp +++ tools/llvm-c-test/echo.cpp @@ -647,6 +647,11 @@ Dst = LLVMBuildInsertValue(Builder, Agg, V, I, Name); break; } + case LLVMFreeze: { + LLVMValueRef Arg = CloneValue(LLVMGetOperand(Src, 0)); + Dst = LLVMBuildFreeze(Builder, Arg, Name); + break; + } default: break; } Index: unittests/IR/VerifierTest.cpp =================================================================== --- unittests/IR/VerifierTest.cpp +++ unittests/IR/VerifierTest.cpp @@ -47,6 +47,54 @@ EXPECT_TRUE(verifyFunction(*F)); } +TEST(VerifierTest, Freeze) { + LLVMContext C; + Module M("M", C); + FunctionType *FTy = FunctionType::get(Type::getVoidTy(C), /*isVarArg=*/false); + Function *F = cast(M.getOrInsertFunction("foo", FTy)); + BasicBlock *Entry = BasicBlock::Create(C, "entry", F); + ReturnInst *RI = ReturnInst::Create(C, Entry); + + IntegerType *ITy = IntegerType::get(C, 32); + ConstantInt *CI = ConstantInt::get(ITy, 0); + + // Invalid type : freeze(<2 x i32>) + Constant *CV = ConstantVector::getSplat(2, CI); + FreezeInst *FI_vec = new FreezeInst(CV); + FI_vec->insertBefore(RI); + + EXPECT_TRUE(verifyFunction(*F)); + + FI_vec->eraseFromParent(); + + // Invalid type : freeze(float) + Constant *CFP = ConstantFP::get(Type::getDoubleTy(C), 0.0); + FreezeInst *FI_dbl = new FreezeInst(CFP); + FI_dbl->insertBefore(RI); + + EXPECT_TRUE(verifyFunction(*F)); + + FI_dbl->eraseFromParent(); + + // Invalid type : freeze(i32*) + PointerType *PT = PointerType::get(ITy, 0); + ConstantPointerNull *CPN = ConstantPointerNull::get(PT); + FreezeInst *FI_ptr = new FreezeInst(CPN); + FI_ptr->insertBefore(RI); + + EXPECT_TRUE(verifyFunction(*F)); + + FI_ptr->eraseFromParent(); + + // Valid type : freeze(int) + FreezeInst *FI = new FreezeInst(CI); + FI->insertBefore(RI); + + EXPECT_FALSE(verifyFunction(*F)); + + FI_ptr->eraseFromParent(); +} + TEST(VerifierTest, InvalidRetAttribute) { LLVMContext C; Module M("M", C);