mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-14 11:32:34 +00:00
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:
parent
1494bccef7
commit
02518140ac
@ -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!
|
||||
|
||||
|
32
test/Transforms/ScalarRepl/2008-06-05-loadstore-agg.ll
Normal file
32
test/Transforms/ScalarRepl/2008-06-05-loadstore-agg.ll
Normal 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user