[cfe-commits] r54318 - in /cfe/trunk: lib/CodeGen/CGExprScalar.cpp lib/CodeGen/CGStmt.cpp lib/CodeGen/CodeGenFunction.cpp lib/CodeGen/CodeGenFunction.h lib/Sema/SemaExpr.cpp test/CodeGen/indirect-goto.c
Daniel Dunbar
daniel at zuster.org
Mon Aug 4 09:51:23 PDT 2008
Author: ddunbar
Date: Mon Aug 4 11:51:22 2008
New Revision: 54318
URL: http://llvm.org/viewvc/llvm-project?rev=54318&view=rev
Log:
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.
Added:
cfe/trunk/test/CodeGen/indirect-goto.c
Modified:
cfe/trunk/lib/CodeGen/CGExprScalar.cpp
cfe/trunk/lib/CodeGen/CGStmt.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
cfe/trunk/lib/CodeGen/CodeGenFunction.h
cfe/trunk/lib/Sema/SemaExpr.cpp
Modified: cfe/trunk/lib/CodeGen/CGExprScalar.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExprScalar.cpp?rev=54318&r1=54317&r2=54318&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGExprScalar.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGExprScalar.cpp Mon Aug 4 11:51:22 2008
@@ -117,6 +117,12 @@
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) {
Modified: cfe/trunk/lib/CodeGen/CGStmt.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGStmt.cpp?rev=54318&r1=54317&r2=54318&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGStmt.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGStmt.cpp Mon Aug 4 11:51:22 2008
@@ -62,6 +62,8 @@
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 @@
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());
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.cpp?rev=54318&r1=54317&r2=54318&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.cpp Mon Aug 4 11:51:22 2008
@@ -68,7 +68,10 @@
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 @@
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));
+ }
+ }
+}
Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=54318&r1=54317&r2=54318&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
+++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Mon Aug 4 11:51:22 2008
@@ -22,6 +22,7 @@
#include "clang/AST/ExprObjC.h"
#include <vector>
+#include <map>
namespace llvm {
class Module;
@@ -240,11 +241,21 @@
/// 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 @@
/// 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 @@
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 @@
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
Modified: cfe/trunk/lib/Sema/SemaExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExpr.cpp?rev=54318&r1=54317&r2=54318&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExpr.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExpr.cpp Mon Aug 4 11:51:22 2008
@@ -2313,7 +2313,8 @@
// 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);
Added: cfe/trunk/test/CodeGen/indirect-goto.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/indirect-goto.c?rev=54318&view=auto
==============================================================================
--- cfe/trunk/test/CodeGen/indirect-goto.c (added)
+++ cfe/trunk/test/CodeGen/indirect-goto.c Mon Aug 4 11:51:22 2008
@@ -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);
+}
More information about the cfe-commits
mailing list