Index: include/llvm/Analysis/PtrUseVisitor.h =================================================================== --- include/llvm/Analysis/PtrUseVisitor.h +++ include/llvm/Analysis/PtrUseVisitor.h @@ -239,6 +239,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 @@ -394,6 +394,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); @@ -634,7 +641,7 @@ if (!GEP->hasAllZeroIndices()) return GEP; } else if (!isa(I) && !isa(I) && - !isa(I)) { + !isa(I) && !isa(I)) { return I; } @@ -854,6 +861,8 @@ Ptr = BCI->getOperand(0); else if (GetElementPtrInst *GEPI = dyn_cast(Ptr)) Ptr = GEPI->getPointerOperand(); + else if (AddrSpaceCastInst *ASC = dyn_cast(Ptr)) + Ptr = ASC->getOperand(0); else return false; @@ -1495,7 +1504,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->mayBeOverridden()) @@ -1522,8 +1532,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; } @@ -2932,6 +2944,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 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* }* %a, i32 0, i32 0 + %val = load 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.