forked from OSchip/llvm-project
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:
parent
7adf076088
commit
88402ce8d0
|
@ -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) {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue