From 02518140ac3310d0357c26a87b2372d85da9c2f4 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Thu, 5 Jun 2008 12:51:53 +0000 Subject: [PATCH] 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 --- .../Scalar/ScalarReplAggregates.cpp | 51 +++++++++++++++++++ .../ScalarRepl/2008-06-05-loadstore-agg.ll | 32 ++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 test/Transforms/ScalarRepl/2008-06-05-loadstore-agg.ll 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 +}