[llvm-commits] CVS: gcc-3.4/gcc/llvm-expand.c

Chris Lattner lattner at cs.uiuc.edu
Tue Mar 9 21:06:02 PST 2004


Changes in directory gcc-3.4/gcc:

llvm-expand.c updated: 1.23 -> 1.24

---
Log message:

Expand large initializers of zeros into memset calls, and large constant
initializers into memcpy calls from a global.  This addresses PR275.


---
Diffs of the changes:  (+63 -60)

Index: gcc-3.4/gcc/llvm-expand.c
diff -u gcc-3.4/gcc/llvm-expand.c:1.23 gcc-3.4/gcc/llvm-expand.c:1.24
--- gcc-3.4/gcc/llvm-expand.c:1.23	Tue Mar  9 16:50:42 2004
+++ gcc-3.4/gcc/llvm-expand.c	Tue Mar  9 21:05:22 2004
@@ -3866,6 +3866,26 @@
 }
 
 
+/* llvm_count_constructor_init_elements - Given a constructor initializer, count
+ * how many elements are zero values and, of the remaining values, how many are
+ * non-zero constants.
+ */
+static void 
+llvm_count_constructor_init_elements(llvm_value **Elements, unsigned Size, 
+                                     unsigned *NumConstant, unsigned *NumZero) {
+  unsigned Constants = 0, Zeros = 0, i;
+  for (i = 0; i != Size; ++i)
+    if (llvm_value_is_constant(Elements[i])) {
+      if (llvm_is_null_constant(Elements[i]))
+        ++Zeros;
+      else
+        ++Constants;
+    }
+  *NumConstant = Constants;
+  *NumZero = Zeros;
+}
+
+
 /* llvm_expand_constructor - Store the value of a CONSTRUCTOR (exp) into the
  * LLVM value (Dest).  Dest is guaranteed to be a pointer to the appropriate
  * memory location.
@@ -3901,74 +3921,57 @@
 
     /* Composite elements handled already */
     if (!llvm_type_is_composite(Ty->Elements[0])) {
-      /* Lots of initializers have LARGE tails of zeros at the end of them.  To
-       * handle this efficiently, we actually check to see if there is a large
-       * tail pad, and if so, emit a loop to initialize it.
+      /* It is very common for constructors to be fully constant, and not
+       * infrequent for them to be large.  In this case, emit an internal global
+       * variable with the constructor value as its initializer, and memcpy it
+       * over.
        */
-      unsigned TailStart = Size;
-      if (TailStart) {
-        do --TailStart;
-        while (TailStart && Elements[TailStart] == Elements[TailStart-1]);
-      }
+      if (Size > 16) {
+        unsigned Alignment = TYPE_ALIGN_UNIT(TREE_TYPE(exp));
+        unsigned NumBytes = Size*llvm_type_get_size(Ty->Elements[0]);
+        unsigned NumConstants = 0, NumZeros = 0;
+        llvm_count_constructor_init_elements(Elements, Size,
+                                             &NumConstants, &NumZeros);
+
+        /* If all of the elements are zeros, memset the constructor to zero. */
+        if (NumZeros == Size) {
+          EmitMemset(Fn, target, llvm_constant_ubyte_0,
+                     llvm_constant_new_integral(LongTy, NumBytes), Alignment);
+          free(Elements);
+          return;
+        } else if (NumZeros+NumConstants == Size) {
+          /* Otherwise, if all of the elements are constants, initialize a
+           * global variable with the constant value, and memcpy it into the
+           * current location.
+           */
+          llvm_constant *C = G2C(llvm_constant_aggregate_new(Ty, Elements));
+          llvm_global *G;
+          static int CtorCounter = 0;
+          char Name[20];
+          sprintf(Name, ".ctor_%d", ++CtorCounter);
+          G = llvm_global_new(D2V(C)->Ty, Name);
+          G->Init = C;
+          llvm_ilist_push_back(llvm_global, TheProgram.Globals, G);
+          EmitMemCpyMove(Fn, target, G2V(G),
+                         llvm_constant_new_integral(LongTy, NumBytes),
+                         Alignment, 0); 
+          return;
+        }
 
-      /* Only do this for substantial tails. */
-      if (Size-TailStart < 16)
-        TailStart = Size;
+        /* FIXME: MORE CASES WE COULD HANDLE EFFICIENTLY:
+         *  - When the init is mostly zeros but not all constant, memset, then
+         *    fill in elements.
+         *  - When the constant is mostly zeros, we could use memset to set
+         *    it to zero, then memcpy the smaller non-zero portion.
+         */
+      }
 
-      /* FIXME: If tailstart is obscenely large, we are better off starting with
-       * an initialized global and memcpy'ing it over.
-       */
-      for (i = 0; i != TailStart; ++i) {
+      for (i = 0; i != Size; ++i) {
         /* Make a getelementptr instruction that addresses the field */
         OffsetInst = create_gep3(target, llvm_constant_long_0,
                                  llvm_constant_new_integral(LongTy, i));
         Offset = append_inst(Fn, OffsetInst);   /* Add it to the program */
         append_inst(Fn, create_store_inst(Elements[i], Offset, isVolatile));
-      }
-
-      /* If there is tail padding to emit, add the loop or memset call now. */
-      if (TailStart != Size) {
-        llvm_value *Val = Elements[i];
-        if (llvm_type_get_size(Val->Ty) == 1) {
-          llvm_value *DestPtr =
-            append_inst(Fn, create_gep3(target, llvm_constant_long_0,
-                                llvm_constant_new_integral(LongTy, TailStart)));
-          EmitMemset(Fn, DestPtr, Val,
-                     llvm_constant_new_integral(LongTy, Size-TailStart), 1);
-        } else {
-          llvm_basicblock *FromBlock =
-            llvm_ilist_back(llvm_basicblock, Fn->BasicBlocks);
-          llvm_basicblock *Loop = llvm_basicblock_new("initializeloop");
-          llvm_basicblock *After = llvm_basicblock_new("continue");
-          llvm_instruction *PHI;
-          llvm_value *SetNE;
-          
-          /* Output the branch to the loop block, and the loop block itself. */
-          append_inst(Fn, create_uncond_branch(Loop));
-          llvm_emit_label(Fn, Loop);
-          
-          /* Create the PHI node now */
-          PHI = llvm_instruction_new(LongTy, "idx", O_PHINode, 4);
-          PHI->Operands[0] = llvm_constant_new_integral(LongTy, TailStart);
-          PHI->Operands[1] = D2V(FromBlock);
-          PHI->Operands[3] = D2V(Loop);
-          append_inst(Fn, PHI);
-          
-          /* Make a getelementptr & store to the fields */
-          OffsetInst = create_gep3(target, llvm_constant_long_0, D2V(PHI));
-          Offset = append_inst(Fn, OffsetInst);   /* Add it to the program */
-          append_inst(Fn, create_store_inst(Val, Offset, isVolatile));
-          
-          /* Add one to the counter, add it to the PHI operand */
-          PHI->Operands[2] = 
-            append_inst(Fn, create_binary_inst("tmp", O_Add, D2V(PHI), 
-                                        llvm_constant_new_integral(LongTy, 1)));
-          /* Add a setne instruction to test for loop termination */
-          SetNE = append_inst(Fn, create_binary_inst("hasmore",O_SetNE,D2V(PHI),
-                                   llvm_constant_new_integral(LongTy, Size-1)));
-          append_inst(Fn, create_cond_branch(SetNE, Loop, After));
-          llvm_emit_label(Fn, After);
-        }
       }
     }
   }





More information about the llvm-commits mailing list