]>
git.proxmox.com Git - rustc.git/blob - src/libsyntax_ext/asm.rs
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.
18 use syntax
::codemap
::Span
;
19 use syntax
::ext
::base
;
20 use syntax
::ext
::base
::*;
21 use syntax
::feature_gate
;
22 use syntax
::parse
::token
::intern
;
23 use syntax
::parse
::{self, token}
;
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 // 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
| {
65 ast
::TokenTree
::Token(_
, token
::Colon
) |
66 ast
::TokenTree
::Token(_
, token
::ModSep
) => true,
69 }).unwrap_or(tts
.len());
70 let mut p
= cx
.new_parser_from_tts(&tts
[first_colon
..]);
71 let mut asm
= token
::InternedString
::new("");
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();
76 let mut volatile
= false;
77 let mut alignstack
= false;
78 let mut dialect
= AsmDialect
::Att
;
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
);
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()),
94 "inline assembly must be a string literal") {
95 Some((s
, st
)) => (s
, st
),
96 // let compilation continue
97 None
=> return DummyResult
::expr(sp
),
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());
108 asm_str_style
= Some(style
);
111 while p
.token
!= token
::Eof
&&
112 p
.token
!= token
::Colon
&&
113 p
.token
!= token
::ModSep
{
115 if !outputs
.is_empty() {
116 p
.eat(&token
::Comma
);
119 let (constraint
, _str_style
) = panictry
!(p
.parse_str());
121 let span
= p
.last_span
;
123 panictry
!(p
.expect(&token
::OpenDelim(token
::Paren
)));
124 let out
= panictry
!(p
.parse_expr());
125 panictry
!(p
.expect(&token
::CloseDelim(token
::Paren
)));
127 // Expands a read+write operand into two operands.
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.)
134 let mut ch
= constraint
.chars();
135 let output
= match ch
.next() {
138 Some(token
::intern_and_get_ident(&format
!(
139 "={}", ch
.as_str())))
142 cx
.span_err(span
, "output operand constraint lacks '=' or '+'");
147 let is_rw
= output
.is_some();
148 let is_indirect
= constraint
.contains("*");
149 outputs
.push(ast
::InlineAsmOutput
{
150 constraint
: output
.unwrap_or(constraint
.clone()),
153 is_indirect
: is_indirect
,
158 while p
.token
!= token
::Eof
&&
159 p
.token
!= token
::Colon
&&
160 p
.token
!= token
::ModSep
{
162 if !inputs
.is_empty() {
163 p
.eat(&token
::Comma
);
166 let (constraint
, _str_style
) = panictry
!(p
.parse_str());
168 if constraint
.starts_with("=") {
169 cx
.span_err(p
.last_span
, "input operand constraint contains '='");
170 } else if constraint
.starts_with("+") {
171 cx
.span_err(p
.last_span
, "input operand constraint contains '+'");
174 panictry
!(p
.expect(&token
::OpenDelim(token
::Paren
)));
175 let input
= panictry
!(p
.parse_expr());
176 panictry
!(p
.expect(&token
::CloseDelim(token
::Paren
)));
178 inputs
.push((constraint
, input
));
182 while p
.token
!= token
::Eof
&&
183 p
.token
!= token
::Colon
&&
184 p
.token
!= token
::ModSep
{
186 if !clobs
.is_empty() {
187 p
.eat(&token
::Comma
);
190 let (s
, _str_style
) = panictry
!(p
.parse_str());
192 if OPTIONS
.iter().any(|&opt
| s
== opt
) {
193 cx
.span_warn(p
.last_span
, "expected a clobber, found an option");
199 let (option
, _str_style
) = panictry
!(p
.parse_str());
201 if option
== "volatile" {
202 // Indicates that the inline assembly has side effects
203 // and must not be optimized out along with its outputs.
205 } else if option
== "alignstack" {
207 } else if option
== "intel" {
208 dialect
= AsmDialect
::Intel
;
210 cx
.span_warn(p
.last_span
, "unrecognized option");
213 if p
.token
== token
::Comma
{
214 p
.eat(&token
::Comma
);
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
) => {
229 (&token
::Colon
, st
, _
) |
230 (&token
::ModSep
, _
, st
) => {
234 (&token
::Eof
, _
, _
) => break 'statement
,
240 let expn_id
= cx
.codemap().record_expansion(codemap
::ExpnInfo
{
242 callee
: codemap
::NameAndSpan
{
243 format
: codemap
::MacroBang(intern("asm")),
245 allow_internal_unstable
: false,
249 MacEager
::expr(P(ast
::Expr
{
250 id
: ast
::DUMMY_NODE_ID
,
251 node
: ast
::ExprKind
::InlineAsm(ast
::InlineAsm
{
252 asm
: token
::intern_and_get_ident(&asm
),
253 asm_str_style
: asm_str_style
.unwrap(),
258 alignstack
: alignstack
,