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};
36 fn next(&self) -> State {
43 StateNone => StateNone
48 const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
50 pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
51 -> Box<base::MacResult+'cx> {
52 if !cx.ecfg.enable_asm() {
53 feature_gate::emit_feature_err(
54 &cx.parse_sess.span_diagnostic, "asm", sp,
55 feature_gate::GateIssue::Language,
56 feature_gate::EXPLAIN_ASM);
57 return DummyResult::expr(sp);
60 let mut p = cx.new_parser_from_tts(tts);
61 let mut asm = InternedString::new("");
62 let mut asm_str_style = None;
63 let mut outputs = Vec::new();
64 let mut inputs = Vec::new();
65 let mut clobs = Vec::new();
66 let mut volatile = false;
67 let mut alignstack = false;
68 let mut dialect = ast::AsmAtt;
75 if asm_str_style.is_some() {
76 // If we already have a string with instructions,
77 // ending up in Asm state again is an error.
78 cx.span_err(sp, "malformed inline assembly");
79 return DummyResult::expr(sp);
81 let (s, style) = match expr_to_string(cx, p.parse_expr(),
82 "inline assembly must be a string literal") {
83 Some((s, st)) => (s, st),
84 // let compilation continue
85 None => return DummyResult::expr(sp),
88 asm_str_style = Some(style);
91 while p.token != token::Eof &&
92 p.token != token::Colon &&
93 p.token != token::ModSep {
95 if !outputs.is_empty() {
96 panictry!(p.eat(&token::Comma));
99 let (constraint, _str_style) = panictry!(p.parse_str());
101 let span = p.last_span;
103 panictry!(p.expect(&token::OpenDelim(token::Paren)));
104 let out = p.parse_expr();
105 panictry!(p.expect(&token::CloseDelim(token::Paren)));
107 // Expands a read+write operand into two operands.
109 // Use '+' modifier when you want the same expression
110 // to be both an input and an output at the same time.
111 // It's the opposite of '=&' which means that the memory
112 // cannot be shared with any other operand (usually when
113 // a register is clobbered early.)
114 let output = match constraint.slice_shift_char() {
115 Some(('=', _)) => None,
116 Some(('+', operand)) => {
117 Some(token::intern_and_get_ident(&format!(
121 cx.span_err(span, "output operand constraint lacks '=' or '+'");
126 let is_rw = output.is_some();
127 outputs.push((output.unwrap_or(constraint), out, is_rw));
131 while p.token != token::Eof &&
132 p.token != token::Colon &&
133 p.token != token::ModSep {
135 if !inputs.is_empty() {
136 panictry!(p.eat(&token::Comma));
139 let (constraint, _str_style) = panictry!(p.parse_str());
141 if constraint.starts_with("=") {
142 cx.span_err(p.last_span, "input operand constraint contains '='");
143 } else if constraint.starts_with("+") {
144 cx.span_err(p.last_span, "input operand constraint contains '+'");
147 panictry!(p.expect(&token::OpenDelim(token::Paren)));
148 let input = p.parse_expr();
149 panictry!(p.expect(&token::CloseDelim(token::Paren)));
151 inputs.push((constraint, input));
155 while p.token != token::Eof &&
156 p.token != token::Colon &&
157 p.token != token::ModSep {
159 if !clobs.is_empty() {
160 panictry!(p.eat(&token::Comma));
163 let (s, _str_style) = panictry!(p.parse_str());
165 if OPTIONS.iter().any(|&opt| s == opt) {
166 cx.span_warn(p.last_span, "expected a clobber, found an option");
172 let (option, _str_style) = panictry!(p.parse_str());
174 if option == "volatile" {
175 // Indicates that the inline assembly has side effects
176 // and must not be optimized out along with its outputs.
178 } else if option == "alignstack" {
180 } else if option == "intel" {
181 dialect = ast::AsmIntel;
183 cx.span_warn(p.last_span, "unrecognized option");
186 if p.token == token::Comma {
187 panictry!(p.eat(&token::Comma));
194 // MOD_SEP is a double colon '::' without space in between.
195 // When encountered, the state must be advanced twice.
196 match (&p.token, state.next(), state.next().next()) {
197 (&token::Colon, StateNone, _) |
198 (&token::ModSep, _, StateNone) => {
202 (&token::Colon, st, _) |
203 (&token::ModSep, _, st) => {
207 (&token::Eof, _, _) => break 'statement,
213 let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
215 callee: codemap::NameAndSpan {
216 format: codemap::MacroBang(intern("asm")),
218 allow_internal_unstable: false,
222 MacEager::expr(P(ast::Expr {
223 id: ast::DUMMY_NODE_ID,
224 node: ast::ExprInlineAsm(ast::InlineAsm {
225 asm: token::intern_and_get_ident(&asm),
226 asm_str_style: asm_str_style.unwrap(),
231 alignstack: alignstack,