From 5113ee9bbc0939a70ffb6f87271b03f9a998cda9 Mon Sep 17 00:00:00 2001 From: beetrees Date: Mon, 10 Aug 2026 12:41:42 +0100 Subject: [PATCH 1/3] Add MSA and `f16` inline ASM support for MIPS --- compiler/rustc_codegen_gcc/src/asm.rs | 7 +- compiler/rustc_codegen_llvm/src/asm.rs | 52 +++- compiler/rustc_span/src/symbol.rs | 1 + compiler/rustc_target/src/asm/mips.rs | 108 ++++++- compiler/rustc_target/src/asm/mod.rs | 2 +- compiler/rustc_target/src/target_features.rs | 2 + tests/assembly-llvm/asm/mips-modifiers.rs | 46 +++ tests/assembly-llvm/asm/mips-types.rs | 282 +++++++++++++++++- tests/ui/asm/mips/bad-reg.mips32.stderr | 14 + tests/ui/asm/mips/bad-reg.mips32r6.stderr | 14 + tests/ui/asm/mips/bad-reg.mips64.stderr | 14 + tests/ui/asm/mips/bad-reg.mips64r6.stderr | 14 + tests/ui/asm/mips/bad-reg.rs | 27 ++ tests/ui/asm/mips/reg-conflict.mips32.stderr | 31 ++ .../ui/asm/mips/reg-conflict.mips32r6.stderr | 26 ++ tests/ui/asm/mips/reg-conflict.mips64.stderr | 31 ++ .../ui/asm/mips/reg-conflict.mips64r6.stderr | 26 ++ tests/ui/asm/mips/reg-conflict.rs | 33 ++ 18 files changed, 701 insertions(+), 29 deletions(-) create mode 100644 tests/assembly-llvm/asm/mips-modifiers.rs create mode 100644 tests/ui/asm/mips/bad-reg.mips32.stderr create mode 100644 tests/ui/asm/mips/bad-reg.mips32r6.stderr create mode 100644 tests/ui/asm/mips/bad-reg.mips64.stderr create mode 100644 tests/ui/asm/mips/bad-reg.mips64r6.stderr create mode 100644 tests/ui/asm/mips/bad-reg.rs create mode 100644 tests/ui/asm/mips/reg-conflict.mips32.stderr create mode 100644 tests/ui/asm/mips/reg-conflict.mips32r6.stderr create mode 100644 tests/ui/asm/mips/reg-conflict.mips64.stderr create mode 100644 tests/ui/asm/mips/reg-conflict.mips64r6.stderr create mode 100644 tests/ui/asm/mips/reg-conflict.rs diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs index ee0cef350b42f..7cc098431d21a 100644 --- a/compiler/rustc_codegen_gcc/src/asm.rs +++ b/compiler/rustc_codegen_gcc/src/asm.rs @@ -733,7 +733,7 @@ fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str { InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => "r", InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r" - InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg | MipsInlineAsmRegClass::wreg) => "f", InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r", // https://github.com/gcc-mirror/gcc/blob/master/gcc/config/nvptx/nvptx.md -> look for // "define_constraint". @@ -843,6 +843,7 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl } InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::wreg) => cx.type_vector(cx.type_i32(), 4), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), @@ -1084,7 +1085,9 @@ fn modifier_to_gcc( modifier } } - InlineAsmRegClass::Mips(_) => None, + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => None, + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => modifier, + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::wreg) => Some('w'), InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vsreg) => { if modifier.is_none() { diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index fba43bba737e0..832ae6fd30d5d 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -765,7 +765,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> | LoongArch(LoongArchInlineAsmRegClass::vreg) | LoongArch(LoongArchInlineAsmRegClass::xreg) => "f", Mips(MipsInlineAsmRegClass::reg) => "r", - Mips(MipsInlineAsmRegClass::freg) => "f", + Mips(MipsInlineAsmRegClass::freg | MipsInlineAsmRegClass::wreg) => "f", Nvptx(NvptxInlineAsmRegClass::reg16) => "h", Nvptx(NvptxInlineAsmRegClass::reg32) => "r", Nvptx(NvptxInlineAsmRegClass::reg64) => "l", @@ -884,7 +884,9 @@ fn modifier_to_llvm( modifier } } - Mips(_) => None, + Mips(MipsInlineAsmRegClass::reg) => None, + Mips(MipsInlineAsmRegClass::freg) => modifier, + Mips(MipsInlineAsmRegClass::wreg) => Some('w'), Nvptx(_) => None, PowerPC(PowerPCInlineAsmRegClass::vsreg) => { // The documentation for the 'x' modifier is missing for llvm, and the gcc @@ -990,6 +992,7 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' LoongArch(LoongArchInlineAsmRegClass::xreg) => cx.type_vector(cx.type_i32(), 8), Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(), Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(), + Mips(MipsInlineAsmRegClass::wreg) => cx.type_vector(cx.type_i32(), 4), Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(), Nvptx(NvptxInlineAsmRegClass::reg32) => cx.type_i32(), Nvptx(NvptxInlineAsmRegClass::reg64) => cx.type_i64(), @@ -1225,12 +1228,24 @@ fn llvm_fixup_input<'ll, 'tcx>( (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. - Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), - Primitive::Float(Float::F32) => bx.bitcast(value, bx.cx.type_i32()), - Primitive::Float(Float::F64) => bx.bitcast(value, bx.cx.type_i64()), + Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.type_i32()), + Primitive::Float(Float::F16) => { + let value = bx.bitcast(value, bx.type_i16()); + bx.zext(value, bx.type_i32()) + } + Primitive::Float(Float::F32) => bx.bitcast(value, bx.type_i32()), + Primitive::Float(Float::F64) => bx.bitcast(value, bx.type_i64()), _ => value, } } + ( + Mips(MipsInlineAsmRegClass::freg | MipsInlineAsmRegClass::wreg), + BackendRepr::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => { + let value = bx.bitcast(value, bx.type_i16()); + let value = bx.zext(value, bx.type_i32()); + bx.bitcast(value, bx.type_f32()) + } (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => @@ -1398,13 +1413,25 @@ fn llvm_fixup_output<'ll, 'tcx>( (Mips(MipsInlineAsmRegClass::reg), BackendRepr::Scalar(s)) => { match s.primitive() { // MIPS only supports register-length arithmetics. - Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), - Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()), - Primitive::Float(Float::F32) => bx.bitcast(value, bx.cx.type_f32()), - Primitive::Float(Float::F64) => bx.bitcast(value, bx.cx.type_f64()), + Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.type_i8()), + Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.type_i16()), + Primitive::Float(Float::F16) => { + let value = bx.trunc(value, bx.type_i16()); + bx.bitcast(value, bx.type_f16()) + } + Primitive::Float(Float::F32) => bx.bitcast(value, bx.type_f32()), + Primitive::Float(Float::F64) => bx.bitcast(value, bx.type_f64()), _ => value, } } + ( + Mips(MipsInlineAsmRegClass::freg | MipsInlineAsmRegClass::wreg), + BackendRepr::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => { + let value = bx.bitcast(value, bx.type_i32()); + let value = bx.trunc(value, bx.type_i16()); + bx.bitcast(value, bx.type_f16()) + } (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(bx, instance, &[sym::zfhmin, sym::zfh]) => @@ -1552,11 +1579,16 @@ fn llvm_fixup_output_type<'ll, 'tcx>( match s.primitive() { // MIPS only supports register-length arithmetics. Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), - Primitive::Float(Float::F32) => cx.type_i32(), + Primitive::Float(Float::F16 | Float::F32) => cx.type_i32(), Primitive::Float(Float::F64) => cx.type_i64(), _ => layout.llvm_type(cx), } } + + ( + Mips(MipsInlineAsmRegClass::freg | MipsInlineAsmRegClass::wreg), + BackendRepr::Scalar(s), + ) if s.primitive() == Primitive::Float(Float::F16) => cx.type_f32(), (RiscV(RiscVInlineAsmRegClass::freg), BackendRepr::Scalar(s)) if s.primitive() == Primitive::Float(Float::F16) && !any_target_feature_enabled(cx, instance, &[sym::zfhmin, sym::zfh]) => diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 165cf7855b83b..76fa0e813fa89 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -1371,6 +1371,7 @@ symbols! { move_ref_pattern, move_size_limit, movrs_target_feature, + msa, msp430, mul, mul_assign, diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs index e28b8453b4784..9ec31c24595b3 100644 --- a/compiler/rustc_target/src/asm/mips.rs +++ b/compiler/rustc_target/src/asm/mips.rs @@ -8,12 +8,19 @@ def_reg_class! { Mips MipsInlineAsmRegClass { reg, freg, + wreg, } } impl MipsInlineAsmRegClass { pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { - &[] + match self { + Self::reg => &[], + Self::freg => &['w'], + // LLVM doesn't currently support displaying vector registers holding vector types as + // float registers. + Self::wreg => &[], + } } pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { @@ -37,9 +44,12 @@ impl MipsInlineAsmRegClass { arch: InlineAsmArch, ) -> &'static [(InlineAsmType, Option)] { match (self, arch) { - (Self::reg, InlineAsmArch::Mips64) => types! { _: I8, I16, I32, I64, F32, F64; }, - (Self::reg, _) => types! { _: I8, I16, I32, F32; }, - (Self::freg, _) => types! { _: F32, F64; }, + (Self::reg, InlineAsmArch::Mips64) => types! { _: I8, I16, I32, I64, F16, F32, F64; }, + (Self::reg, _) => types! { _: I8, I16, I32, F16, F32; }, + (Self::freg, _) => types! { _: F16, F32, F64; }, + (Self::wreg, _) => { + types! { msa: F16, F32, F64, VecI8(16), VecI16(8), VecI32(4), VecI64(2), VecF16(8), VecF32(4), VecF64(2); } + } } } } @@ -105,6 +115,38 @@ def_regs! { f29: freg = ["$f29"], f30: freg = ["$f30"], f31: freg = ["$f31"], + w0: wreg = ["$w0"], + w1: wreg = ["$w1"], + w2: wreg = ["$w2"], + w3: wreg = ["$w3"], + w4: wreg = ["$w4"], + w5: wreg = ["$w5"], + w6: wreg = ["$w6"], + w7: wreg = ["$w7"], + w8: wreg = ["$w8"], + w9: wreg = ["$w9"], + w10: wreg = ["$w10"], + w11: wreg = ["$w11"], + w12: wreg = ["$w12"], + w13: wreg = ["$w13"], + w14: wreg = ["$w14"], + w15: wreg = ["$w15"], + w16: wreg = ["$w16"], + w17: wreg = ["$w17"], + w18: wreg = ["$w18"], + w19: wreg = ["$w19"], + w20: wreg = ["$w20"], + w21: wreg = ["$w21"], + w22: wreg = ["$w22"], + w23: wreg = ["$w23"], + w24: wreg = ["$w24"], + w25: wreg = ["$w25"], + w26: wreg = ["$w26"], + w27: wreg = ["$w27"], + w28: wreg = ["$w28"], + w29: wreg = ["$w29"], + w30: wreg = ["$w30"], + w31: wreg = ["$w31"], #error = ["$0"] => "constant zero cannot be used as an operand for inline asm", #error = ["$1"] => @@ -133,4 +175,62 @@ impl MipsInlineAsmReg { ) -> fmt::Result { out.write_str(self.name()) } + + pub fn overlapping_regs(self, mut cb: impl FnMut(MipsInlineAsmReg)) { + cb(self); + + macro_rules! reg_conflicts { + ( + $( + $full:ident : $($field:ident)* + ),*; + ) => { + match self { + $( + Self::$full => { + $(cb(Self::$field);)* + } + $(Self::$field)|* => cb(Self::$full), + )* + _ => {} + } + }; + } + + // Float registers overlap the first half of vector registers. + reg_conflicts! { + w0: f0, + w1: f1, + w2: f2, + w3: f3, + w4: f4, + w5: f5, + w6: f6, + w7: f7, + w8: f8, + w9: f9, + w10: f10, + w11: f11, + w12: f12, + w13: f13, + w14: f14, + w15: f15, + w16: f16, + w17: f17, + w18: f18, + w19: f19, + w20: f20, + w21: f21, + w22: f22, + w23: f23, + w24: f24, + w25: f25, + w26: f26, + w27: f27, + w28: f28, + w29: f29, + w30: f30, + w31: f31; + } + } } diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 8d99035fd0db4..f918e4df7c74a 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -475,7 +475,7 @@ impl InlineAsmReg { Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))), Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), Self::LoongArch(r) => r.overlapping_regs(|r| cb(Self::LoongArch(r))), - Self::Mips(_) => cb(self), + Self::Mips(r) => r.overlapping_regs(|r| cb(Self::Mips(r))), Self::S390x(r) => r.overlapping_regs(|r| cb(Self::S390x(r))), Self::Sparc(_) => cb(self), Self::Xtensa(_) => cb(self), diff --git a/compiler/rustc_target/src/target_features.rs b/compiler/rustc_target/src/target_features.rs index f1dd2d8191985..f9b600f7f0064 100644 --- a/compiler/rustc_target/src/target_features.rs +++ b/compiler/rustc_target/src/target_features.rs @@ -625,6 +625,8 @@ static POWERPC_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ const MIPS_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[ // tidy-alphabetical-start ("fp64", Unstable(sym::mips_target_feature), &[]), + // FIXME(#150253): msa requires either fp64 or no hard float support at all: LLVM requires fp64 + // FIXME(#150253): msa requires revision 5 or greater (mips32r5/mips64r5 in LLVM) ("msa", Unstable(sym::mips_target_feature), &[]), ("virt", Unstable(sym::mips_target_feature), &[]), // tidy-alphabetical-end diff --git a/tests/assembly-llvm/asm/mips-modifiers.rs b/tests/assembly-llvm/asm/mips-modifiers.rs new file mode 100644 index 0000000000000..009cd24b4a6d2 --- /dev/null +++ b/tests/assembly-llvm/asm/mips-modifiers.rs @@ -0,0 +1,46 @@ +//@ add-minicore +//@ revisions: mips32 mips32el mips32r6 mips32r6el mips64 mips64el mips64r6 mips64r6el +//@ assembly-output: emit-asm +//@[mips32] compile-flags: --target mips-unknown-linux-gnu -Ctarget-feature=+mips32r5 +//@[mips32] needs-llvm-components: mips +//@[mips32el] compile-flags: --target mipsel-unknown-linux-gnu -Ctarget-feature=+mips32r5 +//@[mips32el] needs-llvm-components: mips +//@[mips32r6] compile-flags: --target mipsisa32r6-unknown-linux-gnu +//@[mips32r6] needs-llvm-components: mips +//@[mips32r6el] compile-flags: --target mipsisa32r6el-unknown-linux-gnu +//@[mips32r6el] needs-llvm-components: mips +//@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 -Ctarget-feature=+mips64r5 +//@[mips64] needs-llvm-components: mips +//@[mips64el] compile-flags: --target mips64el-unknown-linux-gnuabi64 -Ctarget-feature=+mips64r5 +//@[mips64el] needs-llvm-components: mips +//@[mips64r6] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64 +//@[mips64r6] needs-llvm-components: mips +//@[mips64r6el] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64 +//@[mips64r6el] needs-llvm-components: mips +//@ compile-flags: -Copt-level=3 -C panic=abort +//@ compile-flags: -Zmerge-functions=disabled +//@ compile-flags: -Ctarget-feature=+fp64,+msa + +#![feature(no_core, asm_experimental_arch)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register)] + +extern crate minicore; +use minicore::*; + +macro_rules! check { + ($func:ident $modifier:literal $reg:ident $mov:literal) => { + // -Copt-level=3 and extern "C" guarantee that the selected register is always w0 + #[unsafe(no_mangle)] + pub unsafe extern "C" fn $func() { + asm!(concat!($mov, " {0:", $modifier, "}, {0:", $modifier, "}"), out($reg) _); + } + }; +} + +// CHECK-LABEL: freg_w: +// CHECK: #APP +// CHECK: move.v $w0, $w0 +// CHECK: #NO_APP +check!(freg_w "w" freg "move.v"); diff --git a/tests/assembly-llvm/asm/mips-types.rs b/tests/assembly-llvm/asm/mips-types.rs index 51fe8124dc2a4..ea46386df133d 100644 --- a/tests/assembly-llvm/asm/mips-types.rs +++ b/tests/assembly-llvm/asm/mips-types.rs @@ -1,20 +1,100 @@ +// ignore-tidy-file-linelength (some revision //@ lines are over 100 chars long) + //@ add-minicore -//@ revisions: mips32 mips64 +//@ revisions: mips32 mips32el mips32r6 mips32r6el mips64 mips64el mips64r6 mips64r6el +//@ revisions: mips32_msa mips32el_msa mips32r6_msa mips32r6el_msa mips64_msa mips64el_msa mips64r6_msa mips64r6el_msa //@ assembly-output: emit-asm + //@[mips32] compile-flags: --target mips-unknown-linux-gnu //@[mips32] needs-llvm-components: mips -//@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +//@[mips32el] compile-flags: --target mipsel-unknown-linux-gnu --cfg mips32 +//@[mips32el] needs-llvm-components: mips +//@[mips32el] filecheck-flags: --check-prefix mips32 + +//@[mips32r6] compile-flags: --target mipsisa32r6-unknown-linux-gnu --cfg mips32 +//@[mips32r6] needs-llvm-components: mips +//@[mips32r6] filecheck-flags: --check-prefix mips32 +//@[mips32r6el] compile-flags: --target mipsisa32r6el-unknown-linux-gnu --cfg mips32 +//@[mips32r6el] needs-llvm-components: mips +//@[mips32r6el] filecheck-flags: --check-prefix mips32 + +//@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 --cfg mips64_not_r6 //@[mips64] needs-llvm-components: mips +//@[mips64] filecheck-flags: --check-prefix mips64-not-r6 +//@[mips64el] compile-flags: --target mips64el-unknown-linux-gnuabi64 --cfg mips64 --cfg mips64_not_r6 +//@[mips64el] needs-llvm-components: mips +//@[mips64el] filecheck-flags: --check-prefix mips64 --check-prefix not-r6 + +//@[mips64r6] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64 --cfg mips64 +//@[mips64r6] needs-llvm-components: mips +//@[mips64r6] filecheck-flags: --check-prefix mips64 +//@[mips64r6el] compile-flags: --target mipsisa64r6el-unknown-linux-gnuabi64 --cfg mips64 --cfg mips64r6 +//@[mips64r6el] needs-llvm-components: mips +//@[mips64r6el] filecheck-flags: --check-prefix mips64 --check-prefix mips64r6 + +//@[mips32_msa] compile-flags: --target mips-unknown-linux-gnu -Ctarget-feature=+fp64,+mips32r5,+msa --cfg mips32 --cfg msa +//@[mips32_msa] needs-llvm-components: mips +//@[mips32_msa] filecheck-flags: --check-prefix mips32 --check-prefix msa +//@[mips32el_msa] compile-flags: --target mipsel-unknown-linux-gnu -Ctarget-feature=+fp64,+mips32r5,+msa --cfg mips32 --cfg msa +//@[mips32el_msa] needs-llvm-components: mips +//@[mips32el_msa] filecheck-flags: --check-prefix mips32 --check-prefix msa + +//@[mips32r6_msa] compile-flags: --target mipsisa32r6-unknown-linux-gnu -Ctarget-feature=+msa --cfg mips32 --cfg msa +//@[mips32r6_msa] needs-llvm-components: mips +//@[mips32r6_msa] filecheck-flags: --check-prefix mips32 --check-prefix msa +//@[mips32r6el_msa] compile-flags: --target mipsisa32r6el-unknown-linux-gnu -Ctarget-feature=+msa --cfg mips32 --cfg msa +//@[mips32r6el_msa] needs-llvm-components: mips +//@[mips32r6el_msa] filecheck-flags: --check-prefix mips32 --check-prefix msa + +//@[mips64_msa] compile-flags: --target mips64-unknown-linux-gnuabi64 -Ctarget-feature=+mips64r5,+msa --cfg mips64 --cfg mips64_not_r6 --cfg msa +//@[mips64_msa] needs-llvm-components: mips +//@[mips64_msa] filecheck-flags: --check-prefix mips64 --check-prefix mips64-not-r6 --check-prefix msa +//@[mips64el_msa] compile-flags: --target mips64el-unknown-linux-gnuabi64 -Ctarget-feature=+mips64r5,+msa --cfg mips64 --cfg mips64_not_r6 --cfg msa +//@[mips64el_msa] needs-llvm-components: mips +//@[mips64el_msa] filecheck-flags: --check-prefix mips64 --check-prefix not-r6 --check-prefix msa + +//@[mips64r6_msa] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64 -Ctarget-feature=+msa --cfg mips64 --cfg mips64r6 --cfg msa +//@[mips64r6_msa] needs-llvm-components: mips +//@[mips64r6_msa] filecheck-flags: --check-prefix mips64 --check-prefix mips64r6 --check-prefix msa +//@[mips64r6el_msa] compile-flags: --target mipsisa64r6el-unknown-linux-gnuabi64 -Ctarget-feature=+msa --cfg mips64 --cfg mips64r6 --cfg msa +//@[mips64r6el_msa] needs-llvm-components: mips +//@[mips64r6el_msa] filecheck-flags: --check-prefix mips64 --check-prefix mips64r6 --check-prefix msa + //@ compile-flags: -Zmerge-functions=disabled +//@ compile-flags: --check-cfg=cfg(mips64_not_r6,msa) +// `f16` causes LLVM to crash when `msa` is enabled on LLVM < 23 +//@ min-llvm-version: 23 -#![feature(no_core, asm_experimental_arch)] +#![deny(unexpected_cfgs)] +#![feature(no_core, asm_experimental_arch, f16)] #![crate_type = "rlib"] #![no_core] -#![allow(asm_sub_register, non_camel_case_types)] +#![allow(asm_sub_register, non_camel_case_types, unused)] extern crate minicore; +use minicore::simd::*; use minicore::*; +#[cfg_attr(mips32, cfg(not(target_pointer_width = "32")))] +#[cfg_attr(not(mips32), cfg(target_pointer_width = "32"))] +compile_error!("mips32 cfg mismatch"); + +#[cfg_attr(mips64, cfg(not(target_pointer_width = "64")))] +#[cfg_attr(not(mips64), cfg(target_pointer_width = "64"))] +compile_error!("mips64 cfg mismatch"); + +#[cfg_attr(mips64_not_r6, cfg(not(target_arch = "mips64")))] +#[cfg_attr(not(mips64_not_r6), cfg(target_arch = "mips64"))] +compile_error!("mips64_not_r6 cfg mismatch"); + +#[cfg_attr(mips64r6, cfg(not(target_arch = "mips64r6")))] +#[cfg_attr(not(mips64r6), cfg(target_arch = "mips64r6"))] +compile_error!("mips64r6 cfg mismatch"); + +#[cfg_attr(msa, cfg(not(target_feature = "msa")))] +#[cfg_attr(not(msa), cfg(target_feature = "msa"))] +compile_error!("msa cfg mismatch"); + type ptr = *const i32; extern "C" { @@ -23,7 +103,7 @@ extern "C" { } macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe fn $func(x: $ty) -> $ty { let y; asm!(concat!($mov," {}, {}"), out($class) y, in($class) x); @@ -32,7 +112,7 @@ macro_rules! check { ($func:ident, $ty:ty, $class:ident, $mov:literal) => { };} macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt, $mov:literal) => { - #[no_mangle] + #[unsafe(no_mangle)] pub unsafe fn $func(x: $ty) -> $ty { let y; asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); @@ -62,9 +142,10 @@ pub unsafe fn sym_fn_32() { // mips64-LABEL: sym_static_64: // mips64: #APP -// mips64: lui $3, %got_hi(extern_static) -// mips64: daddu $3, $3, $gp -// mips64: ld $3, %got_lo(extern_static)($3) +// mips64-not-r6: lui $3, %got_hi(extern_static) +// mips64-not-r6: daddu $3, $3, $gp +// mips64-not-r6: ld $3, %got_lo(extern_static)($3) +// mips64r6: ld $3, %got_disp(extern_static)($gp) // mips64: #NO_APP #[cfg(mips64)] #[no_mangle] @@ -74,9 +155,10 @@ pub unsafe fn sym_static_64() { // mips64-LABEL: sym_fn_64: // mips64: #APP -// mips64: lui $3, %got_hi(extern_func) -// mips64: daddu $3, $3, $gp -// mips64: ld $3, %got_lo(extern_func)($3) +// mips64-not-r6: lui $3, %got_hi(extern_func) +// mips64-not-r6: daddu $3, $3, $gp +// mips64-not-r6: ld $3, %got_lo(extern_func)($3) +// mips64r6: ld $3, %got_disp(extern_func)($gp) // mips64: #NO_APP #[cfg(mips64)] #[no_mangle] @@ -84,6 +166,30 @@ pub unsafe fn sym_fn_64() { asm!("ld $v1, {}", sym extern_func); } +// CHECK-LABEL: reg_f16: +// CHECK: #APP +// CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f16, f16, freg, "mov.s"); + +// CHECK-LABEL: f0_f16: +// CHECK: #APP +// CHECK: mov.s $f0, $f0 +// CHECK: #NO_APP +check_reg!(f0_f16, f16, "$f0", "mov.s"); + +// CHECK-LABEL: reg_f16_64: +// CHECK: #APP +// CHECK: mov.d $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f16_64, f16, freg, "mov.d"); + +// CHECK-LABEL: f0_f16_64: +// CHECK: #APP +// CHECK: mov.d $f0, $f0 +// CHECK: #NO_APP +check_reg!(f0_f16_64, f16, "$f0", "mov.d"); + // CHECK-LABEL: reg_f32: // CHECK: #APP // CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}} @@ -132,6 +238,12 @@ check!(reg_ptr, ptr, reg, "move"); // CHECK: #NO_APP check!(reg_i32, i32, reg, "move"); +// CHECK-LABEL: reg_f16_soft: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f16_soft, f16, reg, "move"); + // CHECK-LABEL: reg_f32_soft: // CHECK: #APP // CHECK: move ${{[0-9]+}}, ${{[0-9]+}} @@ -182,6 +294,12 @@ check_reg!(r8_ptr, ptr, "$8", "move"); // CHECK: #NO_APP check_reg!(r8_i32, i32, "$8", "move"); +// CHECK-LABEL: r8_f16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_f16, f16, "$8", "move"); + // CHECK-LABEL: r8_f32: // CHECK: #APP // CHECK: move $8, $8 @@ -205,3 +323,143 @@ check_reg!(r8_u8, u8, "$8", "move"); // CHECK: move $8, $8 // CHECK: #NO_APP check_reg!(r8_i16, i16, "$8", "move"); + +// msa-LABEL: wreg_f16: +// msa: #APP +// msa: move.v $w{{[0-9]+}}, $w{{[0-9]+}} +// msa: #NO_APP +#[cfg(msa)] +check!(wreg_f16, f16, wreg, "move.v"); + +// msa-LABEL: wreg_f32: +// msa: #APP +// msa: move.v $w{{[0-9]+}}, $w{{[0-9]+}} +// msa: #NO_APP +#[cfg(msa)] +check!(wreg_f32, f32, wreg, "move.v"); + +// msa-LABEL: wreg_f64: +// msa: #APP +// msa: move.v $w{{[0-9]+}}, $w{{[0-9]+}} +// msa: #NO_APP +#[cfg(msa)] +check!(wreg_f64, f64, wreg, "move.v"); + +// msa-LABEL: w0_f16: +// msa: #APP +// msa: move.v $w0, $w0 +// msa: #NO_APP +#[cfg(msa)] +check_reg!(w0_f16, f16, "$w0", "move.v"); + +// msa-LABEL: w0_f32: +// msa: #APP +// msa: move.v $w0, $w0 +// msa: #NO_APP +#[cfg(msa)] +check_reg!(w0_f32, f32, "$w0", "move.v"); + +// msa-LABEL: w0_f64: +// msa: #APP +// msa: move.v $w0, $w0 +// msa: #NO_APP +#[cfg(msa)] +check_reg!(w0_f64, f64, "$w0", "move.v"); + +// msa-LABEL: wreg_i8x16: +// msa: #APP +// msa: move.v $w{{[0-9]+}}, $w{{[0-9]+}} +// msa: #NO_APP +#[cfg(msa)] +check!(wreg_i8x16, i8x16, wreg, "move.v"); + +// msa-LABEL: wreg_i16x8: +// msa: #APP +// msa: move.v $w{{[0-9]+}}, $w{{[0-9]+}} +// msa: #NO_APP +#[cfg(msa)] +check!(wreg_i16x8, i16x8, wreg, "move.v"); + +// msa-LABEL: wreg_i32x4: +// msa: #APP +// msa: move.v $w{{[0-9]+}}, $w{{[0-9]+}} +// msa: #NO_APP +#[cfg(msa)] +check!(wreg_i32x4, i32x4, wreg, "move.v"); + +// msa-LABEL: wreg_i64x2: +// msa: #APP +// msa: move.v $w{{[0-9]+}}, $w{{[0-9]+}} +// msa: #NO_APP +#[cfg(msa)] +check!(wreg_i64x2, i64x2, wreg, "move.v"); + +// msa-LABEL: wreg_f16x8: +// msa: #APP +// msa: move.v $w{{[0-9]+}}, $w{{[0-9]+}} +// msa: #NO_APP +#[cfg(msa)] +check!(wreg_f16x8, f16x8, wreg, "move.v"); + +// msa-LABEL: wreg_f32x4: +// msa: #APP +// msa: move.v $w{{[0-9]+}}, $w{{[0-9]+}} +// msa: #NO_APP +#[cfg(msa)] +check!(wreg_f32x4, f32x4, wreg, "move.v"); + +// msa-LABEL: wreg_f64x2: +// msa: #APP +// msa: move.v $w{{[0-9]+}}, $w{{[0-9]+}} +// msa: #NO_APP +#[cfg(msa)] +check!(wreg_f64x2, f64x2, wreg, "move.v"); + +// msa-LABEL: w0_i8x16: +// msa: #APP +// msa: move.v $w0, $w0 +// msa: #NO_APP +#[cfg(msa)] +check_reg!(w0_i8x16, i8x16, "$w0", "move.v"); + +// msa-LABEL: w0_i16x8: +// msa: #APP +// msa: move.v $w0, $w0 +// msa: #NO_APP +#[cfg(msa)] +check_reg!(w0_i16x8, i16x8, "$w0", "move.v"); + +// msa-LABEL: w0_i32x4: +// msa: #APP +// msa: move.v $w0, $w0 +// msa: #NO_APP +#[cfg(msa)] +check_reg!(w0_i32x4, i32x4, "$w0", "move.v"); + +// msa-LABEL: w0_i64x2: +// msa: #APP +// msa: move.v $w0, $w0 +// msa: #NO_APP +#[cfg(msa)] +check_reg!(w0_i64x2, i64x2, "$w0", "move.v"); + +// msa-LABEL: w0_f16x8: +// msa: #APP +// msa: move.v $w0, $w0 +// msa: #NO_APP +#[cfg(msa)] +check_reg!(w0_f16x8, f16x8, "$w0", "move.v"); + +// msa-LABEL: w0_f32x4: +// msa: #APP +// msa: move.v $w0, $w0 +// msa: #NO_APP +#[cfg(msa)] +check_reg!(w0_f32x4, f32x4, "$w0", "move.v"); + +// msa-LABEL: w0_f64x2: +// msa: #APP +// msa: move.v $w0, $w0 +// msa: #NO_APP +#[cfg(msa)] +check_reg!(w0_f64x2, f64x2, "$w0", "move.v"); diff --git a/tests/ui/asm/mips/bad-reg.mips32.stderr b/tests/ui/asm/mips/bad-reg.mips32.stderr new file mode 100644 index 0000000000000..ce4f91b74f17e --- /dev/null +++ b/tests/ui/asm/mips/bad-reg.mips32.stderr @@ -0,0 +1,14 @@ +error: register class `wreg` requires the `msa` target feature + --> $DIR/bad-reg.rs:22:22 + | +LL | asm!("# {}", in(wreg) 0.0); + | ^^^^^^^^^^^^ + +error: register class `wreg` requires the `msa` target feature + --> $DIR/bad-reg.rs:24:18 + | +LL | asm!("", in("$w10") 0.0); + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/asm/mips/bad-reg.mips32r6.stderr b/tests/ui/asm/mips/bad-reg.mips32r6.stderr new file mode 100644 index 0000000000000..ce4f91b74f17e --- /dev/null +++ b/tests/ui/asm/mips/bad-reg.mips32r6.stderr @@ -0,0 +1,14 @@ +error: register class `wreg` requires the `msa` target feature + --> $DIR/bad-reg.rs:22:22 + | +LL | asm!("# {}", in(wreg) 0.0); + | ^^^^^^^^^^^^ + +error: register class `wreg` requires the `msa` target feature + --> $DIR/bad-reg.rs:24:18 + | +LL | asm!("", in("$w10") 0.0); + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/asm/mips/bad-reg.mips64.stderr b/tests/ui/asm/mips/bad-reg.mips64.stderr new file mode 100644 index 0000000000000..ce4f91b74f17e --- /dev/null +++ b/tests/ui/asm/mips/bad-reg.mips64.stderr @@ -0,0 +1,14 @@ +error: register class `wreg` requires the `msa` target feature + --> $DIR/bad-reg.rs:22:22 + | +LL | asm!("# {}", in(wreg) 0.0); + | ^^^^^^^^^^^^ + +error: register class `wreg` requires the `msa` target feature + --> $DIR/bad-reg.rs:24:18 + | +LL | asm!("", in("$w10") 0.0); + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/asm/mips/bad-reg.mips64r6.stderr b/tests/ui/asm/mips/bad-reg.mips64r6.stderr new file mode 100644 index 0000000000000..ce4f91b74f17e --- /dev/null +++ b/tests/ui/asm/mips/bad-reg.mips64r6.stderr @@ -0,0 +1,14 @@ +error: register class `wreg` requires the `msa` target feature + --> $DIR/bad-reg.rs:22:22 + | +LL | asm!("# {}", in(wreg) 0.0); + | ^^^^^^^^^^^^ + +error: register class `wreg` requires the `msa` target feature + --> $DIR/bad-reg.rs:24:18 + | +LL | asm!("", in("$w10") 0.0); + | ^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/asm/mips/bad-reg.rs b/tests/ui/asm/mips/bad-reg.rs new file mode 100644 index 0000000000000..6496e828fb8fe --- /dev/null +++ b/tests/ui/asm/mips/bad-reg.rs @@ -0,0 +1,27 @@ +//@ add-minicore +//@ revisions: mips32 mips64 mips32r6 mips64r6 +//@[mips32] compile-flags: --target mips-unknown-linux-gnu +//@[mips32] needs-llvm-components: mips +//@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 +//@[mips64] needs-llvm-components: mips +//@[mips32r6] compile-flags: --target mipsisa32r6-unknown-linux-gnu +//@[mips32r6] needs-llvm-components: mips +//@[mips64r6] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64 +//@[mips64r6] needs-llvm-components: mips +//@ ignore-backends: gcc + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch, f16)] +#![no_core] + +extern crate minicore; +use minicore::*; + +fn f() { + unsafe { + asm!("# {}", in(wreg) 0.0); + //~^ ERROR register class `wreg` requires the `msa` target feature + asm!("", in("$w10") 0.0); + //~^ ERROR register class `wreg` requires the `msa` target feature + } +} diff --git a/tests/ui/asm/mips/reg-conflict.mips32.stderr b/tests/ui/asm/mips/reg-conflict.mips32.stderr new file mode 100644 index 0000000000000..cbd95f7e48bcc --- /dev/null +++ b/tests/ui/asm/mips/reg-conflict.mips32.stderr @@ -0,0 +1,31 @@ +warning: unknown and unstable feature specified for `-Ctarget-feature`: `mips32r5` + | + = note: it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future + = help: consider filing a feature request + +warning: unstable feature specified for `-Ctarget-feature`: `fp64` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: unstable feature specified for `-Ctarget-feature`: `msa` + | + = note: this feature is not stably supported; its behavior can change in the future + +error: register `$f4` conflicts with register `$w4` + --> $DIR/reg-conflict.rs:28:33 + | +LL | asm!("", in("$w4") 0.0, in("$f4") 0.0); + | ------------- ^^^^^^^^^^^^^ register `$f4` + | | + | register `$w4` + +error: register `$f25` conflicts with register `$w25` + --> $DIR/reg-conflict.rs:30:34 + | +LL | asm!("", in("$w25") 0.0, in("$f25") 0.0); + | -------------- ^^^^^^^^^^^^^^ register `$f25` + | | + | register `$w25` + +error: aborting due to 2 previous errors; 3 warnings emitted + diff --git a/tests/ui/asm/mips/reg-conflict.mips32r6.stderr b/tests/ui/asm/mips/reg-conflict.mips32r6.stderr new file mode 100644 index 0000000000000..55b11a523102c --- /dev/null +++ b/tests/ui/asm/mips/reg-conflict.mips32r6.stderr @@ -0,0 +1,26 @@ +warning: unstable feature specified for `-Ctarget-feature`: `fp64` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: unstable feature specified for `-Ctarget-feature`: `msa` + | + = note: this feature is not stably supported; its behavior can change in the future + +error: register `$f4` conflicts with register `$w4` + --> $DIR/reg-conflict.rs:28:33 + | +LL | asm!("", in("$w4") 0.0, in("$f4") 0.0); + | ------------- ^^^^^^^^^^^^^ register `$f4` + | | + | register `$w4` + +error: register `$f25` conflicts with register `$w25` + --> $DIR/reg-conflict.rs:30:34 + | +LL | asm!("", in("$w25") 0.0, in("$f25") 0.0); + | -------------- ^^^^^^^^^^^^^^ register `$f25` + | | + | register `$w25` + +error: aborting due to 2 previous errors; 2 warnings emitted + diff --git a/tests/ui/asm/mips/reg-conflict.mips64.stderr b/tests/ui/asm/mips/reg-conflict.mips64.stderr new file mode 100644 index 0000000000000..64b3ffc22431d --- /dev/null +++ b/tests/ui/asm/mips/reg-conflict.mips64.stderr @@ -0,0 +1,31 @@ +warning: unknown and unstable feature specified for `-Ctarget-feature`: `mips64r5` + | + = note: it is still passed through to the codegen backend, but use of this feature might be unsound and the behavior of this feature can change in the future + = help: consider filing a feature request + +warning: unstable feature specified for `-Ctarget-feature`: `fp64` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: unstable feature specified for `-Ctarget-feature`: `msa` + | + = note: this feature is not stably supported; its behavior can change in the future + +error: register `$f4` conflicts with register `$w4` + --> $DIR/reg-conflict.rs:28:33 + | +LL | asm!("", in("$w4") 0.0, in("$f4") 0.0); + | ------------- ^^^^^^^^^^^^^ register `$f4` + | | + | register `$w4` + +error: register `$f25` conflicts with register `$w25` + --> $DIR/reg-conflict.rs:30:34 + | +LL | asm!("", in("$w25") 0.0, in("$f25") 0.0); + | -------------- ^^^^^^^^^^^^^^ register `$f25` + | | + | register `$w25` + +error: aborting due to 2 previous errors; 3 warnings emitted + diff --git a/tests/ui/asm/mips/reg-conflict.mips64r6.stderr b/tests/ui/asm/mips/reg-conflict.mips64r6.stderr new file mode 100644 index 0000000000000..55b11a523102c --- /dev/null +++ b/tests/ui/asm/mips/reg-conflict.mips64r6.stderr @@ -0,0 +1,26 @@ +warning: unstable feature specified for `-Ctarget-feature`: `fp64` + | + = note: this feature is not stably supported; its behavior can change in the future + +warning: unstable feature specified for `-Ctarget-feature`: `msa` + | + = note: this feature is not stably supported; its behavior can change in the future + +error: register `$f4` conflicts with register `$w4` + --> $DIR/reg-conflict.rs:28:33 + | +LL | asm!("", in("$w4") 0.0, in("$f4") 0.0); + | ------------- ^^^^^^^^^^^^^ register `$f4` + | | + | register `$w4` + +error: register `$f25` conflicts with register `$w25` + --> $DIR/reg-conflict.rs:30:34 + | +LL | asm!("", in("$w25") 0.0, in("$f25") 0.0); + | -------------- ^^^^^^^^^^^^^^ register `$f25` + | | + | register `$w25` + +error: aborting due to 2 previous errors; 2 warnings emitted + diff --git a/tests/ui/asm/mips/reg-conflict.rs b/tests/ui/asm/mips/reg-conflict.rs new file mode 100644 index 0000000000000..f0c9b5e6fd091 --- /dev/null +++ b/tests/ui/asm/mips/reg-conflict.rs @@ -0,0 +1,33 @@ +//@ add-minicore +//@ revisions: mips32 mips64 mips32r6 mips64r6 +//@[mips32] compile-flags: --target mips-unknown-linux-gnu -Ctarget-feature=+mips32r5 +//@[mips32] needs-llvm-components: mips +//@[mips64] compile-flags: --target mips64-unknown-linux-gnuabi64 -Ctarget-feature=+mips64r5 +//@[mips64] needs-llvm-components: mips +//@[mips32r6] compile-flags: --target mipsisa32r6-unknown-linux-gnu +//@[mips32r6] needs-llvm-components: mips +//@[mips64r6] compile-flags: --target mipsisa64r6-unknown-linux-gnuabi64 +//@[mips64r6] needs-llvm-components: mips +//@ compile-flags: -Ctarget-feature=+fp64,+msa +//@ ignore-backends: gcc + +#![crate_type = "rlib"] +#![feature(no_core, asm_experimental_arch, f16)] +#![no_core] + +//[mips32]~? WARN unknown and unstable feature specified for `-Ctarget-feature`: `mips32r5` +//[mips64]~? WARN unknown and unstable feature specified for `-Ctarget-feature`: `mips64r5` +//~? WARN unstable feature specified for `-Ctarget-feature`: `fp64` +//~? WARN unstable feature specified for `-Ctarget-feature`: `msa` + +extern crate minicore; +use minicore::*; + +fn f() { + unsafe { + asm!("", in("$w4") 0.0, in("$f4") 0.0); + //~^ ERROR register `$f4` conflicts with register `$w4` + asm!("", in("$w25") 0.0, in("$f25") 0.0); + //~^ ERROR register `$f25` conflicts with register `$w25` + } +} From a132402591491bb629d10b759bc4383b3f19ebb1 Mon Sep 17 00:00:00 2001 From: Philip Kannegaard Hayes Date: Fri, 28 Aug 2026 22:28:49 -0700 Subject: [PATCH 2/3] std::sys::sgx::tls: fix TLS destructor pointer provenance Storing the TLS entry destructor as an `AtomicUsize` loses the pointer provenance and makes miri cry :'( --- library/std/src/sys/pal/sgx/abi/tls/mod.rs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/library/std/src/sys/pal/sgx/abi/tls/mod.rs b/library/std/src/sys/pal/sgx/abi/tls/mod.rs index 537b506d94506..8c02702fada79 100644 --- a/library/std/src/sys/pal/sgx/abi/tls/mod.rs +++ b/library/std/src/sys/pal/sgx/abi/tls/mod.rs @@ -14,7 +14,7 @@ mod sync_bitset; use self::sync_bitset::*; use crate::cell::Cell; use crate::num::NonZero; -use crate::sync::atomic::{Atomic, AtomicUsize, Ordering}; +use crate::sync::atomic::{AtomicPtr, Ordering}; use crate::{mem, ptr}; #[cfg(target_pointer_width = "64")] @@ -29,7 +29,8 @@ static TLS_KEY_IN_USE: SyncBitset = SYNC_BITSET_INIT; // Specifying linkage/symbol name is solely to ensure a single instance between this crate and its unit tests #[cfg_attr(test, linkage = "available_externally")] #[unsafe(export_name = "_ZN16__rust_internals3std3sys3pal3sgx3abi3tls14TLS_DESTRUCTORE")] -static TLS_DESTRUCTOR: [Atomic; TLS_KEYS] = [const { AtomicUsize::new(0) }; TLS_KEYS]; +static TLS_DESTRUCTOR: [AtomicPtr<()>; TLS_KEYS] = + [const { AtomicPtr::new(ptr::null_mut()) }; TLS_KEYS]; unsafe extern "C" { fn get_tls_ptr() -> *const u8; @@ -71,7 +72,10 @@ impl<'a> Drop for ActiveTls<'a> { fn drop(&mut self) { let value_with_destructor = |key: usize| { let ptr = TLS_DESTRUCTOR[key].load(Ordering::Relaxed); - unsafe { mem::transmute::<_, Option>(ptr) } + // SAFETY: + // - Matches the transmute+store below in `Tls::create`. + // - SGX/x86-64: `Option` is layout compatible with `*mut ()`. + unsafe { mem::transmute::<*mut (), Option>(ptr) } .map(|dtor| (self.tls.data_index(key), dtor)) }; @@ -115,8 +119,11 @@ impl Tls { } else { rtabort!("TLS limit exceeded") }; - rtunwrap!(Some, TLS_DESTRUCTOR.get(index)) - .store(dtor.map_or(0, |f| f as usize), Ordering::Relaxed); + // SAFETY: + // - Matches the load+transmute above in `ActiveTls::drop`. + // - SGX/x86-64: `Option` is layout compatible with `*mut ()`. + let ptr = unsafe { mem::transmute::, *mut ()>(dtor) }; + rtunwrap!(Some, TLS_DESTRUCTOR.get(index)).store(ptr, Ordering::Relaxed); unsafe { Self::current() }.data_index(index).set(ptr::null_mut()); Key::from_index(index) } From 3d2b31ead3efcffd331c186e9c7bb8636b65ef74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Le=C3=B3n=20Orell=20Valerian=20Liehr?= Date: Sat, 29 Aug 2026 15:29:20 +0200 Subject: [PATCH 3/3] Improve rustdoc macro expansion code Co-authored-by: Guillaume Gomez --- src/librustdoc/html/macro_expansion.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/src/librustdoc/html/macro_expansion.rs b/src/librustdoc/html/macro_expansion.rs index 55ca93e601b70..27741ea485a36 100644 --- a/src/librustdoc/html/macro_expansion.rs +++ b/src/librustdoc/html/macro_expansion.rs @@ -70,10 +70,9 @@ impl<'ast> ExpandedCodeVisitor<'ast> { return; } let callsite_span = new_span.source_callsite(); - if let Some(index) = - self.expanded_codes.iter().position(|info| info.span.overlaps(callsite_span)) + if let Some(info) = + self.expanded_codes.iter_mut().find(|info| info.span.overlaps(callsite_span)) { - let info = &mut self.expanded_codes[index]; // If the new span we got has the exact same span information as a span already in the // list, it means it's generated from the same macro but is a different item, so we need // to add it as well. @@ -86,12 +85,11 @@ impl<'ast> ExpandedCodeVisitor<'ast> { info.code = f(); } else { // We push the new item after the existing one. - let expanded_code = &mut self.expanded_codes[index]; - expanded_code.code.push('\n'); - expanded_code.code.push_str(&f()); - let lo = BytePos(expanded_code.expanded_span.lo().0.min(new_span.lo().0)); - let hi = BytePos(expanded_code.expanded_span.hi().0.max(new_span.hi().0)); - expanded_code.expanded_span = expanded_code.expanded_span.with_lo(lo).with_hi(hi); + info.code.push('\n'); + info.code.push_str(&f()); + let lo = BytePos(info.expanded_span.lo().0.min(new_span.lo().0)); + let hi = BytePos(info.expanded_span.hi().0.max(new_span.hi().0)); + info.expanded_span = info.expanded_span.with_lo(lo).with_hi(hi); } } else { // We add a new item.