]> git.lizzy.rs Git - rust.git/blobdiff - src/inline_asm.rs
Enable inline asm on macOS
[rust.git] / src / inline_asm.rs
index c242c75ed18ffcf9adb84a9284965fa23e6cb510..7b1a39c675cde67c37d17eee05b14cbb9e9237cf 100644 (file)
@@ -15,89 +15,103 @@ pub(crate) fn codegen_inline_asm<'tcx>(
     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();
@@ -106,6 +120,7 @@ pub(crate) fn codegen_inline_asm<'tcx>(
     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,
@@ -164,11 +179,22 @@ pub(crate) fn codegen_inline_asm<'tcx>(
     }
 
     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,
@@ -182,7 +208,12 @@ struct InlineAssemblyGenerator<'a, 'tcx> {
 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()];
 
@@ -313,14 +344,9 @@ fn allocate_stack_slots(&mut self) {
         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