Address Joseph's review comments.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@241890 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
David Majnemer
2015-07-10 07:01:03 +00:00
parent a5d05b7711
commit 2431442e67
5 changed files with 92 additions and 13 deletions

View File

@@ -4730,6 +4730,7 @@ The terminator instructions are: ':ref:`ret <i_ret>`',
':ref:`resume <i_resume>`', ':ref:`catchblock <i_catchblock>`', ':ref:`resume <i_resume>`', ':ref:`catchblock <i_catchblock>`',
':ref:`catchendblock <i_catchendblock>`', ':ref:`catchendblock <i_catchendblock>`',
':ref:`catchret <i_catchret>`', ':ref:`catchret <i_catchret>`',
':ref:`cleanupret <i_cleanupret>`',
':ref:`terminateblock <i_terminateblock>`', ':ref:`terminateblock <i_terminateblock>`',
and ':ref:`unreachable <i_unreachable>`'. and ':ref:`unreachable <i_unreachable>`'.
@@ -5143,6 +5144,8 @@ The ``catchblock`` instruction has several restrictions:
an exceptional instruction. an exceptional instruction.
- A catch block must have a '``catchblock``' instruction as its - A catch block must have a '``catchblock``' instruction as its
first non-PHI instruction. first non-PHI instruction.
- A catch block's ``exception`` edge must refer to a catch block or a
catch-end block.
- There can be only one '``catchblock``' instruction within the - There can be only one '``catchblock``' instruction within the
catch block. catch block.
- A basic block that is not a catch block may not include a - A basic block that is not a catch block may not include a
@@ -5252,15 +5255,17 @@ Semantics:
The '``catchret``' instruction ends the existing (in-flight) exception The '``catchret``' instruction ends the existing (in-flight) exception
whose unwinding was interrupted with a whose unwinding was interrupted with a
:ref:`catchblock <i_catchblock>` instruction and transfers control to :ref:`catchblock <i_catchblock>` instruction.
``normal``. The :ref:`personality function <personalityfn>` gets a chance to execute
arbitrary code to, for example, run a C++ destructor.
Control then transfers to ``normal``.
Example: Example:
"""""""" """"""""
.. code-block:: llvm .. code-block:: llvm
catchret unwind label %continue catchret label %continue
.. _i_cleanupret: .. _i_cleanupret:
@@ -5293,8 +5298,8 @@ Semantics:
"""""""""" """"""""""
The '``cleanupret``' instruction indicates to the The '``cleanupret``' instruction indicates to the
:ref:`personality function <personalityfn>` that the :ref:`personality function <personalityfn>` that one
:ref:`cleanupblock <i_cleanupblock>` it transfered control to has ended. :ref:`cleanupblock <i_cleanupblock>` it transferred control to has ended.
It transfers control to ``continue`` or unwinds out of the function. It transfers control to ``continue`` or unwinds out of the function.
Example: Example:
@@ -5327,7 +5332,7 @@ is a terminate block --- one where a personality routine may decide to
terminate the program. terminate the program.
The ``args`` correspond to whatever information the personality The ``args`` correspond to whatever information the personality
routine requires to know if this is an appropriate place to terminate the routine requires to know if this is an appropriate place to terminate the
program. Control is tranfered to the ``exception`` label if the program. Control is transferred to the ``exception`` label if the
personality routine decides not to terminate the program for the personality routine decides not to terminate the program for the
in-flight exception. in-flight exception.
@@ -8339,8 +8344,7 @@ transfer control to run cleanup actions.
The ``args`` correspond to whatever additional The ``args`` correspond to whatever additional
information the :ref:`personality function <personalityfn>` requires to information the :ref:`personality function <personalityfn>` requires to
execute the cleanup. execute the cleanup.
:ref:`personality function <personalityfn>` upon re-entry to the The ``resultval`` has the type ``resultty``.
function. The ``resultval`` has the type ``resultty``.
Arguments: Arguments:
"""""""""" """"""""""

View File

@@ -3805,12 +3805,12 @@ public:
void setUnwindDest(BasicBlock *B) { Op<-1>() = reinterpret_cast<Value *>(B); } void setUnwindDest(BasicBlock *B) { Op<-1>() = reinterpret_cast<Value *>(B); }
BasicBlock *getSuccessor(unsigned i) const { BasicBlock *getSuccessor(unsigned i) const {
assert(i < 2 && "Successor # out of range for invoke!"); assert(i < 2 && "Successor # out of range for catchblock!");
return i == 0 ? getNormalDest() : getUnwindDest(); return i == 0 ? getNormalDest() : getUnwindDest();
} }
void setSuccessor(unsigned idx, BasicBlock *NewSucc) { void setSuccessor(unsigned idx, BasicBlock *NewSucc) {
assert(idx < 2 && "Successor # out of range for invoke!"); assert(idx < 2 && "Successor # out of range for catchblock!");
*(&Op<-2>() + idx) = reinterpret_cast<Value *>(NewSucc); *(&Op<-2>() + idx) = reinterpret_cast<Value *>(NewSucc);
} }

View File

@@ -4994,7 +4994,7 @@ bool LLParser::ParseTerminateBlock(Instruction *&Inst, PerFunctionState &PFS) {
BasicBlock *UnwindBB = nullptr; BasicBlock *UnwindBB = nullptr;
if (Lex.getKind() == lltok::kw_to) { if (Lex.getKind() == lltok::kw_to) {
Lex.Lex(); Lex.Lex();
if (ParseToken(lltok::kw_caller, "expected 'caller' in cleanupret")) if (ParseToken(lltok::kw_caller, "expected 'caller' in terminateblock"))
return true; return true;
} else { } else {
if (ParseTypeAndBasicBlock(UnwindBB, PFS)) { if (ParseTypeAndBasicBlock(UnwindBB, PFS)) {
@@ -5022,7 +5022,7 @@ bool LLParser::ParseCleanupBlock(Instruction *&Inst, PerFunctionState &PFS) {
/// ParseCatchEndBlock /// ParseCatchEndBlock
/// ::= 'catchendblock' unwind ('to' 'caller' | TypeAndValue) /// ::= 'catchendblock' unwind ('to' 'caller' | TypeAndValue)
bool LLParser::ParseCatchEndBlock(Instruction *&Inst, PerFunctionState &PFS) { bool LLParser::ParseCatchEndBlock(Instruction *&Inst, PerFunctionState &PFS) {
if (ParseToken(lltok::kw_unwind, "expected 'unwind' in cleanupret")) if (ParseToken(lltok::kw_unwind, "expected 'unwind' in catchendblock"))
return true; return true;
BasicBlock *UnwindBB = nullptr; BasicBlock *UnwindBB = nullptr;

View File

@@ -469,6 +469,8 @@ bool Instruction::mayThrow() const {
return CRI->unwindsToCaller(); return CRI->unwindsToCaller();
if (const auto *CEBI = dyn_cast<CatchEndBlockInst>(this)) if (const auto *CEBI = dyn_cast<CatchEndBlockInst>(this))
return CEBI->unwindsToCaller(); return CEBI->unwindsToCaller();
if (const auto *TBI = dyn_cast<TerminateBlockInst>(this))
return TBI->unwindsToCaller();
return isa<ResumeInst>(this); return isa<ResumeInst>(this);
} }

View File

@@ -184,6 +184,9 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
/// \brief Track unresolved string-based type references. /// \brief Track unresolved string-based type references.
SmallDenseMap<const MDString *, const MDNode *, 32> UnresolvedTypeRefs; SmallDenseMap<const MDString *, const MDNode *, 32> UnresolvedTypeRefs;
/// \brief The result value from the personality function.
Type *PersonalityFnResultTy;
/// \brief Whether we've seen a call to @llvm.localescape in this function /// \brief Whether we've seen a call to @llvm.localescape in this function
/// already. /// already.
bool SawFrameEscape; bool SawFrameEscape;
@@ -194,7 +197,8 @@ class Verifier : public InstVisitor<Verifier>, VerifierSupport {
public: public:
explicit Verifier(raw_ostream &OS) explicit Verifier(raw_ostream &OS)
: VerifierSupport(OS), Context(nullptr), SawFrameEscape(false) {} : VerifierSupport(OS), Context(nullptr), PersonalityFnResultTy(nullptr),
SawFrameEscape(false) {}
bool verify(const Function &F) { bool verify(const Function &F) {
M = F.getParent(); M = F.getParent();
@@ -228,6 +232,7 @@ public:
// FIXME: We strip const here because the inst visitor strips const. // FIXME: We strip const here because the inst visitor strips const.
visit(const_cast<Function &>(F)); visit(const_cast<Function &>(F));
InstsInThisBlock.clear(); InstsInThisBlock.clear();
PersonalityFnResultTy = nullptr;
SawFrameEscape = false; SawFrameEscape = false;
return !Broken; return !Broken;
@@ -383,6 +388,7 @@ private:
void visitCatchBlockInst(CatchBlockInst &CBI); void visitCatchBlockInst(CatchBlockInst &CBI);
void visitCatchEndBlockInst(CatchEndBlockInst &CEBI); void visitCatchEndBlockInst(CatchEndBlockInst &CEBI);
void visitCleanupBlockInst(CleanupBlockInst &CBI); void visitCleanupBlockInst(CleanupBlockInst &CBI);
void visitCleanupReturnInst(CleanupReturnInst &CRI);
void visitTerminateBlockInst(TerminateBlockInst &TBI); void visitTerminateBlockInst(TerminateBlockInst &TBI);
void VerifyCallSite(CallSite CS); void VerifyCallSite(CallSite CS);
@@ -2799,6 +2805,14 @@ void Verifier::visitLandingPadInst(LandingPadInst &LPI) {
&LPI); &LPI);
} }
if (!PersonalityFnResultTy)
PersonalityFnResultTy = LPI.getType();
else
Assert(PersonalityFnResultTy == LPI.getType(),
"The personality routine should have a consistent result type "
"inside a function.",
&LPI);
Function *F = LPI.getParent()->getParent(); Function *F = LPI.getParent()->getParent();
Assert(F->hasPersonalityFn(), Assert(F->hasPersonalityFn(),
"LandingPadInst needs to be in a function with a personality.", &LPI); "LandingPadInst needs to be in a function with a personality.", &LPI);
@@ -2827,6 +2841,14 @@ void Verifier::visitLandingPadInst(LandingPadInst &LPI) {
void Verifier::visitCatchBlockInst(CatchBlockInst &CBI) { void Verifier::visitCatchBlockInst(CatchBlockInst &CBI) {
BasicBlock *BB = CBI.getParent(); BasicBlock *BB = CBI.getParent();
if (!PersonalityFnResultTy)
PersonalityFnResultTy = CBI.getType();
else
Assert(PersonalityFnResultTy == CBI.getType(),
"The personality routine should have a consistent result type "
"inside a function.",
&CBI);
Function *F = BB->getParent(); Function *F = BB->getParent();
Assert(F->hasPersonalityFn(), Assert(F->hasPersonalityFn(),
"CatchBlockInst needs to be in a function with a personality.", &CBI); "CatchBlockInst needs to be in a function with a personality.", &CBI);
@@ -2837,6 +2859,12 @@ void Verifier::visitCatchBlockInst(CatchBlockInst &CBI) {
"CatchBlockInst not the first non-PHI instruction in the block.", "CatchBlockInst not the first non-PHI instruction in the block.",
&CBI); &CBI);
BasicBlock *UnwindDest = CBI.getUnwindDest();
Instruction *I = UnwindDest->getFirstNonPHI();
Assert(I->isEHBlock() && !isa<LandingPadInst>(I),
"CatchBlockInst must unwind to an EH block which is not a landingpad.",
&CBI);
visitTerminatorInst(CBI); visitTerminatorInst(CBI);
} }
@@ -2854,12 +2882,37 @@ void Verifier::visitCatchEndBlockInst(CatchEndBlockInst &CEBI) {
"CatchEndBlockInst not the first non-PHI instruction in the block.", "CatchEndBlockInst not the first non-PHI instruction in the block.",
&CEBI); &CEBI);
unsigned CatchBlocksSeen = 0;
for (BasicBlock *PredBB : predecessors(BB))
if (isa<CatchBlockInst>(PredBB->getTerminator()))
++CatchBlocksSeen;
Assert(CatchBlocksSeen <= 1, "CatchEndBlockInst must have no more than one "
"CatchBlockInst predecessor.",
&CEBI);
if (BasicBlock *UnwindDest = CEBI.getUnwindDest()) {
Instruction *I = UnwindDest->getFirstNonPHI();
Assert(
I->isEHBlock() && !isa<LandingPadInst>(I),
"CatchEndBlock must unwind to an EH block which is not a landingpad.",
&CEBI);
}
visitTerminatorInst(CEBI); visitTerminatorInst(CEBI);
} }
void Verifier::visitCleanupBlockInst(CleanupBlockInst &CBI) { void Verifier::visitCleanupBlockInst(CleanupBlockInst &CBI) {
BasicBlock *BB = CBI.getParent(); BasicBlock *BB = CBI.getParent();
if (!PersonalityFnResultTy)
PersonalityFnResultTy = CBI.getType();
else
Assert(PersonalityFnResultTy == CBI.getType(),
"The personality routine should have a consistent result type "
"inside a function.",
&CBI);
Function *F = BB->getParent(); Function *F = BB->getParent();
Assert(F->hasPersonalityFn(), Assert(F->hasPersonalityFn(),
"CleanupBlockInst needs to be in a function with a personality.", &CBI); "CleanupBlockInst needs to be in a function with a personality.", &CBI);
@@ -2873,6 +2926,18 @@ void Verifier::visitCleanupBlockInst(CleanupBlockInst &CBI) {
visitInstruction(CBI); visitInstruction(CBI);
} }
void Verifier::visitCleanupReturnInst(CleanupReturnInst &CRI) {
if (BasicBlock *UnwindDest = CRI.getUnwindDest()) {
Instruction *I = UnwindDest->getFirstNonPHI();
Assert(I->isEHBlock() && !isa<LandingPadInst>(I),
"CleanupReturnInst must unwind to an EH block which is not a "
"landingpad.",
&CRI);
}
visitTerminatorInst(CRI);
}
void Verifier::visitTerminateBlockInst(TerminateBlockInst &TBI) { void Verifier::visitTerminateBlockInst(TerminateBlockInst &TBI) {
BasicBlock *BB = TBI.getParent(); BasicBlock *BB = TBI.getParent();
@@ -2887,6 +2952,14 @@ void Verifier::visitTerminateBlockInst(TerminateBlockInst &TBI) {
"TerminateBlockInst not the first non-PHI instruction in the block.", "TerminateBlockInst not the first non-PHI instruction in the block.",
&TBI); &TBI);
if (BasicBlock *UnwindDest = TBI.getUnwindDest()) {
Instruction *I = UnwindDest->getFirstNonPHI();
Assert(I->isEHBlock() && !isa<LandingPadInst>(I),
"TerminateBlockInst must unwind to an EH block which is not a "
"landingpad.",
&TBI);
}
visitTerminatorInst(TBI); visitTerminatorInst(TBI);
} }