Index: docs/ExceptionHandling.rst =================================================================== --- docs/ExceptionHandling.rst +++ docs/ExceptionHandling.rst @@ -614,20 +614,19 @@ a ``noexcept`` function should transitively unwind to a terminateblock. Throw specifications are not implemented by MSVC, and are not yet supported. -Each of these new EH pad instructions has a label operand that indicates which +Each of these new EH pad instructions has a way to identify which action should be considered after this action. The ``catchpad`` and -``terminatepad`` instructions are terminators, and this label is considered to -be an unwind destination analogous to the unwind destination of an invoke. The +``terminatepad`` instructions are terminators, and have a label operand considered +to be an unwind destination analogous to the unwind destination of an invoke. The ``cleanuppad`` instruction is different from the other two in that it is not a -terminator, and this label operand is not an edge in the CFG. The code inside a -cleanuppad runs before transferring control to the next action, so the -``cleanupret`` instruction is the instruction that unwinds to the next EH pad. -All of these "unwind edges" may refer to a basic block that contains an EH pad -instruction, or they may simply unwind to the caller. Unwinding to the caller -has roughly the same semantics as the ``resume`` instruction in the -``landingpad`` model. When inlining through an invoke, instructions that unwind -to the caller are hooked up to unwind to the unwind destination of the call -site. +terminator. The code inside a cleanuppad runs before transferring control to the +next action, so the ``cleanupret`` instruction is the instruction that holds a +label operand and unwinds to the next EH pad. All of these "unwind edges" may +refer to a basic block that contains an EH pad instruction, or they may simply +unwind to the caller. Unwinding to the caller has roughly the same semantics as +the ``resume`` instruction in the ``landingpad`` model. When inlining through an +invoke, instructions that unwind to the caller are hooked up to unwind to the +unwind destination of the call site. Putting things together, here is a hypothetical lowering of some C++ that uses all of the new IR instructions: @@ -674,17 +673,17 @@ ; EH scope code, ordered innermost to outermost: lpad.cleanup: ; preds = %invoke.cont - cleanuppad [label %lpad.catch] + %cleanup = cleanuppad [] call void @"\01??_DCleanup@@QEAA@XZ"(%struct.Cleanup* nonnull %obj) nounwind - cleanupret unwind label %lpad.catch + cleanupret %cleanup unwind label %lpad.catch lpad.catch: ; preds = %entry, %lpad.cleanup - catchpad void [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e] + %catch = catchpad [%rtti.TypeDescriptor2* @"\01??_R0H@8", i32 0, i32* %e] to label %catch unwind label %lpad.terminate catch: ; preds = %lpad.catch %9 = load i32, i32* %e, align 4 - catchret label %return + catchret %catch label %return lpad.terminate: terminatepad [void ()* @"\01?terminate@@YAXXZ"] Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -5138,7 +5138,7 @@ :: - = catchpad [*] + = catchpad [*] to label unwind label Overview: @@ -5153,9 +5153,9 @@ exception. Control is tranfered to the ``exception`` label if the ``catchpad`` is not an appropriate handler for the in-flight exception. The ``normal`` label should contain the code found in the ``catch`` -portion of a ``try``/``catch`` sequence. It defines values supplied by -the :ref:`personality function ` upon re-entry to the -function. The ``resultval`` has the type ``resultty``. +portion of a ``try``/``catch`` sequence. The ``resultval`` has the type +:ref:`token ` and is used to match the ``catchpad`` to +corresponding :ref:`catchrets `. Arguments: """""""""" @@ -5170,15 +5170,11 @@ Semantics: """""""""" -The '``catchpad``' instruction defines the values which are set by the -:ref:`personality function ` upon re-entry to the function, and -therefore the "result type" of the ``catchpad`` instruction. As with -calling conventions, how the personality function results are -represented in LLVM IR is target specific. - When the call stack is being unwound due to an exception being thrown, the exception is compared against the ``args``. If it doesn't match, then control is transfered to the ``exception`` basic block. +As with calling conventions, how the personality function results are +represented in LLVM IR is target specific. The ``catchpad`` instruction has several restrictions: @@ -5192,11 +5188,14 @@ catch block. - A basic block that is not a catch block may not include a '``catchpad``' instruction. +- A catch block which has another catch block as a predecessor may not have + any other predecessors. - It is undefined behavior for control to transfer from a ``catchpad`` to a - ``cleanupret`` without first executing a ``catchret`` and a subsequent - ``cleanuppad``. -- It is undefined behavior for control to transfer from a ``catchpad`` to a - ``ret`` without first executing a ``catchret``. + ``ret`` without first executing a ``catchret`` that consumes the + ``catchpad`` or unwinding through its ``catchendpad``. +- It is undefined behavior for control to transfer from a ``catchpad`` to + itself without first executing a ``catchret`` that consumes the + ``catchpad`` or unwinding through its ``catchendpad``. Example: """""""" @@ -5204,7 +5203,7 @@ .. code-block:: llvm ;; A catch block which can catch an integer. - %res = catchpad { i8*, i32 } [i8** @_ZTIi] + %tok = catchpad [i8** @_ZTIi] to label %int.handler unwind label %terminate .. _i_catchendpad: @@ -5264,7 +5263,8 @@ '``catchendpad``' instruction. - Exactly one catch block may unwind to a ``catchendpad``. - The unwind target of invokes between a ``catchpad`` and a - corresponding ``catchret`` must be its ``catchendpad``. + corresponding ``catchret`` must be its ``catchendpad`` or + an inner EH pad. Example: """""""" @@ -5284,7 +5284,7 @@ :: - catchret to label + catchret to label Overview: """"""""" @@ -5296,8 +5296,10 @@ Arguments: """""""""" -The '``catchret``' instruction requires one argument which specifies -where control will transfer to next. +The first argument to a '``catchret``' indicates which ``catchpad`` it +exits. It must be a :ref:`catchpad `. +The second argument to a '``catchret``' specifies where control will +transfer to next. Semantics: """""""""" @@ -5309,13 +5311,21 @@ arbitrary code to, for example, run a C++ destructor. Control then transfers to ``normal``. It may be passed an optional, personality specific, value. +It is undefined behavior to execute a ``catchret`` whose ``catchpad`` has +not been executed. +It is undefined behavior to execute a ``catchret`` if any ``catchpad`` or +``cleanuppad`` has been executed, without subsequently executing a +corresponding ``catchret``/``cleanupret`` or unwinding out of the inner +pad, following the most recent execution of the ``catchret``'s corresponding +``catchpad``. + Example: """""""" .. code-block:: llvm - catchret label %continue + catchret %catch label %continue .. _i_cleanupret: @@ -5327,8 +5337,8 @@ :: - cleanupret unwind label - cleanupret unwind to caller + cleanupret unwind label + cleanupret unwind to caller Overview: """"""""" @@ -5340,9 +5350,9 @@ Arguments: """""""""" -The '``cleanupret``' instruction requires one argument, which must have the -same type as the result of any '``cleanuppad``' instruction in the same -function. It also has an optional successor, ``continue``. +The '``cleanupret``' instruction requires one argument, which indicates +which ``cleanuppad`` it exits, and must be a :ref:`cleanuppad `. +It also has an optional successor, ``continue``. Semantics: """""""""" @@ -5351,14 +5361,21 @@ :ref:`personality function ` that one :ref:`cleanuppad ` it transferred control to has ended. It transfers control to ``continue`` or unwinds out of the function. +It is undefined behavior to execute a ``cleanupret`` whose ``cleanuppad`` has +not been executed. +It is undefined behavior to execute a ``cleanupret`` if any ``catchpad`` or +``cleanuppad`` has been executed, without subsequently executing a +corresponding ``catchret``/``cleanupret`` or unwinding out of the inner pad, +following the most recent execution of the ``cleanupret``'s corresponding +``cleanuppad``. Example: """""""" .. code-block:: llvm - cleanupret void unwind to caller - cleanupret { i8*, i32 } %exn unwind label %continue + cleanupret %cleanup unwind to caller + cleanupret %cleanup unwind label %continue .. _i_terminatepad: @@ -8391,7 +8408,7 @@ :: - = cleanuppad [*] + = cleanuppad [*] Overview: """"""""" @@ -8403,7 +8420,8 @@ The ``args`` correspond to whatever additional information the :ref:`personality function ` requires to execute the cleanup. -The ``resultval`` has the type ``resultty``. +The ``resultval`` has the type :ref:`token ` and is used to +match the ``cleanuppad`` to corresponding :ref:`cleanuprets `. Arguments: """""""""" @@ -8415,9 +8433,8 @@ """""""""" The '``cleanuppad``' instruction defines the values which are set by the -:ref:`personality function ` upon re-entry to the function, and -therefore the "result type" of the ``cleanuppad`` instruction. As with -calling conventions, how the personality function results are +:ref:`personality function ` upon re-entry to the function. +As with calling conventions, how the personality function results are represented in LLVM IR is target specific. When the call stack is being unwound due to an exception being thrown, @@ -8434,18 +8451,21 @@ cleanup block. - A basic block that is not a cleanup block may not include a '``cleanuppad``' instruction. +- All ``cleanupret``s which exit a cleanuppad must have the same + exceptional successor. - It is undefined behavior for control to transfer from a ``cleanuppad`` to a - ``catchret`` without first executing a ``cleanupret`` and a subsequent - ``catchpad``. -- It is undefined behavior for control to transfer from a ``cleanuppad`` to a - ``ret`` without first executing a ``cleanupret``. + ``ret`` without first executing a ``cleanupret`` that consumes the + ``cleanuppad`` or unwinding out of the ``cleanuppad``. +- It is undefined behavior for control to transfer from a ``cleanuppad`` to + itself without first executing a ``cleanupret`` that consumes the + ``cleanuppad`` or unwinding out of the ``cleanuppad``. Example: """""""" .. code-block:: llvm - %res = cleanuppad { i8*, i32 } [label %nextaction] + %tok = cleanuppad [] .. _intrinsics: Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -356,9 +356,9 @@ FUNC_CODE_INST_CMPXCHG = 46, // CMPXCHG: [ptrty,ptr,valty,cmp,new, align, // vol,ordering,synchscope] FUNC_CODE_INST_LANDINGPAD = 47, // LANDINGPAD: [ty,val,num,id0,val0...] - FUNC_CODE_INST_CLEANUPRET = 48, // CLEANUPRET: [] or [val] or [bb#] or [val,bb#] - FUNC_CODE_INST_CATCHRET = 49, // CATCHRET: [bb#] - FUNC_CODE_INST_CATCHPAD = 50, // CATCHPAD: [ty,val,val,num,args...] + FUNC_CODE_INST_CLEANUPRET = 48, // CLEANUPRET: [val] or [val,bb#] + FUNC_CODE_INST_CATCHRET = 49, // CATCHRET: [val,bb#] + FUNC_CODE_INST_CATCHPAD = 50, // CATCHPAD: [bb#,bb#,num,args...] FUNC_CODE_INST_TERMINATEPAD = 51, // TERMINATEPAD: [bb#,num,args...] FUNC_CODE_INST_CLEANUPPAD = 52, // CLEANUPPAD: [num,args...] FUNC_CODE_INST_CATCHENDPAD = 53, // CATCHENDPAD: [] or [bb#] Index: include/llvm/IR/IRBuilder.h =================================================================== --- include/llvm/IR/IRBuilder.h +++ include/llvm/IR/IRBuilder.h @@ -671,15 +671,14 @@ return Insert(ResumeInst::Create(Exn)); } - CleanupReturnInst *CreateCleanupRet(BasicBlock *UnwindBB = nullptr, - Value *RetVal = nullptr) { - return Insert(CleanupReturnInst::Create(Context, RetVal, UnwindBB)); + CleanupReturnInst *CreateCleanupRet(CleanupPadInst *CleanupPad, + BasicBlock *UnwindBB = nullptr) { + return Insert(CleanupReturnInst::Create(CleanupPad, UnwindBB)); } - CatchPadInst *CreateCatchPad(Type *Ty, BasicBlock *NormalDest, - BasicBlock *UnwindDest, ArrayRef Args, - const Twine &Name = "") { - return Insert(CatchPadInst::Create(Ty, NormalDest, UnwindDest, Args), Name); + CatchPadInst *CreateCatchPad(BasicBlock *NormalDest, BasicBlock *UnwindDest, + ArrayRef Args, const Twine &Name = "") { + return Insert(CatchPadInst::Create(NormalDest, UnwindDest, Args), Name); } CatchEndPadInst *CreateCatchEndPad(BasicBlock *UnwindBB = nullptr) { @@ -692,13 +691,13 @@ return Insert(TerminatePadInst::Create(Context, UnwindBB, Args), Name); } - CleanupPadInst *CreateCleanupPad(Type *Ty, ArrayRef Args, + CleanupPadInst *CreateCleanupPad(ArrayRef Args, const Twine &Name = "") { - return Insert(CleanupPadInst::Create(Ty, Args), Name); + return Insert(CleanupPadInst::Create(Context, Args), Name); } - CatchReturnInst *CreateCatchRet(BasicBlock *BB, Value *RetVal = nullptr) { - return Insert(CatchReturnInst::Create(BB, RetVal)); + CatchReturnInst *CreateCatchRet(CatchPadInst *CatchPad, BasicBlock *BB) { + return Insert(CatchReturnInst::Create(CatchPad, BB)); } UnreachableInst *CreateUnreachable() { Index: include/llvm/IR/Instructions.h =================================================================== --- include/llvm/IR/Instructions.h +++ include/llvm/IR/Instructions.h @@ -2740,7 +2740,7 @@ void setSuccessor(unsigned idx, BasicBlock *NewSucc) { assert(idx < getNumSuccessors() && "Successor # out of range for Branch!"); - *(&Op<-1>() - idx) = (Value*)NewSucc; + *(&Op<-1>() - idx) = NewSucc; } /// \brief Swap the successors of this branch instruction. @@ -3056,7 +3056,7 @@ } void setSuccessor(unsigned idx, BasicBlock *NewSucc) { assert(idx < getNumSuccessors() && "Successor # out of range for switch!"); - setOperand(idx*2+1, (Value*)NewSucc); + setOperand(idx * 2 + 1, NewSucc); } // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -3156,7 +3156,7 @@ return cast(getOperand(i+1)); } void setSuccessor(unsigned i, BasicBlock *NewSucc) { - setOperand(i+1, (Value*)NewSucc); + setOperand(i + 1, NewSucc); } // Methods for support type inquiry through isa, cast, and dyn_cast: @@ -3570,111 +3570,6 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ResumeInst, Value) //===----------------------------------------------------------------------===// -// CleanupReturnInst Class -//===----------------------------------------------------------------------===// - -class CleanupReturnInst : public TerminatorInst { - CleanupReturnInst(const CleanupReturnInst &RI); - -private: - void init(Value *RetVal, BasicBlock *UnwindBB); - CleanupReturnInst(LLVMContext &C, Value *RetVal, BasicBlock *UnwindBB, - unsigned Values, Instruction *InsertBefore = nullptr); - CleanupReturnInst(LLVMContext &C, Value *RetVal, BasicBlock *UnwindBB, - unsigned Values, BasicBlock *InsertAtEnd); - - int getUnwindLabelOpIdx() const { - assert(hasUnwindDest()); - return 0; - } - - int getRetValOpIdx() const { - assert(hasReturnValue()); - if (hasUnwindDest()) - return 1; - return 0; - } - -protected: - // Note: Instruction needs to be a friend here to call cloneImpl. - friend class Instruction; - CleanupReturnInst *cloneImpl() const; - -public: - static CleanupReturnInst *Create(LLVMContext &C, - Value *RetVal = nullptr, - BasicBlock *UnwindBB = nullptr, - Instruction *InsertBefore = nullptr) { - unsigned Values = 0; - if (RetVal) - ++Values; - if (UnwindBB) - ++Values; - return new (Values) - CleanupReturnInst(C, RetVal, UnwindBB, Values, InsertBefore); - } - static CleanupReturnInst *Create(LLVMContext &C, Value *RetVal, - BasicBlock *UnwindBB, - BasicBlock *InsertAtEnd) { - unsigned Values = 0; - if (RetVal) - ++Values; - if (UnwindBB) - ++Values; - return new (Values) - CleanupReturnInst(C, RetVal, UnwindBB, Values, InsertAtEnd); - } - - /// Provide fast operand accessors - DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); - - bool hasUnwindDest() const { return getSubclassDataFromInstruction() & 1; } - bool unwindsToCaller() const { return !hasUnwindDest(); } - bool hasReturnValue() const { return getSubclassDataFromInstruction() & 2; } - - /// Convenience accessor. Returns null if there is no return value. - Value *getReturnValue() const { - if (!hasReturnValue()) - return nullptr; - return getOperand(getRetValOpIdx()); - } - void setReturnValue(Value *RetVal) { - assert(hasReturnValue()); - setOperand(getRetValOpIdx(), RetVal); - } - - unsigned getNumSuccessors() const { return hasUnwindDest() ? 1 : 0; } - - BasicBlock *getUnwindDest() const; - void setUnwindDest(BasicBlock *NewDest); - - // Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const Instruction *I) { - return (I->getOpcode() == Instruction::CleanupRet); - } - static inline bool classof(const Value *V) { - return isa(V) && classof(cast(V)); - } - -private: - BasicBlock *getSuccessorV(unsigned Idx) const override; - unsigned getNumSuccessorsV() const override; - void setSuccessorV(unsigned Idx, BasicBlock *B) override; - - // Shadow Instruction::setInstructionSubclassData with a private forwarding - // method so that subclasses cannot accidentally use it. - void setInstructionSubclassData(unsigned short D) { - Instruction::setInstructionSubclassData(D); - } -}; - -template <> -struct OperandTraits - : public VariadicOperandTraits {}; - -DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CleanupReturnInst, Value) - -//===----------------------------------------------------------------------===// // CatchEndPadInst Class //===----------------------------------------------------------------------===// @@ -3760,14 +3655,12 @@ CatchPadInst(const CatchPadInst &CPI); - explicit CatchPadInst(Type *RetTy, BasicBlock *IfNormal, - BasicBlock *IfException, ArrayRef Args, - unsigned Values, const Twine &NameStr, - Instruction *InsertBefore); - explicit CatchPadInst(Type *RetTy, BasicBlock *IfNormal, - BasicBlock *IfException, ArrayRef Args, - unsigned Values, const Twine &NameStr, - BasicBlock *InsertAtEnd); + explicit CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException, + ArrayRef Args, unsigned Values, + const Twine &NameStr, Instruction *InsertBefore); + explicit CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException, + ArrayRef Args, unsigned Values, + const Twine &NameStr, BasicBlock *InsertAtEnd); protected: // Note: Instruction needs to be a friend here to call cloneImpl. @@ -3775,20 +3668,19 @@ CatchPadInst *cloneImpl() const; public: - static CatchPadInst *Create(Type *RetTy, BasicBlock *IfNormal, - BasicBlock *IfException, ArrayRef Args, - const Twine &NameStr = "", + static CatchPadInst *Create(BasicBlock *IfNormal, BasicBlock *IfException, + ArrayRef Args, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { unsigned Values = unsigned(Args.size()) + 2; - return new (Values) CatchPadInst(RetTy, IfNormal, IfException, Args, Values, + return new (Values) CatchPadInst(IfNormal, IfException, Args, Values, NameStr, InsertBefore); } - static CatchPadInst *Create(Type *RetTy, BasicBlock *IfNormal, - BasicBlock *IfException, ArrayRef Args, - const Twine &NameStr, BasicBlock *InsertAtEnd) { + static CatchPadInst *Create(BasicBlock *IfNormal, BasicBlock *IfException, + ArrayRef Args, const Twine &NameStr, + BasicBlock *InsertAtEnd) { unsigned Values = unsigned(Args.size()) + 2; - return new (Values) CatchPadInst(RetTy, IfNormal, IfException, Args, Values, - NameStr, InsertAtEnd); + return new (Values) + CatchPadInst(IfNormal, IfException, Args, Values, NameStr, InsertAtEnd); } /// Provide fast operand accessors @@ -3820,8 +3712,8 @@ // get*Dest - Return the destination basic blocks... BasicBlock *getNormalDest() const { return cast(Op<-2>()); } BasicBlock *getUnwindDest() const { return cast(Op<-1>()); } - void setNormalDest(BasicBlock *B) { Op<-2>() = reinterpret_cast(B); } - void setUnwindDest(BasicBlock *B) { Op<-1>() = reinterpret_cast(B); } + void setNormalDest(BasicBlock *B) { Op<-2>() = B; } + void setUnwindDest(BasicBlock *B) { Op<-1>() = B; } BasicBlock *getSuccessor(unsigned i) const { assert(i < 2 && "Successor # out of range for catchpad!"); @@ -3830,7 +3722,7 @@ void setSuccessor(unsigned idx, BasicBlock *NewSucc) { assert(idx < 2 && "Successor # out of range for catchpad!"); - *(&Op<-2>() + idx) = reinterpret_cast(NewSucc); + *(&Op<-2>() + idx) = NewSucc; } unsigned getNumSuccessors() const { return 2; } @@ -3949,7 +3841,7 @@ } void setUnwindDest(BasicBlock *B) { assert(B && hasUnwindDest()); - Op<-1>() = reinterpret_cast(B); + Op<-1>() = B; } unsigned getNumSuccessors() const { return hasUnwindDest() ? 1 : 0; } @@ -3990,9 +3882,9 @@ CleanupPadInst(const CleanupPadInst &CPI); - explicit CleanupPadInst(Type *RetTy, ArrayRef Args, + explicit CleanupPadInst(LLVMContext &C, ArrayRef Args, const Twine &NameStr, Instruction *InsertBefore); - explicit CleanupPadInst(Type *RetTy, ArrayRef Args, + explicit CleanupPadInst(LLVMContext &C, ArrayRef Args, const Twine &NameStr, BasicBlock *InsertAtEnd); protected: @@ -4001,14 +3893,14 @@ CleanupPadInst *cloneImpl() const; public: - static CleanupPadInst *Create(Type *RetTy, ArrayRef Args, + static CleanupPadInst *Create(LLVMContext &C, ArrayRef Args, const Twine &NameStr = "", Instruction *InsertBefore = nullptr) { - return new (Args.size()) CleanupPadInst(RetTy, Args, NameStr, InsertBefore); + return new (Args.size()) CleanupPadInst(C, Args, NameStr, InsertBefore); } - static CleanupPadInst *Create(Type *RetTy, ArrayRef Args, + static CleanupPadInst *Create(LLVMContext &C, ArrayRef Args, const Twine &NameStr, BasicBlock *InsertAtEnd) { - return new (Args.size()) CleanupPadInst(RetTy, Args, NameStr, InsertAtEnd); + return new (Args.size()) CleanupPadInst(C, Args, NameStr, InsertAtEnd); } /// Provide fast operand accessors @@ -4037,10 +3929,10 @@ CatchReturnInst(const CatchReturnInst &RI); private: - void init(BasicBlock *BB, Value *RetVal); - CatchReturnInst(BasicBlock *BB, Value *RetVal, unsigned Values, + void init(CatchPadInst *CatchPad, BasicBlock *BB); + CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB, Instruction *InsertBefore = nullptr); - CatchReturnInst(BasicBlock *BB, Value *RetVal, unsigned Values, + CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB, BasicBlock *InsertAtEnd); protected: @@ -4049,34 +3941,35 @@ CatchReturnInst *cloneImpl() const; public: - static CatchReturnInst *Create(BasicBlock *BB, Value *RetVal = nullptr, + static CatchReturnInst *Create(CatchPadInst *CatchPad, BasicBlock *BB, Instruction *InsertBefore = nullptr) { + assert(CatchPad); assert(BB); - unsigned Values = 1; - if (RetVal) - ++Values; - return new (Values) CatchReturnInst(BB, RetVal, Values, InsertBefore); + return new (2) CatchReturnInst(CatchPad, BB, InsertBefore); } - static CatchReturnInst *Create(BasicBlock *BB, Value *RetVal, + static CatchReturnInst *Create(CatchPadInst *CatchPad, BasicBlock *BB, BasicBlock *InsertAtEnd) { + assert(CatchPad); assert(BB); - unsigned Values = 1; - if (RetVal) - ++Values; - return new (Values) CatchReturnInst(BB, RetVal, Values, InsertAtEnd); + return new (2) CatchReturnInst(CatchPad, BB, InsertAtEnd); } /// Provide fast operand accessors DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); /// Convenience accessors. - BasicBlock *getSuccessor() const { return cast(Op<-1>()); } - void setSuccessor(BasicBlock *NewSucc) { Op<-1>() = (Value *)NewSucc; } - unsigned getNumSuccessors() const { return 1; } + CatchPadInst *getCatchPad() const { return cast(Op<0>()); } + void setCatchPad(CatchPadInst *CatchPad) { + assert(CatchPad); + Op<0>() = CatchPad; + } - bool hasReturnValue() const { return getNumOperands() > 1; } - Value *getReturnValue() const { return Op<-2>(); } - void setReturnValue(Value *RetVal) { Op<-2>() = RetVal; } + BasicBlock *getSuccessor() const { return cast(Op<1>()); } + void setSuccessor(BasicBlock *NewSucc) { + assert(NewSucc); + Op<1>() = NewSucc; + } + unsigned getNumSuccessors() const { return 1; } // Methods for support type inquiry through isa, cast, and dyn_cast: static inline bool classof(const Instruction *I) { @@ -4094,11 +3987,109 @@ template <> struct OperandTraits - : public VariadicOperandTraits {}; + : public FixedNumOperandTraits {}; DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CatchReturnInst, Value) //===----------------------------------------------------------------------===// +// CleanupReturnInst Class +//===----------------------------------------------------------------------===// + +class CleanupReturnInst : public TerminatorInst { + CleanupReturnInst(const CleanupReturnInst &RI); + +private: + void init(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB); + CleanupReturnInst(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB, + unsigned Values, Instruction *InsertBefore = nullptr); + CleanupReturnInst(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB, + unsigned Values, BasicBlock *InsertAtEnd); + + int getUnwindLabelOpIdx() const { + assert(hasUnwindDest()); + return 0; + } + +protected: + // Note: Instruction needs to be a friend here to call cloneImpl. + friend class Instruction; + CleanupReturnInst *cloneImpl() const; + +public: + static CleanupReturnInst *Create(CleanupPadInst *CleanupPad, + BasicBlock *UnwindBB = nullptr, + Instruction *InsertBefore = nullptr) { + assert(CleanupPad); + unsigned Values = 1; + if (UnwindBB) + ++Values; + return new (Values) + CleanupReturnInst(CleanupPad, UnwindBB, Values, InsertBefore); + } + static CleanupReturnInst *Create(CleanupPadInst *CleanupPad, + BasicBlock *UnwindBB, + BasicBlock *InsertAtEnd) { + assert(CleanupPad); + unsigned Values = 1; + if (UnwindBB) + ++Values; + return new (Values) + CleanupReturnInst(CleanupPad, UnwindBB, Values, InsertAtEnd); + } + + /// Provide fast operand accessors + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); + + bool hasUnwindDest() const { return getSubclassDataFromInstruction() & 1; } + bool unwindsToCaller() const { return !hasUnwindDest(); } + + /// Convenience accessor. + CleanupPadInst *getCleanupPad() const { + return cast(Op<-1>()); + } + void setCleanupPad(CleanupPadInst *CleanupPad) { + assert(CleanupPad); + Op<-1>() = CleanupPad; + } + + unsigned getNumSuccessors() const { return hasUnwindDest() ? 1 : 0; } + + BasicBlock *getUnwindDest() const { + return hasUnwindDest() ? cast(Op<-2>()) : nullptr; + } + void setUnwindDest(BasicBlock *NewDest) { + assert(NewDest); + assert(hasUnwindDest()); + Op<-2>() = NewDest; + } + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const Instruction *I) { + return (I->getOpcode() == Instruction::CleanupRet); + } + static inline bool classof(const Value *V) { + return isa(V) && classof(cast(V)); + } + +private: + BasicBlock *getSuccessorV(unsigned Idx) const override; + unsigned getNumSuccessorsV() const override; + void setSuccessorV(unsigned Idx, BasicBlock *B) override; + + // Shadow Instruction::setInstructionSubclassData with a private forwarding + // method so that subclasses cannot accidentally use it. + void setInstructionSubclassData(unsigned short D) { + Instruction::setInstructionSubclassData(D); + } +}; + +template <> +struct OperandTraits + : public VariadicOperandTraits {}; + +DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CleanupReturnInst, Value) + +//===----------------------------------------------------------------------===// // UnreachableInst Class //===----------------------------------------------------------------------===// Index: lib/Analysis/InlineCost.cpp =================================================================== --- lib/Analysis/InlineCost.cpp +++ lib/Analysis/InlineCost.cpp @@ -913,7 +913,7 @@ bool CallAnalyzer::visitCatchReturnInst(CatchReturnInst &CRI) { // FIXME: It's not clear that a single instruction is an accurate model for - // the inline cost of a cleanupret instruction. + // the inline cost of a catchret instruction. return false; } Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -108,6 +108,14 @@ unsigned MDKind, MDSlot; }; + /// Indicates which operator an operand allows (for the few operands that + /// may only reference a certain operator). + enum OperatorConstraint { + OC_None = 0, // No constraint + OC_CatchPad, // Must be CatchPadInst + OC_CleanupPad // Must be CleanupPadInst + }; + SmallVector InstsWithTBAATag; // Type resolution handling data structures. The location is set when we @@ -325,8 +333,10 @@ /// GetVal - Get a value with the specified name or ID, creating a /// forward reference record if needed. This can return null if the value /// exists but does not have the right type. - Value *GetVal(const std::string &Name, Type *Ty, LocTy Loc); - Value *GetVal(unsigned ID, Type *Ty, LocTy Loc); + Value *GetVal(const std::string &Name, Type *Ty, LocTy Loc, + OperatorConstraint OC = OC_None); + Value *GetVal(unsigned ID, Type *Ty, LocTy Loc, + OperatorConstraint OC = OC_None); /// SetInstName - After an instruction is parsed and inserted into its /// basic block, this installs its name. @@ -348,12 +358,15 @@ }; bool ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, - PerFunctionState *PFS); + PerFunctionState *PFS, + OperatorConstraint OC = OC_None); bool parseConstantValue(Type *Ty, Constant *&C); - bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS); - bool ParseValue(Type *Ty, Value *&V, PerFunctionState &PFS) { - return ParseValue(Ty, V, &PFS); + bool ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS, + OperatorConstraint OC = OC_None); + bool ParseValue(Type *Ty, Value *&V, PerFunctionState &PFS, + OperatorConstraint OC = OC_None) { + return ParseValue(Ty, V, &PFS, OC); } bool ParseValue(Type *Ty, Value *&V, LocTy &Loc, PerFunctionState &PFS) { Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -2218,8 +2218,8 @@ /// GetVal - Get a value with the specified name or ID, creating a /// forward reference record if needed. This can return null if the value /// exists but does not have the right type. -Value *LLParser::PerFunctionState::GetVal(const std::string &Name, - Type *Ty, LocTy Loc) { +Value *LLParser::PerFunctionState::GetVal(const std::string &Name, Type *Ty, + LocTy Loc, OperatorConstraint OC) { // Look this name up in the normal function symbol table. Value *Val = F.getValueSymbolTable().lookup(Name); @@ -2234,6 +2234,24 @@ // If we have the value in the symbol table or fwd-ref table, return it. if (Val) { + // Check operator constraints. + switch (OC) { + case OC_None: + // no constraint + break; + case OC_CatchPad: + if (!isa(Val)) { + P.Error(Loc, "'%" + Name + "' is not a catchpad"); + return nullptr; + } + break; + case OC_CleanupPad: + if (!isa(Val)) { + P.Error(Loc, "'%" + Name + "' is not a cleanuppad"); + return nullptr; + } + break; + } if (Val->getType() == Ty) return Val; if (Ty->isLabelTy()) P.Error(Loc, "'%" + Name + "' is not a basic block"); @@ -2251,17 +2269,31 @@ // Otherwise, create a new forward reference for this value and remember it. Value *FwdVal; - if (Ty->isLabelTy()) + if (Ty->isLabelTy()) { + assert(!OC); FwdVal = BasicBlock::Create(F.getContext(), Name, &F); - else + } else if (!OC) { FwdVal = new Argument(Ty, Name); + } else { + switch (OC) { + case OC_CatchPad: + FwdVal = CatchPadInst::Create(&F.getEntryBlock(), &F.getEntryBlock(), {}, + Name); + break; + case OC_CleanupPad: + FwdVal = CleanupPadInst::Create(F.getContext(), {}, Name); + break; + default: + llvm_unreachable("unexpected constraint"); + } + } ForwardRefVals[Name] = std::make_pair(FwdVal, Loc); return FwdVal; } -Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, - LocTy Loc) { +Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty, LocTy Loc, + OperatorConstraint OC) { // Look this name up in the normal function symbol table. Value *Val = ID < NumberedVals.size() ? NumberedVals[ID] : nullptr; @@ -2276,6 +2308,24 @@ // If we have the value in the symbol table or fwd-ref table, return it. if (Val) { + // Check operator constraint. + switch (OC) { + case OC_None: + // no constraint + break; + case OC_CatchPad: + if (!isa(Val)) { + P.Error(Loc, "'%" + Twine(ID) + "' is not a catchpad"); + return nullptr; + } + break; + case OC_CleanupPad: + if (!isa(Val)) { + P.Error(Loc, "'%" + Twine(ID) + "' is not a cleanuppad"); + return nullptr; + } + break; + } if (Val->getType() == Ty) return Val; if (Ty->isLabelTy()) P.Error(Loc, "'%" + Twine(ID) + "' is not a basic block"); @@ -2292,10 +2342,23 @@ // Otherwise, create a new forward reference for this value and remember it. Value *FwdVal; - if (Ty->isLabelTy()) + if (Ty->isLabelTy()) { + assert(!OC); FwdVal = BasicBlock::Create(F.getContext(), "", &F); - else + } else if (!OC) { FwdVal = new Argument(Ty); + } else { + switch (OC) { + case OC_CatchPad: + FwdVal = CatchPadInst::Create(&F.getEntryBlock(), &F.getEntryBlock(), {}); + break; + case OC_CleanupPad: + FwdVal = CleanupPadInst::Create(F.getContext(), {}); + break; + default: + llvm_unreachable("unexpected constraint"); + } + } ForwardRefValIDs[ID] = std::make_pair(FwdVal, Loc); return FwdVal; @@ -2327,11 +2390,24 @@ std::map >::iterator FI = ForwardRefValIDs.find(NameID); if (FI != ForwardRefValIDs.end()) { - if (FI->second.first->getType() != Inst->getType()) + Value *Sentinel = FI->second.first; + if (Sentinel->getType() != Inst->getType()) return P.Error(NameLoc, "instruction forward referenced with type '" + getTypeString(FI->second.first->getType()) + "'"); - FI->second.first->replaceAllUsesWith(Inst); - delete FI->second.first; + // Check operator constraints. We only put cleanuppads or catchpads in + // the forward value map if the value is constrained to match. + if (isa(Sentinel)) { + if (!isa(Inst)) + return P.Error(FI->second.second, + "'%" + Twine(NameID) + "' is not a catchpad"); + } else if (isa(Sentinel)) { + if (!isa(Inst)) + return P.Error(FI->second.second, + "'%" + Twine(NameID) + "' is not a cleanuppad"); + } + + Sentinel->replaceAllUsesWith(Inst); + delete Sentinel; ForwardRefValIDs.erase(FI); } @@ -2343,11 +2419,24 @@ std::map >::iterator FI = ForwardRefVals.find(NameStr); if (FI != ForwardRefVals.end()) { - if (FI->second.first->getType() != Inst->getType()) + Value *Sentinel = FI->second.first; + if (Sentinel->getType() != Inst->getType()) return P.Error(NameLoc, "instruction forward referenced with type '" + getTypeString(FI->second.first->getType()) + "'"); - FI->second.first->replaceAllUsesWith(Inst); - delete FI->second.first; + // Check operator constraints. We only put cleanuppads or catchpads in + // the forward value map if the value is constrained to match. + if (isa(Sentinel)) { + if (!isa(Inst)) + return P.Error(FI->second.second, + "'%" + NameStr + "' is not a catchpad"); + } else if (isa(Sentinel)) { + if (!isa(Inst)) + return P.Error(FI->second.second, + "'%" + NameStr + "' is not a cleanuppad"); + } + + Sentinel->replaceAllUsesWith(Inst); + delete Sentinel; ForwardRefVals.erase(FI); } @@ -3988,18 +4077,30 @@ //===----------------------------------------------------------------------===// bool LLParser::ConvertValIDToValue(Type *Ty, ValID &ID, Value *&V, - PerFunctionState *PFS) { + PerFunctionState *PFS, + OperatorConstraint OC) { if (Ty->isFunctionTy()) return Error(ID.Loc, "functions are not values, refer to them as pointers"); + if (OC && ID.Kind != ValID::t_LocalID && ID.Kind != ValID::t_LocalName) { + switch (OC) { + case OC_CatchPad: + return Error(ID.Loc, "Catchpad value required in this position"); + case OC_CleanupPad: + return Error(ID.Loc, "Cleanuppad value required in this position"); + default: + llvm_unreachable("Unexpected constraint kind"); + } + } + switch (ID.Kind) { case ValID::t_LocalID: if (!PFS) return Error(ID.Loc, "invalid use of function-local name"); - V = PFS->GetVal(ID.UIntVal, Ty, ID.Loc); + V = PFS->GetVal(ID.UIntVal, Ty, ID.Loc, OC); return V == nullptr; case ValID::t_LocalName: if (!PFS) return Error(ID.Loc, "invalid use of function-local name"); - V = PFS->GetVal(ID.StrVal, Ty, ID.Loc); + V = PFS->GetVal(ID.StrVal, Ty, ID.Loc, OC); return V == nullptr; case ValID::t_InlineAsm: { assert(ID.FTy); @@ -4121,11 +4222,11 @@ } } -bool LLParser::ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS) { +bool LLParser::ParseValue(Type *Ty, Value *&V, PerFunctionState *PFS, + OperatorConstraint OC) { V = nullptr; ValID ID; - return ParseValID(ID, PFS) || - ConvertValIDToValue(Ty, ID, V, PFS); + return ParseValID(ID, PFS) || ConvertValIDToValue(Ty, ID, V, PFS, OC); } bool LLParser::ParseTypeAndValue(Value *&V, PerFunctionState *PFS) { @@ -4966,7 +5067,7 @@ bool LLParser::ParseExceptionArgs(SmallVectorImpl &Args, PerFunctionState &PFS) { - if (ParseToken(lltok::lsquare, "expected '[' in cleanuppad")) + if (ParseToken(lltok::lsquare, "expected '[' in catchpad/cleanuppad")) return true; while (Lex.getKind() != lltok::rsquare) { @@ -4997,16 +5098,12 @@ } /// ParseCleanupRet -/// ::= 'cleanupret' ('void' | TypeAndValue) unwind ('to' 'caller' | TypeAndValue) +/// ::= 'cleanupret' Value unwind ('to' 'caller' | TypeAndValue) bool LLParser::ParseCleanupRet(Instruction *&Inst, PerFunctionState &PFS) { - Type *RetTy = nullptr; - Value *RetVal = nullptr; - if (ParseType(RetTy, /*AllowVoid=*/true)) - return true; + Value *CleanupPad = nullptr; - if (!RetTy->isVoidTy()) - if (ParseValue(RetTy, RetVal, PFS)) - return true; + if (ParseValue(Type::getTokenTy(Context), CleanupPad, PFS, OC_CleanupPad)) + return true; if (ParseToken(lltok::kw_unwind, "expected 'unwind' in cleanupret")) return true; @@ -5022,39 +5119,32 @@ } } - Inst = CleanupReturnInst::Create(Context, RetVal, UnwindBB); + Inst = CleanupReturnInst::Create(cast(CleanupPad), UnwindBB); return false; } /// ParseCatchRet -/// ::= 'catchret' ('void' | TypeAndValue) 'to' TypeAndValue +/// ::= 'catchret' Value 'to' TypeAndValue bool LLParser::ParseCatchRet(Instruction *&Inst, PerFunctionState &PFS) { - Type *RetTy = nullptr; - Value *RetVal = nullptr; + Value *CatchPad = nullptr; - if (ParseType(RetTy, /*AllowVoid=*/true)) + if (ParseValue(Type::getTokenTy(Context), CatchPad, PFS, OC_CatchPad)) return true; - if (!RetTy->isVoidTy()) - if (ParseValue(RetTy, RetVal, PFS)) - return true; - BasicBlock *BB; if (ParseToken(lltok::kw_to, "expected 'to' in catchret") || ParseTypeAndBasicBlock(BB, PFS)) return true; - Inst = CatchReturnInst::Create(BB, RetVal); + Inst = CatchReturnInst::Create(cast(CatchPad), BB); return false; } /// ParseCatchPad -/// ::= 'catchpad' Type ParamList 'to' TypeAndValue 'unwind' TypeAndValue +/// ::= 'catchpad' ParamList 'to' TypeAndValue 'unwind' TypeAndValue bool LLParser::ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS) { - Type *RetType = nullptr; - SmallVector Args; - if (ParseType(RetType, /*AllowVoid=*/true) || ParseExceptionArgs(Args, PFS)) + if (ParseExceptionArgs(Args, PFS)) return true; BasicBlock *NormalBB, *UnwindBB; @@ -5064,7 +5154,7 @@ ParseTypeAndBasicBlock(UnwindBB, PFS)) return true; - Inst = CatchPadInst::Create(RetType, NormalBB, UnwindBB, Args); + Inst = CatchPadInst::Create(NormalBB, UnwindBB, Args); return false; } @@ -5096,13 +5186,11 @@ /// ParseCleanupPad /// ::= 'cleanuppad' ParamList bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) { - Type *RetType = nullptr; - SmallVector Args; - if (ParseType(RetType, /*AllowVoid=*/true) || ParseExceptionArgs(Args, PFS)) + if (ParseExceptionArgs(Args, PFS)) return true; - Inst = CleanupPadInst::Create(RetType, Args); + Inst = CleanupPadInst::Create(Context, Args); return false; } Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -41,6 +41,14 @@ SWITCH_INST_MAGIC = 0x4B5 // May 2012 => 1205 => Hex }; +/// Indicates which operator an operand allows (for the few operands that may +/// only reference a certain operator). +enum OperatorConstraint { + OC_None = 0, // No constraint + OC_CatchPad, // Must be CatchPadInst + OC_CleanupPad // Must be CleanupPadInst +}; + class BitcodeReaderValueList { std::vector ValuePtrs; @@ -84,9 +92,10 @@ } Constant *getConstantFwdRef(unsigned Idx, Type *Ty); - Value *getValueFwdRef(unsigned Idx, Type *Ty); + Value *getValueFwdRef(unsigned Idx, Type *Ty, + OperatorConstraint OC = OC_None); - void assignValue(Value *V, unsigned Idx); + bool assignValue(Value *V, unsigned Idx); /// Once all constants are read, this method bulk resolves any forward /// references. @@ -262,10 +271,11 @@ StructType *createIdentifiedStructType(LLVMContext &Context); Type *getTypeByID(unsigned ID); - Value *getFnValueByID(unsigned ID, Type *Ty) { + Value *getFnValueByID(unsigned ID, Type *Ty, + OperatorConstraint OC = OC_None) { if (Ty && Ty->isMetadataTy()) return MetadataAsValue::get(Ty->getContext(), getFnMetadataByID(ID)); - return ValueList.getValueFwdRef(ID, Ty); + return ValueList.getValueFwdRef(ID, Ty, OC); } Metadata *getFnMetadataByID(unsigned ID) { return MDValueList.getValueFwdRef(ID); @@ -308,8 +318,9 @@ /// past the number of slots used by the value in the record. Return true if /// there is an error. bool popValue(SmallVectorImpl &Record, unsigned &Slot, - unsigned InstNum, Type *Ty, Value *&ResVal) { - if (getValue(Record, Slot, InstNum, Ty, ResVal)) + unsigned InstNum, Type *Ty, Value *&ResVal, + OperatorConstraint OC = OC_None) { + if (getValue(Record, Slot, InstNum, Ty, ResVal, OC)) return true; // All values currently take a single record slot. ++Slot; @@ -318,32 +329,34 @@ /// Like popValue, but does not increment the Slot number. bool getValue(SmallVectorImpl &Record, unsigned Slot, - unsigned InstNum, Type *Ty, Value *&ResVal) { - ResVal = getValue(Record, Slot, InstNum, Ty); + unsigned InstNum, Type *Ty, Value *&ResVal, + OperatorConstraint OC = OC_None) { + ResVal = getValue(Record, Slot, InstNum, Ty, OC); return ResVal == nullptr; } /// Version of getValue that returns ResVal directly, or 0 if there is an /// error. Value *getValue(SmallVectorImpl &Record, unsigned Slot, - unsigned InstNum, Type *Ty) { + unsigned InstNum, Type *Ty, OperatorConstraint OC = OC_None) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)Record[Slot]; // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; - return getFnValueByID(ValNo, Ty); + return getFnValueByID(ValNo, Ty, OC); } /// Like getValue, but decodes signed VBRs. Value *getValueSigned(SmallVectorImpl &Record, unsigned Slot, - unsigned InstNum, Type *Ty) { + unsigned InstNum, Type *Ty, + OperatorConstraint OC = OC_None) { if (Slot == Record.size()) return nullptr; unsigned ValNo = (unsigned)decodeSignRotatedValue(Record[Slot]); // Adjust the ValNo, if it was encoded relative to the InstNum. if (UseRelativeIDs) ValNo = InstNum - ValNo; - return getFnValueByID(ValNo, Ty); + return getFnValueByID(ValNo, Ty, OC); } /// Converts alignment exponent (i.e. power of two (or zero)) to the @@ -753,10 +766,10 @@ DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPlaceHolder, Value) } -void BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) { +bool BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) { if (Idx == size()) { push_back(V); - return; + return false; } if (Idx >= size()) @@ -765,7 +778,7 @@ WeakVH &OldV = ValuePtrs[Idx]; if (!OldV) { OldV = V; - return; + return false; } // Handle constants and non-constants (e.g. instrs) differently for @@ -776,9 +789,26 @@ } else { // If there was a forward reference to this value, replace it. Value *PrevVal = OldV; + // Check operator constraints. We only put cleanuppads or catchpads in + // the forward value map if the value is constrained to match. + if (CatchPadInst *CatchPad = dyn_cast(PrevVal)) { + if (!isa(V)) + return true; + // Delete the dummy basic block that was created with the sentinel + // catchpad. + BasicBlock *DummyBlock = CatchPad->getUnwindDest(); + assert(DummyBlock == CatchPad->getNormalDest()); + CatchPad->dropAllReferences(); + delete DummyBlock; + } else if (isa(PrevVal)) { + if (!isa(V)) + return true; + } OldV->replaceAllUsesWith(V); delete PrevVal; } + + return false; } @@ -799,7 +829,8 @@ return C; } -Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty) { +Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty, + OperatorConstraint OC) { // Bail out for a clearly invalid value. This would make us call resize(0) if (Idx == UINT_MAX) return nullptr; @@ -811,14 +842,39 @@ // If the types don't match, it's invalid. if (Ty && Ty != V->getType()) return nullptr; - return V; + if (!OC) + return V; + // Use dyn_cast to enforce operator constraints + switch (OC) { + case OC_CatchPad: + return dyn_cast(V); + case OC_CleanupPad: + return dyn_cast(V); + default: + llvm_unreachable("Unexpected operator constraint"); + } } // No type specified, must be invalid reference. if (!Ty) return nullptr; // Create and return a placeholder, which will later be RAUW'd. - Value *V = new Argument(Ty); + Value *V; + switch (OC) { + case OC_None: + V = new Argument(Ty); + break; + case OC_CatchPad: { + BasicBlock *BB = BasicBlock::Create(Context); + V = CatchPadInst::Create(BB, BB, {}); + break; + } + default: + assert(OC == OC_CleanupPad && "unexpected operator constraint"); + V = CleanupPadInst::Create(Context, {}); + break; + } + ValuePtrs[Idx] = V; return V; } @@ -2610,7 +2666,8 @@ } } - ValueList.assignValue(V, NextCstNo); + if (ValueList.assignValue(V, NextCstNo)) + return error("Invalid forward reference"); ++NextCstNo; } } @@ -3819,56 +3876,47 @@ } break; } - // CLEANUPRET: [] or [ty,val] or [bb#] or [ty,val,bb#] + // CLEANUPRET: [val] or [val,bb#] case bitc::FUNC_CODE_INST_CLEANUPRET: { - if (Record.size() < 2) + if (Record.size() != 1 && Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; - bool HasReturnValue = !!Record[Idx++]; - bool HasUnwindDest = !!Record[Idx++]; - Value *RetVal = nullptr; - BasicBlock *UnwindDest = nullptr; - - if (HasReturnValue && getValueTypePair(Record, Idx, NextValueNo, RetVal)) + Value *CleanupPad = getValue(Record, Idx++, NextValueNo, + Type::getTokenTy(Context), OC_CleanupPad); + if (!CleanupPad) return error("Invalid record"); - if (HasUnwindDest) { - if (Idx == Record.size()) - return error("Invalid record"); + BasicBlock *UnwindDest = nullptr; + if (Record.size() == 2) { UnwindDest = getBasicBlock(Record[Idx++]); if (!UnwindDest) return error("Invalid record"); } - if (Record.size() != Idx) - return error("Invalid record"); - - I = CleanupReturnInst::Create(Context, RetVal, UnwindDest); + I = CleanupReturnInst::Create(cast(CleanupPad), + UnwindDest); InstructionList.push_back(I); break; } - case bitc::FUNC_CODE_INST_CATCHRET: { // CATCHRET: [bb#] - if (Record.size() != 1 && Record.size() != 3) + case bitc::FUNC_CODE_INST_CATCHRET: { // CATCHRET: [val,bb#] + if (Record.size() != 2) return error("Invalid record"); unsigned Idx = 0; + Value *CatchPad = getValue(Record, Idx++, NextValueNo, + Type::getTokenTy(Context), OC_CatchPad); + if (!CatchPad) + return error("Invalid record"); BasicBlock *BB = getBasicBlock(Record[Idx++]); if (!BB) return error("Invalid record"); - Value *RetVal = nullptr; - if (Record.size() == 3 && - getValueTypePair(Record, Idx, NextValueNo, RetVal)) - return error("Invalid record"); - I = CatchReturnInst::Create(BB, RetVal); + I = CatchReturnInst::Create(cast(CatchPad), BB); InstructionList.push_back(I); break; } - case bitc::FUNC_CODE_INST_CATCHPAD: { // CATCHPAD: [ty,bb#,bb#,num,(ty,val)*] - if (Record.size() < 4) + case bitc::FUNC_CODE_INST_CATCHPAD: { // CATCHPAD: [bb#,bb#,num,(ty,val)*] + if (Record.size() < 3) return error("Invalid record"); unsigned Idx = 0; - Type *Ty = getTypeByID(Record[Idx++]); - if (!Ty) - return error("Invalid record"); BasicBlock *NormalBB = getBasicBlock(Record[Idx++]); if (!NormalBB) return error("Invalid record"); @@ -3886,7 +3934,7 @@ if (Record.size() != Idx) return error("Invalid record"); - I = CatchPadInst::Create(Ty, NormalBB, UnwindBB, Args); + I = CatchPadInst::Create(NormalBB, UnwindBB, Args); InstructionList.push_back(I); break; } @@ -3918,13 +3966,10 @@ InstructionList.push_back(I); break; } - case bitc::FUNC_CODE_INST_CLEANUPPAD: { // CLEANUPPAD: [ty, num,(ty,val)*] - if (Record.size() < 2) + case bitc::FUNC_CODE_INST_CLEANUPPAD: { // CLEANUPPAD: [num,(ty,val)*] + if (Record.size() < 1) return error("Invalid record"); unsigned Idx = 0; - Type *Ty = getTypeByID(Record[Idx++]); - if (!Ty) - return error("Invalid record"); unsigned NumArgOperands = Record[Idx++]; SmallVector Args; for (unsigned Op = 0; Op != NumArgOperands; ++Op) { @@ -3936,7 +3981,7 @@ if (Record.size() != Idx) return error("Invalid record"); - I = CleanupPadInst::Create(Ty, Args); + I = CleanupPadInst::Create(Context, Args); InstructionList.push_back(I); break; } @@ -4541,7 +4586,8 @@ // Non-void values get registered in the value table for future use. if (I && !I->getType()->isVoidTy()) - ValueList.assignValue(I, NextValueNo++); + if (ValueList.assignValue(I, NextValueNo++)) + return error("Invalid forward reference"); } OutOfRecordLoop: Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -1855,10 +1855,7 @@ case Instruction::CleanupRet: { Code = bitc::FUNC_CODE_INST_CLEANUPRET; const auto &CRI = cast(I); - Vals.push_back(CRI.hasReturnValue()); - Vals.push_back(CRI.hasUnwindDest()); - if (CRI.hasReturnValue()) - PushValueAndType(CRI.getReturnValue(), InstID, Vals, VE); + pushValue(CRI.getCleanupPad(), InstID, Vals, VE); if (CRI.hasUnwindDest()) Vals.push_back(VE.getValueID(CRI.getUnwindDest())); break; @@ -1866,15 +1863,13 @@ case Instruction::CatchRet: { Code = bitc::FUNC_CODE_INST_CATCHRET; const auto &CRI = cast(I); + pushValue(CRI.getCatchPad(), InstID, Vals, VE); Vals.push_back(VE.getValueID(CRI.getSuccessor())); - if (CRI.hasReturnValue()) - PushValueAndType(CRI.getReturnValue(), InstID, Vals, VE); break; } case Instruction::CatchPad: { Code = bitc::FUNC_CODE_INST_CATCHPAD; const auto &CPI = cast(I); - Vals.push_back(VE.getTypeID(CPI.getType())); Vals.push_back(VE.getValueID(CPI.getNormalDest())); Vals.push_back(VE.getValueID(CPI.getUnwindDest())); unsigned NumArgOperands = CPI.getNumArgOperands(); @@ -1898,7 +1893,6 @@ case Instruction::CleanupPad: { Code = bitc::FUNC_CODE_INST_CLEANUPPAD; const auto &CPI = cast(I); - Vals.push_back(VE.getTypeID(CPI.getType())); unsigned NumOperands = CPI.getNumOperands(); Vals.push_back(NumOperands); for (unsigned Op = 0; Op != NumOperands; ++Op) Index: lib/CodeGen/WinEHPrepare.cpp =================================================================== --- lib/CodeGen/WinEHPrepare.cpp +++ lib/CodeGen/WinEHPrepare.cpp @@ -2956,8 +2956,7 @@ if (isa(TI) || isa(TI) || isa(TI)) return BB; - return cast(cast(TI)->getReturnValue()) - ->getParent(); + return cast(TI)->getCleanupPad()->getParent(); } static void calculateExplicitStateNumbers(WinEHFuncInfo &FuncInfo, @@ -3242,11 +3241,11 @@ // The token consumed by a CatchReturnInst must match the funclet token. bool IsUnreachableCatchret = false; if (auto *CRI = dyn_cast(TI)) - IsUnreachableCatchret = CRI->getReturnValue() != CatchPad; + IsUnreachableCatchret = CRI->getCatchPad() != CatchPad; // The token consumed by a CleanupPadInst must match the funclet token. bool IsUnreachableCleanupret = false; if (auto *CRI = dyn_cast(TI)) - IsUnreachableCleanupret = CRI->getReturnValue() != CleanupPad; + IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad; if (IsUnreachableRet || IsUnreachableCatchret || IsUnreachableCleanupret) { new UnreachableInst(BB->getContext(), TI); TI->eraseFromParent(); Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -2860,9 +2860,6 @@ writeOperand(LPI->getClause(i), true); } } else if (const auto *CPI = dyn_cast(&I)) { - Out << ' '; - TypePrinter.print(I.getType(), Out); - Out << " ["; for (unsigned Op = 0, NumOps = CPI->getNumArgOperands(); Op < NumOps; ++Op) { @@ -2888,9 +2885,6 @@ else Out << "to caller"; } else if (const auto *CPI = dyn_cast(&I)) { - Out << ' '; - TypePrinter.print(I.getType(), Out); - Out << " ["; for (unsigned Op = 0, NumOps = CPI->getNumOperands(); Op < NumOps; ++Op) { if (Op > 0) @@ -2901,22 +2895,14 @@ } else if (isa(I) && !Operand) { Out << " void"; } else if (const auto *CRI = dyn_cast(&I)) { - if (CRI->hasReturnValue()) { - Out << ' '; - writeOperand(CRI->getReturnValue(), /*PrintType=*/true); - } else { - Out << " void"; - } + Out << ' '; + writeOperand(CRI->getCatchPad(), /*PrintType=*/false); Out << " to "; writeOperand(CRI->getSuccessor(), /*PrintType=*/true); } else if (const auto *CRI = dyn_cast(&I)) { - if (CRI->hasReturnValue()) { - Out << ' '; - writeOperand(CRI->getReturnValue(), /*PrintType=*/true); - } else { - Out << " void"; - } + Out << ' '; + writeOperand(CRI->getCleanupPad(), /*PrintType=*/false); Out << " unwind "; if (CRI->hasUnwindDest()) Index: lib/IR/Instruction.cpp =================================================================== --- lib/IR/Instruction.cpp +++ lib/IR/Instruction.cpp @@ -261,7 +261,7 @@ case ExtractValue: return "extractvalue"; case InsertValue: return "insertvalue"; case LandingPad: return "landingpad"; - case CleanupPad: return "cleanuppad"; + case CleanupPad: return "cleanuppad"; default: return " "; } Index: lib/IR/Instructions.cpp =================================================================== --- lib/IR/Instructions.cpp +++ lib/IR/Instructions.cpp @@ -684,51 +684,39 @@ CRI.getNumOperands()) { SubclassOptionalData = CRI.SubclassOptionalData; setInstructionSubclassData(CRI.getSubclassDataFromInstruction()); - if (Value *RetVal = CRI.getReturnValue()) - setReturnValue(RetVal); - if (BasicBlock *UnwindDest = CRI.getUnwindDest()) - setUnwindDest(UnwindDest); + Op<-1>() = CRI.Op<-1>(); + if (CRI.hasUnwindDest()) + Op<-2>() = CRI.Op<-2>(); } -void CleanupReturnInst::init(Value *RetVal, BasicBlock *UnwindBB) { +void CleanupReturnInst::init(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB) { SubclassOptionalData = 0; if (UnwindBB) setInstructionSubclassData(getSubclassDataFromInstruction() | 1); - if (RetVal) - setInstructionSubclassData(getSubclassDataFromInstruction() | 2); + Op<-1>() = CleanupPad; if (UnwindBB) - setUnwindDest(UnwindBB); - if (RetVal) - setReturnValue(RetVal); + Op<-2>() = UnwindBB; } -CleanupReturnInst::CleanupReturnInst(LLVMContext &C, Value *RetVal, +CleanupReturnInst::CleanupReturnInst(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB, unsigned Values, Instruction *InsertBefore) - : TerminatorInst(Type::getVoidTy(C), Instruction::CleanupRet, + : TerminatorInst(Type::getVoidTy(CleanupPad->getContext()), + Instruction::CleanupRet, OperandTraits::op_end(this) - Values, Values, InsertBefore) { - init(RetVal, UnwindBB); + init(CleanupPad, UnwindBB); } -CleanupReturnInst::CleanupReturnInst(LLVMContext &C, Value *RetVal, +CleanupReturnInst::CleanupReturnInst(CleanupPadInst *CleanupPad, BasicBlock *UnwindBB, unsigned Values, BasicBlock *InsertAtEnd) - : TerminatorInst(Type::getVoidTy(C), Instruction::CleanupRet, + : TerminatorInst(Type::getVoidTy(CleanupPad->getContext()), + Instruction::CleanupRet, OperandTraits::op_end(this) - Values, Values, InsertAtEnd) { - init(RetVal, UnwindBB); -} - -BasicBlock *CleanupReturnInst::getUnwindDest() const { - if (hasUnwindDest()) - return cast(getOperand(getUnwindLabelOpIdx())); - return nullptr; -} -void CleanupReturnInst::setUnwindDest(BasicBlock *NewDest) { - assert(NewDest); - setOperand(getUnwindLabelOpIdx(), NewDest); + init(CleanupPad, UnwindBB); } BasicBlock *CleanupReturnInst::getSuccessorV(unsigned Idx) const { @@ -797,38 +785,32 @@ //===----------------------------------------------------------------------===// // CatchReturnInst Implementation //===----------------------------------------------------------------------===// -void CatchReturnInst::init(BasicBlock *BB, Value *RetVal) { - Op<-1>() = BB; - if (RetVal) - Op<-2>() = RetVal; +void CatchReturnInst::init(CatchPadInst *CatchPad, BasicBlock *BB) { + Op<0>() = CatchPad; + Op<1>() = BB; } CatchReturnInst::CatchReturnInst(const CatchReturnInst &CRI) : TerminatorInst(Type::getVoidTy(CRI.getContext()), Instruction::CatchRet, - OperandTraits::op_end(this) - - CRI.getNumOperands(), - CRI.getNumOperands()) { - Op<-1>() = CRI.Op<-1>(); - if (CRI.getNumOperands() != 1) { - assert(CRI.getNumOperands() == 2); - Op<-2>() = CRI.Op<-2>(); - } + OperandTraits::op_begin(this), 2) { + Op<0>() = CRI.Op<0>(); + Op<1>() = CRI.Op<1>(); } -CatchReturnInst::CatchReturnInst(BasicBlock *BB, Value *RetVal, unsigned Values, +CatchReturnInst::CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB, Instruction *InsertBefore) : TerminatorInst(Type::getVoidTy(BB->getContext()), Instruction::CatchRet, - OperandTraits::op_end(this) - Values, - Values, InsertBefore) { - init(BB, RetVal); + OperandTraits::op_begin(this), 2, + InsertBefore) { + init(CatchPad, BB); } -CatchReturnInst::CatchReturnInst(BasicBlock *BB, Value *RetVal, unsigned Values, +CatchReturnInst::CatchReturnInst(CatchPadInst *CatchPad, BasicBlock *BB, BasicBlock *InsertAtEnd) : TerminatorInst(Type::getVoidTy(BB->getContext()), Instruction::CatchRet, - OperandTraits::op_end(this) - Values, - Values, InsertAtEnd) { - init(BB, RetVal); + OperandTraits::op_begin(this), 2, + InsertAtEnd) { + init(CatchPad, BB); } BasicBlock *CatchReturnInst::getSuccessorV(unsigned Idx) const { @@ -863,21 +845,21 @@ std::copy(CPI.op_begin(), CPI.op_end(), op_begin()); } -CatchPadInst::CatchPadInst(Type *RetTy, BasicBlock *IfNormal, - BasicBlock *IfException, ArrayRef Args, - unsigned Values, const Twine &NameStr, - Instruction *InsertBefore) - : TerminatorInst(RetTy, Instruction::CatchPad, +CatchPadInst::CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException, + ArrayRef Args, unsigned Values, + const Twine &NameStr, Instruction *InsertBefore) + : TerminatorInst(Type::getTokenTy(IfNormal->getContext()), + Instruction::CatchPad, OperandTraits::op_end(this) - Values, Values, InsertBefore) { init(IfNormal, IfException, Args, NameStr); } -CatchPadInst::CatchPadInst(Type *RetTy, BasicBlock *IfNormal, - BasicBlock *IfException, ArrayRef Args, - unsigned Values, const Twine &NameStr, - BasicBlock *InsertAtEnd) - : TerminatorInst(RetTy, Instruction::CatchPad, +CatchPadInst::CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException, + ArrayRef Args, unsigned Values, + const Twine &NameStr, BasicBlock *InsertAtEnd) + : TerminatorInst(Type::getTokenTy(IfNormal->getContext()), + Instruction::CatchPad, OperandTraits::op_end(this) - Values, Values, InsertAtEnd) { init(IfNormal, IfException, Args, NameStr); @@ -962,17 +944,17 @@ std::copy(CPI.op_begin(), CPI.op_end(), op_begin()); } -CleanupPadInst::CleanupPadInst(Type *RetTy, ArrayRef Args, +CleanupPadInst::CleanupPadInst(LLVMContext &C, ArrayRef Args, const Twine &NameStr, Instruction *InsertBefore) - : Instruction(RetTy, Instruction::CleanupPad, + : Instruction(Type::getTokenTy(C), Instruction::CleanupPad, OperandTraits::op_end(this) - Args.size(), Args.size(), InsertBefore) { init(Args, NameStr); } -CleanupPadInst::CleanupPadInst(Type *RetTy, ArrayRef Args, +CleanupPadInst::CleanupPadInst(LLVMContext &C, ArrayRef Args, const Twine &NameStr, BasicBlock *InsertAtEnd) - : Instruction(RetTy, Instruction::CleanupPad, + : Instruction(Type::getTokenTy(C), Instruction::CleanupPad, OperandTraits::op_end(this) - Args.size(), Args.size(), InsertAtEnd) { init(Args, NameStr); Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -184,12 +184,6 @@ /// \brief Track unresolved string-based type references. SmallDenseMap UnresolvedTypeRefs; - /// \brief The result type for a catchpad. - Type *CatchPadResultTy; - - /// \brief The result type for a cleanuppad. - Type *CleanupPadResultTy; - /// \brief The result type for a landingpad. Type *LandingPadResultTy; @@ -203,8 +197,7 @@ public: explicit Verifier(raw_ostream &OS) - : VerifierSupport(OS), Context(nullptr), CatchPadResultTy(nullptr), - CleanupPadResultTy(nullptr), LandingPadResultTy(nullptr), + : VerifierSupport(OS), Context(nullptr), LandingPadResultTy(nullptr), SawFrameEscape(false) {} bool verify(const Function &F) { @@ -239,8 +232,6 @@ // FIXME: We strip const here because the inst visitor strips const. visit(const_cast(F)); InstsInThisBlock.clear(); - CatchPadResultTy = nullptr; - CleanupPadResultTy = nullptr; LandingPadResultTy = nullptr; SawFrameEscape = false; @@ -2877,14 +2868,6 @@ void Verifier::visitCatchPadInst(CatchPadInst &CPI) { visitEHPadPredecessors(CPI); - if (!CatchPadResultTy) - CatchPadResultTy = CPI.getType(); - else - Assert(CatchPadResultTy == CPI.getType(), - "The catchpad instruction should have a consistent result type " - "inside a function.", - &CPI); - BasicBlock *BB = CPI.getParent(); Function *F = BB->getParent(); Assert(F->hasPersonalityFn(), @@ -2896,6 +2879,14 @@ "CatchPadInst not the first non-PHI instruction in the block.", &CPI); + if (!BB->getSinglePredecessor()) + for (BasicBlock *PredBB : predecessors(BB)) { + Assert(!isa(PredBB->getTerminator()), + "CatchPadInst with CatchPadInst predecessor cannot have any other " + "predecessors.", + &CPI); + } + BasicBlock *UnwindDest = CPI.getUnwindDest(); Instruction *I = UnwindDest->getFirstNonPHI(); Assert( @@ -2946,14 +2937,6 @@ BasicBlock *BB = CPI.getParent(); - if (!CleanupPadResultTy) - CleanupPadResultTy = CPI.getType(); - else - Assert(CleanupPadResultTy == CPI.getType(), - "The cleanuppad instruction should have a consistent result type " - "inside a function.", - &CPI); - Function *F = BB->getParent(); Assert(F->hasPersonalityFn(), "CleanupPadInst needs to be in a function with a personality.", &CPI); @@ -2964,6 +2947,18 @@ "CleanupPadInst not the first non-PHI instruction in the block.", &CPI); + CleanupReturnInst *FirstCRI = nullptr; + for (User *U : CPI.users()) + if (CleanupReturnInst *CRI = dyn_cast(U)) { + if (!FirstCRI) + FirstCRI = CRI; + else + Assert(CRI->getUnwindDest() == FirstCRI->getUnwindDest(), + "Cleanuprets from same cleanuppad have different exceptional " + "successors.", + FirstCRI, CRI); + } + visitInstruction(CPI); } Index: lib/Transforms/Instrumentation/MemorySanitizer.cpp =================================================================== --- lib/Transforms/Instrumentation/MemorySanitizer.cpp +++ lib/Transforms/Instrumentation/MemorySanitizer.cpp @@ -2674,17 +2674,13 @@ } void visitCleanupPadInst(CleanupPadInst &I) { - if (!I.getType()->isVoidTy()) { - setShadow(&I, getCleanShadow(&I)); - setOrigin(&I, getCleanOrigin()); - } + setShadow(&I, getCleanShadow(&I)); + setOrigin(&I, getCleanOrigin()); } void visitCatchPad(CatchPadInst &I) { - if (!I.getType()->isVoidTy()) { - setShadow(&I, getCleanShadow(&I)); - setOrigin(&I, getCleanOrigin()); - } + setShadow(&I, getCleanShadow(&I)); + setOrigin(&I, getCleanOrigin()); } void visitTerminatePad(TerminatePadInst &I) { Index: lib/Transforms/Utils/InlineFunction.cpp =================================================================== --- lib/Transforms/Utils/InlineFunction.cpp +++ lib/Transforms/Utils/InlineFunction.cpp @@ -344,8 +344,7 @@ if (auto *CRI = dyn_cast(BB->getTerminator())) { if (CRI->unwindsToCaller()) { - CleanupReturnInst::Create(CRI->getContext(), CRI->getReturnValue(), - UnwindDest, CRI); + CleanupReturnInst::Create(CRI->getCleanupPad(), UnwindDest, CRI); CRI->eraseFromParent(); UpdatePHINodes(BB); } Index: test/Assembler/invalid-OperatorConstraint.ll =================================================================== --- /dev/null +++ test/Assembler/invalid-OperatorConstraint.ll @@ -0,0 +1,59 @@ +; RUN: sed -e s/.T1:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK1 %s +; RUN: sed -e s/.T2:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK2 %s +; RUN: sed -e s/.T3:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK3 %s +; RUN: sed -e s/.T4:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK4 %s +; RUN: sed -e s/.T5:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK5 %s +; RUN: sed -e s/.T6:// %s | not llvm-as -disable-output 2>&1 | FileCheck --check-prefix=CHECK6 %s + +;T1: define void @f() { +;T1: entry: +;T1: ; operator constraint requires an operator +;T1: catchret undef to label %entry +;T1: ; CHECK1: [[@LINE-1]]:15: error: Catchpad value required in this position +;T1: } + +;T2: define void @f() { +;T2: entry: +;T2: %x = cleanuppad [] +;T2: ; catchret's first operand's operator must be catchpad +;T2: catchret %x to label %entry +;T2: ; CHECK2: [[@LINE-1]]:15: error: '%x' is not a catchpad +;T2: } + +;T3: define void @f() { +;T3: entry: +;T3: ; catchret's first operand's operator must be catchpad +;T3: ; (forward reference case) +;T3: catchret %x to label %next +;T3: ; CHECK3: [[@LINE-1]]:15: error: '%x' is not a catchpad +;T3: next: +;T3: %x = cleanuppad [] +;T3: ret void +;T3: } + +;T4: define void @f() { +;T4: entry: +;T4: ; operator constraint requires an operator +;T4: cleanupret undef unwind label %entry +;T4: ; CHECK4: [[@LINE-1]]:17: error: Cleanuppad value required in this position +;T4: } + +;T5: define void @f() { +;T5: entry: +;T5: %x = catchpad [] +;T5: to label %next unwind label %entry +;T5: next: +;T5: ; cleanupret first operand's operator must be cleanuppad +;T5: cleanupret %x unwind to caller +;T5: ; CHECK5: [[@LINE-1]]:17: error: '%x' is not a cleanuppad +;T5: } + +;T6: define void @f() { +;T6: entry: +;T6: ; cleanupret's first operand's operator must be cleanuppad +;T6: ; (forward reference case) +;T6: cleanupret %x unwind label %next +;T6: ; CHECK6: [[@LINE-1]]:17: error: '%x' is not a cleanuppad +;T6: next: +;T6: %x = catchpad [] to label %entry unwind label %next +;T6: } Index: test/CodeGen/WinEH/wineh-demotion.ll =================================================================== --- test/CodeGen/WinEH/wineh-demotion.ll +++ test/CodeGen/WinEH/wineh-demotion.ll @@ -36,14 +36,14 @@ ; CHECK: merge: ; CHECK-NOT: = phi %phi = phi i32 [ %x, %left ], [ %y, %right ] - %cp = catchpad token [] to label %catch unwind label %catchend + %cp = catchpad [] to label %catch unwind label %catchend catch: ; CHECK: catch: ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]] ; CHECK-NEXT: call void @h(i32 [[Reload]]) call void @h(i32 %phi) - catchret token %cp to label %exit + catchret %cp to label %exit catchend: catchendpad unwind to caller @@ -75,9 +75,9 @@ merge.inner: ; CHECK: merge.inner: ; CHECK-NOT: = phi - ; CHECK: catchpad token + ; CHECK: catchpad [] %x = phi i32 [ 1, %left ], [ 2, %right ] - %cpinner = catchpad token [] to label %catch.inner unwind label %catchend.inner + %cpinner = catchpad [] to label %catch.inner unwind label %catchend.inner catch.inner: ; Need just one store here because only %y is affected @@ -89,16 +89,16 @@ to label %catchret.inner unwind label %merge.outer catchret.inner: - catchret token %cpinner to label %exit + catchret %cpinner to label %exit catchend.inner: catchendpad unwind label %merge.outer merge.outer: ; CHECK: merge.outer: ; CHECK-NOT: = phi - ; CHECK: [[CatchPad:%[^ ]+]] = catchpad token + ; CHECK: [[CatchPad:%[^ ]+]] = catchpad [] %y = phi i32 [ %x, %catchend.inner ], [ %z, %catch.inner ] - %cpouter = catchpad token [] to label %catch.outer unwind label %catchend.outer + %cpouter = catchpad [] to label %catch.outer unwind label %catchend.outer catchend.outer: catchendpad unwind to caller @@ -109,10 +109,10 @@ ; CHECK: catch.outer: ; CHECK-DAG: load i32, i32* [[Slot1]] ; CHECK-DAG: load i32, i32* [[Slot2]] - ; CHECK: catchret token [[CatchPad]] to label + ; CHECK: catchret [[CatchPad]] to label call void @h(i32 %x) call void @h(i32 %y) - catchret token %cpouter to label %exit + catchret %cpouter to label %exit exit: ret void @@ -131,7 +131,7 @@ to label %exit unwind label %catchpad catchpad: - %cp = catchpad token [] to label %catch unwind label %catchend + %cp = catchpad [] to label %catch unwind label %catchend catch: ; Need to reload %B here @@ -152,7 +152,7 @@ ; CHECK: %phi = phi i32 [ [[ReloadX]], %left ] %phi = phi i32 [ %x, %left ], [ 42, %right ] call void @h(i32 %phi) - catchret token %cp to label %exit + catchret %cp to label %exit catchend: catchendpad unwind to caller @@ -188,11 +188,11 @@ to label %join unwind label %catchpad.inner catchpad.inner: ; CHECK: catchpad.inner: - ; CHECK-NEXT: catchpad token + ; CHECK-NEXT: catchpad [] %phi.inner = phi i32 [ %l, %left ], [ %r, %right ] - %cp1 = catchpad token [] to label %catch.inner unwind label %catchend.inner + %cp1 = catchpad [] to label %catch.inner unwind label %catchend.inner catch.inner: - catchret token %cp1 to label %join + catchret %cp1 to label %join catchend.inner: catchendpad unwind label %catchpad.outer join: @@ -205,15 +205,15 @@ to label %exit unwind label %catchpad.outer catchpad.outer: ; CHECK: catchpad.outer: - ; CHECK-NEXT: catchpad token + ; CHECK-NEXT: catchpad [] %phi.outer = phi i32 [ %phi.inner, %catchend.inner ], [ %j, %join ] - %cp2 = catchpad token [] to label %catch.outer unwind label %catchend.outer + %cp2 = catchpad [] to label %catch.outer unwind label %catchend.outer catch.outer: ; CHECK: catch.outer: ; CHECK: [[Reload:%[^ ]+]] = load i32, i32* [[Slot]] ; CHECK: call void @h(i32 [[Reload]]) call void @h(i32 %phi.outer) - catchret token %cp2 to label %exit + catchret %cp2 to label %exit catchend.outer: catchendpad unwind to caller exit: @@ -241,10 +241,10 @@ cleanup: ; cleanup phi can be loaded at cleanup entry ; CHECK: cleanup: - ; CHECK-NEXT: cleanuppad token + ; CHECK-NEXT: cleanuppad [] ; CHECK: [[CleanupReload:%[^ ]+]] = load i32, i32* [[CleanupSlot]] %phi.cleanup = phi i32 [ 1, %entry ], [ 2, %invoke.cont ] - %cp = cleanuppad token [] + %cp = cleanuppad [] %b = call i1 @i() br i1 %b, label %left, label %right @@ -264,8 +264,8 @@ ; need store for %phi.catch ; CHECK: merge: ; CHECK-NEXT: store i32 [[CleanupReload]], i32* [[CatchSlot:%[^ ]+]] - ; CHECK-NEXT: cleanupret token - cleanupret token %cp unwind label %catchpad + ; CHECK-NEXT: cleanupret + cleanupret %cp unwind label %catchpad invoke.cont2: ; need store for %phi.catch @@ -277,16 +277,16 @@ catchpad: ; CHECK: catchpad: - ; CHECK-NEXT: catchpad token + ; CHECK-NEXT: catchpad [] %phi.catch = phi i32 [ %phi.cleanup, %merge ], [ 3, %invoke.cont2 ] - %cp2 = catchpad token [] to label %catch unwind label %catchend + %cp2 = catchpad [] to label %catch unwind label %catchend catch: ; CHECK: catch: ; CHECK: [[CatchReload:%[^ ]+]] = load i32, i32* [[CatchSlot]] ; CHECK: call void @h(i32 [[CatchReload]] call void @h(i32 %phi.catch) - catchret token %cp2 to label %exit + catchret %cp2 to label %exit catchend: catchendpad unwind to caller @@ -310,8 +310,8 @@ ; CHECK: store i32 %x, i32* [[SpillSlot:%[^ ]+]] ; CHECK: br label %loop to_caller: - %cp1 = cleanuppad token [] - cleanupret token %cp1 unwind to caller + %cp1 = cleanuppad [] + cleanupret %cp1 unwind to caller loop: invoke void @f() to label %loop unwind label %cleanup @@ -319,9 +319,9 @@ ; CHECK: cleanup: ; CHECK: [[Load:%[^ ]+]] = load i32, i32* [[SpillSlot]] ; CHECK: call void @h(i32 [[Load]]) - %cp2 = cleanuppad token [] + %cp2 = cleanuppad [] call void @h(i32 %x) - cleanupret token %cp2 unwind to caller + cleanupret %cp2 unwind to caller } ; CHECK-LABEL: @test7( @@ -343,9 +343,9 @@ catchpad: ; %x phi should be eliminated ; CHECK: catchpad: - ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad token + ; CHECK-NEXT: %[[CatchPad:[^ ]+]] = catchpad [] %x = phi i32 [ 1, %entry ], [ 2, %invoke.cont ] - %cp = catchpad token [] to label %catch unwind label %catchend + %cp = catchpad [] to label %catch unwind label %catchend catch: %b = call i1 @i() br i1 %b, label %left, label %right @@ -353,8 +353,8 @@ ; Edge from %left to %join needs to be split so that ; the load of %x can be inserted *after* the catchret ; CHECK: left: - ; CHECK-NEXT: catchret token %[[CatchPad]] to label %[[SplitLeft:[^ ]+]] - catchret token %cp to label %join + ; CHECK-NEXT: catchret %[[CatchPad]] to label %[[SplitLeft:[^ ]+]] + catchret %cp to label %join ; CHECK: [[SplitLeft]]: ; CHECK: [[LoadX:%[^ ]+]] = load i32, i32* [[SlotX]] ; CHECK: br label %join @@ -363,9 +363,9 @@ ; the load of %y can be inserted *after* the catchret ; CHECK: right: ; CHECK: store i32 %y, i32* [[SlotY:%[^ ]+]] - ; CHECK: catchret token %[[CatchPad]] to label %[[SplitRight:[^ ]+]] + ; CHECK: catchret %[[CatchPad]] to label %[[SplitRight:[^ ]+]] %y = call i32 @g() - catchret token %cp to label %join + catchret %cp to label %join ; CHECK: [[SplitRight]]: ; CHECK: [[LoadY:%[^ ]+]] = load i32, i32* [[SlotY]] ; CHECK: br label %join @@ -392,20 +392,20 @@ ret void cleanup1: - ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad token + ; CHECK: [[CleanupPad1:%[^ ]+]] = cleanuppad [] ; CHECK-NEXT: call void @f() - ; CHECK-NEXT: cleanupret token [[CleanupPad1]] - %cp0 = cleanuppad token [] + ; CHECK-NEXT: cleanupret [[CleanupPad1]] + %cp0 = cleanuppad [] br label %cleanupexit cleanup2: - ; CHECK: cleanuppad token + ; CHECK: cleanuppad [] ; CHECK-NEXT: call void @f() ; CHECK-NEXT: unreachable - %cp1 = cleanuppad token [] + %cp1 = cleanuppad [] br label %cleanupexit cleanupexit: call void @f() - cleanupret token %cp0 unwind label %cleanup2 + cleanupret %cp0 unwind label %cleanup2 } Index: test/CodeGen/WinEH/wineh-statenumbering.ll =================================================================== --- test/CodeGen/WinEH/wineh-statenumbering.ll +++ test/CodeGen/WinEH/wineh-statenumbering.ll @@ -37,7 +37,7 @@ to label %unreachable.for.entry unwind label %catch.dispatch catch.dispatch: ; preds = %entry - %1 = catchpad token [i8* null, i8* null] to label %catch unwind label %catchendblock + %1 = catchpad [i8* null, i8* null] to label %catch unwind label %catchendblock catch: ; preds = %catch.dispatch ; CHECK: catch: @@ -47,7 +47,7 @@ to label %unreachable unwind label %catch.dispatch.1 catch.dispatch.1: ; preds = %catch - %2 = catchpad token [i8* null, i8* null] to label %catch.3 unwind label %catchendblock.2 + %2 = catchpad [i8* null, i8* null] to label %catch.3 unwind label %catchendblock.2 catch.3: ; preds = %catch.dispatch.1 ; CHECK: catch.3: @@ -57,7 +57,7 @@ to label %invoke.cont unwind label %catchendblock.2 invoke.cont: ; preds = %catch.3 - catchret token %2 to label %try.cont + catchret %2 to label %try.cont try.cont: ; preds = %invoke.cont ; CHECK: try.cont: Index: test/Feature/exception.ll =================================================================== --- test/Feature/exception.ll +++ test/Feature/exception.ll @@ -28,60 +28,100 @@ define void @cleanupret0() personality i32 (...)* @__gxx_personality_v0 { entry: - br label %try.cont - -try.cont: invoke void @_Z3quxv() optsize - to label %try.cont unwind label %bb -bb: - cleanuppad void [i7 4] - cleanupret i8 0 unwind label %bb + to label %exit unwind label %pad +pad: + %cp = cleanuppad [i7 4] + cleanupret %cp unwind to caller +exit: + ret void } +; forward ref by name define void @cleanupret1() personality i32 (...)* @__gxx_personality_v0 { entry: - br label %try.cont - -try.cont: invoke void @_Z3quxv() optsize - to label %try.cont unwind label %bb -bb: - cleanuppad void [i7 4] - cleanupret void unwind label %bb + to label %exit unwind label %pad +cleanup: + cleanupret %cp unwind label %pad +pad: + %cp = cleanuppad [] + br label %cleanup +exit: + ret void } +; forward ref by ID define void @cleanupret2() personality i32 (...)* @__gxx_personality_v0 { entry: - cleanupret i8 0 unwind to caller + invoke void @_Z3quxv() optsize + to label %exit unwind label %pad +cleanup: + cleanupret %0 unwind label %pad +pad: + %0 = cleanuppad [] + br label %cleanup +exit: + ret void } -define void @cleanupret3() personality i32 (...)* @__gxx_personality_v0 { - cleanupret void unwind to caller +define void @catchret0() personality i32 (...)* @__gxx_personality_v0 { +entry: + invoke void @_Z3quxv() optsize + to label %exit unwind label %pad +pad: + %cp = catchpad [i7 4] + to label %catch unwind label %endpad +catch: + catchret %cp to label %exit +endpad: + catchendpad unwind to caller +exit: + ret void } -define void @catchret() personality i32 (...)* @__gxx_personality_v0 { +; forward ref by name +define void @catchret1() personality i32 (...)* @__gxx_personality_v0 { entry: - br label %bb -bb: - catchret void to label %bb + invoke void @_Z3quxv() optsize + to label %exit unwind label %pad +catch: + catchret %cp to label %exit +pad: + %cp = catchpad [] + to label %catch unwind label %endpad +endpad: + catchendpad unwind to caller +exit: + ret void } -define i8 @catchpad() personality i32 (...)* @__gxx_personality_v0 { +; forward ref by ID +define void @catchret2() personality i32 (...)* @__gxx_personality_v0 { entry: - br label %try.cont + invoke void @_Z3quxv() optsize + to label %exit unwind label %pad +catch: + catchret %0 to label %exit +pad: + %0 = catchpad [] + to label %catch unwind label %endpad +endpad: + catchendpad unwind to caller +exit: + ret void +} -try.cont: +define i8 @catchpad() personality i32 (...)* @__gxx_personality_v0 { +entry: invoke void @_Z3quxv() optsize to label %exit unwind label %bb2 -bb: - catchret token %cbv to label %exit - -exit: - ret i8 0 bb2: - %cbv = catchpad token [i7 4] to label %bb unwind label %bb3 + catchpad [i7 4] to label %exit unwind label %bb3 bb3: catchendpad unwind to caller +exit: + ret i8 0 } define void @terminatepad0() personality i32 (...)* @__gxx_personality_v0 { @@ -114,7 +154,7 @@ invoke void @_Z3quxv() optsize to label %try.cont unwind label %bb bb: - cleanuppad void [i7 4] + cleanuppad [i7 4] ret void }