forked from OSchip/llvm-project
[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. llvm-svn: 220618
This commit is contained in:
parent
aa139573f6
commit
fe72fcebf6
|
@ -720,16 +720,16 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
|
|||
Instruction *NewGEP = GEP->clone();
|
||||
NewGEP->insertBefore(GEP);
|
||||
|
||||
uint64_t ElementTypeSizeOfGEP =
|
||||
DL->getTypeAllocSize(GEP->getType()->getElementType());
|
||||
// Per ANSI C standard, signed / unsigned = unsigned and signed % unsigned =
|
||||
// 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());
|
||||
if (AccumulativeByteOffset % ElementTypeSizeOfGEP == 0) {
|
||||
// Very likely. As long as %gep is natually aligned, the byte offset we
|
||||
// extracted should be a multiple of sizeof(*%gep).
|
||||
// Per ANSI C standard, signed / unsigned = unsigned. Therefore, we
|
||||
// cast ElementTypeSizeOfGEP to signed.
|
||||
int64_t Index =
|
||||
AccumulativeByteOffset / static_cast<int64_t>(ElementTypeSizeOfGEP);
|
||||
int64_t Index = AccumulativeByteOffset / ElementTypeSizeOfGEP;
|
||||
NewGEP = GetElementPtrInst::Create(
|
||||
NewGEP, ConstantInt::get(IntPtrTy, Index, true), GEP->getName(), GEP);
|
||||
} else {
|
||||
|
|
|
@ -253,3 +253,27 @@ entry:
|
|||
ret float* %p
|
||||
; 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