Skip to content

Commit 8086f9d

Browse files
committed
[ConstFold] Simplify a load's GEP operand through local aliases
MSVC-style RTTI produces loads through a GEP of a local alias which itself is a GEP. Currently we aren't able to devirtualize any virtual calls when MSVC RTTI is enabled. This patch attempts to simplify a load's GEP operand by calling SymbolicallyEvaluateGEP() with an option to look through local aliases. Differential Revision: https://reviews.llvm.org/D101100
1 parent 0fa5aac commit 8086f9d

File tree

2 files changed

+82
-5
lines changed

2 files changed

+82
-5
lines changed

llvm/lib/Analysis/ConstantFolding.cpp

Lines changed: 47 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@
6363
using namespace llvm;
6464

6565
namespace {
66+
Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
67+
ArrayRef<Constant *> Ops,
68+
const DataLayout &DL,
69+
const TargetLibraryInfo *TLI,
70+
bool ForLoadOperand);
6671

6772
//===----------------------------------------------------------------------===//
6873
// Constant Folding internal helper functions
@@ -690,6 +695,33 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
690695
GV->getInitializer(), CE, Ty, DL))
691696
return V;
692697
}
698+
} else {
699+
// Try to simplify GEP if the pointer operand wasn't a GlobalVariable.
700+
// SymbolicallyEvaluateGEP() with `ForLoadOperand = true` can potentially
701+
// simplify the GEP more than it normally would have been, but should only
702+
// be used for const folding loads.
703+
SmallVector<Constant *> Ops;
704+
for (unsigned I = 0, E = CE->getNumOperands(); I != E; ++I)
705+
Ops.push_back(cast<Constant>(CE->getOperand(I)));
706+
if (auto *Simplified = dyn_cast_or_null<ConstantExpr>(
707+
SymbolicallyEvaluateGEP(cast<GEPOperator>(CE), Ops, DL, nullptr,
708+
/*ForLoadOperand*/ true))) {
709+
// If the symbolically evaluated GEP is another GEP, we can only const
710+
// fold it if the resulting pointer operand is a GlobalValue. Otherwise
711+
// there is nothing else to simplify since the GEP is already in the
712+
// most simplified form.
713+
if (auto *SimplifiedGEP = dyn_cast<GEPOperator>(Simplified)) {
714+
if (auto *GV = dyn_cast<GlobalVariable>(Simplified->getOperand(0))) {
715+
if (GV->isConstant() && GV->hasDefinitiveInitializer()) {
716+
if (Constant *V = ConstantFoldLoadThroughGEPConstantExpr(
717+
GV->getInitializer(), Simplified, Ty, DL))
718+
return V;
719+
}
720+
}
721+
} else {
722+
return ConstantFoldLoadFromConstPtr(Simplified, Ty, DL);
723+
}
724+
}
693725
}
694726
}
695727

@@ -835,10 +867,18 @@ Constant *CastGEPIndices(Type *SrcElemTy, ArrayRef<Constant *> Ops,
835867
}
836868

837869
/// Strip the pointer casts, but preserve the address space information.
838-
Constant *StripPtrCastKeepAS(Constant *Ptr, Type *&ElemTy) {
870+
Constant *StripPtrCastKeepAS(Constant *Ptr, Type *&ElemTy,
871+
bool ForLoadOperand) {
839872
assert(Ptr->getType()->isPointerTy() && "Not a pointer type");
840873
auto *OldPtrTy = cast<PointerType>(Ptr->getType());
841874
Ptr = cast<Constant>(Ptr->stripPointerCasts());
875+
if (ForLoadOperand) {
876+
while (isa<GlobalAlias>(Ptr) && !cast<GlobalAlias>(Ptr)->isInterposable() &&
877+
!cast<GlobalAlias>(Ptr)->getBaseObject()->isInterposable()) {
878+
Ptr = cast<GlobalAlias>(Ptr)->getAliasee();
879+
}
880+
}
881+
842882
auto *NewPtrTy = cast<PointerType>(Ptr->getType());
843883

844884
ElemTy = NewPtrTy->getPointerElementType();
@@ -855,7 +895,8 @@ Constant *StripPtrCastKeepAS(Constant *Ptr, Type *&ElemTy) {
855895
Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
856896
ArrayRef<Constant *> Ops,
857897
const DataLayout &DL,
858-
const TargetLibraryInfo *TLI) {
898+
const TargetLibraryInfo *TLI,
899+
bool ForLoadOperand) {
859900
const GEPOperator *InnermostGEP = GEP;
860901
bool InBounds = GEP->isInBounds();
861902

@@ -903,7 +944,7 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
903944
DL.getIndexedOffsetInType(
904945
SrcElemTy,
905946
makeArrayRef((Value * const *)Ops.data() + 1, Ops.size() - 1)));
906-
Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy);
947+
Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy, ForLoadOperand);
907948

908949
// If this is a GEP of a GEP, fold it all into a single GEP.
909950
while (auto *GEP = dyn_cast<GEPOperator>(Ptr)) {
@@ -925,7 +966,7 @@ Constant *SymbolicallyEvaluateGEP(const GEPOperator *GEP,
925966
Ptr = cast<Constant>(GEP->getOperand(0));
926967
SrcElemTy = GEP->getSourceElementType();
927968
Offset += APInt(BitWidth, DL.getIndexedOffsetInType(SrcElemTy, NestedOps));
928-
Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy);
969+
Ptr = StripPtrCastKeepAS(Ptr, SrcElemTy, ForLoadOperand);
929970
}
930971

931972
// If the base value for this address is a literal integer value, fold the
@@ -1062,7 +1103,8 @@ Constant *ConstantFoldInstOperandsImpl(const Value *InstOrCE, unsigned Opcode,
10621103
return ConstantFoldCastOperand(Opcode, Ops[0], DestTy, DL);
10631104

10641105
if (auto *GEP = dyn_cast<GEPOperator>(InstOrCE)) {
1065-
if (Constant *C = SymbolicallyEvaluateGEP(GEP, Ops, DL, TLI))
1106+
if (Constant *C = SymbolicallyEvaluateGEP(GEP, Ops, DL, TLI,
1107+
/*ForLoadOperand*/ false))
10661108
return C;
10671109

10681110
return ConstantExpr::getGetElementPtr(GEP->getSourceElementType(), Ops[0],
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2+
; RUN: opt -passes=instsimplify -S < %s | FileCheck %s
3+
4+
@a1 = internal alias i32, getelementptr ({[3 x i32]}, {[3 x i32]}* @b, i32 0, i32 0, i32 1)
5+
@a2 = weak alias i32, getelementptr ({[3 x i32]}, {[3 x i32]}* @b, i32 0, i32 0, i32 1)
6+
@b = internal constant {[3 x i32]} {[3 x i32] [i32 2, i32 3, i32 4]}
7+
8+
@c = internal alias i32, getelementptr ({[3 x i32]}, {[3 x i32]}* @d, i32 0, i32 0, i32 1)
9+
@d = weak constant {[3 x i32]} {[3 x i32] [i32 2, i32 3, i32 4]}
10+
11+
define i32 @f() {
12+
; CHECK-LABEL: @f(
13+
; CHECK-NEXT: ret i32 4
14+
;
15+
%a = load i32, i32* getelementptr (i32, i32* @a1, i64 1)
16+
ret i32 %a
17+
}
18+
19+
define i32 @g() {
20+
; CHECK-LABEL: @g(
21+
; CHECK-NEXT: [[A:%.*]] = load i32, i32* getelementptr (i32, i32* @a2, i64 1), align 4
22+
; CHECK-NEXT: ret i32 [[A]]
23+
;
24+
%a = load i32, i32* getelementptr (i32, i32* @a2, i64 1)
25+
ret i32 %a
26+
}
27+
28+
define i32 @h() {
29+
; CHECK-LABEL: @h(
30+
; CHECK-NEXT: [[A:%.*]] = load i32, i32* getelementptr (i32, i32* @c, i64 1), align 4
31+
; CHECK-NEXT: ret i32 [[A]]
32+
;
33+
%a = load i32, i32* getelementptr (i32, i32* @c, i64 1)
34+
ret i32 %a
35+
}

0 commit comments

Comments
 (0)