Skip to content

Commit

Permalink
Handle big index in getelementptr instruction
Browse files Browse the repository at this point in the history
CodeGen incorrectly ignores (assert from APInt) constant index bigger
than 2^64 in getelementptr instruction. This is a test and fix for that.

Patch by Paweł Bylica!

Reviewed By: rnk

Subscribers: majnemer, rnk, mcrosier, resistor, llvm-commits

Differential Revision: http://reviews.llvm.org/D8219

llvm-svn: 231984
  • Loading branch information
rnk committed Mar 11, 2015
1 parent ce2e77c commit 016c6b2
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 21 deletions.
6 changes: 3 additions & 3 deletions llvm/lib/CodeGen/SelectionDAG/FastISel.cpp
Expand Up @@ -497,7 +497,7 @@ bool FastISel::selectGetElementPtr(const User *I) {
OI != E; ++OI) {
const Value *Idx = *OI;
if (auto *StTy = dyn_cast<StructType>(Ty)) {
unsigned Field = cast<ConstantInt>(Idx)->getZExtValue();
uint64_t Field = cast<ConstantInt>(Idx)->getZExtValue();
if (Field) {
// N = N + Offset
TotalOffs += DL.getStructLayout(StTy)->getElementOffset(Field);
Expand All @@ -518,8 +518,8 @@ bool FastISel::selectGetElementPtr(const User *I) {
if (CI->isZero())
continue;
// N = N + Offset
TotalOffs +=
DL.getTypeAllocSize(Ty) * cast<ConstantInt>(CI)->getSExtValue();
uint64_t IdxN = CI->getValue().sextOrTrunc(64).getSExtValue();
TotalOffs += DL.getTypeAllocSize(Ty) * IdxN;
if (TotalOffs >= MaxOffs) {
N = fastEmit_ri_(VT, ISD::ADD, N, NIsKill, TotalOffs, VT);
if (!N) // Unhandled operand. Halt "fast" selection and bail.
Expand Down
27 changes: 9 additions & 18 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Expand Up @@ -3448,30 +3448,21 @@ void SelectionDAGBuilder::visitGetElementPtr(const User &I) {
Ty = StTy->getElementType(Field);
} else {
Ty = cast<SequentialType>(Ty)->getElementType();
MVT PtrTy = DAG.getTargetLoweringInfo().getPointerTy(AS);
unsigned PtrSize = PtrTy.getSizeInBits();
APInt ElementSize(PtrSize, DL->getTypeAllocSize(Ty));

// If this is a constant subscript, handle it quickly.
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
if (const ConstantInt *CI = dyn_cast<ConstantInt>(Idx)) {
if (CI->isZero()) continue;
uint64_t Offs =
DL->getTypeAllocSize(Ty)*cast<ConstantInt>(CI)->getSExtValue();
SDValue OffsVal;
EVT PTy = TLI.getPointerTy(AS);
unsigned PtrBits = PTy.getSizeInBits();
if (PtrBits < 64)
OffsVal = DAG.getNode(ISD::TRUNCATE, getCurSDLoc(), PTy,
DAG.getConstant(Offs, MVT::i64));
else
OffsVal = DAG.getConstant(Offs, PTy);

N = DAG.getNode(ISD::ADD, getCurSDLoc(), N.getValueType(), N,
OffsVal);
if (const auto *CI = dyn_cast<ConstantInt>(Idx)) {
if (CI->isZero())
continue;
APInt Offs = ElementSize * CI->getValue().sextOrTrunc(PtrSize);
SDValue OffsVal = DAG.getConstant(Offs, PtrTy);
N = DAG.getNode(ISD::ADD, getCurSDLoc(), N.getValueType(), N, OffsVal);
continue;
}

// N = N + Idx * ElementSize;
APInt ElementSize =
APInt(TLI.getPointerSizeInBits(AS), DL->getTypeAllocSize(Ty));
SDValue IdxN = getValue(Idx);

// If the index is smaller or larger than intptr_t, truncate or extend
Expand Down
80 changes: 80 additions & 0 deletions llvm/test/CodeGen/X86/getelementptr.ll
@@ -0,0 +1,80 @@
; RUN: llc < %s -O0 -march=x86
; RUN: llc < %s -O0 -march=x86-64
; RUN: llc < %s -O2 -march=x86
; RUN: llc < %s -O2 -march=x86-64


; Test big index trunc to pointer size:

define i8* @test_trunc65(i8* %ptr) nounwind {
; CHECK-LABEL: test_trunc65
; CHECK: 3
%d = getelementptr i8, i8* %ptr, i65 18446744073709551619 ; 2^64 + 3
ret i8* %d
}

define i8* @test_trunc128(i8* %ptr) nounwind {
; CHECK-LABEL: test_trunc128
; CHECK: 5
%d = getelementptr i8, i8* %ptr, i128 18446744073709551621 ; 2^64 + 5
ret i8* %d
}

define i8* @test_trunc160(i8* %ptr) nounwind {
; CHECK-LABEL: test_trunc160
; CHECK: 8
%d = getelementptr i8, i8* %ptr, i160 18446744073709551624 ; 2^64 + 8
ret i8* %d
}

define i8* @test_trunc256(i8* %ptr) nounwind {
; CHECK-LABEL: test_trunc256
; CHECK: 13
%d = getelementptr i8, i8* %ptr, i256 18446744073709551629 ; 2^64 + 13
ret i8* %d
}

define i8* @test_trunc2048(i8* %ptr) nounwind {
; CHECK-LABEL: test_trunc2048
; CHECK: 21
%d = getelementptr i8, i8* %ptr, i2048 18446744073709551637 ; 2^64 + 21
ret i8* %d
}


; Test small index sext to pointer size

define i8* @test_sext3(i8* %ptr) nounwind {
; CHECK-LABEL: test_sext3
; CHECK: -3
%d = getelementptr i8, i8* %ptr, i3 -3
ret i8* %d
}

define i8* @test_sext5(i8* %ptr) nounwind {
; CHECK-LABEL: test_sext5
; CHECK: -5
%d = getelementptr i8, i8* %ptr, i5 -5
ret i8* %d
}

define i8* @test_sext8(i8* %ptr) nounwind {
; CHECK-LABEL: test_sext8
; CHECK: -8
%d = getelementptr i8, i8* %ptr, i8 -8
ret i8* %d
}

define i8* @test_sext13(i8* %ptr) nounwind {
; CHECK-LABEL: test_sext13
; CHECK: -13
%d = getelementptr i8, i8* %ptr, i8 -13
ret i8* %d
}

define i8* @test_sext16(i8* %ptr) nounwind {
; CHECK-LABEL: test_sext16
; CHECK: -21
%d = getelementptr i8, i8* %ptr, i8 -21
ret i8* %d
}

0 comments on commit 016c6b2

Please sign in to comment.