Add asm! to AST

This commit is contained in:
Amanieu d'Antras 2020-01-22 14:20:27 +00:00
parent 989edf6dd9
commit 813a9fc4f1
7 changed files with 214 additions and 1 deletions

View File

@ -3631,6 +3631,7 @@ dependencies = [
"rustc_lexer",
"rustc_macros",
"rustc_span",
"rustc_target",
"scoped-tls",
"serialize",
"smallvec 1.4.0",
@ -3678,6 +3679,7 @@ dependencies = [
"log",
"rustc_ast",
"rustc_span",
"rustc_target",
]
[[package]]

View File

@ -19,3 +19,4 @@ rustc_index = { path = "../librustc_index" }
rustc_lexer = { path = "../librustc_lexer" }
rustc_macros = { path = "../librustc_macros" }
smallvec = { version = "1.0", features = ["union", "may_dangle"] }
rustc_target = { path = "../librustc_target" }

View File

@ -34,6 +34,7 @@ use rustc_serialize::{self, Decoder, Encoder};
use rustc_span::source_map::{respan, Spanned};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::asm::{InlineAsmOptions, InlineAsmTemplatePiece};
use std::convert::TryFrom;
use std::fmt;
@ -1121,7 +1122,7 @@ impl Expr {
ExprKind::Break(..) => ExprPrecedence::Break,
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
ExprKind::InlineAsm(..) | ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
ExprKind::MacCall(..) => ExprPrecedence::Mac,
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
@ -1250,6 +1251,8 @@ pub enum ExprKind {
/// A `return`, with an optional value to be returned.
Ret(Option<P<Expr>>),
/// Output of the `asm!()` macro.
InlineAsm(InlineAsm),
/// Output of the `llvm_asm!()` macro.
LlvmInlineAsm(P<LlvmInlineAsm>),
@ -1864,6 +1867,58 @@ pub enum TraitObjectSyntax {
None,
}
/// Inline assembly operand explicit register or register class.
///
/// E.g., `"eax"` as in `asm!("mov eax, 2", out("eax") result)`.
#[derive(Clone, Copy, RustcEncodable, RustcDecodable, Debug)]
pub enum InlineAsmRegOrRegClass {
Reg(Symbol),
RegClass(Symbol),
}
/// Inline assembly operand.
///
/// E.g., `out("eax") result` as in `asm!("mov eax, 2", out("eax") result)`.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub enum InlineAsmOperand {
In {
reg: InlineAsmRegOrRegClass,
expr: P<Expr>,
},
Out {
reg: InlineAsmRegOrRegClass,
late: bool,
expr: Option<P<Expr>>,
},
InOut {
reg: InlineAsmRegOrRegClass,
late: bool,
expr: P<Expr>,
},
SplitInOut {
reg: InlineAsmRegOrRegClass,
late: bool,
in_expr: P<Expr>,
out_expr: Option<P<Expr>>,
},
Const {
expr: P<Expr>,
},
Sym {
expr: P<Expr>,
},
}
/// Inline assembly.
///
/// E.g., `asm!("NOP");`.
#[derive(Clone, RustcEncodable, RustcDecodable, Debug)]
pub struct InlineAsm {
pub template: Vec<InlineAsmTemplatePiece>,
pub operands: Vec<(InlineAsmOperand, Span)>,
pub options: InlineAsmOptions,
}
/// Inline assembly dialect.
///
/// E.g., `"intel"` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.

View File

@ -1205,6 +1205,27 @@ pub fn noop_visit_expr<T: MutVisitor>(Expr { kind, id, span, attrs }: &mut Expr,
ExprKind::Ret(expr) => {
visit_opt(expr, |expr| vis.visit_expr(expr));
}
ExprKind::InlineAsm(asm) => {
for (op, _) in &mut asm.operands {
match op {
InlineAsmOperand::In { expr, .. }
| InlineAsmOperand::InOut { expr, .. }
| InlineAsmOperand::Const { expr, .. }
| InlineAsmOperand::Sym { expr, .. } => vis.visit_expr(expr),
InlineAsmOperand::Out { expr, .. } => {
if let Some(expr) = expr {
vis.visit_expr(expr);
}
}
InlineAsmOperand::SplitInOut { in_expr, out_expr, .. } => {
vis.visit_expr(in_expr);
if let Some(out_expr) = out_expr {
vis.visit_expr(out_expr);
}
}
}
}
}
ExprKind::LlvmInlineAsm(asm) => {
let LlvmInlineAsm {
asm: _,

View File

@ -818,6 +818,27 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
}
ExprKind::MacCall(ref mac) => visitor.visit_mac(mac),
ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
ExprKind::InlineAsm(ref ia) => {
for (op, _) in &ia.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 ia) => {
for &(_, ref input) in &ia.inputs {
visitor.visit_expr(input)

View File

@ -13,3 +13,4 @@ doctest = false
log = "0.4"
rustc_span = { path = "../librustc_span" }
rustc_ast = { path = "../librustc_ast" }
rustc_target = { path = "../librustc_target" }

View File

@ -4,6 +4,7 @@ use crate::pp::{self, Breaks};
use rustc_ast::ast::{self, BlockCheckMode, PatKind, RangeEnd, RangeSyntax};
use rustc_ast::ast::{Attribute, GenericArg, MacArgs};
use rustc_ast::ast::{GenericBound, SelfKind, TraitBoundModifier};
use rustc_ast::ast::{InlineAsmOperand, InlineAsmRegOrRegClass};
use rustc_ast::attr;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, BinOpToken, DelimToken, Nonterminal, Token, TokenKind};
@ -14,6 +15,7 @@ use rustc_span::edition::Edition;
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::symbol::{kw, sym, Ident, IdentPrinter, Symbol};
use rustc_span::{BytePos, FileName, Span};
use rustc_target::asm::{InlineAsmOptions, InlineAsmTemplatePiece};
use std::borrow::Cow;
@ -2014,6 +2016,116 @@ impl<'a> State<'a> {
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
}
}
ast::ExprKind::InlineAsm(ref a) => {
enum AsmArg<'a> {
Template(String),
Operand(&'a InlineAsmOperand),
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) => {
let print_reg_or_class = |s: &mut Self, r: &InlineAsmRegOrRegClass| match r
{
InlineAsmRegOrRegClass::Reg(r) => {
s.print_string(&r.as_str(), ast::StrStyle::Cooked)
}
InlineAsmRegOrRegClass::RegClass(r) => s.word(r.to_string()),
};
match op {
InlineAsmOperand::In { reg, expr } => {
s.word("in");
s.popen();
print_reg_or_class(s, reg);
s.pclose();
s.space();
s.print_expr(expr);
}
InlineAsmOperand::Out { reg, late, expr } => {
s.word(if *late { "lateout" } else { "out" });
s.popen();
print_reg_or_class(s, reg);
s.pclose();
s.space();
match expr {
Some(expr) => s.print_expr(expr),
None => s.word("_"),
}
}
InlineAsmOperand::InOut { reg, late, expr } => {
s.word(if *late { "inlateout" } else { "inout" });
s.popen();
print_reg_or_class(s, reg);
s.pclose();
s.space();
s.print_expr(expr);
}
InlineAsmOperand::SplitInOut { reg, late, in_expr, out_expr } => {
s.word(if *late { "inlateout" } else { "inout" });
s.popen();
print_reg_or_class(s, 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("_"),
}
}
InlineAsmOperand::Const { expr } => {
s.word("const");
s.space();
s.print_expr(expr);
}
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();
}
ast::ExprKind::LlvmInlineAsm(ref a) => {
self.s.word("llvm_asm!");
self.popen();