]> git.proxmox.com Git - rustc.git/blame - src/libsyntax_ext/asm.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / libsyntax_ext / asm.rs
CommitLineData
1a4d82fc 1// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
223e47cc
LB
2// file at the top-level directory of this distribution and at
3// http://rust-lang.org/COPYRIGHT.
4//
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.
10
223e47cc
LB
11/*
12 * Inline assembly support.
13 */
1a4d82fc 14use self::State::*;
223e47cc 15
9cc50fc6
SL
16use syntax::ast;
17use syntax::codemap;
18use syntax::codemap::Span;
19use syntax::ext::base;
20use syntax::ext::base::*;
21use syntax::feature_gate;
22use syntax::parse::token::intern;
23use syntax::parse::{self, token};
24use syntax::ptr::P;
b039eaaf 25use syntax::ast::AsmDialect;
970d7e83 26
223e47cc
LB
27enum State {
28 Asm,
29 Outputs,
30 Inputs,
31 Clobbers,
1a4d82fc
JJ
32 Options,
33 StateNone
223e47cc
LB
34}
35
1a4d82fc
JJ
36impl State {
37 fn next(&self) -> State {
38 match *self {
39 Asm => Outputs,
40 Outputs => Inputs,
41 Inputs => Clobbers,
42 Clobbers => Options,
43 Options => StateNone,
44 StateNone => StateNone
45 }
223e47cc
LB
46 }
47}
48
c34b1796 49const OPTIONS: &'static [&'static str] = &["volatile", "alignstack", "intel"];
223e47cc 50
1a4d82fc
JJ
51pub fn expand_asm<'cx>(cx: &'cx mut ExtCtxt, sp: Span, tts: &[ast::TokenTree])
52 -> Box<base::MacResult+'cx> {
85aaf69f
SL
53 if !cx.ecfg.enable_asm() {
54 feature_gate::emit_feature_err(
e9174d1e
SL
55 &cx.parse_sess.span_diagnostic, "asm", sp,
56 feature_gate::GateIssue::Language,
57 feature_gate::EXPLAIN_ASM);
85aaf69f
SL
58 return DummyResult::expr(sp);
59 }
60
9cc50fc6
SL
61 // Split the tts before the first colon, to avoid `asm!("x": y)` being
62 // parsed as `asm!(z)` with `z = "x": y` which is type ascription.
63 let first_colon = tts.iter().position(|tt| {
64 match *tt {
65 ast::TokenTree::Token(_, token::Colon) |
66 ast::TokenTree::Token(_, token::ModSep) => true,
67 _ => false
68 }
69 }).unwrap_or(tts.len());
70 let mut p = cx.new_parser_from_tts(&tts[first_colon..]);
71 let mut asm = token::InternedString::new("");
1a4d82fc
JJ
72 let mut asm_str_style = None;
73 let mut outputs = Vec::new();
74 let mut inputs = Vec::new();
75 let mut clobs = Vec::new();
223e47cc
LB
76 let mut volatile = false;
77 let mut alignstack = false;
b039eaaf 78 let mut dialect = AsmDialect::Att;
223e47cc
LB
79
80 let mut state = Asm;
970d7e83 81
1a4d82fc 82 'statement: loop {
223e47cc
LB
83 match state {
84 Asm => {
85aaf69f
SL
85 if asm_str_style.is_some() {
86 // If we already have a string with instructions,
87 // ending up in Asm state again is an error.
88 cx.span_err(sp, "malformed inline assembly");
89 return DummyResult::expr(sp);
90 }
9cc50fc6
SL
91 // Nested parser, stop before the first colon (see above).
92 let mut p2 = cx.new_parser_from_tts(&tts[..first_colon]);
93 let (s, style) = match expr_to_string(cx, panictry!(p2.parse_expr()),
1a4d82fc
JJ
94 "inline assembly must be a string literal") {
95 Some((s, st)) => (s, st),
96 // let compilation continue
97 None => return DummyResult::expr(sp),
98 };
9cc50fc6
SL
99
100 // This is most likely malformed.
101 if p2.token != token::Eof {
102 let mut extra_tts = panictry!(p2.parse_all_token_trees());
103 extra_tts.extend(tts[first_colon..].iter().cloned());
104 p = parse::tts_to_parser(cx.parse_sess, extra_tts, cx.cfg());
105 }
106
1a4d82fc
JJ
107 asm = s;
108 asm_str_style = Some(style);
223e47cc
LB
109 }
110 Outputs => {
1a4d82fc
JJ
111 while p.token != token::Eof &&
112 p.token != token::Colon &&
113 p.token != token::ModSep {
223e47cc 114
9346a6ac 115 if !outputs.is_empty() {
9cc50fc6 116 p.eat(&token::Comma);
223e47cc
LB
117 }
118
9346a6ac 119 let (constraint, _str_style) = panictry!(p.parse_str());
1a4d82fc
JJ
120
121 let span = p.last_span;
223e47cc 122
9346a6ac 123 panictry!(p.expect(&token::OpenDelim(token::Paren)));
92a42be0 124 let out = panictry!(p.parse_expr());
9346a6ac 125 panictry!(p.expect(&token::CloseDelim(token::Paren)));
1a4d82fc
JJ
126
127 // Expands a read+write operand into two operands.
128 //
129 // Use '+' modifier when you want the same expression
130 // to be both an input and an output at the same time.
131 // It's the opposite of '=&' which means that the memory
132 // cannot be shared with any other operand (usually when
133 // a register is clobbered early.)
54a0048b
SL
134 let mut ch = constraint.chars();
135 let output = match ch.next() {
136 Some('=') => None,
137 Some('+') => {
1a4d82fc 138 Some(token::intern_and_get_ident(&format!(
54a0048b 139 "={}", ch.as_str())))
1a4d82fc
JJ
140 }
141 _ => {
142 cx.span_err(span, "output operand constraint lacks '=' or '+'");
143 None
144 }
223e47cc
LB
145 };
146
1a4d82fc 147 let is_rw = output.is_some();
9cc50fc6
SL
148 let is_indirect = constraint.contains("*");
149 outputs.push(ast::InlineAsmOutput {
54a0048b 150 constraint: output.unwrap_or(constraint.clone()),
9cc50fc6
SL
151 expr: out,
152 is_rw: is_rw,
153 is_indirect: is_indirect,
154 });
223e47cc
LB
155 }
156 }
157 Inputs => {
1a4d82fc
JJ
158 while p.token != token::Eof &&
159 p.token != token::Colon &&
160 p.token != token::ModSep {
223e47cc 161
9346a6ac 162 if !inputs.is_empty() {
9cc50fc6 163 p.eat(&token::Comma);
223e47cc
LB
164 }
165
9346a6ac 166 let (constraint, _str_style) = panictry!(p.parse_str());
1a4d82fc 167
9cc50fc6 168 if constraint.starts_with("=") {
1a4d82fc 169 cx.span_err(p.last_span, "input operand constraint contains '='");
9cc50fc6 170 } else if constraint.starts_with("+") {
1a4d82fc
JJ
171 cx.span_err(p.last_span, "input operand constraint contains '+'");
172 }
223e47cc 173
9346a6ac 174 panictry!(p.expect(&token::OpenDelim(token::Paren)));
92a42be0 175 let input = panictry!(p.parse_expr());
9346a6ac 176 panictry!(p.expect(&token::CloseDelim(token::Paren)));
1a4d82fc
JJ
177
178 inputs.push((constraint, input));
223e47cc
LB
179 }
180 }
181 Clobbers => {
1a4d82fc
JJ
182 while p.token != token::Eof &&
183 p.token != token::Colon &&
184 p.token != token::ModSep {
223e47cc 185
9346a6ac 186 if !clobs.is_empty() {
9cc50fc6 187 p.eat(&token::Comma);
223e47cc
LB
188 }
189
9346a6ac 190 let (s, _str_style) = panictry!(p.parse_str());
223e47cc 191
1a4d82fc
JJ
192 if OPTIONS.iter().any(|&opt| s == opt) {
193 cx.span_warn(p.last_span, "expected a clobber, found an option");
194 }
195 clobs.push(s);
196 }
223e47cc
LB
197 }
198 Options => {
9346a6ac 199 let (option, _str_style) = panictry!(p.parse_str());
223e47cc 200
1a4d82fc
JJ
201 if option == "volatile" {
202 // Indicates that the inline assembly has side effects
203 // and must not be optimized out along with its outputs.
223e47cc 204 volatile = true;
1a4d82fc 205 } else if option == "alignstack" {
223e47cc 206 alignstack = true;
1a4d82fc 207 } else if option == "intel" {
b039eaaf 208 dialect = AsmDialect::Intel;
1a4d82fc
JJ
209 } else {
210 cx.span_warn(p.last_span, "unrecognized option");
223e47cc
LB
211 }
212
1a4d82fc 213 if p.token == token::Comma {
9cc50fc6 214 p.eat(&token::Comma);
223e47cc
LB
215 }
216 }
1a4d82fc 217 StateNone => ()
223e47cc
LB
218 }
219
1a4d82fc
JJ
220 loop {
221 // MOD_SEP is a double colon '::' without space in between.
222 // When encountered, the state must be advanced twice.
223 match (&p.token, state.next(), state.next().next()) {
224 (&token::Colon, StateNone, _) |
225 (&token::ModSep, _, StateNone) => {
9cc50fc6 226 p.bump();
1a4d82fc 227 break 'statement;
223e47cc 228 }
1a4d82fc
JJ
229 (&token::Colon, st, _) |
230 (&token::ModSep, _, st) => {
9cc50fc6 231 p.bump();
1a4d82fc 232 state = st;
223e47cc 233 }
1a4d82fc
JJ
234 (&token::Eof, _, _) => break 'statement,
235 _ => break
236 }
223e47cc
LB
237 }
238 }
239
1a4d82fc
JJ
240 let expn_id = cx.codemap().record_expansion(codemap::ExpnInfo {
241 call_site: sp,
242 callee: codemap::NameAndSpan {
e9174d1e 243 format: codemap::MacroBang(intern("asm")),
1a4d82fc 244 span: None,
c34b1796 245 allow_internal_unstable: false,
1a4d82fc
JJ
246 },
247 });
248
c34b1796 249 MacEager::expr(P(ast::Expr {
1a4d82fc 250 id: ast::DUMMY_NODE_ID,
7453a54e 251 node: ast::ExprKind::InlineAsm(ast::InlineAsm {
85aaf69f 252 asm: token::intern_and_get_ident(&asm),
1a4d82fc 253 asm_str_style: asm_str_style.unwrap(),
223e47cc 254 outputs: outputs,
1a4d82fc
JJ
255 inputs: inputs,
256 clobbers: clobs,
223e47cc
LB
257 volatile: volatile,
258 alignstack: alignstack,
1a4d82fc
JJ
259 dialect: dialect,
260 expn_id: expn_id,
223e47cc 261 }),
92a42be0
SL
262 span: sp,
263 attrs: None,
1a4d82fc 264 }))
223e47cc 265}