From: Jingyue Wu Date: Sat, 25 Oct 2014 18:34:03 +0000 (+0000) Subject: [SeparateConstOffsetFromGEP] Fixed a bug related to unsigned modulo X-Git-Url: http://plrg.eecs.uci.edu/git/?a=commitdiff_plain;h=71fe4f0197dd6bcfd476a96d1cc65e119124009a;p=oota-llvm.git [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 --- diff --git a/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp b/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp index 449198c1d2f..5d298027bfc 100644 --- a/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp +++ b/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp @@ -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( + 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(ElementTypeSizeOfGEP); + int64_t Index = AccumulativeByteOffset / ElementTypeSizeOfGEP; NewGEP = GetElementPtrInst::Create( NewGEP, ConstantInt::get(IntPtrTy, Index, true), GEP->getName(), GEP); } else { diff --git a/test/Transforms/SeparateConstOffsetFromGEP/NVPTX/split-gep.ll b/test/Transforms/SeparateConstOffsetFromGEP/NVPTX/split-gep.ll index 4d07ab35b51..ea0d3f5673a 100644 --- a/test/Transforms/SeparateConstOffsetFromGEP/NVPTX/split-gep.ll +++ b/test/Transforms/SeparateConstOffsetFromGEP/NVPTX/split-gep.ll @@ -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 +}