Learn ScalarReplAggregrates how stores and loads of first class aggregrates
authorMatthijs Kooijman <matthijs@stdin.nl>
Thu, 5 Jun 2008 12:51:53 +0000 (12:51 +0000)
committerMatthijs Kooijman <matthijs@stdin.nl>
Thu, 5 Jun 2008 12:51:53 +0000 (12:51 +0000)
work and how to replace them into individual values. Also, when trying to
replace an aggregrate that is used by load or store with a single (large)
integer, don't crash (but don't replace the aggregrate either).

Also adds a testcase for both structs and arrays.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@51997 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Transforms/Scalar/ScalarReplAggregates.cpp
test/Transforms/ScalarRepl/2008-06-05-loadstore-agg.ll [new file with mode: 0644]

index 2db6db754e6343c32d3ce53bde2607acf670fd65..92d1e2036b7112a6252b0dccb2334c1d3a3b4f0e 100644 (file)
@@ -302,6 +302,41 @@ void SROA::DoScalarReplacement(AllocationInst *AI,
       continue;
     }
     
+    // Replace %res = load { i32, i32 }* %alloc
+    // by
+    // %load.0 = load i32* %alloc.0
+    // %insert.0 insertvalue { i32, i32 } zeroinitializer, i32 %load.0, 0 
+    // %load.1 = load i32* %alloc.1
+    // %insert = insertvalue { i32, i32 } %insert.0, i32 %load.1, 1 
+    // (Also works for arrays instead of structs)
+    if (LoadInst *LI = dyn_cast<LoadInst>(User)) {
+      Value *Insert = UndefValue::get(LI->getType());
+      for (unsigned i = 0, e = ElementAllocas.size(); i != e; ++i) {
+        Value *Load = new LoadInst(ElementAllocas[i], "load", LI);
+        Insert = InsertValueInst::Create(Insert, Load, i, "insert", LI);
+      }
+      LI->replaceAllUsesWith(Insert);
+      LI->eraseFromParent();
+      continue;
+    }
+
+    // Replace store { i32, i32 } %val, { i32, i32 }* %alloc
+    // by
+    // %val.0 = extractvalue { i32, i32 } %val, 0 
+    // store i32 %val.0, i32* %alloc.0
+    // %val.1 = extractvalue { i32, i32 } %val, 1 
+    // store i32 %val.1, i32* %alloc.1
+    // (Also works for arrays instead of structs)
+    if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
+      Value *Val = SI->getOperand(0);
+      for (unsigned i = 0, e = ElementAllocas.size(); i != e; ++i) {
+        Value *Extract = ExtractValueInst::Create(Val, i, Val->getName(), SI);
+        new StoreInst(Extract, ElementAllocas[i], SI);
+      }
+      SI->eraseFromParent();
+      continue;
+    }
+    
     GetElementPtrInst *GEPI = cast<GetElementPtrInst>(User);
     // We now know that the GEP is of the form: GEP <ptr>, 0, <cst>
     unsigned Idx =
@@ -440,6 +475,12 @@ void SROA::isSafeUseOfAllocation(Instruction *User, AllocationInst *AI,
   if (BitCastInst *C = dyn_cast<BitCastInst>(User))
     return isSafeUseOfBitCastedAllocation(C, AI, Info);
 
+  if (isa<LoadInst>(User))
+    return; // Loads (returning a first class aggregrate) are always rewritable
+
+  if (isa<StoreInst>(User) && User->getOperand(0) != AI)
+    return; // Store is ok if storing INTO the pointer, not storing the pointer
   GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(User);
   if (GEPI == 0)
     return MarkUnsafe(Info);
@@ -961,12 +1002,22 @@ const Type *SROA::CanConvertToScalar(Value *V, bool &IsNotTrivial) {
     Instruction *User = cast<Instruction>(*UI);
     
     if (LoadInst *LI = dyn_cast<LoadInst>(User)) {
+      // FIXME: Loads of a first class aggregrate value could be converted to a
+      // series of loads and insertvalues
+      if (!LI->getType()->isSingleValueType())
+        return 0;
+
       if (MergeInType(LI->getType(), UsedType, TD))
         return 0;
       
     } else if (StoreInst *SI = dyn_cast<StoreInst>(User)) {
       // Storing the pointer, not into the value?
       if (SI->getOperand(0) == V) return 0;
+
+      // FIXME: Stores of a first class aggregrate value could be converted to a
+      // series of extractvalues and stores
+      if (!SI->getOperand(0)->getType()->isSingleValueType())
+        return 0;
       
       // NOTE: We could handle storing of FP imms into integers here!
       
diff --git a/test/Transforms/ScalarRepl/2008-06-05-loadstore-agg.ll b/test/Transforms/ScalarRepl/2008-06-05-loadstore-agg.ll
new file mode 100644 (file)
index 0000000..73d92be
--- /dev/null
@@ -0,0 +1,32 @@
+; This test shows an alloca of a struct and an array that can be reduced to
+; multiple variables easily. However, the alloca is used by a store
+; instruction, which was not possible before aggregrates were first class
+; values. This checks of scalarrepl splits up the struct and array properly.
+
+; RUN: llvm-as < %s | opt -scalarrepl | llvm-dis | not grep alloca
+
+define i32 @foo() {
+       %target = alloca { i32, i32 }           ; <{ i32, i32 }*> [#uses=1]
+        ; Build a first class struct to store
+       %res1 = insertvalue { i32, i32 } undef, i32 1, 0                ; <{ i32, i32 }> [#uses=1]
+       %res2 = insertvalue { i32, i32 } %res1, i32 2, 1                ; <{ i32, i32 }> [#uses=1]
+        ; And store it
+       store { i32, i32 } %res2, { i32, i32 }* %target
+        ; Actually use %target, so it doesn't get removed alltogether
+        %ptr = getelementptr { i32, i32 }* %target, i32 0, i32 0
+        %val = load i32* %ptr
+       ret i32 %val
+}
+
+define i32 @bar() {
+       %target = alloca [ 2 x i32 ]            ; <{ i32, i32 }*> [#uses=1]
+        ; Build a first class array to store
+       %res1 = insertvalue [ 2 x i32 ] undef, i32 1, 0         ; <{ i32, i32 }> [#uses=1]
+       %res2 = insertvalue [ 2 x i32 ] %res1, i32 2, 1         ; <{ i32, i32 }> [#uses=1]
+        ; And store it
+       store [ 2 x i32 ] %res2, [ 2 x i32 ]* %target
+        ; Actually use %target, so it doesn't get removed alltogether
+        %ptr = getelementptr [ 2 x i32 ]* %target, i32 0, i32 0
+        %val = load i32* %ptr
+       ret i32 %val
+}