mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-08-25 00:29:20 +00:00
Teach all of the loads, stores, memsets and memcpys created by the
rewriter in SROA to carry a proper alignment. This involves interrogating various sources of alignment, etc. This is a more complete and principled fix to PR13920 as well as related bugs pointed out by Eli in review and by inspection in the area. Also by inspection fix the integer and vector promotion paths to create aligned loads and stores. I still need to work up test cases for these... Sorry for the delay, they were found purely by inspection. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@164689 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
4d7aa6dbce
commit
81b001a220
@ -1896,7 +1896,8 @@ private:
|
|||||||
Value *extractInteger(IRBuilder<> &IRB, IntegerType *TargetTy,
|
Value *extractInteger(IRBuilder<> &IRB, IntegerType *TargetTy,
|
||||||
uint64_t Offset) {
|
uint64_t Offset) {
|
||||||
assert(IntPromotionTy && "Alloca is not an integer we can extract from");
|
assert(IntPromotionTy && "Alloca is not an integer we can extract from");
|
||||||
Value *V = IRB.CreateLoad(&NewAI, getName(".load"));
|
Value *V = IRB.CreateAlignedLoad(&NewAI, NewAI.getAlignment(),
|
||||||
|
getName(".load"));
|
||||||
assert(Offset >= NewAllocaBeginOffset && "Out of bounds offset");
|
assert(Offset >= NewAllocaBeginOffset && "Out of bounds offset");
|
||||||
uint64_t RelOffset = Offset - NewAllocaBeginOffset;
|
uint64_t RelOffset = Offset - NewAllocaBeginOffset;
|
||||||
if (RelOffset)
|
if (RelOffset)
|
||||||
@ -1912,7 +1913,7 @@ private:
|
|||||||
StoreInst *insertInteger(IRBuilder<> &IRB, Value *V, uint64_t Offset) {
|
StoreInst *insertInteger(IRBuilder<> &IRB, Value *V, uint64_t Offset) {
|
||||||
IntegerType *Ty = cast<IntegerType>(V->getType());
|
IntegerType *Ty = cast<IntegerType>(V->getType());
|
||||||
if (Ty == IntPromotionTy)
|
if (Ty == IntPromotionTy)
|
||||||
return IRB.CreateStore(V, &NewAI);
|
return IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlignment());
|
||||||
|
|
||||||
assert(Ty->getBitWidth() < IntPromotionTy->getBitWidth() &&
|
assert(Ty->getBitWidth() < IntPromotionTy->getBitWidth() &&
|
||||||
"Cannot insert a larger integer!");
|
"Cannot insert a larger integer!");
|
||||||
@ -1924,10 +1925,12 @@ private:
|
|||||||
|
|
||||||
APInt Mask = ~Ty->getMask().zext(IntPromotionTy->getBitWidth())
|
APInt Mask = ~Ty->getMask().zext(IntPromotionTy->getBitWidth())
|
||||||
.shl(RelOffset*8);
|
.shl(RelOffset*8);
|
||||||
Value *Old = IRB.CreateAnd(IRB.CreateLoad(&NewAI, getName(".oldload")),
|
Value *Old = IRB.CreateAnd(IRB.CreateAlignedLoad(&NewAI,
|
||||||
|
NewAI.getAlignment(),
|
||||||
|
getName(".oldload")),
|
||||||
Mask, getName(".mask"));
|
Mask, getName(".mask"));
|
||||||
return IRB.CreateStore(IRB.CreateOr(Old, V, getName(".insert")),
|
return IRB.CreateAlignedStore(IRB.CreateOr(Old, V, getName(".insert")),
|
||||||
&NewAI);
|
&NewAI, NewAI.getAlignment());
|
||||||
}
|
}
|
||||||
|
|
||||||
void deleteIfTriviallyDead(Value *V) {
|
void deleteIfTriviallyDead(Value *V) {
|
||||||
@ -1949,12 +1952,12 @@ private:
|
|||||||
Value *Result;
|
Value *Result;
|
||||||
if (LI.getType() == VecTy->getElementType() ||
|
if (LI.getType() == VecTy->getElementType() ||
|
||||||
BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset) {
|
BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset) {
|
||||||
Result
|
Result = IRB.CreateExtractElement(
|
||||||
= IRB.CreateExtractElement(IRB.CreateLoad(&NewAI, getName(".load")),
|
IRB.CreateAlignedLoad(&NewAI, NewAI.getAlignment(), getName(".load")),
|
||||||
getIndex(IRB, BeginOffset),
|
getIndex(IRB, BeginOffset), getName(".extract"));
|
||||||
getName(".extract"));
|
|
||||||
} else {
|
} else {
|
||||||
Result = IRB.CreateLoad(&NewAI, getName(".load"));
|
Result = IRB.CreateAlignedLoad(&NewAI, NewAI.getAlignment(),
|
||||||
|
getName(".load"));
|
||||||
}
|
}
|
||||||
if (Result->getType() != LI.getType())
|
if (Result->getType() != LI.getType())
|
||||||
Result = getValueCast(IRB, Result, LI.getType());
|
Result = getValueCast(IRB, Result, LI.getType());
|
||||||
@ -2002,13 +2005,14 @@ private:
|
|||||||
BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset) {
|
BeginOffset > NewAllocaBeginOffset || EndOffset < NewAllocaEndOffset) {
|
||||||
if (V->getType() != ElementTy)
|
if (V->getType() != ElementTy)
|
||||||
V = getValueCast(IRB, V, ElementTy);
|
V = getValueCast(IRB, V, ElementTy);
|
||||||
V = IRB.CreateInsertElement(IRB.CreateLoad(&NewAI, getName(".load")), V,
|
LoadInst *LI = IRB.CreateAlignedLoad(&NewAI, NewAI.getAlignment(),
|
||||||
getIndex(IRB, BeginOffset),
|
getName(".load"));
|
||||||
|
V = IRB.CreateInsertElement(LI, V, getIndex(IRB, BeginOffset),
|
||||||
getName(".insert"));
|
getName(".insert"));
|
||||||
} else if (V->getType() != VecTy) {
|
} else if (V->getType() != VecTy) {
|
||||||
V = getValueCast(IRB, V, VecTy);
|
V = getValueCast(IRB, V, VecTy);
|
||||||
}
|
}
|
||||||
StoreInst *Store = IRB.CreateStore(V, &NewAI);
|
StoreInst *Store = IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlignment());
|
||||||
Pass.DeadInsts.push_back(&SI);
|
Pass.DeadInsts.push_back(&SI);
|
||||||
|
|
||||||
(void)Store;
|
(void)Store;
|
||||||
@ -2073,11 +2077,15 @@ private:
|
|||||||
!TD.isLegalInteger(TD.getTypeSizeInBits(ScalarTy)))) {
|
!TD.isLegalInteger(TD.getTypeSizeInBits(ScalarTy)))) {
|
||||||
Type *SizeTy = II.getLength()->getType();
|
Type *SizeTy = II.getLength()->getType();
|
||||||
Constant *Size = ConstantInt::get(SizeTy, EndOffset - BeginOffset);
|
Constant *Size = ConstantInt::get(SizeTy, EndOffset - BeginOffset);
|
||||||
|
unsigned Align = 1;
|
||||||
|
if (NewAI.getAlignment())
|
||||||
|
Align = MinAlign(NewAI.getAlignment(),
|
||||||
|
BeginOffset - NewAllocaBeginOffset);
|
||||||
|
|
||||||
CallInst *New
|
CallInst *New
|
||||||
= IRB.CreateMemSet(getAdjustedAllocaPtr(IRB,
|
= IRB.CreateMemSet(getAdjustedAllocaPtr(IRB,
|
||||||
II.getRawDest()->getType()),
|
II.getRawDest()->getType()),
|
||||||
II.getValue(), Size, II.getAlignment(),
|
II.getValue(), Size, Align,
|
||||||
II.isVolatile());
|
II.isVolatile());
|
||||||
(void)New;
|
(void)New;
|
||||||
DEBUG(dbgs() << " to: " << *New << "\n");
|
DEBUG(dbgs() << " to: " << *New << "\n");
|
||||||
@ -2115,11 +2123,13 @@ private:
|
|||||||
// If this is an element-wide memset of a vectorizable alloca, insert it.
|
// If this is an element-wide memset of a vectorizable alloca, insert it.
|
||||||
if (VecTy && (BeginOffset > NewAllocaBeginOffset ||
|
if (VecTy && (BeginOffset > NewAllocaBeginOffset ||
|
||||||
EndOffset < NewAllocaEndOffset)) {
|
EndOffset < NewAllocaEndOffset)) {
|
||||||
StoreInst *Store = IRB.CreateStore(
|
StoreInst *Store = IRB.CreateAlignedStore(
|
||||||
IRB.CreateInsertElement(IRB.CreateLoad(&NewAI, getName(".load")), V,
|
IRB.CreateInsertElement(IRB.CreateAlignedLoad(&NewAI,
|
||||||
getIndex(IRB, BeginOffset),
|
NewAI.getAlignment(),
|
||||||
|
getName(".load")),
|
||||||
|
V, getIndex(IRB, BeginOffset),
|
||||||
getName(".insert")),
|
getName(".insert")),
|
||||||
&NewAI);
|
&NewAI, NewAI.getAlignment());
|
||||||
(void)Store;
|
(void)Store;
|
||||||
DEBUG(dbgs() << " to: " << *Store << "\n");
|
DEBUG(dbgs() << " to: " << *Store << "\n");
|
||||||
return true;
|
return true;
|
||||||
@ -2137,7 +2147,8 @@ private:
|
|||||||
assert(V->getType() == VecTy);
|
assert(V->getType() == VecTy);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value *New = IRB.CreateStore(V, &NewAI, II.isVolatile());
|
Value *New = IRB.CreateAlignedStore(V, &NewAI, NewAI.getAlignment(),
|
||||||
|
II.isVolatile());
|
||||||
(void)New;
|
(void)New;
|
||||||
DEBUG(dbgs() << " to: " << *New << "\n");
|
DEBUG(dbgs() << " to: " << *New << "\n");
|
||||||
return !II.isVolatile();
|
return !II.isVolatile();
|
||||||
@ -2227,6 +2238,11 @@ private:
|
|||||||
OtherPtr = getAdjustedPtr(IRB, TD, OtherPtr, RelOffset, OtherPtrTy,
|
OtherPtr = getAdjustedPtr(IRB, TD, OtherPtr, RelOffset, OtherPtrTy,
|
||||||
getName("." + OtherPtr->getName()));
|
getName("." + OtherPtr->getName()));
|
||||||
|
|
||||||
|
unsigned Align = II.getAlignment();
|
||||||
|
if (Align > 1)
|
||||||
|
Align = MinAlign(RelOffset.zextOrTrunc(64).getZExtValue(),
|
||||||
|
MinAlign(II.getAlignment(), NewAI.getAlignment()));
|
||||||
|
|
||||||
// Strip all inbounds GEPs and pointer casts to try to dig out any root
|
// Strip all inbounds GEPs and pointer casts to try to dig out any root
|
||||||
// alloca that should be re-examined after rewriting this instruction.
|
// alloca that should be re-examined after rewriting this instruction.
|
||||||
if (AllocaInst *AI
|
if (AllocaInst *AI
|
||||||
@ -2242,8 +2258,7 @@ private:
|
|||||||
|
|
||||||
CallInst *New = IRB.CreateMemCpy(IsDest ? OurPtr : OtherPtr,
|
CallInst *New = IRB.CreateMemCpy(IsDest ? OurPtr : OtherPtr,
|
||||||
IsDest ? OtherPtr : OurPtr,
|
IsDest ? OtherPtr : OurPtr,
|
||||||
Size, II.getAlignment(),
|
Size, Align, II.isVolatile());
|
||||||
II.isVolatile());
|
|
||||||
(void)New;
|
(void)New;
|
||||||
DEBUG(dbgs() << " to: " << *New << "\n");
|
DEBUG(dbgs() << " to: " << *New << "\n");
|
||||||
return false;
|
return false;
|
||||||
@ -2257,24 +2272,26 @@ private:
|
|||||||
Value *Src;
|
Value *Src;
|
||||||
if (IsVectorElement && !IsDest) {
|
if (IsVectorElement && !IsDest) {
|
||||||
// We have to extract rather than load.
|
// We have to extract rather than load.
|
||||||
Src = IRB.CreateExtractElement(IRB.CreateLoad(SrcPtr,
|
Src = IRB.CreateExtractElement(
|
||||||
getName(".copyload")),
|
IRB.CreateAlignedLoad(SrcPtr, Align, getName(".copyload")),
|
||||||
getIndex(IRB, BeginOffset),
|
getIndex(IRB, BeginOffset),
|
||||||
getName(".copyextract"));
|
getName(".copyextract"));
|
||||||
} else {
|
} else {
|
||||||
Src = IRB.CreateLoad(SrcPtr, II.isVolatile(), getName(".copyload"));
|
Src = IRB.CreateAlignedLoad(SrcPtr, Align, II.isVolatile(),
|
||||||
|
getName(".copyload"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsVectorElement && IsDest) {
|
if (IsVectorElement && IsDest) {
|
||||||
// We have to insert into a loaded copy before storing.
|
// We have to insert into a loaded copy before storing.
|
||||||
Src = IRB.CreateInsertElement(IRB.CreateLoad(&NewAI, getName(".load")),
|
Src = IRB.CreateInsertElement(
|
||||||
Src, getIndex(IRB, BeginOffset),
|
IRB.CreateAlignedLoad(&NewAI, NewAI.getAlignment(), getName(".load")),
|
||||||
getName(".insert"));
|
Src, getIndex(IRB, BeginOffset),
|
||||||
|
getName(".insert"));
|
||||||
}
|
}
|
||||||
|
|
||||||
StoreInst *Store = cast<StoreInst>(IRB.CreateStore(Src, DstPtr,
|
StoreInst *Store = cast<StoreInst>(
|
||||||
II.isVolatile()));
|
IRB.CreateAlignedStore(Src, DstPtr, Align, II.isVolatile()));
|
||||||
Store->setAlignment(II.getAlignment());
|
(void)Store;
|
||||||
DEBUG(dbgs() << " to: " << *Store << "\n");
|
DEBUG(dbgs() << " to: " << *Store << "\n");
|
||||||
return !II.isVolatile();
|
return !II.isVolatile();
|
||||||
}
|
}
|
||||||
|
46
test/Transforms/SROA/alignment.ll
Normal file
46
test/Transforms/SROA/alignment.ll
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
; RUN: opt < %s -sroa -S | FileCheck %s
|
||||||
|
target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
|
||||||
|
|
||||||
|
declare void @llvm.memcpy.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1)
|
||||||
|
|
||||||
|
define void @test1({ i8, i8 }* %a, { i8, i8 }* %b) {
|
||||||
|
; CHECK: @test1
|
||||||
|
; CHECK: %[[gep_a0:.*]] = getelementptr inbounds { i8, i8 }* %a, i64 0, i32 0
|
||||||
|
; CHECK: %[[a0:.*]] = load i8* %[[gep_a0]], align 16
|
||||||
|
; CHECK: %[[gep_a1:.*]] = getelementptr inbounds { i8, i8 }* %a, i64 0, i32 1
|
||||||
|
; CHECK: %[[a1:.*]] = load i8* %[[gep_a1]], align 1
|
||||||
|
; CHECK: %[[gep_b0:.*]] = getelementptr inbounds { i8, i8 }* %b, i64 0, i32 0
|
||||||
|
; CHECK: store i8 %[[a0]], i8* %[[gep_b0]], align 16
|
||||||
|
; CHECK: %[[gep_b1:.*]] = getelementptr inbounds { i8, i8 }* %b, i64 0, i32 1
|
||||||
|
; CHECK: store i8 %[[a1]], i8* %[[gep_b1]], align 1
|
||||||
|
; CHECK: ret void
|
||||||
|
|
||||||
|
entry:
|
||||||
|
%alloca = alloca { i8, i8 }, align 16
|
||||||
|
%gep_a = getelementptr { i8, i8 }* %a, i32 0, i32 0
|
||||||
|
%gep_alloca = getelementptr { i8, i8 }* %alloca, i32 0, i32 0
|
||||||
|
%gep_b = getelementptr { i8, i8 }* %b, i32 0, i32 0
|
||||||
|
|
||||||
|
store i8 420, i8* %gep_alloca, align 16
|
||||||
|
|
||||||
|
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %gep_alloca, i8* %gep_a, i32 2, i32 16, i1 false)
|
||||||
|
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %gep_b, i8* %gep_alloca, i32 2, i32 16, i1 false)
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @PR13920(<2 x i64>* %a, i16* %b) {
|
||||||
|
; Test that alignments on memcpy intrinsics get propagated to loads and stores.
|
||||||
|
; CHECK: @PR13920
|
||||||
|
; CHECK: load <2 x i64>* %a, align 2
|
||||||
|
; CHECK: store <2 x i64> {{.*}}, <2 x i64>* {{.*}}, align 2
|
||||||
|
; CHECK: ret void
|
||||||
|
|
||||||
|
entry:
|
||||||
|
%aa = alloca <2 x i64>, align 16
|
||||||
|
%aptr = bitcast <2 x i64>* %a to i8*
|
||||||
|
%aaptr = bitcast <2 x i64>* %aa to i8*
|
||||||
|
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %aaptr, i8* %aptr, i32 16, i32 2, i1 false)
|
||||||
|
%bptr = bitcast i16* %b to i8*
|
||||||
|
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %bptr, i8* %aaptr, i32 16, i32 2, i1 false)
|
||||||
|
ret void
|
||||||
|
}
|
@ -897,18 +897,3 @@ if.end:
|
|||||||
%tmp2 = load i8* %gep
|
%tmp2 = load i8* %gep
|
||||||
ret void
|
ret void
|
||||||
}
|
}
|
||||||
|
|
||||||
define void @test23(<2 x i64> %a, i16* %b) {
|
|
||||||
; CHECK: @test23
|
|
||||||
; CHECK: store {{.*}}, align 2
|
|
||||||
; CHECK: ret void
|
|
||||||
; PR13920
|
|
||||||
|
|
||||||
entry:
|
|
||||||
%a.addr = alloca <2 x i64>, align 16
|
|
||||||
store <2 x i64> %a, <2 x i64>* %a.addr, align 16
|
|
||||||
%0 = bitcast i16* %b to i8*
|
|
||||||
%1 = bitcast <2 x i64>* %a.addr to i8*
|
|
||||||
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %0, i8* %1, i32 16, i32 2, i1 false)
|
|
||||||
ret void
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user