mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Remove deprecated LLVM-style inline assembly
This commit is contained in:
parent
72e74d7b9c
commit
000b36c505
@ -1266,7 +1266,7 @@ impl Expr {
|
||||
ExprKind::Break(..) => ExprPrecedence::Break,
|
||||
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
||||
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
||||
ExprKind::InlineAsm(..) | ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
|
||||
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
|
||||
ExprKind::MacCall(..) => ExprPrecedence::Mac,
|
||||
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
||||
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
||||
@ -1423,8 +1423,6 @@ pub enum ExprKind {
|
||||
|
||||
/// Output of the `asm!()` macro.
|
||||
InlineAsm(P<InlineAsm>),
|
||||
/// Output of the `llvm_asm!()` macro.
|
||||
LlvmInlineAsm(P<LlvmInlineAsm>),
|
||||
|
||||
/// A macro invocation; pre-expansion.
|
||||
MacCall(MacCall),
|
||||
@ -2076,41 +2074,6 @@ pub struct InlineAsm {
|
||||
pub line_spans: Vec<Span>,
|
||||
}
|
||||
|
||||
/// Inline assembly dialect.
|
||||
///
|
||||
/// E.g., `"intel"` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
|
||||
#[derive(Clone, PartialEq, Encodable, Decodable, Debug, Copy, Hash, HashStable_Generic)]
|
||||
pub enum LlvmAsmDialect {
|
||||
Att,
|
||||
Intel,
|
||||
}
|
||||
|
||||
/// LLVM-style inline assembly.
|
||||
///
|
||||
/// E.g., `"={eax}"(result)` as in `llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct LlvmInlineAsmOutput {
|
||||
pub constraint: Symbol,
|
||||
pub expr: P<Expr>,
|
||||
pub is_rw: bool,
|
||||
pub is_indirect: bool,
|
||||
}
|
||||
|
||||
/// LLVM-style inline assembly.
|
||||
///
|
||||
/// E.g., `llvm_asm!("NOP");`.
|
||||
#[derive(Clone, Encodable, Decodable, Debug)]
|
||||
pub struct LlvmInlineAsm {
|
||||
pub asm: Symbol,
|
||||
pub asm_str_style: StrStyle,
|
||||
pub outputs: Vec<LlvmInlineAsmOutput>,
|
||||
pub inputs: Vec<(Symbol, P<Expr>)>,
|
||||
pub clobbers: Vec<Symbol>,
|
||||
pub volatile: bool,
|
||||
pub alignstack: bool,
|
||||
pub dialect: LlvmAsmDialect,
|
||||
}
|
||||
|
||||
/// A parameter in a function header.
|
||||
///
|
||||
/// E.g., `bar: usize` as in `fn foo(bar: usize)`.
|
||||
|
@ -1350,23 +1350,6 @@ pub fn noop_visit_expr<T: MutVisitor>(
|
||||
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||
}
|
||||
ExprKind::InlineAsm(asm) => noop_visit_inline_asm(asm, vis),
|
||||
ExprKind::LlvmInlineAsm(asm) => {
|
||||
let LlvmInlineAsm {
|
||||
asm: _,
|
||||
asm_str_style: _,
|
||||
outputs,
|
||||
inputs,
|
||||
clobbers: _,
|
||||
volatile: _,
|
||||
alignstack: _,
|
||||
dialect: _,
|
||||
} = asm.deref_mut();
|
||||
for out in outputs {
|
||||
let LlvmInlineAsmOutput { constraint: _, expr, is_rw: _, is_indirect: _ } = out;
|
||||
vis.visit_expr(expr);
|
||||
}
|
||||
visit_vec(inputs, |(_c, expr)| vis.visit_expr(expr));
|
||||
}
|
||||
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
|
||||
ExprKind::Struct(se) => {
|
||||
let StructExpr { qself, path, fields, rest } = se.deref_mut();
|
||||
|
@ -864,14 +864,6 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
|
||||
ExprKind::MacCall(ref mac) => visitor.visit_mac_call(mac),
|
||||
ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
|
||||
ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm),
|
||||
ExprKind::LlvmInlineAsm(ref ia) => {
|
||||
for &(_, ref input) in &ia.inputs {
|
||||
visitor.visit_expr(input)
|
||||
}
|
||||
for output in &ia.outputs {
|
||||
visitor.visit_expr(&output.expr)
|
||||
}
|
||||
}
|
||||
ExprKind::Yield(ref optional_expression) => {
|
||||
walk_list!(visitor, visit_expr, optional_expression);
|
||||
}
|
||||
|
@ -226,7 +226,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
ExprKind::InlineAsm(ref asm) => {
|
||||
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
|
||||
}
|
||||
ExprKind::LlvmInlineAsm(ref asm) => self.lower_expr_llvm_asm(asm),
|
||||
ExprKind::Struct(ref se) => {
|
||||
let rest = match &se.rest {
|
||||
StructRest::Base(e) => Some(self.lower_expr(e)),
|
||||
@ -1284,38 +1283,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||
result
|
||||
}
|
||||
|
||||
fn lower_expr_llvm_asm(&mut self, asm: &LlvmInlineAsm) -> hir::ExprKind<'hir> {
|
||||
let inner = hir::LlvmInlineAsmInner {
|
||||
inputs: asm.inputs.iter().map(|&(c, _)| c).collect(),
|
||||
outputs: asm
|
||||
.outputs
|
||||
.iter()
|
||||
.map(|out| hir::LlvmInlineAsmOutput {
|
||||
constraint: out.constraint,
|
||||
is_rw: out.is_rw,
|
||||
is_indirect: out.is_indirect,
|
||||
span: self.lower_span(out.expr.span),
|
||||
})
|
||||
.collect(),
|
||||
asm: asm.asm,
|
||||
asm_str_style: asm.asm_str_style,
|
||||
clobbers: asm.clobbers.clone(),
|
||||
volatile: asm.volatile,
|
||||
alignstack: asm.alignstack,
|
||||
dialect: asm.dialect,
|
||||
};
|
||||
let hir_asm = hir::LlvmInlineAsm {
|
||||
inner,
|
||||
inputs_exprs: self.arena.alloc_from_iter(
|
||||
asm.inputs.iter().map(|&(_, ref input)| self.lower_expr_mut(input)),
|
||||
),
|
||||
outputs_exprs: self
|
||||
.arena
|
||||
.alloc_from_iter(asm.outputs.iter().map(|out| self.lower_expr_mut(&out.expr))),
|
||||
};
|
||||
hir::ExprKind::LlvmInlineAsm(self.arena.alloc(hir_asm))
|
||||
}
|
||||
|
||||
fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
|
||||
hir::ExprField {
|
||||
hir_id: self.next_id(),
|
||||
|
@ -960,15 +960,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||
return;
|
||||
}
|
||||
ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
|
||||
ExprKind::LlvmInlineAsm(..) if !this.session.target.allow_asm => {
|
||||
struct_span_err!(
|
||||
this.session,
|
||||
expr.span,
|
||||
E0472,
|
||||
"llvm_asm! is unsupported on this target"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
ExprKind::Match(expr, arms) => {
|
||||
this.visit_expr(expr);
|
||||
for arm in arms {
|
||||
|
@ -2168,62 +2168,6 @@ impl<'a> State<'a> {
|
||||
self.word("asm!");
|
||||
self.print_inline_asm(a);
|
||||
}
|
||||
ast::ExprKind::LlvmInlineAsm(ref a) => {
|
||||
self.word("llvm_asm!");
|
||||
self.popen();
|
||||
self.print_symbol(a.asm, a.asm_str_style);
|
||||
self.word_space(":");
|
||||
|
||||
self.commasep(Inconsistent, &a.outputs, |s, out| {
|
||||
let constraint = out.constraint.as_str();
|
||||
let mut ch = constraint.chars();
|
||||
match ch.next() {
|
||||
Some('=') if out.is_rw => {
|
||||
s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
|
||||
}
|
||||
_ => s.print_string(&constraint, ast::StrStyle::Cooked),
|
||||
}
|
||||
s.popen();
|
||||
s.print_expr(&out.expr);
|
||||
s.pclose();
|
||||
});
|
||||
self.space();
|
||||
self.word_space(":");
|
||||
|
||||
self.commasep(Inconsistent, &a.inputs, |s, &(co, ref o)| {
|
||||
s.print_symbol(co, ast::StrStyle::Cooked);
|
||||
s.popen();
|
||||
s.print_expr(o);
|
||||
s.pclose();
|
||||
});
|
||||
self.space();
|
||||
self.word_space(":");
|
||||
|
||||
self.commasep(Inconsistent, &a.clobbers, |s, &co| {
|
||||
s.print_symbol(co, ast::StrStyle::Cooked);
|
||||
});
|
||||
|
||||
let mut options = vec![];
|
||||
if a.volatile {
|
||||
options.push("volatile");
|
||||
}
|
||||
if a.alignstack {
|
||||
options.push("alignstack");
|
||||
}
|
||||
if a.dialect == ast::LlvmAsmDialect::Intel {
|
||||
options.push("intel");
|
||||
}
|
||||
|
||||
if !options.is_empty() {
|
||||
self.space();
|
||||
self.word_space(":");
|
||||
self.commasep(Inconsistent, &options, |s, &co| {
|
||||
s.print_string(co, ast::StrStyle::Cooked);
|
||||
});
|
||||
}
|
||||
|
||||
self.pclose();
|
||||
}
|
||||
ast::ExprKind::MacCall(ref m) => self.print_mac(m),
|
||||
ast::ExprKind::Paren(ref e) => {
|
||||
self.popen();
|
||||
|
@ -8,7 +8,6 @@ use rustc_mir_dataflow::ResultsVisitable;
|
||||
use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
|
||||
use rustc_mir_dataflow::{Analysis, Direction, Results};
|
||||
use std::fmt;
|
||||
use std::iter;
|
||||
|
||||
use crate::{
|
||||
places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
|
||||
@ -385,14 +384,6 @@ impl<'tcx> rustc_mir_dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> {
|
||||
self.kill_borrows_on_place(trans, Place::from(local));
|
||||
}
|
||||
|
||||
mir::StatementKind::LlvmInlineAsm(ref asm) => {
|
||||
for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
|
||||
if !kind.is_indirect && !kind.is_rw {
|
||||
self.kill_borrows_on_place(trans, *output);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mir::StatementKind::FakeRead(..)
|
||||
| mir::StatementKind::SetDiscriminant { .. }
|
||||
| mir::StatementKind::StorageLive(..)
|
||||
|
@ -16,9 +16,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
|
||||
|
||||
PlaceContext::MutatingUse(MutatingUseContext::Store) |
|
||||
|
||||
// This is potentially both a def and a use...
|
||||
PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput) |
|
||||
|
||||
// We let Call define the result in both the success and
|
||||
// unwind cases. This is not really correct, however it
|
||||
// does not seem to be observable due to the way that we
|
||||
|
@ -5,12 +5,11 @@ use rustc_middle::mir::{BorrowKind, Mutability, Operand};
|
||||
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
|
||||
use rustc_middle::mir::{Statement, StatementKind};
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
use std::iter;
|
||||
|
||||
use crate::{
|
||||
borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth,
|
||||
Activation, ArtificialField, BorrowIndex, Deep, JustWrite, LocalMutationIsAllowed, MutateMode,
|
||||
Read, ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind,
|
||||
Read, ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteKind,
|
||||
};
|
||||
|
||||
pub(super) fn generate_invalidates<'tcx>(
|
||||
@ -67,30 +66,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||
StatementKind::SetDiscriminant { place, variant_index: _ } => {
|
||||
self.mutate_place(location, **place, Shallow(None), JustWrite);
|
||||
}
|
||||
StatementKind::LlvmInlineAsm(asm) => {
|
||||
for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
|
||||
if o.is_indirect {
|
||||
// FIXME(eddyb) indirect inline asm outputs should
|
||||
// be encoded through MIR place derefs instead.
|
||||
self.access_place(
|
||||
location,
|
||||
*output,
|
||||
(Deep, Read(ReadKind::Copy)),
|
||||
LocalMutationIsAllowed::No,
|
||||
);
|
||||
} else {
|
||||
self.mutate_place(
|
||||
location,
|
||||
*output,
|
||||
if o.is_rw { Deep } else { Shallow(None) },
|
||||
if o.is_rw { WriteAndRead } else { JustWrite },
|
||||
);
|
||||
}
|
||||
}
|
||||
for (_, input) in asm.inputs.iter() {
|
||||
self.consume_operand(location, input);
|
||||
}
|
||||
}
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
ref src,
|
||||
ref dst,
|
||||
|
@ -40,7 +40,6 @@ use either::Either;
|
||||
use smallvec::SmallVec;
|
||||
use std::cell::RefCell;
|
||||
use std::collections::BTreeMap;
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
use std::rc::Rc;
|
||||
|
||||
@ -55,7 +54,7 @@ use rustc_mir_dataflow::MoveDataParamEnv;
|
||||
use self::diagnostics::{AccessKind, RegionName};
|
||||
use self::location::LocationTable;
|
||||
use self::prefixes::PrefixSet;
|
||||
use self::MutateMode::{JustWrite, WriteAndRead};
|
||||
use self::MutateMode::JustWrite;
|
||||
use facts::AllFacts;
|
||||
|
||||
use self::path_utils::*;
|
||||
@ -653,39 +652,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||
StatementKind::SetDiscriminant { place, variant_index: _ } => {
|
||||
self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state);
|
||||
}
|
||||
StatementKind::LlvmInlineAsm(ref asm) => {
|
||||
for (o, output) in iter::zip(&asm.asm.outputs, &*asm.outputs) {
|
||||
if o.is_indirect {
|
||||
// FIXME(eddyb) indirect inline asm outputs should
|
||||
// be encoded through MIR place derefs instead.
|
||||
self.access_place(
|
||||
location,
|
||||
(*output, o.span),
|
||||
(Deep, Read(ReadKind::Copy)),
|
||||
LocalMutationIsAllowed::No,
|
||||
flow_state,
|
||||
);
|
||||
self.check_if_path_or_subpath_is_moved(
|
||||
location,
|
||||
InitializationRequiringAction::Use,
|
||||
(output.as_ref(), o.span),
|
||||
flow_state,
|
||||
);
|
||||
} else {
|
||||
self.mutate_place(
|
||||
location,
|
||||
(*output, o.span),
|
||||
if o.is_rw { Deep } else { Shallow(None) },
|
||||
if o.is_rw { WriteAndRead } else { JustWrite },
|
||||
flow_state,
|
||||
);
|
||||
}
|
||||
}
|
||||
for (_, input) in asm.inputs.iter() {
|
||||
self.consume_operand(location, (input, span), flow_state);
|
||||
}
|
||||
}
|
||||
|
||||
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||
..
|
||||
}) => {
|
||||
|
@ -1477,7 +1477,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||
StatementKind::FakeRead(..)
|
||||
| StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
| StatementKind::LlvmInlineAsm { .. }
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::Nop => {}
|
||||
|
@ -50,15 +50,6 @@ pub fn parse_asm_args<'a>(
|
||||
return Err(diag.struct_span_err(sp, "requires at least a template string argument"));
|
||||
}
|
||||
|
||||
// Detect use of the legacy llvm_asm! syntax (which used to be called asm!)
|
||||
if !is_global_asm && p.look_ahead(1, |t| *t == token::Colon || *t == token::ModSep) {
|
||||
let mut err =
|
||||
diag.struct_span_err(sp, "the legacy LLVM-style asm! syntax is no longer supported");
|
||||
err.note("consider migrating to the new asm! syntax specified in RFC 2873");
|
||||
err.note("alternatively, switch to llvm_asm! to keep your code working as it is");
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
let first_template = p.parse_expr()?;
|
||||
let mut args = AsmArgs {
|
||||
templates: vec![first_template],
|
||||
|
@ -33,7 +33,6 @@ mod env;
|
||||
mod format;
|
||||
mod format_foreign;
|
||||
mod global_allocator;
|
||||
mod llvm_asm;
|
||||
mod log_syntax;
|
||||
mod panic;
|
||||
mod source_util;
|
||||
@ -78,7 +77,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
||||
include_str: source_util::expand_include_str,
|
||||
include: source_util::expand_include,
|
||||
line: source_util::expand_line,
|
||||
llvm_asm: llvm_asm::expand_llvm_asm,
|
||||
log_syntax: log_syntax::expand_log_syntax,
|
||||
module_path: source_util::expand_mod,
|
||||
option_env: env::expand_option_env,
|
||||
|
@ -1,303 +0,0 @@
|
||||
// Llvm-style inline assembly support.
|
||||
//
|
||||
use State::*;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::token::{self, Token};
|
||||
use rustc_ast::tokenstream::{self, TokenStream};
|
||||
use rustc_ast::LlvmAsmDialect;
|
||||
use rustc_errors::{struct_span_err, DiagnosticBuilder, PResult};
|
||||
use rustc_expand::base::*;
|
||||
use rustc_parse::parser::Parser;
|
||||
use rustc_span::symbol::{kw, sym, Symbol};
|
||||
use rustc_span::Span;
|
||||
|
||||
enum State {
|
||||
Asm,
|
||||
Outputs,
|
||||
Inputs,
|
||||
Clobbers,
|
||||
Options,
|
||||
StateNone,
|
||||
}
|
||||
|
||||
impl State {
|
||||
fn next(&self) -> State {
|
||||
match *self {
|
||||
Asm => Outputs,
|
||||
Outputs => Inputs,
|
||||
Inputs => Clobbers,
|
||||
Clobbers => Options,
|
||||
Options => StateNone,
|
||||
StateNone => StateNone,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const OPTIONS: &[Symbol] = &[sym::volatile, sym::alignstack, sym::intel];
|
||||
|
||||
pub fn expand_llvm_asm<'cx>(
|
||||
cx: &'cx mut ExtCtxt<'_>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Box<dyn MacResult + 'cx> {
|
||||
let mut inline_asm = match parse_inline_asm(cx, sp, tts) {
|
||||
Ok(Some(inline_asm)) => inline_asm,
|
||||
Ok(None) => return DummyResult::any(sp),
|
||||
Err(mut err) => {
|
||||
err.emit();
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
};
|
||||
|
||||
// If there are no outputs, the inline assembly is executed just for its side effects,
|
||||
// so ensure that it is volatile
|
||||
if inline_asm.outputs.is_empty() {
|
||||
inline_asm.volatile = true;
|
||||
}
|
||||
|
||||
MacEager::expr(P(ast::Expr {
|
||||
id: ast::DUMMY_NODE_ID,
|
||||
kind: ast::ExprKind::LlvmInlineAsm(P(inline_asm)),
|
||||
span: cx.with_def_site_ctxt(sp),
|
||||
attrs: ast::AttrVec::new(),
|
||||
tokens: None,
|
||||
}))
|
||||
}
|
||||
|
||||
fn parse_asm_str<'a>(p: &mut Parser<'a>) -> PResult<'a, Symbol> {
|
||||
match p.parse_str_lit() {
|
||||
Ok(str_lit) => Ok(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");
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_inline_asm<'a>(
|
||||
cx: &mut ExtCtxt<'a>,
|
||||
sp: Span,
|
||||
tts: TokenStream,
|
||||
) -> Result<Option<ast::LlvmInlineAsm>, DiagnosticBuilder<'a>> {
|
||||
// Split the tts before the first colon, to avoid `llvm_asm!("x": y)` being
|
||||
// parsed as `llvm_asm!(z)` with `z = "x": y` which is type ascription.
|
||||
let first_colon = tts
|
||||
.trees()
|
||||
.position(|tt| {
|
||||
matches!(
|
||||
tt,
|
||||
tokenstream::TokenTree::Token(Token { kind: token::Colon | token::ModSep, .. })
|
||||
)
|
||||
})
|
||||
.unwrap_or(tts.len());
|
||||
let mut p = cx.new_parser_from_tts(tts.trees().skip(first_colon).collect());
|
||||
let mut asm = kw::Empty;
|
||||
let mut asm_str_style = None;
|
||||
let mut outputs = Vec::new();
|
||||
let mut inputs = Vec::new();
|
||||
let mut clobs = Vec::new();
|
||||
let mut volatile = false;
|
||||
let mut alignstack = false;
|
||||
let mut dialect = LlvmAsmDialect::Att;
|
||||
|
||||
let mut state = Asm;
|
||||
|
||||
'statement: loop {
|
||||
match state {
|
||||
Asm => {
|
||||
if asm_str_style.is_some() {
|
||||
// If we already have a string with instructions,
|
||||
// ending up in Asm state again is an error.
|
||||
return Err(struct_span_err!(
|
||||
cx.sess.parse_sess.span_diagnostic,
|
||||
sp,
|
||||
E0660,
|
||||
"malformed inline assembly"
|
||||
));
|
||||
}
|
||||
// Nested parser, stop before the first colon (see above).
|
||||
let mut p2 = cx.new_parser_from_tts(tts.trees().take(first_colon).collect());
|
||||
|
||||
if p2.token == token::Eof {
|
||||
let mut err =
|
||||
cx.struct_span_err(sp, "macro requires a string literal as an argument");
|
||||
err.span_label(sp, "string literal required");
|
||||
return Err(err);
|
||||
}
|
||||
|
||||
let expr = p2.parse_expr()?;
|
||||
let (s, style) =
|
||||
match expr_to_string(cx, expr, "inline assembly must be a string literal") {
|
||||
Some((s, st)) => (s, st),
|
||||
None => return Ok(None),
|
||||
};
|
||||
|
||||
// This is most likely malformed.
|
||||
if p2.token != token::Eof {
|
||||
let mut extra_tts = p2.parse_all_token_trees()?;
|
||||
extra_tts.extend(tts.trees().skip(first_colon));
|
||||
p = cx.new_parser_from_tts(extra_tts.into_iter().collect());
|
||||
}
|
||||
|
||||
asm = s;
|
||||
asm_str_style = Some(style);
|
||||
}
|
||||
Outputs => {
|
||||
while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
|
||||
if !outputs.is_empty() {
|
||||
p.eat(&token::Comma);
|
||||
}
|
||||
|
||||
let constraint = parse_asm_str(&mut p)?;
|
||||
|
||||
let span = p.prev_token.span;
|
||||
|
||||
p.expect(&token::OpenDelim(token::Paren))?;
|
||||
let expr = p.parse_expr()?;
|
||||
p.expect(&token::CloseDelim(token::Paren))?;
|
||||
|
||||
// Expands a read+write operand into two operands.
|
||||
//
|
||||
// Use '+' modifier when you want the same expression
|
||||
// to be both an input and an output at the same time.
|
||||
// It's the opposite of '=&' which means that the memory
|
||||
// cannot be shared with any other operand (usually when
|
||||
// a register is clobbered early.)
|
||||
let constraint_str = constraint.as_str();
|
||||
let mut ch = constraint_str.chars();
|
||||
let output = match ch.next() {
|
||||
Some('=') => None,
|
||||
Some('+') => Some(Symbol::intern(&format!("={}", ch.as_str()))),
|
||||
_ => {
|
||||
struct_span_err!(
|
||||
cx.sess.parse_sess.span_diagnostic,
|
||||
span,
|
||||
E0661,
|
||||
"output operand constraint lacks '=' or '+'"
|
||||
)
|
||||
.emit();
|
||||
None
|
||||
}
|
||||
};
|
||||
|
||||
let is_rw = output.is_some();
|
||||
let is_indirect = constraint_str.contains('*');
|
||||
outputs.push(ast::LlvmInlineAsmOutput {
|
||||
constraint: output.unwrap_or(constraint),
|
||||
expr,
|
||||
is_rw,
|
||||
is_indirect,
|
||||
});
|
||||
}
|
||||
}
|
||||
Inputs => {
|
||||
while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
|
||||
if !inputs.is_empty() {
|
||||
p.eat(&token::Comma);
|
||||
}
|
||||
|
||||
let constraint = parse_asm_str(&mut p)?;
|
||||
|
||||
if constraint.as_str().starts_with('=') {
|
||||
struct_span_err!(
|
||||
cx.sess.parse_sess.span_diagnostic,
|
||||
p.prev_token.span,
|
||||
E0662,
|
||||
"input operand constraint contains '='"
|
||||
)
|
||||
.emit();
|
||||
} else if constraint.as_str().starts_with('+') {
|
||||
struct_span_err!(
|
||||
cx.sess.parse_sess.span_diagnostic,
|
||||
p.prev_token.span,
|
||||
E0663,
|
||||
"input operand constraint contains '+'"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
p.expect(&token::OpenDelim(token::Paren))?;
|
||||
let input = p.parse_expr()?;
|
||||
p.expect(&token::CloseDelim(token::Paren))?;
|
||||
|
||||
inputs.push((constraint, input));
|
||||
}
|
||||
}
|
||||
Clobbers => {
|
||||
while p.token != token::Eof && p.token != token::Colon && p.token != token::ModSep {
|
||||
if !clobs.is_empty() {
|
||||
p.eat(&token::Comma);
|
||||
}
|
||||
|
||||
let s = parse_asm_str(&mut p)?;
|
||||
|
||||
if OPTIONS.iter().any(|&opt| s == opt) {
|
||||
cx.span_warn(p.prev_token.span, "expected a clobber, found an option");
|
||||
} else if s.as_str().starts_with('{') || s.as_str().ends_with('}') {
|
||||
struct_span_err!(
|
||||
cx.sess.parse_sess.span_diagnostic,
|
||||
p.prev_token.span,
|
||||
E0664,
|
||||
"clobber should not be surrounded by braces"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
|
||||
clobs.push(s);
|
||||
}
|
||||
}
|
||||
Options => {
|
||||
let option = parse_asm_str(&mut p)?;
|
||||
|
||||
if option == sym::volatile {
|
||||
// Indicates that the inline assembly has side effects
|
||||
// and must not be optimized out along with its outputs.
|
||||
volatile = true;
|
||||
} else if option == sym::alignstack {
|
||||
alignstack = true;
|
||||
} else if option == sym::intel {
|
||||
dialect = LlvmAsmDialect::Intel;
|
||||
} else {
|
||||
cx.span_warn(p.prev_token.span, "unrecognized option");
|
||||
}
|
||||
|
||||
if p.token == token::Comma {
|
||||
p.eat(&token::Comma);
|
||||
}
|
||||
}
|
||||
StateNone => (),
|
||||
}
|
||||
|
||||
loop {
|
||||
// MOD_SEP is a double colon '::' without space in between.
|
||||
// When encountered, the state must be advanced twice.
|
||||
match (&p.token.kind, state.next(), state.next().next()) {
|
||||
(&token::Colon, StateNone, _) | (&token::ModSep, _, StateNone) => {
|
||||
p.bump();
|
||||
break 'statement;
|
||||
}
|
||||
(&token::Colon, st, _) | (&token::ModSep, _, st) => {
|
||||
p.bump();
|
||||
state = st;
|
||||
}
|
||||
(&token::Eof, ..) => break 'statement,
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Some(ast::LlvmInlineAsm {
|
||||
asm,
|
||||
asm_str_style: asm_str_style.unwrap(),
|
||||
outputs,
|
||||
inputs,
|
||||
clobbers: clobs,
|
||||
volatile,
|
||||
alignstack,
|
||||
dialect,
|
||||
}))
|
||||
}
|
@ -749,18 +749,6 @@ fn codegen_stmt<'tcx>(
|
||||
| StatementKind::Retag { .. }
|
||||
| StatementKind::AscribeUserType(..) => {}
|
||||
|
||||
StatementKind::LlvmInlineAsm(asm) => {
|
||||
match asm.asm.asm.as_str().trim() {
|
||||
"" => {
|
||||
// Black box
|
||||
}
|
||||
_ => fx.tcx.sess.span_fatal(
|
||||
stmt.source_info.span,
|
||||
"Legacy `llvm_asm!` inline assembly is not supported. \
|
||||
Try using the new `asm!` instead.",
|
||||
),
|
||||
}
|
||||
}
|
||||
StatementKind::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
|
||||
StatementKind::CopyNonOverlapping(inner) => {
|
||||
let dst = codegen_operand(fx, &inner.dst);
|
||||
|
@ -506,7 +506,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||
{
|
||||
return None;
|
||||
}
|
||||
StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => {
|
||||
StatementKind::CopyNonOverlapping(_) => {
|
||||
return None;
|
||||
} // conservative handling
|
||||
StatementKind::Assign(_)
|
||||
|
@ -4,7 +4,6 @@ use rustc_codegen_ssa::mir::operand::OperandValue;
|
||||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||
use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
|
||||
|
||||
use rustc_hir::LlvmInlineAsmInner;
|
||||
use rustc_middle::{bug, ty::Instance};
|
||||
use rustc_span::{Span, Symbol};
|
||||
use rustc_target::asm::*;
|
||||
@ -106,17 +105,6 @@ enum ConstraintOrRegister {
|
||||
|
||||
|
||||
impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
||||
fn codegen_llvm_inline_asm(&mut self, _ia: &LlvmInlineAsmInner, _outputs: Vec<PlaceRef<'tcx, RValue<'gcc>>>, _inputs: Vec<RValue<'gcc>>, span: Span) -> bool {
|
||||
self.sess().struct_span_err(span, "GCC backend does not support `llvm_asm!`")
|
||||
.help("consider using the `asm!` macro instead")
|
||||
.emit();
|
||||
|
||||
// We return `true` even if we've failed to generate the asm
|
||||
// because we want to suppress the "malformed inline assembly" error
|
||||
// generated by the frontend.
|
||||
true
|
||||
}
|
||||
|
||||
fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], _instance: Instance<'_>, _dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>) {
|
||||
if options.contains(InlineAsmOptions::MAY_UNWIND) {
|
||||
self.sess()
|
||||
|
@ -7,13 +7,10 @@ use crate::type_::Type;
|
||||
use crate::type_of::LayoutLlvmExt;
|
||||
use crate::value::Value;
|
||||
|
||||
use rustc_ast::LlvmAsmDialect;
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_codegen_ssa::mir::operand::OperandValue;
|
||||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||
use rustc_codegen_ssa::traits::*;
|
||||
use rustc_data_structures::fx::FxHashMap;
|
||||
use rustc_hir as hir;
|
||||
use rustc_middle::ty::layout::TyAndLayout;
|
||||
use rustc_middle::{bug, span_bug, ty::Instance};
|
||||
use rustc_span::{Pos, Span, Symbol};
|
||||
@ -24,100 +21,6 @@ use libc::{c_char, c_uint};
|
||||
use tracing::debug;
|
||||
|
||||
impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
fn codegen_llvm_inline_asm(
|
||||
&mut self,
|
||||
ia: &hir::LlvmInlineAsmInner,
|
||||
outputs: Vec<PlaceRef<'tcx, &'ll Value>>,
|
||||
mut inputs: Vec<&'ll Value>,
|
||||
span: Span,
|
||||
) -> bool {
|
||||
let mut ext_constraints = vec![];
|
||||
let mut output_types = vec![];
|
||||
|
||||
// Prepare the output operands
|
||||
let mut indirect_outputs = vec![];
|
||||
for (i, (out, &place)) in ia.outputs.iter().zip(&outputs).enumerate() {
|
||||
if out.is_rw {
|
||||
let operand = self.load_operand(place);
|
||||
if let OperandValue::Immediate(_) = operand.val {
|
||||
inputs.push(operand.immediate());
|
||||
}
|
||||
ext_constraints.push(i.to_string());
|
||||
}
|
||||
if out.is_indirect {
|
||||
let operand = self.load_operand(place);
|
||||
if let OperandValue::Immediate(_) = operand.val {
|
||||
indirect_outputs.push(operand.immediate());
|
||||
}
|
||||
} else {
|
||||
output_types.push(place.layout.llvm_type(self.cx));
|
||||
}
|
||||
}
|
||||
if !indirect_outputs.is_empty() {
|
||||
indirect_outputs.extend_from_slice(&inputs);
|
||||
inputs = indirect_outputs;
|
||||
}
|
||||
|
||||
let clobbers = ia.clobbers.iter().map(|s| format!("~{{{}}}", &s));
|
||||
|
||||
// Default per-arch clobbers
|
||||
// Basically what clang does
|
||||
let arch_clobbers = match &self.sess().target.arch[..] {
|
||||
"x86" | "x86_64" => &["~{dirflag}", "~{fpsr}", "~{flags}"][..],
|
||||
"mips" | "mips64" => &["~{$1}"],
|
||||
_ => &[],
|
||||
};
|
||||
|
||||
let all_constraints = ia
|
||||
.outputs
|
||||
.iter()
|
||||
.map(|out| out.constraint.to_string())
|
||||
.chain(ia.inputs.iter().map(|s| s.to_string()))
|
||||
.chain(ext_constraints)
|
||||
.chain(clobbers)
|
||||
.chain(arch_clobbers.iter().map(|s| (*s).to_string()))
|
||||
.collect::<Vec<String>>()
|
||||
.join(",");
|
||||
|
||||
debug!("Asm Constraints: {}", &all_constraints);
|
||||
|
||||
// Depending on how many outputs we have, the return type is different
|
||||
let num_outputs = output_types.len();
|
||||
let output_type = match num_outputs {
|
||||
0 => self.type_void(),
|
||||
1 => output_types[0],
|
||||
_ => self.type_struct(&output_types, false),
|
||||
};
|
||||
|
||||
let asm = ia.asm.as_str();
|
||||
let r = inline_asm_call(
|
||||
self,
|
||||
&asm,
|
||||
&all_constraints,
|
||||
&inputs,
|
||||
output_type,
|
||||
ia.volatile,
|
||||
ia.alignstack,
|
||||
ia.dialect,
|
||||
&[span],
|
||||
false,
|
||||
None,
|
||||
);
|
||||
if r.is_none() {
|
||||
return false;
|
||||
}
|
||||
let r = r.unwrap();
|
||||
|
||||
// Again, based on how many outputs we have
|
||||
let outputs = ia.outputs.iter().zip(&outputs).filter(|&(o, _)| !o.is_indirect);
|
||||
for (i, (_, &place)) in outputs.enumerate() {
|
||||
let v = if num_outputs == 1 { r } else { self.extract_value(r, i as u64) };
|
||||
OperandValue::Immediate(v).store(self, place);
|
||||
}
|
||||
|
||||
true
|
||||
}
|
||||
|
||||
fn codegen_inline_asm(
|
||||
&mut self,
|
||||
template: &[InlineAsmTemplatePiece],
|
||||
@ -349,9 +252,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
InlineAsmArch::X86 | InlineAsmArch::X86_64
|
||||
if !options.contains(InlineAsmOptions::ATT_SYNTAX) =>
|
||||
{
|
||||
LlvmAsmDialect::Intel
|
||||
llvm::AsmDialect::Intel
|
||||
}
|
||||
_ => LlvmAsmDialect::Att,
|
||||
_ => llvm::AsmDialect::Att,
|
||||
};
|
||||
let result = inline_asm_call(
|
||||
self,
|
||||
@ -455,7 +358,7 @@ pub(crate) fn inline_asm_call<'ll>(
|
||||
output: &'ll llvm::Type,
|
||||
volatile: bool,
|
||||
alignstack: bool,
|
||||
dia: LlvmAsmDialect,
|
||||
dia: llvm::AsmDialect,
|
||||
line_spans: &[Span],
|
||||
unwind: bool,
|
||||
dest_catch_funclet: Option<(
|
||||
@ -498,7 +401,7 @@ pub(crate) fn inline_asm_call<'ll>(
|
||||
cons.len(),
|
||||
volatile,
|
||||
alignstack,
|
||||
llvm::AsmDialect::from_generic(dia),
|
||||
dia,
|
||||
can_throw,
|
||||
);
|
||||
|
||||
@ -522,7 +425,7 @@ pub(crate) fn inline_asm_call<'ll>(
|
||||
// we just encode the start position of each line.
|
||||
// FIXME: Figure out a way to pass the entire line spans.
|
||||
let mut srcloc = vec![];
|
||||
if dia == LlvmAsmDialect::Intel && line_spans.len() > 1 {
|
||||
if dia == llvm::AsmDialect::Intel && line_spans.len() > 1 {
|
||||
// LLVM inserts an extra line to add the ".intel_syntax", so add
|
||||
// a dummy srcloc entry for it.
|
||||
//
|
||||
|
@ -7,7 +7,6 @@ use crate::type_of::LayoutLlvmExt;
|
||||
use crate::va_arg::emit_va_arg;
|
||||
use crate::value::Value;
|
||||
|
||||
use rustc_ast as ast;
|
||||
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
|
||||
use rustc_codegen_ssa::common::span_invalid_monomorphization_error;
|
||||
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
||||
@ -351,7 +350,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||
self.type_void(),
|
||||
true,
|
||||
false,
|
||||
ast::LlvmAsmDialect::Att,
|
||||
llvm::AsmDialect::Att,
|
||||
&[span],
|
||||
false,
|
||||
None,
|
||||
|
@ -423,22 +423,13 @@ pub enum MetadataType {
|
||||
}
|
||||
|
||||
/// LLVMRustAsmDialect
|
||||
#[derive(Copy, Clone)]
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
pub enum AsmDialect {
|
||||
Att,
|
||||
Intel,
|
||||
}
|
||||
|
||||
impl AsmDialect {
|
||||
pub fn from_generic(asm: rustc_ast::LlvmAsmDialect) -> Self {
|
||||
match asm {
|
||||
rustc_ast::LlvmAsmDialect::Att => AsmDialect::Att,
|
||||
rustc_ast::LlvmAsmDialect::Intel => AsmDialect::Intel,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// LLVMRustCodeGenOptLevel
|
||||
#[derive(Copy, Clone, PartialEq)]
|
||||
#[repr(C)]
|
||||
|
@ -211,7 +211,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
||||
|
||||
PlaceContext::MutatingUse(
|
||||
MutatingUseContext::Store
|
||||
| MutatingUseContext::LlvmAsmOutput
|
||||
| MutatingUseContext::AsmOutput
|
||||
| MutatingUseContext::Borrow
|
||||
| MutatingUseContext::AddressOf
|
||||
|
@ -1,9 +1,7 @@
|
||||
use rustc_errors::struct_span_err;
|
||||
use rustc_middle::mir;
|
||||
|
||||
use super::FunctionCx;
|
||||
use super::LocalRef;
|
||||
use super::OperandValue;
|
||||
use crate::traits::BuilderMethods;
|
||||
use crate::traits::*;
|
||||
|
||||
@ -66,51 +64,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||
}
|
||||
bx
|
||||
}
|
||||
mir::StatementKind::LlvmInlineAsm(ref asm) => {
|
||||
let outputs = asm
|
||||
.outputs
|
||||
.iter()
|
||||
.map(|output| self.codegen_place(&mut bx, output.as_ref()))
|
||||
.collect();
|
||||
|
||||
let input_vals = asm.inputs.iter().fold(
|
||||
Vec::with_capacity(asm.inputs.len()),
|
||||
|mut acc, (span, input)| {
|
||||
let op = self.codegen_operand(&mut bx, input);
|
||||
if let OperandValue::Immediate(_) = op.val {
|
||||
acc.push(op.immediate());
|
||||
} else {
|
||||
struct_span_err!(
|
||||
bx.sess(),
|
||||
span.to_owned(),
|
||||
E0669,
|
||||
"invalid value for constraint in inline assembly"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
acc
|
||||
},
|
||||
);
|
||||
|
||||
if input_vals.len() == asm.inputs.len() {
|
||||
let res = bx.codegen_llvm_inline_asm(
|
||||
&asm.asm,
|
||||
outputs,
|
||||
input_vals,
|
||||
statement.source_info.span,
|
||||
);
|
||||
if !res {
|
||||
struct_span_err!(
|
||||
bx.sess(),
|
||||
statement.source_info.span,
|
||||
E0668,
|
||||
"malformed inline assembly"
|
||||
)
|
||||
.emit();
|
||||
}
|
||||
}
|
||||
bx
|
||||
}
|
||||
mir::StatementKind::Coverage(box ref coverage) => {
|
||||
self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
|
||||
bx
|
||||
|
@ -3,7 +3,6 @@ use crate::mir::operand::OperandRef;
|
||||
use crate::mir::place::PlaceRef;
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::LlvmInlineAsmInner;
|
||||
use rustc_middle::ty::Instance;
|
||||
use rustc_span::Span;
|
||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||
@ -42,15 +41,6 @@ pub enum GlobalAsmOperandRef {
|
||||
}
|
||||
|
||||
pub trait AsmBuilderMethods<'tcx>: BackendTypes {
|
||||
/// Take an inline assembly expression and splat it out via LLVM
|
||||
fn codegen_llvm_inline_asm(
|
||||
&mut self,
|
||||
ia: &LlvmInlineAsmInner,
|
||||
outputs: Vec<PlaceRef<'tcx, Self::Value>>,
|
||||
inputs: Vec<Self::Value>,
|
||||
span: Span,
|
||||
) -> bool;
|
||||
|
||||
/// Take an inline assembly expression and splat it out via LLVM
|
||||
fn codegen_inline_asm(
|
||||
&mut self,
|
||||
|
@ -140,8 +140,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
|
||||
// Defined to do nothing. These are added by optimization passes, to avoid changing the
|
||||
// size of MIR constantly.
|
||||
Nop => {}
|
||||
|
||||
LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
|
||||
}
|
||||
|
||||
self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1;
|
||||
|
@ -752,10 +752,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
|
||||
self.super_statement(statement, location);
|
||||
|
||||
match statement.kind {
|
||||
StatementKind::LlvmInlineAsm { .. } => {
|
||||
self.check_op(ops::InlineAsm);
|
||||
}
|
||||
|
||||
StatementKind::Assign(..)
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::FakeRead(..)
|
||||
|
@ -352,7 +352,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||
StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
| StatementKind::LlvmInlineAsm(..)
|
||||
| StatementKind::Retag(_, _)
|
||||
| StatementKind::Coverage(_)
|
||||
| StatementKind::Nop => {}
|
||||
|
@ -30,7 +30,6 @@ macro_rules! arena_types {
|
||||
[] impl_item_ref: rustc_hir::ImplItemRef,
|
||||
[] item: rustc_hir::Item<'tcx>,
|
||||
[] inline_asm: rustc_hir::InlineAsm<'tcx>,
|
||||
[] llvm_inline_asm: rustc_hir::LlvmInlineAsm<'tcx>,
|
||||
[] local: rustc_hir::Local<'tcx>,
|
||||
[] mod_: rustc_hir::Mod<'tcx>,
|
||||
[] owner_info: rustc_hir::OwnerInfo<'tcx>,
|
||||
|
@ -5,8 +5,8 @@ use crate::intravisit::FnKind;
|
||||
use crate::LangItem;
|
||||
|
||||
use rustc_ast::util::parser::ExprPrecedence;
|
||||
use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect};
|
||||
use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObjectSyntax, UintTy};
|
||||
use rustc_ast::{self as ast, CrateSugar};
|
||||
use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy};
|
||||
pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
|
||||
pub use rustc_ast::{CaptureBy, Movability, Mutability};
|
||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||
@ -1471,7 +1471,6 @@ impl Expr<'_> {
|
||||
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
||||
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
||||
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
|
||||
ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
|
||||
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
||||
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
||||
ExprKind::Yield(..) => ExprPrecedence::Yield,
|
||||
@ -1531,7 +1530,6 @@ impl Expr<'_> {
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Assign(..)
|
||||
| ExprKind::InlineAsm(..)
|
||||
| ExprKind::LlvmInlineAsm(..)
|
||||
| ExprKind::AssignOp(..)
|
||||
| ExprKind::Lit(_)
|
||||
| ExprKind::ConstBlock(..)
|
||||
@ -1614,7 +1612,6 @@ impl Expr<'_> {
|
||||
| ExprKind::Loop(..)
|
||||
| ExprKind::Assign(..)
|
||||
| ExprKind::InlineAsm(..)
|
||||
| ExprKind::LlvmInlineAsm(..)
|
||||
| ExprKind::AssignOp(..)
|
||||
| ExprKind::ConstBlock(..)
|
||||
| ExprKind::Box(..)
|
||||
@ -1755,8 +1752,6 @@ pub enum ExprKind<'hir> {
|
||||
|
||||
/// Inline assembly (from `asm!`), with its outputs and inputs.
|
||||
InlineAsm(&'hir InlineAsm<'hir>),
|
||||
/// Inline assembly (from `llvm_asm!`), with its outputs and inputs.
|
||||
LlvmInlineAsm(&'hir LlvmInlineAsm<'hir>),
|
||||
|
||||
/// A struct or struct-like variant literal expression.
|
||||
///
|
||||
@ -2368,36 +2363,6 @@ pub struct InlineAsm<'hir> {
|
||||
pub line_spans: &'hir [Span],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)]
|
||||
pub struct LlvmInlineAsmOutput {
|
||||
pub constraint: Symbol,
|
||||
pub is_rw: bool,
|
||||
pub is_indirect: bool,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
// NOTE(eddyb) This is used within MIR as well, so unlike the rest of the HIR,
|
||||
// it needs to be `Clone` and `Decodable` and use plain `Vec<T>` instead of
|
||||
// arena-allocated slice.
|
||||
#[derive(Clone, Encodable, Decodable, Debug, Hash, HashStable_Generic, PartialEq)]
|
||||
pub struct LlvmInlineAsmInner {
|
||||
pub asm: Symbol,
|
||||
pub asm_str_style: StrStyle,
|
||||
pub outputs: Vec<LlvmInlineAsmOutput>,
|
||||
pub inputs: Vec<Symbol>,
|
||||
pub clobbers: Vec<Symbol>,
|
||||
pub volatile: bool,
|
||||
pub alignstack: bool,
|
||||
pub dialect: LlvmAsmDialect,
|
||||
}
|
||||
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
pub struct LlvmInlineAsm<'hir> {
|
||||
pub inner: LlvmInlineAsmInner,
|
||||
pub outputs_exprs: &'hir [Expr<'hir>],
|
||||
pub inputs_exprs: &'hir [Expr<'hir>],
|
||||
}
|
||||
|
||||
/// Represents a parameter in a function header.
|
||||
#[derive(Debug, HashStable_Generic)]
|
||||
pub struct Param<'hir> {
|
||||
|
@ -1251,10 +1251,6 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
|
||||
ExprKind::InlineAsm(ref asm) => {
|
||||
walk_inline_asm(visitor, asm);
|
||||
}
|
||||
ExprKind::LlvmInlineAsm(ref asm) => {
|
||||
walk_list!(visitor, visit_expr, asm.outputs_exprs);
|
||||
walk_list!(visitor, visit_expr, asm.inputs_exprs);
|
||||
}
|
||||
ExprKind::Yield(ref subexpression, _) => {
|
||||
visitor.visit_expr(subexpression);
|
||||
}
|
||||
|
@ -1581,67 +1581,6 @@ impl<'a> State<'a> {
|
||||
self.word("asm!");
|
||||
self.print_inline_asm(asm);
|
||||
}
|
||||
hir::ExprKind::LlvmInlineAsm(ref a) => {
|
||||
let i = &a.inner;
|
||||
self.word("llvm_asm!");
|
||||
self.popen();
|
||||
self.print_symbol(i.asm, i.asm_str_style);
|
||||
self.word_space(":");
|
||||
|
||||
let mut out_idx = 0;
|
||||
self.commasep(Inconsistent, &i.outputs, |s, out| {
|
||||
let constraint = out.constraint.as_str();
|
||||
let mut ch = constraint.chars();
|
||||
match ch.next() {
|
||||
Some('=') if out.is_rw => {
|
||||
s.print_string(&format!("+{}", ch.as_str()), ast::StrStyle::Cooked)
|
||||
}
|
||||
_ => s.print_string(&constraint, ast::StrStyle::Cooked),
|
||||
}
|
||||
s.popen();
|
||||
s.print_expr(&a.outputs_exprs[out_idx]);
|
||||
s.pclose();
|
||||
out_idx += 1;
|
||||
});
|
||||
self.space();
|
||||
self.word_space(":");
|
||||
|
||||
let mut in_idx = 0;
|
||||
self.commasep(Inconsistent, &i.inputs, |s, &co| {
|
||||
s.print_symbol(co, ast::StrStyle::Cooked);
|
||||
s.popen();
|
||||
s.print_expr(&a.inputs_exprs[in_idx]);
|
||||
s.pclose();
|
||||
in_idx += 1;
|
||||
});
|
||||
self.space();
|
||||
self.word_space(":");
|
||||
|
||||
self.commasep(Inconsistent, &i.clobbers, |s, &co| {
|
||||
s.print_symbol(co, ast::StrStyle::Cooked);
|
||||
});
|
||||
|
||||
let mut options = vec![];
|
||||
if i.volatile {
|
||||
options.push("volatile");
|
||||
}
|
||||
if i.alignstack {
|
||||
options.push("alignstack");
|
||||
}
|
||||
if i.dialect == ast::LlvmAsmDialect::Intel {
|
||||
options.push("intel");
|
||||
}
|
||||
|
||||
if !options.is_empty() {
|
||||
self.space();
|
||||
self.word_space(":");
|
||||
self.commasep(Inconsistent, &options, |s, &co| {
|
||||
s.print_string(co, ast::StrStyle::Cooked);
|
||||
});
|
||||
}
|
||||
|
||||
self.pclose();
|
||||
}
|
||||
hir::ExprKind::Yield(ref expr, _) => {
|
||||
self.word_space("yield");
|
||||
self.print_expr_maybe_paren(&expr, parser::PREC_JUMP);
|
||||
|
@ -1565,10 +1565,6 @@ pub enum StatementKind<'tcx> {
|
||||
/// End the current live range for the storage of the local.
|
||||
StorageDead(Local),
|
||||
|
||||
/// Executes a piece of inline Assembly. Stored in a Box to keep the size
|
||||
/// of `StatementKind` low.
|
||||
LlvmInlineAsm(Box<LlvmInlineAsm<'tcx>>),
|
||||
|
||||
/// Retag references in the given place, ensuring they got fresh tags. This is
|
||||
/// part of the Stacked Borrows model. These statements are currently only interpreted
|
||||
/// by miri and only generated when "-Z mir-emit-retag" is passed.
|
||||
@ -1688,13 +1684,6 @@ pub enum FakeReadCause {
|
||||
ForIndex,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable)]
|
||||
pub struct LlvmInlineAsm<'tcx> {
|
||||
pub asm: hir::LlvmInlineAsmInner,
|
||||
pub outputs: Box<[Place<'tcx>]>,
|
||||
pub inputs: Box<[(Span, Operand<'tcx>)]>,
|
||||
}
|
||||
|
||||
impl Debug for Statement<'_> {
|
||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||
use self::StatementKind::*;
|
||||
@ -1719,9 +1708,6 @@ impl Debug for Statement<'_> {
|
||||
SetDiscriminant { ref place, variant_index } => {
|
||||
write!(fmt, "discriminant({:?}) = {:?}", place, variant_index)
|
||||
}
|
||||
LlvmInlineAsm(ref asm) => {
|
||||
write!(fmt, "llvm_asm!({:?} : {:?} : {:?})", asm.asm, asm.outputs, asm.inputs)
|
||||
}
|
||||
AscribeUserType(box (ref place, ref c_ty), ref variance) => {
|
||||
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
|
||||
}
|
||||
|
@ -245,7 +245,6 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
|
||||
SetDiscriminant { .. } => "SetDiscriminant",
|
||||
StorageLive(..) => "StorageLive",
|
||||
StorageDead(..) => "StorageDead",
|
||||
LlvmInlineAsm(..) => "LlvmInlineAsm",
|
||||
Retag(..) => "Retag",
|
||||
AscribeUserType(..) => "AscribeUserType",
|
||||
Coverage(..) => "Coverage",
|
||||
|
@ -408,19 +408,6 @@ macro_rules! make_mir_visitor {
|
||||
location
|
||||
);
|
||||
}
|
||||
StatementKind::LlvmInlineAsm(asm) => {
|
||||
for output in & $($mutability)? asm.outputs[..] {
|
||||
self.visit_place(
|
||||
output,
|
||||
PlaceContext::MutatingUse(MutatingUseContext::LlvmAsmOutput),
|
||||
location
|
||||
);
|
||||
}
|
||||
for (span, input) in & $($mutability)? asm.inputs[..] {
|
||||
self.visit_span(span);
|
||||
self.visit_operand(input, location);
|
||||
}
|
||||
}
|
||||
StatementKind::Retag(kind, place) => {
|
||||
self.visit_retag(kind, place, location);
|
||||
}
|
||||
@ -1178,10 +1165,6 @@ pub enum NonMutatingUseContext {
|
||||
pub enum MutatingUseContext {
|
||||
/// Appears as LHS of an assignment.
|
||||
Store,
|
||||
/// Can often be treated as a `Store`, but needs to be separate because
|
||||
/// ASM is allowed to read outputs as well, so a `Store`-`LlvmAsmOutput` sequence
|
||||
/// cannot be simplified the way a `Store`-`Store` can be.
|
||||
LlvmAsmOutput,
|
||||
/// Output operand of an inline assembly block.
|
||||
AsmOutput,
|
||||
/// Destination of a call.
|
||||
@ -1271,7 +1254,6 @@ impl PlaceContext {
|
||||
PlaceContext::MutatingUse(
|
||||
MutatingUseContext::Store
|
||||
| MutatingUseContext::Call
|
||||
| MutatingUseContext::LlvmAsmOutput
|
||||
| MutatingUseContext::AsmOutput,
|
||||
)
|
||||
)
|
||||
|
@ -431,12 +431,6 @@ pub enum ExprKind<'tcx> {
|
||||
},
|
||||
/// An expression taking a reference to a thread local.
|
||||
ThreadLocalRef(DefId),
|
||||
/// Inline LLVM assembly, i.e. `llvm_asm!()`.
|
||||
LlvmInlineAsm {
|
||||
asm: &'tcx hir::LlvmInlineAsmInner,
|
||||
outputs: Box<[ExprId]>,
|
||||
inputs: Box<[ExprId]>,
|
||||
},
|
||||
/// A `yield` expression.
|
||||
Yield {
|
||||
value: ExprId,
|
||||
|
@ -145,14 +145,6 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
|
||||
}
|
||||
}
|
||||
ThreadLocalRef(_) => {}
|
||||
LlvmInlineAsm { ref outputs, ref inputs, asm: _ } => {
|
||||
for &out_expr in &**outputs {
|
||||
visitor.visit_expr(&visitor.thir()[out_expr]);
|
||||
}
|
||||
for &in_expr in &**inputs {
|
||||
visitor.visit_expr(&visitor.thir()[in_expr]);
|
||||
}
|
||||
}
|
||||
Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
|
||||
}
|
||||
}
|
||||
|
@ -225,7 +225,6 @@ TrivialTypeFoldableAndLiftImpls! {
|
||||
::rustc_hir::def_id::DefId,
|
||||
::rustc_hir::def_id::LocalDefId,
|
||||
::rustc_hir::HirId,
|
||||
::rustc_hir::LlvmInlineAsmInner,
|
||||
::rustc_hir::MatchSource,
|
||||
::rustc_hir::Mutability,
|
||||
::rustc_hir::Unsafety,
|
||||
|
@ -570,7 +570,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
| ExprKind::ConstBlock { .. }
|
||||
| ExprKind::StaticRef { .. }
|
||||
| ExprKind::InlineAsm { .. }
|
||||
| ExprKind::LlvmInlineAsm { .. }
|
||||
| ExprKind::Yield { .. }
|
||||
| ExprKind::ThreadLocalRef(_)
|
||||
| ExprKind::Call { .. } => {
|
||||
|
@ -350,7 +350,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
| ExprKind::Continue { .. }
|
||||
| ExprKind::Return { .. }
|
||||
| ExprKind::InlineAsm { .. }
|
||||
| ExprKind::LlvmInlineAsm { .. }
|
||||
| ExprKind::PlaceTypeAscription { .. }
|
||||
| ExprKind::ValueTypeAscription { .. } => {
|
||||
// these do not have corresponding `Rvalue` variants,
|
||||
|
@ -67,8 +67,7 @@ impl Category {
|
||||
| ExprKind::Repeat { .. }
|
||||
| ExprKind::Assign { .. }
|
||||
| ExprKind::AssignOp { .. }
|
||||
| ExprKind::ThreadLocalRef(_)
|
||||
| ExprKind::LlvmInlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
|
||||
| ExprKind::ThreadLocalRef(_) => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
|
||||
|
||||
ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => {
|
||||
Some(Category::Constant)
|
||||
|
@ -477,9 +477,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
}
|
||||
|
||||
// These cases don't actually need a destination
|
||||
ExprKind::Assign { .. }
|
||||
| ExprKind::AssignOp { .. }
|
||||
| ExprKind::LlvmInlineAsm { .. } => {
|
||||
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
|
||||
unpack!(block = this.stmt_expr(block, expr, None));
|
||||
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
|
||||
block.unit()
|
||||
|
@ -101,38 +101,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||
BreakableTarget::Return,
|
||||
source_info,
|
||||
),
|
||||
ExprKind::LlvmInlineAsm { asm, ref outputs, ref inputs } => {
|
||||
debug!("stmt_expr LlvmInlineAsm block_context.push(SubExpr) : {:?}", expr);
|
||||
this.block_context.push(BlockFrame::SubExpr);
|
||||
let outputs = outputs
|
||||
.into_iter()
|
||||
.copied()
|
||||
.map(|output| unpack!(block = this.as_place(block, &this.thir[output])))
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice();
|
||||
let inputs = inputs
|
||||
.into_iter()
|
||||
.copied()
|
||||
.map(|input| {
|
||||
let input = &this.thir[input];
|
||||
(input.span, unpack!(block = this.as_local_operand(block, &input)))
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.into_boxed_slice();
|
||||
this.cfg.push(
|
||||
block,
|
||||
Statement {
|
||||
source_info,
|
||||
kind: StatementKind::LlvmInlineAsm(Box::new(LlvmInlineAsm {
|
||||
asm: asm.clone(),
|
||||
outputs,
|
||||
inputs,
|
||||
})),
|
||||
},
|
||||
);
|
||||
this.block_context.pop();
|
||||
block.unit()
|
||||
}
|
||||
_ => {
|
||||
assert!(
|
||||
statement_scope.is_some(),
|
||||
|
@ -329,7 +329,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
| ExprKind::Box { .. }
|
||||
| ExprKind::If { .. }
|
||||
| ExprKind::InlineAsm { .. }
|
||||
| ExprKind::LlvmInlineAsm { .. }
|
||||
| ExprKind::LogicalOp { .. }
|
||||
| ExprKind::Use { .. } => {
|
||||
// We don't need to save the old value and restore it
|
||||
@ -377,7 +376,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||
self.requires_unsafe(expr.span, DerefOfRawPointer);
|
||||
}
|
||||
}
|
||||
ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
|
||||
ExprKind::InlineAsm { .. } => {
|
||||
self.requires_unsafe(expr.span, UseOfInlineAssembly);
|
||||
}
|
||||
ExprKind::Adt(box Adt {
|
||||
|
@ -570,12 +570,6 @@ impl<'tcx> Cx<'tcx> {
|
||||
line_spans: asm.line_spans,
|
||||
},
|
||||
|
||||
hir::ExprKind::LlvmInlineAsm(ref asm) => ExprKind::LlvmInlineAsm {
|
||||
asm: &asm.inner,
|
||||
outputs: self.mirror_exprs(asm.outputs_exprs),
|
||||
inputs: self.mirror_exprs(asm.inputs_exprs),
|
||||
},
|
||||
|
||||
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
|
||||
let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
|
||||
|
@ -176,7 +176,6 @@ impl DefUse {
|
||||
// All other contexts are uses...
|
||||
PlaceContext::MutatingUse(
|
||||
MutatingUseContext::AddressOf
|
||||
| MutatingUseContext::LlvmAsmOutput
|
||||
| MutatingUseContext::Borrow
|
||||
| MutatingUseContext::Drop
|
||||
| MutatingUseContext::Retag,
|
||||
|
@ -134,11 +134,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||
| StatementKind::SetDiscriminant { box place, .. } => {
|
||||
trans.gen(place.local);
|
||||
}
|
||||
StatementKind::LlvmInlineAsm(asm) => {
|
||||
for place in &*asm.outputs {
|
||||
trans.gen(place.local);
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||
// variants are added.
|
||||
|
@ -4,7 +4,6 @@ use rustc_middle::mir::*;
|
||||
use rustc_middle::ty::{self, TyCtxt};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use std::iter;
|
||||
use std::mem;
|
||||
|
||||
use super::abs_domain::Lift;
|
||||
@ -293,16 +292,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||
StatementKind::FakeRead(box (_, place)) => {
|
||||
self.create_move_path(*place);
|
||||
}
|
||||
StatementKind::LlvmInlineAsm(ref asm) => {
|
||||
for (output, kind) in iter::zip(&*asm.outputs, &asm.asm.outputs) {
|
||||
if !kind.is_indirect {
|
||||
self.gather_init(output.as_ref(), InitKind::Deep);
|
||||
}
|
||||
}
|
||||
for (_, input) in asm.inputs.iter() {
|
||||
self.gather_operand(input);
|
||||
}
|
||||
}
|
||||
StatementKind::StorageLive(_) => {}
|
||||
StatementKind::StorageDead(local) => {
|
||||
self.gather_move(Place::from(*local));
|
||||
|
@ -104,10 +104,6 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
||||
// safe (at least as emitted during MIR construction)
|
||||
}
|
||||
|
||||
StatementKind::LlvmInlineAsm { .. } => self.require_unsafe(
|
||||
UnsafetyViolationKind::General,
|
||||
UnsafetyViolationDetails::UseOfInlineAssembly,
|
||||
),
|
||||
StatementKind::CopyNonOverlapping(..) => unreachable!(),
|
||||
}
|
||||
self.super_statement(statement, location);
|
||||
@ -208,7 +204,6 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
||||
MutatingUseContext::Store
|
||||
| MutatingUseContext::Drop
|
||||
| MutatingUseContext::AsmOutput
|
||||
| MutatingUseContext::LlvmAsmOutput
|
||||
)
|
||||
);
|
||||
// If this is just an assignment, determine if the assigned type needs dropping.
|
||||
|
@ -1035,8 +1035,7 @@ impl Visitor<'_> for CanConstProp {
|
||||
|
||||
// These could be propagated with a smarter analysis or just some careful thinking about
|
||||
// whether they'd be fine right now.
|
||||
MutatingUse(MutatingUseContext::LlvmAsmOutput)
|
||||
| MutatingUse(MutatingUseContext::Yield)
|
||||
MutatingUse(MutatingUseContext::Yield)
|
||||
| MutatingUse(MutatingUseContext::Drop)
|
||||
| MutatingUse(MutatingUseContext::Retag)
|
||||
// These can't ever be propagated under any scheme, as we can't reason about indirect
|
||||
|
@ -835,7 +835,6 @@ pub(super) fn filtered_statement_span(statement: &Statement<'_>) -> Option<Span>
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Assign(_)
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::LlvmInlineAsm(_)
|
||||
| StatementKind::Retag(_, _)
|
||||
| StatementKind::AscribeUserType(_, _) => {
|
||||
Some(statement.source_info.span)
|
||||
|
@ -534,25 +534,6 @@ impl<'a> Conflicts<'a> {
|
||||
// eliminate the resulting self-assignments automatically.
|
||||
StatementKind::Assign(_) => {}
|
||||
|
||||
StatementKind::LlvmInlineAsm(asm) => {
|
||||
// Inputs and outputs must not overlap.
|
||||
for (_, input) in &*asm.inputs {
|
||||
if let Some(in_place) = input.place() {
|
||||
if !in_place.is_indirect() {
|
||||
for out_place in &*asm.outputs {
|
||||
if !out_place.is_indirect() && !in_place.is_indirect() {
|
||||
self.record_local_conflict(
|
||||
in_place.local,
|
||||
out_place.local,
|
||||
"aliasing llvm_asm! operands",
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::StorageLive(..)
|
||||
| StatementKind::StorageDead(..)
|
||||
|
@ -1449,9 +1449,6 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
||||
self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
|
||||
}
|
||||
|
||||
// FIXME: Does `llvm_asm!` have any aliasing requirements?
|
||||
StatementKind::LlvmInlineAsm(_) => {}
|
||||
|
||||
StatementKind::FakeRead(..)
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::StorageLive(_)
|
||||
|
@ -50,7 +50,6 @@ impl RemoveNoopLandingPads {
|
||||
|
||||
StatementKind::Assign { .. }
|
||||
| StatementKind::SetDiscriminant { .. }
|
||||
| StatementKind::LlvmInlineAsm { .. }
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Retag { .. } => {
|
||||
return false;
|
||||
|
@ -239,10 +239,6 @@ fn is_likely_const<'tcx>(mut tracked_place: Place<'tcx>, block: &BasicBlockData<
|
||||
}
|
||||
}
|
||||
|
||||
// If inline assembly is found, we probably should
|
||||
// not try to analyze the code
|
||||
StatementKind::LlvmInlineAsm(_) => return false,
|
||||
|
||||
// These statements have no influence on the place
|
||||
// we are interested in
|
||||
StatementKind::FakeRead(_)
|
||||
@ -320,10 +316,6 @@ fn find_determining_place<'tcx>(
|
||||
| StatementKind::CopyNonOverlapping(_)
|
||||
| StatementKind::Nop => {}
|
||||
|
||||
// If inline assembly is found, we probably should
|
||||
// not try to analyze the code
|
||||
StatementKind::LlvmInlineAsm(_) => return None,
|
||||
|
||||
// If the discriminant is set, it is always set
|
||||
// as a constant, so the job is already done.
|
||||
// As we are **ignoring projections**, if the place
|
||||
|
@ -483,8 +483,7 @@ impl UsedLocals {
|
||||
impl<'tcx> Visitor<'tcx> for UsedLocals {
|
||||
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||
match statement.kind {
|
||||
StatementKind::LlvmInlineAsm(..)
|
||||
| StatementKind::CopyNonOverlapping(..)
|
||||
StatementKind::CopyNonOverlapping(..)
|
||||
| StatementKind::Retag(..)
|
||||
| StatementKind::Coverage(..)
|
||||
| StatementKind::FakeRead(..)
|
||||
|
@ -631,10 +631,6 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
|
||||
.filter(|(_, bb)| {
|
||||
// Reaching `unreachable` is UB so assume it doesn't happen.
|
||||
bb.terminator().kind != TerminatorKind::Unreachable
|
||||
// But `asm!(...)` could abort the program,
|
||||
// so we cannot assume that the `unreachable` terminator itself is reachable.
|
||||
// FIXME(Centril): use a normalization pass instead of a check.
|
||||
|| bb.statements.iter().any(|stmt| matches!(stmt.kind, StatementKind::LlvmInlineAsm(..)))
|
||||
})
|
||||
.peekable();
|
||||
|
||||
|
@ -23,23 +23,14 @@ impl MirPass<'_> for UnreachablePropagation {
|
||||
|
||||
for (bb, bb_data) in traversal::postorder(body) {
|
||||
let terminator = bb_data.terminator();
|
||||
// HACK: If the block contains any asm statement it is not regarded as unreachable.
|
||||
// This is a temporary solution that handles possibly diverging asm statements.
|
||||
// Accompanying testcases: mir-opt/unreachable_asm.rs and mir-opt/unreachable_asm_2.rs
|
||||
let asm_stmt_in_block = || {
|
||||
bb_data.statements.iter().any(|stmt: &Statement<'_>| {
|
||||
matches!(stmt.kind, StatementKind::LlvmInlineAsm(..))
|
||||
})
|
||||
};
|
||||
|
||||
if terminator.kind == TerminatorKind::Unreachable && !asm_stmt_in_block() {
|
||||
if terminator.kind == TerminatorKind::Unreachable {
|
||||
unreachable_blocks.insert(bb);
|
||||
} else {
|
||||
let is_unreachable = |succ: BasicBlock| unreachable_blocks.contains(&succ);
|
||||
let terminator_kind_opt = remove_successors(&terminator.kind, is_unreachable);
|
||||
|
||||
if let Some(terminator_kind) = terminator_kind_opt {
|
||||
if terminator_kind == TerminatorKind::Unreachable && !asm_stmt_in_block() {
|
||||
if terminator_kind == TerminatorKind::Unreachable {
|
||||
unreachable_blocks.insert(bb);
|
||||
}
|
||||
replacements.insert(bb, terminator_kind);
|
||||
|
@ -103,7 +103,6 @@ use rustc_span::Span;
|
||||
use std::collections::VecDeque;
|
||||
use std::io;
|
||||
use std::io::prelude::*;
|
||||
use std::iter;
|
||||
use std::rc::Rc;
|
||||
|
||||
mod rwu_table;
|
||||
@ -470,7 +469,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
|
||||
| hir::ExprKind::Struct(..)
|
||||
| hir::ExprKind::Repeat(..)
|
||||
| hir::ExprKind::InlineAsm(..)
|
||||
| hir::ExprKind::LlvmInlineAsm(..)
|
||||
| hir::ExprKind::Box(..)
|
||||
| hir::ExprKind::Type(..)
|
||||
| hir::ExprKind::Err
|
||||
@ -1091,26 +1089,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||
succ
|
||||
}
|
||||
|
||||
hir::ExprKind::LlvmInlineAsm(ref asm) => {
|
||||
let ia = &asm.inner;
|
||||
let outputs = asm.outputs_exprs;
|
||||
let inputs = asm.inputs_exprs;
|
||||
let succ = iter::zip(&ia.outputs, outputs).rev().fold(succ, |succ, (o, output)| {
|
||||
// see comment on places
|
||||
// in propagate_through_place_components()
|
||||
if o.is_indirect {
|
||||
self.propagate_through_expr(output, succ)
|
||||
} else {
|
||||
let acc = if o.is_rw { ACC_WRITE | ACC_READ } else { ACC_WRITE };
|
||||
let succ = self.write_place(output, succ, acc);
|
||||
self.propagate_through_place_components(output, succ)
|
||||
}
|
||||
});
|
||||
|
||||
// Inputs are executed first. Propagate last because of rev order
|
||||
self.propagate_through_exprs(inputs, succ)
|
||||
}
|
||||
|
||||
hir::ExprKind::Lit(..)
|
||||
| hir::ExprKind::ConstBlock(..)
|
||||
| hir::ExprKind::Err
|
||||
@ -1387,20 +1365,6 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprKind::LlvmInlineAsm(ref asm) => {
|
||||
for input in asm.inputs_exprs {
|
||||
this.visit_expr(input);
|
||||
}
|
||||
|
||||
// Output operands must be places
|
||||
for (o, output) in iter::zip(&asm.inner.outputs, asm.outputs_exprs) {
|
||||
if !o.is_indirect {
|
||||
this.check_place(output);
|
||||
}
|
||||
this.visit_expr(output);
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprKind::Let(let_expr) => {
|
||||
this.check_unused_vars_in_pat(let_expr.pat, None, |_, _, _, _| {});
|
||||
}
|
||||
|
@ -236,22 +236,6 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
|
||||
self.check_inline_asm(expr.hir_id, asm, span);
|
||||
}
|
||||
|
||||
ExprKind::LlvmInlineAsm(..) => {
|
||||
self.items.push((ItemKind::Asm, span));
|
||||
self.tcx.struct_span_lint_hir(
|
||||
UNSUPPORTED_NAKED_FUNCTIONS,
|
||||
expr.hir_id,
|
||||
span,
|
||||
|lint| {
|
||||
lint.build(
|
||||
"the LLVM-style inline assembly is unsupported in naked functions",
|
||||
)
|
||||
.help("use the new asm! syntax specified in RFC 2873")
|
||||
.emit();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
|
||||
hir::intravisit::walk_expr(self, expr);
|
||||
}
|
||||
|
@ -786,7 +786,6 @@ symbols! {
|
||||
linkage,
|
||||
lint_reasons,
|
||||
literal,
|
||||
llvm_asm,
|
||||
load,
|
||||
loaded_from_disk,
|
||||
local,
|
||||
|
@ -480,7 +480,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
||||
// let expressions imply control flow
|
||||
ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } =>
|
||||
self.error(node.span, "control flow is not supported in generic constants")?,
|
||||
ExprKind::LlvmInlineAsm { .. } | ExprKind::InlineAsm { .. } => {
|
||||
ExprKind::InlineAsm { .. } => {
|
||||
self.error(node.span, "assembly is not supported in generic constants")?
|
||||
}
|
||||
|
||||
|
@ -282,12 +282,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
||||
}
|
||||
ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]),
|
||||
ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
|
||||
ExprKind::LlvmInlineAsm(asm) => {
|
||||
for expr in asm.outputs_exprs.iter().chain(asm.inputs_exprs.iter()) {
|
||||
self.check_expr(expr);
|
||||
}
|
||||
tcx.mk_unit()
|
||||
}
|
||||
ExprKind::Break(destination, ref expr_opt) => {
|
||||
self.check_expr_break(destination, expr_opt.as_deref(), expr)
|
||||
}
|
||||
|
@ -17,7 +17,6 @@ use rustc_middle::hir::place::ProjectionKind;
|
||||
use rustc_middle::mir::FakeReadCause;
|
||||
use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
|
||||
use rustc_target::abi::VariantIdx;
|
||||
use std::iter;
|
||||
|
||||
use crate::mem_categorization as mc;
|
||||
|
||||
@ -360,17 +359,6 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
hir::ExprKind::LlvmInlineAsm(ia) => {
|
||||
for (o, output) in iter::zip(&ia.inner.outputs, ia.outputs_exprs) {
|
||||
if o.is_indirect {
|
||||
self.consume_expr(output);
|
||||
} else {
|
||||
self.mutate_expr(output);
|
||||
}
|
||||
}
|
||||
self.consume_exprs(ia.inputs_exprs);
|
||||
}
|
||||
|
||||
hir::ExprKind::Continue(..)
|
||||
| hir::ExprKind::Lit(..)
|
||||
| hir::ExprKind::ConstBlock(..)
|
||||
|
@ -378,7 +378,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||
| hir::ExprKind::Struct(..)
|
||||
| hir::ExprKind::Repeat(..)
|
||||
| hir::ExprKind::InlineAsm(..)
|
||||
| hir::ExprKind::LlvmInlineAsm(..)
|
||||
| hir::ExprKind::Box(..)
|
||||
| hir::ExprKind::Err => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
|
||||
}
|
||||
|
@ -180,7 +180,6 @@
|
||||
#![feature(intrinsics)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(link_llvm_intrinsics)]
|
||||
#![feature(llvm_asm)]
|
||||
#![feature(min_specialization)]
|
||||
#![feature(mixed_integer_ops)]
|
||||
#![feature(must_not_suspend)]
|
||||
|
@ -1373,32 +1373,6 @@ pub(crate) mod builtin {
|
||||
($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }};
|
||||
}
|
||||
|
||||
/// LLVM-style inline assembly.
|
||||
///
|
||||
/// Read the [unstable book] for the usage.
|
||||
///
|
||||
/// [unstable book]: ../unstable-book/library-features/llvm-asm.html
|
||||
#[unstable(
|
||||
feature = "llvm_asm",
|
||||
issue = "70173",
|
||||
reason = "prefer using the new asm! syntax instead"
|
||||
)]
|
||||
#[rustc_deprecated(
|
||||
since = "1.56",
|
||||
reason = "will be removed from the compiler, use asm! instead"
|
||||
)]
|
||||
#[rustc_builtin_macro]
|
||||
#[macro_export]
|
||||
macro_rules! llvm_asm {
|
||||
("assembly template"
|
||||
: $("output"(operand),)*
|
||||
: $("input"(operand),)*
|
||||
: $("clobbers",)*
|
||||
: $("options",)*) => {
|
||||
/* compiler built-in */
|
||||
};
|
||||
}
|
||||
|
||||
/// Prints passed tokens into the standard output.
|
||||
#[unstable(
|
||||
feature = "log_syntax",
|
||||
|
@ -56,8 +56,8 @@ pub use crate::hash::macros::Hash;
|
||||
#[doc(no_inline)]
|
||||
pub use crate::{
|
||||
assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
|
||||
format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path,
|
||||
option_env, stringify, trace_macros,
|
||||
format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
|
||||
stringify, trace_macros,
|
||||
};
|
||||
|
||||
#[unstable(
|
||||
|
@ -294,7 +294,6 @@
|
||||
#![feature(intra_doc_pointers)]
|
||||
#![feature(lang_items)]
|
||||
#![feature(linkage)]
|
||||
#![feature(llvm_asm)]
|
||||
#![feature(log_syntax)]
|
||||
#![feature(map_try_insert)]
|
||||
#![feature(maybe_uninit_extra)]
|
||||
@ -572,8 +571,8 @@ pub use core::{
|
||||
#[allow(deprecated)]
|
||||
pub use core::{
|
||||
assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args,
|
||||
env, file, format_args, format_args_nl, include, include_bytes, include_str, line, llvm_asm,
|
||||
log_syntax, module_path, option_env, stringify, trace_macros,
|
||||
env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
|
||||
module_path, option_env, stringify, trace_macros,
|
||||
};
|
||||
|
||||
#[unstable(
|
||||
|
@ -40,9 +40,8 @@ pub use crate::result::Result::{self, Err, Ok};
|
||||
#[doc(no_inline)]
|
||||
pub use core::prelude::v1::{
|
||||
assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
|
||||
format_args_nl, include, include_bytes, include_str, line, llvm_asm, log_syntax, module_path,
|
||||
option_env, stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq,
|
||||
PartialOrd,
|
||||
format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
|
||||
stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
|
||||
};
|
||||
|
||||
#[unstable(
|
||||
|
Loading…
Reference in New Issue
Block a user