diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp index 5de47b8625b377..d2bdd2a0d4e00a 100644 --- a/llvm/lib/IR/DataLayout.cpp +++ b/llvm/lib/IR/DataLayout.cpp @@ -903,9 +903,13 @@ int64_t DataLayout::getIndexedOffsetInType(Type *ElemTy, static void addElementIndex(SmallVectorImpl &Indices, TypeSize ElemSize, APInt &Offset) { - // Skip over scalable or zero size elements. - if (ElemSize.isScalable() || ElemSize == 0) { - Indices.push_back(APInt::getZero(Offset.getBitWidth())); + // Skip over scalable or zero size elements. Also skip element sizes larger + // than the positive index space, because the arithmetic below may not be + // correct in that case. + unsigned BitWidth = Offset.getBitWidth(); + if (ElemSize.isScalable() || ElemSize == 0 || + !isUIntN(BitWidth - 1, ElemSize)) { + Indices.push_back(APInt::getZero(BitWidth)); return; } diff --git a/llvm/test/Transforms/GlobalOpt/large-element-size.ll b/llvm/test/Transforms/GlobalOpt/large-element-size.ll new file mode 100644 index 00000000000000..1c091521380840 --- /dev/null +++ b/llvm/test/Transforms/GlobalOpt/large-element-size.ll @@ -0,0 +1,12 @@ +; RUN: opt -S -passes=globalopt < %s | FileCheck %s + +target datalayout = "p:32:32" + +%struct.s.2 = type { %struct.t.1, %struct.t.1, %struct.t.1, %struct.u.0, %struct.u.0 } +%struct.t.1 = type { %struct.u.0, %struct.u.0, %struct.u.0, %struct.u.0, i32, i32, i32, i32 } +%struct.u.0 = type { i32, i32, i32, i8 } + +@s = external global [700 x [24000 x %struct.s.2]], align 1 +@p = global %struct.s.2* bitcast (i8* getelementptr (i8, i8* bitcast ([700 x [24000 x %struct.s.2]]* @s to i8*), i64 2247483647) to %struct.s.2*), align 1 + +; CHECK: @p = local_unnamed_addr global %struct.s.2* bitcast (i8* getelementptr (i8, i8* bitcast ([700 x [24000 x %struct.s.2]]* @s to i8*), i32 -2047483649) to %struct.s.2*), align 1