From 62d5784a8f5aa8995b42b6fb5b0b2ffa4f8d69bb Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 1 Mar 2020 09:52:04 +0000 Subject: Add RISC-V target features --- src/test/ui/target-feature/gate.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'src/test') diff --git a/src/test/ui/target-feature/gate.rs b/src/test/ui/target-feature/gate.rs index 2d51cab675e..f738c16673d 100644 --- a/src/test/ui/target-feature/gate.rs +++ b/src/test/ui/target-feature/gate.rs @@ -25,6 +25,7 @@ // gate-test-movbe_target_feature // gate-test-rtm_target_feature // gate-test-f16c_target_feature +// gate-test-riscv_target_feature #[target_feature(enable = "avx512bw")] //~^ ERROR: currently unstable -- cgit 1.4.1-3-g733a5 From 8ab0f2d3c5a85563b98c4896116e3d53154fff9c Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 20 Feb 2020 09:19:48 +0000 Subject: Add tests for asm! --- src/test/assembly/asm/aarch64-modifiers.rs | 144 +++++ src/test/assembly/asm/aarch64-types.rs | 380 +++++++++++ src/test/assembly/asm/arm-modifiers.rs | 149 +++++ src/test/assembly/asm/arm-types.rs | 413 ++++++++++++ src/test/assembly/asm/riscv-modifiers.rs | 58 ++ src/test/assembly/asm/riscv-types.rs | 134 ++++ src/test/assembly/asm/x86-modifiers.rs | 210 ++++++ src/test/assembly/asm/x86-types.rs | 701 +++++++++++++++++++++ src/test/codegen/asm-options.rs | 96 +++ src/test/pretty/asm-clobbers.rs | 3 - src/test/pretty/asm-options.rs | 11 - src/test/pretty/asm.pp | 25 + src/test/pretty/asm.rs | 19 + src/test/pretty/llvm-asm-clobbers.rs | 3 + src/test/pretty/llvm-asm-options.rs | 11 + src/test/ui/asm-concat-src.rs | 9 - src/test/ui/asm-in-moved.rs | 31 - src/test/ui/asm-in-out-operand.rs | 56 -- src/test/ui/asm-indirect-memory.rs | 43 -- src/test/ui/asm-out-assign.rs | 25 - src/test/ui/asm/bad-options.rs | 18 + src/test/ui/asm/bad-options.stderr | 32 + src/test/ui/asm/bad-reg.rs | 57 ++ src/test/ui/asm/bad-reg.stderr | 148 +++++ src/test/ui/asm/bad-template.rs | 26 + src/test/ui/asm/bad-template.stderr | 86 +++ src/test/ui/asm/noreturn.rs | 17 + src/test/ui/asm/parse-error.rs | 53 ++ src/test/ui/asm/parse-error.stderr | 146 +++++ src/test/ui/asm/rustfix-asm.fixed | 16 + src/test/ui/asm/rustfix-asm.rs | 16 + src/test/ui/asm/rustfix-asm.stderr | 18 + src/test/ui/asm/type-check-1.rs | 25 + src/test/ui/asm/type-check-1.stderr | 45 ++ src/test/ui/asm/type-check-2.rs | 104 +++ src/test/ui/asm/type-check-2.stderr | 133 ++++ src/test/ui/asm/type-check-3.rs | 68 ++ src/test/ui/asm/type-check-3.stderr | 123 ++++ src/test/ui/feature-gates/feature-gate-asm.rs | 1 - src/test/ui/feature-gates/feature-gate-asm.stderr | 12 +- src/test/ui/feature-gates/feature-gate-asm2.rs | 1 - src/test/ui/feature-gates/feature-gate-asm2.stderr | 12 +- src/test/ui/llvm-asm/llvm-asm-concat-src.rs | 9 + src/test/ui/llvm-asm/llvm-asm-in-moved.rs | 31 + src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs | 56 ++ src/test/ui/llvm-asm/llvm-asm-indirect-memory.rs | 43 ++ src/test/ui/llvm-asm/llvm-asm-out-assign.rs | 25 + .../ui/macros/macro-expanded-include/foo/mod.rs | 2 +- src/test/ui/macros/macro-expanded-include/test.rs | 2 +- src/test/ui/macros/macros-nonfatal-errors.rs | 3 +- src/test/ui/macros/macros-nonfatal-errors.stderr | 34 +- src/test/ui/target-feature/gate.stderr | 2 +- 52 files changed, 3667 insertions(+), 218 deletions(-) create mode 100644 src/test/assembly/asm/aarch64-modifiers.rs create mode 100644 src/test/assembly/asm/aarch64-types.rs create mode 100644 src/test/assembly/asm/arm-modifiers.rs create mode 100644 src/test/assembly/asm/arm-types.rs create mode 100644 src/test/assembly/asm/riscv-modifiers.rs create mode 100644 src/test/assembly/asm/riscv-types.rs create mode 100644 src/test/assembly/asm/x86-modifiers.rs create mode 100644 src/test/assembly/asm/x86-types.rs create mode 100644 src/test/codegen/asm-options.rs delete mode 100644 src/test/pretty/asm-clobbers.rs delete mode 100644 src/test/pretty/asm-options.rs create mode 100644 src/test/pretty/asm.pp create mode 100644 src/test/pretty/asm.rs create mode 100644 src/test/pretty/llvm-asm-clobbers.rs create mode 100644 src/test/pretty/llvm-asm-options.rs delete mode 100644 src/test/ui/asm-concat-src.rs delete mode 100644 src/test/ui/asm-in-moved.rs delete mode 100644 src/test/ui/asm-in-out-operand.rs delete mode 100644 src/test/ui/asm-indirect-memory.rs delete mode 100644 src/test/ui/asm-out-assign.rs create mode 100644 src/test/ui/asm/bad-options.rs create mode 100644 src/test/ui/asm/bad-options.stderr create mode 100644 src/test/ui/asm/bad-reg.rs create mode 100644 src/test/ui/asm/bad-reg.stderr create mode 100644 src/test/ui/asm/bad-template.rs create mode 100644 src/test/ui/asm/bad-template.stderr create mode 100644 src/test/ui/asm/noreturn.rs create mode 100644 src/test/ui/asm/parse-error.rs create mode 100644 src/test/ui/asm/parse-error.stderr create mode 100644 src/test/ui/asm/rustfix-asm.fixed create mode 100644 src/test/ui/asm/rustfix-asm.rs create mode 100644 src/test/ui/asm/rustfix-asm.stderr create mode 100644 src/test/ui/asm/type-check-1.rs create mode 100644 src/test/ui/asm/type-check-1.stderr create mode 100644 src/test/ui/asm/type-check-2.rs create mode 100644 src/test/ui/asm/type-check-2.stderr create mode 100644 src/test/ui/asm/type-check-3.rs create mode 100644 src/test/ui/asm/type-check-3.stderr create mode 100644 src/test/ui/llvm-asm/llvm-asm-concat-src.rs create mode 100644 src/test/ui/llvm-asm/llvm-asm-in-moved.rs create mode 100644 src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs create mode 100644 src/test/ui/llvm-asm/llvm-asm-indirect-memory.rs create mode 100644 src/test/ui/llvm-asm/llvm-asm-out-assign.rs (limited to 'src/test') diff --git a/src/test/assembly/asm/aarch64-modifiers.rs b/src/test/assembly/asm/aarch64-modifiers.rs new file mode 100644 index 00000000000..d4519ca7ffa --- /dev/null +++ b/src/test/assembly/asm/aarch64-modifiers.rs @@ -0,0 +1,144 @@ +// assembly-output: emit-asm +// compile-flags: -O +// compile-flags: --target aarch64-unknown-linux-gnu + +#![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-types.rs b/src/test/assembly/asm/aarch64-types.rs new file mode 100644 index 00000000000..8b763462e4a --- /dev/null +++ b/src/test/assembly/asm/aarch64-types.rs @@ -0,0 +1,380 @@ +// assembly-output: emit-asm +// compile-flags: --target aarch64-unknown-linux-gnu + +#![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 {} + +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); +} + +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 + } + }; +} + +// 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"); diff --git a/src/test/assembly/asm/arm-modifiers.rs b/src/test/assembly/asm/arm-modifiers.rs new file mode 100644 index 00000000000..cefab9c4a67 --- /dev/null +++ b/src/test/assembly/asm/arm-modifiers.rs @@ -0,0 +1,149 @@ +// assembly-output: emit-asm +// compile-flags: -O +// compile-flags: --target armv7-unknown-linux-gnueabihf +// compile-flags: -C target-feature=+neon + +#![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: reg_thumb: +// CHECK: @APP +// CHECK: mov r0, r0 +// CHECK: @NO_APP +check!(reg_thumb "" reg_thumb 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 00000000000..729adae66f6 --- /dev/null +++ b/src/test/assembly/asm/arm-types.rs @@ -0,0 +1,413 @@ +// assembly-output: emit-asm +// compile-flags: --target armv7-unknown-linux-gnueabihf +// compile-flags: -C target-feature=+neon + +#![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 {} + +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); +} + +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 + } + }; +} + +// 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: reg_thumb_i8: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_thumb_i8 i8 reg_thumb "mov"); + +// CHECK-LABEL: reg_thumb_i16: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_thumb_i16 i16 reg_thumb "mov"); + +// CHECK-LABEL: reg_thumb_i32: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_thumb_i32 i32 reg_thumb "mov"); + +// CHECK-LABEL: reg_thumb_f32: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_thumb_f32 f32 reg_thumb "mov"); + +// CHECK-LABEL: reg_thumb_ptr: +// CHECK: @APP +// CHECK: mov {{[a-z0-9]+}}, {{[a-z0-9]+}} +// CHECK: @NO_APP +check!(reg_thumb_ptr ptr reg_thumb "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"); diff --git a/src/test/assembly/asm/riscv-modifiers.rs b/src/test/assembly/asm/riscv-modifiers.rs new file mode 100644 index 00000000000..622d0c0dc5e --- /dev/null +++ b/src/test/assembly/asm/riscv-modifiers.rs @@ -0,0 +1,58 @@ +// assembly-output: emit-asm +// compile-flags: -O +// compile-flags: --target riscv64gc-unknown-linux-gnu +// compile-flags: -C target-feature=+f + +#![feature(no_core, lang_items, rustc_attrs)] +#![crate_type = "rlib"] +#![no_core] + +#[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 f32 {} + +macro_rules! check { + ($func:ident $modifier:literal $reg: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() -> f32 { + // 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: mv a0, a0 +// CHECK: #NO_APP +check!(reg "" reg "mv"); + +// CHECK-LABEL: freg: +// CHECK: #APP +// CHECK: fmv.s fa0, fa0 +// CHECK: #NO_APP +check!(freg "" freg "fmv.s"); diff --git a/src/test/assembly/asm/riscv-types.rs b/src/test/assembly/asm/riscv-types.rs new file mode 100644 index 00000000000..5c10753c765 --- /dev/null +++ b/src/test/assembly/asm/riscv-types.rs @@ -0,0 +1,134 @@ +// revisions: riscv64 riscv32 +// assembly-output: emit-asm +//[riscv64] compile-flags: --target riscv64imac-unknown-none-elf +//[riscv32] compile-flags: --target riscv32imac-unknown-none-elf +// compile-flags: -C target-feature=+d + +#![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 {} + +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: lb t0, extern_static +// 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 + } + }; +} + +// 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"); diff --git a/src/test/assembly/asm/x86-modifiers.rs b/src/test/assembly/asm/x86-modifiers.rs new file mode 100644 index 00000000000..460e22aa69e --- /dev/null +++ b/src/test/assembly/asm/x86-modifiers.rs @@ -0,0 +1,210 @@ +// revisions: x86_64 i686 +// assembly-output: emit-asm +// compile-flags: -O +//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//[i686] compile-flags: --target i686-unknown-linux-gnu +// 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"); + +// x86_64-LABEL: reg_h: +// x86_64: #APP +// x86_64: mov ah, ah +// x86_64: #NO_APP +#[cfg(x86_64)] +check!(reg_h "h" 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 00000000000..d2819ac88e7 --- /dev/null +++ b/src/test/assembly/asm/x86-types.rs @@ -0,0 +1,701 @@ +// revisions: x86_64 i686 +// assembly-output: emit-asm +//[x86_64] compile-flags: --target x86_64-unknown-linux-gnu +//[i686] compile-flags: --target i686-unknown-linux-gnu +// compile-flags: -C llvm-args=--x86-asm-syntax=intel +// compile-flags: -C target-feature=+avx512bw + +#![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 {} + +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, " {}, {}"), out($class) y, in($class) x); + y + } + }; +} + +// CHECK-LABEL: reg_i8: +// 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_i8 i8 reg "mov"); + +// 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_i8: +// 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_i8 i8 reg_abcd "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: 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"); diff --git a/src/test/codegen/asm-options.rs b/src/test/codegen/asm-options.rs new file mode 100644 index 00000000000..21e7eb43796 --- /dev/null +++ b/src/test/codegen/asm-options.rs @@ -0,0 +1,96 @@ +// compile-flags: -O +// only-x86_64 + +#![crate_type = "rlib"] +#![feature(asm)] + +// CHECK-LABEL: @pure +// CHECK-NOT: asm +// CHECK: ret void +#[no_mangle] +pub unsafe fn pure(x: i32) { + let y: i32; + asm!("", out("ax") y, in("bx") x, options(pure, nomem)); +} + +// CHECK-LABEL: @noreturn +// CHECK: call void asm +// CHECK-NEXT: unreachable +#[no_mangle] +pub unsafe fn noreturn() { + asm!("", options(noreturn)); +} + +pub static mut VAR: i32 = 0; +pub static mut DUMMY_OUTPUT: i32 = 0; + +// CHECK-LABEL: @readonly +// CHECK: call i32 asm +// CHECK: ret i32 1 +#[no_mangle] +pub unsafe fn readonly() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure, readonly)); + VAR +} + +// CHECK-LABEL: @not_readonly +// CHECK: call i32 asm +// CHECK: ret i32 % +#[no_mangle] +pub unsafe fn not_readonly() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options()); + VAR +} + +// CHECK-LABEL: @nomem +// CHECK-NOT: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn nomem() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure, nomem)); + VAR = 2; + VAR +} + +// CHECK-LABEL: @nomem_nopure +// CHECK-NOT: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn nomem_nopure() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(nomem)); + VAR = 2; + VAR +} + +// CHECK-LABEL: @not_nomem +// CHECK: store +// CHECK: call i32 asm +// CHECK: store +// CHECK: ret i32 2 +#[no_mangle] +pub unsafe fn not_nomem() -> i32 { + VAR = 1; + asm!("", out("ax") DUMMY_OUTPUT, options(pure, readonly)); + VAR = 2; + VAR +} + +// CHECK-LABEL: @dont_remove_nonpure +// CHECK: call void asm +// CHECK: call void asm +// CHECK: call void asm +// CHECK: ret void +#[no_mangle] +pub unsafe fn dont_remove_nonpure() { + asm!("", options()); + asm!("", options(nomem)); + asm!("", options(readonly)); +} diff --git a/src/test/pretty/asm-clobbers.rs b/src/test/pretty/asm-clobbers.rs deleted file mode 100644 index 2c09646e47e..00000000000 --- a/src/test/pretty/asm-clobbers.rs +++ /dev/null @@ -1,3 +0,0 @@ -#![feature(llvm_asm)] - -pub fn main() { unsafe { llvm_asm!("" : : : "hello", "world") }; } diff --git a/src/test/pretty/asm-options.rs b/src/test/pretty/asm-options.rs deleted file mode 100644 index 86a881bfbd1..00000000000 --- a/src/test/pretty/asm-options.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(llvm_asm)] - -// pp-exact - -pub fn main() { - unsafe { - llvm_asm!("" : : : : "volatile"); - llvm_asm!("" : : : : "alignstack"); - llvm_asm!("" : : : : "intel"); - } -} diff --git a/src/test/pretty/asm.pp b/src/test/pretty/asm.pp new file mode 100644 index 00000000000..1723e1cc1cb --- /dev/null +++ b/src/test/pretty/asm.pp @@ -0,0 +1,25 @@ +#![feature(prelude_import)] +#![no_std] +#![feature(asm)] +#[prelude_import] +use ::std::prelude::v1::*; +#[macro_use] +extern crate std; + +// pretty-mode:expanded +// pp-exact:asm.pp + +pub fn main() { + let a: i32; + let mut b = 4i32; + unsafe { + asm!(""); + asm!(""); + asm!("", options(nomem, nostack)); + asm!("{0}", in(reg) 4); + asm!("{0}", out(reg) a); + asm!("{0}", inout(reg) b); + asm!("{0} {1}", out(reg) _, inlateout(reg) b => _); + asm!("", out("al") _, lateout("rbx") _); + } +} diff --git a/src/test/pretty/asm.rs b/src/test/pretty/asm.rs new file mode 100644 index 00000000000..9812f1d97e5 --- /dev/null +++ b/src/test/pretty/asm.rs @@ -0,0 +1,19 @@ +#![feature(asm)] + +// pretty-mode:expanded +// pp-exact:asm.pp + +pub fn main() { + let a: i32; + let mut b = 4i32; + unsafe { + asm!(""); + asm!("", options()); + asm!("", options(nostack, nomem)); + asm!("{}", in(reg) 4); + asm!("{0}", out(reg) a); + asm!("{name}", name = inout(reg) b); + asm!("{} {}", out(reg) _, inlateout(reg) b => _); + asm!("", out("al") _, lateout("rbx") _); + } +} diff --git a/src/test/pretty/llvm-asm-clobbers.rs b/src/test/pretty/llvm-asm-clobbers.rs new file mode 100644 index 00000000000..2c09646e47e --- /dev/null +++ b/src/test/pretty/llvm-asm-clobbers.rs @@ -0,0 +1,3 @@ +#![feature(llvm_asm)] + +pub fn main() { unsafe { llvm_asm!("" : : : "hello", "world") }; } diff --git a/src/test/pretty/llvm-asm-options.rs b/src/test/pretty/llvm-asm-options.rs new file mode 100644 index 00000000000..86a881bfbd1 --- /dev/null +++ b/src/test/pretty/llvm-asm-options.rs @@ -0,0 +1,11 @@ +#![feature(llvm_asm)] + +// pp-exact + +pub fn main() { + unsafe { + llvm_asm!("" : : : : "volatile"); + llvm_asm!("" : : : : "alignstack"); + llvm_asm!("" : : : : "intel"); + } +} diff --git a/src/test/ui/asm-concat-src.rs b/src/test/ui/asm-concat-src.rs deleted file mode 100644 index 1dc1c859c6b..00000000000 --- a/src/test/ui/asm-concat-src.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass -// pretty-expanded FIXME #23616 -// ignore-emscripten no asm - -#![feature(llvm_asm)] - -pub fn main() { - unsafe { llvm_asm!(concat!("", "")) }; -} diff --git a/src/test/ui/asm-in-moved.rs b/src/test/ui/asm-in-moved.rs deleted file mode 100644 index 35f4d92c8ff..00000000000 --- a/src/test/ui/asm-in-moved.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -#![feature(llvm_asm)] -#![allow(dead_code)] - -use std::cell::Cell; - -#[repr(C)] -struct NoisyDrop<'a>(&'a Cell<&'static str>); -impl<'a> Drop for NoisyDrop<'a> { - fn drop(&mut self) { - self.0.set("destroyed"); - } -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn main() { - let status = Cell::new("alive"); - { - let _y: Box; - let x = Box::new(NoisyDrop(&status)); - unsafe { - llvm_asm!("mov $1, $0" : "=r"(_y) : "r"(x)); - } - assert_eq!(status.get(), "alive"); - } - assert_eq!(status.get(), "destroyed"); -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -fn main() {} diff --git a/src/test/ui/asm-in-out-operand.rs b/src/test/ui/asm-in-out-operand.rs deleted file mode 100644 index acefabd8a66..00000000000 --- a/src/test/ui/asm-in-out-operand.rs +++ /dev/null @@ -1,56 +0,0 @@ -// run-pass - -#![feature(llvm_asm)] - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -unsafe fn next_power_of_2(n: u32) -> u32 { - let mut tmp = n; - llvm_asm!("dec $0" : "+rm"(tmp) :: "cc"); - let mut shift = 1_u32; - while shift <= 16 { - llvm_asm!( - "shr %cl, $2 - or $2, $0 - shl $$1, $1" - : "+&rm"(tmp), "+{ecx}"(shift) : "r"(tmp) : "cc" - ); - } - llvm_asm!("inc $0" : "+rm"(tmp) :: "cc"); - return tmp; -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub fn main() { - unsafe { - assert_eq!(64, next_power_of_2(37)); - assert_eq!(2147483648, next_power_of_2(2147483647)); - } - - let mut y: isize = 5; - let x: isize; - unsafe { - // Treat the output as initialization. - llvm_asm!( - "shl $2, $1 - add $3, $1 - mov $1, $0" - : "=r"(x), "+r"(y) : "i"(3_usize), "ir"(7_usize) : "cc" - ); - } - assert_eq!(x, 47); - assert_eq!(y, 47); - - let mut x = x + 1; - assert_eq!(x, 48); - - unsafe { - // Assignment to mutable. - // Early clobber "&": - // Forbids the use of a single register by both operands. - llvm_asm!("shr $$2, $1; add $1, $0" : "+&r"(x) : "r"(x) : "cc"); - } - assert_eq!(x, 60); -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -pub fn main() {} diff --git a/src/test/ui/asm-indirect-memory.rs b/src/test/ui/asm-indirect-memory.rs deleted file mode 100644 index 556ad83a4ea..00000000000 --- a/src/test/ui/asm-indirect-memory.rs +++ /dev/null @@ -1,43 +0,0 @@ -// run-pass - -#![feature(llvm_asm)] - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn read(ptr: &u32) -> u32 { - let out: u32; - unsafe { - llvm_asm!("mov $1, $0" : "=r" (out) : "*m" (ptr)); - } - out -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn write(ptr: &mut u32, val: u32) { - unsafe { - llvm_asm!("mov $1, $0" : "=*m" (ptr) : "r" (val)); - } -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -fn replace(ptr: &mut u32, val: u32) -> u32 { - let out: u32; - unsafe { - llvm_asm!("mov $0, $1; mov $2, $0" : "+*m" (ptr), "=&r" (out) : "r" (val)); - } - out -} - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub fn main() { - let a = 1; - assert_eq!(read(&a), 1); - let mut b = 2; - write(&mut b, 3); - assert_eq!(b, 3); - let mut c = 4; - assert_eq!(replace(&mut c, 5), 4); - assert_eq!(c, 5); -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -pub fn main() {} diff --git a/src/test/ui/asm-out-assign.rs b/src/test/ui/asm-out-assign.rs deleted file mode 100644 index 321f28565ff..00000000000 --- a/src/test/ui/asm-out-assign.rs +++ /dev/null @@ -1,25 +0,0 @@ -// run-pass - -#![feature(llvm_asm)] - -#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] -pub fn main() { - let x: isize; - unsafe { - // Treat the output as initialization. - llvm_asm!("mov $1, $0" : "=r"(x) : "r"(5_usize)); - } - assert_eq!(x, 5); - - let mut x = x + 1; - assert_eq!(x, 6); - - unsafe { - // Assignment to mutable. - llvm_asm!("mov $1, $0" : "=r"(x) : "r"(x + 7)); - } - assert_eq!(x, 13); -} - -#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] -pub fn main() {} diff --git a/src/test/ui/asm/bad-options.rs b/src/test/ui/asm/bad-options.rs new file mode 100644 index 00000000000..755fc2ca238 --- /dev/null +++ b/src/test/ui/asm/bad-options.rs @@ -0,0 +1,18 @@ +// only-x86_64 + +#![feature(asm)] + +fn main() { + let mut foo = 0; + unsafe { + asm!("", options(nomem, readonly)); + //~^ ERROR the `nomem` and `readonly` options are mutually exclusive + asm!("", options(pure, nomem, noreturn)); + //~^ ERROR the `pure` and `noreturn` options are mutually exclusive + //~^^ ERROR asm with `pure` option must have at least one output + asm!("{}", in(reg) foo, options(pure, nomem)); + //~^ ERROR asm with `pure` option must have at least one output + asm!("{}", out(reg) foo, options(noreturn)); + //~^ ERROR asm outputs are not allowed with the `noreturn` option + } +} diff --git a/src/test/ui/asm/bad-options.stderr b/src/test/ui/asm/bad-options.stderr new file mode 100644 index 00000000000..c5e8e2ccf44 --- /dev/null +++ b/src/test/ui/asm/bad-options.stderr @@ -0,0 +1,32 @@ +error: the `nomem` and `readonly` options are mutually exclusive + --> $DIR/bad-options.rs:8:18 + | +LL | asm!("", options(nomem, readonly)); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + +error: the `pure` and `noreturn` options are mutually exclusive + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with `pure` option must have at least one output + --> $DIR/bad-options.rs:10:18 + | +LL | asm!("", options(pure, nomem, noreturn)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: asm with `pure` option must have at least one output + --> $DIR/bad-options.rs:13:33 + | +LL | asm!("{}", in(reg) foo, options(pure, nomem)); + | ^^^^^^^^^^^^^^^^^^^^ + +error: asm outputs are not allowed with the `noreturn` option + --> $DIR/bad-options.rs:15:20 + | +LL | asm!("{}", out(reg) foo, options(noreturn)); + | ^^^^^^^^^^^^ + +error: aborting due to 5 previous errors + diff --git a/src/test/ui/asm/bad-reg.rs b/src/test/ui/asm/bad-reg.rs new file mode 100644 index 00000000000..ed7faa4b156 --- /dev/null +++ b/src/test/ui/asm/bad-reg.rs @@ -0,0 +1,57 @@ +// only-x86_64 +// compile-flags: -C target-feature=+avx2 + +#![feature(asm)] + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + // Bad register/register class + + asm!("{}", in(foo) foo); + //~^ ERROR invalid register class `foo`: unknown register class + asm!("", in("foo") foo); + //~^ ERROR invalid register `foo`: unknown register + asm!("{:z}", in(reg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:r}", in(xmm_reg) foo); + //~^ ERROR invalid asm template modifier for this register class + asm!("{:a}", const 0); + //~^ ERROR asm template modifiers are not allowed for `const` arguments + asm!("{:a}", sym main); + //~^ ERROR asm template modifiers are not allowed for `sym` arguments + asm!("{}", in(zmm_reg) foo); + //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature + asm!("", in("zmm0") foo); + //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature + asm!("", in("ah") foo); + //~^ ERROR invalid register `ah`: high byte registers are not currently supported + asm!("", in("ebp") foo); + //~^ ERROR invalid register `ebp`: the frame pointer cannot be used as an operand + asm!("", in("rsp") foo); + //~^ ERROR invalid register `rsp`: the stack pointer cannot be used as an operand + asm!("", in("ip") foo); + //~^ ERROR invalid register `ip`: the instruction pointer cannot be used as an operand + asm!("", in("st(2)") foo); + //~^ ERROR invalid register `st(2)`: x87 registers are not currently supported as operands + asm!("", in("mm0") foo); + //~^ ERROR invalid register `mm0`: MMX registers are not currently supported as operands + asm!("", in("k0") foo); + //~^ ERROR invalid register `k0`: the k0 AVX mask register cannot be used as an operand + + // Explicit register conflicts + // (except in/lateout which don't conflict) + + asm!("", in("eax") foo, in("al") bar); + //~^ ERROR register `ax` conflicts with register `ax` + asm!("", in("rax") foo, out("rax") bar); + //~^ ERROR register `ax` conflicts with register `ax` + asm!("", in("al") foo, lateout("al") bar); + asm!("", in("xmm0") foo, in("ymm0") bar); + //~^ ERROR register `ymm0` conflicts with register `xmm0` + asm!("", in("xmm0") foo, out("ymm0") bar); + //~^ ERROR register `ymm0` conflicts with register `xmm0` + asm!("", in("xmm0") foo, lateout("ymm0") bar); + } +} diff --git a/src/test/ui/asm/bad-reg.stderr b/src/test/ui/asm/bad-reg.stderr new file mode 100644 index 00000000000..a9d872dae41 --- /dev/null +++ b/src/test/ui/asm/bad-reg.stderr @@ -0,0 +1,148 @@ +error: invalid register class `foo`: unknown register class + --> $DIR/bad-reg.rs:12:20 + | +LL | asm!("{}", in(foo) foo); + | ^^^^^^^^^^^ + +error: invalid register `foo`: unknown register + --> $DIR/bad-reg.rs:14:18 + | +LL | asm!("", in("foo") foo); + | ^^^^^^^^^^^^^ + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:16:15 + | +LL | asm!("{:z}", in(reg) foo); + | ^^^^ ----------- argument + | | + | template modifier + | + = note: the `reg` register class supports the following template modifiers: `l`, `h`, `x`, `e`, `r` + +error: invalid asm template modifier for this register class + --> $DIR/bad-reg.rs:18:15 + | +LL | asm!("{:r}", in(xmm_reg) foo); + | ^^^^ --------------- argument + | | + | template modifier + | + = note: the `xmm_reg` register class supports the following template modifiers: `x`, `y`, `z` + +error: asm template modifiers are not allowed for `const` arguments + --> $DIR/bad-reg.rs:20:15 + | +LL | asm!("{:a}", const 0); + | ^^^^ ------- argument + | | + | template modifier + +error: asm template modifiers are not allowed for `sym` arguments + --> $DIR/bad-reg.rs:22:15 + | +LL | asm!("{:a}", sym main); + | ^^^^ -------- argument + | | + | template modifier + +error: register class `zmm_reg` requires the `avx512f` target feature + --> $DIR/bad-reg.rs:24:20 + | +LL | asm!("{}", in(zmm_reg) foo); + | ^^^^^^^^^^^^^^^ + +error: register class `zmm_reg` requires the `avx512f` target feature + --> $DIR/bad-reg.rs:26:18 + | +LL | asm!("", in("zmm0") foo); + | ^^^^^^^^^^^^^^ + +error: invalid register `ah`: high byte registers are not currently supported as operands for inline asm + --> $DIR/bad-reg.rs:28:18 + | +LL | asm!("", in("ah") foo); + | ^^^^^^^^^^^^ + +error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:30:18 + | +LL | asm!("", in("ebp") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:32:18 + | +LL | asm!("", in("rsp") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:34:18 + | +LL | asm!("", in("ip") foo); + | ^^^^^^^^^^^^ + +error: invalid register `st(2)`: x87 registers are not currently supported as operands for inline asm + --> $DIR/bad-reg.rs:36:18 + | +LL | asm!("", in("st(2)") foo); + | ^^^^^^^^^^^^^^^ + +error: invalid register `mm0`: MMX registers are not currently supported as operands for inline asm + --> $DIR/bad-reg.rs:38:18 + | +LL | asm!("", in("mm0") foo); + | ^^^^^^^^^^^^^ + +error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:40:18 + | +LL | asm!("", in("k0") foo); + | ^^^^^^^^^^^^ + +error: register `ax` conflicts with register `ax` + --> $DIR/bad-reg.rs:46:33 + | +LL | asm!("", in("eax") foo, in("al") bar); + | ------------- ^^^^^^^^^^^^ register `ax` + | | + | register `ax` + +error: register `ax` conflicts with register `ax` + --> $DIR/bad-reg.rs:48:33 + | +LL | asm!("", in("rax") foo, out("rax") bar); + | ------------- ^^^^^^^^^^^^^^ register `ax` + | | + | register `ax` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:48:18 + | +LL | asm!("", in("rax") foo, out("rax") bar); + | ^^^^^^^^^^^^^ + +error: register `ymm0` conflicts with register `xmm0` + --> $DIR/bad-reg.rs:51:34 + | +LL | asm!("", in("xmm0") foo, in("ymm0") bar); + | -------------- ^^^^^^^^^^^^^^ register `ymm0` + | | + | register `xmm0` + +error: register `ymm0` conflicts with register `xmm0` + --> $DIR/bad-reg.rs:53:34 + | +LL | asm!("", in("xmm0") foo, out("ymm0") bar); + | -------------- ^^^^^^^^^^^^^^^ register `ymm0` + | | + | register `xmm0` + | +help: use `lateout` instead of `out` to avoid conflict + --> $DIR/bad-reg.rs:53:18 + | +LL | asm!("", in("xmm0") foo, out("ymm0") bar); + | ^^^^^^^^^^^^^^ + +error: aborting due to 19 previous errors + diff --git a/src/test/ui/asm/bad-template.rs b/src/test/ui/asm/bad-template.rs new file mode 100644 index 00000000000..0b333eca1ab --- /dev/null +++ b/src/test/ui/asm/bad-template.rs @@ -0,0 +1,26 @@ +// only-x86_64 + +#![feature(asm)] + +fn main() { + let mut foo = 0; + unsafe { + asm!("{}"); + //~^ ERROR invalid reference to argument at index 0 + asm!("{1}", in(reg) foo); + //~^ ERROR invalid reference to argument at index 1 + //~^^ ERROR argument never used + asm!("{a}"); + //~^ ERROR there is no argument named `a` + asm!("{}", a = in(reg) foo); + //~^ ERROR invalid reference to argument at index 0 + //~^^ ERROR argument never used + asm!("{1}", a = in(reg) foo); + //~^ ERROR invalid reference to argument at index 1 + //~^^ ERROR named argument never used + asm!("{}", in("eax") foo); + //~^ ERROR invalid reference to argument at index 0 + asm!("{:foo}", in(reg) foo); + //~^ ERROR asm template modifier must be a single character + } +} diff --git a/src/test/ui/asm/bad-template.stderr b/src/test/ui/asm/bad-template.stderr new file mode 100644 index 00000000000..2de76ef8241 --- /dev/null +++ b/src/test/ui/asm/bad-template.stderr @@ -0,0 +1,86 @@ +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:8:15 + | +LL | asm!("{}"); + | ^^ from here + | + = note: no arguments were given + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:10:15 + | +LL | asm!("{1}", in(reg) foo); + | ^^^ from here + | + = note: there is 1 argument + +error: argument never used + --> $DIR/bad-template.rs:10:21 + | +LL | asm!("{1}", in(reg) foo); + | ^^^^^^^^^^^ argument never used + +error: there is no argument named `a` + --> $DIR/bad-template.rs:13:15 + | +LL | asm!("{a}"); + | ^^^ + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:15:15 + | +LL | asm!("{}", a = in(reg) foo); + | ^^ --------------- named argument + | | + | from here + | + = note: no positional arguments were given +note: named arguments cannot be referenced by position + --> $DIR/bad-template.rs:15:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ + +error: named argument never used + --> $DIR/bad-template.rs:15:20 + | +LL | asm!("{}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + +error: invalid reference to argument at index 1 + --> $DIR/bad-template.rs:18:15 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^ from here + | + = note: no positional arguments were given + +error: named argument never used + --> $DIR/bad-template.rs:18:21 + | +LL | asm!("{1}", a = in(reg) foo); + | ^^^^^^^^^^^^^^^ named argument never used + +error: invalid reference to argument at index 0 + --> $DIR/bad-template.rs:21:15 + | +LL | asm!("{}", in("eax") foo); + | ^^ ------------- explicit register argument + | | + | from here + | + = note: no positional arguments were given +note: explicit register arguments cannot be used in the asm template + --> $DIR/bad-template.rs:21:20 + | +LL | asm!("{}", in("eax") foo); + | ^^^^^^^^^^^^^ + +error: asm template modifier must be a single character + --> $DIR/bad-template.rs:23:17 + | +LL | asm!("{:foo}", in(reg) foo); + | ^^^ + +error: aborting due to 10 previous errors + diff --git a/src/test/ui/asm/noreturn.rs b/src/test/ui/asm/noreturn.rs new file mode 100644 index 00000000000..5e1ee93bfb0 --- /dev/null +++ b/src/test/ui/asm/noreturn.rs @@ -0,0 +1,17 @@ +// only-x86_64 +// check-pass + +#![feature(asm, never_type)] +#![crate_type = "rlib"] + +pub unsafe fn asm1() { + let _: () = asm!(""); +} + +pub unsafe fn asm2() { + let _: ! = asm!("", options(noreturn)); +} + +pub unsafe fn asm3() -> ! { + asm!("", options(noreturn)); +} diff --git a/src/test/ui/asm/parse-error.rs b/src/test/ui/asm/parse-error.rs new file mode 100644 index 00000000000..e6566866b22 --- /dev/null +++ b/src/test/ui/asm/parse-error.rs @@ -0,0 +1,53 @@ +// only-x86_64 + +#![feature(asm)] + +fn main() { + let mut foo = 0; + let mut bar = 0; + unsafe { + asm!(); + //~^ ERROR requires at least a template string argument + asm!(foo); + //~^ ERROR asm template must be a string literal + asm!("{}" foo); + //~^ ERROR expected token: `,` + asm!("{}", foo); + //~^ ERROR expected one of + asm!("{}", in foo); + //~^ ERROR expected `(`, found `foo` + asm!("{}", in(reg foo)); + //~^ ERROR expected `)`, found `foo` + asm!("{}", in(reg)); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", inout(=) foo => bar); + //~^ ERROR expected register class or explicit register + asm!("{}", inout(reg) foo =>); + //~^ ERROR expected expression, found end of macro arguments + asm!("{}", in(reg) foo => bar); + //~^ ERROR expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + asm!("{}", sym foo + bar); + //~^ ERROR argument to `sym` must be a path expression + asm!("", options(foo)); + //~^ ERROR expected one of + asm!("", options(nomem foo)); + //~^ ERROR expected one of + asm!("", options(nomem, foo)); + //~^ ERROR expected one of + asm!("", options(), options()); + //~^ ERROR asm options cannot be specified twice + asm!("{}", options(), const foo); + //~^ ERROR arguments are not allowed after options + asm!("{a}", a = const foo, a = const bar); + //~^ ERROR duplicate argument named `a` + //~^^ ERROR argument never used + asm!("", a = in("eax") foo); + //~^ ERROR explicit register arguments cannot have names + asm!("{a}", in("eax") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + asm!("{a}", in("eax") foo, a = const bar); + //~^ ERROR named arguments cannot follow explicit register arguments + asm!("{1}", in("eax") foo, const bar); + //~^ ERROR positional arguments cannot follow named arguments or explicit register arguments + } +} diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr new file mode 100644 index 00000000000..a927ce13858 --- /dev/null +++ b/src/test/ui/asm/parse-error.stderr @@ -0,0 +1,146 @@ +error: requires at least a template string argument + --> $DIR/parse-error.rs:9:9 + | +LL | asm!(); + | ^^^^^^^ + +error: asm template must be a string literal + --> $DIR/parse-error.rs:11:14 + | +LL | asm!(foo); + | ^^^ + +error: expected token: `,` + --> $DIR/parse-error.rs:13:19 + | +LL | asm!("{}" foo); + | ^^^ expected `,` + +error: expected one of `const`, `in`, `inlateout`, `inout`, `lateout`, `options`, `out`, or `sym`, found `foo` + --> $DIR/parse-error.rs:15:20 + | +LL | asm!("{}", foo); + | ^^^ expected one of 8 possible tokens + +error: expected `(`, found `foo` + --> $DIR/parse-error.rs:17:23 + | +LL | asm!("{}", in foo); + | ^^^ expected `(` + +error: expected `)`, found `foo` + --> $DIR/parse-error.rs:19:27 + | +LL | asm!("{}", in(reg foo)); + | ^^^ expected `)` + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:21:27 + | +LL | asm!("{}", in(reg)); + | ^ expected expression + +error: expected register class or explicit register + --> $DIR/parse-error.rs:23:26 + | +LL | asm!("{}", inout(=) foo => bar); + | ^ + +error: expected expression, found end of macro arguments + --> $DIR/parse-error.rs:25:37 + | +LL | asm!("{}", inout(reg) foo =>); + | ^ expected expression + +error: expected one of `!`, `,`, `.`, `::`, `?`, `{`, or an operator, found `=>` + --> $DIR/parse-error.rs:27:32 + | +LL | asm!("{}", in(reg) foo => bar); + | ^^ expected one of 7 possible tokens + +error: argument to `sym` must be a path expression + --> $DIR/parse-error.rs:29:24 + | +LL | asm!("{}", sym foo + bar); + | ^^^^^^^^^ + +error: expected one of `)`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:31:26 + | +LL | asm!("", options(foo)); + | ^^^ expected one of 7 possible tokens + +error: expected one of `)` or `,`, found `foo` + --> $DIR/parse-error.rs:33:32 + | +LL | asm!("", options(nomem foo)); + | ^^^ expected one of `)` or `,` + +error: expected one of `)`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, or `readonly`, found `foo` + --> $DIR/parse-error.rs:35:33 + | +LL | asm!("", options(nomem, foo)); + | ^^^ expected one of 7 possible tokens + +error: asm options cannot be specified twice + --> $DIR/parse-error.rs:37:29 + | +LL | asm!("", options(), options()); + | --------- ^^^^^^^^^ duplicate options + | | + | previously here + +error: arguments are not allowed after options + --> $DIR/parse-error.rs:39:31 + | +LL | asm!("{}", options(), const foo); + | --------- ^^^^^^^^^ argument + | | + | previous options + +error: duplicate argument named `a` + --> $DIR/parse-error.rs:41:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ duplicate argument + | | + | previously here + +error: argument never used + --> $DIR/parse-error.rs:41:36 + | +LL | asm!("{a}", a = const foo, a = const bar); + | ^^^^^^^^^^^^^ argument never used + +error: explicit register arguments cannot have names + --> $DIR/parse-error.rs:44:18 + | +LL | asm!("", a = in("eax") foo); + | ^^^^^^^^^^^^^^^^^ + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:46:36 + | +LL | asm!("{a}", in("eax") foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: named arguments cannot follow explicit register arguments + --> $DIR/parse-error.rs:48:36 + | +LL | asm!("{a}", in("eax") foo, a = const bar); + | ------------- ^^^^^^^^^^^^^ named argument + | | + | explicit register argument + +error: positional arguments cannot follow named arguments or explicit register arguments + --> $DIR/parse-error.rs:50:36 + | +LL | asm!("{1}", in("eax") foo, const bar); + | ------------- ^^^^^^^^^ positional argument + | | + | explicit register argument + +error: aborting due to 22 previous errors + diff --git a/src/test/ui/asm/rustfix-asm.fixed b/src/test/ui/asm/rustfix-asm.fixed new file mode 100644 index 00000000000..c9271059810 --- /dev/null +++ b/src/test/ui/asm/rustfix-asm.fixed @@ -0,0 +1,16 @@ +// run-rustfix +// only-x86_64 + +#![feature(asm, llvm_asm)] + +fn main() { + unsafe { + let x = 1; + let y: i32; + llvm_asm!("" :: "r" (x)); + //~^ ERROR legacy asm! syntax is no longer supported + llvm_asm!("" : "=r" (y)); + //~^ ERROR legacy asm! syntax is no longer supported + let _ = y; + } +} diff --git a/src/test/ui/asm/rustfix-asm.rs b/src/test/ui/asm/rustfix-asm.rs new file mode 100644 index 00000000000..a108595ca1b --- /dev/null +++ b/src/test/ui/asm/rustfix-asm.rs @@ -0,0 +1,16 @@ +// run-rustfix +// only-x86_64 + +#![feature(asm, llvm_asm)] + +fn main() { + unsafe { + let x = 1; + let y: i32; + asm!("" :: "r" (x)); + //~^ ERROR legacy asm! syntax is no longer supported + asm!("" : "=r" (y)); + //~^ ERROR legacy asm! syntax is no longer supported + let _ = y; + } +} diff --git a/src/test/ui/asm/rustfix-asm.stderr b/src/test/ui/asm/rustfix-asm.stderr new file mode 100644 index 00000000000..28675b51d15 --- /dev/null +++ b/src/test/ui/asm/rustfix-asm.stderr @@ -0,0 +1,18 @@ +error: legacy asm! syntax is no longer supported + --> $DIR/rustfix-asm.rs:10:9 + | +LL | asm!("" :: "r" (x)); + | ----^^^^^^^^^^^^^^^^ + | | + | help: replace with: `llvm_asm!` + +error: legacy asm! syntax is no longer supported + --> $DIR/rustfix-asm.rs:12:9 + | +LL | asm!("" : "=r" (y)); + | ----^^^^^^^^^^^^^^^^ + | | + | help: replace with: `llvm_asm!` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/asm/type-check-1.rs b/src/test/ui/asm/type-check-1.rs new file mode 100644 index 00000000000..7880382c3b7 --- /dev/null +++ b/src/test/ui/asm/type-check-1.rs @@ -0,0 +1,25 @@ +// only-x86_64 + +#![feature(asm)] + +fn main() { + unsafe { + // Outputs must be place expressions + + asm!("{}", in(reg) 1 + 2); + asm!("{}", out(reg) 1 + 2); + //~^ ERROR invalid asm output + asm!("{}", inout(reg) 1 + 2); + //~^ ERROR invalid asm output + + // Operands must be sized + + let v: [u64; 3] = [0, 1, 2]; + asm!("{}", in(reg) v[..]); + //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time + asm!("{}", out(reg) v[..]); + //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time + asm!("{}", inout(reg) v[..]); + //~^ ERROR the size for values of type `[u64]` cannot be known at compilation time + } +} diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr new file mode 100644 index 00000000000..7c9c041f457 --- /dev/null +++ b/src/test/ui/asm/type-check-1.stderr @@ -0,0 +1,45 @@ +error: invalid asm output + --> $DIR/type-check-1.rs:10:29 + | +LL | asm!("{}", out(reg) 1 + 2); + | ^^^^^ cannot assign to this expression + +error: invalid asm output + --> $DIR/type-check-1.rs:12:31 + | +LL | asm!("{}", inout(reg) 1 + 2); + | ^^^^^ cannot assign to this expression + +error[E0277]: the size for values of type `[u64]` cannot be known at compilation time + --> $DIR/type-check-1.rs:18:28 + | +LL | asm!("{}", in(reg) v[..]); + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `[u64]` + = note: to learn more, visit + = note: all inline asm arguments must have a statically known size + +error[E0277]: the size for values of type `[u64]` cannot be known at compilation time + --> $DIR/type-check-1.rs:20:29 + | +LL | asm!("{}", out(reg) v[..]); + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `[u64]` + = note: to learn more, visit + = note: all inline asm arguments must have a statically known size + +error[E0277]: the size for values of type `[u64]` cannot be known at compilation time + --> $DIR/type-check-1.rs:22:31 + | +LL | asm!("{}", inout(reg) v[..]); + | ^^^^^ doesn't have a size known at compile-time + | + = help: the trait `std::marker::Sized` is not implemented for `[u64]` + = note: to learn more, visit + = note: all inline asm arguments must have a statically known size + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/asm/type-check-2.rs b/src/test/ui/asm/type-check-2.rs new file mode 100644 index 00000000000..1652e9e4c9f --- /dev/null +++ b/src/test/ui/asm/type-check-2.rs @@ -0,0 +1,104 @@ +// only-x86_64 + +#![feature(asm, repr_simd, never_type)] + +#[repr(simd)] +struct SimdNonCopy(f32, f32, f32, f32); + +fn main() { + unsafe { + // Inputs must be initialized + + let x: u64; + asm!("{}", in(reg) x); + //~^ ERROR use of possibly-uninitialized variable: `x` + let mut y: u64; + asm!("{}", inout(reg) y); + //~^ ERROR use of possibly-uninitialized variable: `y` + let _ = y; + + // Outputs require mutable places + + let v: Vec = vec![0, 1, 2]; + asm!("{}", in(reg) v[0]); + asm!("{}", out(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + asm!("{}", inout(reg) v[0]); + //~^ ERROR cannot borrow `v` as mutable, as it is not declared as mutable + + // Const operands must be integer or floats, and must be constants. + + let x = 0; + const C: i32 = 0; + const fn const_foo(x: i32) -> i32 { + x + } + const fn const_bar(x: T) -> T { + x + } + asm!("{}", const 0i32); + asm!("{}", const 0f32); + asm!("{}", const 0 as *mut u8); + //~^ ERROR asm `const` arguments must be integer or floating-point values + asm!("{}", const &0); + //~^ ERROR asm `const` arguments must be integer or floating-point values + asm!("{}", const x); + //~^ ERROR argument 1 is required to be a constant + asm!("{}", const const_foo(0)); + asm!("{}", const const_foo(x)); + //~^ ERROR argument 1 is required to be a constant + asm!("{}", const const_bar(0)); + asm!("{}", const const_bar(x)); + //~^ ERROR argument 1 is required to be a constant + + // Sym operands must point to a function or static + + static S: i32 = 0; + asm!("{}", sym S); + asm!("{}", sym main); + asm!("{}", sym C); + //~^ ERROR asm `sym` operand must point to a fn or static + asm!("{}", sym x); + //~^ ERROR asm `sym` operand must point to a fn or static + + // Register operands must be Copy + + asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + //~^ ERROR arguments for inline assembly must be copyable + + // Register operands must be integers, floats, SIMD vectors, pointers or + // function pointers. + + asm!("{}", in(reg) 0i64); + asm!("{}", in(reg) 0f64); + asm!("{}", in(xmm_reg) std::arch::x86_64::_mm_setzero_ps()); + asm!("{}", in(reg) 0 as *const u8); + asm!("{}", in(reg) 0 as *mut u8); + asm!("{}", in(reg) main as fn()); + asm!("{}", in(reg) |x: i32| x); + //~^ ERROR cannot use value of type + asm!("{}", in(reg) vec![0]); + //~^ ERROR cannot use value of type `std::vec::Vec` for inline assembly + asm!("{}", in(reg) (1, 2, 3)); + //~^ ERROR cannot use value of type `(i32, i32, i32)` for inline assembly + asm!("{}", in(reg) [1, 2, 3]); + //~^ ERROR cannot use value of type `[i32; 3]` for inline assembly + + // Register inputs (but not outputs) allow references and function types + + let mut f = main; + let mut r = &mut 0; + asm!("{}", in(reg) f); + asm!("{}", inout(reg) f); + //~^ ERROR cannot use value of type `fn() {main}` for inline assembly + asm!("{}", in(reg) r); + asm!("{}", inout(reg) r); + //~^ ERROR cannot use value of type `&mut i32` for inline assembly + let _ = (f, r); + + // Type checks ignore never type + + let u: ! = unreachable!(); + asm!("{}", in(reg) u); + } +} diff --git a/src/test/ui/asm/type-check-2.stderr b/src/test/ui/asm/type-check-2.stderr new file mode 100644 index 00000000000..dc7949534f1 --- /dev/null +++ b/src/test/ui/asm/type-check-2.stderr @@ -0,0 +1,133 @@ +error: asm `const` arguments must be integer or floating-point values + --> $DIR/type-check-2.rs:41:26 + | +LL | asm!("{}", const 0 as *mut u8); + | ^^^^^^^^^^^^ + +error: asm `const` arguments must be integer or floating-point values + --> $DIR/type-check-2.rs:43:26 + | +LL | asm!("{}", const &0); + | ^^ + +error: arguments for inline assembly must be copyable + --> $DIR/type-check-2.rs:66:32 + | +LL | asm!("{}", in(xmm_reg) SimdNonCopy(0.0, 0.0, 0.0, 0.0)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `SimdNonCopy` does not implement the Copy trait + +error: cannot use value of type `[closure@$DIR/type-check-2.rs:78:28: 78:38]` for inline assembly + --> $DIR/type-check-2.rs:78:28 + | +LL | asm!("{}", in(reg) |x: i32| x); + | ^^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `std::vec::Vec` for inline assembly + --> $DIR/type-check-2.rs:80:28 + | +LL | asm!("{}", in(reg) vec![0]); + | ^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: cannot use value of type `(i32, i32, i32)` for inline assembly + --> $DIR/type-check-2.rs:82:28 + | +LL | asm!("{}", in(reg) (1, 2, 3)); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `[i32; 3]` for inline assembly + --> $DIR/type-check-2.rs:84:28 + | +LL | asm!("{}", in(reg) [1, 2, 3]); + | ^^^^^^^^^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `fn() {main}` for inline assembly + --> $DIR/type-check-2.rs:92:31 + | +LL | asm!("{}", inout(reg) f); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: cannot use value of type `&mut i32` for inline assembly + --> $DIR/type-check-2.rs:95:31 + | +LL | asm!("{}", inout(reg) r); + | ^ + | + = note: only integers, floats, SIMD vectors, pointers and function pointers can be used as arguments for inline assembly + +error: asm `sym` operand must point to a fn or static + --> $DIR/type-check-2.rs:59:24 + | +LL | asm!("{}", sym C); + | ^ + +error: asm `sym` operand must point to a fn or static + --> $DIR/type-check-2.rs:61:24 + | +LL | asm!("{}", sym x); + | ^ + +error: argument 1 is required to be a constant + --> $DIR/type-check-2.rs:45:9 + | +LL | asm!("{}", const x); + | ^^^^^^^^^^^^^^^^^^^^ + +error: argument 1 is required to be a constant + --> $DIR/type-check-2.rs:48:9 + | +LL | asm!("{}", const const_foo(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: argument 1 is required to be a constant + --> $DIR/type-check-2.rs:51:9 + | +LL | asm!("{}", const const_bar(x)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0381]: use of possibly-uninitialized variable: `x` + --> $DIR/type-check-2.rs:13:28 + | +LL | asm!("{}", in(reg) x); + | ^ use of possibly-uninitialized `x` + +error[E0381]: use of possibly-uninitialized variable: `y` + --> $DIR/type-check-2.rs:16:9 + | +LL | asm!("{}", inout(reg) y); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ use of possibly-uninitialized `y` + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2.rs:24:29 + | +LL | let v: Vec = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +LL | asm!("{}", in(reg) v[0]); +LL | asm!("{}", out(reg) v[0]); + | ^ cannot borrow as mutable + +error[E0596]: cannot borrow `v` as mutable, as it is not declared as mutable + --> $DIR/type-check-2.rs:26:31 + | +LL | let v: Vec = vec![0, 1, 2]; + | - help: consider changing this to be mutable: `mut v` +... +LL | asm!("{}", inout(reg) v[0]); + | ^ cannot borrow as mutable + +error: aborting due to 18 previous errors + +Some errors have detailed explanations: E0381, E0596. +For more information about an error, try `rustc --explain E0381`. diff --git a/src/test/ui/asm/type-check-3.rs b/src/test/ui/asm/type-check-3.rs new file mode 100644 index 00000000000..750d28026d7 --- /dev/null +++ b/src/test/ui/asm/type-check-3.rs @@ -0,0 +1,68 @@ +// only-x86_64 +// compile-flags: -C target-feature=+avx512f + +#![feature(asm)] + +use std::arch::x86_64::{_mm256_setzero_ps, _mm_setzero_ps}; + +fn main() { + unsafe { + // Types must be in the whitelist for the register class + + asm!("{}", in(reg) 0i128); + //~^ ERROR type `i128` cannot be used with this register class + asm!("{}", in(reg) _mm_setzero_ps()); + //~^ ERROR type `std::arch::x86_64::__m128` cannot be used with this register class + asm!("{}", in(reg) _mm256_setzero_ps()); + //~^ ERROR type `std::arch::x86_64::__m256` cannot be used with this register class + asm!("{}", in(xmm_reg) 0u8); + //~^ ERROR type `u8` cannot be used with this register class + asm!("{:e}", in(reg) 0i32); + asm!("{}", in(xmm_reg) 0i32); + asm!("{:e}", in(reg) 0f32); + asm!("{}", in(xmm_reg) 0f32); + asm!("{}", in(xmm_reg) _mm_setzero_ps()); + asm!("{:x}", in(ymm_reg) _mm_setzero_ps()); + asm!("{}", in(kreg) 0u16); + asm!("{}", in(kreg) 0u64); + //~^ ERROR `avx512bw` target feature is not enabled + + // Template modifier suggestions for sub-registers + + asm!("{0} {0}", in(reg) 0i8); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{0} {0:x}", in(reg) 0i16); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0i32); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(reg) 0i64); + asm!("{}", in(ymm_reg) 0i64); + //~^ WARN formatting may not be suitable for sub-register argument + asm!("{}", in(ymm_reg) _mm256_setzero_ps()); + asm!("{:l}", in(reg) 0i8); + asm!("{:l}", in(reg) 0i16); + asm!("{:l}", in(reg) 0i32); + asm!("{:l}", in(reg) 0i64); + asm!("{:x}", in(ymm_reg) 0i64); + asm!("{:x}", in(ymm_reg) _mm256_setzero_ps()); + + // Split inout operands must have compatible types + + let mut val_i8: i8; + let mut val_f32: f32; + let mut val_u32: u32; + let mut val_u64: u64; + let mut val_ptr: *mut u8; + asm!("{:r}", inout(reg) 0u8 => val_i8); + asm!("{:r}", inout(reg) 0u16 => val_i8); + //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) 0u32 => val_f32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) 0u32 => val_ptr); + //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) main => val_u32); + //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) 0u64 => val_ptr); + asm!("{:r}", inout(reg) main => val_u64); + } +} diff --git a/src/test/ui/asm/type-check-3.stderr b/src/test/ui/asm/type-check-3.stderr new file mode 100644 index 00000000000..e4018ca1d42 --- /dev/null +++ b/src/test/ui/asm/type-check-3.stderr @@ -0,0 +1,123 @@ +error: type `i128` cannot be used with this register class + --> $DIR/type-check-3.rs:12:28 + | +LL | asm!("{}", in(reg) 0i128); + | ^^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + +error: type `std::arch::x86_64::__m128` cannot be used with this register class + --> $DIR/type-check-3.rs:14:28 + | +LL | asm!("{}", in(reg) _mm_setzero_ps()); + | ^^^^^^^^^^^^^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + +error: type `std::arch::x86_64::__m256` cannot be used with this register class + --> $DIR/type-check-3.rs:16:28 + | +LL | asm!("{}", in(reg) _mm256_setzero_ps()); + | ^^^^^^^^^^^^^^^^^^^ + | + = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + +error: type `u8` cannot be used with this register class + --> $DIR/type-check-3.rs:18:32 + | +LL | asm!("{}", in(xmm_reg) 0u8); + | ^^^ + | + = note: register class `xmm_reg` supports these types: i32, i64, f32, f64, i8x16, i16x8, i32x4, i64x2, f32x4, f64x2 + +error: `avx512bw` target feature is not enabled + --> $DIR/type-check-3.rs:27:29 + | +LL | asm!("{}", in(kreg) 0u64); + | ^^^^ + | + = note: this is required to use type `u64` with register class `kreg` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:32:15 + | +LL | asm!("{0} {0}", in(reg) 0i8); + | ^^^ ^^^ --- for this argument + | + = note: `#[warn(asm_sub_register)]` on by default + = help: use the `l` modifier to have the register formatted as `al` + = help: or use the `r` modifier to keep the default formatting of `rax` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:34:15 + | +LL | asm!("{0} {0:x}", in(reg) 0i16); + | ^^^ ---- for this argument + | + = help: use the `x` modifier to have the register formatted as `ax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:36:15 + | +LL | asm!("{}", in(reg) 0i32); + | ^^ ---- for this argument + | + = help: use the `e` modifier to have the register formatted as `eax` + = help: or use the `r` modifier to keep the default formatting of `rax` + +warning: formatting may not be suitable for sub-register argument + --> $DIR/type-check-3.rs:39:15 + | +LL | asm!("{}", in(ymm_reg) 0i64); + | ^^ ---- for this argument + | + = help: use the `x` modifier to have the register formatted as `xmm0` + = help: or use the `y` modifier to keep the default formatting of `ymm0` + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:57:33 + | +LL | asm!("{:r}", inout(reg) 0u16 => val_i8); + | ^^^^ ^^^^^^ type `i8` + | | + | type `u16` + | + = note: asm inout arguments must have the same type + = note: unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:59:33 + | +LL | asm!("{:r}", inout(reg) 0u32 => val_f32); + | ^^^^ ^^^^^^^ type `f32` + | | + | type `u32` + | + = note: asm inout arguments must have the same type + = note: unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:61:33 + | +LL | asm!("{:r}", inout(reg) 0u32 => val_ptr); + | ^^^^ ^^^^^^^ type `*mut u8` + | | + | type `u32` + | + = note: asm inout arguments must have the same type + = note: unless they are both pointers or integers of the same size + +error: incompatible types for asm inout argument + --> $DIR/type-check-3.rs:63:33 + | +LL | asm!("{:r}", inout(reg) main => val_u32); + | ^^^^ ^^^^^^^ type `u32` + | | + | type `fn()` + | + = note: asm inout arguments must have the same type + = note: unless they are both pointers or integers of the same size + +error: aborting due to 9 previous errors; 4 warnings emitted + diff --git a/src/test/ui/feature-gates/feature-gate-asm.rs b/src/test/ui/feature-gates/feature-gate-asm.rs index 70f5845550d..7eeeb4bc4e2 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.rs +++ b/src/test/ui/feature-gates/feature-gate-asm.rs @@ -3,7 +3,6 @@ fn main() { unsafe { asm!(""); //~ ERROR inline assembly is not stable enough - //~^ WARN use of deprecated item 'asm' llvm_asm!(""); //~ ERROR inline assembly is not stable enough } } diff --git a/src/test/ui/feature-gates/feature-gate-asm.stderr b/src/test/ui/feature-gates/feature-gate-asm.stderr index 9d4d7b53955..1f9eaa5632e 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm.stderr @@ -8,7 +8,7 @@ LL | asm!(""); = help: add `#![feature(asm)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'llvm_asm': inline assembly is not stable enough for use and is subject to change - --> $DIR/feature-gate-asm.rs:7:9 + --> $DIR/feature-gate-asm.rs:6:9 | LL | llvm_asm!(""); | ^^^^^^^^ @@ -16,14 +16,6 @@ LL | llvm_asm!(""); = note: see issue #70173 for more information = help: add `#![feature(llvm_asm)]` to the crate attributes to enable -warning: use of deprecated item 'asm': the syntax of asm! will change soon, use llvm_asm! to avoid breakage - --> $DIR/feature-gate-asm.rs:5:9 - | -LL | asm!(""); - | ^^^ help: replace the use of the deprecated item: `llvm_asm` - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-asm2.rs b/src/test/ui/feature-gates/feature-gate-asm2.rs index e3e86592a48..666a4894f62 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.rs +++ b/src/test/ui/feature-gates/feature-gate-asm2.rs @@ -3,7 +3,6 @@ fn main() { unsafe { println!("{:?}", asm!("")); //~ ERROR inline assembly is not stable - //~^ WARN use of deprecated item 'asm' println!("{:?}", llvm_asm!("")); //~ ERROR inline assembly is not stable } } diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr index a3c8116d6b1..17ba66e9842 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm2.stderr @@ -8,7 +8,7 @@ LL | println!("{:?}", asm!("")); = help: add `#![feature(asm)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'llvm_asm': inline assembly is not stable enough for use and is subject to change - --> $DIR/feature-gate-asm2.rs:7:26 + --> $DIR/feature-gate-asm2.rs:6:26 | LL | println!("{:?}", llvm_asm!("")); | ^^^^^^^^ @@ -16,14 +16,6 @@ LL | println!("{:?}", llvm_asm!("")); = note: see issue #70173 for more information = help: add `#![feature(llvm_asm)]` to the crate attributes to enable -warning: use of deprecated item 'asm': the syntax of asm! will change soon, use llvm_asm! to avoid breakage - --> $DIR/feature-gate-asm2.rs:5:26 - | -LL | println!("{:?}", asm!("")); - | ^^^ help: replace the use of the deprecated item: `llvm_asm` - | - = note: `#[warn(deprecated)]` on by default - -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/llvm-asm/llvm-asm-concat-src.rs b/src/test/ui/llvm-asm/llvm-asm-concat-src.rs new file mode 100644 index 00000000000..1dc1c859c6b --- /dev/null +++ b/src/test/ui/llvm-asm/llvm-asm-concat-src.rs @@ -0,0 +1,9 @@ +// run-pass +// pretty-expanded FIXME #23616 +// ignore-emscripten no asm + +#![feature(llvm_asm)] + +pub fn main() { + unsafe { llvm_asm!(concat!("", "")) }; +} diff --git a/src/test/ui/llvm-asm/llvm-asm-in-moved.rs b/src/test/ui/llvm-asm/llvm-asm-in-moved.rs new file mode 100644 index 00000000000..35f4d92c8ff --- /dev/null +++ b/src/test/ui/llvm-asm/llvm-asm-in-moved.rs @@ -0,0 +1,31 @@ +// run-pass + +#![feature(llvm_asm)] +#![allow(dead_code)] + +use std::cell::Cell; + +#[repr(C)] +struct NoisyDrop<'a>(&'a Cell<&'static str>); +impl<'a> Drop for NoisyDrop<'a> { + fn drop(&mut self) { + self.0.set("destroyed"); + } +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn main() { + let status = Cell::new("alive"); + { + let _y: Box; + let x = Box::new(NoisyDrop(&status)); + unsafe { + llvm_asm!("mov $1, $0" : "=r"(_y) : "r"(x)); + } + assert_eq!(status.get(), "alive"); + } + assert_eq!(status.get(), "destroyed"); +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +fn main() {} diff --git a/src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs b/src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs new file mode 100644 index 00000000000..acefabd8a66 --- /dev/null +++ b/src/test/ui/llvm-asm/llvm-asm-in-out-operand.rs @@ -0,0 +1,56 @@ +// run-pass + +#![feature(llvm_asm)] + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +unsafe fn next_power_of_2(n: u32) -> u32 { + let mut tmp = n; + llvm_asm!("dec $0" : "+rm"(tmp) :: "cc"); + let mut shift = 1_u32; + while shift <= 16 { + llvm_asm!( + "shr %cl, $2 + or $2, $0 + shl $$1, $1" + : "+&rm"(tmp), "+{ecx}"(shift) : "r"(tmp) : "cc" + ); + } + llvm_asm!("inc $0" : "+rm"(tmp) :: "cc"); + return tmp; +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub fn main() { + unsafe { + assert_eq!(64, next_power_of_2(37)); + assert_eq!(2147483648, next_power_of_2(2147483647)); + } + + let mut y: isize = 5; + let x: isize; + unsafe { + // Treat the output as initialization. + llvm_asm!( + "shl $2, $1 + add $3, $1 + mov $1, $0" + : "=r"(x), "+r"(y) : "i"(3_usize), "ir"(7_usize) : "cc" + ); + } + assert_eq!(x, 47); + assert_eq!(y, 47); + + let mut x = x + 1; + assert_eq!(x, 48); + + unsafe { + // Assignment to mutable. + // Early clobber "&": + // Forbids the use of a single register by both operands. + llvm_asm!("shr $$2, $1; add $1, $0" : "+&r"(x) : "r"(x) : "cc"); + } + assert_eq!(x, 60); +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +pub fn main() {} diff --git a/src/test/ui/llvm-asm/llvm-asm-indirect-memory.rs b/src/test/ui/llvm-asm/llvm-asm-indirect-memory.rs new file mode 100644 index 00000000000..556ad83a4ea --- /dev/null +++ b/src/test/ui/llvm-asm/llvm-asm-indirect-memory.rs @@ -0,0 +1,43 @@ +// run-pass + +#![feature(llvm_asm)] + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn read(ptr: &u32) -> u32 { + let out: u32; + unsafe { + llvm_asm!("mov $1, $0" : "=r" (out) : "*m" (ptr)); + } + out +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn write(ptr: &mut u32, val: u32) { + unsafe { + llvm_asm!("mov $1, $0" : "=*m" (ptr) : "r" (val)); + } +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +fn replace(ptr: &mut u32, val: u32) -> u32 { + let out: u32; + unsafe { + llvm_asm!("mov $0, $1; mov $2, $0" : "+*m" (ptr), "=&r" (out) : "r" (val)); + } + out +} + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub fn main() { + let a = 1; + assert_eq!(read(&a), 1); + let mut b = 2; + write(&mut b, 3); + assert_eq!(b, 3); + let mut c = 4; + assert_eq!(replace(&mut c, 5), 4); + assert_eq!(c, 5); +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +pub fn main() {} diff --git a/src/test/ui/llvm-asm/llvm-asm-out-assign.rs b/src/test/ui/llvm-asm/llvm-asm-out-assign.rs new file mode 100644 index 00000000000..321f28565ff --- /dev/null +++ b/src/test/ui/llvm-asm/llvm-asm-out-assign.rs @@ -0,0 +1,25 @@ +// run-pass + +#![feature(llvm_asm)] + +#[cfg(any(target_arch = "x86", target_arch = "x86_64"))] +pub fn main() { + let x: isize; + unsafe { + // Treat the output as initialization. + llvm_asm!("mov $1, $0" : "=r"(x) : "r"(5_usize)); + } + assert_eq!(x, 5); + + let mut x = x + 1; + assert_eq!(x, 6); + + unsafe { + // Assignment to mutable. + llvm_asm!("mov $1, $0" : "=r"(x) : "r"(x + 7)); + } + assert_eq!(x, 13); +} + +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +pub fn main() {} diff --git a/src/test/ui/macros/macro-expanded-include/foo/mod.rs b/src/test/ui/macros/macro-expanded-include/foo/mod.rs index f0eb92b2be8..a8bfa0299f6 100644 --- a/src/test/ui/macros/macro-expanded-include/foo/mod.rs +++ b/src/test/ui/macros/macro-expanded-include/foo/mod.rs @@ -5,5 +5,5 @@ macro_rules! m { } macro_rules! n { - () => { unsafe { llvm_asm!(include_str!("file.txt")); } } + () => { unsafe { asm!(include_str!("file.txt")); } } } diff --git a/src/test/ui/macros/macro-expanded-include/test.rs b/src/test/ui/macros/macro-expanded-include/test.rs index abf83a5c6ff..f1a71059a89 100644 --- a/src/test/ui/macros/macro-expanded-include/test.rs +++ b/src/test/ui/macros/macro-expanded-include/test.rs @@ -1,6 +1,6 @@ // ignore-emscripten no llvm_asm! support // build-pass (FIXME(62277): could be check-pass?) -#![feature(llvm_asm)] +#![feature(asm)] #![allow(unused)] #[macro_use] diff --git a/src/test/ui/macros/macros-nonfatal-errors.rs b/src/test/ui/macros/macros-nonfatal-errors.rs index cc96a5bff52..0a496c9dc3d 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.rs +++ b/src/test/ui/macros/macros-nonfatal-errors.rs @@ -3,13 +3,14 @@ // test that errors in a (selection) of macros don't kill compilation // immediately, so that we get more errors listed at a time. -#![feature(llvm_asm)] +#![feature(asm, llvm_asm)] #![feature(trace_macros, concat_idents)] #[derive(Default)] //~ ERROR enum OrDeriveThis {} fn main() { + asm!(invalid); //~ ERROR llvm_asm!(invalid); //~ ERROR concat_idents!("not", "idents"); //~ ERROR diff --git a/src/test/ui/macros/macros-nonfatal-errors.stderr b/src/test/ui/macros/macros-nonfatal-errors.stderr index f416c70123c..6ef757a55b8 100644 --- a/src/test/ui/macros/macros-nonfatal-errors.stderr +++ b/src/test/ui/macros/macros-nonfatal-errors.stderr @@ -6,44 +6,50 @@ LL | #[derive(Default)] | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) +error: asm template must be a string literal + --> $DIR/macros-nonfatal-errors.rs:13:10 + | +LL | asm!(invalid); + | ^^^^^^^ + error: inline assembly must be a string literal - --> $DIR/macros-nonfatal-errors.rs:13:15 + --> $DIR/macros-nonfatal-errors.rs:14:15 | LL | llvm_asm!(invalid); | ^^^^^^^ error: concat_idents! requires ident args. - --> $DIR/macros-nonfatal-errors.rs:15:5 + --> $DIR/macros-nonfatal-errors.rs:16:5 | LL | concat_idents!("not", "idents"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:17:17 + --> $DIR/macros-nonfatal-errors.rs:18:17 | LL | option_env!(invalid); | ^^^^^^^ error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:18:10 + --> $DIR/macros-nonfatal-errors.rs:19:10 | LL | env!(invalid); | ^^^^^^^ error: expected string literal - --> $DIR/macros-nonfatal-errors.rs:19:10 + --> $DIR/macros-nonfatal-errors.rs:20:10 | LL | env!(foo, abr, baz); | ^^^ error: environment variable `RUST_HOPEFULLY_THIS_DOESNT_EXIST` not defined - --> $DIR/macros-nonfatal-errors.rs:20:5 + --> $DIR/macros-nonfatal-errors.rs:21:5 | LL | env!("RUST_HOPEFULLY_THIS_DOESNT_EXIST"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: format argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:22:13 + --> $DIR/macros-nonfatal-errors.rs:23:13 | LL | format!(invalid); | ^^^^^^^ @@ -54,19 +60,19 @@ LL | format!("{}", invalid); | ^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:24:14 + --> $DIR/macros-nonfatal-errors.rs:25:14 | LL | include!(invalid); | ^^^^^^^ error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:26:18 + --> $DIR/macros-nonfatal-errors.rs:27:18 | LL | include_str!(invalid); | ^^^^^^^ error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) - --> $DIR/macros-nonfatal-errors.rs:27:5 + --> $DIR/macros-nonfatal-errors.rs:28:5 | LL | include_str!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -74,13 +80,13 @@ LL | include_str!("i'd be quite surprised if a file with this name existed") = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: argument must be a string literal - --> $DIR/macros-nonfatal-errors.rs:28:20 + --> $DIR/macros-nonfatal-errors.rs:29:20 | LL | include_bytes!(invalid); | ^^^^^^^ error: couldn't read $DIR/i'd be quite surprised if a file with this name existed: $FILE_NOT_FOUND_MSG (os error 2) - --> $DIR/macros-nonfatal-errors.rs:29:5 + --> $DIR/macros-nonfatal-errors.rs:30:5 | LL | include_bytes!("i'd be quite surprised if a file with this name existed"); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -88,11 +94,11 @@ LL | include_bytes!("i'd be quite surprised if a file with this name existed = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: trace_macros! accepts only `true` or `false` - --> $DIR/macros-nonfatal-errors.rs:31:5 + --> $DIR/macros-nonfatal-errors.rs:32:5 | LL | trace_macros!(invalid); | ^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0665`. diff --git a/src/test/ui/target-feature/gate.stderr b/src/test/ui/target-feature/gate.stderr index 848538a4e92..2384a00aa47 100644 --- a/src/test/ui/target-feature/gate.stderr +++ b/src/test/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/gate.rs:29:18 + --> $DIR/gate.rs:30:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ -- cgit 1.4.1-3-g733a5 From ff97db1e54dde5418f55f1c727e1c37257c4a6ab Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Thu, 19 Mar 2020 07:41:43 +0000 Subject: Apply review feedback --- src/librustc_builtin_macros/asm.rs | 125 +++++++++++++++++++----------------- src/librustc_passes/intrinsicck.rs | 17 ++++- src/librustc_target/asm/aarch64.rs | 27 ++++---- src/librustc_target/asm/arm.rs | 21 ++++-- src/librustc_target/asm/mod.rs | 2 +- src/librustc_target/asm/riscv.rs | 20 +++--- src/librustc_target/asm/x86.rs | 61 ++++++++++-------- src/test/ui/asm/parse-error.rs | 5 +- src/test/ui/asm/parse-error.stderr | 34 +++++++--- src/test/ui/asm/type-check-3.stderr | 12 ++-- 10 files changed, 185 insertions(+), 139 deletions(-) (limited to 'src/test') diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index 943ed42e202..c9a3401cac0 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -80,47 +80,14 @@ fn parse_args<'a>( break; } // accept trailing commas - let span_start = p.token.span; - // Parse options if p.eat(&token::Ident(sym::options, false)) { - p.expect(&token::OpenDelim(token::DelimToken::Paren))?; - - while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) { - if p.eat(&token::Ident(sym::pure, false)) { - args.options |= InlineAsmOptions::PURE; - } else if p.eat(&token::Ident(sym::nomem, false)) { - args.options |= InlineAsmOptions::NOMEM; - } else if p.eat(&token::Ident(sym::readonly, false)) { - args.options |= InlineAsmOptions::READONLY; - } else if p.eat(&token::Ident(sym::preserves_flags, false)) { - args.options |= InlineAsmOptions::PRESERVES_FLAGS; - } else if p.eat(&token::Ident(sym::noreturn, false)) { - args.options |= InlineAsmOptions::NORETURN; - } else { - p.expect(&token::Ident(sym::nostack, false))?; - args.options |= InlineAsmOptions::NOSTACK; - } - - // Allow trailing commas - if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { - break; - } - p.expect(&token::Comma)?; - } - - let new_span = span_start.to(p.prev_token.span); - if let Some(options_span) = args.options_span { - ecx.struct_span_err(new_span, "asm options cannot be specified twice") - .span_label(options_span, "previously here") - .span_label(new_span, "duplicate options") - .emit(); - } else { - args.options_span = Some(new_span); - } + parse_options(&mut p, &mut args)?; continue; } + let span_start = p.token.span; + // Parse operand names let name = if p.token.is_ident() && p.look_ahead(1, |t| *t == token::Eq) { let (ident, _) = p.token.ident().unwrap(); @@ -131,29 +98,6 @@ fn parse_args<'a>( None }; - fn parse_reg<'a>( - p: &mut Parser<'a>, - explicit_reg: &mut bool, - ) -> Result> { - p.expect(&token::OpenDelim(token::DelimToken::Paren))?; - let result = match p.token.kind { - token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name), - token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => { - *explicit_reg = true; - ast::InlineAsmRegOrRegClass::Reg(symbol) - } - _ => { - return Err(p.struct_span_err( - p.token.span, - "expected register class or explicit register", - )); - } - }; - p.bump(); - p.expect(&token::CloseDelim(token::DelimToken::Paren))?; - Ok(result) - }; - let mut explicit_reg = false; let op = if p.eat(&token::Ident(kw::In, false)) { let reg = parse_reg(&mut p, &mut explicit_reg)?; @@ -319,6 +263,69 @@ fn parse_args<'a>( Ok(args) } +fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), DiagnosticBuilder<'a>> { + let span_start = p.prev_token.span; + + p.expect(&token::OpenDelim(token::DelimToken::Paren))?; + + while !p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + if p.eat(&token::Ident(sym::pure, false)) { + args.options |= InlineAsmOptions::PURE; + } else if p.eat(&token::Ident(sym::nomem, false)) { + args.options |= InlineAsmOptions::NOMEM; + } else if p.eat(&token::Ident(sym::readonly, false)) { + args.options |= InlineAsmOptions::READONLY; + } else if p.eat(&token::Ident(sym::preserves_flags, false)) { + args.options |= InlineAsmOptions::PRESERVES_FLAGS; + } else if p.eat(&token::Ident(sym::noreturn, false)) { + args.options |= InlineAsmOptions::NORETURN; + } else { + p.expect(&token::Ident(sym::nostack, false))?; + args.options |= InlineAsmOptions::NOSTACK; + } + + // Allow trailing commas + if p.eat(&token::CloseDelim(token::DelimToken::Paren)) { + break; + } + p.expect(&token::Comma)?; + } + + let new_span = span_start.to(p.prev_token.span); + if let Some(options_span) = args.options_span { + p.struct_span_err(new_span, "asm options cannot be specified multiple times") + .span_label(options_span, "previously here") + .span_label(new_span, "duplicate options") + .emit(); + } else { + args.options_span = Some(new_span); + } + + Ok(()) +} + +fn parse_reg<'a>( + p: &mut Parser<'a>, + explicit_reg: &mut bool, +) -> Result> { + p.expect(&token::OpenDelim(token::DelimToken::Paren))?; + let result = match p.token.kind { + token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name), + token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => { + *explicit_reg = true; + ast::InlineAsmRegOrRegClass::Reg(symbol) + } + _ => { + return Err( + p.struct_span_err(p.token.span, "expected register class or explicit register") + ); + } + }; + p.bump(); + p.expect(&token::CloseDelim(token::DelimToken::Paren))?; + Ok(result) +} + fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, sp: Span, args: AsmArgs) -> P { let msg = "asm template must be a string literal"; let template_sp = args.template.span; diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs index 1a9fd30bba0..b98ed99d04e 100644 --- a/src/librustc_passes/intrinsicck.rs +++ b/src/librustc_passes/intrinsicck.rs @@ -239,8 +239,10 @@ impl ExprVisitor<'tcx> { &format!("type `{}`", self.tables.expr_ty_adjusted(in_expr)), ); err.span_label(expr.span, &format!("type `{}`", ty)); - err.note("asm inout arguments must have the same type"); - err.note("unless they are both pointers or integers of the same size"); + err.note( + "asm inout arguments must have the same type, \ + unless they are both pointers or integers of the same size", + ); err.emit(); } @@ -271,7 +273,16 @@ impl ExprVisitor<'tcx> { } }; - // Check whether the selected type requires a target feature. + // Check whether the selected type requires a target feature. Note that + // this is different from the feature check we did earlier in AST + // lowering. While AST lowering checked that this register class is + // usable at all with the currently enabled features, some types may + // only be usable with a register class when a certain feature is + // enabled. We check this here since it depends on the results of typeck. + // + // Also note that this check isn't run when the operand type is never + // (!). In that case we still need the earlier check in AST lowering to + // verify that the register class is usable at all. if let Some(feature) = feature { if !self.tcx.sess.target_features.contains(&Symbol::intern(feature)) { let msg = &format!("`{}` target feature is not enabled", feature); diff --git a/src/librustc_target/asm/aarch64.rs b/src/librustc_target/asm/aarch64.rs index c734344f81f..16bc5d670d8 100644 --- a/src/librustc_target/asm/aarch64.rs +++ b/src/librustc_target/asm/aarch64.rs @@ -24,13 +24,10 @@ impl AArch64InlineAsmRegClass { ty: InlineAsmType, ) -> Option<(char, &'static str, Option<&'static str>)> { match self { - Self::reg => { - if ty.size().bits() <= 32 { - Some(('w', "w0", None)) - } else { - None - } - } + Self::reg => match ty.size().bits() { + 64 => None, + _ => Some(('w', "w0", None)), + }, Self::vreg | Self::vreg_low16 => match ty.size().bits() { 8 => Some(('b', "b0", None)), 16 => Some(('h', "h0", None)), @@ -57,8 +54,8 @@ impl AArch64InlineAsmRegClass { Self::reg => types! { _: I8, I16, I32, I64, F32, F64; }, Self::vreg | Self::vreg_low16 => types! { "fp": I8, I16, I32, I64, F32, F64, - VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1), - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); + VecI8(8), VecI16(4), VecI32(2), VecI64(1), VecF32(2), VecF64(1), + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); }, } } @@ -128,12 +125,12 @@ def_regs! { v29: vreg = ["v29", "b29", "h29", "s29", "d29", "q29"], v30: vreg = ["v30", "b30", "h30", "s30", "d30", "q30"], v31: vreg = ["v31", "b31", "h31", "s31", "d31", "q31"], - "the frame pointer cannot be used as an operand for inline asm" = - ["x29", "fp"], - "the stack pointer cannot be used as an operand for inline asm" = - ["sp", "wsp"], - "the zero register cannot be used as an operand for inline asm" = - ["xzr", "wzr"], + #error = ["x29", "fp"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["sp", "wsp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["xzr", "wzr"] => + "the zero register cannot be used as an operand for inline asm", } } diff --git a/src/librustc_target/asm/arm.rs b/src/librustc_target/asm/arm.rs index 143852db829..0ceb15e297f 100644 --- a/src/librustc_target/asm/arm.rs +++ b/src/librustc_target/asm/arm.rs @@ -149,12 +149,12 @@ def_regs! { q13: qreg = ["q13"], q14: qreg = ["q14"], q15: qreg = ["q15"], - "the frame pointer cannot be used as an operand for inline asm" = - ["r11", "fp"], - "the stack pointer cannot be used as an operand for inline asm" = - ["r13", "sp"], - "the program pointer cannot be used as an operand for inline asm" = - ["r15", "pc"], + #error = ["r11", "fp"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["r13", "sp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["r15", "pc"] => + "the program pointer cannot be used as an operand for inline asm", } } @@ -231,6 +231,15 @@ impl ArmInlineAsmReg { } }; } + + // ARM's floating-point register file is interesting in that it can be + // viewed as 16 128-bit registers, 32 64-bit registers or 32 32-bit + // registers. Because these views overlap, the registers of different + // widths will conflict (e.g. d0 overlaps with s0 and s1, and q1 + // overlaps with d2 and d3). + // + // See section E1.3.1 of the ARM Architecture Reference Manual for + // ARMv8-A for more details. reg_conflicts! { q0 : d0 d1 : s0 s1 s2 s3, q1 : d2 d3 : s4 s5 s6 s7, diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index 1f8ff5d6d39..dda6e7cd5cd 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -57,7 +57,7 @@ macro_rules! def_regs { $reg:ident: $class:ident $(, $extra_class:ident)* = [$reg_name:literal $(, $alias:literal)*] $(% $filter:ident)?, )* $( - $error:literal = [$($bad_reg:literal),+], + #error = [$($bad_reg:literal),+] => $error:literal, )* }) => { #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, Eq, PartialEq, Hash, HashStable_Generic)] diff --git a/src/librustc_target/asm/riscv.rs b/src/librustc_target/asm/riscv.rs index c57e277c0cd..f9b132c2087 100644 --- a/src/librustc_target/asm/riscv.rs +++ b/src/librustc_target/asm/riscv.rs @@ -115,16 +115,16 @@ def_regs! { f29: freg = ["f29", "ft9"], f30: freg = ["f30", "ft10"], f31: freg = ["f31", "ft11"], - "the frame pointer cannot be used as an operand for inline asm" = - ["x8", "s0", "fp"], - "the stack pointer cannot be used as an operand for inline asm" = - ["x2", "sp"], - "the global pointer cannot be used as an operand for inline asm" = - ["x3", "gp"], - "the thread pointer cannot be used as an operand for inline asm" = - ["x4", "tp"], - "the zero register cannot be used as an operand for inline asm" = - ["x0", "zero"], + #error = ["x8", "s0", "fp"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["x2", "sp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["x3", "gp"] => + "the global pointer cannot be used as an operand for inline asm", + #error = ["x4", "tp"] => + "the thread pointer cannot be used as an operand for inline asm" , + #error = ["x0", "zero"] => + "the zero register cannot be used as an operand for inline asm", } } diff --git a/src/librustc_target/asm/x86.rs b/src/librustc_target/asm/x86.rs index 7193b1ca8b6..d10bcb40ba0 100644 --- a/src/librustc_target/asm/x86.rs +++ b/src/librustc_target/asm/x86.rs @@ -62,16 +62,13 @@ impl X86InlineAsmRegClass { _ => None, }, Self::xmm_reg => None, - Self::ymm_reg => { - if ty.size().bits() <= 128 { - Some(('x', "xmm0", None)) - } else { - None - } - } + Self::ymm_reg => match ty.size().bits() { + 256 => None, + _ => Some(('x', "xmm0", None)), + }, Self::zmm_reg => match ty.size().bits() { - 256 => Some(('y', "ymm0", None)), 512 => None, + 256 => Some(('y', "ymm0", None)), _ => Some(('x', "xmm0", None)), }, Self::kreg => None, @@ -108,18 +105,18 @@ impl X86InlineAsmRegClass { } Self::xmm_reg => types! { "sse": I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); }, Self::ymm_reg => types! { "avx": I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4); + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2), + VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4); }, Self::zmm_reg => types! { "avx512f": I32, I64, F32, F64, - VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2), - VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4), - VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF32(16), VecF64(8); + VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2), + VecI8(32), VecI16(16), VecI32(8), VecI64(4), VecF32(8), VecF64(4), + VecI8(64), VecI16(32), VecI32(16), VecI64(8), VecF32(16), VecF64(8); }, Self::kreg => types! { "avx512f": I8, I16; @@ -227,19 +224,20 @@ def_regs! { k5: kreg = ["k5"], k6: kreg = ["k6"], k7: kreg = ["k7"], - "high byte registers are not currently supported as operands for inline asm" = - ["ah", "bh", "ch", "dh"], - "the frame pointer cannot be used as an operand for inline asm" = - ["bp", "bpl", "ebp", "rbp"], - "the stack pointer cannot be used as an operand for inline asm" = - ["sp", "spl", "esp", "rsp"], - "the instruction pointer cannot be used as an operand for inline asm" = - ["ip", "eip", "rip"], - "x87 registers are not currently supported as operands for inline asm" = - ["st", "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"], - "MMX registers are not currently supported as operands for inline asm" = - ["mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"], - "the k0 AVX mask register cannot be used as an operand for inline asm" = ["k0"], + #error = ["ah", "bh", "ch", "dh"] => + "high byte registers are not currently supported as operands for inline asm", + #error = ["bp", "bpl", "ebp", "rbp"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["sp", "spl", "esp", "rsp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["ip", "eip", "rip"] => + "the instruction pointer cannot be used as an operand for inline asm", + #error = ["st", "st(0)", "st(1)", "st(2)", "st(3)", "st(4)", "st(5)", "st(6)", "st(7)"] => + "x87 registers are not currently supported as operands for inline asm", + #error = ["mm0", "mm1", "mm2", "mm3", "mm4", "mm5", "mm6", "mm7"] => + "MMX registers are not currently supported as operands for inline asm", + #error = ["k0"] => + "the k0 AVX mask register cannot be used as an operand for inline asm", } } @@ -316,6 +314,15 @@ impl X86InlineAsmReg { } }; } + + // XMM*, YMM* and ZMM* are all different views of the same register. + // + // See section 15.5 of the combined Intel® 64 and IA-32 Architectures + // Software Developer’s Manual for more details. + // + // We don't need to specify conflicts for [x,y,z]mm[16-31] since these + // registers are only available with AVX-512, so we just specify them + // as aliases directly. reg_conflicts! { xmm0 : ymm0 : zmm0, xmm1 : ymm1 : zmm1, diff --git a/src/test/ui/asm/parse-error.rs b/src/test/ui/asm/parse-error.rs index e6566866b22..2b1f018f364 100644 --- a/src/test/ui/asm/parse-error.rs +++ b/src/test/ui/asm/parse-error.rs @@ -35,7 +35,10 @@ fn main() { asm!("", options(nomem, foo)); //~^ ERROR expected one of asm!("", options(), options()); - //~^ ERROR asm options cannot be specified twice + //~^ ERROR asm options cannot be specified multiple times + asm!("", options(), options(), options()); + //~^ ERROR asm options cannot be specified multiple times + //~^^ ERROR asm options cannot be specified multiple times asm!("{}", options(), const foo); //~^ ERROR arguments are not allowed after options asm!("{a}", a = const foo, a = const bar); diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr index a927ce13858..94eb9d29862 100644 --- a/src/test/ui/asm/parse-error.stderr +++ b/src/test/ui/asm/parse-error.stderr @@ -82,7 +82,7 @@ error: expected one of `)`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, ` LL | asm!("", options(nomem, foo)); | ^^^ expected one of 7 possible tokens -error: asm options cannot be specified twice +error: asm options cannot be specified multiple times --> $DIR/parse-error.rs:37:29 | LL | asm!("", options(), options()); @@ -90,8 +90,24 @@ LL | asm!("", options(), options()); | | | previously here +error: asm options cannot be specified multiple times + --> $DIR/parse-error.rs:39:29 + | +LL | asm!("", options(), options(), options()); + | --------- ^^^^^^^^^ duplicate options + | | + | previously here + +error: asm options cannot be specified multiple times + --> $DIR/parse-error.rs:39:40 + | +LL | asm!("", options(), options(), options()); + | --------- ^^^^^^^^^ duplicate options + | | + | previously here + error: arguments are not allowed after options - --> $DIR/parse-error.rs:39:31 + --> $DIR/parse-error.rs:42:31 | LL | asm!("{}", options(), const foo); | --------- ^^^^^^^^^ argument @@ -99,7 +115,7 @@ LL | asm!("{}", options(), const foo); | previous options error: duplicate argument named `a` - --> $DIR/parse-error.rs:41:36 + --> $DIR/parse-error.rs:44:36 | LL | asm!("{a}", a = const foo, a = const bar); | ------------- ^^^^^^^^^^^^^ duplicate argument @@ -107,19 +123,19 @@ LL | asm!("{a}", a = const foo, a = const bar); | previously here error: argument never used - --> $DIR/parse-error.rs:41:36 + --> $DIR/parse-error.rs:44:36 | LL | asm!("{a}", a = const foo, a = const bar); | ^^^^^^^^^^^^^ argument never used error: explicit register arguments cannot have names - --> $DIR/parse-error.rs:44:18 + --> $DIR/parse-error.rs:47:18 | LL | asm!("", a = in("eax") foo); | ^^^^^^^^^^^^^^^^^ error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:46:36 + --> $DIR/parse-error.rs:49:36 | LL | asm!("{a}", in("eax") foo, a = const bar); | ------------- ^^^^^^^^^^^^^ named argument @@ -127,7 +143,7 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | explicit register argument error: named arguments cannot follow explicit register arguments - --> $DIR/parse-error.rs:48:36 + --> $DIR/parse-error.rs:51:36 | LL | asm!("{a}", in("eax") foo, a = const bar); | ------------- ^^^^^^^^^^^^^ named argument @@ -135,12 +151,12 @@ LL | asm!("{a}", in("eax") foo, a = const bar); | explicit register argument error: positional arguments cannot follow named arguments or explicit register arguments - --> $DIR/parse-error.rs:50:36 + --> $DIR/parse-error.rs:53:36 | LL | asm!("{1}", in("eax") foo, const bar); | ------------- ^^^^^^^^^ positional argument | | | explicit register argument -error: aborting due to 22 previous errors +error: aborting due to 24 previous errors diff --git a/src/test/ui/asm/type-check-3.stderr b/src/test/ui/asm/type-check-3.stderr index e4018ca1d42..ccc795d1013 100644 --- a/src/test/ui/asm/type-check-3.stderr +++ b/src/test/ui/asm/type-check-3.stderr @@ -83,8 +83,7 @@ LL | asm!("{:r}", inout(reg) 0u16 => val_i8); | | | type `u16` | - = note: asm inout arguments must have the same type - = note: unless they are both pointers or integers of the same size + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument --> $DIR/type-check-3.rs:59:33 @@ -94,8 +93,7 @@ LL | asm!("{:r}", inout(reg) 0u32 => val_f32); | | | type `u32` | - = note: asm inout arguments must have the same type - = note: unless they are both pointers or integers of the same size + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument --> $DIR/type-check-3.rs:61:33 @@ -105,8 +103,7 @@ LL | asm!("{:r}", inout(reg) 0u32 => val_ptr); | | | type `u32` | - = note: asm inout arguments must have the same type - = note: unless they are both pointers or integers of the same size + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument --> $DIR/type-check-3.rs:63:33 @@ -116,8 +113,7 @@ LL | asm!("{:r}", inout(reg) main => val_u32); | | | type `fn()` | - = note: asm inout arguments must have the same type - = note: unless they are both pointers or integers of the same size + = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: aborting due to 9 previous errors; 4 warnings emitted -- cgit 1.4.1-3-g733a5 From 7dfa486d4a18b7a6e514e589771f52c43eff4f3b Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 29 Apr 2020 00:45:58 +0100 Subject: Add support for high byte registers on x86 --- src/librustc_codegen_llvm/asm.rs | 3 + src/librustc_passes/intrinsicck.rs | 24 +++--- src/librustc_target/asm/aarch64.rs | 18 +++-- src/librustc_target/asm/arm.rs | 6 +- src/librustc_target/asm/mod.rs | 17 ++++- src/librustc_target/asm/riscv.rs | 6 +- src/librustc_target/asm/x86.rs | 141 ++++++++++++++++++++++++++---------- src/test/assembly/asm/x86-types.rs | 20 ++--- src/test/ui/asm/bad-reg.rs | 4 +- src/test/ui/asm/bad-reg.stderr | 36 ++++----- src/test/ui/asm/type-check-3.rs | 15 ++-- src/test/ui/asm/type-check-3.stderr | 31 ++++---- 12 files changed, 198 insertions(+), 123 deletions(-) (limited to 'src/test') diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs index 21322511c99..20abfbcf405 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -409,6 +409,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass) -> String { InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f", InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r", InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q", + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "r", InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg) | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x", InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v", @@ -459,6 +460,7 @@ fn modifier_to_llvm( Some('r') => Some('q'), _ => unreachable!(), }, + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => None, InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::xmm_reg) | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::ymm_reg) | InlineAsmRegClass::X86(reg @ X86InlineAsmRegClass::zmm_reg) => match (reg, modifier) { @@ -499,6 +501,7 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) | InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => cx.type_i32(), + InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => cx.type_i8(), InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg) | InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) | InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => cx.type_f32(), diff --git a/src/librustc_passes/intrinsicck.rs b/src/librustc_passes/intrinsicck.rs index b98ed99d04e..9e144f86cd8 100644 --- a/src/librustc_passes/intrinsicck.rs +++ b/src/librustc_passes/intrinsicck.rs @@ -268,6 +268,12 @@ impl ExprVisitor<'tcx> { reg_class.name(), supported_tys.join(", "), )); + if let Some(suggest) = reg_class.suggest_class(asm_arch, asm_ty) { + err.help(&format!( + "consider using the `{}` register class instead", + suggest.name() + )); + } err.emit(); return Some(asm_ty); } @@ -298,7 +304,7 @@ impl ExprVisitor<'tcx> { } // Check whether a modifier is suggested for using this type. - if let Some((suggested_modifier, suggested_result, switch_reg_class)) = + if let Some((suggested_modifier, suggested_result)) = reg_class.suggest_modifier(asm_arch, asm_ty) { // Search for any use of this operand without a modifier and emit @@ -323,18 +329,10 @@ impl ExprVisitor<'tcx> { let msg = "formatting may not be suitable for sub-register argument"; let mut err = lint.build(msg); err.span_label(expr.span, "for this argument"); - if let Some(switch_reg_class) = switch_reg_class { - err.help(&format!( - "use the `{}` modifier with the `{}` register class \ - to have the register formatted as `{}`", - suggested_modifier, switch_reg_class, suggested_result, - )); - } else { - err.help(&format!( - "use the `{}` modifier to have the register formatted as `{}`", - suggested_modifier, suggested_result, - )); - } + err.help(&format!( + "use the `{}` modifier to have the register formatted as `{}`", + suggested_modifier, suggested_result, + )); err.help(&format!( "or use the `{}` modifier to keep the default formatting of `{}`", default_modifier, default_result, diff --git a/src/librustc_target/asm/aarch64.rs b/src/librustc_target/asm/aarch64.rs index 16bc5d670d8..e7c9edea765 100644 --- a/src/librustc_target/asm/aarch64.rs +++ b/src/librustc_target/asm/aarch64.rs @@ -18,22 +18,26 @@ impl AArch64InlineAsmRegClass { } } + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + pub fn suggest_modifier( self, _arch: InlineAsmArch, ty: InlineAsmType, - ) -> Option<(char, &'static str, Option<&'static str>)> { + ) -> Option<(char, &'static str)> { match self { Self::reg => match ty.size().bits() { 64 => None, - _ => Some(('w', "w0", None)), + _ => Some(('w', "w0")), }, Self::vreg | Self::vreg_low16 => match ty.size().bits() { - 8 => Some(('b', "b0", None)), - 16 => Some(('h', "h0", None)), - 32 => Some(('s', "s0", None)), - 64 => Some(('d', "d0", None)), - 128 => Some(('q', "q0", None)), + 8 => Some(('b', "b0")), + 16 => Some(('h', "h0")), + 32 => Some(('s', "s0")), + 64 => Some(('d', "d0")), + 128 => Some(('q', "q0")), _ => None, }, } diff --git a/src/librustc_target/asm/arm.rs b/src/librustc_target/asm/arm.rs index 0ceb15e297f..1798b2a0949 100644 --- a/src/librustc_target/asm/arm.rs +++ b/src/librustc_target/asm/arm.rs @@ -25,11 +25,15 @@ impl ArmInlineAsmRegClass { } } + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + pub fn suggest_modifier( self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str, Option<&'static str>)> { + ) -> Option<(char, &'static str)> { None } diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index dda6e7cd5cd..f1e8457cacc 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -291,9 +291,20 @@ impl InlineAsmRegClass { } } + /// Returns a suggested register class to use for this type. This is called + /// after type checking via `supported_types` fails to give a better error + /// message to the user. + pub fn suggest_class(self, arch: InlineAsmArch, ty: InlineAsmType) -> Option { + match self { + Self::X86(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::X86), + Self::Arm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Arm), + Self::AArch64(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::AArch64), + Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV), + } + } + /// Returns a suggested template modifier to use for this type and an - /// example of a register named formatted with it. Optionally also returns - /// the name of a different register class to use instead. + /// example of a register named formatted with it. /// /// Such suggestions are useful if a type smaller than the full register /// size is used and a modifier can be used to point to the subregister of @@ -302,7 +313,7 @@ impl InlineAsmRegClass { self, arch: InlineAsmArch, ty: InlineAsmType, - ) -> Option<(char, &'static str, Option<&'static str>)> { + ) -> Option<(char, &'static str)> { match self { Self::X86(r) => r.suggest_modifier(arch, ty), Self::Arm(r) => r.suggest_modifier(arch, ty), diff --git a/src/librustc_target/asm/riscv.rs b/src/librustc_target/asm/riscv.rs index f9b132c2087..7da30cc8875 100644 --- a/src/librustc_target/asm/riscv.rs +++ b/src/librustc_target/asm/riscv.rs @@ -14,11 +14,15 @@ impl RiscVInlineAsmRegClass { &[] } + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + pub fn suggest_modifier( self, _arch: InlineAsmArch, _ty: InlineAsmType, - ) -> Option<(char, &'static str, Option<&'static str>)> { + ) -> Option<(char, &'static str)> { None } diff --git a/src/librustc_target/asm/x86.rs b/src/librustc_target/asm/x86.rs index d10bcb40ba0..6eb99b0180f 100644 --- a/src/librustc_target/asm/x86.rs +++ b/src/librustc_target/asm/x86.rs @@ -6,6 +6,7 @@ def_reg_class! { X86 X86InlineAsmRegClass { reg, reg_abcd, + reg_byte, xmm_reg, ymm_reg, zmm_reg, @@ -30,46 +31,45 @@ impl X86InlineAsmRegClass { &['l', 'h', 'x', 'e'] } } + Self::reg_byte => &[], Self::xmm_reg | Self::ymm_reg | Self::zmm_reg => &['x', 'y', 'z'], Self::kreg => &[], } } + pub fn suggest_class(self, _arch: InlineAsmArch, ty: InlineAsmType) -> Option { + match self { + Self::reg | Self::reg_abcd if ty.size().bits() == 8 => Some(Self::reg_byte), + _ => None, + } + } + pub fn suggest_modifier( self, arch: InlineAsmArch, ty: InlineAsmType, - ) -> Option<(char, &'static str, Option<&'static str>)> { + ) -> Option<(char, &'static str)> { match self { Self::reg => match ty.size().bits() { - 8 => { - if arch == InlineAsmArch::X86_64 { - Some(('l', "al", None)) - } else { - // Low byte registers require reg_abcd on x86 so we emit - // a suggestion to use that register class instead. - Some(('l', "al", Some("reg_abcd"))) - } - } - 16 => Some(('x', "ax", None)), - 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", None)), + 16 => Some(('x', "ax")), + 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")), _ => None, }, Self::reg_abcd => match ty.size().bits() { - 8 => Some(('l', "al", None)), - 16 => Some(('x', "ax", None)), - 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax", None)), + 16 => Some(('x', "ax")), + 32 if arch == InlineAsmArch::X86_64 => Some(('e', "eax")), _ => None, }, + Self::reg_byte => None, Self::xmm_reg => None, Self::ymm_reg => match ty.size().bits() { 256 => None, - _ => Some(('x', "xmm0", None)), + _ => Some(('x', "xmm0")), }, Self::zmm_reg => match ty.size().bits() { 512 => None, - 256 => Some(('y', "ymm0", None)), - _ => Some(('x', "xmm0", None)), + 256 => Some(('y', "ymm0")), + _ => Some(('x', "xmm0")), }, Self::kreg => None, } @@ -84,6 +84,7 @@ impl X86InlineAsmRegClass { Some(('e', "eax")) } } + Self::reg_byte => None, Self::xmm_reg => Some(('x', "xmm0")), Self::ymm_reg => Some(('y', "ymm0")), Self::zmm_reg => Some(('z', "zmm0")), @@ -98,11 +99,12 @@ impl X86InlineAsmRegClass { match self { Self::reg | Self::reg_abcd => { if arch == InlineAsmArch::X86_64 { - types! { _: I8, I16, I32, I64, F32, F64; } + types! { _: I16, I32, I64, F32, F64; } } else { - types! { _: I8, I16, I32, F32; } + types! { _: I16, I32, F32; } } } + Self::reg_byte => types! { _: I8; }, Self::xmm_reg => types! { "sse": I32, I64, F32, F64, VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF32(4), VecF64(2); @@ -139,20 +141,38 @@ fn x86_64_only( def_regs! { X86 X86InlineAsmReg X86InlineAsmRegClass { - ax: reg, reg_abcd = ["ax", "al", "eax", "rax"], - bx: reg, reg_abcd = ["bx", "bl", "ebx", "rbx"], - cx: reg, reg_abcd = ["cx", "cl", "ecx", "rcx"], - dx: reg, reg_abcd = ["dx", "dl", "edx", "rdx"], - si: reg = ["si", "sil", "esi", "rsi"], - di: reg = ["di", "dil", "edi", "rdi"], - r8: reg = ["r8", "r8b", "r8w", "r8d"] % x86_64_only, - r9: reg = ["r9", "r9b", "r9w", "r9d"] % x86_64_only, - r10: reg = ["r10", "r10b", "r10w", "r10d"] % x86_64_only, - r11: reg = ["r11", "r11b", "r11w", "r11d"] % x86_64_only, - r12: reg = ["r12", "r12b", "r12w", "r12d"] % x86_64_only, - r13: reg = ["r13", "r13b", "r13w", "r13d"] % x86_64_only, - r14: reg = ["r14", "r14b", "r14w", "r14d"] % x86_64_only, - r15: reg = ["r15", "r15b", "r15w", "r15d"] % x86_64_only, + ax: reg, reg_abcd = ["ax", "eax", "rax"], + bx: reg, reg_abcd = ["bx", "ebx", "rbx"], + cx: reg, reg_abcd = ["cx", "ecx", "rcx"], + dx: reg, reg_abcd = ["dx", "edx", "rdx"], + si: reg = ["si", "esi", "rsi"], + di: reg = ["di", "edi", "rdi"], + r8: reg = ["r8", "r8w", "r8d"] % x86_64_only, + r9: reg = ["r9", "r9w", "r9d"] % x86_64_only, + r10: reg = ["r10", "r10w", "r10d"] % x86_64_only, + r11: reg = ["r11", "r11w", "r11d"] % x86_64_only, + r12: reg = ["r12", "r12w", "r12d"] % x86_64_only, + r13: reg = ["r13", "r13w", "r13d"] % x86_64_only, + r14: reg = ["r14", "r14w", "r14d"] % x86_64_only, + r15: reg = ["r15", "r15w", "r15d"] % x86_64_only, + al: reg_byte = ["al"], + ah: reg_byte = ["ah"], + bl: reg_byte = ["bl"], + bh: reg_byte = ["bh"], + cl: reg_byte = ["cl"], + ch: reg_byte = ["ch"], + dl: reg_byte = ["dl"], + dh: reg_byte = ["dh"], + sil: reg_byte = ["sil"] % x86_64_only, + dil: reg_byte = ["dil"] % x86_64_only, + r8b: reg_byte = ["r8b"] % x86_64_only, + r9b: reg_byte = ["r9b"] % x86_64_only, + r10b: reg_byte = ["r10b"] % x86_64_only, + r11b: reg_byte = ["r11b"] % x86_64_only, + r12b: reg_byte = ["r12b"] % x86_64_only, + r13b: reg_byte = ["r13b"] % x86_64_only, + r14b: reg_byte = ["r14b"] % x86_64_only, + r15b: reg_byte = ["r15b"] % x86_64_only, xmm0: xmm_reg = ["xmm0"], xmm1: xmm_reg = ["xmm1"], xmm2: xmm_reg = ["xmm2"], @@ -224,8 +244,6 @@ def_regs! { k5: kreg = ["k5"], k6: kreg = ["k6"], k7: kreg = ["k7"], - #error = ["ah", "bh", "ch", "dh"] => - "high byte registers are not currently supported as operands for inline asm", #error = ["bp", "bpl", "ebp", "rbp"] => "the frame pointer cannot be used as an operand for inline asm", #error = ["sp", "spl", "esp", "rsp"] => @@ -281,6 +299,8 @@ impl X86InlineAsmReg { 'r' => write!(out, "r{}", index), _ => unreachable!(), } + } else if self as u32 <= Self::r15b as u32 { + out.write_str(self.name()) } else if self as u32 <= Self::xmm15 as u32 { let prefix = modifier.unwrap_or('x'); let index = self as u32 - Self::xmm0 as u32; @@ -301,8 +321,39 @@ impl X86InlineAsmReg { pub fn overlapping_regs(self, mut cb: impl FnMut(X86InlineAsmReg)) { macro_rules! reg_conflicts { - ($($x:ident : $y:ident : $z:ident,)*) => { + ( + $( + $w:ident : $l:ident $h:ident + ),*; + $( + $w2:ident : $l2:ident + ),*; + $( + $x:ident : $y:ident : $z:ident + ),*; + ) => { match self { + $( + Self::$w => { + cb(Self::$w); + cb(Self::$l); + cb(Self::$h); + } + Self::$l => { + cb(Self::$w); + cb(Self::$l); + } + Self::$h => { + cb(Self::$w); + cb(Self::$h); + } + )* + $( + Self::$w2 | Self::$l2 => { + cb(Self::$w2); + cb(Self::$l2); + } + )* $( Self::$x | Self::$y | Self::$z => { cb(Self::$x); @@ -324,6 +375,20 @@ impl X86InlineAsmReg { // registers are only available with AVX-512, so we just specify them // as aliases directly. reg_conflicts! { + ax : al ah, + bx : bl bh, + cx : cl ch, + dx : dl dh; + si : sil, + di : dil, + r8 : r8b, + r9 : r9b, + r10 : r10b, + r11 : r11b, + r12 : r12b, + r13 : r13b, + r14 : r14b, + r15 : r15b; xmm0 : ymm0 : zmm0, xmm1 : ymm1 : zmm1, xmm2 : ymm2 : zmm2, @@ -339,7 +404,7 @@ impl X86InlineAsmReg { xmm12 : ymm12 : zmm12, xmm13 : ymm13 : zmm13, xmm14 : ymm14 : zmm14, - xmm15 : ymm15 : zmm15, + xmm15 : ymm15 : zmm15; } } } diff --git a/src/test/assembly/asm/x86-types.rs b/src/test/assembly/asm/x86-types.rs index d2819ac88e7..508d6801580 100644 --- a/src/test/assembly/asm/x86-types.rs +++ b/src/test/assembly/asm/x86-types.rs @@ -266,13 +266,6 @@ macro_rules! check { }; } -// CHECK-LABEL: reg_i8: -// 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_i8 i8 reg "mov"); - // CHECK-LABEL: reg_i16: // CHECK: #APP // x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} @@ -315,13 +308,6 @@ check!(reg_f64 f64 reg "mov"); // CHECK: #NO_APP check!(reg_ptr ptr reg "mov"); -// CHECK-LABEL: reg_abcd_i8: -// 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_i8 i8 reg_abcd "mov"); - // CHECK-LABEL: reg_abcd_i16: // CHECK: #APP // x86_64: mov r{{[a-z0-9]+}}, r{{[a-z0-9]+}} @@ -364,6 +350,12 @@ check!(reg_abcd_f64 f64 reg_abcd "mov"); // 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]+}} diff --git a/src/test/ui/asm/bad-reg.rs b/src/test/ui/asm/bad-reg.rs index ed7faa4b156..016ea9329c4 100644 --- a/src/test/ui/asm/bad-reg.rs +++ b/src/test/ui/asm/bad-reg.rs @@ -25,8 +25,6 @@ fn main() { //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature asm!("", in("zmm0") foo); //~^ ERROR register class `zmm_reg` requires the `avx512f` target feature - asm!("", in("ah") foo); - //~^ ERROR invalid register `ah`: high byte registers are not currently supported asm!("", in("ebp") foo); //~^ ERROR invalid register `ebp`: the frame pointer cannot be used as an operand asm!("", in("rsp") foo); @@ -44,7 +42,7 @@ fn main() { // (except in/lateout which don't conflict) asm!("", in("eax") foo, in("al") bar); - //~^ ERROR register `ax` conflicts with register `ax` + //~^ ERROR register `al` conflicts with register `ax` asm!("", in("rax") foo, out("rax") bar); //~^ ERROR register `ax` conflicts with register `ax` asm!("", in("al") foo, lateout("al") bar); diff --git a/src/test/ui/asm/bad-reg.stderr b/src/test/ui/asm/bad-reg.stderr index a9d872dae41..a1423f0e9c1 100644 --- a/src/test/ui/asm/bad-reg.stderr +++ b/src/test/ui/asm/bad-reg.stderr @@ -58,58 +58,52 @@ error: register class `zmm_reg` requires the `avx512f` target feature LL | asm!("", in("zmm0") foo); | ^^^^^^^^^^^^^^ -error: invalid register `ah`: high byte registers are not currently supported as operands for inline asm - --> $DIR/bad-reg.rs:28:18 - | -LL | asm!("", in("ah") foo); - | ^^^^^^^^^^^^ - error: invalid register `ebp`: the frame pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:30:18 + --> $DIR/bad-reg.rs:28:18 | LL | asm!("", in("ebp") foo); | ^^^^^^^^^^^^^ error: invalid register `rsp`: the stack pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:32:18 + --> $DIR/bad-reg.rs:30:18 | LL | asm!("", in("rsp") foo); | ^^^^^^^^^^^^^ error: invalid register `ip`: the instruction pointer cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:34:18 + --> $DIR/bad-reg.rs:32:18 | LL | asm!("", in("ip") foo); | ^^^^^^^^^^^^ error: invalid register `st(2)`: x87 registers are not currently supported as operands for inline asm - --> $DIR/bad-reg.rs:36:18 + --> $DIR/bad-reg.rs:34:18 | LL | asm!("", in("st(2)") foo); | ^^^^^^^^^^^^^^^ error: invalid register `mm0`: MMX registers are not currently supported as operands for inline asm - --> $DIR/bad-reg.rs:38:18 + --> $DIR/bad-reg.rs:36:18 | LL | asm!("", in("mm0") foo); | ^^^^^^^^^^^^^ error: invalid register `k0`: the k0 AVX mask register cannot be used as an operand for inline asm - --> $DIR/bad-reg.rs:40:18 + --> $DIR/bad-reg.rs:38:18 | LL | asm!("", in("k0") foo); | ^^^^^^^^^^^^ -error: register `ax` conflicts with register `ax` - --> $DIR/bad-reg.rs:46:33 +error: register `al` conflicts with register `ax` + --> $DIR/bad-reg.rs:44:33 | LL | asm!("", in("eax") foo, in("al") bar); - | ------------- ^^^^^^^^^^^^ register `ax` + | ------------- ^^^^^^^^^^^^ register `al` | | | register `ax` error: register `ax` conflicts with register `ax` - --> $DIR/bad-reg.rs:48:33 + --> $DIR/bad-reg.rs:46:33 | LL | asm!("", in("rax") foo, out("rax") bar); | ------------- ^^^^^^^^^^^^^^ register `ax` @@ -117,13 +111,13 @@ LL | asm!("", in("rax") foo, out("rax") bar); | register `ax` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:48:18 + --> $DIR/bad-reg.rs:46:18 | LL | asm!("", in("rax") foo, out("rax") bar); | ^^^^^^^^^^^^^ error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:51:34 + --> $DIR/bad-reg.rs:49:34 | LL | asm!("", in("xmm0") foo, in("ymm0") bar); | -------------- ^^^^^^^^^^^^^^ register `ymm0` @@ -131,7 +125,7 @@ LL | asm!("", in("xmm0") foo, in("ymm0") bar); | register `xmm0` error: register `ymm0` conflicts with register `xmm0` - --> $DIR/bad-reg.rs:53:34 + --> $DIR/bad-reg.rs:51:34 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | -------------- ^^^^^^^^^^^^^^^ register `ymm0` @@ -139,10 +133,10 @@ LL | asm!("", in("xmm0") foo, out("ymm0") bar); | register `xmm0` | help: use `lateout` instead of `out` to avoid conflict - --> $DIR/bad-reg.rs:53:18 + --> $DIR/bad-reg.rs:51:18 | LL | asm!("", in("xmm0") foo, out("ymm0") bar); | ^^^^^^^^^^^^^^ -error: aborting due to 19 previous errors +error: aborting due to 18 previous errors diff --git a/src/test/ui/asm/type-check-3.rs b/src/test/ui/asm/type-check-3.rs index 750d28026d7..5de15fe4906 100644 --- a/src/test/ui/asm/type-check-3.rs +++ b/src/test/ui/asm/type-check-3.rs @@ -29,7 +29,7 @@ fn main() { // Template modifier suggestions for sub-registers - asm!("{0} {0}", in(reg) 0i8); + asm!("{0} {0}", in(reg) 0i16); //~^ WARN formatting may not be suitable for sub-register argument asm!("{0} {0:x}", in(reg) 0i16); //~^ WARN formatting may not be suitable for sub-register argument @@ -39,23 +39,26 @@ fn main() { asm!("{}", in(ymm_reg) 0i64); //~^ WARN formatting may not be suitable for sub-register argument asm!("{}", in(ymm_reg) _mm256_setzero_ps()); - asm!("{:l}", in(reg) 0i8); asm!("{:l}", in(reg) 0i16); asm!("{:l}", in(reg) 0i32); asm!("{:l}", in(reg) 0i64); asm!("{:x}", in(ymm_reg) 0i64); asm!("{:x}", in(ymm_reg) _mm256_setzero_ps()); + // Suggest different register class for type + + asm!("{}", in(reg) 0i8); + //~^ ERROR type `i8` cannot be used with this register class + asm!("{}", in(reg_byte) 0i8); + // Split inout operands must have compatible types - let mut val_i8: i8; + let mut val_i16: i16; let mut val_f32: f32; let mut val_u32: u32; let mut val_u64: u64; let mut val_ptr: *mut u8; - asm!("{:r}", inout(reg) 0u8 => val_i8); - asm!("{:r}", inout(reg) 0u16 => val_i8); - //~^ ERROR incompatible types for asm inout argument + asm!("{:r}", inout(reg) 0u16 => val_i16); asm!("{:r}", inout(reg) 0u32 => val_f32); //~^ ERROR incompatible types for asm inout argument asm!("{:r}", inout(reg) 0u32 => val_ptr); diff --git a/src/test/ui/asm/type-check-3.stderr b/src/test/ui/asm/type-check-3.stderr index ccc795d1013..01dbe78db88 100644 --- a/src/test/ui/asm/type-check-3.stderr +++ b/src/test/ui/asm/type-check-3.stderr @@ -4,7 +4,7 @@ error: type `i128` cannot be used with this register class LL | asm!("{}", in(reg) 0i128); | ^^^^^ | - = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 error: type `std::arch::x86_64::__m128` cannot be used with this register class --> $DIR/type-check-3.rs:14:28 @@ -12,7 +12,7 @@ error: type `std::arch::x86_64::__m128` cannot be used with this register class LL | asm!("{}", in(reg) _mm_setzero_ps()); | ^^^^^^^^^^^^^^^^ | - = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 error: type `std::arch::x86_64::__m256` cannot be used with this register class --> $DIR/type-check-3.rs:16:28 @@ -20,7 +20,7 @@ error: type `std::arch::x86_64::__m256` cannot be used with this register class LL | asm!("{}", in(reg) _mm256_setzero_ps()); | ^^^^^^^^^^^^^^^^^^^ | - = note: register class `reg` supports these types: i8, i16, i32, i64, f32, f64 + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 error: type `u8` cannot be used with this register class --> $DIR/type-check-3.rs:18:32 @@ -41,11 +41,11 @@ LL | asm!("{}", in(kreg) 0u64); warning: formatting may not be suitable for sub-register argument --> $DIR/type-check-3.rs:32:15 | -LL | asm!("{0} {0}", in(reg) 0i8); - | ^^^ ^^^ --- for this argument +LL | asm!("{0} {0}", in(reg) 0i16); + | ^^^ ^^^ ---- for this argument | = note: `#[warn(asm_sub_register)]` on by default - = help: use the `l` modifier to have the register formatted as `al` + = help: use the `x` modifier to have the register formatted as `ax` = help: or use the `r` modifier to keep the default formatting of `rax` warning: formatting may not be suitable for sub-register argument @@ -75,18 +75,17 @@ LL | asm!("{}", in(ymm_reg) 0i64); = help: use the `x` modifier to have the register formatted as `xmm0` = help: or use the `y` modifier to keep the default formatting of `ymm0` -error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:57:33 +error: type `i8` cannot be used with this register class + --> $DIR/type-check-3.rs:50:28 | -LL | asm!("{:r}", inout(reg) 0u16 => val_i8); - | ^^^^ ^^^^^^ type `i8` - | | - | type `u16` +LL | asm!("{}", in(reg) 0i8); + | ^^^ | - = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size + = note: register class `reg` supports these types: i16, i32, i64, f32, f64 + = help: consider using the `reg_byte` register class instead error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:59:33 + --> $DIR/type-check-3.rs:62:33 | LL | asm!("{:r}", inout(reg) 0u32 => val_f32); | ^^^^ ^^^^^^^ type `f32` @@ -96,7 +95,7 @@ LL | asm!("{:r}", inout(reg) 0u32 => val_f32); = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:61:33 + --> $DIR/type-check-3.rs:64:33 | LL | asm!("{:r}", inout(reg) 0u32 => val_ptr); | ^^^^ ^^^^^^^ type `*mut u8` @@ -106,7 +105,7 @@ LL | asm!("{:r}", inout(reg) 0u32 => val_ptr); = note: asm inout arguments must have the same type, unless they are both pointers or integers of the same size error: incompatible types for asm inout argument - --> $DIR/type-check-3.rs:63:33 + --> $DIR/type-check-3.rs:66:33 | LL | asm!("{:r}", inout(reg) main => val_u32); | ^^^^ ^^^^^^^ type `u32` -- cgit 1.4.1-3-g733a5 From 08822546a5656bc5a60831513be75e3e24ca54c0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 1 May 2020 23:59:15 +0100 Subject: Implement att_syntax option --- src/librustc_ast_lowering/expr.rs | 9 +++++++++ src/librustc_ast_pretty/pprust.rs | 3 +++ src/librustc_builtin_macros/asm.rs | 6 ++++-- src/librustc_codegen_llvm/asm.rs | 6 +++++- src/librustc_hir_pretty/lib.rs | 3 +++ src/librustc_span/symbol.rs | 1 + src/librustc_target/asm/mod.rs | 1 + src/test/ui/asm/parse-error.stderr | 8 ++++---- 8 files changed, 30 insertions(+), 7 deletions(-) (limited to 'src/test') diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index f713db9a6cc..72ca8418f83 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -980,6 +980,15 @@ impl<'hir> LoweringContext<'_, 'hir> { struct_span_err!(self.sess, sp, E0472, "asm! is unsupported on this target").emit(); return hir::ExprKind::Err; }; + if asm.options.contains(asm::InlineAsmOptions::ATT_SYNTAX) { + match asm_arch { + asm::InlineAsmArch::X86 | asm::InlineAsmArch::X86_64 => {} + _ => self + .sess + .struct_span_err(sp, "the `att_syntax` option is only supported on x86") + .emit(), + } + } // Lower operands to HIR, filter_map skips any operands with invalid // register classes. diff --git a/src/librustc_ast_pretty/pprust.rs b/src/librustc_ast_pretty/pprust.rs index 1f371f15f18..432f8d47276 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/src/librustc_ast_pretty/pprust.rs @@ -2118,6 +2118,9 @@ impl<'a> State<'a> { if opts.contains(InlineAsmOptions::NOSTACK) { options.push("nostack"); } + if opts.contains(InlineAsmOptions::ATT_SYNTAX) { + options.push("att_syntax"); + } s.commasep(Inconsistent, &options, |s, &opt| { s.word(opt); }); diff --git a/src/librustc_builtin_macros/asm.rs b/src/librustc_builtin_macros/asm.rs index c9a3401cac0..bc068cdcde0 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/src/librustc_builtin_macros/asm.rs @@ -279,9 +279,11 @@ fn parse_options<'a>(p: &mut Parser<'a>, args: &mut AsmArgs) -> Result<(), Diagn args.options |= InlineAsmOptions::PRESERVES_FLAGS; } else if p.eat(&token::Ident(sym::noreturn, false)) { args.options |= InlineAsmOptions::NORETURN; - } else { - p.expect(&token::Ident(sym::nostack, false))?; + } else if p.eat(&token::Ident(sym::nostack, false)) { args.options |= InlineAsmOptions::NOSTACK; + } else { + p.expect(&token::Ident(sym::att_syntax, false))?; + args.options |= InlineAsmOptions::ATT_SYNTAX; } // Allow trailing commas diff --git a/src/librustc_codegen_llvm/asm.rs b/src/librustc_codegen_llvm/asm.rs index 861a756a2ef..0ad304d5a67 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/src/librustc_codegen_llvm/asm.rs @@ -269,7 +269,11 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { tys => self.type_struct(&tys, false), }; let dialect = match asm_arch { - InlineAsmArch::X86 | InlineAsmArch::X86_64 => LlvmAsmDialect::Intel, + InlineAsmArch::X86 | InlineAsmArch::X86_64 + if !options.contains(InlineAsmOptions::ATT_SYNTAX) => + { + LlvmAsmDialect::Intel + } _ => LlvmAsmDialect::Att, }; let result = inline_asm_call( diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs index 918b5901375..312b8edfe23 100644 --- a/src/librustc_hir_pretty/lib.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -1503,6 +1503,9 @@ impl<'a> State<'a> { if opts.contains(InlineAsmOptions::NOSTACK) { options.push("nostack"); } + if opts.contains(InlineAsmOptions::ATT_SYNTAX) { + options.push("att_syntax"); + } s.commasep(Inconsistent, &options, |s, &opt| { s.word(opt); }); diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 1f0764b06b0..a38f5949204 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -160,6 +160,7 @@ symbols! { attr, attributes, attr_literals, + att_syntax, augmented_assignments, automatically_derived, avx512_target_feature, diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index 2a0c51f2afd..5bdfdfefeda 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -426,6 +426,7 @@ bitflags::bitflags! { const PRESERVES_FLAGS = 1 << 3; const NORETURN = 1 << 4; const NOSTACK = 1 << 5; + const ATT_SYNTAX = 1 << 6; } } diff --git a/src/test/ui/asm/parse-error.stderr b/src/test/ui/asm/parse-error.stderr index 94eb9d29862..fa422f56bec 100644 --- a/src/test/ui/asm/parse-error.stderr +++ b/src/test/ui/asm/parse-error.stderr @@ -64,11 +64,11 @@ error: argument to `sym` must be a path expression LL | asm!("{}", sym foo + bar); | ^^^^^^^^^ -error: expected one of `)`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, or `readonly`, found `foo` +error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, or `readonly`, found `foo` --> $DIR/parse-error.rs:31:26 | LL | asm!("", options(foo)); - | ^^^ expected one of 7 possible tokens + | ^^^ expected one of 8 possible tokens error: expected one of `)` or `,`, found `foo` --> $DIR/parse-error.rs:33:32 @@ -76,11 +76,11 @@ error: expected one of `)` or `,`, found `foo` LL | asm!("", options(nomem foo)); | ^^^ expected one of `)` or `,` -error: expected one of `)`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, or `readonly`, found `foo` +error: expected one of `)`, `att_syntax`, `nomem`, `noreturn`, `nostack`, `preserves_flags`, `pure`, or `readonly`, found `foo` --> $DIR/parse-error.rs:35:33 | LL | asm!("", options(nomem, foo)); - | ^^^ expected one of 7 possible tokens + | ^^^ expected one of 8 possible tokens error: asm options cannot be specified multiple times --> $DIR/parse-error.rs:37:29 -- cgit 1.4.1-3-g733a5 From ddcdea45b6cda159a5a1fbf729105b788ec725e0 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 6 May 2020 11:41:37 +0100 Subject: The h modifier is only supported by reg_abcd --- src/librustc_target/asm/x86.rs | 2 +- src/test/assembly/asm/x86-modifiers.rs | 7 ------- 2 files changed, 1 insertion(+), 8 deletions(-) (limited to 'src/test') diff --git a/src/librustc_target/asm/x86.rs b/src/librustc_target/asm/x86.rs index 065bb14966f..c3dd7bc8e7b 100644 --- a/src/librustc_target/asm/x86.rs +++ b/src/librustc_target/asm/x86.rs @@ -19,7 +19,7 @@ impl X86InlineAsmRegClass { match self { Self::reg => { if arch == InlineAsmArch::X86_64 { - &['l', 'h', 'x', 'e', 'r'] + &['l', 'x', 'e', 'r'] } else { &['x', 'e'] } diff --git a/src/test/assembly/asm/x86-modifiers.rs b/src/test/assembly/asm/x86-modifiers.rs index 460e22aa69e..1670744291f 100644 --- a/src/test/assembly/asm/x86-modifiers.rs +++ b/src/test/assembly/asm/x86-modifiers.rs @@ -63,13 +63,6 @@ check!(reg "" reg "mov"); #[cfg(x86_64)] check!(reg_l "l" reg "mov"); -// x86_64-LABEL: reg_h: -// x86_64: #APP -// x86_64: mov ah, ah -// x86_64: #NO_APP -#[cfg(x86_64)] -check!(reg_h "h" reg "mov"); - // CHECK-LABEL: reg_x: // CHECK: #APP // CHECK: mov ax, ax -- cgit 1.4.1-3-g733a5 From 330bdf89b114a22f2509f27f5e2f4a9db309d2a4 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Wed, 6 May 2020 12:04:22 +0100 Subject: Disable asm tests on system llvm --- src/test/assembly/asm/aarch64-modifiers.rs | 1 + src/test/assembly/asm/aarch64-types.rs | 1 + src/test/assembly/asm/arm-modifiers.rs | 1 + src/test/assembly/asm/arm-types.rs | 1 + src/test/assembly/asm/riscv-modifiers.rs | 1 + src/test/assembly/asm/riscv-types.rs | 1 + src/test/assembly/asm/x86-types.rs | 1 + 7 files changed, 7 insertions(+) (limited to 'src/test') diff --git a/src/test/assembly/asm/aarch64-modifiers.rs b/src/test/assembly/asm/aarch64-modifiers.rs index d4519ca7ffa..c2484e9b6d0 100644 --- a/src/test/assembly/asm/aarch64-modifiers.rs +++ b/src/test/assembly/asm/aarch64-modifiers.rs @@ -1,3 +1,4 @@ +// no-system-llvm // assembly-output: emit-asm // compile-flags: -O // compile-flags: --target aarch64-unknown-linux-gnu diff --git a/src/test/assembly/asm/aarch64-types.rs b/src/test/assembly/asm/aarch64-types.rs index 8b763462e4a..ce2f0082a06 100644 --- a/src/test/assembly/asm/aarch64-types.rs +++ b/src/test/assembly/asm/aarch64-types.rs @@ -1,3 +1,4 @@ +// no-system-llvm // assembly-output: emit-asm // compile-flags: --target aarch64-unknown-linux-gnu diff --git a/src/test/assembly/asm/arm-modifiers.rs b/src/test/assembly/asm/arm-modifiers.rs index cefab9c4a67..b71503d0a53 100644 --- a/src/test/assembly/asm/arm-modifiers.rs +++ b/src/test/assembly/asm/arm-modifiers.rs @@ -1,3 +1,4 @@ +// no-system-llvm // assembly-output: emit-asm // compile-flags: -O // compile-flags: --target armv7-unknown-linux-gnueabihf diff --git a/src/test/assembly/asm/arm-types.rs b/src/test/assembly/asm/arm-types.rs index 729adae66f6..1e338f56c4d 100644 --- a/src/test/assembly/asm/arm-types.rs +++ b/src/test/assembly/asm/arm-types.rs @@ -1,3 +1,4 @@ +// no-system-llvm // assembly-output: emit-asm // compile-flags: --target armv7-unknown-linux-gnueabihf // compile-flags: -C target-feature=+neon diff --git a/src/test/assembly/asm/riscv-modifiers.rs b/src/test/assembly/asm/riscv-modifiers.rs index 622d0c0dc5e..8c816e3220b 100644 --- a/src/test/assembly/asm/riscv-modifiers.rs +++ b/src/test/assembly/asm/riscv-modifiers.rs @@ -1,3 +1,4 @@ +// no-system-llvm // assembly-output: emit-asm // compile-flags: -O // compile-flags: --target riscv64gc-unknown-linux-gnu diff --git a/src/test/assembly/asm/riscv-types.rs b/src/test/assembly/asm/riscv-types.rs index 5c10753c765..449213471cc 100644 --- a/src/test/assembly/asm/riscv-types.rs +++ b/src/test/assembly/asm/riscv-types.rs @@ -1,3 +1,4 @@ +// no-system-llvm // revisions: riscv64 riscv32 // assembly-output: emit-asm //[riscv64] compile-flags: --target riscv64imac-unknown-none-elf diff --git a/src/test/assembly/asm/x86-types.rs b/src/test/assembly/asm/x86-types.rs index 508d6801580..de2e67c421f 100644 --- a/src/test/assembly/asm/x86-types.rs +++ b/src/test/assembly/asm/x86-types.rs @@ -1,3 +1,4 @@ +// no-system-llvm // revisions: x86_64 i686 // assembly-output: emit-asm //[x86_64] compile-flags: --target x86_64-unknown-linux-gnu -- cgit 1.4.1-3-g733a5 From 2aa9aaada5f7ebd0236bf7ebdbbce6ec8b684239 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 8 May 2020 01:15:56 +0100 Subject: Add borrow-check test --- src/test/ui/asm/bad-reg.stderr | 2 +- src/test/ui/asm/type-check-4.rs | 23 +++++++++++++++++++++++ src/test/ui/asm/type-check-4.stderr | 26 ++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/asm/type-check-4.rs create mode 100644 src/test/ui/asm/type-check-4.stderr (limited to 'src/test') diff --git a/src/test/ui/asm/bad-reg.stderr b/src/test/ui/asm/bad-reg.stderr index a1423f0e9c1..c6b7d310dfa 100644 --- a/src/test/ui/asm/bad-reg.stderr +++ b/src/test/ui/asm/bad-reg.stderr @@ -18,7 +18,7 @@ LL | asm!("{:z}", in(reg) foo); | | | template modifier | - = note: the `reg` register class supports the following template modifiers: `l`, `h`, `x`, `e`, `r` + = note: the `reg` register class supports the following template modifiers: `l`, `x`, `e`, `r` error: invalid asm template modifier for this register class --> $DIR/bad-reg.rs:18:15 diff --git a/src/test/ui/asm/type-check-4.rs b/src/test/ui/asm/type-check-4.rs new file mode 100644 index 00000000000..2be627c1165 --- /dev/null +++ b/src/test/ui/asm/type-check-4.rs @@ -0,0 +1,23 @@ +// only-x86_64 + +#![feature(asm)] + +fn main() { + unsafe { + // Can't output to borrowed values. + + let mut a = 0isize; + let p = &a; + asm!("{}", out(reg) a); + //~^ cannot assign to `a` because it is borrowed + println!("{}", p); + + // Can't read from mutable borrowed values. + + let mut a = 0isize; + let p = &mut a; + asm!("{}", in(reg) a); + //~^ cannot use `a` because it was mutably borrowed + println!("{}", p); + } +} diff --git a/src/test/ui/asm/type-check-4.stderr b/src/test/ui/asm/type-check-4.stderr new file mode 100644 index 00000000000..8035bbefc1a --- /dev/null +++ b/src/test/ui/asm/type-check-4.stderr @@ -0,0 +1,26 @@ +error[E0506]: cannot assign to `a` because it is borrowed + --> $DIR/type-check-4.rs:11:9 + | +LL | let p = &a; + | -- borrow of `a` occurs here +LL | asm!("{}", out(reg) a); + | ^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `a` occurs here +LL | +LL | println!("{}", p); + | - borrow later used here + +error[E0503]: cannot use `a` because it was mutably borrowed + --> $DIR/type-check-4.rs:19:28 + | +LL | let p = &mut a; + | ------ borrow of `a` occurs here +LL | asm!("{}", in(reg) a); + | ^ use of borrowed `a` +LL | +LL | println!("{}", p); + | - borrow later used here + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0503, E0506. +For more information about an error, try `rustc --explain E0503`. -- cgit 1.4.1-3-g733a5 From ac1fb93fce892f52a5b563b2fcb364f6a603fc0d Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 8 May 2020 16:37:57 +0100 Subject: Fix feature gate tests --- src/test/ui/feature-gates/feature-gate-asm.rs | 6 ++++-- src/test/ui/feature-gates/feature-gate-asm.stderr | 6 +++--- src/test/ui/feature-gates/feature-gate-asm2.rs | 6 ++++-- src/test/ui/feature-gates/feature-gate-asm2.stderr | 6 +++--- 4 files changed, 14 insertions(+), 10 deletions(-) (limited to 'src/test') diff --git a/src/test/ui/feature-gates/feature-gate-asm.rs b/src/test/ui/feature-gates/feature-gate-asm.rs index 7eeeb4bc4e2..4eb72031d51 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.rs +++ b/src/test/ui/feature-gates/feature-gate-asm.rs @@ -2,7 +2,9 @@ fn main() { unsafe { - asm!(""); //~ ERROR inline assembly is not stable enough - llvm_asm!(""); //~ ERROR inline assembly is not stable enough + asm!(""); + //~^ ERROR inline assembly is not stable enough + llvm_asm!(""); + //~^ ERROR LLVM-style inline assembly will never be stabilized } } diff --git a/src/test/ui/feature-gates/feature-gate-asm.stderr b/src/test/ui/feature-gates/feature-gate-asm.stderr index 1f9eaa5632e..a71643e0d33 100644 --- a/src/test/ui/feature-gates/feature-gate-asm.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm.stderr @@ -4,11 +4,11 @@ error[E0658]: use of unstable library feature 'asm': inline assembly is not stab LL | asm!(""); | ^^^ | - = note: see issue #70173 for more information + = note: see issue #72016 for more information = help: add `#![feature(asm)]` to the crate attributes to enable -error[E0658]: use of unstable library feature 'llvm_asm': inline assembly is not stable enough for use and is subject to change - --> $DIR/feature-gate-asm.rs:6:9 +error[E0658]: use of unstable library feature 'llvm_asm': LLVM-style inline assembly will never be stabilized, prefer using asm! instead + --> $DIR/feature-gate-asm.rs:7:9 | LL | llvm_asm!(""); | ^^^^^^^^ diff --git a/src/test/ui/feature-gates/feature-gate-asm2.rs b/src/test/ui/feature-gates/feature-gate-asm2.rs index 666a4894f62..8bd7226aca7 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.rs +++ b/src/test/ui/feature-gates/feature-gate-asm2.rs @@ -2,7 +2,9 @@ fn main() { unsafe { - println!("{:?}", asm!("")); //~ ERROR inline assembly is not stable - println!("{:?}", llvm_asm!("")); //~ ERROR inline assembly is not stable + println!("{:?}", asm!("")); + //~^ ERROR inline assembly is not stable enough + println!("{:?}", llvm_asm!("")); + //~^ ERROR LLVM-style inline assembly will never be stabilized } } diff --git a/src/test/ui/feature-gates/feature-gate-asm2.stderr b/src/test/ui/feature-gates/feature-gate-asm2.stderr index 17ba66e9842..a8022cb72e0 100644 --- a/src/test/ui/feature-gates/feature-gate-asm2.stderr +++ b/src/test/ui/feature-gates/feature-gate-asm2.stderr @@ -4,11 +4,11 @@ error[E0658]: use of unstable library feature 'asm': inline assembly is not stab LL | println!("{:?}", asm!("")); | ^^^ | - = note: see issue #70173 for more information + = note: see issue #72016 for more information = help: add `#![feature(asm)]` to the crate attributes to enable -error[E0658]: use of unstable library feature 'llvm_asm': inline assembly is not stable enough for use and is subject to change - --> $DIR/feature-gate-asm2.rs:6:26 +error[E0658]: use of unstable library feature 'llvm_asm': LLVM-style inline assembly will never be stabilized, prefer using asm! instead + --> $DIR/feature-gate-asm2.rs:7:26 | LL | println!("{:?}", llvm_asm!("")); | ^^^^^^^^ -- cgit 1.4.1-3-g733a5 From 46db0dfe8c5f26c687b5ce269b55ad1aa6d3dc95 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Fri, 8 May 2020 18:14:06 +0100 Subject: Fix tests --- src/libfmt_macros/tests.rs | 4 ++-- src/test/assembly/asm/x86-modifiers.rs | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) (limited to 'src/test') diff --git a/src/libfmt_macros/tests.rs b/src/libfmt_macros/tests.rs index a0cef78f924..9932c1df7a9 100644 --- a/src/libfmt_macros/tests.rs +++ b/src/libfmt_macros/tests.rs @@ -1,7 +1,7 @@ use super::*; fn same(fmt: &'static str, p: &[Piece<'static>]) { - let parser = Parser::new(fmt, None, vec![], false, ParseMode::Format); + let parser = Parser::new(fmt, None, None, false, ParseMode::Format); assert_eq!(parser.collect::>>(), p); } @@ -20,7 +20,7 @@ fn fmtdflt() -> FormatSpec<'static> { } fn musterr(s: &str) { - let mut p = Parser::new(s, None, vec![], false, ParseMode::Format); + let mut p = Parser::new(s, None, None, false, ParseMode::Format); p.next(); assert!(!p.errors.is_empty()); } diff --git a/src/test/assembly/asm/x86-modifiers.rs b/src/test/assembly/asm/x86-modifiers.rs index 1670744291f..e538167cd46 100644 --- a/src/test/assembly/asm/x86-modifiers.rs +++ b/src/test/assembly/asm/x86-modifiers.rs @@ -1,3 +1,4 @@ +// no-system-llvm // revisions: x86_64 i686 // assembly-output: emit-asm // compile-flags: -O -- cgit 1.4.1-3-g733a5 From cecffdc1d74718444b6654b120dcd57dcbad018f Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Mon, 11 May 2020 17:53:32 +0100 Subject: Fix const handling and add tests for const operands --- src/librustc_codegen_ssa/mir/block.rs | 219 ++++++++++++++++++++-------------- src/test/ui/asm/const.rs | 56 +++++++++ 2 files changed, 184 insertions(+), 91 deletions(-) create mode 100644 src/test/ui/asm/const.rs (limited to 'src/test') diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs index 923fcd326a2..b487ed8dea8 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/src/librustc_codegen_ssa/mir/block.rs @@ -13,6 +13,7 @@ use rustc_ast::ast; use rustc_hir::lang_items; use rustc_index::vec::Idx; use rustc_middle::mir; +use rustc_middle::mir::interpret::{AllocId, ConstValue, Pointer, Scalar}; use rustc_middle::mir::AssertKind; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; @@ -821,6 +822,123 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { cleanup, ); } + + fn codegen_asm_terminator( + &mut self, + helper: TerminatorCodegenHelper<'tcx>, + mut bx: Bx, + terminator: &mir::Terminator<'tcx>, + template: &[ast::InlineAsmTemplatePiece], + operands: &[mir::InlineAsmOperand<'tcx>], + options: ast::InlineAsmOptions, + destination: Option, + ) { + let span = terminator.source_info.span; + + let operands: Vec<_> = operands + .iter() + .map(|op| match *op { + mir::InlineAsmOperand::In { reg, ref value } => { + let value = self.codegen_operand(&mut bx, value); + InlineAsmOperandRef::In { reg, value } + } + mir::InlineAsmOperand::Out { reg, late, ref place } => { + let place = place.map(|place| self.codegen_place(&mut bx, place.as_ref())); + InlineAsmOperandRef::Out { reg, late, place } + } + mir::InlineAsmOperand::InOut { reg, late, ref in_value, ref out_place } => { + let in_value = self.codegen_operand(&mut bx, in_value); + let out_place = + out_place.map(|out_place| self.codegen_place(&mut bx, out_place.as_ref())); + InlineAsmOperandRef::InOut { reg, late, in_value, out_place } + } + mir::InlineAsmOperand::Const { ref value } => { + if let mir::Operand::Constant(constant) = value { + let const_value = self + .eval_mir_constant(constant) + .unwrap_or_else(|_| span_bug!(span, "asm const cannot be resolved")); + let ty = constant.literal.ty; + let size = bx.layout_of(ty).size; + let scalar = match const_value { + // Promoted constants are evaluated into a ByRef instead of a Scalar, + // but we want the scalar value here. + ConstValue::ByRef { alloc, offset } => { + let ptr = Pointer::new(AllocId(0), offset); + alloc + .read_scalar(&bx, ptr, size) + .and_then(|s| s.not_undef()) + .unwrap_or_else(|e| { + bx.tcx().sess.span_err( + span, + &format!("Could not evaluate asm const: {}", e), + ); + + // We are erroring out, just emit a dummy constant. + Scalar::from_u64(0) + }) + } + _ => span_bug!(span, "expected ByRef for promoted asm const"), + }; + let value = scalar.assert_bits(size); + let string = match ty.kind { + ty::Uint(_) => value.to_string(), + ty::Int(int_ty) => { + match int_ty.normalize(bx.tcx().sess.target.ptr_width) { + ast::IntTy::I8 => (value as i8).to_string(), + ast::IntTy::I16 => (value as i16).to_string(), + ast::IntTy::I32 => (value as i32).to_string(), + ast::IntTy::I64 => (value as i64).to_string(), + ast::IntTy::I128 => (value as i128).to_string(), + ast::IntTy::Isize => unreachable!(), + } + } + ty::Float(ast::FloatTy::F32) => { + f32::from_bits(value as u32).to_string() + } + ty::Float(ast::FloatTy::F64) => { + f64::from_bits(value as u64).to_string() + } + _ => span_bug!(span, "asm const has bad type {}", ty), + }; + InlineAsmOperandRef::Const { string } + } else { + span_bug!(span, "asm const is not a constant"); + } + } + mir::InlineAsmOperand::SymFn { ref value } => { + let literal = self.monomorphize(&value.literal); + if let ty::FnDef(def_id, substs) = literal.ty.kind { + let instance = ty::Instance::resolve( + bx.tcx(), + ty::ParamEnv::reveal_all(), + def_id, + substs, + ) + .unwrap() + .unwrap(); + InlineAsmOperandRef::SymFn { instance } + } else { + span_bug!(span, "invalid type for asm sym (fn)"); + } + } + mir::InlineAsmOperand::SymStatic { ref value } => { + if let Some(def_id) = value.check_static_ptr(bx.tcx()) { + InlineAsmOperandRef::SymStatic { def_id } + } else { + span_bug!(span, "invalid type for asm sym (static)"); + } + } + }) + .collect(); + + bx.codegen_inline_asm(template, &operands, options, span); + + if let Some(target) = destination { + helper.funclet_br(self, &mut bx, target); + } else { + bx.unreachable(); + } + } } impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { @@ -916,97 +1034,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { bug!("borrowck false edges in codegen") } - mir::TerminatorKind::InlineAsm { template, ref operands, options, ref destination } => { - let span = terminator.source_info.span; - - let operands: Vec<_> = operands - .iter() - .map(|op| match *op { - mir::InlineAsmOperand::In { reg, ref value } => { - let value = self.codegen_operand(&mut bx, value); - InlineAsmOperandRef::In { reg, value } - } - mir::InlineAsmOperand::Out { reg, late, ref place } => { - let place = - place.map(|place| self.codegen_place(&mut bx, place.as_ref())); - InlineAsmOperandRef::Out { reg, late, place } - } - mir::InlineAsmOperand::InOut { reg, late, ref in_value, ref out_place } => { - let in_value = self.codegen_operand(&mut bx, in_value); - let out_place = out_place - .map(|out_place| self.codegen_place(&mut bx, out_place.as_ref())); - InlineAsmOperandRef::InOut { reg, late, in_value, out_place } - } - mir::InlineAsmOperand::Const { ref value } => { - if let mir::Operand::Constant(constant) = value { - let const_value = - self.eval_mir_constant(constant).unwrap_or_else(|_| { - span_bug!(span, "asm const cannot be resolved") - }); - let ty = constant.literal.ty; - let value = const_value - .try_to_bits_for_ty(bx.tcx(), ty::ParamEnv::reveal_all(), ty) - .unwrap_or_else(|| { - span_bug!(span, "asm const has non-scalar value") - }); - let string = match ty.kind { - ty::Uint(_) => value.to_string(), - ty::Int(int_ty) => { - match int_ty.normalize(bx.tcx().sess.target.ptr_width) { - ast::IntTy::I8 => (value as i8).to_string(), - ast::IntTy::I16 => (value as i16).to_string(), - ast::IntTy::I32 => (value as i32).to_string(), - ast::IntTy::I64 => (value as i64).to_string(), - ast::IntTy::I128 => (value as i128).to_string(), - ast::IntTy::Isize => unreachable!(), - } - } - ty::Float(ast::FloatTy::F32) => { - f32::from_bits(value as u32).to_string() - } - ty::Float(ast::FloatTy::F64) => { - f64::from_bits(value as u64).to_string() - } - _ => span_bug!(span, "asm const has bad type {}", ty), - }; - InlineAsmOperandRef::Const { string } - } else { - span_bug!(span, "asm const is not a constant"); - } - } - mir::InlineAsmOperand::SymFn { ref value } => { - let literal = self.monomorphize(&value.literal); - if let ty::FnDef(def_id, substs) = literal.ty.kind { - let instance = ty::Instance::resolve( - bx.tcx(), - ty::ParamEnv::reveal_all(), - def_id, - substs, - ) - .unwrap() - .unwrap(); - InlineAsmOperandRef::SymFn { instance } - } else { - span_bug!(span, "invalid type for asm sym (fn)"); - } - } - mir::InlineAsmOperand::SymStatic { ref value } => { - if let Some(def_id) = value.check_static_ptr(bx.tcx()) { - InlineAsmOperandRef::SymStatic { def_id } - } else { - span_bug!(span, "invalid type for asm sym (static)"); - } - } - }) - .collect(); - - bx.codegen_inline_asm(template, &operands, options, span); - - if let Some(target) = destination { - helper.funclet_br(self, &mut bx, *target); - } else { - bx.unreachable(); - } + mir::TerminatorKind::InlineAsm { template, ref operands, options, destination } => { + self.codegen_asm_terminator( + helper, + bx, + terminator, + template, + operands, + options, + destination, + ); } } } diff --git a/src/test/ui/asm/const.rs b/src/test/ui/asm/const.rs new file mode 100644 index 00000000000..e08da24f44a --- /dev/null +++ b/src/test/ui/asm/const.rs @@ -0,0 +1,56 @@ +// no-system-llvm +// only-x86_64 +// run-pass + +#![feature(asm)] + +use std::mem::size_of; + +trait Proj { + const C: usize; +} +impl Proj for i8 { + const C: usize = 8; +} +impl Proj for i16 { + const C: usize = 16; +} + +const fn constfn(x: usize) -> usize { + x +} + +fn generic() { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const size_of::()); + assert_eq!(a, size_of::()); + + let b: usize; + asm!("mov {}, {}", out(reg) b, const size_of::() + constfn(5)); + assert_eq!(b, size_of::() + 5); + + let c: usize; + asm!("mov {}, {}", out(reg) c, const T::C); + assert_eq!(c, T::C); + } +} + +fn main() { + unsafe { + let a: usize; + asm!("mov {}, {}", out(reg) a, const 5); + assert_eq!(a, 5); + + let b: usize; + asm!("mov {}, {}", out(reg) b, const constfn(5)); + assert_eq!(b, 5); + + let c: usize; + asm!("mov {}, {}", out(reg) c, const constfn(5) + constfn(5)); + assert_eq!(c, 10); + } + + generic::(); + generic::(); +} -- cgit 1.4.1-3-g733a5