about summary refs log tree commit diff
path: root/src/librustc_codegen_ssa/mir/block.rs
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/mir/block.rs
parent342a64caef773f142c347441877d0be064d5cdc7 (diff)
downloadrust-abed45ff9fa3e68f2a32ca12e012f95b9153f4df.tar.gz
rust-abed45ff9fa3e68f2a32ca12e012f95b9153f4df.zip
Implement asm! codegen
Diffstat (limited to 'src/librustc_codegen_ssa/mir/block.rs')
-rw-r--r--src/librustc_codegen_ssa/mir/block.rs93
1 files changed, 93 insertions, 0 deletions
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();
+                }
+            }
         }
     }