1 // Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 * Inline assembly support.
22 use parse::token::{intern, InternedString};
25 use syntax::ast::AsmDialect;
37 fn next(&self) -> State {
44 StateNone => StateNone
49 const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
51 pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
52 -> Box<base::MacResult+'cx> {
53 if !cx.ecfg.enable_asm() {
54 feature_gate::emit_feature_err(
55 &cx.parse_sess.span_diagnostic, "asm", sp,
56 feature_gate::GateIssue::Language,
57 feature_gate::EXPLAIN_ASM);
58 return DummyResult::expr(sp);
61 let mut p = cx.new_parser_from_tts(tts);
62 let mut asm = InternedString::new("");
63 let mut asm_str_style = None;
64 let mut outputs = Vec::new();
65 let mut inputs = Vec::new();
66 let mut clobs = Vec::new();
67 let mut volatile = false;
68 let mut alignstack = false;
69 let mut dialect = AsmDialect::Att;
76 if asm_str_style.is_some() {
77 // If we already have a string with instructions,
78 // ending up in Asm state again is an error.
79 cx.span_err(sp, "malformed inline assembly");
80 return DummyResult::expr(sp);
82 let (s, style) = match expr_to_string(cx, p.parse_expr(),
83 "inline assembly must be a string literal") {
84 Some((s, st)) => (s, st),
85 // let compilation continue
86 None => return DummyResult::expr(sp),
89 asm_str_style = Some(style);
92 while p.token != token::Eof &&
93 p.token != token::Colon &&
94 p.token != token::ModSep {
96 if !outputs.is_empty() {
97 panictry!(p.eat(&token::Comma));
100 let (constraint, _str_style) = panictry!(p.parse_str());
102 let span = p.last_span;
104 panictry!(p.expect(&token::OpenDelim(token::Paren)));
105 let out = p.parse_expr();
106 panictry!(p.expect(&token::CloseDelim(token::Paren)));
108 // Expands a read+write operand into two operands.
110 // Use '+' modifier when you want the same expression
111 // to be both an input and an output at the same time.
112 // It's the opposite of '=&' which means that the memory
113 // cannot be shared with any other operand (usually when
114 // a register is clobbered early.)
115 let output = match constraint.slice_shift_char() {
116 Some(('=', _)) => None,
117 Some(('+', operand)) => {
118 Some(token::intern_and_get_ident(&format!(
122 cx.span_err(span, "output operand constraint lacks '=' or '+'");
127 let is_rw = output.is_some();
128 outputs.push((output.unwrap_or(constraint), out, is_rw));
132 while p.token != token::Eof &&
133 p.token != token::Colon &&
134 p.token != token::ModSep {
136 if !inputs.is_empty() {
137 panictry!(p.eat(&token::Comma));
140 let (constraint, _str_style) = panictry!(p.parse_str());
142 if constraint.starts_with("=") {
143 cx.span_err(p.last_span, "input operand constraint contains '='");
144 } else if constraint.starts_with("+") {
145 cx.span_err(p.last_span, "input operand constraint contains '+'");
148 panictry!(p.expect(&token::OpenDelim(token::Paren)));
149 let input = p.parse_expr();
150 panictry!(p.expect(&token::CloseDelim(token::Paren)));
152 inputs.push((constraint, input));
156 while p.token != token::Eof &&
157 p.token != token::Colon &&
158 p.token != token::ModSep {
160 if !clobs.is_empty() {
161 panictry!(p.eat(&token::Comma));
164 let (s, _str_style) = panictry!(p.parse_str());
166 if OPTIONS.iter().any(|&opt| s == opt) {
167 cx.span_warn(p.last_span, "expected a clobber, found an option");
173 let (option, _str_style) = panictry!(p.parse_str());
175 if option == "volatile" {
176 // Indicates that the inline assembly has side effects
177 // and must not be optimized out along with its outputs.
179 } else if option == "alignstack" {
181 } else if option == "intel" {
182 dialect = AsmDialect::Intel;
184 cx.span_warn(p.last_span, "unrecognized option");
187 if p.token == token::Comma {
188 panictry!(p.eat(&token::Comma));
195 // MOD_SEP is a double colon '::' without space in between.
196 // When encountered, the state must be advanced twice.
197 match (&p.token, state.next(), state.next().next()) {
198 (&token::Colon, StateNone, _) |
199 (&token::ModSep, _, StateNone) => {
203 (&token::Colon, st, _) |
204 (&token::ModSep, _, st) => {
208 (&token::Eof, _, _) => break 'statement,
214 let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
216 callee: codemap::NameAndSpan {
217 format: codemap::MacroBang(intern("asm")),
219 allow_internal_unstable: false,
223 MacEager::expr(P(ast::Expr {
224 id: ast::DUMMY_NODE_ID,
225 node: ast::ExprInlineAsm(ast::InlineAsm {
226 asm: token::intern_and_get_ident(&asm),
227 asm_str_style: asm_str_style.unwrap(),
232 alignstack: alignstack,