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