Skip to content

Commit fcac229

Browse files
authored
Merge pull request #630 from folkertdev/x86-register-classes
support `reg_byte` registers
2 parents 1f98329 + 53aa977 commit fcac229

File tree

2 files changed

+136
-101
lines changed

2 files changed

+136
-101
lines changed

src/asm.rs

+114-101
Original file line numberDiff line numberDiff line change
@@ -611,114 +611,127 @@ fn estimate_template_length(
611611
}
612612

613613
/// Converts a register class to a GCC constraint code.
614-
fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
615-
let constraint = match reg {
616-
// For vector registers LLVM wants the register name to match the type size.
614+
fn reg_to_gcc(reg_or_reg_class: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
615+
match reg_or_reg_class {
617616
InlineAsmRegOrRegClass::Reg(reg) => {
618-
match reg {
619-
InlineAsmReg::X86(_) => {
620-
// TODO(antoyo): add support for vector register.
621-
//
622-
// // For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119
623-
return ConstraintOrRegister::Register(match reg.name() {
624-
// Some of registers' names does not map 1-1 from rust to gcc
625-
"st(0)" => "st",
617+
ConstraintOrRegister::Register(explicit_reg_to_gcc(reg))
618+
}
619+
InlineAsmRegOrRegClass::RegClass(reg_class) => {
620+
ConstraintOrRegister::Constraint(reg_class_to_gcc(reg_class))
621+
}
622+
}
623+
}
626624

627-
name => name,
628-
});
625+
fn explicit_reg_to_gcc(reg: InlineAsmReg) -> &'static str {
626+
// For explicit registers, we have to create a register variable: https://stackoverflow.com/a/31774784/389119
627+
match reg {
628+
InlineAsmReg::X86(reg) => {
629+
// TODO(antoyo): add support for vector register.
630+
match reg.reg_class() {
631+
X86InlineAsmRegClass::reg_byte => {
632+
// GCC does not support the `b` suffix, so we just strip it
633+
// see https://github.com/rust-lang/rustc_codegen_gcc/issues/485
634+
reg.name().trim_end_matches('b')
629635
}
636+
_ => match reg.name() {
637+
// Some of registers' names does not map 1-1 from rust to gcc
638+
"st(0)" => "st",
630639

631-
_ => unimplemented!(),
640+
name => name,
641+
},
632642
}
633643
}
634-
// They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
635-
InlineAsmRegOrRegClass::RegClass(reg) => match reg {
636-
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
637-
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
638-
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
639-
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
640-
unreachable!("clobber-only")
641-
}
642-
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
643-
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
644-
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
645-
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
646-
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
647-
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8)
648-
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4)
649-
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
650-
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "t",
651-
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r",
652-
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d",
653-
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r",
654-
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w",
655-
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
656-
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
657-
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
658-
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
659-
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => {
660-
unreachable!("clobber-only")
661-
}
662-
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
663-
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
664-
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
665-
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
666-
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
667-
InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => "r",
668-
InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => "f",
669-
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r"
670-
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
671-
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
672-
// https://github.com/gcc-mirror/gcc/blob/master/gcc/config/nvptx/nvptx.md -> look for
673-
// "define_constraint".
674-
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
675-
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
676-
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
677-
678-
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
679-
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
680-
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
681-
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
682-
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
683-
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
684-
unreachable!("clobber-only")
685-
}
686-
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
687-
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
688-
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
689-
unreachable!("clobber-only")
690-
}
691-
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
692-
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
693-
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
694-
InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
695-
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
696-
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
697-
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk",
698-
InlineAsmRegClass::X86(
699-
X86InlineAsmRegClass::kreg0
700-
| X86InlineAsmRegClass::x87_reg
701-
| X86InlineAsmRegClass::mmx_reg
702-
| X86InlineAsmRegClass::tmm_reg,
703-
) => unreachable!("clobber-only"),
704-
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
705-
bug!("GCC backend does not support SPIR-V")
706-
}
707-
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
708-
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
709-
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
710-
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
711-
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
712-
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
713-
unreachable!("clobber-only")
714-
}
715-
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
716-
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"),
717-
InlineAsmRegClass::Err => unreachable!(),
718-
},
719-
};
720644

721-
ConstraintOrRegister::Constraint(constraint)
645+
_ => unimplemented!(),
646+
}
647+
}
648+
649+
/// They can be retrieved from https://gcc.gnu.org/onlinedocs/gcc/Machine-Constraints.html
650+
fn reg_class_to_gcc(reg_class: InlineAsmRegClass) -> &'static str {
651+
match reg_class {
652+
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::reg) => "r",
653+
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg) => "w",
654+
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::vreg_low16) => "x",
655+
InlineAsmRegClass::AArch64(AArch64InlineAsmRegClass::preg) => {
656+
unreachable!("clobber-only")
657+
}
658+
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::reg) => "r",
659+
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg)
660+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low16)
661+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low8)
662+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::sreg_low16)
663+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg_low8)
664+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg_low4)
665+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
666+
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "t",
667+
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r",
668+
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_upper) => "d",
669+
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_pair) => "r",
670+
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_iw) => "w",
671+
InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg_ptr) => "e",
672+
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
673+
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
674+
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
675+
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::preg) => {
676+
unreachable!("clobber-only")
677+
}
678+
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
679+
InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
680+
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
681+
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
682+
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
683+
InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::reg) => "r",
684+
InlineAsmRegClass::CSKY(CSKYInlineAsmRegClass::freg) => "f",
685+
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "d", // more specific than "r"
686+
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
687+
InlineAsmRegClass::Msp430(Msp430InlineAsmRegClass::reg) => "r",
688+
// https://github.com/gcc-mirror/gcc/blob/master/gcc/config/nvptx/nvptx.md -> look for
689+
// "define_constraint".
690+
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
691+
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r",
692+
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l",
693+
694+
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg) => "r",
695+
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::reg_nonzero) => "b",
696+
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::freg) => "f",
697+
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::vreg) => "v",
698+
InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::cr)
699+
| InlineAsmRegClass::PowerPC(PowerPCInlineAsmRegClass::xer) => {
700+
unreachable!("clobber-only")
701+
}
702+
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) => "r",
703+
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => "f",
704+
InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => {
705+
unreachable!("clobber-only")
706+
}
707+
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg) => "r",
708+
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_abcd) => "Q",
709+
InlineAsmRegClass::X86(X86InlineAsmRegClass::reg_byte) => "q",
710+
InlineAsmRegClass::X86(X86InlineAsmRegClass::xmm_reg)
711+
| InlineAsmRegClass::X86(X86InlineAsmRegClass::ymm_reg) => "x",
712+
InlineAsmRegClass::X86(X86InlineAsmRegClass::zmm_reg) => "v",
713+
InlineAsmRegClass::X86(X86InlineAsmRegClass::kreg) => "Yk",
714+
InlineAsmRegClass::X86(
715+
X86InlineAsmRegClass::kreg0
716+
| X86InlineAsmRegClass::x87_reg
717+
| X86InlineAsmRegClass::mmx_reg
718+
| X86InlineAsmRegClass::tmm_reg,
719+
) => unreachable!("clobber-only"),
720+
InlineAsmRegClass::SpirV(SpirVInlineAsmRegClass::reg) => {
721+
bug!("GCC backend does not support SPIR-V")
722+
}
723+
InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r",
724+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg) => "r",
725+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::reg_addr) => "a",
726+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::freg) => "f",
727+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::vreg) => "v",
728+
InlineAsmRegClass::S390x(S390xInlineAsmRegClass::areg) => {
729+
unreachable!("clobber-only")
730+
}
731+
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::reg) => "r",
732+
InlineAsmRegClass::Sparc(SparcInlineAsmRegClass::yreg) => unreachable!("clobber-only"),
733+
InlineAsmRegClass::Err => unreachable!(),
734+
}
722735
}
723736

724737
/// Type to use for outputs that are discarded. It doesn't really matter what

tests/run/asm.rs

+22
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,28 @@ fn asm() {
205205
}
206206
assert_eq!((x, y), (16, 16));
207207
}
208+
209+
// the `b` suffix for registers in the `reg_byte` register class is not supported in GCC
210+
// and needs to be stripped in order to use these registers.
211+
unsafe {
212+
core::arch::asm!(
213+
"",
214+
out("al") _,
215+
out("bl") _,
216+
out("cl") _,
217+
out("dl") _,
218+
out("sil") _,
219+
out("dil") _,
220+
out("r8b") _,
221+
out("r9b") _,
222+
out("r10b") _,
223+
out("r11b") _,
224+
out("r12b") _,
225+
out("r13b") _,
226+
out("r14b") _,
227+
out("r15b") _,
228+
);
229+
}
208230
}
209231

210232
#[cfg(not(target_arch = "x86_64"))]

0 commit comments

Comments
 (0)