From 042eb37837bd36eb44bd928de19bd7bc97888ace Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 01:44:32 +0000 Subject: [PATCH 01/11] Implement register allocation for inline assembly --- src/inline_asm.rs | 277 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 207 insertions(+), 70 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index e0116c8b7..07bb26227 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>( @@ -115,11 +116,21 @@ pub(crate) fn codegen_inline_asm<'tcx>( offset }; + let mut asm_gen = InlineAssemblyGenerator { + tcx: fx.tcx, + arch: InlineAsmArch::X86_64, + template, + operands, + options, + registers: Vec::new(), + }; + asm_gen.allocate_registers(); + // FIXME overlap input and output slots to save stack space - for operand in operands { + for (i, operand) in operands.iter().enumerate() { match *operand { InlineAsmOperand::In { reg, ref value } => { - let reg = expect_reg(reg); + let reg = asm_gen.registers[i].unwrap(); clobbered_regs.push((reg, new_slot(reg.reg_class()))); inputs.push(( reg, @@ -128,7 +139,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( )); } InlineAsmOperand::Out { reg, late: _, place } => { - let reg = expect_reg(reg); + let reg = asm_gen.registers[i].unwrap(); clobbered_regs.push((reg, new_slot(reg.reg_class()))); if let Some(place) = place { outputs.push(( @@ -139,7 +150,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( } } InlineAsmOperand::InOut { reg, late: _, ref in_value, out_place } => { - let reg = expect_reg(reg); + let reg = asm_gen.registers[i].unwrap(); clobbered_regs.push((reg, new_slot(reg.reg_class()))); inputs.push(( reg, @@ -164,94 +175,220 @@ pub(crate) fn codegen_inline_asm<'tcx>( 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, - ); + let generated_asm = asm_gen.generate_asm_wrapper(&asm_name, clobbered_regs, &inputs, &outputs); fx.cx.global_asm.push_str(&generated_asm); call_inline_asm(fx, &asm_name, 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>, +} - // Write input registers - for &(reg, offset, _value) in inputs { - restore_register(&mut generated_asm, arch, reg, offset); - } +impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { + fn allocate_registers(&mut self) { + let sess = self.tcx.sess; + let map = allocatable_registers( + self.arch, + |feature| sess.target_features.contains(&Symbol::intern(feature)), + &sess.target, + ); + let mut allocated = FxHashMap::<_, (bool, bool)>::default(); + let mut regs = vec![None; self.operands.len()]; + + // Add explicit registers to the allocated set. + for (i, operand) in self.operands.iter().enumerate() { + match *operand { + InlineAsmOperand::In { reg: InlineAsmRegOrRegClass::Reg(reg), .. } => { + regs[i] = Some(reg); + allocated.entry(reg).or_default().0 = true; + } + InlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(reg), late: true, .. + } => { + regs[i] = Some(reg); + allocated.entry(reg).or_default().1 = true; + } + InlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(reg), .. } + | InlineAsmOperand::InOut { reg: InlineAsmRegOrRegClass::Reg(reg), .. } => { + regs[i] = Some(reg); + allocated.insert(reg, (true, true)); + } + _ => (), + } + } - if options.contains(InlineAsmOptions::ATT_SYNTAX) { - generated_asm.push_str(".att_syntax\n"); - } + // Allocate out/inout/inlateout registers first because they are more constrained. + for (i, operand) in self.operands.iter().enumerate() { + match *operand { + InlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::RegClass(class), + late: false, + .. + } + | InlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::RegClass(class), .. + } => { + let mut alloc_reg = None; + for ® in &map[&class] { + let mut used = false; + reg.overlapping_regs(|r| { + if allocated.contains_key(&r) { + used = true; + } + }); + + if !used { + alloc_reg = Some(reg); + break; + } + } + + let reg = alloc_reg.expect("cannot allocate registers"); + regs[i] = Some(reg); + allocated.insert(reg, (true, true)); + } + _ => (), + } + } - // The actual inline asm - for piece in template { - match piece { - InlineAsmTemplatePiece::String(s) => { - generated_asm.push_str(s); + // Allocate in/lateout. + for (i, operand) in self.operands.iter().enumerate() { + match *operand { + InlineAsmOperand::In { reg: InlineAsmRegOrRegClass::RegClass(class), .. } => { + let mut alloc_reg = None; + for ® in &map[&class] { + let mut used = false; + reg.overlapping_regs(|r| { + if allocated.get(&r).copied().unwrap_or_default().0 { + used = true; + } + }); + + if !used { + alloc_reg = Some(reg); + break; + } + } + + let reg = alloc_reg.expect("cannot allocate registers"); + regs[i] = Some(reg); + allocated.entry(reg).or_default().0 = true; + } + InlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::RegClass(class), + late: true, + .. + } => { + let mut alloc_reg = None; + for ® in &map[&class] { + let mut used = false; + reg.overlapping_regs(|r| { + if allocated.get(&r).copied().unwrap_or_default().1 { + used = true; + } + }); + + if !used { + alloc_reg = Some(reg); + break; + } + } + + let reg = alloc_reg.expect("cannot allocate registers"); + regs[i] = Some(reg); + allocated.entry(reg).or_default().1 = true; + } + _ => (), } - InlineAsmTemplatePiece::Placeholder { operand_idx: _, modifier: _, span: _ } => todo!(), } + + self.registers = regs; } - generated_asm.push('\n'); - if options.contains(InlineAsmOptions::ATT_SYNTAX) { + fn generate_asm_wrapper( + &self, + asm_name: &str, + 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 !self.options.contains(InlineAsmOptions::NORETURN) { + // FIXME skip registers saved by the calling convention + for &(reg, offset) in &clobbered_regs { + save_register(&mut generated_asm, self.arch, reg, offset); + } + } - if !options.contains(InlineAsmOptions::NORETURN) { - // Read output registers - for &(reg, offset, _place) in outputs { - save_register(&mut generated_asm, arch, reg, offset); + // Write input registers + for &(reg, offset, _value) in inputs { + restore_register(&mut generated_asm, self.arch, reg, offset); } - // Restore clobbered registers - for &(reg, offset) in clobbered_regs.iter().rev() { - restore_register(&mut generated_asm, arch, reg, offset); + if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { + generated_asm.push_str(".att_syntax\n"); } - generated_asm.push_str(" pop rbp\n"); - generated_asm.push_str(" ret\n"); - } else { - generated_asm.push_str(" ud2\n"); - } + // The actual inline asm + for piece in self.template { + match piece { + InlineAsmTemplatePiece::String(s) => { + generated_asm.push_str(s); + } + InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span: _ } => { + self.registers[*operand_idx] + .unwrap() + .emit(&mut generated_asm, self.arch, *modifier) + .unwrap(); + } + } + } + generated_asm.push('\n'); + + if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { + generated_asm.push_str(".intel_syntax noprefix\n"); + } + + if !self.options.contains(InlineAsmOptions::NORETURN) { + // Read output registers + for &(reg, offset, _place) in outputs { + save_register(&mut generated_asm, self.arch, reg, offset); + } - generated_asm.push_str(".att_syntax\n"); - writeln!(generated_asm, ".size {name}, .-{name}", name = asm_name).unwrap(); - generated_asm.push_str(".text\n"); - generated_asm.push_str("\n\n"); + // Restore clobbered registers + for &(reg, offset) in clobbered_regs.iter().rev() { + restore_register(&mut generated_asm, self.arch, reg, offset); + } + + generated_asm.push_str(" pop rbp\n"); + generated_asm.push_str(" ret\n"); + } else { + generated_asm.push_str(" ud2\n"); + } - generated_asm + generated_asm.push_str(".att_syntax\n"); + writeln!(generated_asm, ".size {name}, .-{name}", name = asm_name).unwrap(); + generated_asm.push_str(".text\n"); + generated_asm.push_str("\n\n"); + + generated_asm + } } fn call_inline_asm<'tcx>( From f16d27aca48454fc3a05a477b20ba5264a740b14 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 01:48:22 +0000 Subject: [PATCH 02/11] Remove expect_reg --- src/inline_asm.rs | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 07bb26227..771f3056e 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -42,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()), @@ -65,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()), @@ -76,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!(), @@ -437,13 +443,6 @@ fn call_inline_asm<'tcx>( } } -fn expect_reg(reg_or_class: InlineAsmRegOrRegClass) -> InlineAsmReg { - match reg_or_class { - InlineAsmRegOrRegClass::Reg(reg) => reg, - InlineAsmRegOrRegClass::RegClass(class) => unimplemented!("{:?}", class), - } -} - fn save_register(generated_asm: &mut String, arch: InlineAsmArch, reg: InlineAsmReg, offset: Size) { match arch { InlineAsmArch::X86_64 => { From 894468a5377b374da3cb5c143549b21dd2dd32d6 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 02:05:56 +0000 Subject: [PATCH 03/11] Move stack slot allocation to a new fn --- src/inline_asm.rs | 93 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 70 insertions(+), 23 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 771f3056e..dde776d8e 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -103,25 +103,10 @@ 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: InlineAsmArch::X86_64, @@ -129,44 +114,49 @@ pub(crate) fn codegen_inline_asm<'tcx>( 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(); // FIXME overlap input and output slots to save stack space for (i, operand) in operands.iter().enumerate() { match *operand { InlineAsmOperand::In { reg, ref value } => { let reg = asm_gen.registers[i].unwrap(); - clobbered_regs.push((reg, new_slot(reg.reg_class()))); + clobbered_regs.push((reg, asm_gen.stack_slots_clobber[i].unwrap())); 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 = asm_gen.registers[i].unwrap(); - clobbered_regs.push((reg, new_slot(reg.reg_class()))); + clobbered_regs.push((reg, asm_gen.stack_slots_clobber[i].unwrap())); 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 = asm_gen.registers[i].unwrap(); - clobbered_regs.push((reg, new_slot(reg.reg_class()))); + clobbered_regs.push((reg, asm_gen.stack_slots_clobber[i].unwrap())); 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), )); } @@ -184,7 +174,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( let generated_asm = asm_gen.generate_asm_wrapper(&asm_name, 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); } struct InlineAssemblyGenerator<'a, 'tcx> { @@ -194,6 +184,10 @@ struct InlineAssemblyGenerator<'a, 'tcx> { operands: &'a [InlineAsmOperand<'tcx>], options: InlineAsmOptions, registers: Vec>, + stack_slots_clobber: Vec>, + stack_slots_input: Vec>, + stack_slots_output: Vec>, + stack_slot_size: Size, } impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { @@ -317,6 +311,59 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { self.registers = regs; } + fn allocate_stack_slots(&mut self) { + let mut slot_size = Size::from_bytes(0); + let mut slots_clobber = vec![None; self.operands.len()]; + let mut slots_input = vec![None; self.operands.len()]; + let mut slots_output = vec![None; self.operands.len()]; + + 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 + }; + + // FIXME overlap input and output slots to save stack space + for (i, operand) in self.operands.iter().enumerate() { + match *operand { + InlineAsmOperand::In { reg, .. } => { + slots_clobber[i] = Some(new_slot(reg.reg_class())); + slots_input[i] = Some(new_slot(reg.reg_class())); + } + InlineAsmOperand::Out { reg, place, .. } => { + slots_clobber[i] = Some(new_slot(reg.reg_class())); + if place.is_some() { + slots_output[i] = Some(new_slot(reg.reg_class())); + } + } + InlineAsmOperand::InOut { reg, out_place, .. } => { + slots_clobber[i] = Some(new_slot(reg.reg_class())); + let slot = new_slot(reg.reg_class()); + slots_input[i] = Some(slot); + if out_place.is_some() { + slots_output[i] = Some(slot); + } + } + InlineAsmOperand::Const { value: _ } => (), + InlineAsmOperand::SymFn { value: _ } => (), + InlineAsmOperand::SymStatic { def_id: _ } => (), + } + } + + self.stack_slots_clobber = slots_clobber; + self.stack_slots_input = slots_input; + self.stack_slots_output = slots_output; + self.stack_slot_size = slot_size; + } + fn generate_asm_wrapper( &self, asm_name: &str, From 703027f0fc5dbd47d1655f1af013e67ae7d5f974 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 02:28:16 +0000 Subject: [PATCH 04/11] Code cleanup as a follow up to the previous commit --- src/inline_asm.rs | 85 ++++++++++++++++++++++++----------------------- 1 file changed, 44 insertions(+), 41 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index dde776d8e..8b999f3c5 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -103,7 +103,6 @@ pub(crate) fn codegen_inline_asm<'tcx>( crate::trap::trap_unimplemented(fx, "Alloca is not supported"); } - let mut clobbered_regs = Vec::new(); let mut inputs = Vec::new(); let mut outputs = Vec::new(); @@ -122,40 +121,37 @@ pub(crate) fn codegen_inline_asm<'tcx>( 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); + + let generated_asm = asm_gen.generate_asm_wrapper(&asm_name); + fx.cx.global_asm.push_str(&generated_asm); + // FIXME overlap input and output slots to save stack space for (i, operand) in operands.iter().enumerate() { match *operand { - InlineAsmOperand::In { reg, ref value } => { - let reg = asm_gen.registers[i].unwrap(); - clobbered_regs.push((reg, asm_gen.stack_slots_clobber[i].unwrap())); + InlineAsmOperand::In { reg: _, ref value } => { inputs.push(( - reg, asm_gen.stack_slots_input[i].unwrap(), crate::base::codegen_operand(fx, value).load_scalar(fx), )); } - InlineAsmOperand::Out { reg, late: _, place } => { - let reg = asm_gen.registers[i].unwrap(); - clobbered_regs.push((reg, asm_gen.stack_slots_clobber[i].unwrap())); + InlineAsmOperand::Out { reg: _, late: _, place } => { if let Some(place) = place { outputs.push(( - reg, asm_gen.stack_slots_output[i].unwrap(), crate::base::codegen_place(fx, place), )); } } - InlineAsmOperand::InOut { reg, late: _, ref in_value, out_place } => { - let reg = asm_gen.registers[i].unwrap(); - clobbered_regs.push((reg, asm_gen.stack_slots_clobber[i].unwrap())); + InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { inputs.push(( - reg, 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, asm_gen.stack_slots_output[i].unwrap(), crate::base::codegen_place(fx, out_place), )); @@ -167,13 +163,6 @@ 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 = asm_gen.generate_asm_wrapper(&asm_name, clobbered_regs, &inputs, &outputs); - fx.cx.global_asm.push_str(&generated_asm); - call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs); } @@ -364,13 +353,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { self.stack_slot_size = slot_size; } - fn generate_asm_wrapper( - &self, - asm_name: &str, - clobbered_regs: Vec<(InlineAsmReg, Size)>, - inputs: &[(InlineAsmReg, Size, Value)], - outputs: &[(InlineAsmReg, Size, CPlace<'_>)], - ) -> String { + fn generate_asm_wrapper(&self, asm_name: &str) -> String { let mut generated_asm = String::new(); writeln!(generated_asm, ".globl {}", asm_name).unwrap(); writeln!(generated_asm, ".type {},@function", asm_name).unwrap(); @@ -384,14 +367,24 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // Save clobbered registers if !self.options.contains(InlineAsmOptions::NORETURN) { // FIXME skip registers saved by the calling convention - for &(reg, offset) in &clobbered_regs { - save_register(&mut generated_asm, self.arch, reg, offset); + for (reg, slot) in self + .registers + .iter() + .zip(self.stack_slots_clobber.iter().copied()) + .filter_map(|(r, s)| r.zip(s)) + { + save_register(&mut generated_asm, self.arch, reg, slot); } } // Write input registers - for &(reg, offset, _value) in inputs { - restore_register(&mut generated_asm, self.arch, reg, offset); + for (reg, slot) in self + .registers + .iter() + .zip(self.stack_slots_input.iter().copied()) + .filter_map(|(r, s)| r.zip(s)) + { + restore_register(&mut generated_asm, self.arch, reg, slot); } if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { @@ -414,19 +407,29 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } generated_asm.push('\n'); - if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { + if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) { generated_asm.push_str(".intel_syntax noprefix\n"); } if !self.options.contains(InlineAsmOptions::NORETURN) { // Read output registers - for &(reg, offset, _place) in outputs { - save_register(&mut generated_asm, self.arch, reg, offset); + for (reg, slot) in self + .registers + .iter() + .zip(self.stack_slots_output.iter().copied()) + .filter_map(|(r, s)| r.zip(s)) + { + save_register(&mut generated_asm, self.arch, reg, slot); } // Restore clobbered registers - for &(reg, offset) in clobbered_regs.iter().rev() { - restore_register(&mut generated_asm, self.arch, reg, offset); + for (reg, slot) in self + .registers + .iter() + .zip(self.stack_slots_clobber.iter().copied()) + .filter_map(|(r, s)| r.zip(s)) + { + restore_register(&mut generated_asm, self.arch, reg, slot); } generated_asm.push_str(" pop rbp\n"); @@ -448,8 +451,8 @@ fn call_inline_asm<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, asm_name: &str, slot_size: Size, - inputs: Vec<(InlineAsmReg, Size, Value)>, - outputs: Vec<(InlineAsmReg, Size, CPlace<'tcx>)>, + inputs: Vec<(Size, Value)>, + outputs: Vec<(Size, CPlace<'tcx>)>, ) { let stack_slot = fx.bcx.func.create_stack_slot(StackSlotData { kind: StackSlotKind::ExplicitSlot, @@ -476,14 +479,14 @@ fn call_inline_asm<'tcx>( fx.add_comment(inline_asm_func, asm_name); } - for (_reg, offset, value) in inputs { + for (offset, value) in inputs { fx.bcx.ins().stack_store(value, stack_slot, i32::try_from(offset.bytes()).unwrap()); } let stack_slot_addr = fx.bcx.ins().stack_addr(fx.pointer_type, stack_slot, 0); fx.bcx.ins().call(inline_asm_func, &[stack_slot_addr]); - for (_reg, offset, place) in outputs { + for (offset, place) in outputs { let ty = fx.clif_type(place.layout().ty).unwrap(); let value = fx.bcx.ins().stack_load(ty, stack_slot, i32::try_from(offset.bytes()).unwrap()); place.write_cvalue(fx, CValue::by_val(value, place.layout())); From 14aa039d3087b76152018e3ca8c5df34fe1540b3 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 02:38:50 +0000 Subject: [PATCH 05/11] Skip registers saved by calling convention --- src/inline_asm.rs | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 8b999f3c5..8f9deeec7 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -320,21 +320,44 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { offset }; + // Allocate stack slots for saving clobbered registers + let abi_clobber = + InlineAsmClobberAbi::parse(self.arch, &self.tcx.sess.target, Symbol::intern("C")) + .unwrap() + .clobbered_regs(); + for (i, reg) in self.registers.iter().enumerate().filter_map(|(i, r)| r.map(|r| (i, r))) { + let mut need_save = true; + // If the register overlaps with a register clobbered by function call, then + // we don't need to save it. + for r in abi_clobber { + r.overlapping_regs(|r| { + if r == reg { + need_save = false; + } + }); + + if !need_save { + break; + } + } + + if need_save { + slots_clobber[i] = Some(new_slot(reg.reg_class())); + } + } + // FIXME overlap input and output slots to save stack space for (i, operand) in self.operands.iter().enumerate() { match *operand { InlineAsmOperand::In { reg, .. } => { - slots_clobber[i] = Some(new_slot(reg.reg_class())); slots_input[i] = Some(new_slot(reg.reg_class())); } InlineAsmOperand::Out { reg, place, .. } => { - slots_clobber[i] = Some(new_slot(reg.reg_class())); if place.is_some() { slots_output[i] = Some(new_slot(reg.reg_class())); } } InlineAsmOperand::InOut { reg, out_place, .. } => { - slots_clobber[i] = Some(new_slot(reg.reg_class())); let slot = new_slot(reg.reg_class()); slots_input[i] = Some(slot); if out_place.is_some() { @@ -366,7 +389,6 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // Save clobbered registers if !self.options.contains(InlineAsmOptions::NORETURN) { - // FIXME skip registers saved by the calling convention for (reg, slot) in self .registers .iter() From fe3ba31860f2eb93f1f1cb1fe45658a8dd4d7610 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 02:50:09 +0000 Subject: [PATCH 06/11] Overlap input and output stack slots --- src/inline_asm.rs | 61 +++++++++++++++++++++++++++++++---------------- 1 file changed, 40 insertions(+), 21 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 8f9deeec7..9c4de3932 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -128,7 +128,6 @@ pub(crate) fn codegen_inline_asm<'tcx>( let generated_asm = asm_gen.generate_asm_wrapper(&asm_name); fx.cx.global_asm.push_str(&generated_asm); - // FIXME overlap input and output slots to save stack space for (i, operand) in operands.iter().enumerate() { match *operand { InlineAsmOperand::In { reg: _, ref value } => { @@ -306,7 +305,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { let mut slots_input = vec![None; self.operands.len()]; let mut slots_output = vec![None; self.operands.len()]; - let mut new_slot = |reg_class: InlineAsmRegClass| { + let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| { let reg_size = reg_class .supported_types(InlineAsmArch::X86_64) .iter() @@ -314,11 +313,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { .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; + let offset = slot_size.align_to(align); + *slot_size = offset + reg_size; offset }; + let mut new_slot = |x| new_slot_fn(&mut slot_size, x); // Allocate stack slots for saving clobbered registers let abi_clobber = @@ -346,30 +345,50 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { } } - // FIXME overlap input and output slots to save stack space + // Allocate stack slots for inout for (i, operand) in self.operands.iter().enumerate() { match *operand { - InlineAsmOperand::In { reg, .. } => { - slots_input[i] = Some(new_slot(reg.reg_class())); - } - InlineAsmOperand::Out { reg, place, .. } => { - if place.is_some() { - slots_output[i] = Some(new_slot(reg.reg_class())); - } - } - InlineAsmOperand::InOut { reg, out_place, .. } => { + InlineAsmOperand::InOut { reg, out_place: Some(_), .. } => { let slot = new_slot(reg.reg_class()); slots_input[i] = Some(slot); - if out_place.is_some() { - slots_output[i] = Some(slot); - } + slots_output[i] = Some(slot); + } + _ => (), + } + } + + let slot_size_before_input = slot_size; + let mut new_slot = |x| new_slot_fn(&mut slot_size, x); + + // Allocate stack slots for input + for (i, operand) in self.operands.iter().enumerate() { + match *operand { + InlineAsmOperand::In { reg, .. } + | InlineAsmOperand::InOut { reg, out_place: None, .. } => { + slots_input[i] = Some(new_slot(reg.reg_class())); + } + _ => (), + } + } + + // Reset slot size to before input so that input and output operands can overlap + // and save some memory. + let slot_size_after_input = slot_size; + slot_size = slot_size_before_input; + let mut new_slot = |x| new_slot_fn(&mut slot_size, x); + + // Allocate stack slots for output + for (i, operand) in self.operands.iter().enumerate() { + match *operand { + InlineAsmOperand::Out { reg, place: Some(_), .. } => { + slots_output[i] = Some(new_slot(reg.reg_class())); } - InlineAsmOperand::Const { value: _ } => (), - InlineAsmOperand::SymFn { value: _ } => (), - InlineAsmOperand::SymStatic { def_id: _ } => (), + _ => (), } } + slot_size = slot_size.max(slot_size_after_input); + self.stack_slots_clobber = slots_clobber; self.stack_slots_input = slots_input; self.stack_slots_output = slots_output; From eaf88c5b5299dfe721cb777b1632a18f8fff3cd0 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 02:56:56 +0000 Subject: [PATCH 07/11] Skeleton for multiple arch support --- src/inline_asm.rs | 116 ++++++++++++++++++++++++++++++---------------- 1 file changed, 77 insertions(+), 39 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 9c4de3932..19c3a9b82 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -402,9 +402,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { 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"); + let is_x86 = matches!(self.arch, InlineAsmArch::X86 | InlineAsmArch::X86_64); + + if is_x86 { + generated_asm.push_str(".intel_syntax noprefix\n"); + } + Self::prologue(&mut generated_asm, self.arch); // Save clobbered registers if !self.options.contains(InlineAsmOptions::NORETURN) { @@ -414,7 +417,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { .zip(self.stack_slots_clobber.iter().copied()) .filter_map(|(r, s)| r.zip(s)) { - save_register(&mut generated_asm, self.arch, reg, slot); + Self::save_register(&mut generated_asm, self.arch, reg, slot); } } @@ -425,10 +428,10 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { .zip(self.stack_slots_input.iter().copied()) .filter_map(|(r, s)| r.zip(s)) { - restore_register(&mut generated_asm, self.arch, reg, slot); + Self::restore_register(&mut generated_asm, self.arch, reg, slot); } - if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { + if is_x86 && self.options.contains(InlineAsmOptions::ATT_SYNTAX) { generated_asm.push_str(".att_syntax\n"); } @@ -460,7 +463,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { .zip(self.stack_slots_output.iter().copied()) .filter_map(|(r, s)| r.zip(s)) { - save_register(&mut generated_asm, self.arch, reg, slot); + Self::save_register(&mut generated_asm, self.arch, reg, slot); } // Restore clobbered registers @@ -470,22 +473,84 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { .zip(self.stack_slots_clobber.iter().copied()) .filter_map(|(r, s)| r.zip(s)) { - restore_register(&mut generated_asm, self.arch, reg, slot); + Self::restore_register(&mut generated_asm, self.arch, reg, slot); } - generated_asm.push_str(" pop rbp\n"); - generated_asm.push_str(" ret\n"); + Self::epilogue(&mut generated_asm, self.arch); } else { - generated_asm.push_str(" ud2\n"); + Self::epilogue_noreturn(&mut generated_asm, self.arch); } - generated_asm.push_str(".att_syntax\n"); + if is_x86 { + generated_asm.push_str(".att_syntax\n"); + } writeln!(generated_asm, ".size {name}, .-{name}", name = asm_name).unwrap(); generated_asm.push_str(".text\n"); generated_asm.push_str("\n\n"); generated_asm } + + fn prologue(generated_asm: &mut String, arch: InlineAsmArch) { + match arch { + InlineAsmArch::X86_64 => { + generated_asm.push_str(" push rbp\n"); + generated_asm.push_str(" mov rbp,rdi\n"); + } + _ => unimplemented!("prologue for {:?}", arch), + } + } + + fn epilogue(generated_asm: &mut String, arch: InlineAsmArch) { + match arch { + InlineAsmArch::X86_64 => { + generated_asm.push_str(" pop rbp\n"); + generated_asm.push_str(" ret\n"); + } + _ => unimplemented!("epilogue for {:?}", arch), + } + } + + fn epilogue_noreturn(generated_asm: &mut String, arch: InlineAsmArch) { + match arch { + InlineAsmArch::X86_64 => { + generated_asm.push_str(" ud2\n"); + } + _ => unimplemented!("epilogue_noreturn for {:?}", arch), + } + } + + fn save_register( + generated_asm: &mut String, + arch: InlineAsmArch, + reg: InlineAsmReg, + offset: Size, + ) { + match arch { + InlineAsmArch::X86_64 => { + write!(generated_asm, " mov [rbp+0x{:x}], ", offset.bytes()).unwrap(); + reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); + generated_asm.push('\n'); + } + _ => unimplemented!("save_register for {:?}", arch), + } + } + + fn restore_register( + generated_asm: &mut String, + arch: InlineAsmArch, + reg: InlineAsmReg, + offset: Size, + ) { + match arch { + InlineAsmArch::X86_64 => { + generated_asm.push_str(" mov "); + reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); + writeln!(generated_asm, ", [rbp+0x{:x}]", offset.bytes()).unwrap(); + } + _ => unimplemented!("restore_register for {:?}", arch), + } + } } fn call_inline_asm<'tcx>( @@ -533,30 +598,3 @@ fn call_inline_asm<'tcx>( place.write_cvalue(fx, CValue::by_val(value, place.layout())); } } - -fn save_register(generated_asm: &mut String, arch: InlineAsmArch, reg: InlineAsmReg, offset: Size) { - match arch { - InlineAsmArch::X86_64 => { - write!(generated_asm, " mov [rbp+0x{:x}], ", offset.bytes()).unwrap(); - reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); - generated_asm.push('\n'); - } - _ => unimplemented!("save_register for {:?}", arch), - } -} - -fn restore_register( - generated_asm: &mut String, - arch: InlineAsmArch, - reg: InlineAsmReg, - offset: Size, -) { - match arch { - InlineAsmArch::X86_64 => { - generated_asm.push_str(" mov "); - reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); - writeln!(generated_asm, ", [rbp+0x{:x}]", offset.bytes()).unwrap(); - } - _ => unimplemented!("restore_register for {:?}", arch), - } -} From cfdf10b259f20e94f82c39dcb87faaa12f7f8dc7 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 02:58:53 +0000 Subject: [PATCH 08/11] x86 inline asm support --- src/inline_asm.rs | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 19c3a9b82..35876e57f 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -493,6 +493,10 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { fn prologue(generated_asm: &mut String, arch: InlineAsmArch) { match arch { + InlineAsmArch::X86 => { + generated_asm.push_str(" push ebp\n"); + generated_asm.push_str(" mov ebp,[esp+8]\n"); + } InlineAsmArch::X86_64 => { generated_asm.push_str(" push rbp\n"); generated_asm.push_str(" mov rbp,rdi\n"); @@ -503,6 +507,10 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { fn epilogue(generated_asm: &mut String, arch: InlineAsmArch) { match arch { + InlineAsmArch::X86 => { + generated_asm.push_str(" pop ebp\n"); + generated_asm.push_str(" ret\n"); + } InlineAsmArch::X86_64 => { generated_asm.push_str(" pop rbp\n"); generated_asm.push_str(" ret\n"); @@ -513,7 +521,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { fn epilogue_noreturn(generated_asm: &mut String, arch: InlineAsmArch) { match arch { - InlineAsmArch::X86_64 => { + InlineAsmArch::X86 | InlineAsmArch::X86_64 => { generated_asm.push_str(" ud2\n"); } _ => unimplemented!("epilogue_noreturn for {:?}", arch), @@ -527,6 +535,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { offset: Size, ) { match arch { + InlineAsmArch::X86 => { + write!(generated_asm, " mov [ebp+0x{:x}], ", offset.bytes()).unwrap(); + reg.emit(generated_asm, InlineAsmArch::X86, None).unwrap(); + generated_asm.push('\n'); + } InlineAsmArch::X86_64 => { write!(generated_asm, " mov [rbp+0x{:x}], ", offset.bytes()).unwrap(); reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); @@ -543,6 +556,11 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { offset: Size, ) { match arch { + InlineAsmArch::X86 => { + generated_asm.push_str(" mov "); + reg.emit(generated_asm, InlineAsmArch::X86, None).unwrap(); + writeln!(generated_asm, ", [ebp+0x{:x}]", offset.bytes()).unwrap(); + } InlineAsmArch::X86_64 => { generated_asm.push_str(" mov "); reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); From 31e7fa54a0e92beef60fcff84128626c4b01ef62 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 03:01:42 +0000 Subject: [PATCH 09/11] Dispatch inline asm to the correct arch --- src/inline_asm.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 35876e57f..688fda753 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -108,7 +108,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( let mut asm_gen = InlineAssemblyGenerator { tcx: fx.tcx, - arch: InlineAsmArch::X86_64, + arch: fx.tcx.sess.asm_arch.unwrap(), template, operands, options, @@ -306,12 +306,8 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { let mut slots_output = vec![None; self.operands.len()]; let new_slot_fn = |slot_size: &mut Size, reg_class: InlineAsmRegClass| { - let reg_size = reg_class - .supported_types(InlineAsmArch::X86_64) - .iter() - .map(|(ty, _)| ty.size()) - .max() - .unwrap(); + let reg_size = + reg_class.supported_types(self.arch).iter().map(|(ty, _)| ty.size()).max().unwrap(); let align = rustc_target::abi::Align::from_bytes(reg_size.bytes()).unwrap(); let offset = slot_size.align_to(align); *slot_size = offset + reg_size; From f9534a9bc997833ccca51dcdcc922fb0df1790e1 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 03:15:02 +0000 Subject: [PATCH 10/11] Add RISC-V inline asm support --- src/inline_asm.rs | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 688fda753..71fbcedd1 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -497,6 +497,18 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(" push rbp\n"); generated_asm.push_str(" mov rbp,rdi\n"); } + InlineAsmArch::RiscV32 => { + generated_asm.push_str(" addi sp, sp, -8\n"); + generated_asm.push_str(" sw ra, 4(sp)\n"); + generated_asm.push_str(" sw s0, 0(sp)\n"); + generated_asm.push_str(" mv s0, a0\n"); + } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" addi sp, sp, -16\n"); + generated_asm.push_str(" sd ra, 8(sp)\n"); + generated_asm.push_str(" sd s0, 0(sp)\n"); + generated_asm.push_str(" mv s0, a0\n"); + } _ => unimplemented!("prologue for {:?}", arch), } } @@ -511,6 +523,18 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(" pop rbp\n"); generated_asm.push_str(" ret\n"); } + InlineAsmArch::RiscV32 => { + generated_asm.push_str(" lw s0, 0(sp)\n"); + generated_asm.push_str(" lw ra, 4(sp)\n"); + generated_asm.push_str(" addi sp, sp, 8\n"); + generated_asm.push_str(" ret\n"); + } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" ld s0, 0(sp)\n"); + generated_asm.push_str(" ld ra, 8(sp)\n"); + generated_asm.push_str(" addi sp, sp, 16\n"); + generated_asm.push_str(" ret\n"); + } _ => unimplemented!("epilogue for {:?}", arch), } } @@ -520,6 +544,9 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { InlineAsmArch::X86 | InlineAsmArch::X86_64 => { generated_asm.push_str(" ud2\n"); } + InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { + generated_asm.push_str(" ebreak\n"); + } _ => unimplemented!("epilogue_noreturn for {:?}", arch), } } @@ -541,6 +568,16 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); generated_asm.push('\n'); } + InlineAsmArch::RiscV32 => { + generated_asm.push_str(" sw "); + reg.emit(generated_asm, InlineAsmArch::RiscV32, None).unwrap(); + writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap(); + } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" sd "); + reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap(); + writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap(); + } _ => unimplemented!("save_register for {:?}", arch), } } @@ -562,6 +599,16 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); writeln!(generated_asm, ", [rbp+0x{:x}]", offset.bytes()).unwrap(); } + InlineAsmArch::RiscV32 => { + generated_asm.push_str(" lw "); + reg.emit(generated_asm, InlineAsmArch::RiscV32, None).unwrap(); + writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap(); + } + InlineAsmArch::RiscV64 => { + generated_asm.push_str(" ld "); + reg.emit(generated_asm, InlineAsmArch::RiscV64, None).unwrap(); + writeln!(generated_asm, ", 0x{:x}(s0)", offset.bytes()).unwrap(); + } _ => unimplemented!("restore_register for {:?}", arch), } } From 5f0c6e5539c66c251f562542cc6c1c01bcbdc75c Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Mon, 22 Nov 2021 17:01:43 +0000 Subject: [PATCH 11/11] Fix allocated reg in AT&T style asm --- src/inline_asm.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 71fbcedd1..706d9cdc1 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -438,6 +438,9 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { generated_asm.push_str(s); } InlineAsmTemplatePiece::Placeholder { operand_idx, modifier, span: _ } => { + if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { + generated_asm.push('%'); + } self.registers[*operand_idx] .unwrap() .emit(&mut generated_asm, self.arch, *modifier)