Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -8444,9 +8444,14 @@ ``ptrval`` to type ``pty2``. It can be a *no-op cast* or a complex value modification, depending on the target and the address space pair. Pointer conversions within the same address space must be -performed with the ``bitcast`` instruction. Note that if the address space -conversion is legal then both result and operand refer to the same memory -location. +performed with the ``bitcast`` instruction. Note that if the address +space conversion is legal then both result and operand refer to the +same memory location. The pointer conversion cannot be an arbitrarily +complex value modification. A defined pointer computation casted in +one address space and then indexed should give the same result as an +equivalent indexing calculation in the original address space and then +casted. It must be possible to return the original pointer value if +casted back to the original address space. Example: """""""" Index: include/llvm/Analysis/PtrUseVisitor.h =================================================================== --- include/llvm/Analysis/PtrUseVisitor.h +++ include/llvm/Analysis/PtrUseVisitor.h @@ -242,6 +242,10 @@ enqueueUsers(BC); } + void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) { + enqueueUsers(ASC); + } + void visitPtrToIntInst(PtrToIntInst &I) { PI.setEscaped(&I); } Index: lib/Transforms/Scalar/SROA.cpp =================================================================== --- lib/Transforms/Scalar/SROA.cpp +++ lib/Transforms/Scalar/SROA.cpp @@ -670,6 +670,13 @@ return Base::visitBitCastInst(BC); } + void visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) { + if (ASC.use_empty()) + return markAsDead(ASC); + + return Base::visitAddrSpaceCastInst(ASC); + } + void visitGetElementPtrInst(GetElementPtrInst &GEPI) { if (GEPI.use_empty()) return markAsDead(GEPI); @@ -907,7 +914,7 @@ if (!GEP->hasAllZeroIndices()) return GEP; } else if (!isa(I) && !isa(I) && - !isa(I)) { + !isa(I) && !isa(I)) { return I; } @@ -1546,7 +1553,8 @@ } // Peel off a layer of the pointer and update the offset appropriately. - if (Operator::getOpcode(Ptr) == Instruction::BitCast) { + unsigned Opc = Operator::getOpcode(Ptr); + if (Opc == Instruction::BitCast || Opc == Instruction::AddrSpaceCast) { Ptr = cast(Ptr)->getOperand(0); } else if (GlobalAlias *GA = dyn_cast(Ptr)) { if (GA->isInterposable()) @@ -1575,8 +1583,10 @@ Ptr = OffsetPtr; // On the off chance we were targeting i8*, guard the bitcast here. - if (Ptr->getType() != PointerTy) - Ptr = IRB.CreateBitCast(Ptr, PointerTy, NamePrefix + "sroa_cast"); + if (Ptr->getType() != PointerTy) { + Ptr = IRB.CreatePointerBitCastOrAddrSpaceCast(Ptr, PointerTy, + NamePrefix + "sroa_cast"); + } return Ptr; } @@ -3159,6 +3169,11 @@ return false; } + bool visitAddrSpaceCastInst(AddrSpaceCastInst &ASC) { + enqueueUsers(ASC); + return false; + } + bool visitGetElementPtrInst(GetElementPtrInst &GEPI) { enqueueUsers(GEPI); return false; Index: test/Transforms/SROA/basictest.ll =================================================================== --- test/Transforms/SROA/basictest.ll +++ test/Transforms/SROA/basictest.ll @@ -65,6 +65,22 @@ ret i64 %Z } +define i64 @test2_addrspacecast(i64 %X) { +; CHECK-LABEL: @test2_addrspacecast( +; CHECK-NOT: alloca +; CHECK: ret i64 %X + +entry: + %A = alloca [8 x i8] + %B = addrspacecast [8 x i8]* %A to i64 addrspace(1)* + store i64 %X, i64 addrspace(1)* %B + br label %L2 + +L2: + %Z = load i64, i64 addrspace(1)* %B + ret i64 %Z +} + define void @test3(i8* %dst, i8* %src) { ; CHECK-LABEL: @test3( @@ -825,6 +841,27 @@ ret i32 undef } +declare void @llvm.memcpy.p0i8.p1i8.i32(i8* nocapture, i8 addrspace(1)* nocapture, i32, i32, i1) nounwind + +define i32 @test19_addrspacecast(%opaque* %x) { +; This input will cause us to try to compute a natural GEP when rewriting +; pointers in such a way that we try to GEP through the opaque type. Previously, +; a check for an unsized type was missing and this crashed. Ensure it behaves +; reasonably now. +; CHECK-LABEL: @test19_addrspacecast( +; CHECK-NOT: alloca +; CHECK: ret i32 undef + +entry: + %a = alloca { i64, i8* } + %cast1 = addrspacecast %opaque* %x to i8 addrspace(1)* + %cast2 = bitcast { i64, i8* }* %a to i8* + call void @llvm.memcpy.p0i8.p1i8.i32(i8* %cast2, i8 addrspace(1)* %cast1, i32 16, i32 1, i1 false) + %gep = getelementptr inbounds { i64, i8* }, { i64, i8* }* %a, i32 0, i32 0 + %val = load i64, i64* %gep + ret i32 undef +} + define i32 @test20() { ; Ensure we can track negative offsets (before the beginning of the alloca) and ; negative relative offsets from offsets starting past the end of the alloca.