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. + /// + /// 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,12 @@ 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 @@ -555,6 +555,7 @@ enum PointerStripKind { PSK_ZeroIndices, PSK_ZeroIndicesAndAliases, + PSK_ZeroIndicesAndLocalAliases, PSK_ZeroIndicesSameRepresentation, PSK_ForAliasAnalysis, PSK_InBoundsConstantIndices, @@ -581,6 +582,7 @@ switch (StripKind) { case PSK_ZeroIndices: case PSK_ZeroIndicesAndAliases: + case PSK_ZeroIndicesAndLocalAliases: case PSK_ZeroIndicesSameRepresentation: case PSK_ForAliasAnalysis: if (!GEP->hasAllZeroIndices()) @@ -607,6 +609,9 @@ 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()) { + V = cast(V)->getAliasee(); } else if (StripKind == PSK_ForAliasAnalysis && isa(V) && cast(V)->getNumIncomingValues() == 1) { V = cast(V)->getIncomingValue(0); @@ -643,6 +648,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,30 @@ -; 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 is non-local when simplifying GEPs. +; The transformation is invalid for @f() 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). +; It's fine to look through local aliases though. + +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 +@c = internal alias [3 x i8*], [3 x i8*]* @a +@d = private 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) +} + +define i8** @g() { +; CHECK: ret i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @a, i64 0, i64 1) + ret i8** getelementptr ([3 x i8*], [3 x i8*]* @c, i64 0, i64 1) +} + +define i8** @h() { +; CHECK: ret i8** getelementptr inbounds ([3 x i8*], [3 x i8*]* @a, i64 0, i64 1) + ret i8** getelementptr ([3 x i8*], [3 x i8*]* @d, i64 0, i64 1) +}