mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[WinEH] Require token linkage in EH pad/ret signatures
Summary: WinEHPrepare is going to require that cleanuppad and catchpad produce values of token type which are consumed by any cleanupret or catchret exiting the pad. This change updates the signatures of those operators to require/enforce that the type produced by the pads is token type and that the rets have an appropriate argument. The catchpad argument of a `CatchReturnInst` must be a `CatchPadInst` (and similarly for `CleanupReturnInst`/`CleanupPadInst`). To accommodate that restriction, this change adds a notion of an operator constraint to both LLParser and BitcodeReader, allowing appropriate sentinels to be constructed for forward references and appropriate error messages to be emitted for illegal inputs. Also add a verifier rule (noted in LangRef) that a catchpad with a catchpad predecessor must have no other predecessors; this ensures that WinEHPrepare will see the expected linear relationship between sibling catches on the same try. Lastly, remove some superfluous/vestigial casts from instruction operand setters operating on BasicBlocks. Reviewers: rnk, majnemer Subscribers: llvm-commits Differential Revision: http://reviews.llvm.org/D12108 llvm-svn: 245797
This commit is contained in:
parent
6c8cdd903c
commit
56089ea65e
@ -614,20 +614,19 @@ specifications with one combined instruction. All potentially throwing calls in
|
||||
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 @@ all of the new IR instructions:
|
||||
; 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"]
|
||||
|
@ -5138,7 +5138,7 @@ Syntax:
|
||||
|
||||
::
|
||||
|
||||
<resultval> = catchpad <resultty> [<args>*]
|
||||
<resultval> = catchpad [<args>*]
|
||||
to label <normal label> unwind label <exception label>
|
||||
|
||||
Overview:
|
||||
@ -5153,9 +5153,9 @@ routine requires to know if this is an appropriate place to catch the
|
||||
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 <personalityfn>` 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 <t_token>` and is used to match the ``catchpad`` to
|
||||
corresponding :ref:`catchrets <i_catchret>`.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
@ -5170,15 +5170,11 @@ label to transfer control to if it doesn't.
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
The '``catchpad``' instruction defines the values which are set by the
|
||||
:ref:`personality function <personalityfn>` 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 @@ The ``catchpad`` instruction has several restrictions:
|
||||
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 @@ Example:
|
||||
.. 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 @@ The ``catchendpad`` instruction has several restrictions:
|
||||
'``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 @@ Syntax:
|
||||
|
||||
::
|
||||
|
||||
catchret <type> <value> to label <normal>
|
||||
catchret <value> to label <normal>
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
@ -5296,8 +5296,10 @@ single successor.
|
||||
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 <i_catchpad>`.
|
||||
The second argument to a '``catchret``' specifies where control will
|
||||
transfer to next.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
@ -5309,13 +5311,21 @@ The :ref:`personality function <personalityfn>` gets a chance to execute
|
||||
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 @@ Syntax:
|
||||
|
||||
::
|
||||
|
||||
cleanupret <type> <value> unwind label <continue>
|
||||
cleanupret <type> <value> unwind to caller
|
||||
cleanupret <value> unwind label <continue>
|
||||
cleanupret <value> unwind to caller
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
@ -5340,9 +5350,9 @@ an optional successor.
|
||||
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 <i_cleanuppad>`.
|
||||
It also has an optional successor, ``continue``.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
@ -5351,14 +5361,21 @@ The '``cleanupret``' instruction indicates to the
|
||||
:ref:`personality function <personalityfn>` that one
|
||||
:ref:`cleanuppad <i_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 @@ Syntax:
|
||||
|
||||
::
|
||||
|
||||
<resultval> = cleanuppad <resultty> [<args>*]
|
||||
<resultval> = cleanuppad [<args>*]
|
||||
|
||||
Overview:
|
||||
"""""""""
|
||||
@ -8403,7 +8420,8 @@ transfer control to run cleanup actions.
|
||||
The ``args`` correspond to whatever additional
|
||||
information the :ref:`personality function <personalityfn>` requires to
|
||||
execute the cleanup.
|
||||
The ``resultval`` has the type ``resultty``.
|
||||
The ``resultval`` has the type :ref:`token <t_token>` and is used to
|
||||
match the ``cleanuppad`` to corresponding :ref:`cleanuprets <i_cleanupret>`.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
@ -8415,9 +8433,8 @@ Semantics:
|
||||
""""""""""
|
||||
|
||||
The '``cleanuppad``' instruction defines the values which are set by the
|
||||
:ref:`personality function <personalityfn>` 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 <personalityfn>` 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 @@ The ``cleanuppad`` instruction has several restrictions:
|
||||
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:
|
||||
|
||||
|
@ -356,9 +356,9 @@ namespace bitc {
|
||||
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#]
|
||||
|
@ -671,15 +671,14 @@ public:
|
||||
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<Value *> Args,
|
||||
const Twine &Name = "") {
|
||||
return Insert(CatchPadInst::Create(Ty, NormalDest, UnwindDest, Args), Name);
|
||||
CatchPadInst *CreateCatchPad(BasicBlock *NormalDest, BasicBlock *UnwindDest,
|
||||
ArrayRef<Value *> Args, const Twine &Name = "") {
|
||||
return Insert(CatchPadInst::Create(NormalDest, UnwindDest, Args), Name);
|
||||
}
|
||||
|
||||
CatchEndPadInst *CreateCatchEndPad(BasicBlock *UnwindBB = nullptr) {
|
||||
@ -692,13 +691,13 @@ public:
|
||||
return Insert(TerminatePadInst::Create(Context, UnwindBB, Args), Name);
|
||||
}
|
||||
|
||||
CleanupPadInst *CreateCleanupPad(Type *Ty, ArrayRef<Value *> Args,
|
||||
CleanupPadInst *CreateCleanupPad(ArrayRef<Value *> 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() {
|
||||
|
@ -2740,7 +2740,7 @@ public:
|
||||
|
||||
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 @@ public:
|
||||
}
|
||||
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 @@ public:
|
||||
return cast<BasicBlock>(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:
|
||||
@ -3569,111 +3569,6 @@ struct OperandTraits<ResumeInst> :
|
||||
|
||||
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<Instruction>(V) && classof(cast<Instruction>(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<CleanupReturnInst>
|
||||
: public VariadicOperandTraits<CleanupReturnInst> {};
|
||||
|
||||
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CleanupReturnInst, Value)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// CatchEndPadInst Class
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -3760,14 +3655,12 @@ private:
|
||||
|
||||
CatchPadInst(const CatchPadInst &CPI);
|
||||
|
||||
explicit CatchPadInst(Type *RetTy, BasicBlock *IfNormal,
|
||||
BasicBlock *IfException, ArrayRef<Value *> Args,
|
||||
unsigned Values, const Twine &NameStr,
|
||||
Instruction *InsertBefore);
|
||||
explicit CatchPadInst(Type *RetTy, BasicBlock *IfNormal,
|
||||
BasicBlock *IfException, ArrayRef<Value *> Args,
|
||||
unsigned Values, const Twine &NameStr,
|
||||
BasicBlock *InsertAtEnd);
|
||||
explicit CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException,
|
||||
ArrayRef<Value *> Args, unsigned Values,
|
||||
const Twine &NameStr, Instruction *InsertBefore);
|
||||
explicit CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException,
|
||||
ArrayRef<Value *> Args, unsigned Values,
|
||||
const Twine &NameStr, BasicBlock *InsertAtEnd);
|
||||
|
||||
protected:
|
||||
// Note: Instruction needs to be a friend here to call cloneImpl.
|
||||
@ -3775,20 +3668,19 @@ protected:
|
||||
CatchPadInst *cloneImpl() const;
|
||||
|
||||
public:
|
||||
static CatchPadInst *Create(Type *RetTy, BasicBlock *IfNormal,
|
||||
BasicBlock *IfException, ArrayRef<Value *> Args,
|
||||
const Twine &NameStr = "",
|
||||
static CatchPadInst *Create(BasicBlock *IfNormal, BasicBlock *IfException,
|
||||
ArrayRef<Value *> 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<Value *> Args,
|
||||
const Twine &NameStr, BasicBlock *InsertAtEnd) {
|
||||
static CatchPadInst *Create(BasicBlock *IfNormal, BasicBlock *IfException,
|
||||
ArrayRef<Value *> 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 @@ public:
|
||||
// get*Dest - Return the destination basic blocks...
|
||||
BasicBlock *getNormalDest() const { return cast<BasicBlock>(Op<-2>()); }
|
||||
BasicBlock *getUnwindDest() const { return cast<BasicBlock>(Op<-1>()); }
|
||||
void setNormalDest(BasicBlock *B) { Op<-2>() = reinterpret_cast<Value *>(B); }
|
||||
void setUnwindDest(BasicBlock *B) { Op<-1>() = reinterpret_cast<Value *>(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 @@ public:
|
||||
|
||||
void setSuccessor(unsigned idx, BasicBlock *NewSucc) {
|
||||
assert(idx < 2 && "Successor # out of range for catchpad!");
|
||||
*(&Op<-2>() + idx) = reinterpret_cast<Value *>(NewSucc);
|
||||
*(&Op<-2>() + idx) = NewSucc;
|
||||
}
|
||||
|
||||
unsigned getNumSuccessors() const { return 2; }
|
||||
@ -3949,7 +3841,7 @@ public:
|
||||
}
|
||||
void setUnwindDest(BasicBlock *B) {
|
||||
assert(B && hasUnwindDest());
|
||||
Op<-1>() = reinterpret_cast<Value *>(B);
|
||||
Op<-1>() = B;
|
||||
}
|
||||
|
||||
unsigned getNumSuccessors() const { return hasUnwindDest() ? 1 : 0; }
|
||||
@ -3990,9 +3882,9 @@ private:
|
||||
|
||||
CleanupPadInst(const CleanupPadInst &CPI);
|
||||
|
||||
explicit CleanupPadInst(Type *RetTy, ArrayRef<Value *> Args,
|
||||
explicit CleanupPadInst(LLVMContext &C, ArrayRef<Value *> Args,
|
||||
const Twine &NameStr, Instruction *InsertBefore);
|
||||
explicit CleanupPadInst(Type *RetTy, ArrayRef<Value *> Args,
|
||||
explicit CleanupPadInst(LLVMContext &C, ArrayRef<Value *> Args,
|
||||
const Twine &NameStr, BasicBlock *InsertAtEnd);
|
||||
|
||||
protected:
|
||||
@ -4001,14 +3893,14 @@ protected:
|
||||
CleanupPadInst *cloneImpl() const;
|
||||
|
||||
public:
|
||||
static CleanupPadInst *Create(Type *RetTy, ArrayRef<Value *> Args,
|
||||
static CleanupPadInst *Create(LLVMContext &C, ArrayRef<Value *> 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<Value *> Args,
|
||||
static CleanupPadInst *Create(LLVMContext &C, ArrayRef<Value *> 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 @@ class CatchReturnInst : public TerminatorInst {
|
||||
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 @@ protected:
|
||||
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<BasicBlock>(Op<-1>()); }
|
||||
void setSuccessor(BasicBlock *NewSucc) { Op<-1>() = (Value *)NewSucc; }
|
||||
unsigned getNumSuccessors() const { return 1; }
|
||||
CatchPadInst *getCatchPad() const { return cast<CatchPadInst>(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<BasicBlock>(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,10 +3987,108 @@ private:
|
||||
|
||||
template <>
|
||||
struct OperandTraits<CatchReturnInst>
|
||||
: public VariadicOperandTraits<CatchReturnInst> {};
|
||||
: public FixedNumOperandTraits<CatchReturnInst, 2> {};
|
||||
|
||||
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<CleanupPadInst>(Op<-1>());
|
||||
}
|
||||
void setCleanupPad(CleanupPadInst *CleanupPad) {
|
||||
assert(CleanupPad);
|
||||
Op<-1>() = CleanupPad;
|
||||
}
|
||||
|
||||
unsigned getNumSuccessors() const { return hasUnwindDest() ? 1 : 0; }
|
||||
|
||||
BasicBlock *getUnwindDest() const {
|
||||
return hasUnwindDest() ? cast<BasicBlock>(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<Instruction>(V) && classof(cast<Instruction>(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<CleanupReturnInst>
|
||||
: public VariadicOperandTraits<CleanupReturnInst, /*MINARITY=*/1> {};
|
||||
|
||||
DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CleanupReturnInst, Value)
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// UnreachableInst Class
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -913,7 +913,7 @@ bool CallAnalyzer::visitCleanupReturnInst(CleanupReturnInst &CRI) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2237,8 +2237,8 @@ bool LLParser::PerFunctionState::FinishFunction() {
|
||||
/// 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);
|
||||
|
||||
@ -2253,6 +2253,24 @@ Value *LLParser::PerFunctionState::GetVal(const std::string &Name,
|
||||
|
||||
// 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<CatchPadInst>(Val)) {
|
||||
P.Error(Loc, "'%" + Name + "' is not a catchpad");
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
case OC_CleanupPad:
|
||||
if (!isa<CleanupPadInst>(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");
|
||||
@ -2270,17 +2288,31 @@ Value *LLParser::PerFunctionState::GetVal(const std::string &Name,
|
||||
|
||||
// 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;
|
||||
|
||||
@ -2295,6 +2327,24 @@ Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty,
|
||||
|
||||
// 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<CatchPadInst>(Val)) {
|
||||
P.Error(Loc, "'%" + Twine(ID) + "' is not a catchpad");
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
case OC_CleanupPad:
|
||||
if (!isa<CleanupPadInst>(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");
|
||||
@ -2311,10 +2361,23 @@ Value *LLParser::PerFunctionState::GetVal(unsigned ID, Type *Ty,
|
||||
|
||||
// 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;
|
||||
@ -2346,11 +2409,24 @@ bool LLParser::PerFunctionState::SetInstName(int NameID,
|
||||
std::map<unsigned, std::pair<Value*, LocTy> >::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<CatchPadInst>(Sentinel)) {
|
||||
if (!isa<CatchPadInst>(Inst))
|
||||
return P.Error(FI->second.second,
|
||||
"'%" + Twine(NameID) + "' is not a catchpad");
|
||||
} else if (isa<CleanupPadInst>(Sentinel)) {
|
||||
if (!isa<CleanupPadInst>(Inst))
|
||||
return P.Error(FI->second.second,
|
||||
"'%" + Twine(NameID) + "' is not a cleanuppad");
|
||||
}
|
||||
|
||||
Sentinel->replaceAllUsesWith(Inst);
|
||||
delete Sentinel;
|
||||
ForwardRefValIDs.erase(FI);
|
||||
}
|
||||
|
||||
@ -2362,11 +2438,24 @@ bool LLParser::PerFunctionState::SetInstName(int NameID,
|
||||
std::map<std::string, std::pair<Value*, LocTy> >::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<CatchPadInst>(Sentinel)) {
|
||||
if (!isa<CatchPadInst>(Inst))
|
||||
return P.Error(FI->second.second,
|
||||
"'%" + NameStr + "' is not a catchpad");
|
||||
} else if (isa<CleanupPadInst>(Sentinel)) {
|
||||
if (!isa<CleanupPadInst>(Inst))
|
||||
return P.Error(FI->second.second,
|
||||
"'%" + NameStr + "' is not a cleanuppad");
|
||||
}
|
||||
|
||||
Sentinel->replaceAllUsesWith(Inst);
|
||||
delete Sentinel;
|
||||
ForwardRefVals.erase(FI);
|
||||
}
|
||||
|
||||
@ -4007,18 +4096,30 @@ bool LLParser::ParseMetadata(Metadata *&MD, PerFunctionState *PFS) {
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
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);
|
||||
@ -4140,11 +4241,11 @@ bool LLParser::parseConstantValue(Type *Ty, Constant *&C) {
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
@ -4985,7 +5086,7 @@ bool LLParser::ParseResume(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
|
||||
bool LLParser::ParseExceptionArgs(SmallVectorImpl<Value *> &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) {
|
||||
@ -5016,16 +5117,12 @@ bool LLParser::ParseExceptionArgs(SmallVectorImpl<Value *> &Args,
|
||||
}
|
||||
|
||||
/// 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;
|
||||
@ -5041,39 +5138,32 @@ bool LLParser::ParseCleanupRet(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
}
|
||||
}
|
||||
|
||||
Inst = CleanupReturnInst::Create(Context, RetVal, UnwindBB);
|
||||
Inst = CleanupReturnInst::Create(cast<CleanupPadInst>(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<CatchPadInst>(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<Value *, 8> Args;
|
||||
if (ParseType(RetType, /*AllowVoid=*/true) || ParseExceptionArgs(Args, PFS))
|
||||
if (ParseExceptionArgs(Args, PFS))
|
||||
return true;
|
||||
|
||||
BasicBlock *NormalBB, *UnwindBB;
|
||||
@ -5083,7 +5173,7 @@ bool LLParser::ParseCatchPad(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
ParseTypeAndBasicBlock(UnwindBB, PFS))
|
||||
return true;
|
||||
|
||||
Inst = CatchPadInst::Create(RetType, NormalBB, UnwindBB, Args);
|
||||
Inst = CatchPadInst::Create(NormalBB, UnwindBB, Args);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -5115,13 +5205,11 @@ bool LLParser::ParseTerminatePad(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
/// ParseCleanupPad
|
||||
/// ::= 'cleanuppad' ParamList
|
||||
bool LLParser::ParseCleanupPad(Instruction *&Inst, PerFunctionState &PFS) {
|
||||
Type *RetType = nullptr;
|
||||
|
||||
SmallVector<Value *, 8> 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;
|
||||
}
|
||||
|
||||
|
@ -108,6 +108,14 @@ namespace llvm {
|
||||
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<Instruction*, 64> InstsWithTBAATag;
|
||||
|
||||
// Type resolution handling data structures. The location is set when we
|
||||
@ -329,8 +337,10 @@ namespace llvm {
|
||||
/// 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.
|
||||
@ -352,12 +362,15 @@ namespace llvm {
|
||||
};
|
||||
|
||||
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) {
|
||||
|
@ -41,6 +41,14 @@ enum {
|
||||
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<WeakVH> ValuePtrs;
|
||||
|
||||
@ -84,9 +92,10 @@ public:
|
||||
}
|
||||
|
||||
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 @@ private:
|
||||
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 @@ private:
|
||||
/// past the number of slots used by the value in the record. Return true if
|
||||
/// there is an error.
|
||||
bool popValue(SmallVectorImpl<uint64_t> &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 @@ private:
|
||||
|
||||
/// Like popValue, but does not increment the Slot number.
|
||||
bool getValue(SmallVectorImpl<uint64_t> &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<uint64_t> &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<uint64_t> &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 @@ struct OperandTraits<ConstantPlaceHolder> :
|
||||
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 @@ void BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) {
|
||||
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 @@ void BitcodeReaderValueList::assignValue(Value *V, unsigned Idx) {
|
||||
} 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<CatchPadInst>(PrevVal)) {
|
||||
if (!isa<CatchPadInst>(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<CleanupPadInst>(PrevVal)) {
|
||||
if (!isa<CleanupPadInst>(V))
|
||||
return true;
|
||||
}
|
||||
OldV->replaceAllUsesWith(V);
|
||||
delete PrevVal;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@ -799,7 +829,8 @@ Constant *BitcodeReaderValueList::getConstantFwdRef(unsigned Idx,
|
||||
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 @@ Value *BitcodeReaderValueList::getValueFwdRef(unsigned Idx, Type *Ty) {
|
||||
// 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<CatchPadInst>(V);
|
||||
case OC_CleanupPad:
|
||||
return dyn_cast<CleanupPadInst>(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 @@ std::error_code BitcodeReader::parseConstants() {
|
||||
}
|
||||
}
|
||||
|
||||
ValueList.assignValue(V, NextCstNo);
|
||||
if (ValueList.assignValue(V, NextCstNo))
|
||||
return error("Invalid forward reference");
|
||||
++NextCstNo;
|
||||
}
|
||||
}
|
||||
@ -3819,56 +3876,47 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
|
||||
}
|
||||
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<CleanupPadInst>(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<CatchPadInst>(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 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
|
||||
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 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
|
||||
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<Value *, 2> Args;
|
||||
for (unsigned Op = 0; Op != NumArgOperands; ++Op) {
|
||||
@ -3936,7 +3981,7 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
|
||||
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 @@ std::error_code BitcodeReader::parseFunctionBody(Function *F) {
|
||||
|
||||
// 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:
|
||||
|
@ -1855,10 +1855,7 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
|
||||
case Instruction::CleanupRet: {
|
||||
Code = bitc::FUNC_CODE_INST_CLEANUPRET;
|
||||
const auto &CRI = cast<CleanupReturnInst>(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 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
|
||||
case Instruction::CatchRet: {
|
||||
Code = bitc::FUNC_CODE_INST_CATCHRET;
|
||||
const auto &CRI = cast<CatchReturnInst>(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<CatchPadInst>(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 @@ static void WriteInstruction(const Instruction &I, unsigned InstID,
|
||||
case Instruction::CleanupPad: {
|
||||
Code = bitc::FUNC_CODE_INST_CLEANUPPAD;
|
||||
const auto &CPI = cast<CleanupPadInst>(I);
|
||||
Vals.push_back(VE.getTypeID(CPI.getType()));
|
||||
unsigned NumOperands = CPI.getNumOperands();
|
||||
Vals.push_back(NumOperands);
|
||||
for (unsigned Op = 0; Op != NumOperands; ++Op)
|
||||
|
@ -2956,8 +2956,7 @@ static const BasicBlock *getEHPadFromPredecessor(const BasicBlock *BB) {
|
||||
if (isa<CatchPadInst>(TI) || isa<CatchEndPadInst>(TI) ||
|
||||
isa<TerminatePadInst>(TI))
|
||||
return BB;
|
||||
return cast<CleanupPadInst>(cast<CleanupReturnInst>(TI)->getReturnValue())
|
||||
->getParent();
|
||||
return cast<CleanupReturnInst>(TI)->getCleanupPad()->getParent();
|
||||
}
|
||||
|
||||
static void calculateExplicitStateNumbers(WinEHFuncInfo &FuncInfo,
|
||||
@ -3242,11 +3241,11 @@ bool WinEHPrepare::prepareExplicitEH(Function &F) {
|
||||
// The token consumed by a CatchReturnInst must match the funclet token.
|
||||
bool IsUnreachableCatchret = false;
|
||||
if (auto *CRI = dyn_cast<CatchReturnInst>(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<CleanupReturnInst>(TI))
|
||||
IsUnreachableCleanupret = CRI->getReturnValue() != CleanupPad;
|
||||
IsUnreachableCleanupret = CRI->getCleanupPad() != CleanupPad;
|
||||
if (IsUnreachableRet || IsUnreachableCatchret || IsUnreachableCleanupret) {
|
||||
new UnreachableInst(BB->getContext(), TI);
|
||||
TI->eraseFromParent();
|
||||
|
@ -2860,9 +2860,6 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
|
||||
writeOperand(LPI->getClause(i), true);
|
||||
}
|
||||
} else if (const auto *CPI = dyn_cast<CatchPadInst>(&I)) {
|
||||
Out << ' ';
|
||||
TypePrinter.print(I.getType(), Out);
|
||||
|
||||
Out << " [";
|
||||
for (unsigned Op = 0, NumOps = CPI->getNumArgOperands(); Op < NumOps;
|
||||
++Op) {
|
||||
@ -2888,9 +2885,6 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
|
||||
else
|
||||
Out << "to caller";
|
||||
} else if (const auto *CPI = dyn_cast<CleanupPadInst>(&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 @@ void AssemblyWriter::printInstruction(const Instruction &I) {
|
||||
} else if (isa<ReturnInst>(I) && !Operand) {
|
||||
Out << " void";
|
||||
} else if (const auto *CRI = dyn_cast<CatchReturnInst>(&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<CleanupReturnInst>(&I)) {
|
||||
if (CRI->hasReturnValue()) {
|
||||
Out << ' ';
|
||||
writeOperand(CRI->getReturnValue(), /*PrintType=*/true);
|
||||
} else {
|
||||
Out << " void";
|
||||
}
|
||||
Out << ' ';
|
||||
writeOperand(CRI->getCleanupPad(), /*PrintType=*/false);
|
||||
|
||||
Out << " unwind ";
|
||||
if (CRI->hasUnwindDest())
|
||||
|
@ -261,7 +261,7 @@ const char *Instruction::getOpcodeName(unsigned OpCode) {
|
||||
case ExtractValue: return "extractvalue";
|
||||
case InsertValue: return "insertvalue";
|
||||
case LandingPad: return "landingpad";
|
||||
case CleanupPad: return "cleanuppad";
|
||||
case CleanupPad: return "cleanuppad";
|
||||
|
||||
default: return "<Invalid operator> ";
|
||||
}
|
||||
|
@ -684,51 +684,39 @@ CleanupReturnInst::CleanupReturnInst(const CleanupReturnInst &CRI)
|
||||
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<CleanupReturnInst>::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<CleanupReturnInst>::op_end(this) - Values,
|
||||
Values, InsertAtEnd) {
|
||||
init(RetVal, UnwindBB);
|
||||
}
|
||||
|
||||
BasicBlock *CleanupReturnInst::getUnwindDest() const {
|
||||
if (hasUnwindDest())
|
||||
return cast<BasicBlock>(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 @@ void CatchEndPadInst::setSuccessorV(unsigned Idx, BasicBlock *B) {
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 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<CatchReturnInst>::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<CatchReturnInst>::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<CatchReturnInst>::op_end(this) - Values,
|
||||
Values, InsertBefore) {
|
||||
init(BB, RetVal);
|
||||
OperandTraits<CatchReturnInst>::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<CatchReturnInst>::op_end(this) - Values,
|
||||
Values, InsertAtEnd) {
|
||||
init(BB, RetVal);
|
||||
OperandTraits<CatchReturnInst>::op_begin(this), 2,
|
||||
InsertAtEnd) {
|
||||
init(CatchPad, BB);
|
||||
}
|
||||
|
||||
BasicBlock *CatchReturnInst::getSuccessorV(unsigned Idx) const {
|
||||
@ -863,21 +845,21 @@ CatchPadInst::CatchPadInst(const CatchPadInst &CPI)
|
||||
std::copy(CPI.op_begin(), CPI.op_end(), op_begin());
|
||||
}
|
||||
|
||||
CatchPadInst::CatchPadInst(Type *RetTy, BasicBlock *IfNormal,
|
||||
BasicBlock *IfException, ArrayRef<Value *> Args,
|
||||
unsigned Values, const Twine &NameStr,
|
||||
Instruction *InsertBefore)
|
||||
: TerminatorInst(RetTy, Instruction::CatchPad,
|
||||
CatchPadInst::CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException,
|
||||
ArrayRef<Value *> Args, unsigned Values,
|
||||
const Twine &NameStr, Instruction *InsertBefore)
|
||||
: TerminatorInst(Type::getTokenTy(IfNormal->getContext()),
|
||||
Instruction::CatchPad,
|
||||
OperandTraits<CatchPadInst>::op_end(this) - Values, Values,
|
||||
InsertBefore) {
|
||||
init(IfNormal, IfException, Args, NameStr);
|
||||
}
|
||||
|
||||
CatchPadInst::CatchPadInst(Type *RetTy, BasicBlock *IfNormal,
|
||||
BasicBlock *IfException, ArrayRef<Value *> Args,
|
||||
unsigned Values, const Twine &NameStr,
|
||||
BasicBlock *InsertAtEnd)
|
||||
: TerminatorInst(RetTy, Instruction::CatchPad,
|
||||
CatchPadInst::CatchPadInst(BasicBlock *IfNormal, BasicBlock *IfException,
|
||||
ArrayRef<Value *> Args, unsigned Values,
|
||||
const Twine &NameStr, BasicBlock *InsertAtEnd)
|
||||
: TerminatorInst(Type::getTokenTy(IfNormal->getContext()),
|
||||
Instruction::CatchPad,
|
||||
OperandTraits<CatchPadInst>::op_end(this) - Values, Values,
|
||||
InsertAtEnd) {
|
||||
init(IfNormal, IfException, Args, NameStr);
|
||||
@ -962,17 +944,17 @@ CleanupPadInst::CleanupPadInst(const CleanupPadInst &CPI)
|
||||
std::copy(CPI.op_begin(), CPI.op_end(), op_begin());
|
||||
}
|
||||
|
||||
CleanupPadInst::CleanupPadInst(Type *RetTy, ArrayRef<Value *> Args,
|
||||
CleanupPadInst::CleanupPadInst(LLVMContext &C, ArrayRef<Value *> Args,
|
||||
const Twine &NameStr, Instruction *InsertBefore)
|
||||
: Instruction(RetTy, Instruction::CleanupPad,
|
||||
: Instruction(Type::getTokenTy(C), Instruction::CleanupPad,
|
||||
OperandTraits<CleanupPadInst>::op_end(this) - Args.size(),
|
||||
Args.size(), InsertBefore) {
|
||||
init(Args, NameStr);
|
||||
}
|
||||
|
||||
CleanupPadInst::CleanupPadInst(Type *RetTy, ArrayRef<Value *> Args,
|
||||
CleanupPadInst::CleanupPadInst(LLVMContext &C, ArrayRef<Value *> Args,
|
||||
const Twine &NameStr, BasicBlock *InsertAtEnd)
|
||||
: Instruction(RetTy, Instruction::CleanupPad,
|
||||
: Instruction(Type::getTokenTy(C), Instruction::CleanupPad,
|
||||
OperandTraits<CleanupPadInst>::op_end(this) - Args.size(),
|
||||
Args.size(), InsertAtEnd) {
|
||||
init(Args, NameStr);
|
||||
|
@ -184,12 +184,6 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
|
||||
/// \brief Track unresolved string-based type references.
|
||||
SmallDenseMap<const MDString *, const MDNode *, 32> 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 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
|
||||
|
||||
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 @@ public:
|
||||
// FIXME: We strip const here because the inst visitor strips const.
|
||||
visit(const_cast<Function &>(F));
|
||||
InstsInThisBlock.clear();
|
||||
CatchPadResultTy = nullptr;
|
||||
CleanupPadResultTy = nullptr;
|
||||
LandingPadResultTy = nullptr;
|
||||
SawFrameEscape = false;
|
||||
|
||||
@ -2877,14 +2868,6 @@ void Verifier::visitLandingPadInst(LandingPadInst &LPI) {
|
||||
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 @@ void Verifier::visitCatchPadInst(CatchPadInst &CPI) {
|
||||
"CatchPadInst not the first non-PHI instruction in the block.",
|
||||
&CPI);
|
||||
|
||||
if (!BB->getSinglePredecessor())
|
||||
for (BasicBlock *PredBB : predecessors(BB)) {
|
||||
Assert(!isa<CatchPadInst>(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 @@ void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) {
|
||||
|
||||
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 @@ void Verifier::visitCleanupPadInst(CleanupPadInst &CPI) {
|
||||
"CleanupPadInst not the first non-PHI instruction in the block.",
|
||||
&CPI);
|
||||
|
||||
CleanupReturnInst *FirstCRI = nullptr;
|
||||
for (User *U : CPI.users())
|
||||
if (CleanupReturnInst *CRI = dyn_cast<CleanupReturnInst>(U)) {
|
||||
if (!FirstCRI)
|
||||
FirstCRI = CRI;
|
||||
else
|
||||
Assert(CRI->getUnwindDest() == FirstCRI->getUnwindDest(),
|
||||
"Cleanuprets from same cleanuppad have different exceptional "
|
||||
"successors.",
|
||||
FirstCRI, CRI);
|
||||
}
|
||||
|
||||
visitInstruction(CPI);
|
||||
}
|
||||
|
||||
|
@ -2674,17 +2674,13 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
@ -344,8 +344,7 @@ static void HandleInlinedEHPad(InvokeInst *II, BasicBlock *FirstNewBlock,
|
||||
|
||||
if (auto *CRI = dyn_cast<CleanupReturnInst>(BB->getTerminator())) {
|
||||
if (CRI->unwindsToCaller()) {
|
||||
CleanupReturnInst::Create(CRI->getContext(), CRI->getReturnValue(),
|
||||
UnwindDest, CRI);
|
||||
CleanupReturnInst::Create(CRI->getCleanupPad(), UnwindDest, CRI);
|
||||
CRI->eraseFromParent();
|
||||
UpdatePHINodes(BB);
|
||||
}
|
||||
|
59
test/Assembler/invalid-OperatorConstraint.ll
Normal file
59
test/Assembler/invalid-OperatorConstraint.ll
Normal file
@ -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: }
|
@ -36,14 +36,14 @@ merge:
|
||||
; 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 @@ right:
|
||||
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 @@ catch.inner:
|
||||
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 @@ catch.outer:
|
||||
; 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 @@ entry:
|
||||
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 @@ merge:
|
||||
; 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 @@ right:
|
||||
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 @@ join:
|
||||
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 @@ invoke.cont:
|
||||
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 @@ merge:
|
||||
; 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 @@ invoke.cont2:
|
||||
|
||||
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 @@ entry:
|
||||
; 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 @@ cleanup:
|
||||
; 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 @@ invoke.cont:
|
||||
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 @@ left:
|
||||
; 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 @@ right:
|
||||
; 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 @@ done:
|
||||
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
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ entry:
|
||||
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 @@ catch: ; preds = %catch.dispatch
|
||||
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 @@ catch.3: ; preds = %catch.dispatch.1
|
||||
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:
|
||||
|
@ -28,60 +28,100 @@ declare i32 @__gxx_personality_v0(...)
|
||||
|
||||
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 @catchret() personality i32 (...)* @__gxx_personality_v0 {
|
||||
define void @catchret0() 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
|
||||
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
|
||||
}
|
||||
|
||||
; forward ref by name
|
||||
define void @catchret1() personality i32 (...)* @__gxx_personality_v0 {
|
||||
entry:
|
||||
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
|
||||
}
|
||||
|
||||
; forward ref by ID
|
||||
define void @catchret2() personality i32 (...)* @__gxx_personality_v0 {
|
||||
entry:
|
||||
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
|
||||
}
|
||||
|
||||
define i8 @catchpad() personality i32 (...)* @__gxx_personality_v0 {
|
||||
entry:
|
||||
br label %try.cont
|
||||
|
||||
try.cont:
|
||||
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 @@ try.cont:
|
||||
invoke void @_Z3quxv() optsize
|
||||
to label %try.cont unwind label %bb
|
||||
bb:
|
||||
cleanuppad void [i7 4]
|
||||
cleanuppad [i7 4]
|
||||
ret void
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user