mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-23 11:13:28 +01:00
85900aef27
Summary: A while ago I implemented the functionality to lower Microsoft __ptr32 and __ptr64 pointers, which are stored as 32-bit and 64-bit pointer and are extended/truncated to the appropriate pointer size when dereferenced. This patch adds an addrspacecast to cast from the __ptr32/__ptr64 pointer to a default address space when dereferencing. Bug: https://bugs.llvm.org/show_bug.cgi?id=42359 Reviewers: hans, arsenm, RKSimon Subscribers: wdng, hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D81517
284 lines
8.7 KiB
LLVM
284 lines
8.7 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
|
; RUN: llc < %s | FileCheck %s --check-prefixes=ALL,CHECK
|
|
; RUN: llc -O0 < %s | FileCheck %s --check-prefixes=ALL,CHECK-O0
|
|
|
|
; Source to regenerate:
|
|
; struct Foo {
|
|
; int * __ptr32 p32;
|
|
; int * __ptr64 p64;
|
|
; __attribute__((address_space(9))) int *p_other;
|
|
; };
|
|
; void use_foo(Foo *f);
|
|
; void test_sign_ext(Foo *f, int * __ptr32 __sptr i) {
|
|
; f->p64 = i;
|
|
; use_foo(f);
|
|
; }
|
|
; void test_zero_ext(Foo *f, int * __ptr32 __uptr i) {
|
|
; f->p64 = i;
|
|
; use_foo(f);
|
|
; }
|
|
; void test_trunc(Foo *f, int * __ptr64 i) {
|
|
; f->p32 = i;
|
|
; use_foo(f);
|
|
; }
|
|
; void test_noop1(Foo *f, int * __ptr32 i) {
|
|
; f->p32 = i;
|
|
; use_foo(f);
|
|
; }
|
|
; void test_noop2(Foo *f, int * __ptr64 i) {
|
|
; f->p64 = i;
|
|
; use_foo(f);
|
|
; }
|
|
; void test_null_arg(Foo *f, int * __ptr32 i) {
|
|
; test_noop1(f, 0);
|
|
; }
|
|
; void test_unrecognized(Foo *f, __attribute__((address_space(14))) int *i) {
|
|
; f->p32 = (int * __ptr32)i;
|
|
; use_foo(f);
|
|
; }
|
|
;
|
|
; $ clang -cc1 -triple x86_64-windows-msvc -fms-extensions -O2 -S t.cpp
|
|
|
|
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
|
target triple = "x86_64-unknown-windows-msvc"
|
|
|
|
%struct.Foo = type { i32 addrspace(270)*, i32*, i32 addrspace(9)* }
|
|
declare dso_local void @use_foo(%struct.Foo*)
|
|
|
|
define dso_local void @test_sign_ext(%struct.Foo* %f, i32 addrspace(270)* %i) {
|
|
; ALL-LABEL: test_sign_ext:
|
|
; ALL: # %bb.0: # %entry
|
|
; ALL-NEXT: movslq %edx, %rax
|
|
; ALL-NEXT: movq %rax, 8(%rcx)
|
|
; ALL-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
|
|
store i32* %0, i32** %p64, align 8
|
|
tail call void @use_foo(%struct.Foo* %f)
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @test_zero_ext(%struct.Foo* %f, i32 addrspace(271)* %i) {
|
|
; 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
|
|
store i32* %0, i32** %p64, align 8
|
|
tail call void @use_foo(%struct.Foo* %f)
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @test_trunc(%struct.Foo* %f, i32* %i) {
|
|
; 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
|
|
store i32 addrspace(270)* %0, i32 addrspace(270)** %p32, align 8
|
|
tail call void @use_foo(%struct.Foo* %f)
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @test_noop1(%struct.Foo* %f, i32 addrspace(270)* %i) {
|
|
; ALL-LABEL: test_noop1:
|
|
; ALL: # %bb.0: # %entry
|
|
; ALL-NEXT: movl %edx, (%rcx)
|
|
; ALL-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
|
|
tail call void @use_foo(%struct.Foo* %f)
|
|
ret void
|
|
}
|
|
|
|
define dso_local void @test_noop2(%struct.Foo* %f, i32* %i) {
|
|
; ALL-LABEL: test_noop2:
|
|
; ALL: # %bb.0: # %entry
|
|
; ALL-NEXT: movq %rdx, 8(%rcx)
|
|
; ALL-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
|
|
tail call void @use_foo(%struct.Foo* %f)
|
|
ret void
|
|
}
|
|
|
|
; 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
|
|
}
|
|
|
|
; Test casts between unrecognized address spaces.
|
|
define void @test_unrecognized(%struct.Foo* %f, i32 addrspace(14)* %i) {
|
|
; 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
|
|
store i32 addrspace(270)* %0, i32 addrspace(270)** %p32, align 8
|
|
tail call void @use_foo(%struct.Foo* %f)
|
|
ret void
|
|
}
|
|
|
|
define void @test_unrecognized2(%struct.Foo* %f, i32 addrspace(271)* %i) {
|
|
; 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
|
|
store i32 addrspace(9)* %0, i32 addrspace(9)** %p32, align 8
|
|
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
|
|
}
|