[ConstFold] Support opaque pointers in constexpr GEPs
authorNikita Popov <nikita.ppv@gmail.com>
Tue, 20 Jul 2021 15:19:52 +0000 (17:19 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Tue, 7 Sep 2021 18:50:29 +0000 (20:50 +0200)
Support opaque pointers in SymbolicallyEvaluateGEP() by using the
value type of a GlobalValue base or falling back to i8 if there
isn't one. We don't unconditionally generate i8 GEPs here because
that would lose inrange attribues, and because some optimizations
on globals currently rely on GEP types (e.g. the globals SROA
mentioned in the comment).

Differential Revision: https://reviews.llvm.org/D109297

llvm/lib/Analysis/ConstantFolding.cpp
llvm/test/Transforms/InstCombine/force-opaque-ptr.ll [new file with mode: 0644]

index 2c2e6c3..6ea7dcf 100644 (file)
@@ -987,7 +987,15 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
   // 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()) {
@@ -1067,7 +1075,7 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
   // 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
diff --git a/llvm/test/Transforms/InstCombine/force-opaque-ptr.ll b/llvm/test/Transforms/InstCombine/force-opaque-ptr.ll
new file mode 100644 (file)
index 0000000..d239ec7
--- /dev/null
@@ -0,0 +1,26 @@
+; 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)
+}