Avoid generation of dead code in a few more situations.

- Emit variable declarations as "simple", we want to avoid forcing the creation
   of a dummy basic block, but still need to make the variable available for
   later use.

 - With that, we can now skip IRgen for other unreachable statements (which
   don't define a label).

 - Anders, I added two fixmes on calls to EmitVLASize, can you check them?

llvm-svn: 76361
This commit is contained in:
Daniel Dunbar 2009-07-19 06:58:07 +00:00
parent 567daf3ce8
commit b6adc43f6e
5 changed files with 92 additions and 15 deletions

View File

@ -112,7 +112,6 @@ CodeGenFunction::CreateStaticBlockVarDecl(const VarDecl &D,
}
void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
llvm::Value *&DMEntry = LocalDeclMap[&D];
assert(DMEntry == 0 && "Decl already exists in localdeclmap!");
@ -124,6 +123,8 @@ void CodeGenFunction::EmitStaticBlockVarDecl(const VarDecl &D) {
DMEntry = GV;
// Make sure to evaluate VLA bounds now so that we have them for later.
//
// FIXME: Can this happen?
if (D.getType()->isVariablyModifiedType())
EmitVLASize(D.getType());
@ -274,9 +275,12 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
::InternalLinkage);
}
// FIXME: Can this happen?
if (Ty->isVariablyModifiedType())
EmitVLASize(Ty);
} else {
EnsureInsertPoint();
if (!DidCallStackSave) {
// Save the stack.
const llvm::Type *LTy =
@ -321,6 +325,11 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
// Emit debug info for local var declaration.
if (CGDebugInfo *DI = getDebugInfo()) {
// FIXME: Remove this once debug info isn't modeled as instructions.
EnsureInsertPoint();
EmitStopPoint(S);
DI->setLocation(D.getLocation());
if (Target.useGlobalsForAutomaticVariables()) {
DI->EmitGlobalVariable(static_cast<llvm::GlobalVariable *>(DeclPtr), &D);
@ -338,7 +347,18 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
}
// If this local has an initializer, emit it now.
if (const Expr *Init = D.getInit()) {
const Expr *Init = D.getInit();
// If we are at an unreachable point, we don't need to emit the initializer
// unless it contains a label.
if (!HaveInsertPoint()) {
if (!ContainsLabel(Init))
Init = 0;
else
EnsureInsertPoint();
}
if (Init) {
llvm::Value *Loc = DeclPtr;
if (isByRef) {
bool needsCopyDispose = BlockRequiresCopying(Ty);
@ -357,10 +377,12 @@ void CodeGenFunction::EmitLocalBlockVarDecl(const VarDecl &D) {
EmitAggExpr(Init, Loc, D.getType().isVolatileQualified());
}
}
if (isByRef) {
const llvm::PointerType *PtrToInt8Ty
= VMContext.getPointerTypeUnqual(llvm::Type::Int8Ty);
EnsureInsertPoint();
llvm::Value *isa_field = Builder.CreateStructGEP(DeclPtr, 0);
llvm::Value *forwarding_field = Builder.CreateStructGEP(DeclPtr, 1);
llvm::Value *flags_field = Builder.CreateStructGEP(DeclPtr, 2);

View File

@ -43,13 +43,24 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
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
// probably not worth the effort.
// FIXME: Verify previous performance/effort claim.
EnsureInsertPoint();
// Check if we are generating unreachable code.
if (!HaveInsertPoint()) {
// If so, and the statement doesn't contain a label, then we do not need to
// generate actual code. This is safe because (1) the current point is
// unreachable, so we don't need to execute the code, and (2) we've already
// handled the statements which update internal data structures (like the
// local variable map) which could be used by subsequent statements.
if (!ContainsLabel(S)) {
// Verify that any decl statements were handled as simple, they may be in
// scope of subsequent reachable statements.
assert(!isa<DeclStmt>(*S) && "Unexpected DeclStmt!");
return;
}
// Otherwise, make a new block to hold the code.
EnsureInsertPoint();
}
// Generate a stoppoint if we are emitting debug info.
EmitStopPoint(S);
@ -72,7 +83,6 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
case Stmt::ForStmtClass: EmitForStmt(cast<ForStmt>(*S)); break;
case Stmt::ReturnStmtClass: EmitReturnStmt(cast<ReturnStmt>(*S)); break;
case Stmt::DeclStmtClass: EmitDeclStmt(cast<DeclStmt>(*S)); break;
case Stmt::SwitchStmtClass: EmitSwitchStmt(cast<SwitchStmt>(*S)); break;
case Stmt::AsmStmtClass: EmitAsmStmt(cast<AsmStmt>(*S)); break;
@ -103,6 +113,7 @@ bool CodeGenFunction::EmitSimpleStmt(const Stmt *S) {
default: return false;
case Stmt::NullStmtClass: break;
case Stmt::CompoundStmtClass: EmitCompoundStmt(cast<CompoundStmt>(*S)); break;
case Stmt::DeclStmtClass: EmitDeclStmt(cast<DeclStmt>(*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;

View File

@ -450,19 +450,19 @@ void CodeGenFunction::EmitIndirectSwitches() {
}
}
llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT)
{
llvm::Value *CodeGenFunction::GetVLASize(const VariableArrayType *VAT) {
llvm::Value *&SizeEntry = VLASizeMap[VAT];
assert(SizeEntry && "Did not emit size for type");
return SizeEntry;
}
llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty)
{
llvm::Value *CodeGenFunction::EmitVLASize(QualType Ty) {
assert(Ty->isVariablyModifiedType() &&
"Must pass variably modified type to EmitVLASizes!");
EnsureInsertPoint();
if (const VariableArrayType *VAT = getContext().getAsVariableArrayType(Ty)) {
llvm::Value *&SizeEntry = VLASizeMap[VAT];

View File

@ -147,7 +147,11 @@ public:
~CleanupScope() {
CGF.PushCleanupBlock(CleanupBB);
CGF.Builder.SetInsertPoint(CurBB);
// FIXME: This is silly, move this into the builder.
if (CurBB)
CGF.Builder.SetInsertPoint(CurBB);
else
CGF.Builder.ClearInsertionPoint();
}
};
@ -510,6 +514,8 @@ public:
// EmitVLASize - Generate code for any VLA size expressions that might occur
// in a variably modified type. If Ty is a VLA, will return the value that
// corresponds to the size in bytes of the VLA type. Will return 0 otherwise.
///
/// This function can be called with a null (unreachable) insert point.
llvm::Value *EmitVLASize(QualType Ty);
// GetVLASize - Returns an LLVM value that corresponds to the size in bytes
@ -537,9 +543,21 @@ public:
// Declaration Emission
//===--------------------------------------------------------------------===//
/// EmitDecl - Emit a declaration.
///
/// This function can be called with a null (unreachable) insert point.
void EmitDecl(const Decl &D);
/// EmitBlockVarDecl - Emit a block variable declaration.
///
/// This function can be called with a null (unreachable) insert point.
void EmitBlockVarDecl(const VarDecl &D);
/// EmitLocalBlockVarDecl - Emit a local block variable declaration.
///
/// This function can be called with a null (unreachable) insert point.
void EmitLocalBlockVarDecl(const VarDecl &D);
void EmitStaticBlockVarDecl(const VarDecl &D);
/// EmitParmDecl - Emit a ParmVarDecl or an ImplicitParamDecl.

View File

@ -0,0 +1,26 @@
// RUN: clang-cc -emit-llvm -o %t %s &&
// RUN: grep '@unreachable' %t | count 0
extern int unreachable();
int f0() {
return 0;
unreachable();
}
int f1(int i) {
goto L0;
int a = unreachable();
L0:
return 0;
}
int f2(int i) {
goto L0;
unreachable();
int a;
unreachable();
L0:
a = i + 1;
return a;
}