diff --git a/llvm/include/llvm/IR/Value.h b/llvm/include/llvm/IR/Value.h --- a/llvm/include/llvm/IR/Value.h +++ b/llvm/include/llvm/IR/Value.h @@ -643,6 +643,17 @@ static_cast(this)->stripPointerCastsAndAliases()); } + /// Strip off pointer casts, all-zero GEPs, address space casts, and local + /// aliases to local aliasees. + /// + /// Returns the original uncasted value. If this is called on a non-pointer + /// value, it returns 'this'. + const Value *stripPointerCastsAndLocalAliases() const; + Value *stripPointerCastsAndLocalAliases() { + return const_cast( + static_cast(this)->stripPointerCastsAndLocalAliases()); + } + /// Strip off pointer casts, all-zero GEPs and address space casts /// but ensures the representation of the result stays the same. /// diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -848,11 +848,13 @@ return ConstantFoldConstant(C, DL, TLI); } -/// Strip the pointer casts, but preserve the address space information. +/// Strip the pointer casts and local aliases, but preserve the address space +/// information. Constant *StripPtrCastKeepAS(Constant *Ptr, Type *&ElemTy) { assert(Ptr->getType()->isPointerTy() && "Not a pointer type"); auto *OldPtrTy = cast(Ptr->getType()); - Ptr = cast(Ptr->stripPointerCasts()); + Ptr = cast(Ptr->stripPointerCastsAndLocalAliases()); + auto *NewPtrTy = cast(Ptr->getType()); ElemTy = NewPtrTy->getPointerElementType(); diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp --- a/llvm/lib/IR/Value.cpp +++ b/llvm/lib/IR/Value.cpp @@ -553,6 +553,7 @@ enum PointerStripKind { PSK_ZeroIndices, PSK_ZeroIndicesAndAliases, + PSK_ZeroIndicesAndLocalAliases, PSK_ZeroIndicesSameRepresentation, PSK_ForAliasAnalysis, PSK_InBoundsConstantIndices, @@ -579,6 +580,7 @@ switch (StripKind) { case PSK_ZeroIndices: case PSK_ZeroIndicesAndAliases: + case PSK_ZeroIndicesAndLocalAliases: case PSK_ZeroIndicesSameRepresentation: case PSK_ForAliasAnalysis: if (!GEP->hasAllZeroIndices()) @@ -605,6 +607,10 @@ V = cast(V)->getOperand(0); } else if (StripKind == PSK_ZeroIndicesAndAliases && isa(V)) { V = cast(V)->getAliasee(); + } else if (StripKind == PSK_ZeroIndicesAndLocalAliases && + isa(V) && cast(V)->hasLocalLinkage() && + cast(V)->getBaseObject()->hasLocalLinkage()) { + V = cast(V)->getAliasee(); } else if (StripKind == PSK_ForAliasAnalysis && isa(V) && cast(V)->getNumIncomingValues() == 1) { V = cast(V)->getIncomingValue(0); @@ -641,6 +647,10 @@ return stripPointerCastsAndOffsets(this); } +const Value *Value::stripPointerCastsAndLocalAliases() const { + return stripPointerCastsAndOffsets(this); +} + const Value *Value::stripPointerCastsSameRepresentation() const { return stripPointerCastsAndOffsets(this); } diff --git a/llvm/test/Transforms/InstSimplify/ConstProp/gep-alias.ll b/llvm/test/Transforms/InstSimplify/ConstProp/gep-alias.ll --- a/llvm/test/Transforms/InstSimplify/ConstProp/gep-alias.ll +++ b/llvm/test/Transforms/InstSimplify/ConstProp/gep-alias.ll @@ -1,17 +1,38 @@ -; RUN: opt -instcombine -S -o - %s | FileCheck %s -; Test that we don't replace an alias with its aliasee when simplifying GEPs. -; In this test case the transformation is invalid because it replaces the -; reference to the symbol "b" (which refers to whichever instance of "b" -; was chosen by the linker) with a reference to "a" (which refers to the -; specific instance of "b" in this module). - -target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" -target triple = "x86_64-unknown-linux-gnu" - -@a = internal global [3 x i8*] zeroinitializer -@b = linkonce_odr alias [3 x i8*], [3 x i8*]* @a - -define i8** @f() { - ; CHECK: ret i8** getelementptr ([3 x i8*], [3 x i8*]* @b, i64 0, i64 1) - ret i8** getelementptr ([3 x i8*], [3 x i8*]* @b, i64 0, i64 1) -} +; RUN: opt -instcombine -S -o - %s | FileCheck %s +; Test that we don't replace an alias with its aliasee if the alias or aliasee +; is non-local when simplifying GEPs. + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@gi = internal global [3 x i8*] zeroinitializer +@gl = linkonce_odr global [3 x i8*] zeroinitializer + +@all = linkonce_odr alias [3 x i8*], [3 x i8*]* @gl +@ali = linkonce_odr alias [3 x i8*], [3 x i8*]* @gi +@ail = internal alias [3 x i8*], [3 x i8*]* @gl +@aii = internal alias [3 x i8*], [3 x i8*]* @gi + +define i8** @f1() { +; CHECK-LABEL: @f1 +; CHECK: ret i8** getelementptr {{.*}}([3 x i8*], [3 x i8*]* @all, i64 0, i64 1) + ret i8** getelementptr ([3 x i8*], [3 x i8*]* @all, i64 0, i64 1) +} + +define i8** @f2() { +; CHECK-LABEL: @f2 +; CHECK: ret i8** getelementptr {{.*}}([3 x i8*], [3 x i8*]* @ali, i64 0, i64 1) + ret i8** getelementptr ([3 x i8*], [3 x i8*]* @ali, i64 0, i64 1) +} + +define i8** @f3() { +; CHECK-LABEL: @f3 +; CHECK: ret i8** getelementptr {{.*}}([3 x i8*], [3 x i8*]* @ail, i64 0, i64 1) + ret i8** getelementptr ([3 x i8*], [3 x i8*]* @ail, i64 0, i64 1) +} + +define i8** @f4() { +; CHECK-LABEL: @f4 +; CHECK: ret i8** getelementptr {{.*}}([3 x i8*], [3 x i8*]* @gi, i64 0, i64 1) + ret i8** getelementptr ([3 x i8*], [3 x i8*]* @aii, i64 0, i64 1) +}