]>
git.proxmox.com Git - rustc.git/blob - src/libsyntax_ext/asm.rs
e4d0cb74046037a9407e421640445adaaacb8d16
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.
11 // Inline assembly support.
17 use syntax
::ext
::base
;
18 use syntax
::ext
::base
::*;
19 use syntax
::feature_gate
;
20 use syntax
::parse
::token
::intern
;
21 use syntax
::parse
::{self, token}
;
23 use syntax
::ast
::AsmDialect
;
25 use syntax
::tokenstream
;
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
,
53 tts
: &[tokenstream
::TokenTree
])
54 -> Box
<base
::MacResult
+ 'cx
> {
55 if !cx
.ecfg
.enable_asm() {
56 feature_gate
::emit_feature_err(&cx
.parse_sess
,
59 feature_gate
::GateIssue
::Language
,
60 feature_gate
::EXPLAIN_ASM
);
61 return DummyResult
::expr(sp
);
64 // Split the tts before the first colon, to avoid `asm!("x": y)` being
65 // parsed as `asm!(z)` with `z = "x": y` which is type ascription.
66 let first_colon
= tts
.iter()
69 tokenstream
::TokenTree
::Token(_
, token
::Colon
) |
70 tokenstream
::TokenTree
::Token(_
, token
::ModSep
) => true,
74 .unwrap_or(tts
.len());
75 let mut p
= cx
.new_parser_from_tts(&tts
[first_colon
..]);
76 let mut asm
= token
::InternedString
::new("");
77 let mut asm_str_style
= None
;
78 let mut outputs
= Vec
::new();
79 let mut inputs
= Vec
::new();
80 let mut clobs
= Vec
::new();
81 let mut volatile
= false;
82 let mut alignstack
= false;
83 let mut dialect
= AsmDialect
::Att
;
90 if asm_str_style
.is_some() {
91 // If we already have a string with instructions,
92 // ending up in Asm state again is an error.
93 cx
.span_err(sp
, "malformed inline assembly");
94 return DummyResult
::expr(sp
);
96 // Nested parser, stop before the first colon (see above).
97 let mut p2
= cx
.new_parser_from_tts(&tts
[..first_colon
]);
98 let (s
, style
) = match expr_to_string(cx
,
99 panictry
!(p2
.parse_expr()),
100 "inline assembly must be a string literal") {
101 Some((s
, st
)) => (s
, st
),
102 // let compilation continue
103 None
=> return DummyResult
::expr(sp
),
106 // This is most likely malformed.
107 if p2
.token
!= token
::Eof
{
108 let mut extra_tts
= panictry
!(p2
.parse_all_token_trees());
109 extra_tts
.extend(tts
[first_colon
..].iter().cloned());
110 p
= parse
::tts_to_parser(cx
.parse_sess
, extra_tts
);
114 asm_str_style
= Some(style
);
117 while p
.token
!= token
::Eof
&& p
.token
!= token
::Colon
&& p
.token
!= token
::ModSep
{
119 if !outputs
.is_empty() {
120 p
.eat(&token
::Comma
);
123 let (constraint
, _str_style
) = panictry
!(p
.parse_str());
125 let span
= p
.prev_span
;
127 panictry
!(p
.expect(&token
::OpenDelim(token
::Paren
)));
128 let out
= panictry
!(p
.parse_expr());
129 panictry
!(p
.expect(&token
::CloseDelim(token
::Paren
)));
131 // Expands a read+write operand into two operands.
133 // Use '+' modifier when you want the same expression
134 // to be both an input and an output at the same time.
135 // It's the opposite of '=&' which means that the memory
136 // cannot be shared with any other operand (usually when
137 // a register is clobbered early.)
138 let mut ch
= constraint
.chars();
139 let output
= match ch
.next() {
142 Some(token
::intern_and_get_ident(&format
!("={}", ch
.as_str())))
145 cx
.span_err(span
, "output operand constraint lacks '=' or '+'");
150 let is_rw
= output
.is_some();
151 let is_indirect
= constraint
.contains("*");
152 outputs
.push(ast
::InlineAsmOutput
{
153 constraint
: output
.unwrap_or(constraint
.clone()),
156 is_indirect
: is_indirect
,
161 while p
.token
!= token
::Eof
&& p
.token
!= token
::Colon
&& p
.token
!= token
::ModSep
{
163 if !inputs
.is_empty() {
164 p
.eat(&token
::Comma
);
167 let (constraint
, _str_style
) = panictry
!(p
.parse_str());
169 if constraint
.starts_with("=") {
170 cx
.span_err(p
.prev_span
, "input operand constraint contains '='");
171 } else if constraint
.starts_with("+") {
172 cx
.span_err(p
.prev_span
, "input operand constraint contains '+'");
175 panictry
!(p
.expect(&token
::OpenDelim(token
::Paren
)));
176 let input
= panictry
!(p
.parse_expr());
177 panictry
!(p
.expect(&token
::CloseDelim(token
::Paren
)));
179 inputs
.push((constraint
, input
));
183 while p
.token
!= token
::Eof
&& p
.token
!= token
::Colon
&& p
.token
!= token
::ModSep
{
185 if !clobs
.is_empty() {
186 p
.eat(&token
::Comma
);
189 let (s
, _str_style
) = panictry
!(p
.parse_str());
191 if OPTIONS
.iter().any(|&opt
| s
== opt
) {
192 cx
.span_warn(p
.prev_span
, "expected a clobber, found an option");
193 } else if s
.starts_with("{") || s.ends_with("}") {
194 cx
.span_err(p
.prev_span
, "clobber should not be surrounded by braces");
201 let (option
, _str_style
) = panictry
!(p
.parse_str());
203 if option
== "volatile" {
204 // Indicates that the inline assembly has side effects
205 // and must not be optimized out along with its outputs.
207 } else if option
== "alignstack" {
209 } else if option
== "intel" {
210 dialect
= AsmDialect
::Intel
;
212 cx
.span_warn(p
.prev_span
, "unrecognized option");
215 if p
.token
== token
::Comma
{
216 p
.eat(&token
::Comma
);
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()) {
226 (&token
::Colon
, StateNone
, _
) |
227 (&token
::ModSep
, _
, StateNone
) => {
231 (&token
::Colon
, st
, _
) |
232 (&token
::ModSep
, _
, st
) => {
236 (&token
::Eof
, ..) => break 'statement
,
242 let expn_id
= cx
.codemap().record_expansion(codemap
::ExpnInfo
{
244 callee
: codemap
::NameAndSpan
{
245 format
: codemap
::MacroBang(intern("asm")),
247 allow_internal_unstable
: false,
251 MacEager
::expr(P(ast
::Expr
{
252 id
: ast
::DUMMY_NODE_ID
,
253 node
: ast
::ExprKind
::InlineAsm(P(ast
::InlineAsm
{
254 asm
: token
::intern_and_get_ident(&asm
),
255 asm_str_style
: asm_str_style
.unwrap(),
260 alignstack
: alignstack
,
265 attrs
: ast
::ThinVec
::new(),