[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