Skip to content

Commit d532473

Browse files
Add missing register class conversion for inline asm
1 parent e84f9a1 commit d532473

File tree

1 file changed

+70
-37
lines changed

1 file changed

+70
-37
lines changed

src/asm.rs

Lines changed: 70 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use rustc_codegen_ssa::mir::place::PlaceRef;
55
use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
66

77
use rustc_middle::{bug, ty::Instance};
8+
use rustc_middle::ty::layout::TyAndLayout;
89
use rustc_span::Span;
910
use rustc_target::asm::*;
1011

@@ -155,7 +156,8 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
155156
InlineAsmOperandRef::Out { reg, late, place } => {
156157
use ConstraintOrRegister::*;
157158

158-
let (constraint, ty) = match (reg_to_gcc(reg), place) {
159+
let constraint = reg_to_gcc(reg, place.map(|p| p.layout).as_ref());
160+
let (constraint, ty) = match (constraint, place) {
159161
(Constraint(constraint), Some(place)) => (constraint, place.layout.gcc_type(self.cx)),
160162
// When `reg` is a class and not an explicit register but the out place is not specified,
161163
// we need to create an unused output variable to assign the output to. This var
@@ -197,7 +199,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
197199
}
198200

199201
InlineAsmOperandRef::In { reg, value } => {
200-
if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
202+
if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg, None) {
201203
inputs.push(AsmInOperand {
202204
constraint: Cow::Borrowed(constraint),
203205
rust_idx,
@@ -211,7 +213,12 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
211213
}
212214

213215
InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
214-
let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg) {
216+
let layout = if let Some(ref out_place) = out_place {
217+
&out_place.layout
218+
} else {
219+
&in_value.layout
220+
};
221+
let constraint = if let ConstraintOrRegister::Constraint(constraint) = reg_to_gcc(reg, Some(layout)) {
215222
constraint
216223
}
217224
else {
@@ -276,7 +283,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
276283
match *op {
277284
// `out("explicit register") var`
278285
InlineAsmOperandRef::Out { reg, late, place } => {
279-
if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
286+
if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg, place.map(|p| p.layout).as_ref()) {
280287
let out_place = if let Some(place) = place {
281288
place
282289
}
@@ -304,7 +311,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
304311

305312
// `in("explicit register") var`
306313
InlineAsmOperandRef::In { reg, value } => {
307-
if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
314+
if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg, None) {
308315
let ty = value.layout.gcc_type(self.cx);
309316
let reg_var = self.current_func().new_local(None, ty, "input_register");
310317
reg_var.set_register_name(reg_name);
@@ -322,7 +329,12 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
322329

323330
// `inout("explicit register") in_var => out_var`
324331
InlineAsmOperandRef::InOut { reg, late, in_value, out_place } => {
325-
if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg) {
332+
let layout = if let Some(ref out_place) = out_place {
333+
&out_place.layout
334+
} else {
335+
&in_value.layout
336+
};
337+
if let ConstraintOrRegister::Register(reg_name) = reg_to_gcc(reg, Some(&layout)) {
326338
// See explanation in the first pass.
327339
let ty = in_value.layout.gcc_type(self.cx);
328340
let tmp_var = self.current_func().new_local(None, ty, "output_register");
@@ -544,7 +556,7 @@ fn estimate_template_length(template: &[InlineAsmTemplatePiece], constants_len:
544556
}
545557

546558
/// Converts a register class to a GCC constraint code.
547-
fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
559+
fn reg_to_gcc(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> ConstraintOrRegister {
548560
let constraint = match reg {
549561
// For vector registers LLVM wants the register name to match the type size.
550562
InlineAsmRegOrRegClass::Reg(reg) => {
@@ -564,56 +576,77 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
564576
_ => unimplemented!(),
565577
}
566578
},
579+
// They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
567580
InlineAsmRegOrRegClass::RegClass(reg) => match reg {
568-
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => unimplemented!(),
569-
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => unimplemented!(),
570-
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => unimplemented!(),
571-
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => unimplemented!(),
572-
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => unimplemented!(),
581+
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => {
582+
match layout.map(|l| l.size.bytes()) {
583+
Some(64) => "L",
584+
_ => "K", // we default to `K` which is a 32 bits register.
585+
}
586+
}
587+
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
588+
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
589+
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
590+
unreachable!("clobber-only")
591+
}
592+
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
573593
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
574594
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
575-
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8) => unimplemented!(),
576-
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
595+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
596+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
577597
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8)
578-
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4) => unimplemented!(),
579-
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
580-
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => unimplemented!(),
581-
InlineAsmRegClass::Avr(_) => unimplemented!(),
582-
InlineAsmRegClass::Bpf(_) => unimplemented!(),
583-
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => unimplemented!(),
584-
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => unimplemented!(),
585-
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => unimplemented!(),
586-
InlineAsmRegClass::Msp430(_) => unimplemented!(),
587-
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => unimplemented!(),
588-
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => unimplemented!(),
589-
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => unimplemented!(),
590-
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => unimplemented!(),
591-
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => unimplemented!(),
592-
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => unimplemented!(),
598+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4)
599+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
600+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "t",
601+
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r",
602+
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d",
603+
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r",
604+
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w",
605+
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
606+
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
607+
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
608+
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
609+
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r"
610+
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
611+
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
612+
// For the NVPTX target, could only find the information from LLVM at
613+
// https://llvm.org/docs/LangRef.html#supported-constraint-code-list so they might be
614+
// incorrect.
615+
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
616+
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
617+
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
618+
619+
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
620+
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
621+
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
593622
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
594623
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
595624
unreachable!("clobber-only")
596625
},
597-
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => unimplemented!(),
598-
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => unimplemented!(),
599-
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => unimplemented!(),
626+
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
627+
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
628+
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
629+
unreachable!("clobber-only")
630+
}
600631
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
601632
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
602633
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
603634
InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
604635
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
605636
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
606637
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk",
607-
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg0) => unimplemented!(),
608-
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => unimplemented!(),
609638
InlineAsmRegClass::X86(
610-
X86InlineAsmRegClass::x87_reg | X86InlineAsmRegClass::mmx_reg | X86InlineAsmRegClass::tmm_reg,
639+
X86InlineAsmRegClass::kreg0
640+
| X86InlineAsmRegClass::x87_reg
641+
| X86InlineAsmRegClass::mmx_reg
642+
| X86InlineAsmRegClass::tmm_reg,
611643
) => unreachable!("clobber-only"),
612644
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
613645
bug!("GCC backend does not support SPIR-V")
614646
}
615-
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => unimplemented!(),
616-
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => unimplemented!(),
647+
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
648+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
649+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
617650
InlineAsmRegClass::Err => unreachable!(),
618651
}
619652
};

0 commit comments

Comments
 (0)