IRgen improvements on unreachable code:

- Split out "simple" statements which can easily handle IR generation
   when there is no insert point. These are generally statements which
   start by emitting a new block or are only containers for other
   statements.

 - This fixes a regression in emitting dummy blocks, notably for case
   statements.

 - This also fixes spurious emission of a number of debug stoppoint
   intrinsic instructions.

Remove unneeded sw.body block, just clear the insertion point.

Lift out CodeGenFunction::EmitStopPoint which calls into the
CGDebugInfo class when generating debug info.

Normalize definitions of Emit{Break,Continue}Stmt and usage of
ErrorUnsupported.

llvm-svn: 59118
This commit is contained in:
Daniel Dunbar 2008-11-12 08:21:33 +00:00
parent 45d030a05a
commit 5fc2871820
2 changed files with 76 additions and 38 deletions

View File

@ -25,9 +25,21 @@ using namespace CodeGen;
// Statement Emission
//===----------------------------------------------------------------------===//
void CodeGenFunction::EmitStopPoint(const Stmt *S) {
if (CGDebugInfo *DI = CGM.getDebugInfo()) {
DI->setLocation(S->getLocStart());
DI->EmitStopPoint(CurFn, Builder);
}
}
void CodeGenFunction::EmitStmt(const Stmt *S) {
assert(S && "Null statement?");
// Check if we can handle this without bothering to generate an
// insert point or debug info.
if (EmitSimpleStmt(S))
return;
// If we happen to be at an unreachable point just create a dummy
// basic block to hold the code. We could change parts of irgen to
// simply not generate this code, but this situation is rare and
@ -35,14 +47,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
// FIXME: Verify previous performance/effort claim.
EnsureInsertPoint();
// Generate stoppoints if we are emitting debug info.
// Beginning of a Compound Statement (e.g. an opening '{') does not produce
// executable code. So do not generate a stoppoint for that.
CGDebugInfo *DI = CGM.getDebugInfo();
if (DI && S->getStmtClass() != Stmt::CompoundStmtClass) {
DI->setLocation(S->getLocStart());
DI->EmitStopPoint(CurFn, Builder);
}
// Generate a stoppoint if we are emitting debug info.
EmitStopPoint(S);
switch (S->getStmtClass()) {
default:
@ -59,10 +65,6 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
ErrorUnsupported(S, "statement");
}
break;
case Stmt::NullStmtClass: break;
case Stmt::CompoundStmtClass: EmitCompoundStmt(cast<CompoundStmt>(*S)); break;
case Stmt::LabelStmtClass: EmitLabelStmt(cast<LabelStmt>(*S)); break;
case Stmt::GotoStmtClass: EmitGotoStmt(cast<GotoStmt>(*S)); break;
case Stmt::IndirectGotoStmtClass:
EmitIndirectGotoStmt(cast<IndirectGotoStmt>(*S)); break;
@ -73,28 +75,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
case Stmt::DeclStmtClass: EmitDeclStmt(cast<DeclStmt>(*S)); break;
case Stmt::BreakStmtClass:
// FIXME: Implement break in @try or @catch blocks.
if (!ObjCEHStack.empty()) {
CGM.ErrorUnsupported(S, "continue inside an Obj-C exception block");
return;
}
EmitBreakStmt();
break;
case Stmt::ContinueStmtClass:
// FIXME: Implement continue in @try or @catch blocks.
if (!ObjCEHStack.empty()) {
CGM.ErrorUnsupported(S, "continue inside an Obj-C exception block");
return;
}
EmitContinueStmt();
break;
case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
case Stmt::DefaultStmtClass: EmitDefaultStmt(cast<DefaultStmt>(*S)); break;
case Stmt::CaseStmtClass: EmitCaseStmt(cast<CaseStmt>(*S)); break;
case Stmt::AsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
case Stmt::ObjCAtTryStmtClass:
@ -118,6 +100,22 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
}
}
bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) {
switch (S->getStmtClass()) {
default: return false;
case Stmt::NullStmtClass: break;
case Stmt::CompoundStmtClass: EmitCompoundStmt(cast<CompoundStmt>(*S)); break;
case Stmt::LabelStmtClass: EmitLabelStmt(cast<LabelStmt>(*S)); break;
case Stmt::GotoStmtClass: EmitGotoStmt(cast<GotoStmt>(*S)); break;
case Stmt::BreakStmtClass: EmitBreakStmt(cast<BreakStmt>(*S)); break;
case Stmt::ContinueStmtClass: EmitContinueStmt(cast<ContinueStmt>(*S)); break;
case Stmt::DefaultStmtClass: EmitDefaultStmt(cast<DefaultStmt>(*S)); break;
case Stmt::CaseStmtClass: EmitCaseStmt(cast<CaseStmt>(*S)); break;
}
return true;
}
/// EmitCompoundStmt - Emit a compound statement {..} node. If GetLast is true,
/// this captures the expression result of the last sub-statement and returns it
/// (for use by the statement expression extension).
@ -126,6 +124,7 @@ RValue CodeGenFunction::EmitCompoundStmt(const CompoundStmt &S, bool GetLast,
// FIXME: handle vla's etc.
CGDebugInfo *DI = CGM.getDebugInfo();
if (DI) {
EnsureInsertPoint();
DI->setLocation(S.getLBracLoc());
DI->EmitRegionStart(CurFn, Builder);
}
@ -200,6 +199,11 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
return;
}
// If this code is reachable then emit a stop point (if generating
// debug info). We have to do this ourselves because we are on the
// "simple" statement path.
if (HaveInsertPoint())
EmitStopPoint(&S);
EmitBranch(getBasicBlockForLabel(S.getLabel()));
}
@ -485,16 +489,38 @@ void CodeGenFunction::EmitDeclStmt(const DeclStmt &S) {
EmitDecl(**I);
}
void CodeGenFunction::EmitBreakStmt() {
void CodeGenFunction::EmitBreakStmt(const BreakStmt &S) {
assert(!BreakContinueStack.empty() && "break stmt not in a loop or switch!");
// FIXME: Implement break in @try or @catch blocks.
if (!ObjCEHStack.empty()) {
CGM.ErrorUnsupported(&S, "continue inside an Obj-C exception block");
return;
}
// If this code is reachable then emit a stop point (if generating
// debug info). We have to do this ourselves because we are on the
// "simple" statement path.
if (HaveInsertPoint())
EmitStopPoint(&S);
llvm::BasicBlock *Block = BreakContinueStack.back().BreakBlock;
EmitBranch(Block);
}
void CodeGenFunction::EmitContinueStmt() {
void CodeGenFunction::EmitContinueStmt(const ContinueStmt &S) {
assert(!BreakContinueStack.empty() && "continue stmt not in a loop!");
// FIXME: Implement continue in @try or @catch blocks.
if (!ObjCEHStack.empty()) {
CGM.ErrorUnsupported(&S, "continue inside an Obj-C exception block");
return;
}
// If this code is reachable then emit a stop point (if generating
// debug info). We have to do this ourselves because we are on the
// "simple" statement path.
if (HaveInsertPoint())
EmitStopPoint(&S);
llvm::BasicBlock *Block = BreakContinueStack.back().ContinueBlock;
EmitBranch(Block);
}
@ -595,8 +621,8 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
SwitchInsn = Builder.CreateSwitch(CondV, DefaultBlock);
CaseRangeBlock = DefaultBlock;
// Create basic block for body of switch
EmitBlock(createBasicBlock("sw.body"));
// Clear the insertion point to indicate we are in unreachable code.
Builder.ClearInsertionPoint();
// All break statements jump to NextBlock. If BreakContinueStack is non empty
// then reuse last ContinueBlock.

View File

@ -346,6 +346,10 @@ public:
// Statement Emission
//===--------------------------------------------------------------------===//
/// EmitStopPoint - Emit a debug stoppoint if we are emitting debug
/// info.
void EmitStopPoint(const Stmt *S);
/// EmitStmt - Emit the code for the statement \arg S. It is legal
/// to call this function even if there is no current insertion
/// point.
@ -356,6 +360,14 @@ public:
/// EmitStmt.
void EmitStmt(const Stmt *S);
/// EmitSimpleStmt - Try to emit a "simple" statement which does not
/// necessarily require an insertion point or debug information;
/// typically because the statement amounts to a jump or a container
/// of other statements.
///
/// \return True if the statement was handled.
bool EmitSimpleStmt(const Stmt *S);
RValue EmitCompoundStmt(const CompoundStmt &S, bool GetLast = false,
llvm::Value *AggLoc = 0, bool isAggVol = false);
@ -373,8 +385,8 @@ public:
void EmitForStmt(const ForStmt &S);
void EmitReturnStmt(const ReturnStmt &S);
void EmitDeclStmt(const DeclStmt &S);
void EmitBreakStmt();
void EmitContinueStmt();
void EmitBreakStmt(const BreakStmt &S);
void EmitContinueStmt(const ContinueStmt &S);
void EmitSwitchStmt(const SwitchStmt &S);
void EmitDefaultStmt(const DefaultStmt &S);
void EmitCaseStmt(const CaseStmt &S);