Remove deprecated LLVM-style inline assembly

This commit is contained in:
Tomasz Miąsko 2022-01-12 00:00:00 +00:00
parent 72e74d7b9c
commit 000b36c505
68 changed files with 27 additions and 1132 deletions

View File

@ -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)`.

View File

@ -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();

View File

@ -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);
}

View File

@ -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(),

View File

@ -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 {

View File

@ -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();

View File

@ -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(..)

View File

@ -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

View File

@ -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,

View File

@ -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 {
..
}) => {

View File

@ -1477,7 +1477,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
StatementKind::FakeRead(..)
| StatementKind::StorageLive(..)
| StatementKind::StorageDead(..)
| StatementKind::LlvmInlineAsm { .. }
| StatementKind::Retag { .. }
| StatementKind::Coverage(..)
| StatementKind::Nop => {}

View File

@ -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],

View File

@ -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,

View File

@ -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,
}))
}

View File

@ -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);

View File

@ -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(_)

View File

@ -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()

View File

@ -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.
//

View File

@ -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,

View File

@ -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)]

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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;

View File

@ -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(..)

View File

@ -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 => {}

View File

@ -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>,

View File

@ -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> {

View File

@ -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);
}

View File

@ -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);

View File

@ -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)
}

View File

@ -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",

View File

@ -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,
)
)

View File

@ -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,

View File

@ -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]),
}
}

View File

@ -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,

View File

@ -570,7 +570,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::ConstBlock { .. }
| ExprKind::StaticRef { .. }
| ExprKind::InlineAsm { .. }
| ExprKind::LlvmInlineAsm { .. }
| ExprKind::Yield { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::Call { .. } => {

View File

@ -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,

View File

@ -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)

View File

@ -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()

View File

@ -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(),

View File

@ -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 {

View File

@ -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);

View File

@ -176,7 +176,6 @@ impl DefUse {
// All other contexts are uses...
PlaceContext::MutatingUse(
MutatingUseContext::AddressOf
| MutatingUseContext::LlvmAsmOutput
| MutatingUseContext::Borrow
| MutatingUseContext::Drop
| MutatingUseContext::Retag,

View File

@ -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.

View File

@ -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));

View File

@ -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.

View File

@ -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

View File

@ -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)

View File

@ -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(..)

View File

@ -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(_)

View File

@ -50,7 +50,6 @@ impl RemoveNoopLandingPads {
StatementKind::Assign { .. }
| StatementKind::SetDiscriminant { .. }
| StatementKind::LlvmInlineAsm { .. }
| StatementKind::CopyNonOverlapping(..)
| StatementKind::Retag { .. } => {
return false;

View File

@ -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

View File

@ -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(..)

View File

@ -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();

View File

@ -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);

View File

@ -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, |_, _, _, _| {});
}

View File

@ -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);
}

View File

@ -786,7 +786,6 @@ symbols! {
linkage,
lint_reasons,
literal,
llvm_asm,
load,
loaded_from_disk,
local,

View File

@ -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")?
}

View File

@ -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)
}

View File

@ -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(..)

View File

@ -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)),
}

View File

@ -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)]

View File

@ -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",

View File

@ -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(

View File

@ -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(

View File

@ -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(