Support const and sym operands in inline asm
This commit is contained in:
parent
8b48138039
commit
044a3a65a0
@ -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<CPlace<'tcx>>,
|
||||
},
|
||||
InOut {
|
||||
reg: InlineAsmRegOrRegClass,
|
||||
_late: bool,
|
||||
in_value: CValue<'tcx>,
|
||||
out_place: Option<CPlace<'tcx>>,
|
||||
},
|
||||
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::<Vec<_>>();
|
||||
|
||||
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<Option<InlineAsmReg>>,
|
||||
stack_slots_clobber: Vec<Option<Size>>,
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user