diff --git a/lib/Transforms/Scalar/ScalarReplAggregates.cpp b/lib/Transforms/Scalar/ScalarReplAggregates.cpp index 2db6db754e6..92d1e2036b7 100644 --- a/lib/Transforms/Scalar/ScalarReplAggregates.cpp +++ b/lib/Transforms/Scalar/ScalarReplAggregates.cpp @@ -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(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(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(User); // We now know that the GEP is of the form: GEP , 0, unsigned Idx = @@ -440,6 +475,12 @@ void SROA::isSafeUseOfAllocation(Instruction *User, AllocationInst *AI, if (BitCastInst *C = dyn_cast(User)) return isSafeUseOfBitCastedAllocation(C, AI, Info); + if (isa(User)) + return; // Loads (returning a first class aggregrate) are always rewritable + + if (isa(User) && User->getOperand(0) != AI) + return; // Store is ok if storing INTO the pointer, not storing the pointer + GetElementPtrInst *GEPI = dyn_cast(User); if (GEPI == 0) return MarkUnsafe(Info); @@ -961,12 +1002,22 @@ const Type *SROA::CanConvertToScalar(Value *V, bool &IsNotTrivial) { Instruction *User = cast(*UI); if (LoadInst *LI = dyn_cast(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(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 index 00000000000..73d92be179e --- /dev/null +++ b/test/Transforms/ScalarRepl/2008-06-05-loadstore-agg.ll @@ -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 +}