Index: include/llvm/IR/Value.h =================================================================== --- include/llvm/IR/Value.h +++ include/llvm/IR/Value.h @@ -509,6 +509,17 @@ static_cast(this)->stripPointerCasts()); } + /// \brief Strip off pointer casts (except addrspacecast), all-zero GEPs, + /// and aliases. + /// + /// Returns the original uncasted value or addrspacecast (if present). + /// If this is called on a non-pointer value, it returns 'this'. + const Value *stripPointerCastsKeepAddrSpaceCast() const; + Value *stripPointerCastsKeepAddrSpaceCast() { + return const_cast( + static_cast(this)->stripPointerCastsKeepAddrSpaceCast()); + } + /// \brief Strip off pointer casts, all-zero GEPs, aliases and barriers. /// /// Returns the original uncasted value. If this is called on a non-pointer Index: lib/IR/Value.cpp =================================================================== --- lib/IR/Value.cpp +++ lib/IR/Value.cpp @@ -490,6 +490,7 @@ enum PointerStripKind { PSK_ZeroIndices, PSK_ZeroIndicesAndAliases, + PSK_ZeroIndicesAndAliasesKeepAddrSpaceCast, PSK_ZeroIndicesAndAliasesAndBarriers, PSK_InBoundsConstantIndices, PSK_InBounds @@ -509,6 +510,7 @@ if (auto *GEP = dyn_cast(V)) { switch (StripKind) { case PSK_ZeroIndicesAndAliases: + case PSK_ZeroIndicesAndAliasesKeepAddrSpaceCast: case PSK_ZeroIndicesAndAliasesAndBarriers: case PSK_ZeroIndices: if (!GEP->hasAllZeroIndices()) @@ -525,7 +527,8 @@ } V = GEP->getPointerOperand(); } else if (Operator::getOpcode(V) == Instruction::BitCast || - Operator::getOpcode(V) == Instruction::AddrSpaceCast) { + (StripKind != PSK_ZeroIndicesAndAliasesKeepAddrSpaceCast && + Operator::getOpcode(V) == Instruction::AddrSpaceCast)) { V = cast(V)->getOperand(0); } else if (auto *GA = dyn_cast(V)) { if (StripKind == PSK_ZeroIndices || GA->isInterposable()) @@ -559,6 +562,11 @@ return stripPointerCastsAndOffsets(this); } +const Value *Value::stripPointerCastsKeepAddrSpaceCast() const { + return stripPointerCastsAndOffsets< + PSK_ZeroIndicesAndAliasesKeepAddrSpaceCast>(this); +} + const Value *Value::stripPointerCastsNoFollowAliases() const { return stripPointerCastsAndOffsets(this); } Index: lib/Transforms/InstCombine/InstructionCombining.cpp =================================================================== --- lib/Transforms/InstCombine/InstructionCombining.cpp +++ lib/Transforms/InstCombine/InstructionCombining.cpp @@ -135,6 +135,10 @@ static cl::opt ShouldLowerDbgDeclare("instcombine-lower-dbg-declare", cl::Hidden, cl::init(true)); +static cl::opt +NoAddrSpaceCastFolding("instcombine-no-addrspacecast-folding", + cl::desc("Do not fold addrspacecast into GEP.")); + Value *InstCombiner::EmitGEPOffset(User *GEP) { return llvm::EmitGEPOffset(&Builder, DL, GEP); } @@ -1771,7 +1775,11 @@ return nullptr; // Handle gep(bitcast x) and gep(gep x, 0, 0, 0). - Value *StrippedPtr = PtrOp->stripPointerCasts(); + Value *StrippedPtr; + if (NoAddrSpaceCastFolding) + StrippedPtr = PtrOp->stripPointerCastsKeepAddrSpaceCast(); + else + StrippedPtr = PtrOp->stripPointerCasts(); PointerType *StrippedPtrTy = cast(StrippedPtr->getType()); if (StrippedPtr != PtrOp) { Index: test/Transforms/InstCombine/cast-no-addrspacecast-folding.ll =================================================================== --- /dev/null +++ test/Transforms/InstCombine/cast-no-addrspacecast-folding.ll @@ -0,0 +1,16 @@ +; RUN: opt < %s -instcombine -instcombine-no-addrspacecast-folding=true -S | FileCheck %s +target datalayout = "E-p:64:64:64-p1:32:32:32-p2:64:64:64-p3:64:64:64-a0:0:8-f32:32:32-f64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-v64:64:64-v128:128:128-n8:16:32:64" + +define double @test80_addrspacecast(double addrspace(1)* %p, i32 %i) { +; CHECK-LABEL: @test80_addrspacecast( +; CHECK-NEXT: [[Q:%.*]] = addrspacecast double addrspace(1)* %p to double addrspace(2)* +; CHECK-NEXT: [[S:%.*]] = sext i32 %i to i64 +; CHECK-NEXT: [[PP:%.*]] = getelementptr double, double addrspace(2)* [[Q]], i64 [[S]] +; CHECK-NEXT: [[L:%.*]] = load double, double addrspace(2)* [[PP]], align 8 +; CHECK-NEXT: ret double [[L]] +; + %q = addrspacecast double addrspace(1)* %p to double addrspace(2)* + %pp = getelementptr double, double addrspace(2)* %q, i32 %i + %l = load double, double addrspace(2)* %pp + ret double %l +}