diff --git a/src/librustc_hir/hir.rs b/src/librustc_hir/hir.rs index eafff6705ba..19cea3a3466 100644 --- a/src/librustc_hir/hir.rs +++ b/src/librustc_hir/hir.rs @@ -15,6 +15,7 @@ use rustc_macros::HashStable_Generic; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{MultiSpan, Span, DUMMY_SP}; +use rustc_target::asm::{InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece}; use rustc_target::spec::abi::Abi; use smallvec::SmallVec; @@ -1391,6 +1392,7 @@ impl Expr<'_> { ExprKind::Break(..) => ExprPrecedence::Break, ExprKind::Continue(..) => ExprPrecedence::Continue, ExprKind::Ret(..) => ExprPrecedence::Ret, + ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm, ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm, ExprKind::Struct(..) => ExprPrecedence::Struct, ExprKind::Repeat(..) => ExprPrecedence::Repeat, @@ -1446,6 +1448,7 @@ impl Expr<'_> { | ExprKind::Ret(..) | ExprKind::Loop(..) | ExprKind::Assign(..) + | ExprKind::InlineAsm(..) | ExprKind::LlvmInlineAsm(..) | ExprKind::AssignOp(..) | ExprKind::Lit(_) @@ -1622,6 +1625,8 @@ pub enum ExprKind<'hir> { /// A `return`, with an optional value to be returned. Ret(Option<&'hir Expr<'hir>>), + /// Inline assembly (from `asm!`), with its outputs and inputs. + InlineAsm(&'hir InlineAsm<'hir>), /// Inline assembly (from `llvm_asm!`), with its outputs and inputs. LlvmInlineAsm(&'hir LlvmInlineAsm<'hir>), @@ -2054,6 +2059,55 @@ pub enum TyKind<'hir> { Err, } +#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +pub enum InlineAsmOperand<'hir> { + In { + reg: InlineAsmRegOrRegClass, + expr: Expr<'hir>, + }, + Out { + reg: InlineAsmRegOrRegClass, + late: bool, + expr: Option>, + }, + InOut { + reg: InlineAsmRegOrRegClass, + late: bool, + expr: Expr<'hir>, + }, + SplitInOut { + reg: InlineAsmRegOrRegClass, + late: bool, + in_expr: Expr<'hir>, + out_expr: Option>, + }, + Const { + expr: Expr<'hir>, + }, + Sym { + expr: Expr<'hir>, + }, +} + +impl<'hir> InlineAsmOperand<'hir> { + pub fn reg(&self) -> Option { + match *self { + Self::In { reg, .. } + | Self::Out { reg, .. } + | Self::InOut { reg, .. } + | Self::SplitInOut { reg, .. } => Some(reg), + Self::Const { .. } | Self::Sym { .. } => None, + } + } +} + +#[derive(RustcEncodable, RustcDecodable, Debug, HashStable_Generic)] +pub struct InlineAsm<'hir> { + pub template: &'hir [InlineAsmTemplatePiece], + pub operands: &'hir [InlineAsmOperand<'hir>], + pub options: InlineAsmOptions, +} + #[derive(Copy, Clone, RustcEncodable, RustcDecodable, Debug, HashStable_Generic, PartialEq)] pub struct LlvmInlineAsmOutput { pub constraint: Symbol, diff --git a/src/librustc_hir/intravisit.rs b/src/librustc_hir/intravisit.rs index 0270d0de5c7..97601a3e1ac 100644 --- a/src/librustc_hir/intravisit.rs +++ b/src/librustc_hir/intravisit.rs @@ -1157,6 +1157,27 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>) ExprKind::Ret(ref optional_expression) => { walk_list!(visitor, visit_expr, optional_expression); } + ExprKind::InlineAsm(ref asm) => { + for op in asm.operands { + match op { + InlineAsmOperand::In { expr, .. } + | InlineAsmOperand::InOut { expr, .. } + | InlineAsmOperand::Const { expr, .. } + | InlineAsmOperand::Sym { expr, .. } => visitor.visit_expr(expr), + InlineAsmOperand::Out { expr, .. } => { + if let Some(expr) = expr { + visitor.visit_expr(expr); + } + } + InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => { + visitor.visit_expr(in_expr); + if let Some(out_expr) = out_expr { + visitor.visit_expr(out_expr); + } + } + } + } + } ExprKind::LlvmInlineAsm(ref asm) => { walk_list!(visitor, visit_expr, asm.outputs_exprs); walk_list!(visitor, visit_expr, asm.inputs_exprs); diff --git a/src/librustc_hir_pretty/lib.rs b/src/librustc_hir_pretty/lib.rs index f8a42376d14..918b5901375 100644 --- a/src/librustc_hir_pretty/lib.rs +++ b/src/librustc_hir_pretty/lib.rs @@ -12,6 +12,7 @@ use rustc_hir::{GenericBound, PatKind, RangeEnd, TraitBoundModifier}; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::symbol::{kw, Ident, IdentPrinter, Symbol}; use rustc_span::{self, BytePos, FileName}; +use rustc_target::asm::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_target::spec::abi::Abi; use std::borrow::Cow; @@ -1409,6 +1410,107 @@ impl<'a> State<'a> { self.print_expr_maybe_paren(&expr, parser::PREC_JUMP); } } + hir::ExprKind::InlineAsm(ref a) => { + enum AsmArg<'a> { + Template(String), + Operand(&'a hir::InlineAsmOperand<'a>), + Options(InlineAsmOptions), + } + + let mut args = vec![]; + args.push(AsmArg::Template(InlineAsmTemplatePiece::to_string(&a.template))); + args.extend(a.operands.iter().map(|o| AsmArg::Operand(o))); + if !a.options.is_empty() { + args.push(AsmArg::Options(a.options)); + } + + self.word("asm!"); + self.popen(); + self.commasep(Consistent, &args, |s, arg| match arg { + AsmArg::Template(template) => s.print_string(&template, ast::StrStyle::Cooked), + AsmArg::Operand(op) => match op { + hir::InlineAsmOperand::In { reg, expr } => { + s.word("in"); + s.popen(); + s.word(format!("{}", reg)); + s.pclose(); + s.space(); + s.print_expr(expr); + } + hir::InlineAsmOperand::Out { reg, late, expr } => { + s.word(if *late { "lateout" } else { "out" }); + s.popen(); + s.word(format!("{}", reg)); + s.pclose(); + s.space(); + match expr { + Some(expr) => s.print_expr(expr), + None => s.word("_"), + } + } + hir::InlineAsmOperand::InOut { reg, late, expr } => { + s.word(if *late { "inlateout" } else { "inout" }); + s.popen(); + s.word(format!("{}", reg)); + s.pclose(); + s.space(); + s.print_expr(expr); + } + hir::InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => { + s.word(if *late { "inlateout" } else { "inout" }); + s.popen(); + s.word(format!("{}", reg)); + s.pclose(); + s.space(); + s.print_expr(in_expr); + s.space(); + s.word_space("=>"); + match out_expr { + Some(out_expr) => s.print_expr(out_expr), + None => s.word("_"), + } + } + hir::InlineAsmOperand::Const { expr } => { + s.word("const"); + s.space(); + s.print_expr(expr); + } + hir::InlineAsmOperand::Sym { expr } => { + s.word("sym"); + s.space(); + s.print_expr(expr); + } + }, + AsmArg::Options(opts) => { + s.word("options"); + s.popen(); + let mut options = vec![]; + if opts.contains(InlineAsmOptions::PURE) { + options.push("pure"); + } + if opts.contains(InlineAsmOptions::NOMEM) { + options.push("nomem"); + } + if opts.contains(InlineAsmOptions::READONLY) { + options.push("readonly"); + } + if opts.contains(InlineAsmOptions::PRESERVES_FLAGS) { + options.push("preserves_flags"); + } + if opts.contains(InlineAsmOptions::NORETURN) { + options.push("noreturn"); + } + if opts.contains(InlineAsmOptions::NOSTACK) { + options.push("nostack"); + } + s.commasep(Inconsistent, &options, |s, &opt| { + s.word(opt); + }); + s.pclose(); + } + }); + self.pclose(); + } hir::ExprKind::LlvmInlineAsm(ref a) => { let i = &a.inner; self.s.word("llvm_asm!");