about summary refs log tree commit diff
path: root/src/librustc_codegen_ssa
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2020-02-17 21:36:01 +0000
committerAmanieu d'Antras <amanieu@gmail.com>2020-05-18 14:41:32 +0100
commitabed45ff9fa3e68f2a32ca12e012f95b9153f4df (patch)
tree1e40b0230c7ede2ccb29e1ffd42142d6c076a054 /src/librustc_codegen_ssa
parent342a64caef773f142c347441877d0be064d5cdc7 (diff)
downloadrust-abed45ff9fa3e68f2a32ca12e012f95b9153f4df.tar.gz
rust-abed45ff9fa3e68f2a32ca12e012f95b9153f4df.zip
Implement asm! codegen
Diffstat (limited to 'src/librustc_codegen_ssa')
-rw-r--r--src/librustc_codegen_ssa/mir/analyze.rs3
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs93
-rw-r--r--src/librustc_codegen_ssa/traits/asm.rs41
-rw-r--r--src/librustc_codegen_ssa/traits/mod.rs2
4 files changed, 137 insertions, 2 deletions
diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/src/librustc_codegen_ssa/mir/analyze.rs
index 9fcaf2818e8..5e3a37e20bd 100644
--- a/src/librustc_codegen_ssa/mir/analyze.rs
+++ b/src/librustc_codegen_ssa/mir/analyze.rs
@@ -358,7 +358,8 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
                 | TerminatorKind::SwitchInt { .. }
                 | TerminatorKind::Yield { .. }
                 | TerminatorKind::FalseEdges { .. }
-                | TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
+                | TerminatorKind::FalseUnwind { .. }
+                | TerminatorKind::InlineAsm { .. } => { /* nothing to do */ }
                 TerminatorKind::Call { cleanup: unwind, .. }
                 | TerminatorKind::Assert { cleanup: unwind, .. }
                 | TerminatorKind::DropAndReplace { unwind, .. }
diff --git a/src/librustc_codegen_ssa/mir/block.rs b/src/librustc_codegen_ssa/mir/block.rs
index dfb1656a6e0..f8c5caa440c 100644
--- a/src/librustc_codegen_ssa/mir/block.rs
+++ b/src/librustc_codegen_ssa/mir/block.rs
@@ -9,6 +9,7 @@ use crate::meth;
 use crate::traits::*;
 use crate::MemFlags;
 
+use rustc_ast::ast;
 use rustc_hir::lang_items;
 use rustc_index::vec::Idx;
 use rustc_middle::mir;
@@ -914,6 +915,98 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
             mir::TerminatorKind::FalseEdges { .. } | mir::TerminatorKind::FalseUnwind { .. } => {
                 bug!("borrowck false edges in codegen")
             }
+
+            mir::TerminatorKind::InlineAsm { template, ref operands, options, ref destination } => {
+                let span = terminator.source_info.span;
+
+                let operands: Vec<_> = operands
+                    .iter()
+                    .map(|op| match *op {
+                        mir::InlineAsmOperand::In { reg, ref value } => {
+                            let value = self.codegen_operand(&mut bx, value);
+                            InlineAsmOperandRef::In { reg, value }
+                        }
+                        mir::InlineAsmOperand::Out { reg, late, ref place } => {
+                            let place =
+                                place.map(|place| self.codegen_place(&mut bx, place.as_ref()));
+                            InlineAsmOperandRef::Out { reg, late, place }
+                        }
+                        mir::InlineAsmOperand::InOut { reg, late, ref in_value, ref out_place } => {
+                            let in_value = self.codegen_operand(&mut bx, in_value);
+                            let out_place = out_place
+                                .map(|out_place| self.codegen_place(&mut bx, out_place.as_ref()));
+                            InlineAsmOperandRef::InOut { reg, late, in_value, out_place }
+                        }
+                        mir::InlineAsmOperand::Const { ref value } => {
+                            if let mir::Operand::Constant(constant) = value {
+                                let const_value =
+                                    self.eval_mir_constant(constant).unwrap_or_else(|_| {
+                                        span_bug!(span, "asm const cannot be resolved")
+                                    });
+                                let ty = constant.literal.ty;
+                                let value = const_value
+                                    .try_to_bits_for_ty(bx.tcx(), ty::ParamEnv::reveal_all(), ty)
+                                    .unwrap_or_else(|| {
+                                        span_bug!(span, "asm const has non-scalar value")
+                                    });
+                                let string = match ty.kind {
+                                    ty::Uint(_) => value.to_string(),
+                                    ty::Int(int_ty) => {
+                                        match int_ty.normalize(bx.tcx().sess.target.ptr_width) {
+                                            ast::IntTy::I8 => (value as i8).to_string(),
+                                            ast::IntTy::I16 => (value as i16).to_string(),
+                                            ast::IntTy::I32 => (value as i32).to_string(),
+                                            ast::IntTy::I64 => (value as i64).to_string(),
+                                            ast::IntTy::I128 => (value as i128).to_string(),
+                                            ast::IntTy::Isize => unreachable!(),
+                                        }
+                                    }
+                                    ty::Float(ast::FloatTy::F32) => {
+                                        f32::from_bits(value as u32).to_string()
+                                    }
+                                    ty::Float(ast::FloatTy::F64) => {
+                                        f64::from_bits(value as u64).to_string()
+                                    }
+                                    _ => span_bug!(span, "asm const has bad type {}", ty),
+                                };
+                                InlineAsmOperandRef::Const { string }
+                            } else {
+                                span_bug!(span, "asm const is not a constant");
+                            }
+                        }
+                        mir::InlineAsmOperand::SymFn { ref value } => {
+                            if let ty::FnDef(def_id, substs) = value.literal.ty.kind {
+                                let instance = ty::Instance::resolve(
+                                    bx.tcx(),
+                                    ty::ParamEnv::reveal_all(),
+                                    def_id,
+                                    substs,
+                                )
+                                .unwrap()
+                                .unwrap();
+                                InlineAsmOperandRef::SymFn { instance }
+                            } else {
+                                span_bug!(span, "invalid type for asm sym (fn)");
+                            }
+                        }
+                        mir::InlineAsmOperand::SymStatic { ref value } => {
+                            if let Some(def_id) = value.check_static_ptr(bx.tcx()) {
+                                InlineAsmOperandRef::SymStatic { def_id }
+                            } else {
+                                span_bug!(span, "invalid type for asm sym (static)");
+                            }
+                        }
+                    })
+                    .collect();
+
+                bx.codegen_inline_asm(template, &operands, options, span);
+
+                if let Some(target) = destination {
+                    helper.funclet_br(self, &mut bx, *target);
+                } else {
+                    bx.unreachable();
+                }
+            }
         }
     }
 
diff --git a/src/librustc_codegen_ssa/traits/asm.rs b/src/librustc_codegen_ssa/traits/asm.rs
index 1cdfd3ae356..cb2b3545c4c 100644
--- a/src/librustc_codegen_ssa/traits/asm.rs
+++ b/src/librustc_codegen_ssa/traits/asm.rs
@@ -1,7 +1,39 @@
 use super::BackendTypes;
+use crate::mir::operand::OperandRef;
 use crate::mir::place::PlaceRef;
+use rustc_hir::def_id::DefId;
 use rustc_hir::{GlobalAsm, LlvmInlineAsmInner};
+use rustc_middle::ty::Instance;
 use rustc_span::Span;
+use rustc_target::asm::{InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece};
+
+#[derive(Debug)]
+pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> {
+    In {
+        reg: InlineAsmRegOrRegClass,
+        value: OperandRef<'tcx, B::Value>,
+    },
+    Out {
+        reg: InlineAsmRegOrRegClass,
+        late: bool,
+        place: Option<PlaceRef<'tcx, B::Value>>,
+    },
+    InOut {
+        reg: InlineAsmRegOrRegClass,
+        late: bool,
+        in_value: OperandRef<'tcx, B::Value>,
+        out_place: Option<PlaceRef<'tcx, B::Value>>,
+    },
+    Const {
+        string: String,
+    },
+    SymFn {
+        instance: Instance<'tcx>,
+    },
+    SymStatic {
+        def_id: DefId,
+    },
+}
 
 pub trait AsmBuilderMethods<'tcx>: BackendTypes {
     /// Take an inline assembly expression and splat it out via LLVM
@@ -12,6 +44,15 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
         inputs: Vec<Self::Value>,
         span: Span,
     ) -> bool;
+
+    /// Take an inline assembly expression and splat it out via LLVM
+    fn codegen_inline_asm(
+        &mut self,
+        template: &[InlineAsmTemplatePiece],
+        operands: &[InlineAsmOperandRef<'tcx, Self>],
+        options: InlineAsmOptions,
+        span: Span,
+    );
 }
 
 pub trait AsmMethods {
diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/src/librustc_codegen_ssa/traits/mod.rs
index f4c09a33285..6b782731d53 100644
--- a/src/librustc_codegen_ssa/traits/mod.rs
+++ b/src/librustc_codegen_ssa/traits/mod.rs
@@ -28,7 +28,7 @@ mod type_;
 mod write;
 
 pub use self::abi::AbiBuilderMethods;
-pub use self::asm::{AsmBuilderMethods, AsmMethods};
+pub use self::asm::{AsmBuilderMethods, AsmMethods, InlineAsmOperandRef};
 pub use self::backend::{Backend, BackendTypes, CodegenBackend, ExtraBackendMethods};
 pub use self::builder::{BuilderMethods, OverflowOp};
 pub use self::consts::ConstMethods;