template: &[InlineAsmTemplatePiece],
operands: &[InlineAsmOperand<'tcx>],
options: InlineAsmOptions,
+ destination: Option<mir::BasicBlock>,
) {
// FIXME add .eh_frame unwind info directives
- if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
- let true_ = fx.bcx.ins().iconst(types::I32, 1);
- fx.bcx.ins().trapnz(true_, TrapCode::User(1));
- return;
- } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
- && matches!(
- template[1],
- InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
- )
- && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
- && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
- && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
- && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
- && matches!(
- template[6],
- InlineAsmTemplatePiece::Placeholder { operand_idx: 0, modifier: Some('r'), span: _ }
- )
- {
- assert_eq!(operands.len(), 4);
- let (leaf, eax_place) = match operands[1] {
- InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
- 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()),
- )
- }
- _ => unreachable!(),
- };
- let ebx_place = match operands[0] {
- InlineAsmOperand::Out { reg, late: true, place } => {
- assert_eq!(
- reg,
- InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
- X86InlineAsmRegClass::reg
- ))
- );
- crate::base::codegen_place(fx, place.unwrap())
- }
- _ => unreachable!(),
- };
- let (sub_leaf, ecx_place) = match operands[2] {
- InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
- 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()),
- )
- }
- _ => unreachable!(),
- };
- let edx_place = match operands[3] {
- InlineAsmOperand::Out { reg, late: true, place } => {
- assert_eq!(
- reg,
- InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx))
- );
- crate::base::codegen_place(fx, place.unwrap())
- }
- _ => unreachable!(),
- };
-
- let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
-
- eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
- ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
- ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
- edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
- return;
- } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
- // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
- crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
- } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
- crate::trap::trap_unimplemented(fx, "Alloca is not supported");
+ if !template.is_empty() {
+ if template[0] == InlineAsmTemplatePiece::String("int $$0x29".to_string()) {
+ fx.bcx.ins().trap(TrapCode::User(1));
+ return;
+ } else if template[0] == InlineAsmTemplatePiece::String("movq %rbx, ".to_string())
+ && matches!(
+ template[1],
+ InlineAsmTemplatePiece::Placeholder {
+ operand_idx: 0,
+ modifier: Some('r'),
+ span: _
+ }
+ )
+ && template[2] == InlineAsmTemplatePiece::String("\n".to_string())
+ && template[3] == InlineAsmTemplatePiece::String("cpuid".to_string())
+ && template[4] == InlineAsmTemplatePiece::String("\n".to_string())
+ && template[5] == InlineAsmTemplatePiece::String("xchgq %rbx, ".to_string())
+ && matches!(
+ template[6],
+ InlineAsmTemplatePiece::Placeholder {
+ operand_idx: 0,
+ modifier: Some('r'),
+ span: _
+ }
+ )
+ {
+ assert_eq!(operands.len(), 4);
+ let (leaf, eax_place) = match operands[1] {
+ InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+ 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()),
+ )
+ }
+ _ => unreachable!(),
+ };
+ let ebx_place = match operands[0] {
+ InlineAsmOperand::Out { reg, late: true, place } => {
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::RegClass(InlineAsmRegClass::X86(
+ X86InlineAsmRegClass::reg
+ ))
+ );
+ crate::base::codegen_place(fx, place.unwrap())
+ }
+ _ => unreachable!(),
+ };
+ let (sub_leaf, ecx_place) = match operands[2] {
+ InlineAsmOperand::InOut { reg, late: true, ref in_value, out_place } => {
+ 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()),
+ )
+ }
+ _ => unreachable!(),
+ };
+ let edx_place = match operands[3] {
+ InlineAsmOperand::Out { reg, late: true, place } => {
+ assert_eq!(
+ reg,
+ InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx))
+ );
+ crate::base::codegen_place(fx, place.unwrap())
+ }
+ _ => unreachable!(),
+ };
+
+ let (eax, ebx, ecx, edx) = crate::intrinsics::codegen_cpuid_call(fx, leaf, sub_leaf);
+
+ eax_place.write_cvalue(fx, CValue::by_val(eax, fx.layout_of(fx.tcx.types.u32)));
+ ebx_place.write_cvalue(fx, CValue::by_val(ebx, fx.layout_of(fx.tcx.types.u32)));
+ ecx_place.write_cvalue(fx, CValue::by_val(ecx, fx.layout_of(fx.tcx.types.u32)));
+ edx_place.write_cvalue(fx, CValue::by_val(edx, fx.layout_of(fx.tcx.types.u32)));
+ let destination_block = fx.get_block(destination.unwrap());
+ fx.bcx.ins().jump(destination_block, &[]);
+ return;
+ } else if fx.tcx.symbol_name(fx.instance).name.starts_with("___chkstk") {
+ // ___chkstk, ___chkstk_ms and __alloca are only used on Windows
+ crate::trap::trap_unimplemented(fx, "Stack probes are not supported");
+ return;
+ } else if fx.tcx.symbol_name(fx.instance).name == "__alloca" {
+ crate::trap::trap_unimplemented(fx, "Alloca is not supported");
+ return;
+ }
}
let mut inputs = Vec::new();
let mut asm_gen = InlineAssemblyGenerator {
tcx: fx.tcx,
arch: fx.tcx.sess.asm_arch.unwrap(),
+ enclosing_def_id: fx.instance.def_id(),
template,
operands,
options,
}
call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs);
+
+ match destination {
+ Some(destination) => {
+ let destination_block = fx.get_block(destination);
+ fx.bcx.ins().jump(destination_block, &[]);
+ }
+ None => {
+ fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
+ }
+ }
}
struct InlineAssemblyGenerator<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
arch: InlineAsmArch,
+ enclosing_def_id: DefId,
template: &'a [InlineAsmTemplatePiece],
operands: &'a [InlineAsmOperand<'tcx>],
options: InlineAsmOptions,
impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> {
fn allocate_registers(&mut self) {
let sess = self.tcx.sess;
- let map = allocatable_registers(self.arch, &sess.target_features, &sess.target);
+ let map = allocatable_registers(
+ self.arch,
+ sess.relocation_model(),
+ self.tcx.asm_target_features(self.enclosing_def_id),
+ &sess.target,
+ );
let mut allocated = FxHashMap::<_, (bool, bool)>::default();
let mut regs = vec![None; self.operands.len()];
let mut new_slot = |x| new_slot_fn(&mut slot_size, x);
// Allocate stack slots for saving clobbered registers
- let abi_clobber = InlineAsmClobberAbi::parse(
- self.arch,
- &self.tcx.sess.target_features,
- &self.tcx.sess.target,
- sym::C,
- )
- .unwrap()
- .clobbered_regs();
+ let abi_clobber = InlineAsmClobberAbi::parse(self.arch, &self.tcx.sess.target, sym::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