// Also, this helps GlobalOpt do SROA on GlobalVariables.
SmallVector<Constant *, 32> NewIdxs;
Type *Ty = PTy;
- SrcElemTy = PTy->getElementType();
+
+ // For GEPs of GlobalValues, use the value type even for opaque pointers.
+ // Otherwise use an i8 GEP.
+ if (auto *GV = dyn_cast<GlobalValue>(Ptr))
+ SrcElemTy = GV->getValueType();
+ else if (!PTy->isOpaque())
+ SrcElemTy = PTy->getElementType();
+ else
+ SrcElemTy = Type::getInt8Ty(Ptr->getContext());
do {
if (!Ty->isStructTy()) {
// Create a GEP.
Constant *C = ConstantExpr::getGetElementPtr(SrcElemTy, Ptr, NewIdxs,
InBounds, InRangeIndex);
- assert(C->getType()->getPointerElementType() == Ty &&
+ assert(cast<PointerType>(C->getType())->isOpaqueOrPointeeTypeMatches(Ty) &&
"Computed GetElementPtr has unexpected type!");
// If we ended up indexing a member with a type that doesn't match
--- /dev/null
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -instcombine -force-opaque-pointers < %s | FileCheck %s
+
+@g = global [16 x i16] zeroinitializer
+
+define ptr @gep_constexpr_gv_1() {
+; CHECK-LABEL: @gep_constexpr_gv_1(
+; CHECK-NEXT: ret ptr getelementptr inbounds ([16 x i16], ptr @g, i64 0, i64 10)
+;
+ ret ptr getelementptr([16 x i16], ptr @g, i64 0, i64 10)
+}
+
+define ptr @gep_constexpr_gv_2() {
+; CHECK-LABEL: @gep_constexpr_gv_2(
+; CHECK-NEXT: ret ptr getelementptr inbounds ([16 x i16], ptr @g, i64 0, i64 12)
+;
+ ret ptr getelementptr(i32, ptr getelementptr([16 x i16], ptr @g, i64 0, i64 10), i64 1)
+}
+
+; Silly expression to get an inttoptr that does not combine with the GEP.
+define ptr @gep_constexpr_inttoptr() {
+; CHECK-LABEL: @gep_constexpr_inttoptr(
+; CHECK-NEXT: ret ptr getelementptr (i8, ptr inttoptr (i64 mul (i64 ptrtoint (ptr @g to i64), i64 2) to ptr), i64 20)
+;
+ ret ptr getelementptr([16 x i16], ptr inttoptr (i64 mul (i64 ptrtoint ([16 x i16]* @g to i64), i64 2) to ptr), i64 0, i64 10)
+}