[llvm-commits] [gcc-plugin] r82764 - in /gcc-plugin/trunk: llvm-convert.cpp llvm-internal.h

Duncan Sands baldrick at free.fr
Fri Sep 25 05:50:52 PDT 2009


Author: baldrick
Date: Fri Sep 25 07:50:52 2009
New Revision: 82764

URL: http://llvm.org/viewvc/llvm-project?rev=82764&view=rev
Log:
In the plugin we convert GCC's ssa form directly to LLVM's ssa
form, creating LLVM phi nodes for GCC phi nodes and so forth.
Thanks to ssa form, the vast majority of GCC local variables are
not used at all, but they still exist in the list of local vars.
Since we convert all variables in this list into alloca's, this
result in bitcode filled with unused alloca's.  Instead, generate
alloca's for local variables on demand, the first time we need
one.  This is done by having DECL_LLVM use a local cache for
declarations local to the current function (this cache is thrown
away once we converted the function), and having a local version
of make_decl_llvm that knows how to generate alloca's for local
variables (I also did it for the function result).  At -O0, this
results in a more than 10% decrease in the size of bitcode for
sqlite3.

Modified:
    gcc-plugin/trunk/llvm-convert.cpp
    gcc-plugin/trunk/llvm-internal.h

Modified: gcc-plugin/trunk/llvm-convert.cpp
URL: http://llvm.org/viewvc/llvm-project/gcc-plugin/trunk/llvm-convert.cpp?rev=82764&r1=82763&r2=82764&view=diff

==============================================================================
--- gcc-plugin/trunk/llvm-convert.cpp (original)
+++ gcc-plugin/trunk/llvm-convert.cpp Fri Sep 25 07:50:52 2009
@@ -200,6 +200,61 @@
   TheTreeToLLVM = 0;
 }
 
+//===----------------------------------------------------------------------===//
+//                         ... Local declarations ...
+//===----------------------------------------------------------------------===//
+
+/// isLocalDecl - Whether this declaration is local to the current function.
+static bool isLocalDecl(tree decl) {
+  assert(HAS_RTL_P(decl) && "Expected a declaration with RTL!");
+  return DECL_CONTEXT(decl) == current_function_decl &&
+    !TREE_STATIC(decl) && // Static variables not considered local.
+    TREE_CODE(decl) != FUNCTION_DECL; // Nested functions not considered local.
+}
+
+/// set_decl_local - Remember the LLVM value for a GCC declaration.
+Value *TreeToLLVM::set_decl_local(tree decl, Value *V) {
+  if (!isLocalDecl(decl))
+    return set_decl_llvm(decl, V);
+  if (V != NULL)
+    return LocalDecls[decl] = V;
+  LocalDecls.erase(decl);
+  return NULL;
+}
+
+/// get_decl_local - Retrieve the LLVM value for a GCC declaration, or NULL.
+Value *TreeToLLVM::get_decl_local(tree decl) {
+  if (!isLocalDecl(decl))
+    return get_decl_llvm(decl);
+  DenseMap<tree, AssertingVH<> >::iterator I = LocalDecls.find(decl);
+  if (I != LocalDecls.end())
+    return I->second;
+  return NULL;
+}
+
+/// make_decl_local - Return the LLVM value for a GCC declaration if it exists.
+/// Otherwise creates and returns an appropriate value.
+Value *TreeToLLVM::make_decl_local(tree decl) {
+  if (!isLocalDecl(decl))
+    return make_decl_llvm(decl);
+
+  DenseMap<tree, AssertingVH<> >::iterator I = LocalDecls.find(decl);
+  if (I != LocalDecls.end())
+    return I->second;
+
+  switch (TREE_CODE(decl)) {
+  default:
+    llvm_unreachable("Unhandled local declaration!");
+
+  case RESULT_DECL:
+  case VAR_DECL:
+    EmitAutomaticVariableDecl(decl);
+    I = LocalDecls.find(decl);
+    assert(I != LocalDecls.end() && "Not a local variable?");
+    return I->second;
+  }
+}
+
 /// llvm_store_scalar_argument - Store scalar argument ARGVAL of type
 /// LLVMTY at location LOC.
 static void llvm_store_scalar_argument(Value *Loc, Value *ArgVal,
@@ -282,7 +337,7 @@
       tree ResultDecl = DECL_RESULT(FunctionDecl);
       tree RetTy = TREE_TYPE(TREE_TYPE(FunctionDecl));
       if (TREE_CODE(RetTy) == TREE_CODE(TREE_TYPE(ResultDecl))) {
-        SET_DECL_LLVM(ResultDecl, AI);
+        TheTreeToLLVM->set_decl_local(ResultDecl, AI);
         ++AI;
         return;
       }
@@ -294,7 +349,7 @@
       Value *Tmp = TheTreeToLLVM->CreateTemporary(AI->getType());
       Builder.CreateStore(AI, Tmp);
 
-      SET_DECL_LLVM(ResultDecl, Tmp);
+      TheTreeToLLVM->set_decl_local(ResultDecl, Tmp);
       if (TheDebugInfo) {
         TheDebugInfo->EmitDeclare(ResultDecl,
                                   dwarf::DW_TAG_return_variable,
@@ -309,7 +364,7 @@
              "No explicit return value?");
       AI->setName("scalar.result");
       isShadowRet = true;
-      SET_DECL_LLVM(DECL_RESULT(FunctionDecl), AI);
+      TheTreeToLLVM->set_decl_local(DECL_RESULT(FunctionDecl), AI);
       ++AI;
     }
 
@@ -428,9 +483,9 @@
 
   // If we've already seen this function and created a prototype, and if the
   // proto has the right LLVM type, just use it.
-  if (DECL_LLVM_SET_P(FnDecl) &&
-      cast<PointerType>(DECL_LLVM(FnDecl)->getType())->getElementType() == FTy){
-    Fn = cast<Function>(DECL_LLVM(FnDecl));
+  if (DECL_LOCAL_SET_P(FnDecl) &&
+      cast<PointerType>(DECL_LOCAL(FnDecl)->getType())->getElementType()==FTy) {
+    Fn = cast<Function>(DECL_LOCAL(FnDecl));
     assert(Fn->getCallingConv() == CallingConv &&
            "Calling convention disagreement between prototype and impl!");
     // The visibility can be changed from the last time we've seen this
@@ -463,7 +518,7 @@
       changeLLVMConstant(FnEntry, Fn);
       FnEntry->eraseFromParent();
     }
-    SET_DECL_LLVM(FnDecl, Fn);
+    SET_DECL_LOCAL(FnDecl, Fn);
   }
 
   // The function should not already have a body.
@@ -574,7 +629,7 @@
       // If the value is passed by 'invisible reference' or 'byval reference',
       // the l-value for the argument IS the argument itself.
       AI->setName(Name);
-      SET_DECL_LLVM(Args, AI);
+      SET_DECL_LOCAL(Args, AI);
       if (!isInvRef && TheDebugInfo)
         TheDebugInfo->EmitDeclare(Args, dwarf::DW_TAG_arg_variable,
                                   Name, TREE_TYPE(Args),
@@ -586,7 +641,7 @@
       // into the alloca.
       Value *Tmp = CreateTemporary(ArgTy);
       Tmp->setName(std::string(Name)+"_addr");
-      SET_DECL_LLVM(Args, Tmp);
+      SET_DECL_LOCAL(Args, Tmp);
       if (TheDebugInfo) {
         TheDebugInfo->EmitDeclare(Args, dwarf::DW_TAG_arg_variable,
                                   Name, TREE_TYPE(Args), Tmp,
@@ -618,23 +673,12 @@
                               Constant::getNullValue(Type::getInt32Ty(Context)),
                               Type::getInt32Ty(Context)), "ssa point");
 
-  // If this is not a void-returning function, initialize the RESULT_DECL.
-  if (DECL_RESULT(FnDecl) && !VOID_TYPE_P(TREE_TYPE(DECL_RESULT(FnDecl))) &&
-      !DECL_LLVM_SET_P(DECL_RESULT(FnDecl)))
-    EmitAutomaticVariableDecl(DECL_RESULT(FnDecl));
-
   // If this function has nested functions, we should handle a potential
   // nonlocal_goto_save_area.
   if (cfun->nonlocal_goto_save_area) {
     // Not supported yet.
   }
 
-  // Emit any automatic or static variables.
-  for (tree vars = DECL_STRUCT_FUNCTION(FnDecl)->local_decls; vars;
-       vars = TREE_CHAIN(vars))
-    if (!DECL_LLVM_SET_P(TREE_VALUE(vars)))
-      EmitAutomaticVariableDecl(TREE_VALUE(vars));
-
   // Create a new block for the return node, but don't insert it yet.
   ReturnBB = BasicBlock::Create(Context, "return");
 }
@@ -775,14 +819,14 @@
       // If the DECL_RESULT is a scalar type, just load out the return value
       // and return it.
       tree TreeRetVal = DECL_RESULT(FnDecl);
-      Value *RetVal = Builder.CreateLoad(DECL_LLVM(TreeRetVal), "retval");
+      Value *RetVal = Builder.CreateLoad(DECL_LOCAL(TreeRetVal), "retval");
       bool RetValSigned = !TYPE_UNSIGNED(TREE_TYPE(TreeRetVal));
       Instruction::CastOps opcode = CastInst::getCastOpcode(
           RetVal, RetValSigned, Fn->getReturnType(), RetValSigned);
       RetVal = Builder.CreateCast(opcode, RetVal, Fn->getReturnType());
       RetVals.push_back(RetVal);
     } else {
-      Value *RetVal = DECL_LLVM(DECL_RESULT(FnDecl));
+      Value *RetVal = DECL_LOCAL(DECL_RESULT(FnDecl));
       if (const StructType *STy = dyn_cast<StructType>(Fn->getReturnType())) {
         Value *R1 = Builder.CreateBitCast(RetVal, PointerType::getUnqual(STy));
 
@@ -900,11 +944,11 @@
 /// label.
 BasicBlock *TreeToLLVM::getLabelDeclBlock(tree LabelDecl) {
   assert(TREE_CODE(LabelDecl) == LABEL_DECL && "Isn't a label!?");
-  if (DECL_LLVM_SET_P(LabelDecl))
-    return cast<BasicBlock>(DECL_LLVM(LabelDecl));
+  if (DECL_LOCAL_SET_P(LabelDecl))
+    return cast<BasicBlock>(DECL_LOCAL(LabelDecl));
 
   BasicBlock *BB = getBasicBlock(label_to_block(LabelDecl));
-  SET_DECL_LLVM(LabelDecl, BB);
+  SET_DECL_LOCAL(LabelDecl, BB);
   return BB;
 }
 
@@ -1623,38 +1667,14 @@
 //===----------------------------------------------------------------------===//
 
 /// EmitAutomaticVariableDecl - Emit the function-local decl to the current
-/// function and set DECL_LLVM for the decl to the right pointer.
+/// function and set DECL_LOCAL for the decl to the right pointer.
 void TreeToLLVM::EmitAutomaticVariableDecl(tree decl) {
-  tree type = TREE_TYPE(decl);
-
-  // An LLVM value pointer for this decl may already be set, for example, if the
-  // named return value optimization is being applied to this function, and
-  // this variable is the one being returned.
-  assert(!DECL_LLVM_SET_P(decl) && "Shouldn't call this on an emitted var!");
-
-  // For a CONST_DECL, set mode, alignment, and sizes from those of the
-  // type in case this node is used in a reference.
-  if (TREE_CODE(decl) == CONST_DECL) {
-    DECL_MODE(decl)      = TYPE_MODE(type);
-    DECL_ALIGN(decl)     = TYPE_ALIGN(type);
-    DECL_SIZE(decl)      = TYPE_SIZE(type);
-    DECL_SIZE_UNIT(decl) = TYPE_SIZE_UNIT(type);
-    return;
-  }
-
-  // Otherwise, only automatic (and result) variables need any expansion done.
-  // Static and external variables, and external functions, will be handled by
-  // `assemble_variable' (called from finish_decl).  TYPE_DECL requires nothing.
-  // PARM_DECLs are handled in `llvm_expand_function_start'.
-  if ((TREE_CODE(decl) != VAR_DECL && TREE_CODE(decl) != RESULT_DECL) ||
-      TREE_STATIC(decl) || DECL_EXTERNAL(decl) || type == error_mark_node)
-    return;
-
   // If this is just the rotten husk of a variable that the gimplifier
   // eliminated all uses of, but is preserving for debug info, ignore it.
   if (TREE_CODE(decl) == VAR_DECL && DECL_VALUE_EXPR(decl))
     return;
 
+  tree type = TREE_TYPE(decl);
   const Type *Ty;  // Type to allocate
   Value *Size = 0; // Amount to alloca (null for 1)
 
@@ -1719,7 +1739,7 @@
 
   AI->setAlignment(Alignment);
 
-  SET_DECL_LLVM(decl, AI);
+  SET_DECL_LOCAL(decl, AI);
 
   // Handle annotate attributes
   if (DECL_ATTRIBUTES(decl))
@@ -1860,7 +1880,7 @@
 abort();//FIXME
 //FIXME    assert(llvm_eh_personality_libfunc
 //FIXME           && "no exception handling personality function!");
-//FIXME    Args.push_back(Builder.CreateBitCast(DECL_LLVM(llvm_eh_personality_libfunc),
+//FIXME    Args.push_back(Builder.CreateBitCast(DECL_LOCAL(llvm_eh_personality_libfunc),
 //FIXME                                 PointerType::getUnqual(Type::getInt8Ty(Context))));
 //FIXME
 //FIXME    // Add selections for each handler.
@@ -2074,11 +2094,11 @@
 //FIXME    CallingConv::ID CallingConvention = CallingConv::C;
 //FIXME
 //FIXME    TARGET_ADJUST_LLVM_CC(CallingConvention, fntype);
-//FIXME    CallInst *Call = Builder.CreateCall(DECL_LLVM(llvm_unwind_resume_libfunc),
+//FIXME    CallInst *Call = Builder.CreateCall(DECL_LOCAL(llvm_unwind_resume_libfunc),
 //FIXME                                       Arg);
 //FIXME    Call->setCallingConv(CallingConvention);
 //FIXME#else
-//FIXME    Builder.CreateCall(DECL_LLVM(llvm_unwind_resume_libfunc), Arg);
+//FIXME    Builder.CreateCall(DECL_LOCAL(llvm_unwind_resume_libfunc), Arg);
 //FIXME#endif
     Builder.CreateUnreachable();
   }
@@ -2132,7 +2152,7 @@
     return UndefValue::get(ConvertType(TREE_TYPE(exp)));
 
   // Read the initial value of the parameter and associate it with the ssa name.
-  assert(DECL_LLVM_IF_SET(var) && "Parameter not laid out?");
+  assert(DECL_LOCAL_IF_SET(var) && "Parameter not laid out?");
 
   unsigned Alignment = DECL_ALIGN(var);
   assert(Alignment != 0 && "Parameter with unknown alignment!");
@@ -2141,7 +2161,7 @@
     DECL_NAME(var) ? IDENTIFIER_POINTER(DECL_NAME(var)) : "anon";
 
   const Type *Ty = ConvertType(TREE_TYPE(exp));
-  Value *Ptr = Builder.CreateBitCast(DECL_LLVM_IF_SET(var),
+  Value *Ptr = Builder.CreateBitCast(DECL_LOCAL_IF_SET(var),
                                      PointerType::getUnqual(Ty));
 
   // Perform the load in the entry block, after all parameters have been set up
@@ -6083,19 +6103,19 @@
       // emit a NEW declaration for the global variable, now that it has been
       // laid out.  We then tell the compiler to "forward" any uses of the old
       // global to this new one.
-      if (Value *Val = DECL_LLVM_IF_SET(exp)) {
+      if (Value *Val = DECL_LOCAL_IF_SET(exp)) {
         //fprintf(stderr, "***\n*** SHOULD HANDLE GLOBAL VARIABLES!\n***\n");
         //assert(0 && "Reimplement this with replace all uses!");
-        SET_DECL_LLVM(exp, 0);
+        SET_DECL_LOCAL(exp, 0);
         // Create a new global variable declaration
         llvm_assemble_external(exp);
-        V2GV(Val)->ForwardedGlobal = V2GV(DECL_LLVM(exp));
+        V2GV(Val)->ForwardedGlobal = V2GV(DECL_LOCAL(exp));
       }
 #endif
     }
   }
 
-  Value *Decl = DECL_LLVM(exp);
+  Value *Decl = DECL_LOCAL(exp);
   if (Decl == 0) {
     if (errorcount || sorrycount) {
       const Type *Ty = ConvertType(TREE_TYPE(exp));
@@ -6112,7 +6132,7 @@
   if (!TREE_USED(exp)) {
     assemble_external(exp);
     TREE_USED(exp) = 1;
-    Decl = DECL_LLVM(exp);
+    Decl = DECL_LOCAL(exp);
   }
 
   if (GlobalValue *GV = dyn_cast<GlobalValue>(Decl)) {
@@ -6123,7 +6143,7 @@
           GV->isDeclaration() &&
           !BOGUS_CTOR(exp)) {
         emit_global_to_llvm(exp);
-        Decl = DECL_LLVM(exp);     // Decl could have change if it changed type.
+        Decl = DECL_LOCAL(exp);     // Decl could have change if it changed type.
       }
     } else {
       // Otherwise, inform cgraph that we used the global.
@@ -8060,12 +8080,12 @@
   if (retval && retval != error_mark_node && retval != result) {
     // Store the return value to the function's DECL_RESULT.
     if (isAggregateTreeType(TREE_TYPE(result))) {
-      MemRef DestLoc(DECL_LLVM(result), 1, false); // FIXME: What alignment?
+      MemRef DestLoc(DECL_LOCAL(result), 1, false); // FIXME: What alignment?
       Emit(retval, &DestLoc);
     } else {
       Value *Val = Builder.CreateBitCast(Emit(retval, 0),
                                          ConvertType(TREE_TYPE(result)));
-      Builder.CreateStore(Val, DECL_LLVM(result));
+      Builder.CreateStore(Val, DECL_LOCAL(result));
     }
   }
 

Modified: gcc-plugin/trunk/llvm-internal.h
URL: http://llvm.org/viewvc/llvm-project/gcc-plugin/trunk/llvm-internal.h?rev=82764&r1=82763&r2=82764&view=diff

==============================================================================
--- gcc-plugin/trunk/llvm-internal.h (original)
+++ gcc-plugin/trunk/llvm-internal.h Fri Sep 25 07:50:52 2009
@@ -108,7 +108,7 @@
 
 // Mapping between GCC declarations and LLVM values.
 
-/// DECL_LLVM - Holds the LLVM expression for the value of a variable or
+/// DECL_LLVM - Holds the LLVM expression for the value of a global variable or
 /// function.  This value can be evaluated lazily for functions and variables
 /// with static storage duration.
 extern Value *make_decl_llvm(union tree_node *);
@@ -347,12 +347,41 @@
   /// BasicBlocks - Map from GCC to LLVM basic blocks.
   DenseMap<basic_block, BasicBlock*> BasicBlocks;
 
+  /// LocalDecls - Map from local declarations to their associated LLVM values.
+  DenseMap<tree, AssertingVH<> > LocalDecls;
+
   /// PendingPhis - Phi nodes which have not yet been populated with operands.
   SmallVector<PhiRecord, 16> PendingPhis;
 
   // SSANames - Map from GCC ssa names to the defining LLVM value.
   DenseMap<tree, AssertingVH<> > SSANames;
 
+public:
+
+  //===---------------------- Local Declarations --------------------------===//
+
+  /// DECL_LOCAL - Like DECL_LLVM, returns the LLVM expression for the value of
+  /// a variable or function.  However DECL_LOCAL can be used with declarations
+  /// local to the current function as well as with global declarations.
+  Value *make_decl_local(union tree_node *);
+  #define DECL_LOCAL(NODE) make_decl_local(NODE)
+
+  /// SET_DECL_LOCAL - Set the DECL_LOCAL for NODE to LLVM. 
+  Value *set_decl_local(union tree_node *, Value *);
+  #define SET_DECL_LOCAL(NODE, LLVM) set_decl_local(NODE, LLVM)
+
+  /// DECL_LOCAL_IF_SET - The DECL_LOCAL for NODE, if it is set, or NULL, if it
+  /// is not set.
+  Value *get_decl_local(union tree_node *);
+  #define DECL_LOCAL_IF_SET(NODE) (HAS_RTL_P(NODE) ? get_decl_local(NODE) : NULL)
+
+  /// DECL_LOCAL_SET_P - Returns nonzero if the DECL_LOCAL for NODE has already
+  /// been set.
+  #define DECL_LOCAL_SET_P(NODE) (DECL_LOCAL_IF_SET(NODE) != NULL)
+
+
+private:
+
   //===---------------------- Exception Handling --------------------------===//
 
   /// LandingPads - The landing pad for a given EH region.





More information about the llvm-commits mailing list