diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp --- a/llvm/lib/Target/X86/X86ISelLowering.cpp +++ b/llvm/lib/Target/X86/X86ISelLowering.cpp @@ -43169,6 +43169,20 @@ } } + // Cast ptr32 and ptr64 pointers to the default address space before a load. + unsigned AddrSpace = Ld->getAddressSpace(); + if (AddrSpace == X86AS::PTR64 || AddrSpace == X86AS::PTR32_SPTR || + AddrSpace == X86AS::PTR32_UPTR) { + MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); + if (PtrVT != Ld->getBasePtr().getSimpleValueType()) { + SDValue Cast = + DAG.getAddrSpaceCast(dl, PtrVT, Ld->getBasePtr(), AddrSpace, 0); + return DAG.getLoad(RegVT, dl, Ld->getChain(), Cast, Ld->getPointerInfo(), + Ld->getOriginalAlign(), + Ld->getMemOperand()->getFlags()); + } + } + return SDValue(); } @@ -43596,6 +43610,20 @@ return SDValue(); } + // Cast ptr32 and ptr64 pointers to the default address space before a store. + unsigned AddrSpace = St->getAddressSpace(); + if (AddrSpace == X86AS::PTR64 || AddrSpace == X86AS::PTR32_SPTR || + AddrSpace == X86AS::PTR32_UPTR) { + MVT PtrVT = TLI.getPointerTy(DAG.getDataLayout()); + if (PtrVT != St->getBasePtr().getSimpleValueType()) { + SDValue Cast = + DAG.getAddrSpaceCast(dl, PtrVT, St->getBasePtr(), AddrSpace, 0); + return DAG.getStore(St->getChain(), dl, StoredVal, Cast, + St->getPointerInfo(), St->getOriginalAlign(), + St->getMemOperand()->getFlags(), St->getAAInfo()); + } + } + // Turn load->store of MMX types into GPR load/stores. This avoids clobbering // the FP state in cases where an emms may be missing. // A preferable solution to the general problem is to figure out the right diff --git a/llvm/test/CodeGen/X86/mixed-ptr-sizes-i686.ll b/llvm/test/CodeGen/X86/mixed-ptr-sizes-i686.ll --- a/llvm/test/CodeGen/X86/mixed-ptr-sizes-i686.ll +++ b/llvm/test/CodeGen/X86/mixed-ptr-sizes-i686.ll @@ -251,3 +251,111 @@ tail call void @use_foo(%struct.Foo* %f) ret void } + +define i32 @test_load_sptr32(i32 addrspace(270)* %i) { +; CHECK-LABEL: test_load_sptr32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl (%eax), %eax +; CHECK-NEXT: retl +; CHECK-O0-LABEL: test_load_sptr32: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-O0-NEXT: movl (%eax), %eax +; CHECK-O0-NEXT: retl +entry: + %0 = load i32, i32 addrspace(270)* %i, align 4 + ret i32 %0 +} + +define i32 @test_load_uptr32(i32 addrspace(271)* %i) { +; CHECK-LABEL: test_load_uptr32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl (%eax), %eax +; CHECK-NEXT: retl +; CHECK-O0-LABEL: test_load_uptr32: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-O0-NEXT: movl (%eax), %eax +; CHECK-O0-NEXT: retl +entry: + %0 = load i32, i32 addrspace(271)* %i, align 4 + ret i32 %0 +} + +define i32 @test_load_ptr64(i32 addrspace(272)* %i) { +; CHECK-LABEL: test_load_ptr64: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl (%eax), %eax +; CHECK-NEXT: retl +; CHECK-O0-LABEL: test_load_ptr64: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: pushl %eax +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %ecx +; CHECK-O0-NEXT: movl (%ecx), %ecx +; CHECK-O0-NEXT: movl %eax, (%esp) +; CHECK-O0-NEXT: movl %ecx, %eax +; CHECK-O0-NEXT: popl %ecx +; CHECK-O0-NEXT: retl +entry: + %0 = load i32, i32 addrspace(272)* %i, align 8 + ret i32 %0 +} + +define void @test_store_sptr32(i32 addrspace(270)* %s, i32 %i) { +; CHECK-LABEL: test_store_sptr32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %ecx +; CHECK-NEXT: movl %eax, (%ecx) +; CHECK-NEXT: retl +; CHECK-O0-LABEL: test_store_sptr32: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %ecx +; CHECK-O0-NEXT: movl %eax, (%ecx) +; CHECK-O0-NEXT: retl +entry: + store i32 %i, i32 addrspace(270)* %s, align 4 + ret void +} + +define void @test_store_uptr32(i32 addrspace(271)* %s, i32 %i) { +; CHECK-LABEL: test_store_uptr32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %ecx +; CHECK-NEXT: movl %eax, (%ecx) +; CHECK-NEXT: retl +; CHECK-O0-LABEL: test_store_uptr32: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %ecx +; CHECK-O0-NEXT: movl %eax, (%ecx) +; CHECK-O0-NEXT: retl +entry: + store i32 %i, i32 addrspace(271)* %s, align 4 + ret void +} + +define void @test_store_ptr64(i32 addrspace(272)* %s, i32 %i) { +; CHECK-LABEL: test_store_ptr64: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-NEXT: movl {{[0-9]+}}(%esp), %ecx +; CHECK-NEXT: movl %eax, (%ecx) +; CHECK-NEXT: retl +; CHECK-O0-LABEL: test_store_ptr64: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %eax +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %ecx +; CHECK-O0-NEXT: movl {{[0-9]+}}(%esp), %edx +; CHECK-O0-NEXT: movl %edx, (%ecx) +; CHECK-O0-NEXT: retl +entry: + store i32 %i, i32 addrspace(272)* %s, align 8 + ret void +} diff --git a/llvm/test/CodeGen/X86/mixed-ptr-sizes.ll b/llvm/test/CodeGen/X86/mixed-ptr-sizes.ll --- a/llvm/test/CodeGen/X86/mixed-ptr-sizes.ll +++ b/llvm/test/CodeGen/X86/mixed-ptr-sizes.ll @@ -1,5 +1,5 @@ ; RUN: llc < %s | FileCheck --check-prefixes=CHECK %s -; RUN: llc -O0 < %s | FileCheck --check-prefixes=CHECK %s +; RUN: llc -O0 < %s | FileCheck --check-prefixes=CHECK-O0 %s ; Source to regenerate: ; struct Foo { @@ -45,8 +45,17 @@ declare dso_local void @use_foo(%struct.Foo*) define dso_local void @test_sign_ext(%struct.Foo* %f, i32 addrspace(270)* %i) { -; CHECK-LABEL: test_sign_ext -; CHECK: movslq %edx, %rax +; CHECK-LABEL: test_sign_ext: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movslq %edx, %rax +; CHECK-NEXT: movq %rax, 8(%rcx) +; CHECK-NEXT: jmp use_foo # TAILCALL +; +; CHECK-O0-LABEL: test_sign_ext: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movslq %edx, %rax +; CHECK-O0-NEXT: movq %rax, 8(%rcx) +; CHECK-O0-NEXT: jmp use_foo # TAILCALL entry: %0 = addrspacecast i32 addrspace(270)* %i to i32* %p64 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 1 @@ -56,8 +65,18 @@ } define dso_local void @test_zero_ext(%struct.Foo* %f, i32 addrspace(271)* %i) { -; CHECK-LABEL: test_zero_ext -; CHECK: movl %edx, %eax +; CHECK-LABEL: test_zero_ext: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl %edx, %eax +; CHECK-NEXT: movq %rax, 8(%rcx) +; CHECK-NEXT: jmp use_foo # TAILCALL +; +; CHECK-O0-LABEL: test_zero_ext: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl %edx, %eax +; CHECK-O0-NEXT: # kill: def $rax killed $eax +; CHECK-O0-NEXT: movq %rax, 8(%rcx) +; CHECK-O0-NEXT: jmp use_foo # TAILCALL entry: %0 = addrspacecast i32 addrspace(271)* %i to i32* %p64 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 1 @@ -67,8 +86,16 @@ } define dso_local void @test_trunc(%struct.Foo* %f, i32* %i) { -; CHECK-LABEL: test_trunc -; CHECK: movl %edx, (%rcx) +; CHECK-LABEL: test_trunc: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl %edx, (%rcx) +; CHECK-NEXT: jmp use_foo # TAILCALL +; +; CHECK-O0-LABEL: test_trunc: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: # kill: def $edx killed $edx killed $rdx +; CHECK-O0-NEXT: movl %edx, (%rcx) +; CHECK-O0-NEXT: jmp use_foo # TAILCALL entry: %0 = addrspacecast i32* %i to i32 addrspace(270)* %p32 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 0 @@ -78,8 +105,14 @@ } define dso_local void @test_noop1(%struct.Foo* %f, i32 addrspace(270)* %i) { -; CHECK-LABEL: test_noop1 -; CHECK: movl %edx, (%rcx) +; CHECK-LABEL: test_noop1: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl %edx, (%rcx) +; CHECK-NEXT: jmp use_foo # TAILCALL +; CHECK-O0-LABEL: test_noop1: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl %edx, (%rcx) +; CHECK-O0-NEXT: jmp use_foo # TAILCALL entry: %p32 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 0 store i32 addrspace(270)* %i, i32 addrspace(270)** %p32, align 8 @@ -89,7 +122,13 @@ define dso_local void @test_noop2(%struct.Foo* %f, i32* %i) { ; CHECK-LABEL: test_noop2 -; CHECK: movq %rdx, 8(%rcx) +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movq %rdx, 8(%rcx) +; CHECK-NEXT: jmp use_foo # TAILCALL +; CHECK-O0-LABEL: test_noop2: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movq %rdx, 8(%rcx) +; CHECK-O0-NEXT: jmp use_foo # TAILCALL entry: %p64 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 1 store i32* %i, i32** %p64, align 8 @@ -99,6 +138,23 @@ ; Test that null can be passed as a 32-bit pointer. define dso_local void @test_null_arg(%struct.Foo* %f) { +; CHECK-LABEL: test_null_arg: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: subq $40, %rsp +; CHECK: xorl %edx, %edx +; CHECK-NEXT: callq test_noop1 +; CHECK-NEXT: nop +; CHECK-NEXT: addq $40, %rsp +; CHECK-NEXT: retq +; +; CHECK-O0-LABEL: test_null_arg: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: subq $40, %rsp +; CHECK-O0: xorl %edx, %edx +; CHECK-O0-NEXT: callq test_noop1 +; CHECK-O0-NEXT: nop +; CHECK-O0-NEXT: addq $40, %rsp +; CHECK-O0-NEXT: retq entry: call void @test_noop1(%struct.Foo* %f, i32 addrspace(270)* null) ret void @@ -106,8 +162,16 @@ ; Test casts between unrecognized address spaces. define void @test_unrecognized(%struct.Foo* %f, i32 addrspace(14)* %i) { -; CHECK-LABEL: test_unrecognized -; CHECK: movl %edx, (%rcx) +; CHECK-LABEL: test_unrecognized: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl %edx, (%rcx) +; CHECK-NEXT: jmp use_foo # TAILCALL +; +; CHECK-O0-LABEL: test_unrecognized: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: # kill: def $edx killed $edx killed $rdx +; CHECK-O0-NEXT: movl %edx, (%rcx) +; CHECK-O0-NEXT: jmp use_foo # TAILCALL entry: %0 = addrspacecast i32 addrspace(14)* %i to i32 addrspace(270)* %p32 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 0 @@ -117,8 +181,18 @@ } define void @test_unrecognized2(%struct.Foo* %f, i32 addrspace(271)* %i) { -; CHECK-LABEL: test_unrecognized2 -; CHECK: movl %edx, %eax +; CHECK-LABEL: test_unrecognized2: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl %edx, %eax +; CHECK-NEXT: movq %rax, 16(%rcx) +; CHECK-NEXT: jmp use_foo # TAILCALL +; +; CHECK-O0-LABEL: test_unrecognized2: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl %edx, %eax +; CHECK-O0-NEXT: # kill: def $rax killed $eax +; CHECK-O0-NEXT: movq %rax, 16(%rcx) +; CHECK-O0-NEXT: jmp use_foo # TAILCALL entry: %0 = addrspacecast i32 addrspace(271)* %i to i32 addrspace(9)* %p32 = getelementptr inbounds %struct.Foo, %struct.Foo* %f, i64 0, i32 2 @@ -126,3 +200,97 @@ tail call void @use_foo(%struct.Foo* %f) ret void } + +define i32 @test_load_sptr32(i32 addrspace(270)* %i) { +; CHECK-LABEL: test_load_sptr32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movslq %ecx, %rax +; CHECK-NEXT: movl (%rax), %eax +; CHECK-NEXT: retq +; CHECK-O0-LABEL: test_load_sptr32: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movslq %ecx, %rax +; CHECK-O0-NEXT: movl (%rax), %eax +; CHECK-O0-NEXT: retq +entry: + %0 = load i32, i32 addrspace(270)* %i, align 4 + ret i32 %0 +} + +define i32 @test_load_uptr32(i32 addrspace(271)* %i) { +; CHECK-LABEL: test_load_uptr32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl %ecx, %eax +; CHECK-NEXT: movl (%rax), %eax +; CHECK-NEXT: retq +; CHECK-O0-LABEL: test_load_uptr32: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl %ecx, %eax +; CHECK-O0-NEXT: # kill: def $rax killed $eax +; CHECK-O0-NEXT: movl (%rax), %eax +; CHECK-O0-NEXT: retq +entry: + %0 = load i32, i32 addrspace(271)* %i, align 4 + ret i32 %0 +} + +define i32 @test_load_ptr64(i32 addrspace(272)* %i) { +; CHECK-LABEL: test_load_ptr64: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl (%rcx), %eax +; CHECK-NEXT: retq +; CHECK-O0-LABEL: test_load_ptr64: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl (%rcx), %eax +; CHECK-O0-NEXT: retq +entry: + %0 = load i32, i32 addrspace(272)* %i, align 8 + ret i32 %0 +} + +define void @test_store_sptr32(i32 addrspace(270)* %s, i32 %i) { +; CHECK-LABEL: test_store_sptr32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movslq %ecx, %rax +; CHECK-NEXT: movl %edx, (%rax) +; CHECK-NEXT: retq +; CHECK-O0-LABEL: test_store_sptr32: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movslq %ecx, %rax +; CHECK-O0-NEXT: movl %edx, (%rax) +; CHECK-O0-NEXT: retq +entry: + store i32 %i, i32 addrspace(270)* %s, align 4 + ret void +} + +define void @test_store_uptr32(i32 addrspace(271)* %s, i32 %i) { +; CHECK-LABEL: test_store_uptr32: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl %ecx, %eax +; CHECK-NEXT: movl %edx, (%rax) +; CHECK-NEXT: retq +; CHECK-O0-LABEL: test_store_uptr32: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl %ecx, %eax +; CHECK-O0-NEXT: # kill: def $rax killed $eax +; CHECK-O0-NEXT: movl %edx, (%rax) +; CHECK-O0-NEXT: retq +entry: + store i32 %i, i32 addrspace(271)* %s, align 4 + ret void +} + +define void @test_store_ptr64(i32 addrspace(272)* %s, i32 %i) { +; CHECK-LABEL: test_store_ptr64: +; CHECK: # %bb.0: # %entry +; CHECK-NEXT: movl %edx, (%rcx) +; CHECK-NEXT: retq +; CHECK-O0-LABEL: test_store_ptr64: +; CHECK-O0: # %bb.0: # %entry +; CHECK-O0-NEXT: movl %edx, (%rcx) +; CHECK-O0-NEXT: retq +entry: + store i32 %i, i32 addrspace(272)* %s, align 8 + ret void +}