diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp --- a/llvm/lib/Transforms/Scalar/SROA.cpp +++ b/llvm/lib/Transforms/Scalar/SROA.cpp @@ -1703,8 +1703,15 @@ NewTy = NewTy->getScalarType(); if (NewTy->isPointerTy() || OldTy->isPointerTy()) { if (NewTy->isPointerTy() && OldTy->isPointerTy()) { - return cast(NewTy)->getPointerAddressSpace() == - cast(OldTy)->getPointerAddressSpace(); + unsigned OldAS = OldTy->getPointerAddressSpace(); + unsigned NewAS = NewTy->getPointerAddressSpace(); + // Convert pointers if they are pointers from the same address space or + // different integral (not non-integral) address spaces with the same + // pointer size. + return OldAS == NewAS || + (!DL.isNonIntegralAddressSpace(OldAS) && + !DL.isNonIntegralAddressSpace(NewAS) && + DL.getPointerSize(OldAS) == DL.getPointerSize(NewAS)); } // We can convert integers to integral pointers, but not to non-integral @@ -1772,6 +1779,22 @@ return IRB.CreatePtrToInt(V, NewTy); } + if (OldTy->isPtrOrPtrVectorTy() && NewTy->isPtrOrPtrVectorTy()) { + unsigned OldAS = OldTy->getPointerAddressSpace(); + unsigned NewAS = NewTy->getPointerAddressSpace(); + // To convert pointers with different address spaces (they are already + // checked convertible, i.e. they have the same pointer size), so far we + // cannot use `bitcast` (which has restrict on the same address space) or + // `addrspacecast` (which is not always no-op casting). Instead, use a pair + // of no-op `ptrtoint`/`inttoptr` casts through an integer with the same bit + // size. + if (OldAS != NewAS) { + assert(DL.getPointerSize(OldAS) == DL.getPointerSize(NewAS)); + return IRB.CreateIntToPtr(IRB.CreatePtrToInt(V, DL.getIntPtrType(OldTy)), + NewTy); + } + } + return IRB.CreateBitCast(V, NewTy); } diff --git a/llvm/test/Transforms/SROA/address-spaces.ll b/llvm/test/Transforms/SROA/address-spaces.ll --- a/llvm/test/Transforms/SROA/address-spaces.ll +++ b/llvm/test/Transforms/SROA/address-spaces.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -sroa -S | FileCheck %s -target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" +target datalayout = "e-p:64:64:64-p1:16:16:16-p3:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64" declare void @llvm.memcpy.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i1) declare void @llvm.memcpy.p1i8.p0i8.i32(i8 addrspace(1)* nocapture, i8* nocapture readonly, i32, i1) @@ -71,7 +71,8 @@ @g = common global i32 0, align 4 @l = common addrspace(3) global i32 0, align 4 -; Make sure an illegal bitcast isn't introduced +; If pointers from different address spaces have different sizes, make sure an +; illegal bitcast isn't introduced define void @pr27557() { ; CHECK-LABEL: @pr27557( ; CHECK: %[[CAST:.*]] = bitcast i32** {{.*}} to i32 addrspace(3)** @@ -84,6 +85,21 @@ ret void } +@l2 = common addrspace(2) global i32 0, align 4 + +; If pointers from different address spaces have the same size, that pointer +; should be promoted through the pair of `ptrtoint`/`inttoptr`. +define i32* @pr27557.alt() { +; CHECK-LABEL: @pr27557.alt( +; CHECK: ret i32* inttoptr (i64 ptrtoint (i32 addrspace(2)* @l2 to i64) to i32*) + %1 = alloca %union.anon, align 8 + %2 = bitcast %union.anon* %1 to i32 addrspace(2)** + store i32 addrspace(2)* @l2, i32 addrspace(2)** %2, align 8 + %3 = bitcast %union.anon* %1 to i32** + %4 = load i32*, i32** %3, align 8 + ret i32* %4 +} + ; Make sure pre-splitting doesn't try to introduce an illegal bitcast define float @presplit(i64 addrspace(1)* %p) { entry: diff --git a/llvm/test/Transforms/SROA/alloca-address-space.ll b/llvm/test/Transforms/SROA/alloca-address-space.ll --- a/llvm/test/Transforms/SROA/alloca-address-space.ll +++ b/llvm/test/Transforms/SROA/alloca-address-space.ll @@ -1,5 +1,5 @@ ; RUN: opt < %s -sroa -S | FileCheck %s -target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64-A2" +target datalayout = "e-p:64:64:64-p1:16:16:16-p2:32:32-p3:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64-A2" declare void @llvm.memcpy.p2i8.p2i8.i32(i8 addrspace(2)* nocapture, i8 addrspace(2)* nocapture readonly, i32, i1) declare void @llvm.memcpy.p1i8.p2i8.i32(i8 addrspace(1)* nocapture, i8 addrspace(2)* nocapture readonly, i32, i1) @@ -70,7 +70,8 @@ @g = common global i32 0, align 4 @l = common addrspace(3) global i32 0, align 4 -; Make sure an illegal bitcast isn't introduced +; If pointers from different address spaces have different sizes, make sure an +; illegal bitcast isn't introduced ; CHECK-LABEL: @pr27557( ; CHECK: %[[CAST:.*]] = bitcast i32* addrspace(2)* {{.*}} to i32 addrspace(3)* addrspace(2)* ; CHECK: store i32 addrspace(3)* @l, i32 addrspace(3)* addrspace(2)* %[[CAST]] @@ -83,6 +84,21 @@ ret void } +@l4 = common addrspace(4) global i32 0, align 4 + +; If pointers from different address spaces have the same size, that pointer +; should be promoted through the pair of `ptrtoint`/`inttoptr`. +define i32* @pr27557.alt() { +; CHECK-LABEL: @pr27557.alt( +; CHECK: ret i32* inttoptr (i64 ptrtoint (i32 addrspace(4)* @l4 to i64) to i32*) + %1 = alloca %union.anon, align 8, addrspace(2) + %2 = bitcast %union.anon addrspace(2)* %1 to i32 addrspace(4)* addrspace(2)* + store i32 addrspace(4)* @l4, i32 addrspace(4)* addrspace(2)* %2, align 8 + %3 = bitcast %union.anon addrspace(2)* %1 to i32* addrspace(2)* + %4 = load i32*, i32* addrspace(2)* %3, align 8 + ret i32* %4 +} + ; Test load from and store to non-zero address space. define void @test_load_store_diff_addr_space([2 x float] addrspace(1)* %complex1, [2 x float] addrspace(1)* %complex2) { ; CHECK-LABEL: @test_load_store_diff_addr_space diff --git a/llvm/test/Transforms/SROA/non-integral-pointers.ll b/llvm/test/Transforms/SROA/non-integral-pointers.ll --- a/llvm/test/Transforms/SROA/non-integral-pointers.ll +++ b/llvm/test/Transforms/SROA/non-integral-pointers.ll @@ -85,4 +85,18 @@ ret i64 addrspace(4)* null } +%union.anon = type { i32* } + +; CHECK-LABEL: @f2( +; CHECK-NOT: ptr2int +; CHECK-NOT: int2ptr +define i8 *@f2(i8 addrspace(4)* %p) { + %1 = alloca %union.anon, align 8 + %2 = bitcast %union.anon* %1 to i8 addrspace(4)** + store i8 addrspace(4)* %p, i8 addrspace(4)** %2, align 8 + %3 = bitcast %union.anon* %1 to i8** + %4 = load i8*, i8** %3, align 8 + ret i8* %4 +} + declare void @llvm.memset.p0i8.i64(i8*, i8, i64, i1)