Learn ScalarReplAggregrates how stores and loads of first class aggregrates

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
This commit is contained in:
Matthijs Kooijman 2008-06-05 12:51:53 +00:00
parent 1494bccef7
commit 02518140ac
2 changed files with 83 additions and 0 deletions

View 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!

View File

@ -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
}