summaryrefslogtreecommitdiff
path: root/lib/Transforms
diff options
context:
space:
mode:
authorJingyue Wu <jingyue@google.com>2014-05-23 18:39:40 +0000
committerJingyue Wu <jingyue@google.com>2014-05-23 18:39:40 +0000
commit8d959dd5638cdc556c736637e78639a3ccf074fc (patch)
treed04ef8acd2a0d3019185114ad91f582d0cecfafe /lib/Transforms
parentbb75e24528a4bdb3030787640e4d5adb7cdfc476 (diff)
downloadllvm-8d959dd5638cdc556c736637e78639a3ccf074fc.tar.gz
llvm-8d959dd5638cdc556c736637e78639a3ccf074fc.tar.bz2
llvm-8d959dd5638cdc556c736637e78639a3ccf074fc.tar.xz
Add the extracted constant offset using GEP
Fixed a TODO in r207783. Add the extracted constant offset using GEP instead of ugly ptrtoint+add+inttoptr. Using GEP simplifies future optimizations and makes IR easier to understand. Updated all affected tests, and added a new test in split-gep.ll to cover a corner case where emitting uglygep is necessary. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@209537 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms')
-rw-r--r--lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp76
1 files changed, 50 insertions, 26 deletions
diff --git a/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp b/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
index 0ccf29c225..ac3e7c4d74 100644
--- a/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
+++ b/lib/Transforms/Scalar/SeparateConstOffsetFromGEP.cpp
@@ -487,7 +487,8 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
int64_t ConstantOffset =
ConstantOffsetExtractor::Extract(GEP->getOperand(I), NewIdx, DL, GEP);
if (ConstantOffset != 0) {
- assert(NewIdx && "ConstantOffset != 0 implies NewIdx is set");
+ assert(NewIdx != nullptr &&
+ "ConstantOffset != 0 implies NewIdx is set");
GEP->setOperand(I, NewIdx);
// Clear the inbounds attribute because the new index may be off-bound.
// e.g.,
@@ -522,44 +523,67 @@ bool SeparateConstOffsetFromGEP::splitGEP(GetElementPtrInst *GEP) {
// => add the offset
//
// %gep2 ; clone of %gep
- // %0 = ptrtoint %gep2
- // %1 = add %0, <offset>
- // %new.gep = inttoptr %1
+ // %new.gep = gep %gep2, <offset / sizeof(*%gep)>
// %gep ; will be removed
// ... %gep ...
//
// => replace all uses of %gep with %new.gep and remove %gep
//
// %gep2 ; clone of %gep
- // %0 = ptrtoint %gep2
- // %1 = add %0, <offset>
- // %new.gep = inttoptr %1
+ // %new.gep = gep %gep2, <offset / sizeof(*%gep)>
// ... %new.gep ...
//
- // TODO(jingyue): Emit a GEP instead of an "uglygep"
- // (http://llvm.org/docs/GetElementPtr.html#what-s-an-uglygep) to make the IR
- // prettier and more alias analysis friendly. One caveat: if the original GEP
- // ends with a StructType, we need to split the GEP at the last
- // SequentialType. For instance, consider the following IR:
+ // If AccumulativeByteOffset is not a multiple of sizeof(*%gep), we emit an
+ // uglygep (http://llvm.org/docs/GetElementPtr.html#what-s-an-uglygep):
+ // bitcast %gep2 to i8*, add the offset, and bitcast the result back to the
+ // type of %gep.
//
- // %struct.S = type { float, double }
- // @array = global [1024 x %struct.S]
- // %p = getelementptr %array, 0, %i + 5, 1
- //
- // To separate the constant 5 from %p, we would need to split %p at the last
- // array index so that we have:
- //
- // %addr = gep %array, 0, %i
- // %p = gep %addr, 5, 1
+ // %gep2 ; clone of %gep
+ // %0 = bitcast %gep2 to i8*
+ // %uglygep = gep %0, <offset>
+ // %new.gep = bitcast %uglygep to <type of %gep>
+ // ... %new.gep ...
Instruction *NewGEP = GEP->clone();
NewGEP->insertBefore(GEP);
+
Type *IntPtrTy = DL->getIntPtrType(GEP->getType());
- Value *Addr = new PtrToIntInst(NewGEP, IntPtrTy, "", GEP);
- Addr = BinaryOperator::CreateAdd(
- Addr, ConstantInt::get(IntPtrTy, AccumulativeByteOffset, true), "", GEP);
- Addr = new IntToPtrInst(Addr, GEP->getType(), "", GEP);
+ uint64_t ElementTypeSizeOfGEP =
+ DL->getTypeAllocSize(GEP->getType()->getElementType());
+ 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);
+ NewGEP = GetElementPtrInst::Create(
+ NewGEP, ConstantInt::get(IntPtrTy, Index, true), GEP->getName(), GEP);
+ } else {
+ // Unlikely but possible. For example,
+ // #pragma pack(1)
+ // struct S {
+ // int a[3];
+ // int64 b[8];
+ // };
+ // #pragma pack()
+ //
+ // Suppose the gep before extraction is &s[i + 1].b[j + 3]. After
+ // extraction, it becomes &s[i].b[j] and AccumulativeByteOffset is
+ // sizeof(S) + 3 * sizeof(int64) = 100, which is not a multiple of
+ // sizeof(int64).
+ //
+ // Emit an uglygep in this case.
+ Type *I8PtrTy = Type::getInt8PtrTy(GEP->getContext(),
+ GEP->getPointerAddressSpace());
+ NewGEP = new BitCastInst(NewGEP, I8PtrTy, "", GEP);
+ NewGEP = GetElementPtrInst::Create(
+ NewGEP, ConstantInt::get(IntPtrTy, AccumulativeByteOffset, true),
+ "uglygep", GEP);
+ if (GEP->getType() != I8PtrTy)
+ NewGEP = new BitCastInst(NewGEP, GEP->getType(), GEP->getName(), GEP);
+ }
- GEP->replaceAllUsesWith(Addr);
+ GEP->replaceAllUsesWith(NewGEP);
GEP->eraseFromParent();
return true;