Add CodeGen support for indirect goto.

- Follows emission scheme used by llvm-gcc, i.e. invent an id for
   each label whose address is taken and replace each indirect goto by
   a switch to each possible target.
 - Currently we emit a switch for each indirect goto instead of
   merging them as llvm-gcc does.

llvm-svn: 54318
This commit is contained in:
Daniel Dunbar 2008-08-04 16:51:22 +00:00
parent 7adf076088
commit 88402ce8d0
6 changed files with 106 additions and 3 deletions

View File

@ -117,6 +117,12 @@ public:
Value *VisitSizeOfAlignOfTypeExpr(const SizeOfAlignOfTypeExpr *E) {
return EmitSizeAlignOf(E->getArgumentType(), E->getType(), E->isSizeOf());
}
Value *VisitAddrLabelExpr(const AddrLabelExpr *E) {
Value *V = llvm::ConstantInt::get(llvm::Type::Int32Ty,
CGF.GetIDForAddrOfLabel(E->getLabel()));
return Builder.CreateIntToPtr(V,
llvm::PointerType::getUnqual(llvm::Type::Int8Ty));
}
// l-values.
Value *VisitDeclRefExpr(DeclRefExpr *E) {

View File

@ -62,6 +62,8 @@ void CodeGenFunction::EmitStmt(const Stmt *S) {
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;
case Stmt::IfStmtClass: EmitIfStmt(cast<IfStmt>(*S)); break;
case Stmt::WhileStmtClass: EmitWhileStmt(cast<WhileStmt>(*S)); break;
@ -157,7 +159,25 @@ void CodeGenFunction::EmitGotoStmt(const GotoStmt &S) {
Builder.SetInsertPoint(llvm::BasicBlock::Create("", CurFn));
}
void CodeGenFunction::EmitIndirectGotoStmt(const IndirectGotoStmt &S) {
// Emit initial switch which will be patched up later by
// EmitIndirectSwitches(). We need a default dest, so we use the
// current BB, but this is overwritten.
llvm::Value *V = Builder.CreatePtrToInt(EmitScalarExpr(S.getTarget()),
llvm::Type::Int32Ty,
"addr");
llvm::SwitchInst *I = Builder.CreateSwitch(V, Builder.GetInsertBlock());
IndirectSwitches.push_back(I);
// Emit a block after the branch so that dead code after a goto has some place
// to go.
Builder.SetInsertPoint(llvm::BasicBlock::Create("", CurFn));
}
void CodeGenFunction::EmitIfStmt(const IfStmt &S) {
// FIXME: It would probably be nice for us to skip emission of if
// (0) code here.
// C99 6.8.4.1: The first substatement is executed if the expression compares
// unequal to 0. The condition must be a scalar type.
llvm::Value *BoolCondVal = EvaluateExprAsBool(S.getCond());

View File

@ -68,7 +68,10 @@ bool CodeGenFunction::hasAggregateLLVMType(QualType T) {
void CodeGenFunction::GenerateFunction(const Stmt *Body) {
// Emit the function body.
EmitStmt(Body);
// Finish emission of indirect switches.
EmitIndirectSwitches();
// Emit debug descriptor for function end.
CGDebugInfo *DI = CGM.getDebugInfo();
if (DI) {
@ -179,3 +182,33 @@ void CodeGenFunction::WarnUnsupported(const Stmt *S, const char *Type) {
CGM.WarnUnsupported(S, Type);
}
unsigned CodeGenFunction::GetIDForAddrOfLabel(const LabelStmt *L) {
// Use LabelIDs.size() as the new ID if one hasn't been assigned.
return LabelIDs.insert(std::make_pair(L, LabelIDs.size())).first->second;
}
void CodeGenFunction::EmitIndirectSwitches() {
llvm::BasicBlock *Default;
if (!LabelIDs.empty()) {
Default = getBasicBlockForLabel(LabelIDs.begin()->first);
} else {
// No possible targets for indirect goto, just emit an infinite
// loop.
Default = llvm::BasicBlock::Create("indirectgoto.loop", CurFn);
llvm::BranchInst::Create(Default, Default);
}
for (std::vector<llvm::SwitchInst*>::iterator i = IndirectSwitches.begin(),
e = IndirectSwitches.end(); i != e; ++i) {
llvm::SwitchInst *I = *i;
I->setSuccessor(0, Default);
for (std::map<const LabelStmt*,unsigned>::iterator LI = LabelIDs.begin(),
LE = LabelIDs.end(); LI != LE; ++LI) {
I->addCase(llvm::ConstantInt::get(llvm::Type::Int32Ty,
LI->second),
getBasicBlockForLabel(LI->first));
}
}
}

View File

@ -22,6 +22,7 @@
#include "clang/AST/ExprObjC.h"
#include <vector>
#include <map>
namespace llvm {
class Module;
@ -240,11 +241,21 @@ public:
/// AllocaInsertPoint - This is an instruction in the entry block before which
/// we prefer to insert allocas.
llvm::Instruction *AllocaInsertPt;
const llvm::Type *LLVMIntTy;
uint32_t LLVMPointerWidth;
private:
/// LabelIDs - Track arbitrary ids assigned to labels for use in
/// implementing the GCC address-of-label extension and indirect
/// goto. IDs are assigned to labels inside getIDForAddrOfLabel().
std::map<const LabelStmt*, unsigned> LabelIDs;
/// IndirectSwitches - Record the list of switches for indirect
/// gotos. Emission of the actual switching code needs to be delayed
/// until all AddrLabelExprs have been seen.
std::vector<llvm::SwitchInst*> IndirectSwitches;
/// LocalDeclMap - This keeps track of the LLVM allocas or globals for local C
/// decls.
llvm::DenseMap<const Decl*, llvm::Value*> LocalDeclMap;
@ -342,6 +353,8 @@ public:
/// the input field number being accessed.
static unsigned getAccessedFieldNo(unsigned Idx, const llvm::Constant *Elts);
unsigned GetIDForAddrOfLabel(const LabelStmt *L);
//===--------------------------------------------------------------------===//
// Declaration Emission
//===--------------------------------------------------------------------===//
@ -363,6 +376,7 @@ public:
void EmitLabel(const LabelStmt &S); // helper for EmitLabelStmt.
void EmitLabelStmt(const LabelStmt &S);
void EmitGotoStmt(const GotoStmt &S);
void EmitIndirectGotoStmt(const IndirectGotoStmt &S);
void EmitIfStmt(const IfStmt &S);
void EmitWhileStmt(const WhileStmt &S);
void EmitDoStmt(const DoStmt &S);
@ -502,6 +516,15 @@ public:
llvm::GlobalValue *GenerateStaticBlockVarDecl(const VarDecl &D,
bool NoInit,
const char *Separator);
//===--------------------------------------------------------------------===//
// Internal Helpers
//===--------------------------------------------------------------------===//
private:
/// EmitIndirectSwitches - Emit code for all of the switch
/// instructions in IndirectSwitches.
void EmitIndirectSwitches();
};
} // end namespace CodeGen
} // end namespace clang

View File

@ -2313,7 +2313,8 @@ Sema::ExprResult Sema::ActOnAddrLabel(SourceLocation OpLoc,
// Look up the record for this label identifier.
LabelStmt *&LabelDecl = LabelMap[LabelII];
// If we haven't seen this label yet, create a forward reference.
// If we haven't seen this label yet, create a forward reference. It
// will be validated and/or cleaned up in ActOnFinishFunctionBody.
if (LabelDecl == 0)
LabelDecl = new LabelStmt(LabLoc, LabelII, 0);

View File

@ -0,0 +1,20 @@
// RUN: clang -emit-llvm-bc -o - %s | opt -std-compile-opts | llvm-dis > %t &&
// RUN: grep "ret i32" %t | count 1 &&
// RUN: grep "ret i32 210" %t | count 1
static int foo(unsigned i) {
const void *addrs[] = { &&L1, &&L2, &&L3, &&L4, &&L5 };
int res = 1;
goto *addrs[i];
L5: res *= 11;
L4: res *= 7;
L3: res *= 5;
L2: res *= 3;
L1: res *= 2;
return res;
}
int bar() {
return foo(3);
}