Index: include/llvm-c/Core.h =================================================================== --- include/llvm-c/Core.h +++ include/llvm-c/Core.h @@ -69,6 +69,7 @@ /* Standard Unary Operators */ LLVMFNeg = 66, + LLVMFreeze = 68, /* Standard Binary Operators */ LLVMAdd = 8, @@ -140,7 +141,7 @@ LLVMCatchRet = 62, LLVMCatchPad = 63, LLVMCleanupPad = 64, - LLVMCatchSwitch = 65 + LLVMCatchSwitch = 65, } LLVMOpcode; typedef enum { @@ -1592,7 +1593,8 @@ macro(ZExtInst) \ macro(ExtractValueInst) \ macro(LoadInst) \ - macro(VAArgInst) + macro(VAArgInst) \ + macro(FreezeInst) /** * @defgroup LLVMCCoreValueGeneral General APIs @@ -3893,6 +3895,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 @@ -559,6 +559,7 @@ FUNC_CODE_INST_UNOP = 56, // UNOP: [opcode, ty, opval] FUNC_CODE_INST_CALLBR = 57, // CALLBR: [attr, cc, norm, transfs, // fnty, fnid, args...] + FUNC_CODE_INST_FREEZE = 58, // FREEZE: [opty, opval] }; enum UseListCodes { Index: include/llvm/CodeGen/GlobalISel/IRTranslator.h =================================================================== --- include/llvm/CodeGen/GlobalISel/IRTranslator.h +++ include/llvm/CodeGen/GlobalISel/IRTranslator.h @@ -483,6 +483,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 @@ -2354,6 +2354,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 @@ -199,6 +199,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(DbgVariableIntrinsic);} Index: include/llvm/IR/Instruction.def =================================================================== --- include/llvm/IR/Instruction.def +++ include/llvm/IR/Instruction.def @@ -217,7 +217,8 @@ HANDLE_OTHER_INST(64, ExtractValue, ExtractValueInst)// extract from aggregate HANDLE_OTHER_INST(65, InsertValue, InsertValueInst) // insert into aggregate HANDLE_OTHER_INST(66, LandingPad, LandingPadInst) // Landing pad instruction. - LAST_OTHER_INST(66) +HANDLE_OTHER_INST(67, Freeze, FreezeInst) // Freeze instruction. + LAST_OTHER_INST(67) #undef FIRST_TERM_INST #undef HANDLE_TERM_INST Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -5292,6 +5292,44 @@ return cast(I)->getPointerAddressSpace(); } +//===----------------------------------------------------------------------===// +// 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 @@ -1187,6 +1187,12 @@ return m_Select(C, m_ConstantInt(), m_ConstantInt()); } +/// Matches LoadInst. +template +inline OneOps_match m_Freeze(const OpTy &Op) { + return OneOps_match(Op); +} + /// Matches InsertElementInst. template inline ThreeOps_match Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -891,6 +891,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 @@ -600,6 +600,7 @@ int ParseGetElementPtr(Instruction *&Inst, PerFunctionState &PFS); int ParseExtractValue(Instruction *&Inst, PerFunctionState &PFS); int ParseInsertValue(Instruction *&Inst, 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 @@ -5804,6 +5804,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); @@ -6727,6 +6728,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 @@ -351,6 +351,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 @@ -5096,6 +5096,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 @@ -3028,6 +3028,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 @@ -742,6 +742,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); void visitIntrinsicCall(const CallInst &I, unsigned Intrinsic); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -10535,3 +10535,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 @@ -1611,6 +1611,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 @@ -3821,6 +3821,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 @@ -368,6 +368,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 @@ -4090,6 +4090,22 @@ setNumHungOffUseOperands(NumOps-1); } +//===----------------------------------------------------------------------===// +// 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 //===----------------------------------------------------------------------===// @@ -4305,3 +4321,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 @@ -492,6 +492,7 @@ void visitFuncletPadInst(FuncletPadInst &FPI); void visitCatchSwitchInst(CatchSwitchInst &CatchSwitch); void visitCleanupReturnInst(CleanupReturnInst &CRI); + void visitFreezeInst(FreezeInst &FI); void verifySwiftErrorCall(CallBase &Call, const Value *SwiftErrorVal); void verifySwiftErrorValue(const Value *SwiftErrorVal); @@ -3959,6 +3960,13 @@ visitTerminator(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 @@ -1361,6 +1361,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 @@ -729,6 +729,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 @@ -45,6 +45,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 = Function::Create(FTy, Function::ExternalLinkage, "foo", M); + 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);