From 516519ee9af3235d5a5ed9bb7afa5bb1a27a8ddf Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Mon, 27 Jun 2016 02:34:02 +0200 Subject: [PATCH 1/9] Allow specification of the system V AMD64 ABI constraint. This can be specified using `extern sysV64 fn` on all platforms --- src/doc/book/ffi.md | 1 + src/librustc_llvm/ffi.rs | 1 + src/librustc_trans/abi.rs | 1 + src/libsyntax/abi.rs | 2 ++ 4 files changed, 5 insertions(+) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index ca104ff29ace3..44cc75f8fed1a 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -539,6 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan * `system` * `C` * `win64` +* `sysV64` Most of the abis in this list are self-explanatory, but the `system` abi may seem a little odd. This constraint selects whatever the appropriate ABI is for diff --git a/src/librustc_llvm/ffi.rs b/src/librustc_llvm/ffi.rs index 754910c246d6f..92fe568a72c57 100644 --- a/src/librustc_llvm/ffi.rs +++ b/src/librustc_llvm/ffi.rs @@ -42,6 +42,7 @@ pub enum CallConv { ColdCallConv = 9, X86StdcallCallConv = 64, X86FastcallCallConv = 65, + X86_64_SysV = 78, X86_64_Win64 = 79, X86_VectorCall = 80 } diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 3a7fde6a36bad..9f3c20a4fd096 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -269,6 +269,7 @@ impl FnType { Vectorcall => llvm::X86_VectorCall, C => llvm::CCallConv, Win64 => llvm::X86_64_Win64, + SysV64 => llvm::X86_64_SysV, // These API constants ought to be more specific... Cdecl => llvm::CCallConv, diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index c959e2108f5a7..9fb2b539b8fe8 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -39,6 +39,7 @@ pub enum Abi { Vectorcall, Aapcs, Win64, + SysV64, // Multiplatform ABIs second Rust, @@ -86,6 +87,7 @@ const AbiDatas: &'static [AbiData] = &[ AbiData {abi: Abi::Vectorcall, name: "vectorcall"}, AbiData {abi: Abi::Aapcs, name: "aapcs" }, AbiData {abi: Abi::Win64, name: "win64" }, + AbiData {abi: Abi::SysV64, name: "sysV64" }, // Cross-platform ABIs // From 30c4173cb8f942afbb1588174e5867eb780cdaa0 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Thu, 7 Jul 2016 10:27:30 +0200 Subject: [PATCH 2/9] Change ABI string from sysV64 to sysv64 --- src/doc/book/ffi.md | 2 +- src/libsyntax/abi.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/book/ffi.md b/src/doc/book/ffi.md index 44cc75f8fed1a..1dea15311ce82 100644 --- a/src/doc/book/ffi.md +++ b/src/doc/book/ffi.md @@ -539,7 +539,7 @@ This is currently hidden behind the `abi_vectorcall` gate and is subject to chan * `system` * `C` * `win64` -* `sysV64` +* `sysv64` Most of the abis in this list are self-explanatory, but the `system` abi may seem a little odd. This constraint selects whatever the appropriate ABI is for diff --git a/src/libsyntax/abi.rs b/src/libsyntax/abi.rs index 9fb2b539b8fe8..64a71133a8c02 100644 --- a/src/libsyntax/abi.rs +++ b/src/libsyntax/abi.rs @@ -87,7 +87,7 @@ const AbiDatas: &'static [AbiData] = &[ AbiData {abi: Abi::Vectorcall, name: "vectorcall"}, AbiData {abi: Abi::Aapcs, name: "aapcs" }, AbiData {abi: Abi::Win64, name: "win64" }, - AbiData {abi: Abi::SysV64, name: "sysV64" }, + AbiData {abi: Abi::SysV64, name: "sysv64" }, // Cross-platform ABIs // From 0e58a5d139772404ab936b6c7679e9ff936101c4 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Sat, 27 Aug 2016 15:14:51 +0200 Subject: [PATCH 3/9] Feature gate the sysv64 abi as feature(abi_sysv64) and add tests --- src/libsyntax/feature_gate.rs | 23 +++- src/test/codegen/abi-sysv64.rs | 24 ++++ .../compile-fail/feature-gate-abi-sysv64.rs | 19 +++ .../run-pass/abi-sysv64-register-usage.rs | 125 ++++++++++++++++++ 4 files changed, 184 insertions(+), 7 deletions(-) create mode 100644 src/test/codegen/abi-sysv64.rs create mode 100644 src/test/compile-fail/feature-gate-abi-sysv64.rs create mode 100644 src/test/run-pass/abi-sysv64-register-usage.rs diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 1e15c1563561c..18924a3dc2535 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -281,7 +281,11 @@ declare_features! ( (active, never_type, "1.13.0", Some(35121)), // Allows all literals in attribute lists and values of key-value pairs. - (active, attr_literals, "1.13.0", Some(34981)) + (active, attr_literals, "1.13.0", Some(34981)), + + // Allows the sysV64 ABI to be specified on all platforms + // instead of just the platforms on which it is the C ABI + (active, abi_sysv64, "1.13.0", None) ); declare_features! ( @@ -811,21 +815,26 @@ macro_rules! gate_feature_post { impl<'a> PostExpansionVisitor<'a> { fn check_abi(&self, abi: Abi, span: Span) { match abi { - Abi::RustIntrinsic => + Abi::RustIntrinsic => { gate_feature_post!(&self, intrinsics, span, - "intrinsics are subject to change"), + "intrinsics are subject to change"); + }, Abi::PlatformIntrinsic => { gate_feature_post!(&self, platform_intrinsics, span, - "platform intrinsics are experimental and possibly buggy") + "platform intrinsics are experimental and possibly buggy"); }, Abi::Vectorcall => { gate_feature_post!(&self, abi_vectorcall, span, - "vectorcall is experimental and subject to change") - } + "vectorcall is experimental and subject to change"); + }, Abi::RustCall => { gate_feature_post!(&self, unboxed_closures, span, "rust-call ABI is subject to change"); - } + }, + Abi::SysV64 => { + gate_feature_post!(&self, abi_sysv64, span, + "sysv64 ABI is experimental and subject to change"); + }, _ => {} } } diff --git a/src/test/codegen/abi-sysv64.rs b/src/test/codegen/abi-sysv64.rs new file mode 100644 index 0000000000000..2b8e8a1b6b2c7 --- /dev/null +++ b/src/test/codegen/abi-sysv64.rs @@ -0,0 +1,24 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks if the correct annotation for the sysv64 ABI is passed to +// llvm. Also checks that the abi-sysv64 feature gate allows usage +// of the sysv64 abi. + +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(abi_sysv64)] + +// CHECK: define x86_64_sysvcc i64 @has_sysv64_abi +#[no_mangle] +pub extern "sysv64" fn has_sysv64_abi(a: i64) -> i64 { + a * 2 +} diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs new file mode 100644 index 0000000000000..2a4aae8c06bba --- /dev/null +++ b/src/test/compile-fail/feature-gate-abi-sysv64.rs @@ -0,0 +1,19 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Test that the sysv64 ABI cannot be used when abi-sysv64 feature +// gate is not used. + +extern "sysv64" fn foo() {} +//~^ ERROR sysv64 ABI is experimental and subject to change + +fn main() { + foo(); +} diff --git a/src/test/run-pass/abi-sysv64-register-usage.rs b/src/test/run-pass/abi-sysv64-register-usage.rs new file mode 100644 index 0000000000000..5e58240359e6c --- /dev/null +++ b/src/test/run-pass/abi-sysv64-register-usage.rs @@ -0,0 +1,125 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks if the correct registers are being used to pass arguments +// when the sysv64 ABI is specified. + +#![feature(abi_sysv64)] +#![feature(naked_functions)] +#![feature(asm)] + +#[naked] +#[inline(never)] +#[allow(unused_variables)] +pub unsafe extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64, + rcx: i64, r8 : i64, r9 : i64, + xmm0: f32, xmm1: f32, xmm2: f32, + xmm3: f32, xmm4: f32, xmm5: f32, + xmm6: f32, xmm7: f32) -> i64 { + // this assembly checks all registers for specific values, and puts in rax + // how many values were correct. + asm!("cmp rdi, 0x1; + xor rax, rax; + setz al; + + cmp rsi, 0x2; + xor rdi, rdi + setz dil; + add rax, rdi; + + cmp rdx, 0x3; + setz dil; + add rax, rdi; + + cmp rcx, 0x4; + setz dil; + add rax, rdi; + + cmp r8, 0x5; + setz dil; + add rax, rdi; + + cmp r9, 0x6; + setz dil; + add rax, rdi; + + movd esi, xmm0; + cmp rsi, 0x3F800000; + setz dil; + add rax, rdi; + + movd esi, xmm1; + cmp rsi, 0x40000000; + setz dil; + add rax, rdi; + + movd esi, xmm2; + cmp rsi, 0x40800000; + setz dil; + add rax, rdi; + + movd esi, xmm3; + cmp rsi, 0x41000000; + setz dil; + add rax, rdi; + + movd esi, xmm4; + cmp rsi, 0x41800000; + setz dil; + add rax, rdi; + + movd esi, xmm5; + cmp rsi, 0x42000000; + setz dil; + add rax, rdi; + + movd esi, xmm6; + cmp rsi, 0x42800000; + setz dil; + add rax, rdi; + + movd esi, xmm7; + cmp rsi, 0x43000000; + setz dil; + add rax, rdi; + ret + " :::: "intel"); + unreachable!(); +} + +// this struct contains 8 i64's, while only 6 can be passed in registers. +#[derive(PartialEq, Eq, Debug)] +pub struct LargeStruct(i64, i64, i64, i64, i64, i64, i64, i64); + +#[inline(never)] +pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct { + foo.0 *= 1; + foo.1 *= 2; + foo.2 *= 3; + foo.3 *= 4; + foo.4 *= 5; + foo.5 *= 6; + foo.6 *= 7; + foo.7 *= 8; + foo +} + +pub fn main() { + assert_eq!(unsafe { + all_the_registers(1, 2, 3, 4, 5, 6, + 1.0, 2.0, 4.0, 8.0, + 16.0, 32.0, 64.0, 128.0) + }, 14); + + assert_eq!( + large_struct_by_val(LargeStruct(1, 2, 3, 4, 5, 6, 7, 8)), + LargeStruct(1, 4, 9, 16, 25, 36, 49, 64) + ); +} From eef4434bf8ebcf2f9377166ff069656a1708586d Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Sat, 27 Aug 2016 19:45:15 +0200 Subject: [PATCH 4/9] Add the sysv64 calling convention to the list of known calling conventions and add the feature(abi_sysv64) to the list of known features --- src/doc/reference.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/doc/reference.md b/src/doc/reference.md index be3559a588089..ec2d3e2822e20 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -1677,6 +1677,7 @@ There are also some platform-specific ABI strings: * `extern "cdecl"` -- The default for x86\_32 C code. * `extern "stdcall"` -- The default for the Win32 API on x86\_32. * `extern "win64"` -- The default for C code on x86\_64 Windows. +* `extern "sysv64"` -- The default for C code on non-Windows x86\_64. * `extern "aapcs"` -- The default for ARM. * `extern "fastcall"` -- The `fastcall` ABI -- corresponds to MSVC's `__fastcall` and GCC and clang's `__attribute__((fastcall))` @@ -2485,6 +2486,9 @@ The currently implemented features of the reference compiler are: * - `dotdot_in_tuple_patterns` - Allows `..` in tuple (struct) patterns. +* - `abi_sysv64` - Allows the usage of the system V AMD64 calling convention + (e.g. `extern "sysv64" func fn_();`) + If a feature is promoted to a language feature, then all existing programs will start to receive compilation warnings about `#![feature]` directives which enabled the new feature (because the directive is no longer necessary). However, if a From 0e30446259be88af7b9ae6c733b49fc0c88bd7ce Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Tue, 30 Aug 2016 03:54:29 +0200 Subject: [PATCH 5/9] Select the proper x86_64 ABI based first and foremost on the specified calling convention instead of just looking at the selected platform --- src/librustc_trans/abi.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/librustc_trans/abi.rs b/src/librustc_trans/abi.rs index 9f3c20a4fd096..7f209dde27db9 100644 --- a/src/librustc_trans/abi.rs +++ b/src/librustc_trans/abi.rs @@ -484,7 +484,9 @@ impl FnType { match &ccx.sess().target.target.arch[..] { "x86" => cabi_x86::compute_abi_info(ccx, self), - "x86_64" => if ccx.sess().target.target.options.is_like_windows { + "x86_64" => if abi == Abi::SysV64 { + cabi_x86_64::compute_abi_info(ccx, self); + } else if abi == Abi::Win64 || ccx.sess().target.target.options.is_like_windows { cabi_x86_win64::compute_abi_info(ccx, self); } else { cabi_x86_64::compute_abi_info(ccx, self); From d282a633fa6f511f087a53976ce71c269d14c861 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Sat, 27 Aug 2016 20:29:14 +0200 Subject: [PATCH 6/9] Guard against platforms on which the sysv64 calling convention is not valid in non-codegen tests. Remove false positive in a test that relied on the exact formatting of an error string and rewrite the sysv64 register allocation test at it was triggering undefined behaviour --- .../compile-fail/feature-gate-abi-sysv64.rs | 6 + .../run-pass/abi-sysv64-register-usage.rs | 147 ++++++++---------- src/test/ui/codemap_tests/unicode.stderr | 2 +- 3 files changed, 71 insertions(+), 84 deletions(-) diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs index 2a4aae8c06bba..d7c012743231b 100644 --- a/src/test/compile-fail/feature-gate-abi-sysv64.rs +++ b/src/test/compile-fail/feature-gate-abi-sysv64.rs @@ -11,9 +11,15 @@ // Test that the sysv64 ABI cannot be used when abi-sysv64 feature // gate is not used. +// ignore-android +// ignore-arm +// ignore-aarch64 + +#[cfg(target_arch = "x86_64")] extern "sysv64" fn foo() {} //~^ ERROR sysv64 ABI is experimental and subject to change +#[cfg(target_arch = "x86_64")] fn main() { foo(); } diff --git a/src/test/run-pass/abi-sysv64-register-usage.rs b/src/test/run-pass/abi-sysv64-register-usage.rs index 5e58240359e6c..7e3b32122ac23 100644 --- a/src/test/run-pass/abi-sysv64-register-usage.rs +++ b/src/test/run-pass/abi-sysv64-register-usage.rs @@ -11,93 +11,42 @@ // Checks if the correct registers are being used to pass arguments // when the sysv64 ABI is specified. +// ignore-android +// ignore-arm +// ignore-aarch64 + #![feature(abi_sysv64)] -#![feature(naked_functions)] #![feature(asm)] -#[naked] -#[inline(never)] -#[allow(unused_variables)] -pub unsafe extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64, - rcx: i64, r8 : i64, r9 : i64, - xmm0: f32, xmm1: f32, xmm2: f32, - xmm3: f32, xmm4: f32, xmm5: f32, - xmm6: f32, xmm7: f32) -> i64 { - // this assembly checks all registers for specific values, and puts in rax - // how many values were correct. - asm!("cmp rdi, 0x1; - xor rax, rax; - setz al; - - cmp rsi, 0x2; - xor rdi, rdi - setz dil; - add rax, rdi; - - cmp rdx, 0x3; - setz dil; - add rax, rdi; - - cmp rcx, 0x4; - setz dil; - add rax, rdi; - - cmp r8, 0x5; - setz dil; - add rax, rdi; - - cmp r9, 0x6; - setz dil; - add rax, rdi; - - movd esi, xmm0; - cmp rsi, 0x3F800000; - setz dil; - add rax, rdi; - - movd esi, xmm1; - cmp rsi, 0x40000000; - setz dil; - add rax, rdi; - - movd esi, xmm2; - cmp rsi, 0x40800000; - setz dil; - add rax, rdi; - - movd esi, xmm3; - cmp rsi, 0x41000000; - setz dil; - add rax, rdi; - - movd esi, xmm4; - cmp rsi, 0x41800000; - setz dil; - add rax, rdi; - - movd esi, xmm5; - cmp rsi, 0x42000000; - setz dil; - add rax, rdi; - - movd esi, xmm6; - cmp rsi, 0x42800000; - setz dil; - add rax, rdi; - - movd esi, xmm7; - cmp rsi, 0x43000000; - setz dil; - add rax, rdi; - ret - " :::: "intel"); - unreachable!(); +#[cfg(target_arch = "x86_64")] +pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64, + rcx: i64, r8 : i64, r9 : i64, + xmm0: f32, xmm1: f32, xmm2: f32, + xmm3: f32, xmm4: f32, xmm5: f32, + xmm6: f32, xmm7: f32) -> i64 { + assert_eq!(rdi, 1); + assert_eq!(rsi, 2); + assert_eq!(rdx, 3); + assert_eq!(rcx, 4); + assert_eq!(r8, 5); + assert_eq!(r9, 6); + assert_eq!(xmm0, 1.0f32); + assert_eq!(xmm1, 2.0f32); + assert_eq!(xmm2, 4.0f32); + assert_eq!(xmm3, 8.0f32); + assert_eq!(xmm4, 16.0f32); + assert_eq!(xmm5, 32.0f32); + assert_eq!(xmm6, 64.0f32); + assert_eq!(xmm7, 128.0f32); + 42 } // this struct contains 8 i64's, while only 6 can be passed in registers. +#[cfg(target_arch = "x86_64")] #[derive(PartialEq, Eq, Debug)] pub struct LargeStruct(i64, i64, i64, i64, i64, i64, i64, i64); +#[cfg(target_arch = "x86_64")] #[inline(never)] pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct { foo.0 *= 1; @@ -111,15 +60,47 @@ pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct foo } +#[cfg(target_arch = "x86_64")] pub fn main() { - assert_eq!(unsafe { - all_the_registers(1, 2, 3, 4, 5, 6, - 1.0, 2.0, 4.0, 8.0, - 16.0, 32.0, 64.0, 128.0) - }, 14); + let result: i64; + unsafe { + asm!("mov rdi, 1; + mov rsi, 2; + mov rdx, 3; + mov rcx, 4; + mov r8, 5; + mov r9, 6; + mov eax, 0x3F800000; + movd xmm0, eax; + mov eax, 0x40000000; + movd xmm1, eax; + mov eax, 0x40800000; + movd xmm2, eax; + mov eax, 0x41000000; + movd xmm3, eax; + mov eax, 0x41800000; + movd xmm4, eax; + mov eax, 0x42000000; + movd xmm5, eax; + mov eax, 0x42800000; + movd xmm6, eax; + mov eax, 0x43000000; + movd xmm7, eax; + call r10 + " + : "={rax}"(result) + : "{r10}"(all_the_registers as usize) + : "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r11", "cc", "memory" + : "intel", "alignstack" + ) + } + assert_eq!(result, 42); assert_eq!( large_struct_by_val(LargeStruct(1, 2, 3, 4, 5, 6, 7, 8)), LargeStruct(1, 4, 9, 16, 25, 36, 49, 64) ); } + +#[cfg(not(target_arch = "x86_64"))] +pub fn main() {} \ No newline at end of file diff --git a/src/test/ui/codemap_tests/unicode.stderr b/src/test/ui/codemap_tests/unicode.stderr index aa42ae341c545..a748e13ecf102 100644 --- a/src/test/ui/codemap_tests/unicode.stderr +++ b/src/test/ui/codemap_tests/unicode.stderr @@ -1,4 +1,4 @@ -error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` +error: invalid ABI: expected one of [cdecl, stdcall, fastcall, vectorcall, aapcs, win64, sysv64, Rust, C, system, rust-intrinsic, rust-call, platform-intrinsic], found `路濫狼á́́` --> $DIR/unicode.rs:11:8 | 11 | extern "路濫狼á́́" fn foo() {} From 46a719e2ccc03f22537b1a3ce9e345770ca4e1ba Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Tue, 30 Aug 2016 03:24:34 +0200 Subject: [PATCH 7/9] Remove useless //ignore-arch directives on a compile-fail test, and add another test that checks if the sysv64 abi corresponds to the same rules as the C abi on unix platforms --- .../compile-fail/feature-gate-abi-sysv64.rs | 6 - src/test/run-pass/abi-sysv64-arg-passing.rs | 341 ++++++++++++++++++ 2 files changed, 341 insertions(+), 6 deletions(-) create mode 100644 src/test/run-pass/abi-sysv64-arg-passing.rs diff --git a/src/test/compile-fail/feature-gate-abi-sysv64.rs b/src/test/compile-fail/feature-gate-abi-sysv64.rs index d7c012743231b..2a4aae8c06bba 100644 --- a/src/test/compile-fail/feature-gate-abi-sysv64.rs +++ b/src/test/compile-fail/feature-gate-abi-sysv64.rs @@ -11,15 +11,9 @@ // Test that the sysv64 ABI cannot be used when abi-sysv64 feature // gate is not used. -// ignore-android -// ignore-arm -// ignore-aarch64 - -#[cfg(target_arch = "x86_64")] extern "sysv64" fn foo() {} //~^ ERROR sysv64 ABI is experimental and subject to change -#[cfg(target_arch = "x86_64")] fn main() { foo(); } diff --git a/src/test/run-pass/abi-sysv64-arg-passing.rs b/src/test/run-pass/abi-sysv64-arg-passing.rs new file mode 100644 index 0000000000000..3f6ae71ffa8e7 --- /dev/null +++ b/src/test/run-pass/abi-sysv64-arg-passing.rs @@ -0,0 +1,341 @@ +// Copyright 2016 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +// Checks if the "sysv64" calling convention behaves the same as the +// "C" calling convention on platforms where both should be the same + +// This file contains versions of the following run-pass tests with +// the calling convention changed to "sysv64" + +// cabi-int-widening +// extern-pass-char +// extern-pass-u32 +// extern-pass-u64 +// extern-pass-double +// extern-pass-empty +// extern-pass-TwoU8s +// extern-pass-TwoU16s +// extern-pass-TwoU32s +// extern-pass-TwoU64s +// extern-return-TwoU8s +// extern-return-TwoU16s +// extern-return-TwoU32s +// extern-return-TwoU64s +// foreign-fn-with-byval +// issue-28676 +// struct-return + +// ignore-android +// ignore-arm +// ignore-aarch64 +// ignore-msvc + +// note: msvc is ignored as rust_test_helpers does not have the sysv64 abi on msvc + +#![feature(abi_sysv64)] +#[allow(dead_code)] +#[allow(improper_ctypes)] + +#[cfg(target_arch = "x86_64")] +mod tests { + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU8s { + one: u8, two: u8 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU16s { + one: u16, two: u16 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU32s { + one: u32, two: u32 + } + + #[repr(C)] + #[derive(Copy, Clone, PartialEq, Debug)] + pub struct TwoU64s { + one: u64, two: u64 + } + + #[repr(C)] + pub struct ManyInts { + arg1: i8, + arg2: i16, + arg3: i32, + arg4: i16, + arg5: i8, + arg6: TwoU8s, + } + + #[repr(C)] + pub struct Empty; + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct S { + x: u64, + y: u64, + z: u64, + } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Quad { a: u64, b: u64, c: u64, d: u64 } + + #[repr(C)] + #[derive(Copy, Clone)] + pub struct Floats { a: f64, b: u8, c: f64 } + + #[link(name = "rust_test_helpers")] + extern "sysv64" { + pub fn rust_int8_to_int32(_: i8) -> i32; + pub fn rust_dbg_extern_identity_u8(v: u8) -> u8; + pub fn rust_dbg_extern_identity_u32(v: u32) -> u32; + pub fn rust_dbg_extern_identity_u64(v: u64) -> u64; + pub fn rust_dbg_extern_identity_double(v: f64) -> f64; + pub fn rust_dbg_extern_empty_struct(v1: ManyInts, e: Empty, v2: ManyInts); + pub fn rust_dbg_extern_identity_TwoU8s(v: TwoU8s) -> TwoU8s; + pub fn rust_dbg_extern_identity_TwoU16s(v: TwoU16s) -> TwoU16s; + pub fn rust_dbg_extern_identity_TwoU32s(v: TwoU32s) -> TwoU32s; + pub fn rust_dbg_extern_identity_TwoU64s(v: TwoU64s) -> TwoU64s; + pub fn rust_dbg_extern_return_TwoU8s() -> TwoU8s; + pub fn rust_dbg_extern_return_TwoU16s() -> TwoU16s; + pub fn rust_dbg_extern_return_TwoU32s() -> TwoU32s; + pub fn rust_dbg_extern_return_TwoU64s() -> TwoU64s; + pub fn get_x(x: S) -> u64; + pub fn get_y(x: S) -> u64; + pub fn get_z(x: S) -> u64; + pub fn get_c_many_params(_: *const (), _: *const (), + _: *const (), _: *const (), f: Quad) -> u64; + pub fn rust_dbg_abi_1(q: Quad) -> Quad; + pub fn rust_dbg_abi_2(f: Floats) -> Floats; + } + + pub fn cabi_int_widening() { + let x = unsafe { + rust_int8_to_int32(-1) + }; + + assert!(x == -1); + } + + pub fn extern_pass_char() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u8(22)); + } + } + + pub fn extern_pass_u32() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u32(22)); + } + } + + pub fn extern_pass_u64() { + unsafe { + assert_eq!(22, rust_dbg_extern_identity_u64(22)); + } + } + + pub fn extern_pass_double() { + unsafe { + assert_eq!(22.0_f64, rust_dbg_extern_identity_double(22.0_f64)); + } + } + + pub fn extern_pass_empty() { + unsafe { + let x = ManyInts { + arg1: 2, + arg2: 3, + arg3: 4, + arg4: 5, + arg5: 6, + arg6: TwoU8s { one: 7, two: 8, } + }; + let y = ManyInts { + arg1: 1, + arg2: 2, + arg3: 3, + arg4: 4, + arg5: 5, + arg6: TwoU8s { one: 6, two: 7, } + }; + let empty = Empty; + rust_dbg_extern_empty_struct(x, empty, y); + } + } + + pub fn extern_pass_twou8s() { + unsafe { + let x = TwoU8s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU8s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou16s() { + unsafe { + let x = TwoU16s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU16s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou32s() { + unsafe { + let x = TwoU32s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU32s(x); + assert_eq!(x, y); + } + } + + pub fn extern_pass_twou64s() { + unsafe { + let x = TwoU64s {one: 22, two: 23}; + let y = rust_dbg_extern_identity_TwoU64s(x); + assert_eq!(x, y); + } + } + + pub fn extern_return_twou8s() { + unsafe { + let y = rust_dbg_extern_return_TwoU8s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou16s() { + unsafe { + let y = rust_dbg_extern_return_TwoU16s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou32s() { + unsafe { + let y = rust_dbg_extern_return_TwoU32s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + pub fn extern_return_twou64s() { + unsafe { + let y = rust_dbg_extern_return_TwoU64s(); + assert_eq!(y.one, 10); + assert_eq!(y.two, 20); + } + } + + #[inline(never)] + fn indirect_call(func: unsafe extern "sysv64" fn(s: S) -> u64, s: S) -> u64 { + unsafe { + func(s) + } + } + + pub fn foreign_fn_with_byval() { + let s = S { x: 1, y: 2, z: 3 }; + assert_eq!(s.x, indirect_call(get_x, s)); + assert_eq!(s.y, indirect_call(get_y, s)); + assert_eq!(s.z, indirect_call(get_z, s)); + } + + fn test() { + use std::ptr; + unsafe { + let null = ptr::null(); + let q = Quad { + a: 1, + b: 2, + c: 3, + d: 4 + }; + assert_eq!(get_c_many_params(null, null, null, null, q), q.c); + } + } + + pub fn issue_28676() { + test(); + } + + fn test1() { + unsafe { + let q = Quad { a: 0xaaaa_aaaa_aaaa_aaaa, + b: 0xbbbb_bbbb_bbbb_bbbb, + c: 0xcccc_cccc_cccc_cccc, + d: 0xdddd_dddd_dddd_dddd }; + let qq = rust_dbg_abi_1(q); + println!("a: {:x}", qq.a as usize); + println!("b: {:x}", qq.b as usize); + println!("c: {:x}", qq.c as usize); + println!("d: {:x}", qq.d as usize); + assert_eq!(qq.a, q.c + 1); + assert_eq!(qq.b, q.d - 1); + assert_eq!(qq.c, q.a + 1); + assert_eq!(qq.d, q.b - 1); + } + } + + fn test2() { + unsafe { + let f = Floats { a: 1.234567890e-15_f64, + b: 0b_1010_1010, + c: 1.0987654321e-15_f64 }; + let ff = rust_dbg_abi_2(f); + println!("a: {}", ff.a as f64); + println!("b: {}", ff.b as usize); + println!("c: {}", ff.c as f64); + assert_eq!(ff.a, f.c + 1.0f64); + assert_eq!(ff.b, 0xff); + assert_eq!(ff.c, f.a - 1.0f64); + } + } + + pub fn struct_return() { + test1(); + test2(); + } +} + +#[cfg(target_arch = "x86_64")] +fn main() { + use tests::*; + cabi_int_widening(); + extern_pass_char(); + extern_pass_u32(); + extern_pass_u64(); + extern_pass_double(); + extern_pass_empty(); + extern_pass_twou8s(); + extern_pass_twou16s(); + extern_pass_twou32s(); + extern_pass_twou64s(); + extern_return_twou8s(); + extern_return_twou16s(); + extern_return_twou32s(); + extern_return_twou64s(); + foreign_fn_with_byval(); + issue_28676(); + struct_return(); +} + +#[cfg(not(target_arch = "x86_64"))] +fn main() { + +} From ad447a12b5b057802a434eb02373a966328cb3f9 Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Wed, 31 Aug 2016 15:52:10 +0200 Subject: [PATCH 8/9] Add a tracking issue to the feature gate of the sysv64 ABI --- src/libsyntax/feature_gate.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 18924a3dc2535..e224e30b1a2a4 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -285,7 +285,7 @@ declare_features! ( // Allows the sysV64 ABI to be specified on all platforms // instead of just the platforms on which it is the C ABI - (active, abi_sysv64, "1.13.0", None) + (active, abi_sysv64, "1.13.0", Some(36167)) ); declare_features! ( From 3d766a077944f167dbd412538af4c6957943374d Mon Sep 17 00:00:00 2001 From: CensoredUsername Date: Thu, 1 Sep 2016 10:35:37 +0200 Subject: [PATCH 9/9] the win64 calling convention is also used on x86_64-pc-windows-gnu, so ignore windows entirely instead of just msvc --- src/test/run-pass/abi-sysv64-arg-passing.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/run-pass/abi-sysv64-arg-passing.rs b/src/test/run-pass/abi-sysv64-arg-passing.rs index 3f6ae71ffa8e7..989155bdfd98b 100644 --- a/src/test/run-pass/abi-sysv64-arg-passing.rs +++ b/src/test/run-pass/abi-sysv64-arg-passing.rs @@ -35,9 +35,9 @@ // ignore-android // ignore-arm // ignore-aarch64 -// ignore-msvc +// ignore-windows -// note: msvc is ignored as rust_test_helpers does not have the sysv64 abi on msvc +// note: windows is ignored as rust_test_helpers does not have the sysv64 abi on windows #![feature(abi_sysv64)] #[allow(dead_code)]