diff options
| author | Amanieu d'Antras <amanieu@gmail.com> | 2020-02-17 21:36:01 +0000 |
|---|---|---|
| committer | Amanieu d'Antras <amanieu@gmail.com> | 2020-05-18 14:41:32 +0100 |
| commit | abed45ff9fa3e68f2a32ca12e012f95b9153f4df (patch) | |
| tree | 1e40b0230c7ede2ccb29e1ffd42142d6c076a054 /src/librustc_codegen_ssa | |
| parent | 342a64caef773f142c347441877d0be064d5cdc7 (diff) | |
| download | rust-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.rs | 3 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/mir/block.rs | 93 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/traits/asm.rs | 41 | ||||
| -rw-r--r-- | src/librustc_codegen_ssa/traits/mod.rs | 2 |
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; |
