From aa9da4b85922f34ba2cb7f6c7b3f8068a5d55e85 Mon Sep 17 00:00:00 2001 From: Brian Cain Date: Thu, 2 Apr 2026 09:36:14 -0700 Subject: [PATCH] Hexagon inline asm: add reg_pair, vreg, vreg_pair, and qreg register classes Add new Hexagon inline asm register classes: - reg_pair: GPR double registers (r1:0 through r27:26) for i64/f64 types - vreg: HVX vector registers (v0-v31) for mode-dependent vector types - vreg_pair: HVX vector pair registers (v1:0 through v31:30) for vector pairs - qreg: HVX predicate registers (q0-q3), clobber-only Key implementation details: - GPR pairs use LLVM's 'd' register naming (d0-d13) for constraints - HVX vector pairs use LLVM's 'w' register naming (w0-w15) for constraints - Register overlap tracking for GPR pair<->single and HVX pair<->single conflicts - HVX vector types are mode-dependent (64B vs 128B HVX length) Note: vreg_quad (HVX vector quads) is not supported as LLVM's Hexagon backend does not support vector quad types in inline asm constraints. --- compiler/rustc_codegen_gcc/src/asm.rs | 16 ++ compiler/rustc_codegen_llvm/src/asm.rs | 74 +++++++++ compiler/rustc_span/src/symbol.rs | 4 + compiler/rustc_target/src/asm/hexagon.rs | 150 ++++++++++++++++- tests/assembly-llvm/asm/hexagon-types.rs | 65 +++++++- tests/ui/asm/hexagon/bad-reg.rs | 114 +++++++++++++ tests/ui/asm/hexagon/bad-reg.stderr | 202 +++++++++++++++++++++++ 7 files changed, 623 insertions(+), 2 deletions(-) create mode 100644 tests/ui/asm/hexagon/bad-reg.rs create mode 100644 tests/ui/asm/hexagon/bad-reg.stderr diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index c5fb257107ff5..1443aa925f741 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -687,9 +687,15 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str { InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg_pair) => "r", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => { unreachable!("clobber-only") } + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::vreg) => "v", + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::vreg_pair) => "v", + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::qreg) => { + unreachable!("clobber-only") + } InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r", InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f", InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r", @@ -779,9 +785,19 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl cx.type_vector(cx.type_i64(), 2) } InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg_pair) => cx.type_i64(), InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => { unreachable!("clobber-only") } + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::vreg) => { + cx.type_vector(cx.type_i32(), 16) + } + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::vreg_pair) => { + cx.type_vector(cx.type_i32(), 32) + } + InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::qreg) => { + unreachable!("clobber-only") + } InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index 1bd40d32285ad..c5ab9fc2336eb 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -575,6 +575,52 @@ fn a64_vreg_index(reg: InlineAsmReg) -> Option { } } +/// If the register is a Hexagon register pair then return its LLVM double register index. +/// LLVM uses `d0`, `d1`, ... for Hexagon double registers in inline asm constraints, +/// not the assembly-printed `r1:0`, `r3:2`, ... format. +fn hexagon_reg_pair_index(reg: InlineAsmReg) -> Option { + match reg { + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r1_0) => Some(0), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r3_2) => Some(1), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r5_4) => Some(2), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r7_6) => Some(3), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r9_8) => Some(4), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r11_10) => Some(5), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r13_12) => Some(6), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r15_14) => Some(7), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r17_16) => Some(8), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r21_20) => Some(10), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r23_22) => Some(11), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r25_24) => Some(12), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::r27_26) => Some(13), + _ => None, + } +} + +/// If the register is a Hexagon HVX vector pair then return its LLVM W-register index. +/// LLVM uses `w0`, `w1`, ... for Hexagon vector pair registers in inline asm constraints. +fn hexagon_vreg_pair_index(reg: InlineAsmReg) -> Option { + match reg { + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v1_0) => Some(0), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v3_2) => Some(1), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v5_4) => Some(2), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v7_6) => Some(3), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v9_8) => Some(4), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v11_10) => Some(5), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v13_12) => Some(6), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v15_14) => Some(7), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v17_16) => Some(8), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v19_18) => Some(9), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v21_20) => Some(10), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v23_22) => Some(11), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v25_24) => Some(12), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v27_26) => Some(13), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v29_28) => Some(14), + InlineAsmReg::Hexagon(HexagonInlineAsmReg::v31_30) => Some(15), + _ => None, + } +} + /// Converts a register class to an LLVM constraint code. fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> String { use InlineAsmRegClass::*; @@ -624,6 +670,12 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> 'q' }; format!("{{{}{}}}", class, idx) + } else if let Some(idx) = hexagon_reg_pair_index(reg) { + // LLVM uses `dN` for Hexagon double registers, not the `rN+1:N` asm syntax. + format!("{{d{}}}", idx) + } else if let Some(idx) = hexagon_vreg_pair_index(reg) { + // LLVM uses `wN` for Hexagon HVX vector pair registers. + format!("{{w{}}}", idx) } else if reg == InlineAsmReg::Arm(ArmInlineAsmReg::r14) { // LLVM doesn't recognize r14 "{lr}".to_string() @@ -647,7 +699,11 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> | Arm(ArmInlineAsmRegClass::qreg_low4) => "x", Arm(ArmInlineAsmRegClass::dreg) | Arm(ArmInlineAsmRegClass::qreg) => "w", Hexagon(HexagonInlineAsmRegClass::reg) => "r", + Hexagon(HexagonInlineAsmRegClass::reg_pair) => "r", Hexagon(HexagonInlineAsmRegClass::preg) => unreachable!("clobber-only"), + Hexagon(HexagonInlineAsmRegClass::vreg) => "v", + Hexagon(HexagonInlineAsmRegClass::vreg_pair) => "v", + Hexagon(HexagonInlineAsmRegClass::qreg) => unreachable!("clobber-only"), LoongArch(LoongArchInlineAsmRegClass::reg) => "r", LoongArch(LoongArchInlineAsmRegClass::freg) => "f", Mips(MipsInlineAsmRegClass::reg) => "r", @@ -828,7 +884,25 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' | Arm(ArmInlineAsmRegClass::qreg_low8) | Arm(ArmInlineAsmRegClass::qreg_low4) => cx.type_vector(cx.type_i64(), 2), Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(), + Hexagon(HexagonInlineAsmRegClass::reg_pair) => cx.type_i64(), Hexagon(HexagonInlineAsmRegClass::preg) => unreachable!("clobber-only"), + Hexagon(HexagonInlineAsmRegClass::vreg) => { + // HVX vector register size depends on the HVX mode. + // LLVM's "v" constraint requires the exact vector width. + if cx.tcx.sess.unstable_target_features.contains(&sym::hvx_length128b) { + cx.type_vector(cx.type_i32(), 32) // 1024-bit for 128B mode + } else { + cx.type_vector(cx.type_i32(), 16) // 512-bit for 64B mode + } + } + Hexagon(HexagonInlineAsmRegClass::vreg_pair) => { + if cx.tcx.sess.unstable_target_features.contains(&sym::hvx_length128b) { + cx.type_vector(cx.type_i32(), 64) // 2048-bit for 128B mode + } else { + cx.type_vector(cx.type_i32(), 32) // 1024-bit for 64B mode + } + } + Hexagon(HexagonInlineAsmRegClass::qreg) => unreachable!("clobber-only"), LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(), LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(), Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 30bf8dd7c2206..6e39539a44daa 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1042,6 +1042,9 @@ symbols! { html_no_source, html_playground_url, html_root_url, + hvx, + hvx_length64b: "hvx-length64b", + hvx_length128b: "hvx-length128b", hwaddress, i8, i16, @@ -2215,6 +2218,7 @@ symbols! { volatile_store, vreg, vreg_low16, + vreg_pair, vsreg, vsx, vtable_align, diff --git a/compiler/rustc_target/src/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs index aa14ca3f337b6..592edd554f74d 100644 --- a/compiler/rustc_target/src/asm/hexagon.rs +++ b/compiler/rustc_target/src/asm/hexagon.rs @@ -7,7 +7,11 @@ use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; def_reg_class! { Hexagon HexagonInlineAsmRegClass { reg, + reg_pair, preg, + vreg, + vreg_pair, + qreg, } } @@ -38,7 +42,17 @@ impl HexagonInlineAsmRegClass { ) -> &'static [(InlineAsmType, Option)] { match self { Self::reg => types! { _: I8, I16, I32, F32; }, + Self::reg_pair => types! { _: I64, F64; }, Self::preg => &[], + Self::vreg => types! { + hvx_length64b: VecI32(16); + hvx_length128b: VecI32(32); + }, + Self::vreg_pair => types! { + hvx_length64b: VecI32(32); + hvx_length128b: VecI32(64); + }, + Self::qreg => &[], } } } @@ -73,18 +87,89 @@ def_regs! { r26: reg = ["r26"], r27: reg = ["r27"], r28: reg = ["r28"], + r1_0: reg_pair = ["r1:0"], + r3_2: reg_pair = ["r3:2"], + r5_4: reg_pair = ["r5:4"], + r7_6: reg_pair = ["r7:6"], + r9_8: reg_pair = ["r9:8"], + r11_10: reg_pair = ["r11:10"], + r13_12: reg_pair = ["r13:12"], + r15_14: reg_pair = ["r15:14"], + r17_16: reg_pair = ["r17:16"], + r21_20: reg_pair = ["r21:20"], + r23_22: reg_pair = ["r23:22"], + r25_24: reg_pair = ["r25:24"], + r27_26: reg_pair = ["r27:26"], p0: preg = ["p0"], p1: preg = ["p1"], p2: preg = ["p2"], p3: preg = ["p3"], + v0: vreg = ["v0"], + v1: vreg = ["v1"], + v2: vreg = ["v2"], + v3: vreg = ["v3"], + v4: vreg = ["v4"], + v5: vreg = ["v5"], + v6: vreg = ["v6"], + v7: vreg = ["v7"], + v8: vreg = ["v8"], + v9: vreg = ["v9"], + v10: vreg = ["v10"], + v11: vreg = ["v11"], + v12: vreg = ["v12"], + v13: vreg = ["v13"], + v14: vreg = ["v14"], + v15: vreg = ["v15"], + v16: vreg = ["v16"], + v17: vreg = ["v17"], + v18: vreg = ["v18"], + v19: vreg = ["v19"], + v20: vreg = ["v20"], + v21: vreg = ["v21"], + v22: vreg = ["v22"], + v23: vreg = ["v23"], + v24: vreg = ["v24"], + v25: vreg = ["v25"], + v26: vreg = ["v26"], + v27: vreg = ["v27"], + v28: vreg = ["v28"], + v29: vreg = ["v29"], + v30: vreg = ["v30"], + v31: vreg = ["v31"], + v1_0: vreg_pair = ["v1:0"], + v3_2: vreg_pair = ["v3:2"], + v5_4: vreg_pair = ["v5:4"], + v7_6: vreg_pair = ["v7:6"], + v9_8: vreg_pair = ["v9:8"], + v11_10: vreg_pair = ["v11:10"], + v13_12: vreg_pair = ["v13:12"], + v15_14: vreg_pair = ["v15:14"], + v17_16: vreg_pair = ["v17:16"], + v19_18: vreg_pair = ["v19:18"], + v21_20: vreg_pair = ["v21:20"], + v23_22: vreg_pair = ["v23:22"], + v25_24: vreg_pair = ["v25:24"], + v27_26: vreg_pair = ["v27:26"], + v29_28: vreg_pair = ["v29:28"], + v31_30: vreg_pair = ["v31:30"], + q0: qreg = ["q0"], + q1: qreg = ["q1"], + q2: qreg = ["q2"], + q3: qreg = ["q3"], #error = ["r19"] => "r19 is used internally by LLVM and cannot be used as an operand for inline asm", + #error = ["r19:18"] => + "r19 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r29", "sp"] => "the stack pointer cannot be used as an operand for inline asm", + #error = ["r29:28"] => + "the stack pointer cannot be used as an operand for inline asm", #error = ["r30", "fr"] => "the frame register cannot be used as an operand for inline asm", #error = ["r31", "lr"] => "the link register cannot be used as an operand for inline asm", + #error = ["r31:30"] => + "the frame register and link register cannot be used as an operand for inline asm", } } @@ -98,5 +183,68 @@ impl HexagonInlineAsmReg { out.write_str(self.name()) } - pub fn overlapping_regs(self, mut _cb: impl FnMut(HexagonInlineAsmReg)) {} + pub fn overlapping_regs(self, mut cb: impl FnMut(HexagonInlineAsmReg)) { + cb(self); + + macro_rules! reg_pair_conflicts { + ( + $( + $pair:ident : $hi:ident $lo:ident, + )* + ) => { + match self { + $( + Self::$pair => { + cb(Self::$hi); + cb(Self::$lo); + } + Self::$hi => { + cb(Self::$pair); + } + Self::$lo => { + cb(Self::$pair); + } + )* + _ => {} + } + }; + } + + // GPR pair ↔ single GPR conflicts + reg_pair_conflicts! { + r1_0 : r1 r0, + r3_2 : r3 r2, + r5_4 : r5 r4, + r7_6 : r7 r6, + r9_8 : r9 r8, + r11_10 : r11 r10, + r13_12 : r13 r12, + r15_14 : r15 r14, + r17_16 : r17 r16, + r21_20 : r21 r20, + r23_22 : r23 r22, + r25_24 : r25 r24, + r27_26 : r27 r26, + } + + // HVX vector pair ↔ single vector conflicts + reg_pair_conflicts! { + v1_0 : v1 v0, + v3_2 : v3 v2, + v5_4 : v5 v4, + v7_6 : v7 v6, + v9_8 : v9 v8, + v11_10 : v11 v10, + v13_12 : v13 v12, + v15_14 : v15 v14, + v17_16 : v17 v16, + v19_18 : v19 v18, + v21_20 : v21 v20, + v23_22 : v23 v22, + v25_24 : v25 v24, + v27_26 : v27 v26, + v29_28 : v29 v28, + v31_30 : v31 v30, + } + } } diff --git a/tests/assembly-llvm/asm/hexagon-types.rs b/tests/assembly-llvm/asm/hexagon-types.rs index fb66d777b677d..258e5b4355e0d 100644 --- a/tests/assembly-llvm/asm/hexagon-types.rs +++ b/tests/assembly-llvm/asm/hexagon-types.rs @@ -1,10 +1,11 @@ //@ add-minicore //@ assembly-output: emit-asm //@ compile-flags: --target hexagon-unknown-linux-musl +//@ compile-flags: -C target-feature=+hvx-length128b //@ compile-flags: -Zmerge-functions=disabled //@ needs-llvm-components: hexagon -#![feature(no_core, asm_experimental_arch)] +#![feature(no_core, repr_simd, asm_experimental_arch)] #![crate_type = "rlib"] #![no_core] #![allow(asm_sub_register, non_camel_case_types)] @@ -14,6 +15,14 @@ use minicore::*; type ptr = *const i32; +#[repr(simd)] +pub struct i32x32([i32; 32]); // 1024-bit HVX vector (128B mode) +impl Copy for i32x32 {} + +#[repr(simd)] +pub struct i32x64([i32; 64]); // 2048-bit HVX vector pair (128B mode) +impl Copy for i32x64 {} + extern "C" { fn extern_func(); static extern_static: u8; @@ -137,3 +146,57 @@ check_reg!(r0_i8 i8 "r0"); // CHECK: r0 = r0 // CHECK: InlineAsm End check_reg!(r0_i16 i16 "r0"); + +// ===== Register pair (reg_pair) tests ===== + +// CHECK-LABEL: reg_pair_i64: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}}:{{[0-9]+}} = combine(r{{[0-9]+}},r{{[0-9]+}}) +// CHECK: InlineAsm End +check!(reg_pair_i64 i64 reg_pair); + +// CHECK-LABEL: reg_pair_f64: +// CHECK: InlineAsm Start +// CHECK: r{{[0-9]+}}:{{[0-9]+}} = combine(r{{[0-9]+}},r{{[0-9]+}}) +// CHECK: InlineAsm End +check!(reg_pair_f64 f64 reg_pair); + +// CHECK-LABEL: r1_0_i64: +// CHECK: InlineAsm Start +// CHECK: r1:0 = combine(r1,r0) +// CHECK: InlineAsm End +check_reg!(r1_0_i64 i64 "r1:0"); + +// CHECK-LABEL: r1_0_f64: +// CHECK: InlineAsm Start +// CHECK: r1:0 = combine(r1,r0) +// CHECK: InlineAsm End +check_reg!(r1_0_f64 f64 "r1:0"); + +// ===== HVX vector register (vreg) tests ===== + +// CHECK-LABEL: vreg_i32x32: +// CHECK: InlineAsm Start +// CHECK: v{{[0-9]+}} = v{{[0-9]+}} +// CHECK: InlineAsm End +check!(vreg_i32x32 i32x32 vreg); + +// CHECK-LABEL: v0_i32x32: +// CHECK: InlineAsm Start +// CHECK: v0 = v0 +// CHECK: InlineAsm End +check_reg!(v0_i32x32 i32x32 "v0"); + +// ===== HVX vector pair (vreg_pair) tests ===== + +// CHECK-LABEL: vreg_pair_i32x64: +// CHECK: InlineAsm Start +// CHECK: v{{[0-9]+}}:{{[0-9]+}} = vcombine(r{{[0-9]+}},r{{[0-9]+}}) +// CHECK: InlineAsm End +check!(vreg_pair_i32x64 i32x64 vreg_pair); + +// CHECK-LABEL: v1_0_i32x64: +// CHECK: InlineAsm Start +// CHECK: v1:0 = vcombine(r1,r0) +// CHECK: InlineAsm End +check_reg!(v1_0_i32x64 i32x64 "v1:0"); diff --git a/tests/ui/asm/hexagon/bad-reg.rs b/tests/ui/asm/hexagon/bad-reg.rs new file mode 100644 index 0000000000000..6d3e1521a26cc --- /dev/null +++ b/tests/ui/asm/hexagon/bad-reg.rs @@ -0,0 +1,114 @@ +//@ add-minicore +//@ compile-flags: --target hexagon-unknown-linux-musl -C target-feature=+hvx-length128b +//@ needs-llvm-components: hexagon +//@ ignore-backends: gcc + +//~? WARN unstable feature specified for `-Ctarget-feature`: `hvx-length128b` + +#![crate_type = "lib"] +#![feature(no_core, asm_experimental_arch)] +#![no_core] + +extern crate minicore; +use minicore::*; + +fn f() { + let mut x: i32 = 0; + let mut y: i64 = 0; + unsafe { + // Blocked registers + asm!("", out("r19") _); + //~^ ERROR invalid register `r19`: r19 is used internally by LLVM and cannot be used as an operand for inline asm + asm!("", out("sp") _); + //~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + asm!("", out("r29") _); + //~^ ERROR invalid register `r29`: the stack pointer cannot be used as an operand for inline asm + asm!("", out("r30") _); + //~^ ERROR invalid register `r30`: the frame register cannot be used as an operand for inline asm + asm!("", out("fr") _); + //~^ ERROR invalid register `fr`: the frame register cannot be used as an operand for inline asm + asm!("", out("r31") _); + //~^ ERROR invalid register `r31`: the link register cannot be used as an operand for inline asm + asm!("", out("lr") _); + //~^ ERROR invalid register `lr`: the link register cannot be used as an operand for inline asm + + // Blocked register pairs + asm!("", out("r19:18") _); + //~^ ERROR invalid register `r19:18`: r19 is used internally by LLVM and cannot be used as an operand for inline asm + asm!("", out("r29:28") _); + //~^ ERROR invalid register `r29:28`: the stack pointer cannot be used as an operand for inline asm + asm!("", out("r31:30") _); + //~^ ERROR invalid register `r31:30`: the frame register and link register cannot be used as an operand for inline asm + + // Clobber-only: preg + asm!("", out("p0") _); // ok (clobber) + asm!("", in("p0") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("", out("p0") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + + // Clobber-only: qreg + asm!("", out("q0") _); // ok (clobber) + asm!("", in("q0") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + asm!("", out("q0") x); + //~^ ERROR can only be used as a clobber + //~| ERROR type `i32` cannot be used with this register class + + // Type mismatches: reg (supports i8, i16, i32, f32) + asm!("/* {} */", in(reg) y); + //~^ ERROR type `i64` cannot be used with this register class + + // Type mismatches: reg_pair (supports i64, f64) + asm!("/* {} */", in(reg_pair) x); + //~^ ERROR type `i32` cannot be used with this register class + + // Type mismatches: vreg (supports vector types only) + asm!("/* {} */", in(vreg) x); + //~^ ERROR type `i32` cannot be used with this register class + asm!("/* {} */", in(vreg) y); + //~^ ERROR type `i64` cannot be used with this register class + + // Type mismatches: vreg_pair (supports vector types only) + asm!("/* {} */", in(vreg_pair) x); + //~^ ERROR type `i32` cannot be used with this register class + asm!("/* {} */", in(vreg_pair) y); + //~^ ERROR type `i64` cannot be used with this register class + + // Valid usage: reg + asm!("", out("r0") _); + asm!("/* {} */", in(reg) x); + + // Valid usage: reg_pair + asm!("", out("r1:0") _); + asm!("/* {} */", in(reg_pair) y); + + // Valid usage: vreg clobber + asm!("", out("v0") _); + + // Valid usage: vreg_pair clobber + asm!("", out("v1:0") _); + + // Valid usage: qreg clobber + asm!("", out("q0") _); + + // Register pair overlap: r0 and r1:0 conflict + asm!("", out("r0") _, out("r1:0") _); + //~^ ERROR register `r1:0` conflicts with register `r0` + asm!("", out("r1") _, out("r1:0") _); + //~^ ERROR register `r1:0` conflicts with register `r1` + + // HVX vector pair overlap: v0 and v1:0 conflict + asm!("", out("v0") _, out("v1:0") _); + //~^ ERROR register `v1:0` conflicts with register `v0` + asm!("", out("v1") _, out("v1:0") _); + //~^ ERROR register `v1:0` conflicts with register `v1` + + // Non-overlapping pair and single: no conflict + asm!("", out("r0") _, out("r3:2") _); + asm!("", out("v0") _, out("v3:2") _); + } +} diff --git a/tests/ui/asm/hexagon/bad-reg.stderr b/tests/ui/asm/hexagon/bad-reg.stderr new file mode 100644 index 0000000000000..57c381bf411a3 --- /dev/null +++ b/tests/ui/asm/hexagon/bad-reg.stderr @@ -0,0 +1,202 @@ +warning: unstable feature specified for `-Ctarget-feature`: `hvx-length128b` + | + = note: this feature is not stably supported; its behavior can change in the future + +error: invalid register `r19`: r19 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:20:18 + | +LL | asm!("", out("r19") _); + | ^^^^^^^^^^^^ + +error: invalid register `sp`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:22:18 + | +LL | asm!("", out("sp") _); + | ^^^^^^^^^^^ + +error: invalid register `r29`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:24:18 + | +LL | asm!("", out("r29") _); + | ^^^^^^^^^^^^ + +error: invalid register `r30`: the frame register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:26:18 + | +LL | asm!("", out("r30") _); + | ^^^^^^^^^^^^ + +error: invalid register `fr`: the frame register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:28:18 + | +LL | asm!("", out("fr") _); + | ^^^^^^^^^^^ + +error: invalid register `r31`: the link register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:30:18 + | +LL | asm!("", out("r31") _); + | ^^^^^^^^^^^^ + +error: invalid register `lr`: the link register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:32:18 + | +LL | asm!("", out("lr") _); + | ^^^^^^^^^^^ + +error: invalid register `r19:18`: r19 is used internally by LLVM and cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:36:18 + | +LL | asm!("", out("r19:18") _); + | ^^^^^^^^^^^^^^^ + +error: invalid register `r29:28`: the stack pointer cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:38:18 + | +LL | asm!("", out("r29:28") _); + | ^^^^^^^^^^^^^^^ + +error: invalid register `r31:30`: the frame register and link register cannot be used as an operand for inline asm + --> $DIR/bad-reg.rs:40:18 + | +LL | asm!("", out("r31:30") _); + | ^^^^^^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:45:18 + | +LL | asm!("", in("p0") x); + | ^^^^^^^^^^ + +error: register class `preg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:48:18 + | +LL | asm!("", out("p0") x); + | ^^^^^^^^^^^ + +error: register class `qreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:54:18 + | +LL | asm!("", in("q0") x); + | ^^^^^^^^^^ + +error: register class `qreg` can only be used as a clobber, not as an input or output + --> $DIR/bad-reg.rs:57:18 + | +LL | asm!("", out("q0") x); + | ^^^^^^^^^^^ + +error: register `r1:0` conflicts with register `r0` + --> $DIR/bad-reg.rs:99:31 + | +LL | asm!("", out("r0") _, out("r1:0") _); + | ----------- ^^^^^^^^^^^^^ register `r1:0` + | | + | register `r0` + +error: register `r1:0` conflicts with register `r1` + --> $DIR/bad-reg.rs:101:31 + | +LL | asm!("", out("r1") _, out("r1:0") _); + | ----------- ^^^^^^^^^^^^^ register `r1:0` + | | + | register `r1` + +error: register `v1:0` conflicts with register `v0` + --> $DIR/bad-reg.rs:105:31 + | +LL | asm!("", out("v0") _, out("v1:0") _); + | ----------- ^^^^^^^^^^^^^ register `v1:0` + | | + | register `v0` + +error: register `v1:0` conflicts with register `v1` + --> $DIR/bad-reg.rs:107:31 + | +LL | asm!("", out("v1") _, out("v1:0") _); + | ----------- ^^^^^^^^^^^^^ register `v1:0` + | | + | register `v1` + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:45:27 + | +LL | asm!("", in("p0") x); + | ^ + | + = note: register class `preg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:48:28 + | +LL | asm!("", out("p0") x); + | ^ + | + = note: register class `preg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:54:27 + | +LL | asm!("", in("q0") x); + | ^ + | + = note: register class `qreg` supports these types: + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:57:28 + | +LL | asm!("", out("q0") x); + | ^ + | + = note: register class `qreg` supports these types: + +error: type `i64` cannot be used with this register class + --> $DIR/bad-reg.rs:62:34 + | +LL | asm!("/* {} */", in(reg) y); + | ^ + | + = note: register class `reg` supports these types: i8, i16, i32, f32 + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:66:39 + | +LL | asm!("/* {} */", in(reg_pair) x); + | ^ + | + = note: register class `reg_pair` supports these types: i64, f64 + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:70:35 + | +LL | asm!("/* {} */", in(vreg) x); + | ^ + | + = note: register class `vreg` supports these types: i32x16, i32x32 + +error: type `i64` cannot be used with this register class + --> $DIR/bad-reg.rs:72:35 + | +LL | asm!("/* {} */", in(vreg) y); + | ^ + | + = note: register class `vreg` supports these types: i32x16, i32x32 + +error: type `i32` cannot be used with this register class + --> $DIR/bad-reg.rs:76:40 + | +LL | asm!("/* {} */", in(vreg_pair) x); + | ^ + | + = note: register class `vreg_pair` supports these types: i32x32, i32x64 + +error: type `i64` cannot be used with this register class + --> $DIR/bad-reg.rs:78:40 + | +LL | asm!("/* {} */", in(vreg_pair) y); + | ^ + | + = note: register class `vreg_pair` supports these types: i32x32, i32x64 + +error: aborting due to 28 previous errors; 1 warning emitted +