From 5fc28718204a2def3e7998cf23321236c225d6e4 Mon Sep 17 00:00:00 2001 From: Daniel Dunbar Date: Wed, 12 Nov 2008 08:21:33 +0000 Subject: [PATCH] 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 --- clang/lib/CodeGen/CGStmt.cpp | 98 ++++++++++++++++++----------- clang/lib/CodeGen/CodeGenFunction.h | 16 ++++- 2 files changed, 76 insertions(+), 38 deletions(-) diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp index 88da20d4e829..e40508669abb 100644 --- a/clang/lib/CodeGen/CGStmt.cpp +++ b/clang/lib/CodeGen/CGStmt.cpp @@ -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(*S)); break; - case Stmt::LabelStmtClass: EmitLabelStmt(cast(*S)); break; - case Stmt::GotoStmtClass: EmitGotoStmt(cast(*S)); break; case Stmt::IndirectGotoStmtClass: EmitIndirectGotoStmt(cast(*S)); break; @@ -73,28 +75,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) { case Stmt::ReturnStmtClass: EmitReturnStmt(cast(*S)); break; case Stmt::DeclStmtClass: EmitDeclStmt(cast(*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(*S)); break; - case Stmt::DefaultStmtClass: EmitDefaultStmt(cast(*S)); break; - case Stmt::CaseStmtClass: EmitCaseStmt(cast(*S)); break; case Stmt::AsmStmtClass: EmitAsmStmt(cast(*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(*S)); break; + case Stmt::LabelStmtClass: EmitLabelStmt(cast(*S)); break; + case Stmt::GotoStmtClass: EmitGotoStmt(cast(*S)); break; + case Stmt::BreakStmtClass: EmitBreakStmt(cast(*S)); break; + case Stmt::ContinueStmtClass: EmitContinueStmt(cast(*S)); break; + case Stmt::DefaultStmtClass: EmitDefaultStmt(cast(*S)); break; + case Stmt::CaseStmtClass: EmitCaseStmt(cast(*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. diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index d867c3f380ea..3489b782398e 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -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);