diff options
| author | Amanieu d'Antras <amanieu@gmail.com> | 2021-07-29 13:43:26 +0200 |
|---|---|---|
| committer | Amanieu d'Antras <amanieu@gmail.com> | 2021-08-12 12:43:11 +0100 |
| commit | 3fd463a5ca98c54b4e79271280c69ce5468e1173 (patch) | |
| tree | a89ee858ba88f4d0866b4e11093fd3dc850dacb5 /compiler/rustc_builtin_macros | |
| parent | 2f4612260d35ef162c088b6b1a87f1e75717acb6 (diff) | |
| download | rust-3fd463a5ca98c54b4e79271280c69ce5468e1173.tar.gz rust-3fd463a5ca98c54b4e79271280c69ce5468e1173.zip | |
Add support for clobber_abi to asm!
Diffstat (limited to 'compiler/rustc_builtin_macros')
| -rw-r--r-- | compiler/rustc_builtin_macros/src/asm.rs | 107 |
1 files changed, 100 insertions, 7 deletions
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index df3aed3bca2..3eaa629448a 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -19,6 +19,7 @@ struct AsmArgs { operands: Vec<(ast::InlineAsmOperand, Span)>, named_args: FxHashMap<Symbol, usize>, reg_args: FxHashSet<usize>, + clobber_abi: Option<(Symbol, Span)>, options: ast::InlineAsmOptions, options_spans: Vec<Span>, } @@ -63,6 +64,7 @@ fn parse_args<'a>( operands: vec![], named_args: FxHashMap::default(), reg_args: FxHashSet::default(), + clobber_abi: None, options: ast::InlineAsmOptions::empty(), options_spans: vec![], }; @@ -85,6 +87,13 @@ fn parse_args<'a>( break; } // accept trailing commas + // Parse clobber_abi + if p.eat_keyword(sym::clobber_abi) { + parse_clobber_abi(&mut p, &mut args)?; + allow_templates = false; + continue; + } + // Parse options if p.eat_keyword(sym::options) { parse_options(&mut p, &mut args, is_global_asm)?; @@ -160,7 +169,11 @@ fn parse_args<'a>( ast::ExprKind::Lit(ast::Lit { kind: ast::LitKind::Str(..), .. }) => {} ast::ExprKind::MacCall(..) => {} _ => { - let errstr = "expected operand, options, or additional template string"; + let errstr = if is_global_asm { + "expected operand, options, or additional template string" + } else { + "expected operand, clobber_abi, options, or additional template string" + }; let mut err = ecx.struct_span_err(template.span, errstr); err.span_label(template.span, errstr); return Err(err); @@ -177,13 +190,19 @@ fn parse_args<'a>( let slot = args.operands.len(); args.operands.push((op, span)); - // Validate the order of named, positional & explicit register operands and options. We do - // this at the end once we have the full span of the argument available. + // Validate the order of named, positional & explicit register operands and + // clobber_abi/options. We do this at the end once we have the full span + // of the argument available. if !args.options_spans.is_empty() { ecx.struct_span_err(span, "arguments are not allowed after options") .span_labels(args.options_spans.clone(), "previous options") .span_label(span, "argument") .emit(); + } else if let Some((_, abi_span)) = args.clobber_abi { + ecx.struct_span_err(span, "arguments are not allowed after clobber_abi") + .span_label(abi_span, "clobber_abi") + .span_label(span, "argument") + .emit(); } if explicit_reg { if name.is_some() { @@ -256,16 +275,23 @@ fn parse_args<'a>( let mut have_real_output = false; let mut outputs_sp = vec![]; + let mut regclass_outputs = vec![]; for (op, op_sp) in &args.operands { match op { - ast::InlineAsmOperand::Out { expr, .. } - | ast::InlineAsmOperand::SplitInOut { out_expr: expr, .. } => { + ast::InlineAsmOperand::Out { reg, expr, .. } + | ast::InlineAsmOperand::SplitInOut { reg, out_expr: expr, .. } => { outputs_sp.push(*op_sp); have_real_output |= expr.is_some(); + if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg { + regclass_outputs.push(*op_sp); + } } - ast::InlineAsmOperand::InOut { .. } => { + ast::InlineAsmOperand::InOut { reg, .. } => { outputs_sp.push(*op_sp); have_real_output = true; + if let ast::InlineAsmRegOrRegClass::RegClass(_) = reg { + regclass_outputs.push(*op_sp); + } } _ => {} } @@ -284,6 +310,24 @@ fn parse_args<'a>( // Bail out now since this is likely to confuse MIR return Err(err); } + if let Some((_, abi_span)) = args.clobber_abi { + if is_global_asm { + let err = + ecx.struct_span_err(abi_span, "`clobber_abi` cannot be used with `global_asm!`"); + + // Bail out now since this is likely to confuse later stages + return Err(err); + } + if !regclass_outputs.is_empty() { + ecx.struct_span_err( + regclass_outputs.clone(), + "asm with `clobber_abi` must specify explicit registers for outputs", + ) + .span_label(abi_span, "clobber_abi") + .span_labels(regclass_outputs, "generic outputs") + .emit(); + } + } Ok(args) } @@ -375,6 +419,49 @@ fn parse_options<'a>( Ok(()) } +fn parse_clobber_abi<'a>( + p: &mut Parser<'a>, + args: &mut AsmArgs, +) -> Result<(), DiagnosticBuilder<'a>> { + let span_start = p.prev_token.span; + + p.expect(&token::OpenDelim(token::DelimToken::Paren))?; + + let clobber_abi = match p.parse_str_lit() { + Ok(str_lit) => str_lit.symbol_unescaped, + Err(opt_lit) => { + let span = opt_lit.map_or(p.token.span, |lit| lit.span); + let mut err = p.sess.span_diagnostic.struct_span_err(span, "expected string literal"); + err.span_label(span, "not a string literal"); + return Err(err); + } + }; + + p.expect(&token::CloseDelim(token::DelimToken::Paren))?; + + let new_span = span_start.to(p.prev_token.span); + + if let Some((_, prev_span)) = args.clobber_abi { + let mut err = p + .sess + .span_diagnostic + .struct_span_err(new_span, "clobber_abi specified multiple times"); + err.span_label(prev_span, "clobber_abi previously specified here"); + return Err(err); + } else if !args.options_spans.is_empty() { + let mut err = p + .sess + .span_diagnostic + .struct_span_err(new_span, "clobber_abi is not allowed after options"); + err.span_labels(args.options_spans.clone(), "options"); + return Err(err); + } + + args.clobber_abi = Some((clobber_abi, new_span)); + + Ok(()) +} + fn parse_reg<'a>( p: &mut Parser<'a>, explicit_reg: &mut bool, @@ -660,7 +747,13 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl } } - Some(ast::InlineAsm { template, operands: args.operands, options: args.options, line_spans }) + Some(ast::InlineAsm { + template, + operands: args.operands, + clobber_abi: args.clobber_abi, + options: args.options, + line_spans, + }) } pub fn expand_asm<'cx>( |
