diff options
Diffstat (limited to '')
50 files changed, 6375 insertions, 0 deletions
diff --git a/src/test/assembly/aarch64-naked-fn-no-bti-prolog.rs b/src/test/assembly/aarch64-naked-fn-no-bti-prolog.rs new file mode 100644 index 000000000..79b0bb2d7 --- /dev/null +++ b/src/test/assembly/aarch64-naked-fn-no-bti-prolog.rs @@ -0,0 +1,21 @@ +// compile-flags: -C no-prepopulate-passes -Zbranch-protection=bti +// assembly-output: emit-asm +// needs-asm-support +// only-aarch64 + +#![crate_type = "lib"] +#![feature(naked_functions)] +use std::arch::asm; + +// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", +// meaning "no prologue whatsoever, no, really, not one instruction." +// Unfortunately, aarch64's "branch target identification" works via hints at landing sites. +// LLVM implements this via making sure of that, even for functions with the naked attribute. +// So, we must emit an appropriate instruction instead! +#[no_mangle] +#[naked] +pub unsafe extern "C" fn _hlt() -> ! { + // CHECK-NOT: hint #34 + // CHECK: hlt #0x1 + asm!("hlt #1", options(noreturn)) +} diff --git a/src/test/assembly/aarch64-pointer-auth.rs b/src/test/assembly/aarch64-pointer-auth.rs new file mode 100644 index 000000000..27e289086 --- /dev/null +++ b/src/test/assembly/aarch64-pointer-auth.rs @@ -0,0 +1,22 @@ +// Test that PAC instructions are emitted when branch-protection is specified. + +// min-llvm-version: 10.0.1 +// assembly-output: emit-asm +// compile-flags: --target aarch64-unknown-linux-gnu +// compile-flags: -Z branch-protection=pac-ret,leaf +// needs-llvm-components: aarch64 + +#![feature(no_core, lang_items)] +#![no_std] +#![no_core] +#![crate_type = "lib"] + +#[lang = "sized"] +trait Sized {} + +// CHECK: hint #25 +// CHECK: hint #29 +#[no_mangle] +pub fn test() -> u8 { + 42 +} diff --git a/src/test/assembly/align_offset.rs b/src/test/assembly/align_offset.rs new file mode 100644 index 000000000..c5eefca34 --- /dev/null +++ b/src/test/assembly/align_offset.rs @@ -0,0 +1,48 @@ +// assembly-output: emit-asm +// compile-flags: -Copt-level=1 +// only-x86_64 +// min-llvm-version: 14.0 +#![crate_type="rlib"] + +// CHECK-LABEL: align_offset_byte_ptr +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +#[no_mangle] +pub fn align_offset_byte_ptr(ptr: *const u8) -> usize { + ptr.align_offset(32) +} + +// CHECK-LABEL: align_offset_byte_slice +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +#[no_mangle] +pub fn align_offset_byte_slice(slice: &[u8]) -> usize { + slice.as_ptr().align_offset(32) +} + +// CHECK-LABEL: align_offset_word_ptr +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +// CHECK: shrq +// This `ptr` is not known to be aligned, so it is required to check if it is at all possible to +// align. LLVM applies a simple mask. +// CHECK: orq +#[no_mangle] +pub fn align_offset_word_ptr(ptr: *const u32) -> usize { + ptr.align_offset(32) +} + +// CHECK-LABEL: align_offset_word_slice +// CHECK: leaq 31 +// CHECK: andq $-32 +// CHECK: subq +// CHECK: shrq +// `slice` is known to be aligned, so `!0` is not possible as a return +// CHECK-NOT: orq +#[no_mangle] +pub fn align_offset_word_slice(slice: &[u32]) -> usize { + slice.as_ptr().align_offset(32) +} diff --git a/src/test/assembly/asm/aarch64-modifiers.rs b/src/test/assembly/asm/aarch64-modifiers.rs new file mode 100644 index 000000000..5196aa9fa --- /dev/null +++ b/src/test/assembly/asm/aarch64-modifiers.rs @@ -0,0 +1,145 @@ +// assembly-output: emit-asm +// compile-flags: -O +// compile-flags: --target aarch64-unknown-linux-gnu +// needs-llvm-components: aarch64 + +#![feature(no_core, lang_items, rustc_attrs)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +impl Copy for i32 {} + +macro_rules! check { + ($func:ident $reg:ident $code:literal) => { + // -O and extern "C" guarantee that the selected register is always r0/s0/d0/q0 + #[no_mangle] + pub unsafe extern "C" fn $func() -> i32 { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!($code, out($reg) y); + y + } + }; +} + +// CHECK-LABEL: reg: +// CHECK: //APP +// CHECK: mov x0, x0 +// CHECK: //NO_APP +check!(reg reg "mov {0}, {0}"); + +// CHECK-LABEL: reg_w: +// CHECK: //APP +// CHECK: mov w0, w0 +// CHECK: //NO_APP +check!(reg_w reg "mov {0:w}, {0:w}"); + +// CHECK-LABEL: reg_x: +// CHECK: //APP +// CHECK: mov x0, x0 +// CHECK: //NO_APP +check!(reg_x reg "mov {0:x}, {0:x}"); + +// CHECK-LABEL: vreg: +// CHECK: //APP +// CHECK: add v0.4s, v0.4s, v0.4s +// CHECK: //NO_APP +check!(vreg vreg "add {0}.4s, {0}.4s, {0}.4s"); + +// CHECK-LABEL: vreg_b: +// CHECK: //APP +// CHECK: ldr b0, [x0] +// CHECK: //NO_APP +check!(vreg_b vreg "ldr {:b}, [x0]"); + +// CHECK-LABEL: vreg_h: +// CHECK: //APP +// CHECK: ldr h0, [x0] +// CHECK: //NO_APP +check!(vreg_h vreg "ldr {:h}, [x0]"); + +// CHECK-LABEL: vreg_s: +// CHECK: //APP +// CHECK: ldr s0, [x0] +// CHECK: //NO_APP +check!(vreg_s vreg "ldr {:s}, [x0]"); + +// CHECK-LABEL: vreg_d: +// CHECK: //APP +// CHECK: ldr d0, [x0] +// CHECK: //NO_APP +check!(vreg_d vreg "ldr {:d}, [x0]"); + +// CHECK-LABEL: vreg_q: +// CHECK: //APP +// CHECK: ldr q0, [x0] +// CHECK: //NO_APP +check!(vreg_q vreg "ldr {:q}, [x0]"); + +// CHECK-LABEL: vreg_v: +// CHECK: //APP +// CHECK: add v0.4s, v0.4s, v0.4s +// CHECK: //NO_APP +check!(vreg_v vreg "add {0:v}.4s, {0:v}.4s, {0:v}.4s"); + +// CHECK-LABEL: vreg_low16: +// CHECK: //APP +// CHECK: add v0.4s, v0.4s, v0.4s +// CHECK: //NO_APP +check!(vreg_low16 vreg_low16 "add {0}.4s, {0}.4s, {0}.4s"); + +// CHECK-LABEL: vreg_low16_b: +// CHECK: //APP +// CHECK: ldr b0, [x0] +// CHECK: //NO_APP +check!(vreg_low16_b vreg_low16 "ldr {:b}, [x0]"); + +// CHECK-LABEL: vreg_low16_h: +// CHECK: //APP +// CHECK: ldr h0, [x0] +// CHECK: //NO_APP +check!(vreg_low16_h vreg_low16 "ldr {:h}, [x0]"); + +// CHECK-LABEL: vreg_low16_s: +// CHECK: //APP +// CHECK: ldr s0, [x0] +// CHECK: //NO_APP +check!(vreg_low16_s vreg_low16 "ldr {:s}, [x0]"); + +// CHECK-LABEL: vreg_low16_d: +// CHECK: //APP +// CHECK: ldr d0, [x0] +// CHECK: //NO_APP +check!(vreg_low16_d vreg_low16 "ldr {:d}, [x0]"); + +// CHECK-LABEL: vreg_low16_q: +// CHECK: //APP +// CHECK: ldr q0, [x0] +// CHECK: //NO_APP +check!(vreg_low16_q vreg_low16 "ldr {:q}, [x0]"); + +// CHECK-LABEL: vreg_low16_v: +// CHECK: //APP +// CHECK: add v0.4s, v0.4s, v0.4s +// CHECK: //NO_APP +check!(vreg_low16_v vreg_low16 "add {0:v}.4s, {0:v}.4s, {0:v}.4s"); diff --git a/src/test/assembly/asm/aarch64-outline-atomics.rs b/src/test/assembly/asm/aarch64-outline-atomics.rs new file mode 100644 index 000000000..c2ec4e911 --- /dev/null +++ b/src/test/assembly/asm/aarch64-outline-atomics.rs @@ -0,0 +1,16 @@ +// assembly-output: emit-asm +// compile-flags: -O +// compile-flags: --target aarch64-unknown-linux-gnu +// needs-llvm-components: aarch64 +// only-aarch64 +// only-linux + +#![crate_type = "rlib"] + +use std::sync::atomic::{AtomicI32, Ordering::*}; + +pub fn compare_exchange(a: &AtomicI32) { + // On AArch64 LLVM should outline atomic operations. + // CHECK: __aarch64_cas4_relax + let _ = a.compare_exchange(0, 10, Relaxed, Relaxed); +} diff --git a/src/test/assembly/asm/aarch64-types.rs b/src/test/assembly/asm/aarch64-types.rs new file mode 100644 index 000000000..04b5f4aed --- /dev/null +++ b/src/test/assembly/asm/aarch64-types.rs @@ -0,0 +1,565 @@ +// assembly-output: emit-asm +// compile-flags: --target aarch64-unknown-linux-gnu +// needs-llvm-components: aarch64 + +#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *mut u8; + +#[repr(simd)] +pub struct i8x8(i8, i8, i8, i8, i8, i8, i8, i8); +#[repr(simd)] +pub struct i16x4(i16, i16, i16, i16); +#[repr(simd)] +pub struct i32x2(i32, i32); +#[repr(simd)] +pub struct i64x1(i64); +#[repr(simd)] +pub struct f32x2(f32, f32); +#[repr(simd)] +pub struct f64x1(f64); +#[repr(simd)] +pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8); +#[repr(simd)] +pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] +pub struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +pub struct i64x2(i64, i64); +#[repr(simd)] +pub struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +pub struct f64x2(f64, f64); + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for i64 {} +impl Copy for f64 {} +impl Copy for ptr {} +impl Copy for i8x8 {} +impl Copy for i16x4 {} +impl Copy for i32x2 {} +impl Copy for i64x1 {} +impl Copy for f32x2 {} +impl Copy for f64x1 {} +impl Copy for i8x16 {} +impl Copy for i16x8 {} +impl Copy for i32x4 {} +impl Copy for i64x2 {} +impl Copy for f32x4 {} +impl Copy for f64x2 {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: sym_fn: +// CHECK: //APP +// CHECK: bl extern_func +// CHECK: //NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("bl {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: //APP +// CHECK: adr x0, extern_static +// CHECK: //NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("adr x0, {}", sym extern_static); +} + +// Regression test for #75761 +// CHECK-LABEL: issue_75761: +// CHECK: str {{.*}}x30 +// CHECK: //APP +// CHECK: //NO_APP +// CHECK: ldr {{.*}}x30 +#[no_mangle] +pub unsafe fn issue_75761() { + asm!("", out("v0") _, out("x30") _); +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal $modifier:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!( + concat!($mov, " {:", $modifier, "}, {:", $modifier, "}"), + out($class) y, + in($class) x + ); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +// CHECK-LABEL: reg_i8: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_i8 i8 reg "mov" ""); + +// CHECK-LABEL: reg_i16: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_i16 i16 reg "mov" ""); + +// CHECK-LABEL: reg_i32: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_i32 i32 reg "mov" ""); + +// CHECK-LABEL: reg_f32: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_f32 f32 reg "mov" ""); + +// CHECK-LABEL: reg_i64: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_i64 i64 reg "mov" ""); + +// CHECK-LABEL: reg_f64: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_f64 f64 reg "mov" ""); + +// CHECK-LABEL: reg_ptr: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check!(reg_ptr ptr reg "mov" ""); + +// CHECK-LABEL: vreg_i8: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i8 i8 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i16: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i16 i16 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i32: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i32 i32 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_f32: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f32 f32 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i64: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i64 i64 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_f64: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f64 f64 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_ptr: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_ptr ptr vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i8x8: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i8x8 i8x8 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i16x4: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i16x4 i16x4 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i32x2: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i32x2 i32x2 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i64x1: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i64x1 i64x1 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_f32x2: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f32x2 f32x2 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_f64x1: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f64x1 f64x1 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i8x16: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i8x16 i8x16 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i16x8: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i16x8 i16x8 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i32x4: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i32x4 i32x4 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_i64x2: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_i64x2 i64x2 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_f32x4: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f32x4 f32x4 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_f64x2: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_f64x2 f64x2 vreg "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i8: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i8 i8 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i16: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i16 i16 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_f32: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f32 f32 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i64: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i64 i64 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_f64: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f64 f64 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_ptr: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_ptr ptr vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i8x8: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i8x8 i8x8 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i16x4: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i16x4 i16x4 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i32x2: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i32x2 i32x2 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i64x1: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i64x1 i64x1 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_f32x2: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f32x2 f32x2 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_f64x1: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f64x1 f64x1 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i8x16: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i8x16 i8x16 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i16x8: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i16x8 i16x8 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i32x4: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i32x4 i32x4 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_i64x2: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_i64x2 i64x2 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_f32x4: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f32x4 f32x4 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: vreg_low16_f64x2: +// CHECK: //APP +// CHECK: fmov s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: //NO_APP +check!(vreg_low16_f64x2 f64x2 vreg_low16 "fmov" "s"); + +// CHECK-LABEL: x0_i8: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_i8 i8 "x0" "mov"); + +// CHECK-LABEL: x0_i16: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_i16 i16 "x0" "mov"); + +// CHECK-LABEL: x0_i32: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_i32 i32 "x0" "mov"); + +// CHECK-LABEL: x0_f32: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_f32 f32 "x0" "mov"); + +// CHECK-LABEL: x0_i64: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_i64 i64 "x0" "mov"); + +// CHECK-LABEL: x0_f64: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_f64 f64 "x0" "mov"); + +// CHECK-LABEL: x0_ptr: +// CHECK: //APP +// CHECK: mov x{{[0-9]+}}, x{{[0-9]+}} +// CHECK: //NO_APP +check_reg!(x0_ptr ptr "x0" "mov"); + +// CHECK-LABEL: v0_i8: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i8 i8 "s0" "fmov"); + +// CHECK-LABEL: v0_i16: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i16 i16 "s0" "fmov"); + +// CHECK-LABEL: v0_i32: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i32 i32 "s0" "fmov"); + +// CHECK-LABEL: v0_f32: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f32 f32 "s0" "fmov"); + +// CHECK-LABEL: v0_i64: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i64 i64 "s0" "fmov"); + +// CHECK-LABEL: v0_f64: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f64 f64 "s0" "fmov"); + +// CHECK-LABEL: v0_ptr: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_ptr ptr "s0" "fmov"); + +// CHECK-LABEL: v0_i8x8: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i8x8 i8x8 "s0" "fmov"); + +// CHECK-LABEL: v0_i16x4: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i16x4 i16x4 "s0" "fmov"); + +// CHECK-LABEL: v0_i32x2: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i32x2 i32x2 "s0" "fmov"); + +// CHECK-LABEL: v0_i64x1: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i64x1 i64x1 "s0" "fmov"); + +// CHECK-LABEL: v0_f32x2: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f32x2 f32x2 "s0" "fmov"); + +// CHECK-LABEL: v0_f64x1: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f64x1 f64x1 "s0" "fmov"); + +// CHECK-LABEL: v0_i8x16: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i8x16 i8x16 "s0" "fmov"); + +// CHECK-LABEL: v0_i16x8: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i16x8 i16x8 "s0" "fmov"); + +// CHECK-LABEL: v0_i32x4: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i32x4 i32x4 "s0" "fmov"); + +// CHECK-LABEL: v0_i64x2: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_i64x2 i64x2 "s0" "fmov"); + +// CHECK-LABEL: v0_f32x4: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f32x4 f32x4 "s0" "fmov"); + +// CHECK-LABEL: v0_f64x2: +// CHECK: //APP +// CHECK: fmov s0, s0 +// CHECK: //NO_APP +check_reg!(v0_f64x2 f64x2 "s0" "fmov"); diff --git a/src/test/assembly/asm/arm-modifiers.rs b/src/test/assembly/asm/arm-modifiers.rs new file mode 100644 index 000000000..88ffeaecf --- /dev/null +++ b/src/test/assembly/asm/arm-modifiers.rs @@ -0,0 +1,144 @@ +// assembly-output: emit-asm +// compile-flags: -O +// compile-flags: --target armv7-unknown-linux-gnueabihf +// compile-flags: -C target-feature=+neon +// needs-llvm-components: arm + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[repr(simd)] +pub struct f32x4(f32, f32, f32, f32); + +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for f64 {} +impl Copy for f32x4 {} + +macro_rules! check { + ($func:ident $modifier:literal $reg:ident $ty:ident $mov:literal) => { + // -O and extern "C" guarantee that the selected register is always r0/s0/d0/q0 + #[no_mangle] + pub unsafe extern "C" fn $func() -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " {0:", $modifier, "}, {0:", $modifier, "}"), out($reg) y); + y + } + }; +} + +// CHECK-LABEL: reg: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check!(reg "" reg i32 "mov"); + +// CHECK-LABEL: sreg: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check!(sreg "" sreg f32 "vmov.f32"); + +// CHECK-LABEL: sreg_low16: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check!(sreg_low16 "" sreg_low16 f32 "vmov.f32"); + +// CHECK-LABEL: dreg: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(dreg "" dreg f64 "vmov.f64"); + +// CHECK-LABEL: dreg_low16: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(dreg_low16 "" dreg_low16 f64 "vmov.f64"); + +// CHECK-LABEL: dreg_low8: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(dreg_low8 "" dreg_low8 f64 "vmov.f64"); + +// CHECK-LABEL: qreg: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check!(qreg "" qreg f32x4 "vmov"); + +// CHECK-LABEL: qreg_e: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(qreg_e "e" qreg f32x4 "vmov.f64"); + +// CHECK-LABEL: qreg_f: +// CHECK: @APP +// CHECK: vmov.f64 d1, d1 +// CHECK: @NO_APP +check!(qreg_f "f" qreg f32x4 "vmov.f64"); + +// CHECK-LABEL: qreg_low8: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check!(qreg_low8 "" qreg_low8 f32x4 "vmov"); + +// CHECK-LABEL: qreg_low8_e: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(qreg_low8_e "e" qreg_low8 f32x4 "vmov.f64"); + +// CHECK-LABEL: qreg_low8_f: +// CHECK: @APP +// CHECK: vmov.f64 d1, d1 +// CHECK: @NO_APP +check!(qreg_low8_f "f" qreg_low8 f32x4 "vmov.f64"); + +// CHECK-LABEL: qreg_low4: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check!(qreg_low4 "" qreg_low4 f32x4 "vmov"); + +// CHECK-LABEL: qreg_low4_e: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check!(qreg_low4_e "e" qreg_low4 f32x4 "vmov.f64"); + +// CHECK-LABEL: qreg_low4_f: +// CHECK: @APP +// CHECK: vmov.f64 d1, d1 +// CHECK: @NO_APP +check!(qreg_low4_f "f" qreg_low4 f32x4 "vmov.f64"); diff --git a/src/test/assembly/asm/arm-types.rs b/src/test/assembly/asm/arm-types.rs new file mode 100644 index 000000000..5ac1af6af --- /dev/null +++ b/src/test/assembly/asm/arm-types.rs @@ -0,0 +1,530 @@ +// assembly-output: emit-asm +// compile-flags: --target armv7-unknown-linux-gnueabihf +// compile-flags: -C target-feature=+neon +// needs-llvm-components: arm + +#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *mut u8; + +#[repr(simd)] +pub struct i8x8(i8, i8, i8, i8, i8, i8, i8, i8); +#[repr(simd)] +pub struct i16x4(i16, i16, i16, i16); +#[repr(simd)] +pub struct i32x2(i32, i32); +#[repr(simd)] +pub struct i64x1(i64); +#[repr(simd)] +pub struct f32x2(f32, f32); +#[repr(simd)] +pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8); +#[repr(simd)] +pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] +pub struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +pub struct i64x2(i64, i64); +#[repr(simd)] +pub struct f32x4(f32, f32, f32, f32); + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for i64 {} +impl Copy for f64 {} +impl Copy for ptr {} +impl Copy for i8x8 {} +impl Copy for i16x4 {} +impl Copy for i32x2 {} +impl Copy for i64x1 {} +impl Copy for f32x2 {} +impl Copy for i8x16 {} +impl Copy for i16x8 {} +impl Copy for i32x4 {} +impl Copy for i64x2 {} +impl Copy for f32x4 {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: sym_fn: +// CHECK: @APP +// CHECK: bl extern_func +// CHECK: @NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("bl {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: @APP +// CHECK: adr r0, extern_static +// CHECK: @NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("adr r0, {}", sym extern_static); +} + +// Regression test for #82052. +// CHECK-LABEL: issue_82052 +// CHECK: push {{.*}}lr +// CHECK: @APP +// CHECK: @NO_APP +pub unsafe fn issue_82052() { + asm!("", out("r14") _); +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " {}, {}"), out($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +// CHECK-LABEL: reg_i8: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_i8 i8 reg "mov"); + +// CHECK-LABEL: reg_i16: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_i16 i16 reg "mov"); + +// CHECK-LABEL: reg_i32: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_i32 i32 reg "mov"); + +// CHECK-LABEL: reg_f32: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_f32 f32 reg "mov"); + +// CHECK-LABEL: reg_ptr: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_ptr ptr reg "mov"); + +// CHECK-LABEL: sreg_i32: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_i32 i32 sreg "vmov.f32"); + +// CHECK-LABEL: sreg_f32: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_f32 f32 sreg "vmov.f32"); + +// CHECK-LABEL: sreg_ptr: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_ptr ptr sreg "vmov.f32"); + +// CHECK-LABEL: sreg_low16_i32: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_low16_i32 i32 sreg_low16 "vmov.f32"); + +// CHECK-LABEL: sreg_low16_f32: +// CHECK: @APP +// CHECK: vmov.f32 s{{[0-9]+}}, s{{[0-9]+}} +// CHECK: @NO_APP +check!(sreg_low16_f32 f32 sreg_low16 "vmov.f32"); + +// CHECK-LABEL: dreg_i64: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_i64 i64 dreg "vmov.f64"); + +// CHECK-LABEL: dreg_f64: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_f64 f64 dreg "vmov.f64"); + +// CHECK-LABEL: dreg_i8x8: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_i8x8 i8x8 dreg "vmov.f64"); + +// CHECK-LABEL: dreg_i16x4: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_i16x4 i16x4 dreg "vmov.f64"); + +// CHECK-LABEL: dreg_i32x2: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_i32x2 i32x2 dreg "vmov.f64"); + +// CHECK-LABEL: dreg_i64x1: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_i64x1 i64x1 dreg "vmov.f64"); + +// CHECK-LABEL: dreg_f32x2: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_f32x2 f32x2 dreg "vmov.f64"); + +// CHECK-LABEL: dreg_low16_i64: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low16_i64 i64 dreg_low16 "vmov.f64"); + +// CHECK-LABEL: dreg_low16_f64: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low16_f64 f64 dreg_low16 "vmov.f64"); + +// CHECK-LABEL: dreg_low16_i8x8: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low16_i8x8 i8x8 dreg_low16 "vmov.f64"); + +// CHECK-LABEL: dreg_low16_i16x4: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low16_i16x4 i16x4 dreg_low16 "vmov.f64"); + +// CHECK-LABEL: dreg_low16_i32x2: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low16_i32x2 i32x2 dreg_low16 "vmov.f64"); + +// CHECK-LABEL: dreg_low16_i64x1: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low16_i64x1 i64x1 dreg_low16 "vmov.f64"); + +// CHECK-LABEL: dreg_low16_f32x2: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low16_f32x2 f32x2 dreg_low16 "vmov.f64"); + +// CHECK-LABEL: dreg_low8_i64: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low8_i64 i64 dreg_low8 "vmov.f64"); + +// CHECK-LABEL: dreg_low8_f64: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low8_f64 f64 dreg_low8 "vmov.f64"); + +// CHECK-LABEL: dreg_low8_i8x8: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low8_i8x8 i8x8 dreg_low8 "vmov.f64"); + +// CHECK-LABEL: dreg_low8_i16x4: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low8_i16x4 i16x4 dreg_low8 "vmov.f64"); + +// CHECK-LABEL: dreg_low8_i32x2: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low8_i32x2 i32x2 dreg_low8 "vmov.f64"); + +// CHECK-LABEL: dreg_low8_i64x1: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low8_i64x1 i64x1 dreg_low8 "vmov.f64"); + +// CHECK-LABEL: dreg_low8_f32x2: +// CHECK: @APP +// CHECK: vmov.f64 d{{[0-9]+}}, d{{[0-9]+}} +// CHECK: @NO_APP +check!(dreg_low8_f32x2 f32x2 dreg_low8 "vmov.f64"); + +// CHECK-LABEL: qreg_i8x16: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_i8x16 i8x16 qreg "vmov"); + +// CHECK-LABEL: qreg_i16x8: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_i16x8 i16x8 qreg "vmov"); + +// CHECK-LABEL: qreg_i32x4: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_i32x4 i32x4 qreg "vmov"); + +// CHECK-LABEL: qreg_i64x2: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_i64x2 i64x2 qreg "vmov"); + +// CHECK-LABEL: qreg_f32x4: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_f32x4 f32x4 qreg "vmov"); + +// CHECK-LABEL: qreg_low8_i8x16: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_low8_i8x16 i8x16 qreg_low8 "vmov"); + +// CHECK-LABEL: qreg_low8_i16x8: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_low8_i16x8 i16x8 qreg_low8 "vmov"); + +// CHECK-LABEL: qreg_low8_i32x4: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_low8_i32x4 i32x4 qreg_low8 "vmov"); + +// CHECK-LABEL: qreg_low8_i64x2: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_low8_i64x2 i64x2 qreg_low8 "vmov"); + +// CHECK-LABEL: qreg_low8_f32x4: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_low8_f32x4 f32x4 qreg_low8 "vmov"); + +// CHECK-LABEL: qreg_low4_i8x16: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_low4_i8x16 i8x16 qreg_low4 "vmov"); + +// CHECK-LABEL: qreg_low4_i16x8: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_low4_i16x8 i16x8 qreg_low4 "vmov"); + +// CHECK-LABEL: qreg_low4_i32x4: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_low4_i32x4 i32x4 qreg_low4 "vmov"); + +// CHECK-LABEL: qreg_low4_i64x2: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_low4_i64x2 i64x2 qreg_low4 "vmov"); + +// CHECK-LABEL: qreg_low4_f32x4: +// CHECK: @APP +// CHECK: vorr q{{[0-9]+}}, q{{[0-9]+}}, q{{[0-9]+}} +// CHECK: @NO_APP +check!(qreg_low4_f32x4 f32x4 qreg_low4 "vmov"); + +// CHECK-LABEL: r0_i8: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_i8 i8 "r0" "mov"); + +// CHECK-LABEL: r0_i16: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_i16 i16 "r0" "mov"); + +// CHECK-LABEL: r0_i32: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_i32 i32 "r0" "mov"); + +// CHECK-LABEL: r0_f32: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_f32 f32 "r0" "mov"); + +// CHECK-LABEL: r0_ptr: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check_reg!(r0_ptr ptr "r0" "mov"); + +// CHECK-LABEL: s0_i32: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check_reg!(s0_i32 i32 "s0" "vmov.f32"); + +// CHECK-LABEL: s0_f32: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check_reg!(s0_f32 f32 "s0" "vmov.f32"); + +// CHECK-LABEL: s0_ptr: +// CHECK: @APP +// CHECK: vmov.f32 s0, s0 +// CHECK: @NO_APP +check_reg!(s0_ptr ptr "s0" "vmov.f32"); + +// CHECK-LABEL: d0_i64: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check_reg!(d0_i64 i64 "d0" "vmov.f64"); + +// CHECK-LABEL: d0_f64: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check_reg!(d0_f64 f64 "d0" "vmov.f64"); + +// CHECK-LABEL: d0_i8x8: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check_reg!(d0_i8x8 i8x8 "d0" "vmov.f64"); + +// CHECK-LABEL: d0_i16x4: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check_reg!(d0_i16x4 i16x4 "d0" "vmov.f64"); + +// CHECK-LABEL: d0_i32x2: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check_reg!(d0_i32x2 i32x2 "d0" "vmov.f64"); + +// CHECK-LABEL: d0_i64x1: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check_reg!(d0_i64x1 i64x1 "d0" "vmov.f64"); + +// CHECK-LABEL: d0_f32x2: +// CHECK: @APP +// CHECK: vmov.f64 d0, d0 +// CHECK: @NO_APP +check_reg!(d0_f32x2 f32x2 "d0" "vmov.f64"); + +// CHECK-LABEL: q0_i8x16: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check_reg!(q0_i8x16 i8x16 "q0" "vmov"); + +// CHECK-LABEL: q0_i16x8: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check_reg!(q0_i16x8 i16x8 "q0" "vmov"); + +// CHECK-LABEL: q0_i32x4: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check_reg!(q0_i32x4 i32x4 "q0" "vmov"); + +// CHECK-LABEL: q0_i64x2: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check_reg!(q0_i64x2 i64x2 "q0" "vmov"); + +// CHECK-LABEL: q0_f32x4: +// CHECK: @APP +// CHECK: vorr q0, q0, q0 +// CHECK: @NO_APP +check_reg!(q0_f32x4 f32x4 "q0" "vmov"); diff --git a/src/test/assembly/asm/avr-modifiers.rs b/src/test/assembly/asm/avr-modifiers.rs new file mode 100644 index 000000000..aba4c982c --- /dev/null +++ b/src/test/assembly/asm/avr-modifiers.rs @@ -0,0 +1,60 @@ +// min-llvm-version: 13.0 +// assembly-output: emit-asm +// compile-flags: --target avr-unknown-gnu-atmega328 +// needs-llvm-components: avr + +#![feature(no_core, lang_items, rustc_attrs, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const u64; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for ptr {} + +macro_rules! check { + ($func:ident $hi:literal $lo:literal $reg:tt) => { + #[no_mangle] + unsafe fn $func() -> i16 { + let y; + asm!(concat!("mov {0:", $hi, "}, {0:", $lo, "}"), out($reg) y); + y + } + }; +} + +// CHECK-LABEL: reg_pair_modifiers: +// CHECK: ;APP +// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}} +// CHECK: ;NO_APP +check!(reg_pair_modifiers "h" "l" reg_pair); + +// CHECK-LABEL: reg_iw_modifiers: +// CHECK: ;APP +// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}} +// CHECK: ;NO_APP +check!(reg_iw_modifiers "h" "l" reg_iw); + +// CHECK-LABEL: reg_ptr_modifiers: +// CHECK: ;APP +// CHECK: mov r{{[1-9]?[13579]}}, r{{[1-9]?[24680]}} +// CHECK: ;NO_APP +check!(reg_ptr_modifiers "h" "l" reg_ptr); diff --git a/src/test/assembly/asm/avr-types.rs b/src/test/assembly/asm/avr-types.rs new file mode 100644 index 000000000..53a601e51 --- /dev/null +++ b/src/test/assembly/asm/avr-types.rs @@ -0,0 +1,222 @@ +// min-llvm-version: 13.0 +// assembly-output: emit-asm +// compile-flags: --target avr-unknown-gnu-atmega328 +// needs-llvm-components: avr + +#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const u64; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for ptr {} + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("mov {}, {}", lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! checkw { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("movw {}, {}", lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("mov ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +macro_rules! check_regw { + ($func:ident $ty:ident $reg:tt $reg_lit:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("movw ", $reg_lit, ", ", $reg_lit), lateout($reg) y, in($reg) x); + y + } + }; +} + +extern "C" { + fn extern_func(); + static extern_static: i8; +} + +// CHECK-LABEL: sym_fn +// CHECK: ;APP +// CHECK: call extern_func +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static +// CHECK: ;APP +// CHECK: lds r{{[0-9]+}}, extern_static +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn sym_static() -> i8 { + let y; + asm!("lds {}, {}", lateout(reg) y, sym extern_static); + y +} + +// CHECK-LABEL: ld_z: +// CHECK: ;APP +// CHECK: ld r{{[0-9]+}}, Z +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn ld_z(x: i16) -> i8 { + let y; + asm!("ld {}, Z", out(reg) y, in("Z") x); + y +} + +// CHECK-LABEL: ldd_z: +// CHECK: ;APP +// CHECK: ldd r{{[0-9]+}}, Z+4 +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn ldd_z(x: i16) -> i8 { + let y; + asm!("ldd {}, Z+4", out(reg) y, in("Z") x); + y +} + +// CHECK-LABEL: ld_predecrement: +// CHECK: ;APP +// CHECK: ld r{{[0-9]+}}, -Z +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn ld_predecrement(x: i16) -> i8 { + let y; + asm!("ld {}, -Z", out(reg) y, in("Z") x); + y +} + +// CHECK-LABEL: ld_postincrement: +// CHECK: ;APP +// CHECK: ld r{{[0-9]+}}, Z+ +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn ld_postincrement(x: i16) -> i8 { + let y; + asm!("ld {}, Z+", out(reg) y, in("Z") x); + y +} + +// CHECK-LABEL: muls_clobber: +// CHECK: ;APP +// CHECK: muls r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: movw r{{[0-9]+}}, r0 +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn muls_clobber(x: i8, y: i8) -> i16 { + let z; + asm!( + "muls {}, {}", + "movw {}, r1:r0", + out(reg_iw) z, + in(reg) x, + in(reg) y, + ); + z +} + +// CHECK-LABEL: reg_i8: +// CHECK: ;APP +// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_upper_i8: +// CHECK: ;APP +// CHECK: mov r{{[1-3][0-9]}}, r{{[1-3][0-9]}} +// CHECK: ;NO_APP +check!(reg_upper_i8 i8 reg_upper); + +// CHECK-LABEL: reg_pair_i16: +// CHECK: ;APP +// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +checkw!(reg_pair_i16 i16 reg_pair); + +// CHECK-LABEL: reg_iw_i16: +// CHECK: ;APP +// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +checkw!(reg_iw_i16 i16 reg_iw); + +// CHECK-LABEL: reg_ptr_i16: +// CHECK: ;APP +// CHECK: movw r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +checkw!(reg_ptr_i16 i16 reg_ptr); + +// CHECK-LABEL: r2_i8: +// CHECK: ;APP +// CHECK: mov r2, r2 +// CHECK: ;NO_APP +check_reg!(r2_i8 i8 "r2"); + +// CHECK-LABEL: xl_i8: +// CHECK: ;APP +// CHECK: mov r26, r26 +// CHECK: ;NO_APP +check_reg!(xl_i8 i8 "XL"); + +// CHECK-LABEL: xh_i8: +// CHECK: ;APP +// CHECK: mov r27, r27 +// CHECK: ;NO_APP +check_reg!(xh_i8 i8 "XH"); + +// CHECK-LABEL: x_i16: +// CHECK: ;APP +// CHECK: movw r26, r26 +// CHECK: ;NO_APP +check_regw!(x_i16 i16 "X" "X"); + +// CHECK-LABEL: r25r24_i16: +// CHECK: ;APP +// CHECK: movw r24, r24 +// CHECK: ;NO_APP +check_regw!(r25r24_i16 i16 "r25r24" "r24"); diff --git a/src/test/assembly/asm/bpf-types.rs b/src/test/assembly/asm/bpf-types.rs new file mode 100644 index 000000000..3428d93fb --- /dev/null +++ b/src/test/assembly/asm/bpf-types.rs @@ -0,0 +1,154 @@ +// min-llvm-version: 13.0 +// assembly-output: emit-asm +// compile-flags: --target bpfel-unknown-none -C target_feature=+alu32 +// needs-llvm-components: bpf + +#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const u64; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for ptr {} + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("{} = {}", out($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +extern "C" { + fn extern_func(); +} + +// CHECK-LABEL: sym_fn +// CHECK: #APP +// CHECK: call extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16 i16 reg); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32 i32 reg); + +// CHECK-LABEL: reg_i64: +// CHECK: #APP +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i64 i64 reg); + +// CHECK-LABEL: wreg_i8: +// CHECK: #APP +// CHECK: w{{[0-9]+}} = w{{[0-9]+}} +// CHECK: #NO_APP +check!(wreg_i8 i8 wreg); + +// CHECK-LABEL: wreg_i16: +// CHECK: #APP +// CHECK: w{{[0-9]+}} = w{{[0-9]+}} +// CHECK: #NO_APP +check!(wreg_i16 i16 wreg); + +// CHECK-LABEL: wreg_i32: +// CHECK: #APP +// CHECK: w{{[0-9]+}} = w{{[0-9]+}} +// CHECK: #NO_APP +check!(wreg_i32 i32 wreg); + +// CHECK-LABEL: r0_i8: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i8 i8 "r0"); + +// CHECK-LABEL: r0_i16: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i16 i16 "r0"); + +// CHECK-LABEL: r0_i32: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i32 i32 "r0"); + +// CHECK-LABEL: r0_i64: +// CHECK: #APP +// CHECK: r0 = r0 +// CHECK: #NO_APP +check_reg!(r0_i64 i64 "r0"); + +// CHECK-LABEL: w0_i8: +// CHECK: #APP +// CHECK: w0 = w0 +// CHECK: #NO_APP +check_reg!(w0_i8 i8 "w0"); + +// CHECK-LABEL: w0_i16: +// CHECK: #APP +// CHECK: w0 = w0 +// CHECK: #NO_APP +check_reg!(w0_i16 i16 "w0"); + +// CHECK-LABEL: w0_i32: +// CHECK: #APP +// CHECK: w0 = w0 +// CHECK: #NO_APP +check_reg!(w0_i32 i32 "w0"); diff --git a/src/test/assembly/asm/global_asm.rs b/src/test/assembly/asm/global_asm.rs new file mode 100644 index 000000000..4cf73b40f --- /dev/null +++ b/src/test/assembly/asm/global_asm.rs @@ -0,0 +1,31 @@ +// only-x86_64 +// only-linux +// assembly-output: emit-asm +// compile-flags: -C llvm-args=--x86-asm-syntax=intel +// compile-flags: -C symbol-mangling-version=v0 + +#![feature(asm_const, asm_sym)] +#![crate_type = "rlib"] + +use std::arch::global_asm; + +#[no_mangle] +fn my_func() {} + +#[no_mangle] +static MY_STATIC: i32 = 0; + +// CHECK: mov eax, eax +global_asm!("mov eax, eax"); +// CHECK: mov ebx, 5 +global_asm!("mov ebx, {}", const 5); +// CHECK: mov ecx, 5 +global_asm!("movl ${}, %ecx", const 5, options(att_syntax)); +// CHECK: call my_func +global_asm!("call {}", sym my_func); +// CHECK: lea rax, [rip + MY_STATIC] +global_asm!("lea rax, [rip + {}]", sym MY_STATIC); +// CHECK: call _RNvCsiubXh4Yz005_10global_asm6foobar +global_asm!("call {}", sym foobar); +// CHECK: _RNvCsiubXh4Yz005_10global_asm6foobar: +fn foobar() { loop {} } diff --git a/src/test/assembly/asm/hexagon-types.rs b/src/test/assembly/asm/hexagon-types.rs new file mode 100644 index 000000000..eff9a0bb4 --- /dev/null +++ b/src/test/assembly/asm/hexagon-types.rs @@ -0,0 +1,181 @@ +// assembly-output: emit-asm +// compile-flags: --target hexagon-unknown-linux-musl +// needs-llvm-components: hexagon + +#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!("{} = {}", out($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($reg, " = ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +// CHECK-LABEL: sym_static: +// CHECK: InlineAsm Start +// CHECK: r0 = {{#+}}extern_static +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn sym_static() { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + asm!("r0 = #{}", sym extern_static); +} + +// CHECK-LABEL: sym_fn: +// CHECK: InlineAsm Start +// CHECK: r0 = {{#+}}extern_func +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn sym_fn() { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + asm!("r0 = #{}", sym extern_func); +} + +// This is a test for multi-instruction packets, +// which require the escaped braces. +// +// CHECK-LABEL: packet: +// CHECK: InlineAsm Start +// CHECK: { +// CHECK: r{{[0-9]+}} = r0 +// CHECK: memw(r1{{(\+#0)?}}) = r{{[0-9]+}} +// CHECK: } +// CHECK: InlineAsm End +#[no_mangle] +pub unsafe fn packet() { + let val = 1024; + asm!("{{ + {} = r0 + memw(r1) = {} + }}", out(reg) _, in(reg) &val); +} + +// CHECK-LABEL: reg_ptr: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_ptr ptr reg); + +// CHECK-LABEL: reg_f32: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_f32 f32 reg); + +// CHECK-LABEL: reg_i32: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i32 i32 reg); + +// CHECK-LABEL: reg_i8: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_i16: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}} = r{{[0-9]+}} +// CHECK: InlineAsm End +check!(reg_i16 i16 reg); + +// CHECK-LABEL: r0_ptr: +// CHECK: InlineAsm Start +// CHECK: r0 = r0 +// CHECK: InlineAsm End +check_reg!(r0_ptr ptr "r0"); + +// CHECK-LABEL: r0_f32: +// CHECK: InlineAsm Start +// CHECK: r0 = r0 +// CHECK: InlineAsm End +check_reg!(r0_f32 f32 "r0"); + +// CHECK-LABEL: r0_i32: +// CHECK: InlineAsm Start +// CHECK: r0 = r0 +// CHECK: InlineAsm End +check_reg!(r0_i32 i32 "r0"); + +// CHECK-LABEL: r0_i8: +// CHECK: InlineAsm Start +// CHECK: r0 = r0 +// CHECK: InlineAsm End +check_reg!(r0_i8 i8 "r0"); + +// CHECK-LABEL: r0_i16: +// CHECK: InlineAsm Start +// CHECK: r0 = r0 +// CHECK: InlineAsm End +check_reg!(r0_i16 i16 "r0"); diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs new file mode 100644 index 000000000..04bf49a40 --- /dev/null +++ b/src/test/assembly/asm/mips-types.rs @@ -0,0 +1,237 @@ +// revisions: mips32 mips64 +// assembly-output: emit-asm +//[mips32] compile-flags: --target mips-unknown-linux-gnu +//[mips32] needs-llvm-components: mips +//[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +//[mips64] needs-llvm-components: mips + +#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for u8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for f32 {} +impl Copy for f64 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// Hack to avoid function merging +extern "Rust" { + fn dont_merge(s: &str); +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } +};} + +// mips32-LABEL: sym_static_32: +// mips32: #APP +// mips32: lw $3, %got(extern_static) +// mips32: #NO_APP +#[cfg(mips32)] +#[no_mangle] +pub unsafe fn sym_static_32() { + asm!("lw $v1, {}", sym extern_static); +} + +// mips32-LABEL: sym_fn_32: +// mips32: #APP +// mips32: lw $3, %got(extern_func) +// mips32: #NO_APP +#[cfg(mips32)] +#[no_mangle] +pub unsafe fn sym_fn_32() { + asm!("lw $v1, {}", sym extern_func); +} + +// mips64-LABEL: sym_static_64: +// mips64: #APP +// mips64: ld $3, %got_disp(extern_static) +// mips64: #NO_APP +#[cfg(mips64)] +#[no_mangle] +pub unsafe fn sym_static_64() { + asm!("ld $v1, {}", sym extern_static); +} + +// mips64-LABEL: sym_fn_64: +// mips64: #APP +// mips64: ld $3, %got_disp(extern_func) +// mips64: #NO_APP +#[cfg(mips64)] +#[no_mangle] +pub unsafe fn sym_fn_64() { + asm!("ld $v1, {}", sym extern_func); +} + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32, f32, freg, "mov.s"); + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: mov.s $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +check_reg!(f0_f32, f32, "$f0", "mov.s"); + +// CHECK-LABEL: reg_f32_64: +// CHECK: #APP +// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32_64, f32, freg, "mov.d"); + +// CHECK-LABEL: f0_f32_64: +// CHECK: #APP +// CHECK: mov.d $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +check_reg!(f0_f32_64, f32, "$f0", "mov.d"); + +// CHECK-LABEL: reg_f64: +// CHECK: #APP +// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +#[no_mangle] +check!(reg_f64, f64, freg, "mov.d"); + +// CHECK-LABEL: f0_f64: +// CHECK: #APP +// CHECK: mov.d $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +check_reg!(f0_f64, f64, "$f0", "mov.d"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr, ptr, reg, "move"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg, "move"); + +// CHECK-LABEL: reg_f32_soft: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32_soft, f32, reg, "move"); + +// mips64-LABEL: reg_f64_soft: +// mips64: #APP +// mips64: move ${{[0-9]+}}, ${{[0-9]+}} +// mips64: #NO_APP +#[cfg(mips64)] +check!(reg_f64_soft, f64, reg, "move"); + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg, "move"); + +// CHECK-LABEL: reg_u8: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_u8, u8, reg, "move"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg, "move"); + +// mips64-LABEL: reg_i64: +// mips64: #APP +// mips64: move ${{[0-9]+}}, ${{[0-9]+}} +// mips64: #NO_APP +#[cfg(mips64)] +check!(reg_i64, i64, reg, "move"); + +// CHECK-LABEL: r8_ptr: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_ptr, ptr, "$8", "move"); + +// CHECK-LABEL: r8_i32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_i32, i32, "$8", "move"); + +// CHECK-LABEL: r8_f32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_f32, f32, "$8", "move"); + +// CHECK-LABEL: r8_i8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_i8, i8, "$8", "move"); + +// CHECK-LABEL: r8_u8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_u8, u8, "$8", "move"); + +// CHECK-LABEL: r8_i16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_i16, i16, "$8", "move"); diff --git a/src/test/assembly/asm/msp430-types.rs b/src/test/assembly/asm/msp430-types.rs new file mode 100644 index 000000000..6cfb86e27 --- /dev/null +++ b/src/test/assembly/asm/msp430-types.rs @@ -0,0 +1,158 @@ +// min-llvm-version: 13.0 +// assembly-output: emit-asm +// compile-flags: --target msp430-none-elf +// needs-llvm-components: msp430 + +#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch, asm_const)] +#![crate_type = "rlib"] +#![no_core] +#![allow(non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i16; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for ptr {} + +macro_rules! check { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("mov {}, {}", lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! checkb { + ($func:ident $ty:ident $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!("mov.b {}, {}", lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("mov ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +macro_rules! check_regb { + ($func:ident $ty:ident $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("mov.b ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +extern "C" { + fn extern_func(); + static extern_static: i8; +} + +// CHECK-LABEL: sym_fn +// CHECK: ;APP +// CHECK: call extern_func +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static +// CHECK: ;APP +// CHECK: mov.b extern_static, r{{[0-9]+}} +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn sym_static() -> i8 { + let y; + asm!("mov.b {1}, {0}", lateout(reg) y, sym extern_static); + y +} + +// CHECK-LABEL: add_const: +// CHECK: ;APP +// CHECK: add.b #5, r{{[0-9]+}} +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn add_const() -> i8 { + let y; + asm!("add.b #{number}, {}", out(reg) y, number = const 5); + y +} + +// CHECK-LABEL: mov_postincrement: +// CHECK: ;APP +// CHECK: mov @r5+, r{{[0-9]+}} +// CHECK: ;NO_APP +#[no_mangle] +pub unsafe fn mov_postincrement(mut x: *const i16) -> (i16, *const i16) { + let y; + asm!("mov @r5+, {0}", out(reg) y, inlateout("r5") x); + (y, x) +} + +// CHECK-LABEL: reg_i8: +// CHECK: ;APP +// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +check!(reg_i8 i8 reg); + +// CHECK-LABEL: reg_i16: +// CHECK: ;APP +// CHECK: mov r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +check!(reg_i16 i16 reg); + +// CHECK-LABEL: reg_i8b: +// CHECK: ;APP +// CHECK: mov.b r{{[0-9]+}}, r{{[0-9]+}} +// CHECK: ;NO_APP +checkb!(reg_i8b i8 reg); + +// CHECK-LABEL: r5_i8: +// CHECK: ;APP +// CHECK: mov r5, r5 +// CHECK: ;NO_APP +check_reg!(r5_i8 i8 "r5"); + +// CHECK-LABEL: r5_i16: +// CHECK: ;APP +// CHECK: mov r5, r5 +// CHECK: ;NO_APP +check_reg!(r5_i16 i16 "r5"); + +// CHECK-LABEL: r5_i8b: +// CHECK: ;APP +// CHECK: mov.b r5, r5 +// CHECK: ;NO_APP +check_regb!(r5_i8b i8 "r5"); diff --git a/src/test/assembly/asm/nvptx-types.rs b/src/test/assembly/asm/nvptx-types.rs new file mode 100644 index 000000000..3ebd5b4b8 --- /dev/null +++ b/src/test/assembly/asm/nvptx-types.rs @@ -0,0 +1,133 @@ +// assembly-output: emit-asm +// compile-flags: --target nvptx64-nvidia-cuda +// compile-flags: --crate-type cdylib +// needs-llvm-components: nvptx + +#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *mut u8; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for i64 {} +impl Copy for f64 {} +impl Copy for ptr {} + +// NVPTX does not support static variables +#[no_mangle] +fn extern_func() {} + +// CHECK-LABEL: .visible .func sym_fn() +// CHECK: // begin inline asm +// CHECK: call extern_func; +// CHECK: // end inline asm +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {};", sym extern_func); +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!($mov, " {}, {};"), out($class) y, in($class) x); + y + } + }; +} + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i8 +// CHECK: // begin inline asm +// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg16_i8 i8 reg16 "mov.i16"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg16_i16 +// CHECK: // begin inline asm +// CHECK: mov.i16 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg16_i16 i16 reg16 "mov.i16"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i8 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg32_i8 i8 reg32 "mov.i32"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i16 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg32_i16 i16 reg32 "mov.i32"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_i32 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg32_i32 i32 reg32 "mov.i32"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg32_f32 +// CHECK: // begin inline asm +// CHECK: mov.i32 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg32_f32 f32 reg32 "mov.i32"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i8 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_i8 i8 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i16 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_i16 i16 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_i32 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_i32 i32 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b32 func_retval0) reg64_f32 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_f32 f32 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_i64 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_i64 i64 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_f64 +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_f64 f64 reg64 "mov.i64"); + +// CHECK-LABEL: .visible .func (.param .b64 func_retval0) reg64_ptr +// CHECK: // begin inline asm +// CHECK: mov.i64 %{{[a-z0-9]+}}, %{{[a-z0-9]+}}; +// CHECK: // end inline asm +check!(reg64_ptr ptr reg64 "mov.i64"); diff --git a/src/test/assembly/asm/powerpc-types.rs b/src/test/assembly/asm/powerpc-types.rs new file mode 100644 index 000000000..b8859c07e --- /dev/null +++ b/src/test/assembly/asm/powerpc-types.rs @@ -0,0 +1,208 @@ +// min-llvm-version: 12.0.1 +// revisions: powerpc powerpc64 +// assembly-output: emit-asm +//[powerpc] compile-flags: --target powerpc-unknown-linux-gnu +//[powerpc] needs-llvm-components: powerpc +//[powerpc64] compile-flags: --target powerpc64-unknown-linux-gnu +//[powerpc64] needs-llvm-components: powerpc + +#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for u8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for f32 {} +impl Copy for f64 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// Hack to avoid function merging +extern "Rust" { + fn dont_merge(s: &str); +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $rego:tt, $regc:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " ", $rego, ", ", $rego), lateout($regc) y, in($regc) x); + y + } +};} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg, "mr"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg, "mr"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg, "mr"); + +// powerpc64-LABEL: reg_i64: +// powerpc64: #APP +// powerpc64: mr {{[0-9]+}}, {{[0-9]+}} +// powerpc64: #NO_APP +#[cfg(powerpc64)] +check!(reg_i64, i64, reg, "mr"); + +// CHECK-LABEL: reg_i8_nz: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8_nz, i8, reg_nonzero, "mr"); + +// CHECK-LABEL: reg_i16_nz: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16_nz, i16, reg_nonzero, "mr"); + +// CHECK-LABEL: reg_i32_nz: +// CHECK: #APP +// CHECK: mr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32_nz, i32, reg_nonzero, "mr"); + +// powerpc64-LABEL: reg_i64_nz: +// powerpc64: #APP +// powerpc64: mr {{[0-9]+}}, {{[0-9]+}} +// powerpc64: #NO_APP +#[cfg(powerpc64)] +check!(reg_i64_nz, i64, reg_nonzero, "mr"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: fmr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32, f32, freg, "fmr"); + +// CHECK-LABEL: reg_f64: +// CHECK: #APP +// CHECK: fmr {{[0-9]+}}, {{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f64, f64, freg, "fmr"); + +// CHECK-LABEL: reg_i8_r0: +// CHECK: #APP +// CHECK: mr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_i8_r0, i8, "0", "0", "mr"); + +// CHECK-LABEL: reg_i16_r0: +// CHECK: #APP +// CHECK: mr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_i16_r0, i16, "0", "0", "mr"); + +// CHECK-LABEL: reg_i32_r0: +// CHECK: #APP +// CHECK: mr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_i32_r0, i32, "0", "0", "mr"); + +// powerpc64-LABEL: reg_i64_r0: +// powerpc64: #APP +// powerpc64: mr 0, 0 +// powerpc64: #NO_APP +#[cfg(powerpc64)] +check_reg!(reg_i64_r0, i64, "0", "0", "mr"); + +// CHECK-LABEL: reg_i8_r18: +// CHECK: #APP +// CHECK: mr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_i8_r18, i8, "18", "18", "mr"); + +// CHECK-LABEL: reg_i16_r18: +// CHECK: #APP +// CHECK: mr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_i16_r18, i16, "18", "18", "mr"); + +// CHECK-LABEL: reg_i32_r18: +// CHECK: #APP +// CHECK: mr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_i32_r18, i32, "18", "18", "mr"); + +// powerpc64-LABEL: reg_i64_r18: +// powerpc64: #APP +// powerpc64: mr 18, 18 +// powerpc64: #NO_APP +#[cfg(powerpc64)] +check_reg!(reg_i64_r18, i64, "18", "18", "mr"); + +// CHECK-LABEL: reg_f32_f0: +// CHECK: #APP +// CHECK: fmr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_f32_f0, f32, "0", "f0", "fmr"); + +// CHECK-LABEL: reg_f64_f0: +// CHECK: #APP +// CHECK: fmr 0, 0 +// CHECK: #NO_APP +check_reg!(reg_f64_f0, f64, "0", "f0", "fmr"); + +// CHECK-LABEL: reg_f32_f18: +// CHECK: #APP +// CHECK: fmr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_f32_f18, f32, "18", "f18", "fmr"); + +// CHECK-LABEL: reg_f64_f18: +// CHECK: #APP +// CHECK: fmr 18, 18 +// CHECK: #NO_APP +check_reg!(reg_f64_f18, f64, "18", "f18", "fmr"); diff --git a/src/test/assembly/asm/riscv-types.rs b/src/test/assembly/asm/riscv-types.rs new file mode 100644 index 000000000..68dc186ea --- /dev/null +++ b/src/test/assembly/asm/riscv-types.rs @@ -0,0 +1,210 @@ +// revisions: riscv64 riscv32 +// assembly-output: emit-asm +//[riscv64] compile-flags: --target riscv64imac-unknown-none-elf +//[riscv64] needs-llvm-components: riscv +//[riscv32] compile-flags: --target riscv32imac-unknown-none-elf +//[riscv32] needs-llvm-components: riscv +// compile-flags: -C target-feature=+d + +#![feature(no_core, lang_items, rustc_attrs, asm_sym)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *mut u8; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for i64 {} +impl Copy for f64 {} +impl Copy for ptr {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: call extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: auipc t0, %pcrel_hi(extern_static) +// CHECK: lb t0, %pcrel_lo(.Lpcrel_hi{{[0-9]+}})(t0) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("lb t0, {}", sym extern_static); +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " {}, {}"), out($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i8 i8 reg "mv"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i16 i16 reg "mv"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i32 i32 reg "mv"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f32 f32 reg "mv"); + +// riscv64-LABEL: reg_i64: +// riscv64: #APP +// riscv64: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// riscv64: #NO_APP +#[cfg(riscv64)] +check!(reg_i64 i64 reg "mv"); + +// riscv64-LABEL: reg_f64: +// riscv64: #APP +// riscv64: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// riscv64: #NO_APP +#[cfg(riscv64)] +check!(reg_f64 f64 reg "mv"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: mv {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr ptr reg "mv"); + +// CHECK-LABEL: freg_f32: +// CHECK: #APP +// CHECK: fmv.s f{{[a-z0-9]+}}, f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f32 f32 freg "fmv.s"); + +// CHECK-LABEL: freg_f64: +// CHECK: #APP +// CHECK: fmv.d f{{[a-z0-9]+}}, f{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(freg_f64 f64 freg "fmv.d"); + +// CHECK-LABEL: a0_i8: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_i8 i8 "a0" "mv"); + +// CHECK-LABEL: a0_i16: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_i16 i16 "a0" "mv"); + +// CHECK-LABEL: a0_i32: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_i32 i32 "a0" "mv"); + +// CHECK-LABEL: a0_f32: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_f32 f32 "a0" "mv"); + +// riscv64-LABEL: a0_i64: +// riscv64: #APP +// riscv64: mv a0, a0 +// riscv64: #NO_APP +#[cfg(riscv64)] +check_reg!(a0_i64 i64 "a0" "mv"); + +// riscv64-LABEL: a0_f64: +// riscv64: #APP +// riscv64: mv a0, a0 +// riscv64: #NO_APP +#[cfg(riscv64)] +check_reg!(a0_f64 f64 "a0" "mv"); + +// CHECK-LABEL: a0_ptr: +// CHECK: #APP +// CHECK: mv a0, a0 +// CHECK: #NO_APP +check_reg!(a0_ptr ptr "a0" "mv"); + +// CHECK-LABEL: fa0_f32: +// CHECK: #APP +// CHECK: fmv.s fa0, fa0 +// CHECK: #NO_APP +check_reg!(fa0_f32 f32 "fa0" "fmv.s"); + +// CHECK-LABEL: fa0_f64: +// CHECK: #APP +// CHECK: fmv.d fa0, fa0 +// CHECK: #NO_APP +check_reg!(fa0_f64 f64 "fa0" "fmv.d"); diff --git a/src/test/assembly/asm/s390x-types.rs b/src/test/assembly/asm/s390x-types.rs new file mode 100644 index 000000000..6a12902a0 --- /dev/null +++ b/src/test/assembly/asm/s390x-types.rs @@ -0,0 +1,167 @@ +// revisions: s390x +// assembly-output: emit-asm +//[s390x] compile-flags: --target s390x-unknown-linux-gnu +//[s390x] needs-llvm-components: systemz + +#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for u8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for i64 {} +impl Copy for f32 {} +impl Copy for f64 {} +impl Copy for ptr {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// Hack to avoid function merging +extern "Rust" { + fn dont_merge(s: &str); +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " %", $reg, ", %", $reg), lateout($reg) y, in($reg) x); + y + } +};} + +// CHECK-LABEL: sym_fn_32: +// CHECK: #APP +// CHECK: brasl %r14, extern_func +// CHECK: #NO_APP +#[cfg(s390x)] +#[no_mangle] +pub unsafe fn sym_fn_32() { + asm!("brasl %r14, {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: brasl %r14, extern_static +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("brasl %r14, {}", sym extern_static); +} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg, "lgr"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg, "lgr"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg, "lgr"); + +// CHECK-LABEL: reg_i64: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i64, i64, reg, "lgr"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: ler %f{{[0-9]+}}, %f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32, f32, freg, "ler"); + +// CHECK-LABEL: reg_f64: +// CHECK: #APP +// CHECK: ldr %f{{[0-9]+}}, %f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f64, f64, freg, "ldr"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: lgr %r{{[0-9]+}}, %r{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr, ptr, reg, "lgr"); + +// CHECK-LABEL: r0_i8: +// CHECK: #APP +// CHECK: lr %r0, %r0 +// CHECK: #NO_APP +check_reg!(r0_i8, i8, "r0", "lr"); + +// CHECK-LABEL: r0_i16: +// CHECK: #APP +// CHECK: lr %r0, %r0 +// CHECK: #NO_APP +check_reg!(r0_i16, i16, "r0", "lr"); + +// CHECK-LABEL: r0_i32: +// CHECK: #APP +// CHECK: lr %r0, %r0 +// CHECK: #NO_APP +check_reg!(r0_i32, i32, "r0", "lr"); + +// CHECK-LABEL: r0_i64: +// CHECK: #APP +// CHECK: lr %r0, %r0 +// CHECK: #NO_APP +check_reg!(r0_i64, i64, "r0", "lr"); + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: ler %f0, %f0 +// CHECK: #NO_APP +check_reg!(f0_f32, f32, "f0", "ler"); + +// CHECK-LABEL: f0_f64: +// CHECK: #APP +// CHECK: ldr %f0, %f0 +// CHECK: #NO_APP +check_reg!(f0_f64, f64, "f0", "ldr"); diff --git a/src/test/assembly/asm/wasm-types.rs b/src/test/assembly/asm/wasm-types.rs new file mode 100644 index 000000000..3aa128c46 --- /dev/null +++ b/src/test/assembly/asm/wasm-types.rs @@ -0,0 +1,149 @@ +// assembly-output: emit-asm +// compile-flags: --target wasm32-unknown-unknown +// compile-flags: --crate-type cdylib +// needs-llvm-components: webassembly + +#![feature(no_core, lang_items, rustc_attrs, asm_sym, asm_experimental_arch)] +#![no_core] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *mut u8; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for i64 {} +impl Copy for f64 {} +impl Copy for ptr {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: call extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static +// CHECK: #APP +// CHECK: i32.const 42 +// CHECK: i32.store extern_static +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!(" + i32.const 42 + i32.store {} + ", sym extern_static); +} + +macro_rules! check { + ($func:ident $ty:ident $instr:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + let y; + asm!(concat!("local.get {}\n", $instr, "\nlocal.set {}"), in(local) x, out(local) y); + y + } + }; +} + +// CHECK-LABEL: i8_i32: +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i32.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i8_i32 i8 "i32.clz"); + +// CHECK-LABEL: i16_i32: +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i32.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i16_i32 i16 "i32.clz"); + +// CHECK-LABEL: i32_i32: +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i32.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i32_i32 i32 "i32.clz"); + +// CHECK-LABEL: i8_i64 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i64.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i8_i64 i8 "i64.clz"); + +// CHECK-LABEL: i16_i64 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i64.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i16_i64 i16 "i64.clz"); + +// CHECK-LABEL: i32_i64 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i64.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i32_i64 i32 "i64.clz"); + +// CHECK-LABEL: i64_i64 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i64.clz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i64_i64 i64 "i64.clz"); + +// CHECK-LABEL: f32_f32 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: f32.abs +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(f32_f32 f32 "f32.abs"); + +// CHECK-LABEL: f64_f64 +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: f64.abs +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(f64_f64 f64 "f64.abs"); + +// CHECK-LABEL: i32_ptr +// CHECK: #APP +// CHECK: local.get {{[0-9]}} +// CHECK: i32.eqz +// CHECK: local.set {{[0-9]}} +// CHECK: #NO_APP +check!(i32_ptr ptr "i32.eqz"); diff --git a/src/test/assembly/asm/x86-modifiers.rs b/src/test/assembly/asm/x86-modifiers.rs new file mode 100644 index 000000000..574fdf12c --- /dev/null +++ b/src/test/assembly/asm/x86-modifiers.rs @@ -0,0 +1,205 @@ +// revisions: x86_64 i686 +// assembly-output: emit-asm +// compile-flags: -O +//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//[x86_64] needs-llvm-components: x86 +//[i686] compile-flags: --target i686-unknown-linux-gnu +//[i686] needs-llvm-components: x86 +// compile-flags: -C llvm-args=--x86-asm-syntax=intel +// compile-flags: -C target-feature=+avx512bw + +#![feature(no_core, lang_items, rustc_attrs)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +impl Copy for i32 {} + +macro_rules! check { + ($func:ident $modifier:literal $reg:ident $mov:literal) => { + // -O and extern "C" guarantee that the selected register is always ax/xmm0 + #[no_mangle] + pub unsafe extern "C" fn $func() -> i32 { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " {0:", $modifier, "}, {0:", $modifier, "}"), out($reg) y); + y + } + }; +} + +// CHECK-LABEL: reg: +// CHECK: #APP +// x86_64: mov rax, rax +// i686: mov eax, eax +// CHECK: #NO_APP +check!(reg "" reg "mov"); + +// x86_64-LABEL: reg_l: +// x86_64: #APP +// x86_64: mov al, al +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_l "l" reg "mov"); + +// CHECK-LABEL: reg_x: +// CHECK: #APP +// CHECK: mov ax, ax +// CHECK: #NO_APP +check!(reg_x "x" reg "mov"); + +// CHECK-LABEL: reg_e: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check!(reg_e "e" reg "mov"); + +// x86_64-LABEL: reg_r: +// x86_64: #APP +// x86_64: mov rax, rax +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_r "r" reg "mov"); + +// CHECK-LABEL: reg_abcd: +// CHECK: #APP +// x86_64: mov rax, rax +// i686: mov eax, eax +// CHECK: #NO_APP +check!(reg_abcd "" reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_l: +// CHECK: #APP +// CHECK: mov al, al +// CHECK: #NO_APP +check!(reg_abcd_l "l" reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_h: +// CHECK: #APP +// CHECK: mov ah, ah +// CHECK: #NO_APP +check!(reg_abcd_h "h" reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_x: +// CHECK: #APP +// CHECK: mov ax, ax +// CHECK: #NO_APP +check!(reg_abcd_x "x" reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_e: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check!(reg_abcd_e "e" reg_abcd "mov"); + +// x86_64-LABEL: reg_abcd_r: +// x86_64: #APP +// x86_64: mov rax, rax +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_abcd_r "r" reg_abcd "mov"); + +// CHECK-LABEL: xmm_reg +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check!(xmm_reg "" xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_x +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check!(xmm_reg_x "x" xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_y +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check!(xmm_reg_y "y" xmm_reg "vmovaps"); + +// CHECK-LABEL: xmm_reg_z +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check!(xmm_reg_z "z" xmm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg +// CHECK: #APP +// CHECK: movaps ymm0, ymm0 +// CHECK: #NO_APP +check!(ymm_reg "" ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_x +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check!(ymm_reg_x "x" ymm_reg "movaps"); + +// CHECK-LABEL: ymm_reg_y +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check!(ymm_reg_y "y" ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_z +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check!(ymm_reg_z "z" ymm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg +// CHECK: #APP +// CHECK: movaps zmm0, zmm0 +// CHECK: #NO_APP +check!(zmm_reg "" zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_x +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check!(zmm_reg_x "x" zmm_reg "movaps"); + +// CHECK-LABEL: zmm_reg_y +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check!(zmm_reg_y "y" zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_z +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check!(zmm_reg_z "z" zmm_reg "vmovaps"); + +// Note: we don't have any way of ensuring that k1 is actually the register +// chosen by the register allocator, so this check may fail if a different +// register is chosen. + +// CHECK-LABEL: kreg: +// CHECK: #APP +// CHECK: kmovb k1, k1 +// CHECK: #NO_APP +check!(kreg "" kreg "kmovb"); diff --git a/src/test/assembly/asm/x86-types.rs b/src/test/assembly/asm/x86-types.rs new file mode 100644 index 000000000..e871535cf --- /dev/null +++ b/src/test/assembly/asm/x86-types.rs @@ -0,0 +1,1093 @@ +// revisions: x86_64 i686 +// assembly-output: emit-asm +//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//[x86_64] needs-llvm-components: x86 +//[i686] compile-flags: --target i686-unknown-linux-gnu +//[i686] needs-llvm-components: x86 +// compile-flags: -C llvm-args=--x86-asm-syntax=intel +// compile-flags: -C target-feature=+avx512bw + +#![feature(no_core, lang_items, rustc_attrs, repr_simd, asm_sym)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *mut u8; + +#[repr(simd)] +pub struct i8x16(i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8, i8); +#[repr(simd)] +pub struct i16x8(i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] +pub struct i32x4(i32, i32, i32, i32); +#[repr(simd)] +pub struct i64x2(i64, i64); +#[repr(simd)] +pub struct f32x4(f32, f32, f32, f32); +#[repr(simd)] +pub struct f64x2(f64, f64); + +#[repr(simd)] +pub struct i8x32( + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, +); +#[repr(simd)] +pub struct i16x16(i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16, i16); +#[repr(simd)] +pub struct i32x8(i32, i32, i32, i32, i32, i32, i32, i32); +#[repr(simd)] +pub struct i64x4(i64, i64, i64, i64); +#[repr(simd)] +pub struct f32x8(f32, f32, f32, f32, f32, f32, f32, f32); +#[repr(simd)] +pub struct f64x4(f64, f64, f64, f64); + +#[repr(simd)] +pub struct i8x64( + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, +); +#[repr(simd)] +pub struct i16x32( + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, +); +#[repr(simd)] +pub struct i32x16(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32, i32); +#[repr(simd)] +pub struct i64x8(i64, i64, i64, i64, i64, i64, i64, i64); +#[repr(simd)] +pub struct f32x16(f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32, f32); +#[repr(simd)] +pub struct f64x8(f64, f64, f64, f64, f64, f64, f64, f64); + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for i64 {} +impl Copy for f64 {} +impl Copy for ptr {} +impl Copy for i8x16 {} +impl Copy for i16x8 {} +impl Copy for i32x4 {} +impl Copy for i64x2 {} +impl Copy for f32x4 {} +impl Copy for f64x2 {} +impl Copy for i8x32 {} +impl Copy for i16x16 {} +impl Copy for i32x8 {} +impl Copy for i64x4 {} +impl Copy for f32x8 {} +impl Copy for f64x4 {} +impl Copy for i8x64 {} +impl Copy for i16x32 {} +impl Copy for i32x16 {} +impl Copy for i64x8 {} +impl Copy for f32x16 {} +impl Copy for f64x8 {} + +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: call extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call {}", sym extern_func); +} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: mov al, byte ptr [extern_static] +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + asm!("mov al, byte ptr [{}]", sym extern_static); +} + +macro_rules! check { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " {}, {}"), lateout($class) y, in($class) x); + y + } + }; +} + +macro_rules! check_reg { + ($func:ident $ty:ident $reg:tt $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + // Hack to avoid function merging + extern "Rust" { + fn dont_merge(s: &str); + } + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i16 i16 reg "mov"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_i32 i32 reg "mov"); + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_f32 f32 reg "mov"); + +// x86_64-LABEL: reg_i64: +// x86_64: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_i64 i64 reg "mov"); + +// x86_64-LABEL: reg_f64: +// x86_64: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_f64 f64 reg "mov"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr ptr reg "mov"); + +// CHECK-LABEL: reg_abcd_i16: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_i16 i16 reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_i32: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_i32 i32 reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_f32: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_f32 f32 reg_abcd "mov"); + +// x86_64-LABEL: reg_abcd_i64: +// x86_64: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_abcd_i64 i64 reg_abcd "mov"); + +// x86_64-LABEL: reg_abcd_f64: +// x86_64: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_abcd_f64 f64 reg_abcd "mov"); + +// CHECK-LABEL: reg_abcd_ptr: +// CHECK: #APP +// x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} +// i686: mov e{{[a-z0-9]+}}, e{{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_abcd_ptr ptr reg_abcd "mov"); + +// CHECK-LABEL: reg_byte: +// CHECK: #APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: #NO_APP +check!(reg_byte i8 reg_byte "mov"); + +// CHECK-LABEL: xmm_reg_i32: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i32 i32 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_f32: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f32 f32 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i64: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i64 i64 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_f64: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f64 f64 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_ptr: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_ptr ptr xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i8x16: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i8x16 i8x16 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i16x8: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i16x8 i16x8 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i32x4: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i32x4 i32x4 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_i64x2: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_i64x2 i64x2 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_f32x4: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f32x4 f32x4 xmm_reg "movaps"); + +// CHECK-LABEL: xmm_reg_f64x2: +// CHECK: #APP +// CHECK: movaps xmm{{[0-9]+}}, xmm{{[0-9]+}} +// CHECK: #NO_APP +check!(xmm_reg_f64x2 f64x2 xmm_reg "movaps"); + +// CHECK-LABEL: ymm_reg_i32: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i32 i32 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f32: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f32 f32 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i64: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i64 i64 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f64: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f64 f64 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_ptr: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_ptr ptr ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i8x16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i8x16 i8x16 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i16x8: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i16x8 i16x8 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i32x4: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i32x4 i32x4 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i64x2: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i64x2 i64x2 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f32x4: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f32x4 f32x4 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f64x2: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f64x2 f64x2 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i8x32: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i8x32 i8x32 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i16x16: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i16x16 i16x16 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i32x8: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i32x8 i32x8 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_i64x4: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_i64x4 i64x4 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f32x8: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f32x8 f32x8 ymm_reg "vmovaps"); + +// CHECK-LABEL: ymm_reg_f64x4: +// CHECK: #APP +// CHECK: vmovaps ymm{{[0-9]+}}, ymm{{[0-9]+}} +// CHECK: #NO_APP +check!(ymm_reg_f64x4 f64x4 ymm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i32 i32 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f32 f32 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i64: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i64 i64 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f64: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f64 f64 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_ptr: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_ptr ptr zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i8x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i8x16 i8x16 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i16x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i16x8 i16x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i32x4: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i32x4 i32x4 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i64x2: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i64x2 i64x2 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f32x4: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f32x4 f32x4 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f64x2: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f64x2 f64x2 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i8x32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i8x32 i8x32 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i16x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i16x16 i16x16 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i32x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i32x8 i32x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i64x4: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i64x4 i64x4 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f32x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f32x8 f32x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f64x4: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f64x4 f64x4 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i8x64: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i8x64 i8x64 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i16x32: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i16x32 i16x32 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i32x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i32x16 i32x16 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_i64x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_i64x8 i64x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f32x16: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f32x16 f32x16 zmm_reg "vmovaps"); + +// CHECK-LABEL: zmm_reg_f64x8: +// CHECK: #APP +// CHECK: vmovaps zmm{{[0-9]+}}, zmm{{[0-9]+}} +// CHECK: #NO_APP +check!(zmm_reg_f64x8 f64x8 zmm_reg "vmovaps"); + +// CHECK-LABEL: kreg_i8: +// CHECK: #APP +// CHECK: kmovb k{{[0-9]+}}, k{{[0-9]+}} +// CHECK: #NO_APP +check!(kreg_i8 i8 kreg "kmovb"); + +// CHECK-LABEL: kreg_i16: +// CHECK: #APP +// CHECK: kmovw k{{[0-9]+}}, k{{[0-9]+}} +// CHECK: #NO_APP +check!(kreg_i16 i16 kreg "kmovw"); + +// CHECK-LABEL: kreg_i32: +// CHECK: #APP +// CHECK: kmovd k{{[0-9]+}}, k{{[0-9]+}} +// CHECK: #NO_APP +check!(kreg_i32 i32 kreg "kmovd"); + +// CHECK-LABEL: kreg_i64: +// CHECK: #APP +// CHECK: kmovq k{{[0-9]+}}, k{{[0-9]+}} +// CHECK: #NO_APP +check!(kreg_i64 i64 kreg "kmovq"); + +// CHECK-LABEL: kreg_ptr: +// CHECK: #APP +// CHECK: kmovq k{{[0-9]+}}, k{{[0-9]+}} +// CHECK: #NO_APP +check!(kreg_ptr ptr kreg "kmovq"); + +// CHECK-LABEL: eax_i16: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_i16 i16 "eax" "mov"); + +// CHECK-LABEL: eax_i32: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_i32 i32 "eax" "mov"); + +// CHECK-LABEL: eax_f32: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_f32 f32 "eax" "mov"); + +// x86_64-LABEL: eax_i64: +// x86_64: #APP +// x86_64: mov eax, eax +// x86_64: #NO_APP +#[cfg(x86_64)] +check_reg!(eax_i64 i64 "eax" "mov"); + +// x86_64-LABEL: eax_f64: +// x86_64: #APP +// x86_64: mov eax, eax +// x86_64: #NO_APP +#[cfg(x86_64)] +check_reg!(eax_f64 f64 "eax" "mov"); + +// CHECK-LABEL: eax_ptr: +// CHECK: #APP +// CHECK: mov eax, eax +// CHECK: #NO_APP +check_reg!(eax_ptr ptr "eax" "mov"); + +// i686-LABEL: ah_byte: +// i686: #APP +// i686: mov ah, ah +// i686: #NO_APP +#[cfg(i686)] +check_reg!(ah_byte i8 "ah" "mov"); + +// CHECK-LABEL: xmm0_i32: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i32 i32 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_f32: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f32 f32 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i64: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i64 i64 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_f64: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f64 f64 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_ptr: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_ptr ptr "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i8x16: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i8x16 i8x16 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i16x8: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i16x8 i16x8 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i32x4: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i32x4 i32x4 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_i64x2: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_i64x2 i64x2 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_f32x4: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f32x4 f32x4 "xmm0" "movaps"); + +// CHECK-LABEL: xmm0_f64x2: +// CHECK: #APP +// CHECK: movaps xmm0, xmm0 +// CHECK: #NO_APP +check_reg!(xmm0_f64x2 f64x2 "xmm0" "movaps"); + +// CHECK-LABEL: ymm0_i32: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i32 i32 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f32: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f32 f32 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i64: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i64 i64 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f64: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f64 f64 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_ptr: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_ptr ptr "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i8x16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i8x16 i8x16 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i16x8: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i16x8 i16x8 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i32x4: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i32x4 i32x4 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i64x2: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i64x2 i64x2 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f32x4: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f32x4 f32x4 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f64x2: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f64x2 f64x2 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i8x32: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i8x32 i8x32 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i16x16: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i16x16 i16x16 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i32x8: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i32x8 i32x8 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_i64x4: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_i64x4 i64x4 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f32x8: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f32x8 f32x8 "ymm0" "vmovaps"); + +// CHECK-LABEL: ymm0_f64x4: +// CHECK: #APP +// CHECK: vmovaps ymm0, ymm0 +// CHECK: #NO_APP +check_reg!(ymm0_f64x4 f64x4 "ymm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i32 i32 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f32 f32 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i64: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i64 i64 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f64: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f64 f64 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_ptr: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_ptr ptr "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i8x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i8x16 i8x16 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i16x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i16x8 i16x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i32x4: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i32x4 i32x4 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i64x2: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i64x2 i64x2 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f32x4: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f32x4 f32x4 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f64x2: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f64x2 f64x2 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i8x32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i8x32 i8x32 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i16x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i16x16 i16x16 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i32x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i32x8 i32x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i64x4: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i64x4 i64x4 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f32x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f32x8 f32x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f64x4: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f64x4 f64x4 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i8x64: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i8x64 i8x64 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i16x32: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i16x32 i16x32 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i32x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i32x16 i32x16 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_i64x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_i64x8 i64x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f32x16: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f32x16 f32x16 "zmm0" "vmovaps"); + +// CHECK-LABEL: zmm0_f64x8: +// CHECK: #APP +// CHECK: vmovaps zmm0, zmm0 +// CHECK: #NO_APP +check_reg!(zmm0_f64x8 f64x8 "zmm0" "vmovaps"); + +// CHECK-LABEL: k1_i8: +// CHECK: #APP +// CHECK: kmovb k1, k1 +// CHECK: #NO_APP +check_reg!(k1_i8 i8 "k1" "kmovb"); + +// CHECK-LABEL: k1_i16: +// CHECK: #APP +// CHECK: kmovw k1, k1 +// CHECK: #NO_APP +check_reg!(k1_i16 i16 "k1" "kmovw"); + +// CHECK-LABEL: k1_i32: +// CHECK: #APP +// CHECK: kmovd k1, k1 +// CHECK: #NO_APP +check_reg!(k1_i32 i32 "k1" "kmovd"); + +// CHECK-LABEL: k1_i64: +// CHECK: #APP +// CHECK: kmovq k1, k1 +// CHECK: #NO_APP +check_reg!(k1_i64 i64 "k1" "kmovq"); + +// CHECK-LABEL: k1_ptr: +// CHECK: #APP +// CHECK: kmovq k1, k1 +// CHECK: #NO_APP +check_reg!(k1_ptr ptr "k1" "kmovq"); diff --git a/src/test/assembly/auxiliary/breakpoint-panic-handler.rs b/src/test/assembly/auxiliary/breakpoint-panic-handler.rs new file mode 100644 index 000000000..d54c1181e --- /dev/null +++ b/src/test/assembly/auxiliary/breakpoint-panic-handler.rs @@ -0,0 +1,8 @@ +#![feature(core_intrinsics)] +#![no_std] + +#[panic_handler] +unsafe fn breakpoint_panic_handler(_: &::core::panic::PanicInfo) -> ! { + core::intrinsics::breakpoint(); + core::hint::unreachable_unchecked(); +} diff --git a/src/test/assembly/auxiliary/non-inline-dependency.rs b/src/test/assembly/auxiliary/non-inline-dependency.rs new file mode 100644 index 000000000..57f3ee87c --- /dev/null +++ b/src/test/assembly/auxiliary/non-inline-dependency.rs @@ -0,0 +1,14 @@ +#![no_std] +#![deny(warnings)] + +#[inline(never)] +#[no_mangle] +pub fn wrapping_external_fn(a: u32) -> u32 { + a.wrapping_mul(a) +} + +#[inline(never)] +#[no_mangle] +pub fn panicking_external_fn(a: u32) -> u32 { + a * a +} diff --git a/src/test/assembly/dwarf5.rs b/src/test/assembly/dwarf5.rs new file mode 100644 index 000000000..f41e6bd55 --- /dev/null +++ b/src/test/assembly/dwarf5.rs @@ -0,0 +1,20 @@ +// Makes sure that `-Z dwarf-version=5` causes `rustc` to emit DWARF version 5. +// assembly-output: emit-asm +// compile-flags: -g --target x86_64-unknown-linux-gnu -Z dwarf-version=5 +// needs-llvm-components: x86 + +#![feature(no_core, lang_items)] +#![crate_type = "rlib"] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +pub fn wibble() {} + +// CHECK: .section .debug_info +// CHECK-NOT: .short 2 +// CHECK-NOT: .short 4 +// CHECK: .short 5 diff --git a/src/test/assembly/niche-prefer-zero.rs b/src/test/assembly/niche-prefer-zero.rs new file mode 100644 index 000000000..0ab37a618 --- /dev/null +++ b/src/test/assembly/niche-prefer-zero.rs @@ -0,0 +1,25 @@ +// Check that niche selection prefers zero and that jumps are optimized away. +// See https://github.com/rust-lang/rust/pull/87794 +// assembly-output: emit-asm +// only-x86 +// compile-flags: -Copt-level=3 + +#![crate_type = "lib"] + +#[repr(u8)] +pub enum Size { + One = 1, + Two = 2, + Three = 3, +} + +#[no_mangle] +pub fn handle(x: Option<Size>) -> u8 { + match x { + None => 0, + Some(size) => size as u8, + } +} + +// There should be no jumps in output +// CHECK-NOT: j diff --git a/src/test/assembly/nvptx-arch-default.rs b/src/test/assembly/nvptx-arch-default.rs new file mode 100644 index 000000000..8a71a6370 --- /dev/null +++ b/src/test/assembly/nvptx-arch-default.rs @@ -0,0 +1,13 @@ +// assembly-output: ptx-linker +// compile-flags: --crate-type cdylib +// only-nvptx64 +// ignore-nvptx64 + +#![no_std] + +// aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// Verify default target arch with ptx-linker. +// CHECK: .target sm_30 +// CHECK: .address_size 64 diff --git a/src/test/assembly/nvptx-arch-emit-asm.rs b/src/test/assembly/nvptx-arch-emit-asm.rs new file mode 100644 index 000000000..b252b450f --- /dev/null +++ b/src/test/assembly/nvptx-arch-emit-asm.rs @@ -0,0 +1,10 @@ +// assembly-output: emit-asm +// compile-flags: --crate-type rlib +// only-nvptx64 +// ignore-nvptx64 + +#![no_std] + +// Verify default arch without ptx-linker involved. +// CHECK: .target sm_30 +// CHECK: .address_size 64 diff --git a/src/test/assembly/nvptx-arch-link-arg.rs b/src/test/assembly/nvptx-arch-link-arg.rs new file mode 100644 index 000000000..025a9ad49 --- /dev/null +++ b/src/test/assembly/nvptx-arch-link-arg.rs @@ -0,0 +1,13 @@ +// assembly-output: ptx-linker +// compile-flags: --crate-type cdylib -C link-arg=--arch=sm_60 +// only-nvptx64 +// ignore-nvptx64 + +#![no_std] + +// aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// Verify target arch override via `link-arg`. +// CHECK: .target sm_60 +// CHECK: .address_size 64 diff --git a/src/test/assembly/nvptx-arch-target-cpu.rs b/src/test/assembly/nvptx-arch-target-cpu.rs new file mode 100644 index 000000000..824ee9cd8 --- /dev/null +++ b/src/test/assembly/nvptx-arch-target-cpu.rs @@ -0,0 +1,13 @@ +// assembly-output: ptx-linker +// compile-flags: --crate-type cdylib -C target-cpu=sm_50 +// only-nvptx64 +// ignore-nvptx64 + +#![no_std] + +// aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// Verify target arch override via `target-cpu`. +// CHECK: .target sm_50 +// CHECK: .address_size 64 diff --git a/src/test/assembly/nvptx-atomics.rs b/src/test/assembly/nvptx-atomics.rs new file mode 100644 index 000000000..f96398064 --- /dev/null +++ b/src/test/assembly/nvptx-atomics.rs @@ -0,0 +1,86 @@ +// assembly-output: ptx-linker +// compile-flags: --crate-type cdylib +// only-nvptx64 +// ignore-nvptx64 + +#![feature(abi_ptx, core_intrinsics)] +#![no_std] + +use core::intrinsics::*; + +// aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// Currently, LLVM NVPTX backend can only emit atomic instructions with +// `relaxed` (PTX default) ordering. But it's also useful to make sure +// the backend won't fail with other orders. Apparently, the backend +// doesn't support fences as well. As a workaround `llvm.nvvm.membar.*` +// could work, and perhaps on the long run, all the atomic operations +// should rather be provided by `core::arch::nvptx`. + +// Also, PTX ISA doesn't have atomic `load`, `store` and `nand`. + +// FIXME(denzp): add tests for `core::sync::atomic::*`. + +#[no_mangle] +pub unsafe extern "ptx-kernel" fn atomics_kernel(a: *mut u32) { + // CHECK: atom.global.and.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.and.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_and(a, 1); + atomic_and_relaxed(a, 1); + + // CHECK: atom.global.cas.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1, 2; + // CHECK: atom.global.cas.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1, 2; + atomic_cxchg(a, 1, 2); + atomic_cxchg_relaxed(a, 1, 2); + + // CHECK: atom.global.max.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.max.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_max(a, 1); + atomic_max_relaxed(a, 1); + + // CHECK: atom.global.min.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.min.s32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_min(a, 1); + atomic_min_relaxed(a, 1); + + // CHECK: atom.global.or.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.or.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_or(a, 1); + atomic_or_relaxed(a, 1); + + // CHECK: atom.global.max.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.max.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_umax(a, 1); + atomic_umax_relaxed(a, 1); + + // CHECK: atom.global.min.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.min.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_umin(a, 1); + atomic_umin_relaxed(a, 1); + + // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_xadd(a, 1); + atomic_xadd_relaxed(a, 1); + + // CHECK: atom.global.exch.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.exch.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_xchg(a, 1); + atomic_xchg_relaxed(a, 1); + + // CHECK: atom.global.xor.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + // CHECK: atom.global.xor.b32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], 1; + atomic_xor(a, 1); + atomic_xor_relaxed(a, 1); + + // CHECK: mov.u32 %[[sub_0_arg:r[0-9]+]], 100; + // CHECK: neg.s32 temp, %[[sub_0_arg]]; + // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], temp; + atomic_xsub(a, 100); + + // CHECK: mov.u32 %[[sub_1_arg:r[0-9]+]], 200; + // CHECK: neg.s32 temp, %[[sub_1_arg]]; + // CHECK: atom.global.add.u32 %{{r[0-9]+}}, [%{{rd[0-9]+}}], temp; + atomic_xsub_relaxed(a, 200); +} diff --git a/src/test/assembly/nvptx-internalizing.rs b/src/test/assembly/nvptx-internalizing.rs new file mode 100644 index 000000000..0004fcea7 --- /dev/null +++ b/src/test/assembly/nvptx-internalizing.rs @@ -0,0 +1,27 @@ +// assembly-output: ptx-linker +// compile-flags: --crate-type cdylib +// only-nvptx64 +// ignore-nvptx64 + +#![feature(abi_ptx)] +#![no_std] + +// aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// aux-build: non-inline-dependency.rs +extern crate non_inline_dependency as dep; + +// Verify that no extra function declarations are present. +// CHECK-NOT: .func + +// CHECK: .visible .entry top_kernel( +#[no_mangle] +pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { + // CHECK: add.s32 %{{r[0-9]+}}, %{{r[0-9]+}}, 5; + *b = *a + 5; +} + +// Verify that no extra function definitions are here. +// CHECK-NOT: .func +// CHECK-NOT: .entry diff --git a/src/test/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs b/src/test/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs new file mode 100644 index 000000000..5bf44f949 --- /dev/null +++ b/src/test/assembly/nvptx-kernel-abi/nvptx-kernel-args-abi-v7.rs @@ -0,0 +1,254 @@ +// assembly-output: ptx-linker +// compile-flags: --crate-type cdylib -C target-cpu=sm_86 +// only-nvptx64 +// ignore-nvptx64 + +// The following ABI tests are made with nvcc 11.6 does. +// +// The PTX ABI stability is tied to major versions of the PTX ISA +// These tests assume major version 7 +// +// +// The following correspondence between types are assumed: +// u<N> - uint<N>_t +// i<N> - int<N>_t +// [T, N] - std::array<T, N> +// &T - T const* +// &mut T - T* + +// CHECK: .version 7 + +#![feature(abi_ptx, lang_items, no_core)] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[repr(C)] +pub struct SingleU8 { + f: u8, +} + +#[repr(C)] +pub struct DoubleU8 { + f: u8, + g: u8, +} + +#[repr(C)] +pub struct TripleU8 { + f: u8, + g: u8, + h: u8, +} + +#[repr(C)] +pub struct TripleU16 { + f: u16, + g: u16, + h: u16, +} +#[repr(C)] +pub struct TripleU32 { + f: u32, + g: u32, + h: u32, +} +#[repr(C)] +pub struct TripleU64 { + f: u64, + g: u64, + h: u64, +} + +#[repr(C)] +pub struct DoubleFloat { + f: f32, + g: f32, +} + +#[repr(C)] +pub struct TripleFloat { + f: f32, + g: f32, + h: f32, +} + +#[repr(C)] +pub struct TripleDouble { + f: f64, + g: f64, + h: f64, +} + +#[repr(C)] +pub struct ManyIntegers { + f: u8, + g: u16, + h: u32, + i: u64, +} + +#[repr(C)] +pub struct ManyNumerics { + f: u8, + g: u16, + h: u32, + i: u64, + j: f32, + k: f64, +} + +// CHECK: .visible .entry f_u8_arg( +// CHECK: .param .u8 f_u8_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u8_arg(_a: u8) {} + +// CHECK: .visible .entry f_u16_arg( +// CHECK: .param .u16 f_u16_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u16_arg(_a: u16) {} + +// CHECK: .visible .entry f_u32_arg( +// CHECK: .param .u32 f_u32_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u32_arg(_a: u32) {} + +// CHECK: .visible .entry f_u64_arg( +// CHECK: .param .u64 f_u64_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u64_arg(_a: u64) {} + +// CHECK: .visible .entry f_u128_arg( +// CHECK: .param .align 16 .b8 f_u128_arg_param_0[16] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u128_arg(_a: u128) {} + +// CHECK: .visible .entry f_i8_arg( +// CHECK: .param .u8 f_i8_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_i8_arg(_a: i8) {} + +// CHECK: .visible .entry f_i16_arg( +// CHECK: .param .u16 f_i16_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_i16_arg(_a: i16) {} + +// CHECK: .visible .entry f_i32_arg( +// CHECK: .param .u32 f_i32_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_i32_arg(_a: i32) {} + +// CHECK: .visible .entry f_i64_arg( +// CHECK: .param .u64 f_i64_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_i64_arg(_a: i64) {} + +// CHECK: .visible .entry f_i128_arg( +// CHECK: .param .align 16 .b8 f_i128_arg_param_0[16] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_i128_arg(_a: i128) {} + +// CHECK: .visible .entry f_f32_arg( +// CHECK: .param .f32 f_f32_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_f32_arg(_a: f32) {} + +// CHECK: .visible .entry f_f64_arg( +// CHECK: .param .f64 f_f64_arg_param_0 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_f64_arg(_a: f64) {} + +// CHECK: .visible .entry f_single_u8_arg( +// CHECK: .param .align 1 .b8 f_single_u8_arg_param_0[1] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_single_u8_arg(_a: SingleU8) {} + +// CHECK: .visible .entry f_double_u8_arg( +// CHECK: .param .align 1 .b8 f_double_u8_arg_param_0[2] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_double_u8_arg(_a: DoubleU8) {} + +// CHECK: .visible .entry f_triple_u8_arg( +// CHECK: .param .align 1 .b8 f_triple_u8_arg_param_0[3] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_u8_arg(_a: TripleU8) {} + +// CHECK: .visible .entry f_triple_u16_arg( +// CHECK: .param .align 2 .b8 f_triple_u16_arg_param_0[6] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_u16_arg(_a: TripleU16) {} + +// CHECK: .visible .entry f_triple_u32_arg( +// CHECK: .param .align 4 .b8 f_triple_u32_arg_param_0[12] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_u32_arg(_a: TripleU32) {} + +// CHECK: .visible .entry f_triple_u64_arg( +// CHECK: .param .align 8 .b8 f_triple_u64_arg_param_0[24] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_u64_arg(_a: TripleU64) {} + +// CHECK: .visible .entry f_many_integers_arg( +// CHECK: .param .align 8 .b8 f_many_integers_arg_param_0[16] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_many_integers_arg(_a: ManyIntegers) {} + +// CHECK: .visible .entry f_double_float_arg( +// CHECK: .param .align 4 .b8 f_double_float_arg_param_0[8] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_double_float_arg(_a: DoubleFloat) {} + +// CHECK: .visible .entry f_triple_float_arg( +// CHECK: .param .align 4 .b8 f_triple_float_arg_param_0[12] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_float_arg(_a: TripleFloat) {} + +// CHECK: .visible .entry f_triple_double_arg( +// CHECK: .param .align 8 .b8 f_triple_double_arg_param_0[24] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_triple_double_arg(_a: TripleDouble) {} + +// CHECK: .visible .entry f_many_numerics_arg( +// CHECK: .param .align 8 .b8 f_many_numerics_arg_param_0[32] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_many_numerics_arg(_a: ManyNumerics) {} + +// CHECK: .visible .entry f_byte_array_arg( +// CHECK: .param .align 1 .b8 f_byte_array_arg_param_0[5] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_byte_array_arg(_a: [u8; 5]) {} + +// CHECK: .visible .entry f_float_array_arg( +// CHECK: .param .align 4 .b8 f_float_array_arg_param_0[20] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_float_array_arg(_a: [f32; 5]) {} + +// CHECK: .visible .entry f_u128_array_arg( +// CHECK: .param .align 16 .b8 f_u128_array_arg_param_0[80] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u128_array_arg(_a: [u128; 5]) {} + +// CHECK: .visible .entry f_u32_slice_arg( +// CHECK: .param .u64 f_u32_slice_arg_param_0 +// CHECK: .param .u64 f_u32_slice_arg_param_1 +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_u32_slice_arg(_a: &[u32]) {} + +// CHECK: .visible .entry f_tuple_u8_u8_arg( +// CHECK: .param .align 1 .b8 f_tuple_u8_u8_arg_param_0[2] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_tuple_u8_u8_arg(_a: (u8, u8)) {} + +// CHECK: .visible .entry f_tuple_u32_u32_arg( +// CHECK: .param .align 4 .b8 f_tuple_u32_u32_arg_param_0[8] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_tuple_u32_u32_arg(_a: (u32, u32)) {} + + +// CHECK: .visible .entry f_tuple_u8_u8_u32_arg( +// CHECK: .param .align 4 .b8 f_tuple_u8_u8_u32_arg_param_0[8] +#[no_mangle] +pub unsafe extern "ptx-kernel" fn f_tuple_u8_u8_u32_arg(_a: (u8, u8, u32)) {} diff --git a/src/test/assembly/nvptx-linking-binary.rs b/src/test/assembly/nvptx-linking-binary.rs new file mode 100644 index 000000000..64b9c2f17 --- /dev/null +++ b/src/test/assembly/nvptx-linking-binary.rs @@ -0,0 +1,40 @@ +// assembly-output: ptx-linker +// compile-flags: --crate-type bin +// only-nvptx64 +// ignore-nvptx64 + +#![feature(abi_ptx)] +#![no_main] +#![no_std] + +// aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// aux-build: non-inline-dependency.rs +extern crate non_inline_dependency as dep; + +// Make sure declarations are there. +// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn +// CHECK: .func (.param .b32 func_retval0) panicking_external_fn + +// CHECK-LABEL: .visible .entry top_kernel( +#[no_mangle] +pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { + // CHECK: call.uni (retval0), + // CHECK-NEXT: wrapping_external_fn + // CHECK: ld.param.b32 %[[LHS:r[0-9]+]], [retval0+0]; + let lhs = dep::wrapping_external_fn(*a); + + // CHECK: call.uni (retval0), + // CHECK-NEXT: panicking_external_fn + // CHECK: ld.param.b32 %[[RHS:r[0-9]+]], [retval0+0]; + let rhs = dep::panicking_external_fn(*a); + + // CHECK: add.s32 %[[RES:r[0-9]+]], %[[RHS]], %[[LHS]]; + // CHECK: st.global.u32 [%{{rd[0-9]+}}], %[[RES]]; + *b = lhs + rhs; +} + +// Verify that external function bodies are available. +// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn +// CHECK: .func (.param .b32 func_retval0) panicking_external_fn diff --git a/src/test/assembly/nvptx-linking-cdylib.rs b/src/test/assembly/nvptx-linking-cdylib.rs new file mode 100644 index 000000000..bdbc30ea9 --- /dev/null +++ b/src/test/assembly/nvptx-linking-cdylib.rs @@ -0,0 +1,39 @@ +// assembly-output: ptx-linker +// compile-flags: --crate-type cdylib +// only-nvptx64 +// ignore-nvptx64 + +#![feature(abi_ptx)] +#![no_std] + +// aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// aux-build: non-inline-dependency.rs +extern crate non_inline_dependency as dep; + +// Make sure declarations are there. +// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn +// CHECK: .func (.param .b32 func_retval0) panicking_external_fn + +// CHECK-LABEL: .visible .entry top_kernel( +#[no_mangle] +pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { + // CHECK: call.uni (retval0), + // CHECK-NEXT: wrapping_external_fn + // CHECK: ld.param.b32 %[[LHS:r[0-9]+]], [retval0+0]; + let lhs = dep::wrapping_external_fn(*a); + + // CHECK: call.uni (retval0), + // CHECK-NEXT: panicking_external_fn + // CHECK: ld.param.b32 %[[RHS:r[0-9]+]], [retval0+0]; + let rhs = dep::panicking_external_fn(*a); + + // CHECK: add.s32 %[[RES:r[0-9]+]], %[[RHS]], %[[LHS]]; + // CHECK: st.global.u32 [%{{rd[0-9]+}}], %[[RES]]; + *b = lhs + rhs; +} + +// Verify that external function bodies are available. +// CHECK: .func (.param .b32 func_retval0) wrapping_external_fn +// CHECK: .func (.param .b32 func_retval0) panicking_external_fn diff --git a/src/test/assembly/nvptx-safe-naming.rs b/src/test/assembly/nvptx-safe-naming.rs new file mode 100644 index 000000000..80bb04fc0 --- /dev/null +++ b/src/test/assembly/nvptx-safe-naming.rs @@ -0,0 +1,38 @@ +// assembly-output: ptx-linker +// compile-flags: --crate-type cdylib +// only-nvptx64 +// ignore-nvptx64 + +#![feature(abi_ptx)] +#![no_std] + +// aux-build: breakpoint-panic-handler.rs +extern crate breakpoint_panic_handler; + +// Verify function name doesn't contain unacceaptable characters. +// CHECK: .func (.param .b32 func_retval0) [[IMPL_FN:[a-zA-Z0-9$_]+square[a-zA-Z0-9$_]+]]( + +// CHECK-LABEL: .visible .entry top_kernel( +#[no_mangle] +pub unsafe extern "ptx-kernel" fn top_kernel(a: *const u32, b: *mut u32) { + // CHECK: call.uni (retval0), + // CHECK-NEXT: [[IMPL_FN]] + *b = deep::private::MyStruct::new(*a).square(); +} + +pub mod deep { + pub mod private { + pub struct MyStruct<T>(T); + + impl MyStruct<u32> { + pub fn new(a: u32) -> Self { + MyStruct(a) + } + + #[inline(never)] + pub fn square(&self) -> u32 { + self.0.wrapping_mul(self.0) + } + } + } +} diff --git a/src/test/assembly/panic-no-unwind-no-uwtable.rs b/src/test/assembly/panic-no-unwind-no-uwtable.rs new file mode 100644 index 000000000..499d4e698 --- /dev/null +++ b/src/test/assembly/panic-no-unwind-no-uwtable.rs @@ -0,0 +1,8 @@ +// assembly-output: emit-asm +// only-x86_64-unknown-linux-gnu +// compile-flags: -C panic=unwind -C force-unwind-tables=n -O + +#![crate_type = "lib"] + +// CHECK-NOT: .cfi_startproc +pub fn foo() {} diff --git a/src/test/assembly/panic-unwind-no-uwtable.rs b/src/test/assembly/panic-unwind-no-uwtable.rs new file mode 100644 index 000000000..8eed72b2f --- /dev/null +++ b/src/test/assembly/panic-unwind-no-uwtable.rs @@ -0,0 +1,12 @@ +// assembly-output: emit-asm +// only-x86_64-unknown-linux-gnu +// compile-flags: -C panic=unwind -C force-unwind-tables=n + +#![crate_type = "lib"] + +// CHECK-LABEL: foo: +// CHECK: .cfi_startproc +#[no_mangle] +fn foo() { + panic!(); +} diff --git a/src/test/assembly/pic-relocation-model.rs b/src/test/assembly/pic-relocation-model.rs new file mode 100644 index 000000000..72471ffcd --- /dev/null +++ b/src/test/assembly/pic-relocation-model.rs @@ -0,0 +1,35 @@ +// revisions: x64 +// assembly-output: emit-asm +// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pic +// [x64] needs-llvm-components: x86 + + +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type="rlib"] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +// CHECK-LABEL: call_other_fn: +// CHECK: {{(jmpq|callq)}} *other_fn@GOTPCREL(%rip) +#[no_mangle] +pub fn call_other_fn() -> u8 { + unsafe { + other_fn() + } +} + +// CHECK-LABEL: other_fn: +// CHECK: callq *foreign_fn@GOTPCREL(%rip) +#[no_mangle] +#[inline(never)] +pub fn other_fn() -> u8 { + unsafe { + foreign_fn() + } +} + +extern "C" {fn foreign_fn() -> u8;} diff --git a/src/test/assembly/pie-relocation-model.rs b/src/test/assembly/pie-relocation-model.rs new file mode 100644 index 000000000..e40797e03 --- /dev/null +++ b/src/test/assembly/pie-relocation-model.rs @@ -0,0 +1,38 @@ +// revisions: x64 +// assembly-output: emit-asm +// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=pie +// [x64] needs-llvm-components: x86 + + +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type="rlib"] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +// CHECK-LABEL: call_other_fn: +// With PIE local functions are called "directly". +// CHECK: {{(jmp|callq)}} other_fn +#[no_mangle] +pub fn call_other_fn() -> u8 { + unsafe { + other_fn() + } +} + +// CHECK-LABEL: other_fn: +// External functions are still called through GOT, since we don't know if the symbol +// is defined in the binary or in the shared library. +// CHECK: callq *foreign_fn@GOTPCREL(%rip) +#[no_mangle] +#[inline(never)] +pub fn other_fn() -> u8 { + unsafe { + foreign_fn() + } +} + +extern "C" {fn foreign_fn() -> u8;} diff --git a/src/test/assembly/sparc-struct-abi.rs b/src/test/assembly/sparc-struct-abi.rs new file mode 100644 index 000000000..6a898b297 --- /dev/null +++ b/src/test/assembly/sparc-struct-abi.rs @@ -0,0 +1,65 @@ +// Test SPARC64 ABI +// - float structure members are passes in floating point registers +// (#86163) + +// assembly-output: emit-asm +// needs-llvm-components: sparc +// compile-flags: --target=sparcv9-sun-solaris -Copt-level=3 +#![crate_type = "lib"] +#![feature(no_core, lang_items)] +#![no_core] + +#[lang = "sized"] +pub trait Sized {} +#[lang = "copy"] +pub trait Copy {} +impl Copy for f32 {} + +#[repr(C)] +pub struct Franta { + a: f32, + b: f32, + c: f32, + d: f32, +} + +// NB: due to delay slots the `ld` following the call is actually executed before the call. +#[no_mangle] +pub unsafe extern "C" fn callee(arg: Franta) { + // CHECK-LABEL: callee: + // CHECK: st %f3, [[PLACE_D:.*]] + // CHECK: st %f2, [[PLACE_C:.*]] + // CHECK: st %f1, [[PLACE_B:.*]] + // CHECK: st %f0, [[PLACE_A:.*]] + // CHECK: call tst_use + // CHECK-NEXT: ld [[PLACE_A]], %f1 + // CHECK: call tst_use + // CHECK-NEXT: ld [[PLACE_B]], %f1 + // CHECK: call tst_use + // CHECK-NEXT: ld [[PLACE_C]], %f1 + // CHECK: call tst_use + // CHECK-NEXT: ld [[PLACE_D]], %f1 + clobber(); + tst_use(arg.a); + tst_use(arg.b); + tst_use(arg.c); + tst_use(arg.d); +} + +extern "C" { + fn opaque_callee(arg: Franta, intarg: i32); + fn tst_use(arg: f32); + fn clobber(); +} + +#[no_mangle] +pub unsafe extern "C" fn caller() { + // CHECK-LABEL: caller: + // CHECK: ld [{{.*}}], %f0 + // CHECK: ld [{{.*}}], %f1 + // CHECK: ld [{{.*}}], %f2 + // CHECK: ld [{{.*}}], %f3 + // CHECK: call opaque_callee + // CHECK: mov 3, %o2 + opaque_callee(Franta { a: 1.0, b: 2.0, c: 3.0, d: 4.0 }, 3); +} diff --git a/src/test/assembly/stack-protector/stack-protector-heuristics-effect.rs b/src/test/assembly/stack-protector/stack-protector-heuristics-effect.rs new file mode 100644 index 000000000..7c2b60550 --- /dev/null +++ b/src/test/assembly/stack-protector/stack-protector-heuristics-effect.rs @@ -0,0 +1,396 @@ +// revisions: all strong basic none missing +// assembly-output: emit-asm +// ignore-macos slightly different policy on stack protection of arrays +// ignore-windows stack check code uses different function names +// ignore-nvptx64 stack protector is not supported +// [all] compile-flags: -Z stack-protector=all +// [strong] compile-flags: -Z stack-protector=strong +// [basic] compile-flags: -Z stack-protector=basic +// [none] compile-flags: -Z stack-protector=none +// compile-flags: -C opt-level=2 -Z merge-functions=disabled + +#![crate_type = "lib"] + +#![allow(incomplete_features)] + +#![feature(unsized_locals, unsized_fn_params)] + + +// CHECK-LABEL: emptyfn: +#[no_mangle] +pub fn emptyfn() { + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: array_char +#[no_mangle] +pub fn array_char(f: fn(*const char)) { + let a = ['c'; 1]; + let b = ['d'; 3]; + let c = ['e'; 15]; + + f(&a as *const _); + f(&b as *const _); + f(&c as *const _); + + // Any type of local array variable leads to stack protection with the + // "strong" heuristic. The 'basic' heuristic only adds stack protection to + // functions with local array variables of a byte-sized type, however. Since + // 'char' is 4 bytes in Rust, this function is not protected by the 'basic' + // heuristic + // + // (This test *also* takes the address of the local stack variables. We + // cannot know that this isn't what triggers the `strong` heuristic. + // However, the test strategy of passing the address of a stack array to an + // external function is sufficient to trigger the `basic` heuristic (see + // test `array_u8_large()`). Since the `basic` heuristic only checks for the + // presence of stack-local array variables, we can be confident that this + // test also captures this part of the `strong` heuristic specification.) + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: array_u8_1 +#[no_mangle] +pub fn array_u8_1(f: fn(*const u8)) { + let a = [0u8; 1]; + f(&a as *const _); + + // The 'strong' heuristic adds stack protection to functions with local + // array variables regardless of their size. + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: array_u8_small: +#[no_mangle] +pub fn array_u8_small(f: fn(*const u8)) { + let a = [0u8; 2]; + let b = [0u8; 7]; + f(&a as *const _); + f(&b as *const _); + + // Small arrays do not lead to stack protection by the 'basic' heuristic. + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: array_u8_large: +#[no_mangle] +pub fn array_u8_large(f: fn(*const u8)) { + let a = [0u8; 9]; + f(&a as *const _); + + // Since `a` is a byte array with size greater than 8, the basic heuristic + // will also protect this function. + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +#[derive(Copy, Clone)] +pub struct ByteSizedNewtype(u8); + +// CHECK-LABEL: array_bytesizednewtype_9: +#[no_mangle] +pub fn array_bytesizednewtype_9(f: fn(*const ByteSizedNewtype)) { + let a = [ByteSizedNewtype(0); 9]; + f(&a as *const _); + + // Since `a` is a byte array in the LLVM output, the basic heuristic will + // also protect this function. + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: local_var_addr_used_indirectly +#[no_mangle] +pub fn local_var_addr_used_indirectly(f: fn(bool)) { + let a = 5; + let a_addr = &a as *const _ as usize; + f(a_addr & 0x10 == 0); + + // This function takes the address of a local variable taken. Although this + // address is never used as a way to refer to stack memory, the `strong` + // heuristic adds stack smash protection. This is also the case in C++: + // ``` + // cat << EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk + // #include <cstdint> + // void f(void (*g)(bool)) { + // int32_t x; + // g((reinterpret_cast<uintptr_t>(&x) & 0x10U) == 0); + // } + // EOF + // ``` + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + + +// CHECK-LABEL: local_string_addr_taken +#[no_mangle] +pub fn local_string_addr_taken(f: fn(&String)) { + let x = String::new(); + f(&x); + + // Taking the address of the local variable `x` leads to stack smash + // protection with the `strong` heuristic, but not with the `basic` + // heuristic. It does not matter that the reference is not mut. + // + // An interesting note is that a similar function in C++ *would* be + // protected by the `basic` heuristic, because `std::string` has a char + // array internally as a small object optimization: + // ``` + // cat <<EOF | clang++ -O2 -fstack-protector -S -x c++ - -o - | grep stack_chk + // #include <string> + // void f(void (*g)(const std::string&)) { + // std::string x; + // g(x); + // } + // EOF + // ``` + // + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +pub trait SelfByRef { + fn f(&self) -> i32; +} + +impl SelfByRef for i32 { + fn f(&self) -> i32 { + return self + 1; + } +} + +// CHECK-LABEL: local_var_addr_taken_used_locally_only +#[no_mangle] +pub fn local_var_addr_taken_used_locally_only(factory: fn() -> i32, sink: fn(i32)) { + let x = factory(); + let g = x.f(); + sink(g); + + // Even though the local variable conceptually has its address taken, as + // it's passed by reference to the trait function, the use of the reference + // is easily inlined. There is therefore no stack smash protection even with + // the `strong` heuristic. + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +pub struct Gigastruct { + does: u64, + not: u64, + have: u64, + array: u64, + members: u64 +} + +// CHECK-LABEL: local_large_var_moved +#[no_mangle] +pub fn local_large_var_moved(f: fn(Gigastruct)) { + let x = Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }; + f(x); + + // Even though the local variable conceptually doesn't have its address + // taken, it's so large that the "move" is implemented with a reference to a + // stack-local variable in the ABI. Consequently, this function *is* + // protected by the `strong` heuristic. This is also the case for + // rvalue-references in C++, regardless of struct size: + // ``` + // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk + // #include <cstdint> + // #include <utility> + // void f(void (*g)(uint64_t&&)) { + // uint64_t x; + // g(std::move(x)); + // } + // EOF + // ``` + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: local_large_var_cloned +#[no_mangle] +pub fn local_large_var_cloned(f: fn(Gigastruct)) { + f(Gigastruct { does: 0, not: 1, have: 2, array: 3, members: 4 }); + + // A new instance of `Gigastruct` is passed to `f()`, without any apparent + // connection to this stack frame. Still, since instances of `Gigastruct` + // are sufficiently large, it is allocated in the caller stack frame and + // passed as a pointer. As such, this function is *also* protected by the + // `strong` heuristic, just like `local_large_var_moved`. This is also the + // case for pass-by-value of sufficiently large structs in C++: + // ``` + // cat <<EOF | clang++ -O2 -fstack-protector-strong -S -x c++ - -o - | grep stack_chk + // #include <cstdint> + // #include <utility> + // struct Gigastruct { uint64_t a, b, c, d, e; }; + // void f(void (*g)(Gigastruct)) { + // g(Gigastruct{}); + // } + // EOF + // ``` + + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + + +extern "C" { + // A call to an external `alloca` function is *not* recognized as an + // `alloca(3)` operation. This function is a compiler built-in, as the + // man page explains. Clang translates it to an LLVM `alloca` + // instruction with a count argument, which is also what the LLVM stack + // protector heuristics looks for. The man page for `alloca(3)` details + // a way to avoid using the compiler built-in: pass a -std=c11 + // argument, *and* don't include <alloca.h>. Though this leads to an + // external alloca() function being called, it doesn't lead to stack + // protection being included. It even fails with a linker error + // "undefined reference to `alloca'". Example: + // ``` + // cat<<EOF | clang -fstack-protector-strong -x c -std=c11 - -o /dev/null + // #include <stdlib.h> + // void * alloca(size_t); + // void f(void (*g)(void*)) { + // void * p = alloca(10); + // g(p); + // } + // int main() { return 0; } + // EOF + // ``` + // The following tests demonstrate that calls to an external `alloca` + // function in Rust also doesn't trigger stack protection. + + fn alloca(size: usize) -> *mut (); +} + +// CHECK-LABEL: alloca_small_compile_time_constant_arg +#[no_mangle] +pub fn alloca_small_compile_time_constant_arg(f: fn(*mut ())) { + f(unsafe { alloca(8) }); + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: alloca_large_compile_time_constant_arg +#[no_mangle] +pub fn alloca_large_compile_time_constant_arg(f: fn(*mut ())) { + f(unsafe { alloca(9) }); + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + + +// CHECK-LABEL: alloca_dynamic_arg +#[no_mangle] +pub fn alloca_dynamic_arg(f: fn(*mut ()), n: usize) { + f(unsafe { alloca(n) }); + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// The question then is: in what ways can Rust code generate array-`alloca` +// LLVM instructions? This appears to only be generated by +// rustc_codegen_ssa::traits::Builder::array_alloca() through +// rustc_codegen_ssa::mir::operand::OperandValue::store_unsized(). FWICT +// this is support for the "unsized locals" unstable feature: +// https://doc.rust-lang.org/unstable-book/language-features/unsized-locals.html. + + +// CHECK-LABEL: unsized_fn_param +#[no_mangle] +pub fn unsized_fn_param(s: [u8], l: bool, f: fn([u8])) { + let n = if l { 1 } else { 2 }; + f(*Box::<[u8]>::from(&s[0..n])); // slice-copy with Box::from + + // Even though slices are conceptually passed by-value both into this + // function and into `f()`, this is implemented with pass-by-reference + // using a suitably constructed fat-pointer (as if the functions + // accepted &[u8]). This function therefore doesn't need dynamic array + // alloca, and is therefore not protected by the `strong` or `basic` + // heuristics. + + + // all: __stack_chk_fail + // strong-NOT: __stack_chk_fail + // basic-NOT: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} + +// CHECK-LABEL: unsized_local +#[no_mangle] +pub fn unsized_local(s: &[u8], l: bool, f: fn(&mut [u8])) { + let n = if l { 1 } else { 2 }; + let mut a: [u8] = *Box::<[u8]>::from(&s[0..n]); // slice-copy with Box::from + f(&mut a); + + // This function allocates a slice as a local variable in its stack + // frame. Since the size is not a compile-time constant, an array + // alloca is required, and the function is protected by both the + // `strong` and `basic` heuristic. + + // all: __stack_chk_fail + // strong: __stack_chk_fail + // basic: __stack_chk_fail + // none-NOT: __stack_chk_fail + // missing-NOT: __stack_chk_fail +} diff --git a/src/test/assembly/stack-protector/stack-protector-target-support.rs b/src/test/assembly/stack-protector/stack-protector-target-support.rs new file mode 100644 index 000000000..5ba46d082 --- /dev/null +++ b/src/test/assembly/stack-protector/stack-protector-target-support.rs @@ -0,0 +1,286 @@ +// Test that stack smash protection code is emitted for all tier1 and tier2 +// targets, with the exception of nvptx64-nvidia-cuda +// +// revisions: r1 r2 r3 r4 r5 r6 r7 r8 r9 r10 r11 r12 r13 r14 r15 r16 r17 r18 r19 r20 r21 r22 r23 +// revisions: r24 r25 r26 r27 r28 r29 r30 r31 r32 r33 r34 r35 r36 r37 r38 r39 r40 r41 r42 r43 r44 +// revisions: r45 r46 r47 r48 r49 r50 r51 r52 r53 r54 r55 r56 r57 r58 r59 r60 r61 r62 r63 r64 r65 +// revisions: r66 r67 r68 r69 r70 r71 r72 r73 r74 r75 r76 r77 r78 r79 r80 r81 r82 r83 r84 +// assembly-output: emit-asm +// [r1] compile-flags: --target aarch64-unknown-linux-gnu +// [r1] needs-llvm-components: aarch64 +// [r2] compile-flags: --target i686-pc-windows-gnu +// [r2] needs-llvm-components: x86 +// [r3] compile-flags: --target i686-pc-windows-msvc +// [r3] needs-llvm-components: x86 +// [r4] compile-flags: --target i686-unknown-linux-gnu +// [r4] needs-llvm-components: x86 +// [r5] compile-flags: --target x86_64-apple-darwin +// [r5] needs-llvm-components: x86 +// [r6] compile-flags: --target x86_64-pc-windows-gnu +// [r6] needs-llvm-components: x86 +// [r7] compile-flags: --target x86_64-pc-windows-msvc +// [r7] needs-llvm-components: x86 +// [r8] compile-flags: --target x86_64-unknown-linux-gnu +// [r8] needs-llvm-components: x86 +// [r9] compile-flags: --target aarch64-apple-darwin +// [r9] needs-llvm-components: aarch64 +// [r10] compile-flags: --target aarch64-apple-ios +// [r10] needs-llvm-components: aarch64 +// [r11] compile-flags: --target aarch64-fuchsia +// [r11] needs-llvm-components: aarch64 +// [r12] compile-flags: --target aarch64-linux-android +// [r12] needs-llvm-components: aarch64 +// [r13] compile-flags: --target aarch64-pc-windows-msvc +// [r13] needs-llvm-components: aarch64 +// [r14] compile-flags: --target aarch64-unknown-linux-musl +// [r14] needs-llvm-components: aarch64 +// [r15] compile-flags: --target aarch64-unknown-none +// [r15] needs-llvm-components: aarch64 +// [r16] compile-flags: --target aarch64-unknown-none-softfloat +// [r16] needs-llvm-components: aarch64 +// [r17] compile-flags: --target arm-linux-androideabi +// [r17] needs-llvm-components: arm +// [r18] compile-flags: --target arm-unknown-linux-gnueabi +// [r18] needs-llvm-components: arm +// [r19] compile-flags: --target arm-unknown-linux-gnueabihf +// [r19] needs-llvm-components: arm +// [r20] compile-flags: --target arm-unknown-linux-musleabi +// [r20] needs-llvm-components: arm +// [r21] compile-flags: --target arm-unknown-linux-musleabihf +// [r21] needs-llvm-components: arm +// [r22] compile-flags: --target armebv7r-none-eabi +// [r22] needs-llvm-components: arm +// [r23] compile-flags: --target armebv7r-none-eabihf +// [r23] needs-llvm-components: arm +// [r24] compile-flags: --target armv5te-unknown-linux-gnueabi +// [r24] needs-llvm-components: arm +// [r25] compile-flags: --target armv5te-unknown-linux-musleabi +// [r25] needs-llvm-components: arm +// [r26] compile-flags: --target armv7-linux-androideabi +// [r26] needs-llvm-components: arm +// [r27] compile-flags: --target armv7a-none-eabi +// [r27] needs-llvm-components: arm +// [r28] compile-flags: --target armv7r-none-eabi +// [r28] needs-llvm-components: arm +// [r29] compile-flags: --target armv7r-none-eabihf +// [r29] needs-llvm-components: arm +// [r30] compile-flags: --target armv7-unknown-linux-gnueabi +// [r30] needs-llvm-components: arm +// [r31] compile-flags: --target armv7-unknown-linux-gnueabihf +// [r31] needs-llvm-components: arm +// [r32] compile-flags: --target armv7-unknown-linux-musleabi +// [r32] needs-llvm-components: arm +// [r33] compile-flags: --target armv7-unknown-linux-musleabihf +// [r33] needs-llvm-components: arm +// [r34] compile-flags: --target asmjs-unknown-emscripten +// [r34] needs-llvm-components: webassembly +// [r35] compile-flags: --target i586-pc-windows-msvc +// [r35] needs-llvm-components: x86 +// [r36] compile-flags: --target i586-unknown-linux-gnu +// [r36] needs-llvm-components: x86 +// [r37] compile-flags: --target i586-unknown-linux-musl +// [r37] needs-llvm-components: x86 +// [r38] compile-flags: --target i686-linux-android +// [r38] needs-llvm-components: x86 +// [r39] compile-flags: --target i686-unknown-freebsd +// [r39] needs-llvm-components: x86 +// [r40] compile-flags: --target i686-unknown-linux-musl +// [r40] needs-llvm-components: x86 +// [r41] compile-flags: --target mips-unknown-linux-gnu +// [r41] needs-llvm-components: mips +// [r42] compile-flags: --target mips-unknown-linux-musl +// [r42] needs-llvm-components: mips +// [r43] compile-flags: --target mips64-unknown-linux-gnuabi64 +// [r43] needs-llvm-components: mips +// [r44] compile-flags: --target mips64-unknown-linux-muslabi64 +// [r44] needs-llvm-components: mips +// [r45] compile-flags: --target mips64el-unknown-linux-gnuabi64 +// [r45] needs-llvm-components: mips +// [r46] compile-flags: --target mips64el-unknown-linux-muslabi64 +// [r46] needs-llvm-components: mips +// [r47] compile-flags: --target mipsel-unknown-linux-gnu +// [r47] needs-llvm-components: mips +// [r48] compile-flags: --target mipsel-unknown-linux-musl +// [r48] needs-llvm-components: mips +// [r49] compile-flags: --target nvptx64-nvidia-cuda +// [r49] needs-llvm-components: nvptx +// [r50] compile-flags: --target powerpc-unknown-linux-gnu +// [r50] needs-llvm-components: powerpc +// [r51] compile-flags: --target powerpc64-unknown-linux-gnu +// [r51] needs-llvm-components: powerpc +// [r52] compile-flags: --target powerpc64le-unknown-linux-gnu +// [r52] needs-llvm-components: powerpc +// [r53] compile-flags: --target riscv32i-unknown-none-elf +// [r53] needs-llvm-components: riscv +// [r54] compile-flags: --target riscv32imac-unknown-none-elf +// [r54] needs-llvm-components: riscv +// [r55] compile-flags:--target riscv32imc-unknown-none-elf +// [r55] needs-llvm-components: riscv +// [r56] compile-flags:--target riscv64gc-unknown-linux-gnu +// [r56] needs-llvm-components: riscv +// [r57] compile-flags:--target riscv64gc-unknown-none-elf +// [r57] needs-llvm-components: riscv +// [r58] compile-flags:--target riscv64imac-unknown-none-elf +// [r58] needs-llvm-components: riscv +// [r59] compile-flags:--target s390x-unknown-linux-gnu +// [r59] needs-llvm-components: systemz +// [r60] compile-flags:--target sparc64-unknown-linux-gnu +// [r60] needs-llvm-components: sparc +// [r61] compile-flags:--target sparcv9-sun-solaris +// [r61] needs-llvm-components: sparc +// [r62] compile-flags:--target thumbv6m-none-eabi +// [r62] needs-llvm-components: arm +// [r63] compile-flags:--target thumbv7em-none-eabi +// [r63] needs-llvm-components: arm +// [r64] compile-flags:--target thumbv7em-none-eabihf +// [r64] needs-llvm-components: arm +// [r65] compile-flags:--target thumbv7m-none-eabi +// [r65] needs-llvm-components: arm +// [r66] compile-flags:--target thumbv7neon-linux-androideabi +// [r66] needs-llvm-components: arm +// [r67] compile-flags:--target thumbv7neon-unknown-linux-gnueabihf +// [r67] needs-llvm-components: arm +// [r68] compile-flags:--target thumbv8m.base-none-eabi +// [r68] needs-llvm-components: arm +// [r69] compile-flags:--target thumbv8m.main-none-eabi +// [r69] needs-llvm-components: arm +// [r70] compile-flags:--target thumbv8m.main-none-eabihf +// [r70] needs-llvm-components: arm +// [r71] compile-flags:--target wasm32-unknown-emscripten +// [r71] needs-llvm-components: webassembly +// [r72] compile-flags:--target wasm32-unknown-unknown +// [r72] needs-llvm-components: webassembly +// [r73] compile-flags:--target wasm32-wasi +// [r73] needs-llvm-components: webassembly +// [r74] compile-flags:--target x86_64-apple-ios +// [r74] needs-llvm-components: x86 +// [r75] compile-flags:--target x86_64-fortanix-unknown-sgx +// [r75] needs-llvm-components: x86 +// [r75] min-llvm-version: 11.0.0 +// [r76] compile-flags:--target x86_64-fuchsia +// [r76] needs-llvm-components: x86 +// [r77] compile-flags:--target x86_64-linux-android +// [r77] needs-llvm-components: x86 +// [r78] compile-flags:--target x86_64-sun-solaris +// [r78] needs-llvm-components: x86 +// [r79] compile-flags:--target x86_64-unknown-freebsd +// [r79] needs-llvm-components: x86 +// [r80] compile-flags:--target x86_64-unknown-illumos +// [r80] needs-llvm-components: x86 +// [r81] compile-flags:--target x86_64-unknown-linux-gnux32 +// [r81] needs-llvm-components: x86 +// [r82] compile-flags:--target x86_64-unknown-linux-musl +// [r82] needs-llvm-components: x86 +// [r83] compile-flags:--target x86_64-unknown-netbsd +// [r83] needs-llvm-components: x86 +// [r84] compile-flags: --target x86_64-unknown-redox +// [r84] needs-llvm-components: x86 +// compile-flags: -Z stack-protector=all +// compile-flags: -C opt-level=2 + +#![crate_type = "lib"] + +#![feature(no_core, lang_items)] +#![crate_type = "lib"] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +#[no_mangle] +pub fn foo() { + // CHECK: foo{{:|()}} + + // MSVC does the stack checking within a stack-check function: + // r3: calll @__security_check_cookie + // r7: callq __security_check_cookie + // r13: bl __security_check_cookie + // r35: calll @__security_check_cookie + + // cuda doesn't support stack-smash protection + // r49-NOT: __security_check_cookie + // r49-NOT: __stack_chk_fail + + // Other targets do stack checking within the function, and call a failure function on error + // r1: __stack_chk_fail + // r2: __stack_chk_fail + // r4: __stack_chk_fail + // r5: __stack_chk_fail + // r6: __stack_chk_fail + // r8: __stack_chk_fail + // r9: __stack_chk_fail + // r10: __stack_chk_fail + // r11: __stack_chk_fail + // r12: __stack_chk_fail + // r14: __stack_chk_fail + // r15: __stack_chk_fail + // r16: __stack_chk_fail + // r17: __stack_chk_fail + // r18: __stack_chk_fail + // r19: __stack_chk_fail + // r20: __stack_chk_fail + // r21: __stack_chk_fail + // r22: __stack_chk_fail + // r23: __stack_chk_fail + // r24: __stack_chk_fail + // r25: __stack_chk_fail + // r26: __stack_chk_fail + // r27: __stack_chk_fail + // r28: __stack_chk_fail + // r29: __stack_chk_fail + // r30: __stack_chk_fail + // r31: __stack_chk_fail + // r32: __stack_chk_fail + // r33: __stack_chk_fail + // r34: __stack_chk_fail + // r36: __stack_chk_fail + // r37: __stack_chk_fail + // r38: __stack_chk_fail + // r39: __stack_chk_fail + // r40: __stack_chk_fail + // r41: __stack_chk_fail + // r42: __stack_chk_fail + // r43: __stack_chk_fail + // r44: __stack_chk_fail + // r45: __stack_chk_fail + // r46: __stack_chk_fail + // r47: __stack_chk_fail + // r48: __stack_chk_fail + // r50: __stack_chk_fail + // r51: __stack_chk_fail + // r52: __stack_chk_fail + // r53: __stack_chk_fail + // r54: __stack_chk_fail + // r55: __stack_chk_fail + // r56: __stack_chk_fail + // r57: __stack_chk_fail + // r58: __stack_chk_fail + // r59: __stack_chk_fail + // r60: __stack_chk_fail + // r61: __stack_chk_fail + // r62: __stack_chk_fail + // r63: __stack_chk_fail + // r64: __stack_chk_fail + // r65: __stack_chk_fail + // r66: __stack_chk_fail + // r67: __stack_chk_fail + // r68: __stack_chk_fail + // r69: __stack_chk_fail + // r70: __stack_chk_fail + // r71: __stack_chk_fail + // r72: __stack_chk_fail + // r73: __stack_chk_fail + // r74: __stack_chk_fail + // r75: __stack_chk_fail + // r76: __stack_chk_fail + // r77: __stack_chk_fail + // r78: __stack_chk_fail + // r79: __stack_chk_fail + // r80: __stack_chk_fail + // r81: __stack_chk_fail + // r82: __stack_chk_fail + // r83: __stack_chk_fail + // r84: __stack_chk_fail +} diff --git a/src/test/assembly/static-relocation-model.rs b/src/test/assembly/static-relocation-model.rs new file mode 100644 index 000000000..faa2e3952 --- /dev/null +++ b/src/test/assembly/static-relocation-model.rs @@ -0,0 +1,86 @@ +// revisions: x64 A64 ppc64le +// assembly-output: emit-asm +// [x64] compile-flags: --target x86_64-unknown-linux-gnu -Crelocation-model=static +// [x64] needs-llvm-components: x86 +// [A64] compile-flags: --target aarch64-unknown-linux-gnu -Crelocation-model=static +// [A64] needs-llvm-components: aarch64 +// [ppc64le] compile-flags: --target powerpc64le-unknown-linux-gnu -Crelocation-model=static +// [ppc64le] needs-llvm-components: powerpc + +#![feature(no_core, lang_items)] +#![no_core] +#![crate_type="rlib"] + +#[lang="sized"] +trait Sized {} + +#[lang="copy"] +trait Copy {} + +#[lang="sync"] +trait Sync {} + +#[lang = "drop_in_place"] +fn drop_in_place<T>(_: *mut T) {} + +impl Copy for u8 {} +impl Sync for u8 {} + +#[no_mangle] +pub static PIERIS: u8 = 42; + +extern "C" { + static EXOCHORDA: *mut u8; + + fn chaenomeles(); +} + +// CHECK-LABEL: banana: +// On the next line LLVM 14 produces a `movb`, whereas LLVM 15+ produces a `movzbl`. +// x64: {{movb|movzbl}} chaenomeles{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} +// A64: adrp [[REG:[a-z0-9]+]], chaenomeles +// A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG]], :lo12:chaenomeles] +#[no_mangle] +pub fn banana() -> u8 { + unsafe { + *(chaenomeles as *mut u8) + } +} + +// CHECK-LABEL: peach: +// x64: {{movb|movzbl}} banana{{(\(%[a-z0-9]+\))?}}, %{{[a-z0-9]+}} +// A64: adrp [[REG2:[a-z0-9]+]], banana +// A64-NEXT: ldrb {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:banana] +#[no_mangle] +pub fn peach() -> u8 { + unsafe { + *(banana as *mut u8) + } +} + +// CHECK-LABEL: mango: +// x64: movq EXOCHORDA{{(\(%[a-z0-9]+\))?}}, %[[REG:[a-z0-9]+]] +// x64-NEXT: {{movb|movzbl}} (%[[REG]]), %{{[a-z0-9]+}} +// A64: adrp [[REG2:[a-z0-9]+]], EXOCHORDA +// A64-NEXT: ldr {{[a-z0-9]+}}, {{\[}}[[REG2]], :lo12:EXOCHORDA] +#[no_mangle] +pub fn mango() -> u8 { + unsafe { + *EXOCHORDA + } +} + +// CHECK-LABEL: orange: +// x64: mov{{l|absq}} $PIERIS, %{{[a-z0-9]+}} +// A64: adrp [[REG2:[a-z0-9]+]], PIERIS +// A64-NEXT: add {{[a-z0-9]+}}, [[REG2]], :lo12:PIERIS +#[no_mangle] +pub fn orange() -> &'static u8 { + &PIERIS +} + +// For ppc64 we need to make sure to generate TOC entries even with the static relocation model +// ppc64le: .tc chaenomeles[TC],chaenomeles +// ppc64le: .tc banana[TC],banana +// ppc64le: .tc EXOCHORDA[TC],EXOCHORDA +// ppc64le: .tc PIERIS[TC],PIERIS diff --git a/src/test/assembly/target-feature-multiple.rs b/src/test/assembly/target-feature-multiple.rs new file mode 100644 index 000000000..18d896e86 --- /dev/null +++ b/src/test/assembly/target-feature-multiple.rs @@ -0,0 +1,42 @@ +// assembly-output: emit-asm +// needs-llvm-components: x86 +// revisions: TWOFLAGS SINGLEFLAG +// compile-flags: --target=x86_64-unknown-linux-gnu +// [TWOFLAGS] compile-flags: -C target-feature=+rdrnd -C target-feature=+rdseed +// [SINGLEFLAG] compile-flags: -C target-feature=+rdrnd,+rdseed + +// Target features set via flags aren't necessarily reflected in the IR, so the only way to test +// them is to build code that requires the features to be enabled to work. +// +// In this particular test if `rdrnd,rdseed` somehow didn't make it to LLVM, the instruction +// selection should crash. +// +// > LLVM ERROR: Cannot select: 0x7f00f400c010: i32,i32,ch = X86ISD::RDSEED 0x7f00f400bfa8:2 +// > In function: foo +// +// See also src/test/codegen/target-feature-overrides.rs +#![feature(no_core, lang_items, link_llvm_intrinsics, abi_unadjusted)] +#![crate_type = "lib"] +#![no_core] + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} +impl Copy for u32 {} + +// Use of these requires target features to be enabled +extern "unadjusted" { + #[link_name = "llvm.x86.rdrand.32"] + fn x86_rdrand32_step() -> (u32, i32); + #[link_name = "llvm.x86.rdseed.32"] + fn x86_rdseed32_step() -> (u32, i32); +} + +#[no_mangle] +pub unsafe fn foo() -> (u32, u32) { + // CHECK-LABEL: foo: + // CHECK: rdrand + // CHECK: rdseed + (x86_rdrand32_step().0, x86_rdseed32_step().0) +} diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs new file mode 100644 index 000000000..79d82cf70 --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs @@ -0,0 +1,17 @@ +// Test LVI load hardening on SGX enclave code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#[no_mangle] +pub extern fn plus_one(r: &mut u64) { + *r = *r + 1; +} + +// CHECK: plus_one +// CHECK: lfence +// CHECK-NEXT: addq +// CHECK: popq [[REGISTER:%[a-z]+]] +// CHECK-NEXT: lfence +// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs new file mode 100644 index 000000000..a21ef6b75 --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs @@ -0,0 +1,12 @@ +// Test LVI ret hardening on generic rust code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#[no_mangle] +pub extern fn myret() {} +// CHECK: myret: +// CHECK: popq [[REGISTER:%[a-z]+]] +// CHECK-NEXT: lfence +// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs new file mode 100644 index 000000000..c316379d5 --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs @@ -0,0 +1,43 @@ +// Test LVI load hardening on SGX inline assembly code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +use std::arch::asm; + +#[no_mangle] +pub extern "C" fn get(ptr: *const u64) -> u64 { + let value: u64; + unsafe { + asm!(".start_inline_asm:", + "mov {}, [{}]", + ".end_inline_asm:", + out(reg) value, + in(reg) ptr); + } + value +} + +// CHECK: get +// CHECK: .start_inline_asm +// CHECK-NEXT: movq +// CHECK-NEXT: lfence +// CHECK-NEXT: .end_inline_asm + +#[no_mangle] +pub extern "C" fn myret() { + unsafe { + asm!( + ".start_myret_inline_asm:", + "ret", + ".end_myret_inline_asm:", + ); + } +} + +// CHECK: myret +// CHECK: .start_myret_inline_asm +// CHECK-NEXT: shlq $0, (%rsp) +// CHECK-NEXT: lfence +// CHECK-NEXT: retq diff --git a/src/test/assembly/x86_64-naked-fn-no-cet-prolog.rs b/src/test/assembly/x86_64-naked-fn-no-cet-prolog.rs new file mode 100644 index 000000000..bedcded73 --- /dev/null +++ b/src/test/assembly/x86_64-naked-fn-no-cet-prolog.rs @@ -0,0 +1,24 @@ +// compile-flags: -C no-prepopulate-passes -Zcf-protection=full +// assembly-output: emit-asm +// needs-asm-support +// only-x86_64 + +#![crate_type = "lib"] +#![feature(naked_functions)] +use std::arch::asm; + +// The problem at hand: Rust has adopted a fairly strict meaning for "naked functions", +// meaning "no prologue whatsoever, no, really, not one instruction." +// Unfortunately, x86's control-flow enforcement, specifically indirect branch protection, +// works by using an instruction for each possible landing site, +// and LLVM implements this via making sure of that. +#[no_mangle] +#[naked] +pub unsafe extern "sysv64" fn will_halt() -> ! { + // CHECK-NOT: endbr{{32|64}} + // CHECK: hlt + asm!("hlt", options(noreturn)) +} + +// what about aarch64? +// "branch-protection"=false diff --git a/src/test/assembly/x86_64-sse_crc.rs b/src/test/assembly/x86_64-sse_crc.rs new file mode 100644 index 000000000..cdbf057b8 --- /dev/null +++ b/src/test/assembly/x86_64-sse_crc.rs @@ -0,0 +1,12 @@ +// only-x86_64 +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib -Ctarget-feature=+sse4.2 + +// CHECK-LABEL: banana +// CHECK: crc32 +#[no_mangle] +pub unsafe fn banana(v: u8) -> u32 { + use std::arch::x86_64::*; + let out = !0u32; + _mm_crc32_u8(out, v) +} |