Add asm! to AST
This commit is contained in:
parent
989edf6dd9
commit
813a9fc4f1
7 changed files with 214 additions and 1 deletions
|
@ -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]]
|
||||
|
|
|
@ -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" }
|
||||
|
|
|
@ -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")`.
|
||||
|
|
|
@ -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: _,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -13,3 +13,4 @@ doctest = false
|
|||
log = "0.4"
|
||||
rustc_span = { path = "../librustc_span" }
|
||||
rustc_ast = { path = "../librustc_ast" }
|
||||
rustc_target = { path = "../librustc_target" }
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue