mirror of
https://github.com/RPCS3/llvm.git
synced 2024-12-20 11:08:27 +00:00
[SeparateConstOffsetFromGEP] Fixed a bug related to unsigned modulo
The dividend in "signed % unsigned" is treated as unsigned instead of signed, causing unexpected behavior such as -64 % (uint64_t)24 == 0. Added a regression test in split-gep.ll Patched by Hao Liu. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@220618 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
1f79facb06
commit
71fe4f0197
@ -720,16 +720,16 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
|
|||||||
Instruction *NewGEP = GEP->clone();
|
Instruction *NewGEP = GEP->clone();
|
||||||
NewGEP->insertBefore(GEP);
|
NewGEP->insertBefore(GEP);
|
||||||
|
|
||||||
uint64_t ElementTypeSizeOfGEP =
|
// Per ANSI C standard, signed / unsigned = unsigned and signed % unsigned =
|
||||||
DL->getTypeAllocSize(GEP->getType()->getElementType());
|
// unsigned.. Therefore, we cast ElementTypeSizeOfGEP to signed because it is
|
||||||
|
// used with unsigned integers later.
|
||||||
|
int64_t ElementTypeSizeOfGEP = static_cast<int64_t>(
|
||||||
|
DL->getTypeAllocSize(GEP->getType()->getElementType()));
|
||||||
Type *IntPtrTy = DL->getIntPtrType(GEP->getType());
|
Type *IntPtrTy = DL->getIntPtrType(GEP->getType());
|
||||||
if (AccumulativeByteOffset % ElementTypeSizeOfGEP == 0) {
|
if (AccumulativeByteOffset % ElementTypeSizeOfGEP == 0) {
|
||||||
// Very likely. As long as %gep is natually aligned, the byte offset we
|
// Very likely. As long as %gep is natually aligned, the byte offset we
|
||||||
// extracted should be a multiple of sizeof(*%gep).
|
// extracted should be a multiple of sizeof(*%gep).
|
||||||
// Per ANSI C standard, signed / unsigned = unsigned. Therefore, we
|
int64_t Index = AccumulativeByteOffset / ElementTypeSizeOfGEP;
|
||||||
// cast ElementTypeSizeOfGEP to signed.
|
|
||||||
int64_t Index =
|
|
||||||
AccumulativeByteOffset / static_cast<int64_t>(ElementTypeSizeOfGEP);
|
|
||||||
NewGEP = GetElementPtrInst::Create(
|
NewGEP = GetElementPtrInst::Create(
|
||||||
NewGEP, ConstantInt::get(IntPtrTy, Index, true), GEP->getName(), GEP);
|
NewGEP, ConstantInt::get(IntPtrTy, Index, true), GEP->getName(), GEP);
|
||||||
} else {
|
} else {
|
||||||
|
@ -253,3 +253,27 @@ entry:
|
|||||||
ret float* %p
|
ret float* %p
|
||||||
; CHECK-NEXT: ret
|
; CHECK-NEXT: ret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
; The source code used to be buggy in checking
|
||||||
|
; (AccumulativeByteOffset % ElementTypeSizeOfGEP == 0)
|
||||||
|
; where AccumulativeByteOffset is signed but ElementTypeSizeOfGEP is unsigned.
|
||||||
|
; The compiler would promote AccumulativeByteOffset to unsigned, causing
|
||||||
|
; unexpected results. For example, while -64 % (int64_t)24 != 0,
|
||||||
|
; -64 % (uint64_t)24 == 0.
|
||||||
|
%struct3 = type { i64, i32 }
|
||||||
|
%struct2 = type { %struct3, i32 }
|
||||||
|
%struct1 = type { i64, %struct2 }
|
||||||
|
%struct0 = type { i32, i32, i64*, [100 x %struct1] }
|
||||||
|
define %struct2* @sign_mod_unsign(%struct0* %ptr, i64 %idx) {
|
||||||
|
; CHECK-LABEL: @sign_mod_unsign(
|
||||||
|
entry:
|
||||||
|
%arrayidx = add nsw i64 %idx, -2
|
||||||
|
; CHECK-NOT: add
|
||||||
|
%ptr2 = getelementptr inbounds %struct0* %ptr, i64 0, i32 3, i64 %arrayidx, i32 1
|
||||||
|
; CHECK: [[PTR:%[a-zA-Z0-9]+]] = getelementptr %struct0* %ptr, i64 0, i32 3, i64 %idx, i32 1
|
||||||
|
; CHECK: [[PTR1:%[a-zA-Z0-9]+]] = bitcast %struct2* [[PTR]] to i8*
|
||||||
|
; CHECK: getelementptr i8* [[PTR1]], i64 -64
|
||||||
|
; CHECK: bitcast
|
||||||
|
ret %struct2* %ptr2
|
||||||
|
; CHECK-NEXT: ret
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user