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.
21 use parse::token::InternedString;
35 fn next(&self) -> State {
42 StateNone => StateNone
47 static OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
49 pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
50 -> Box<base::MacResult+'cx> {
51 let mut p = cx.new_parser_from_tts(tts);
52 let mut asm = InternedString::new("");
53 let mut asm_str_style = None;
54 let mut outputs = Vec::new();
55 let mut inputs = Vec::new();
56 let mut clobs = Vec::new();
57 let mut volatile = false;
58 let mut alignstack = false;
59 let mut dialect = ast::AsmAtt;
66 if asm_str_style.is_some() {
67 // If we already have a string with instructions,
68 // ending up in Asm state again is an error.
69 cx.span_err(sp, "malformed inline assembly");
70 return DummyResult::expr(sp);
72 let (s, style) = match expr_to_string(cx, p.parse_expr(),
73 "inline assembly must be a string literal") {
74 Some((s, st)) => (s, st),
75 // let compilation continue
76 None => return DummyResult::expr(sp),
79 asm_str_style = Some(style);
82 while p.token != token::Eof &&
83 p.token != token::Colon &&
84 p.token != token::ModSep {
86 if outputs.len() != 0 {
90 let (constraint, _str_style) = p.parse_str();
92 let span = p.last_span;
94 p.expect(&token::OpenDelim(token::Paren));
95 let out = p.parse_expr();
96 p.expect(&token::CloseDelim(token::Paren));
98 // Expands a read+write operand into two operands.
100 // Use '+' modifier when you want the same expression
101 // to be both an input and an output at the same time.
102 // It's the opposite of '=&' which means that the memory
103 // cannot be shared with any other operand (usually when
104 // a register is clobbered early.)
105 let output = match constraint.get().slice_shift_char() {
106 Some(('=', _)) => None,
107 Some(('+', operand)) => {
108 Some(token::intern_and_get_ident(&format!(
112 cx.span_err(span, "output operand constraint lacks '=' or '+'");
117 let is_rw = output.is_some();
118 outputs.push((output.unwrap_or(constraint), out, is_rw));
122 while p.token != token::Eof &&
123 p.token != token::Colon &&
124 p.token != token::ModSep {
126 if inputs.len() != 0 {
127 p.eat(&token::Comma);
130 let (constraint, _str_style) = p.parse_str();
132 if constraint.get().starts_with("=") {
133 cx.span_err(p.last_span, "input operand constraint contains '='");
134 } else if constraint.get().starts_with("+") {
135 cx.span_err(p.last_span, "input operand constraint contains '+'");
138 p.expect(&token::OpenDelim(token::Paren));
139 let input = p.parse_expr();
140 p.expect(&token::CloseDelim(token::Paren));
142 inputs.push((constraint, input));
146 while p.token != token::Eof &&
147 p.token != token::Colon &&
148 p.token != token::ModSep {
150 if clobs.len() != 0 {
151 p.eat(&token::Comma);
154 let (s, _str_style) = p.parse_str();
156 if OPTIONS.iter().any(|&opt| s == opt) {
157 cx.span_warn(p.last_span, "expected a clobber, found an option");
163 let (option, _str_style) = p.parse_str();
165 if option == "volatile" {
166 // Indicates that the inline assembly has side effects
167 // and must not be optimized out along with its outputs.
169 } else if option == "alignstack" {
171 } else if option == "intel" {
172 dialect = ast::AsmIntel;
174 cx.span_warn(p.last_span, "unrecognized option");
177 if p.token == token::Comma {
178 p.eat(&token::Comma);
185 // MOD_SEP is a double colon '::' without space in between.
186 // When encountered, the state must be advanced twice.
187 match (&p.token, state.next(), state.next().next()) {
188 (&token::Colon, StateNone, _) |
189 (&token::ModSep, _, StateNone) => {
193 (&token::Colon, st, _) |
194 (&token::ModSep, _, st) => {
198 (&token::Eof, _, _) => break 'statement,
204 let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
206 callee: codemap::NameAndSpan {
207 name: "asm".to_string(),
208 format: codemap::MacroBang,
213 MacExpr::new(P(ast::Expr {
214 id: ast::DUMMY_NODE_ID,
215 node: ast::ExprInlineAsm(ast::InlineAsm {
216 asm: token::intern_and_get_ident(asm.get()),
217 asm_str_style: asm_str_style.unwrap(),
222 alignstack: alignstack,