diff --git a/src/inline_asm.rs b/src/inline_asm.rs index 3fcc84d3929..aa0b51181f4 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -6,12 +6,37 @@ use std::fmt::Write; use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::mir::InlineAsmOperand; +use rustc_middle::ty::SymbolName; use rustc_span::sym; use rustc_target::asm::*; +enum CInlineAsmOperand<'tcx> { + In { + reg: InlineAsmRegOrRegClass, + value: CValue<'tcx>, + }, + Out { + reg: InlineAsmRegOrRegClass, + late: bool, + place: Option>, + }, + InOut { + reg: InlineAsmRegOrRegClass, + _late: bool, + in_value: CValue<'tcx>, + out_place: Option>, + }, + Const { + value: String, + }, + Symbol { + symbol: SymbolName<'tcx>, + }, +} + pub(crate) fn codegen_inline_asm<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, - _span: Span, + span: Span, template: &[InlineAsmTemplatePiece], operands: &[InlineAsmOperand<'tcx>], options: InlineAsmOptions, @@ -198,6 +223,59 @@ pub(crate) fn codegen_inline_asm<'tcx>( } } + let operands = operands + .into_iter() + .map(|operand| match *operand { + InlineAsmOperand::In { reg, ref value } => { + CInlineAsmOperand::In { reg, value: crate::base::codegen_operand(fx, value) } + } + InlineAsmOperand::Out { reg, late, ref place } => CInlineAsmOperand::Out { + reg, + late, + place: place.map(|place| crate::base::codegen_place(fx, place)), + }, + InlineAsmOperand::InOut { reg, late, ref in_value, ref out_place } => { + CInlineAsmOperand::InOut { + reg, + _late: late, + in_value: crate::base::codegen_operand(fx, in_value), + out_place: out_place.map(|place| crate::base::codegen_place(fx, place)), + } + } + InlineAsmOperand::Const { ref value } => { + let (const_value, ty) = crate::constant::eval_mir_constant(fx, &*value) + .unwrap_or_else(|| span_bug!(span, "asm const cannot be resolved")); + let value = rustc_codegen_ssa::common::asm_const_to_str( + fx.tcx, + span, + const_value, + fx.layout_of(ty), + ); + CInlineAsmOperand::Const { value } + } + InlineAsmOperand::SymFn { ref value } => { + let literal = fx.monomorphize(value.literal); + if let ty::FnDef(def_id, substs) = *literal.ty().kind() { + let instance = ty::Instance::resolve_for_fn_ptr( + fx.tcx, + ty::ParamEnv::reveal_all(), + def_id, + substs, + ) + .unwrap(); + CInlineAsmOperand::Symbol { symbol: fx.tcx.symbol_name(instance) } + } else { + span_bug!(span, "invalid type for asm sym (fn)"); + } + } + InlineAsmOperand::SymStatic { def_id } => { + assert!(fx.tcx.is_static(def_id)); + let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx); + CInlineAsmOperand::Symbol { symbol: fx.tcx.symbol_name(instance) } + } + }) + .collect::>(); + let mut inputs = Vec::new(); let mut outputs = Vec::new(); @@ -206,7 +284,7 @@ pub(crate) fn codegen_inline_asm<'tcx>( arch: fx.tcx.sess.asm_arch.unwrap(), enclosing_def_id: fx.instance.def_id(), template, - operands, + operands: &operands, options, registers: Vec::new(), stack_slots_clobber: Vec::new(), @@ -229,36 +307,22 @@ pub(crate) fn codegen_inline_asm<'tcx>( fx.cx.global_asm.push_str(&generated_asm); for (i, operand) in operands.iter().enumerate() { - match *operand { - InlineAsmOperand::In { reg: _, ref value } => { - inputs.push(( - asm_gen.stack_slots_input[i].unwrap(), - crate::base::codegen_operand(fx, value).load_scalar(fx), - )); + match operand { + CInlineAsmOperand::In { reg: _, value } => { + inputs.push((asm_gen.stack_slots_input[i].unwrap(), value.load_scalar(fx))); } - InlineAsmOperand::Out { reg: _, late: _, place } => { + CInlineAsmOperand::Out { reg: _, late: _, place } => { if let Some(place) = place { - outputs.push(( - asm_gen.stack_slots_output[i].unwrap(), - crate::base::codegen_place(fx, place), - )); + outputs.push((asm_gen.stack_slots_output[i].unwrap(), place.clone())); } } - InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => { - inputs.push(( - asm_gen.stack_slots_input[i].unwrap(), - crate::base::codegen_operand(fx, in_value).load_scalar(fx), - )); + CInlineAsmOperand::InOut { reg: _, _late: _, in_value, out_place } => { + inputs.push((asm_gen.stack_slots_input[i].unwrap(), in_value.load_scalar(fx))); if let Some(out_place) = out_place { - outputs.push(( - asm_gen.stack_slots_output[i].unwrap(), - crate::base::codegen_place(fx, out_place), - )); + outputs.push((asm_gen.stack_slots_output[i].unwrap(), out_place.clone())); } } - InlineAsmOperand::Const { value: _ } => todo!(), - InlineAsmOperand::SymFn { value: _ } => todo!(), - InlineAsmOperand::SymStatic { def_id: _ } => todo!(), + CInlineAsmOperand::Const { value: _ } | CInlineAsmOperand::Symbol { symbol: _ } => {} } } @@ -280,7 +344,7 @@ struct InlineAssemblyGenerator<'a, 'tcx> { arch: InlineAsmArch, enclosing_def_id: DefId, template: &'a [InlineAsmTemplatePiece], - operands: &'a [InlineAsmOperand<'tcx>], + operands: &'a [CInlineAsmOperand<'tcx>], options: InlineAsmOptions, registers: Vec>, stack_slots_clobber: Vec>, @@ -304,18 +368,20 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // Add explicit registers to the allocated set. for (i, operand) in self.operands.iter().enumerate() { match *operand { - InlineAsmOperand::In { reg: InlineAsmRegOrRegClass::Reg(reg), .. } => { + CInlineAsmOperand::In { reg: InlineAsmRegOrRegClass::Reg(reg), .. } => { regs[i] = Some(reg); allocated.entry(reg).or_default().0 = true; } - InlineAsmOperand::Out { - reg: InlineAsmRegOrRegClass::Reg(reg), late: true, .. + CInlineAsmOperand::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), .. } => { + CInlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::Reg(reg), .. } + | CInlineAsmOperand::InOut { reg: InlineAsmRegOrRegClass::Reg(reg), .. } => { regs[i] = Some(reg); allocated.insert(reg, (true, true)); } @@ -326,12 +392,12 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // Allocate out/inout/inlateout registers first because they are more constrained. for (i, operand) in self.operands.iter().enumerate() { match *operand { - InlineAsmOperand::Out { + CInlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::RegClass(class), late: false, .. } - | InlineAsmOperand::InOut { + | CInlineAsmOperand::InOut { reg: InlineAsmRegOrRegClass::RegClass(class), .. } => { let mut alloc_reg = None; @@ -360,7 +426,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // Allocate in/lateout. for (i, operand) in self.operands.iter().enumerate() { match *operand { - InlineAsmOperand::In { reg: InlineAsmRegOrRegClass::RegClass(class), .. } => { + CInlineAsmOperand::In { reg: InlineAsmRegOrRegClass::RegClass(class), .. } => { let mut alloc_reg = None; for ® in &map[&class] { let mut used = false; @@ -380,7 +446,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { regs[i] = Some(reg); allocated.entry(reg).or_default().0 = true; } - InlineAsmOperand::Out { + CInlineAsmOperand::Out { reg: InlineAsmRegOrRegClass::RegClass(class), late: true, .. @@ -455,7 +521,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // Allocate stack slots for inout for (i, operand) in self.operands.iter().enumerate() { match *operand { - InlineAsmOperand::InOut { reg, out_place: Some(_), .. } => { + CInlineAsmOperand::InOut { reg, out_place: Some(_), .. } => { let slot = new_slot(reg.reg_class()); slots_input[i] = Some(slot); slots_output[i] = Some(slot); @@ -470,8 +536,8 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // Allocate stack slots for input for (i, operand) in self.operands.iter().enumerate() { match *operand { - InlineAsmOperand::In { reg, .. } - | InlineAsmOperand::InOut { reg, out_place: None, .. } => { + CInlineAsmOperand::In { reg, .. } + | CInlineAsmOperand::InOut { reg, out_place: None, .. } => { slots_input[i] = Some(new_slot(reg.reg_class())); } _ => (), @@ -487,7 +553,7 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { // Allocate stack slots for output for (i, operand) in self.operands.iter().enumerate() { match *operand { - InlineAsmOperand::Out { reg, place: Some(_), .. } => { + CInlineAsmOperand::Out { reg, place: Some(_), .. } => { slots_output[i] = Some(new_slot(reg.reg_class())); } _ => (), @@ -549,13 +615,23 @@ 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('%'); + match self.operands[*operand_idx] { + CInlineAsmOperand::In { .. } + | CInlineAsmOperand::Out { .. } + | CInlineAsmOperand::InOut { .. } => { + if self.options.contains(InlineAsmOptions::ATT_SYNTAX) { + generated_asm.push('%'); + } + self.registers[*operand_idx] + .unwrap() + .emit(&mut generated_asm, self.arch, *modifier) + .unwrap(); + } + CInlineAsmOperand::Const { ref value } => { + generated_asm.push_str(value); + } + CInlineAsmOperand::Symbol { symbol } => generated_asm.push_str(symbol.name), } - self.registers[*operand_idx] - .unwrap() - .emit(&mut generated_asm, self.arch, *modifier) - .unwrap(); } } }