diff --git a/src/inline_asm.rs b/src/inline_asm.rs
index e0116c8b7..706d9cdc1 100644
--- a/src/inline_asm.rs
+++ b/src/inline_asm.rs
@@ -6,6 +6,7 @@ use std::fmt::Write;
use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_middle::mir::InlineAsmOperand;
+use rustc_span::Symbol;
use rustc_target::asm::*;
pub(crate) fn codegen_inline_asm<'tcx>(
@@ -41,8 +42,10 @@ pub(crate) fn codegen_inline_asm<'tcx>(
assert_eq!(operands.len(), 4);
let (leaf, eax_place) = match operands[1] {
InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
- let reg = expect_reg(reg);
- assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::ax));
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax))
+ );
(
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
crate::base::codegen_place(fx, out_place.unwrap()),
@@ -64,8 +67,10 @@ pub(crate) fn codegen_inline_asm<'tcx>(
};
let (sub_leaf, ecx_place) = match operands[2] {
InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
- let reg = expect_reg(reg);
- assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::cx));
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx))
+ );
(
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
crate::base::codegen_place(fx, out_place.unwrap()),
@@ -75,8 +80,10 @@ pub(crate) fn codegen_inline_asm<'tcx>(
};
let edx_place = match operands[3] {
InlineAsmOperand::Out { reg, late: true, place } => {
- let reg = expect_reg(reg);
- assert_eq!(reg, InlineAsmReg::X86(X86InlineAsmReg::dx));
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx))
+ );
crate::base::codegen_place(fx, place.unwrap())
}
_ => unreachable!(),
@@ -96,60 +103,55 @@ pub(crate) fn codegen_inline_asm<'tcx>(
crate::trap::trap_unimplemented(fx, "Alloca is not supported");
}
- let mut slot_size = Size::from_bytes(0);
- let mut clobbered_regs = Vec::new();
let mut inputs = Vec::new();
let mut outputs = Vec::new();
- let mut new_slot = |reg_class: InlineAsmRegClass| {
- let reg_size = reg_class
- .supported_types(InlineAsmArch::X86_64)
- .iter()
- .map(|(ty, _)| ty.size())
- .max()
- .unwrap();
- let align = rustc_target::abi::Align::from_bytes(reg_size.bytes()).unwrap();
- slot_size = slot_size.align_to(align);
- let offset = slot_size;
- slot_size += reg_size;
- offset
+ let mut asm_gen = InlineAssemblyGenerator {
+ tcx: fx.tcx,
+ arch: fx.tcx.sess.asm_arch.unwrap(),
+ template,
+ operands,
+ options,
+ registers: Vec::new(),
+ stack_slots_clobber: Vec::new(),
+ stack_slots_input: Vec::new(),
+ stack_slots_output: Vec::new(),
+ stack_slot_size: Size::from_bytes(0),
};
+ asm_gen.allocate_registers();
+ asm_gen.allocate_stack_slots();
+
+ let inline_asm_index = fx.inline_asm_index;
+ fx.inline_asm_index += 1;
+ let asm_name = format!("{}__inline_asm_{}", fx.symbol_name, inline_asm_index);
- // FIXME overlap input and output slots to save stack space
- for operand in operands {
+ let generated_asm = asm_gen.generate_asm_wrapper(&asm_name);
+ fx.cx.global_asm.push_str(&generated_asm);
+
+ for (i, operand) in operands.iter().enumerate() {
match *operand {
- InlineAsmOperand::In { reg, ref value } => {
- let reg = expect_reg(reg);
- clobbered_regs.push((reg, new_slot(reg.reg_class())));
+ InlineAsmOperand::In { reg: _, ref value } => {
inputs.push((
- reg,
- new_slot(reg.reg_class()),
+ asm_gen.stack_slots_input[i].unwrap(),
crate::base::codegen_operand(fx, value).load_scalar(fx),
));
}
- InlineAsmOperand::Out { reg, late: _, place } => {
- let reg = expect_reg(reg);
- clobbered_regs.push((reg, new_slot(reg.reg_class())));
+ InlineAsmOperand::Out { reg: _, late: _, place } => {
if let Some(place) = place {
outputs.push((
- reg,
- new_slot(reg.reg_class()),
+ asm_gen.stack_slots_output[i].unwrap(),
crate::base::codegen_place(fx, place),
));
}
}
- InlineAsmOperand::InOut { reg, late: _, ref in_value, out_place } => {
- let reg = expect_reg(reg);
- clobbered_regs.push((reg, new_slot(reg.reg_class())));
+ InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
inputs.push((
- reg,
- new_slot(reg.reg_class()),
+ asm_gen.stack_slots_input[i].unwrap(),
crate::base::codegen_operand(fx, in_value).load_scalar(fx),
));
if let Some(out_place) = out_place {
outputs.push((
- reg,
- new_slot(reg.reg_class()),
+ asm_gen.stack_slots_output[i].unwrap(),
crate::base::codegen_place(fx, out_place),
));
}
@@ -160,106 +162,467 @@ pub(crate) fn codegen_inline_asm<'tcx>(
}
}
- let inline_asm_index = fx.inline_asm_index;
- fx.inline_asm_index += 1;
- let asm_name = format!("{}__inline_asm_{}", fx.symbol_name, inline_asm_index);
-
- let generated_asm = generate_asm_wrapper(
- &asm_name,
- InlineAsmArch::X86_64,
- options,
- template,
- clobbered_regs,
- &inputs,
- &outputs,
- );
- fx.cx.global_asm.push_str(&generated_asm);
-
- call_inline_asm(fx, &asm_name, slot_size, inputs, outputs);
+ call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs);
}
-fn generate_asm_wrapper(
- asm_name: &str,
+struct InlineAssemblyGenerator<'a, 'tcx> {
+ tcx: TyCtxt<'tcx>,
arch: InlineAsmArch,
+ template: &'a [InlineAsmTemplatePiece],
+ operands: &'a [InlineAsmOperand<'tcx>],
options: InlineAsmOptions,
- template: &[InlineAsmTemplatePiece],
- clobbered_regs: Vec<(InlineAsmReg, Size)>,
- inputs: &[(InlineAsmReg, Size, Value)],
- outputs: &[(InlineAsmReg, Size, CPlace<'_>)],
-) -> String {
- let mut generated_asm = String::new();
- writeln!(generated_asm, ".globl {}", asm_name).unwrap();
- writeln!(generated_asm, ".type {},@function", asm_name).unwrap();
- writeln!(generated_asm, ".section .text.{},\"ax\",@progbits", asm_name).unwrap();
- writeln!(generated_asm, "{}:", asm_name).unwrap();
-
- generated_asm.push_str(".intel_syntax noprefix\n");
- generated_asm.push_str(" push rbp\n");
- generated_asm.push_str(" mov rbp,rdi\n");
-
- // Save clobbered registers
- if !options.contains(InlineAsmOptions::NORETURN) {
- // FIXME skip registers saved by the calling convention
- for &(reg, offset) in &clobbered_regs {
- save_register(&mut generated_asm, arch, reg, offset);
+ registers: Vec