Remove deprecated LLVM-style inline assembly
This commit is contained in:
parent
72e74d7b9c
commit
000b36c505
68 changed files with 27 additions and 1132 deletions
|
@ -1266,7 +1266,7 @@ impl Expr {
|
||||||
ExprKind::Break(..) => ExprPrecedence::Break,
|
ExprKind::Break(..) => ExprPrecedence::Break,
|
||||||
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
||||||
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
||||||
ExprKind::InlineAsm(..) | ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
|
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
|
||||||
ExprKind::MacCall(..) => ExprPrecedence::Mac,
|
ExprKind::MacCall(..) => ExprPrecedence::Mac,
|
||||||
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
||||||
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
||||||
|
@ -1423,8 +1423,6 @@ pub enum ExprKind {
|
||||||
|
|
||||||
/// Output of the `asm!()` macro.
|
/// Output of the `asm!()` macro.
|
||||||
InlineAsm(P<InlineAsm>),
|
InlineAsm(P<InlineAsm>),
|
||||||
/// Output of the `llvm_asm!()` macro.
|
|
||||||
LlvmInlineAsm(P<LlvmInlineAsm>),
|
|
||||||
|
|
||||||
/// A macro invocation; pre-expansion.
|
/// A macro invocation; pre-expansion.
|
||||||
MacCall(MacCall),
|
MacCall(MacCall),
|
||||||
|
@ -2076,41 +2074,6 @@ pub struct InlineAsm {
|
||||||
pub line_spans: Vec<Span>,
|
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.
|
/// A parameter in a function header.
|
||||||
///
|
///
|
||||||
/// E.g., `bar: usize` as in `fn foo(bar: usize)`.
|
/// 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));
|
visit_opt(expr, |expr| vis.visit_expr(expr));
|
||||||
}
|
}
|
||||||
ExprKind::InlineAsm(asm) => noop_visit_inline_asm(asm, vis),
|
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::MacCall(mac) => vis.visit_mac_call(mac),
|
||||||
ExprKind::Struct(se) => {
|
ExprKind::Struct(se) => {
|
||||||
let StructExpr { qself, path, fields, rest } = se.deref_mut();
|
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::MacCall(ref mac) => visitor.visit_mac_call(mac),
|
||||||
ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
|
ExprKind::Paren(ref subexpression) => visitor.visit_expr(subexpression),
|
||||||
ExprKind::InlineAsm(ref asm) => walk_inline_asm(visitor, asm),
|
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) => {
|
ExprKind::Yield(ref optional_expression) => {
|
||||||
walk_list!(visitor, visit_expr, optional_expression);
|
walk_list!(visitor, visit_expr, optional_expression);
|
||||||
}
|
}
|
||||||
|
|
|
@ -226,7 +226,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
ExprKind::InlineAsm(ref asm) => {
|
ExprKind::InlineAsm(ref asm) => {
|
||||||
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, 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) => {
|
ExprKind::Struct(ref se) => {
|
||||||
let rest = match &se.rest {
|
let rest = match &se.rest {
|
||||||
StructRest::Base(e) => Some(self.lower_expr(e)),
|
StructRest::Base(e) => Some(self.lower_expr(e)),
|
||||||
|
@ -1284,38 +1283,6 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
result
|
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> {
|
fn lower_expr_field(&mut self, f: &ExprField) -> hir::ExprField<'hir> {
|
||||||
hir::ExprField {
|
hir::ExprField {
|
||||||
hir_id: self.next_id(),
|
hir_id: self.next_id(),
|
||||||
|
|
|
@ -960,15 +960,6 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ExprKind::Let(..) if !let_allowed => this.ban_let_expr(expr),
|
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) => {
|
ExprKind::Match(expr, arms) => {
|
||||||
this.visit_expr(expr);
|
this.visit_expr(expr);
|
||||||
for arm in arms {
|
for arm in arms {
|
||||||
|
|
|
@ -2168,62 +2168,6 @@ impl<'a> State<'a> {
|
||||||
self.word("asm!");
|
self.word("asm!");
|
||||||
self.print_inline_asm(a);
|
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::MacCall(ref m) => self.print_mac(m),
|
||||||
ast::ExprKind::Paren(ref e) => {
|
ast::ExprKind::Paren(ref e) => {
|
||||||
self.popen();
|
self.popen();
|
||||||
|
|
|
@ -8,7 +8,6 @@ use rustc_mir_dataflow::ResultsVisitable;
|
||||||
use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
|
use rustc_mir_dataflow::{self, fmt::DebugWithContext, CallReturnPlaces, GenKill};
|
||||||
use rustc_mir_dataflow::{Analysis, Direction, Results};
|
use rustc_mir_dataflow::{Analysis, Direction, Results};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid,
|
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));
|
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::FakeRead(..)
|
||||||
| mir::StatementKind::SetDiscriminant { .. }
|
| mir::StatementKind::SetDiscriminant { .. }
|
||||||
| mir::StatementKind::StorageLive(..)
|
| mir::StatementKind::StorageLive(..)
|
||||||
|
|
|
@ -16,9 +16,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
|
||||||
|
|
||||||
PlaceContext::MutatingUse(MutatingUseContext::Store) |
|
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
|
// We let Call define the result in both the success and
|
||||||
// unwind cases. This is not really correct, however it
|
// unwind cases. This is not really correct, however it
|
||||||
// does not seem to be observable due to the way that we
|
// 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::{InlineAsmOperand, Terminator, TerminatorKind};
|
||||||
use rustc_middle::mir::{Statement, StatementKind};
|
use rustc_middle::mir::{Statement, StatementKind};
|
||||||
use rustc_middle::ty::TyCtxt;
|
use rustc_middle::ty::TyCtxt;
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth,
|
borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, path_utils::*, AccessDepth,
|
||||||
Activation, ArtificialField, BorrowIndex, Deep, JustWrite, LocalMutationIsAllowed, MutateMode,
|
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>(
|
pub(super) fn generate_invalidates<'tcx>(
|
||||||
|
@ -67,30 +66,6 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
StatementKind::SetDiscriminant { place, variant_index: _ } => {
|
StatementKind::SetDiscriminant { place, variant_index: _ } => {
|
||||||
self.mutate_place(location, **place, Shallow(None), JustWrite);
|
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 {
|
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||||
ref src,
|
ref src,
|
||||||
ref dst,
|
ref dst,
|
||||||
|
|
|
@ -40,7 +40,6 @@ use either::Either;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::iter;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
@ -55,7 +54,7 @@ use rustc_mir_dataflow::MoveDataParamEnv;
|
||||||
use self::diagnostics::{AccessKind, RegionName};
|
use self::diagnostics::{AccessKind, RegionName};
|
||||||
use self::location::LocationTable;
|
use self::location::LocationTable;
|
||||||
use self::prefixes::PrefixSet;
|
use self::prefixes::PrefixSet;
|
||||||
use self::MutateMode::{JustWrite, WriteAndRead};
|
use self::MutateMode::JustWrite;
|
||||||
use facts::AllFacts;
|
use facts::AllFacts;
|
||||||
|
|
||||||
use self::path_utils::*;
|
use self::path_utils::*;
|
||||||
|
@ -653,39 +652,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
StatementKind::SetDiscriminant { place, variant_index: _ } => {
|
StatementKind::SetDiscriminant { place, variant_index: _ } => {
|
||||||
self.mutate_place(location, (**place, span), Shallow(None), JustWrite, flow_state);
|
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 {
|
StatementKind::CopyNonOverlapping(box rustc_middle::mir::CopyNonOverlapping {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
|
|
|
@ -1477,7 +1477,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
|
||||||
StatementKind::FakeRead(..)
|
StatementKind::FakeRead(..)
|
||||||
| StatementKind::StorageLive(..)
|
| StatementKind::StorageLive(..)
|
||||||
| StatementKind::StorageDead(..)
|
| StatementKind::StorageDead(..)
|
||||||
| StatementKind::LlvmInlineAsm { .. }
|
|
||||||
| StatementKind::Retag { .. }
|
| StatementKind::Retag { .. }
|
||||||
| StatementKind::Coverage(..)
|
| StatementKind::Coverage(..)
|
||||||
| StatementKind::Nop => {}
|
| 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"));
|
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 first_template = p.parse_expr()?;
|
||||||
let mut args = AsmArgs {
|
let mut args = AsmArgs {
|
||||||
templates: vec![first_template],
|
templates: vec![first_template],
|
||||||
|
|
|
@ -33,7 +33,6 @@ mod env;
|
||||||
mod format;
|
mod format;
|
||||||
mod format_foreign;
|
mod format_foreign;
|
||||||
mod global_allocator;
|
mod global_allocator;
|
||||||
mod llvm_asm;
|
|
||||||
mod log_syntax;
|
mod log_syntax;
|
||||||
mod panic;
|
mod panic;
|
||||||
mod source_util;
|
mod source_util;
|
||||||
|
@ -78,7 +77,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
|
||||||
include_str: source_util::expand_include_str,
|
include_str: source_util::expand_include_str,
|
||||||
include: source_util::expand_include,
|
include: source_util::expand_include,
|
||||||
line: source_util::expand_line,
|
line: source_util::expand_line,
|
||||||
llvm_asm: llvm_asm::expand_llvm_asm,
|
|
||||||
log_syntax: log_syntax::expand_log_syntax,
|
log_syntax: log_syntax::expand_log_syntax,
|
||||||
module_path: source_util::expand_mod,
|
module_path: source_util::expand_mod,
|
||||||
option_env: env::expand_option_env,
|
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::Retag { .. }
|
||||||
| StatementKind::AscribeUserType(..) => {}
|
| 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::Coverage { .. } => fx.tcx.sess.fatal("-Zcoverage is unimplemented"),
|
||||||
StatementKind::CopyNonOverlapping(inner) => {
|
StatementKind::CopyNonOverlapping(inner) => {
|
||||||
let dst = codegen_operand(fx, &inner.dst);
|
let dst = codegen_operand(fx, &inner.dst);
|
||||||
|
|
|
@ -506,7 +506,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>(
|
||||||
{
|
{
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
StatementKind::LlvmInlineAsm(_) | StatementKind::CopyNonOverlapping(_) => {
|
StatementKind::CopyNonOverlapping(_) => {
|
||||||
return None;
|
return None;
|
||||||
} // conservative handling
|
} // conservative handling
|
||||||
StatementKind::Assign(_)
|
StatementKind::Assign(_)
|
||||||
|
|
|
@ -4,7 +4,6 @@ use rustc_codegen_ssa::mir::operand::OperandValue;
|
||||||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
use rustc_codegen_ssa::mir::place::PlaceRef;
|
||||||
use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
|
use rustc_codegen_ssa::traits::{AsmBuilderMethods, AsmMethods, BaseTypeMethods, BuilderMethods, GlobalAsmOperandRef, InlineAsmOperandRef};
|
||||||
|
|
||||||
use rustc_hir::LlvmInlineAsmInner;
|
|
||||||
use rustc_middle::{bug, ty::Instance};
|
use rustc_middle::{bug, ty::Instance};
|
||||||
use rustc_span::{Span, Symbol};
|
use rustc_span::{Span, Symbol};
|
||||||
use rustc_target::asm::*;
|
use rustc_target::asm::*;
|
||||||
|
@ -106,17 +105,6 @@ enum ConstraintOrRegister {
|
||||||
|
|
||||||
|
|
||||||
impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
|
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>)>) {
|
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) {
|
if options.contains(InlineAsmOptions::MAY_UNWIND) {
|
||||||
self.sess()
|
self.sess()
|
||||||
|
|
|
@ -7,13 +7,10 @@ use crate::type_::Type;
|
||||||
use crate::type_of::LayoutLlvmExt;
|
use crate::type_of::LayoutLlvmExt;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
use rustc_ast::LlvmAsmDialect;
|
|
||||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||||
use rustc_codegen_ssa::mir::operand::OperandValue;
|
use rustc_codegen_ssa::mir::operand::OperandValue;
|
||||||
use rustc_codegen_ssa::mir::place::PlaceRef;
|
|
||||||
use rustc_codegen_ssa::traits::*;
|
use rustc_codegen_ssa::traits::*;
|
||||||
use rustc_data_structures::fx::FxHashMap;
|
use rustc_data_structures::fx::FxHashMap;
|
||||||
use rustc_hir as hir;
|
|
||||||
use rustc_middle::ty::layout::TyAndLayout;
|
use rustc_middle::ty::layout::TyAndLayout;
|
||||||
use rustc_middle::{bug, span_bug, ty::Instance};
|
use rustc_middle::{bug, span_bug, ty::Instance};
|
||||||
use rustc_span::{Pos, Span, Symbol};
|
use rustc_span::{Pos, Span, Symbol};
|
||||||
|
@ -24,100 +21,6 @@ use libc::{c_char, c_uint};
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
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(
|
fn codegen_inline_asm(
|
||||||
&mut self,
|
&mut self,
|
||||||
template: &[InlineAsmTemplatePiece],
|
template: &[InlineAsmTemplatePiece],
|
||||||
|
@ -349,9 +252,9 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||||
InlineAsmArch::X86 | InlineAsmArch::X86_64
|
InlineAsmArch::X86 | InlineAsmArch::X86_64
|
||||||
if !options.contains(InlineAsmOptions::ATT_SYNTAX) =>
|
if !options.contains(InlineAsmOptions::ATT_SYNTAX) =>
|
||||||
{
|
{
|
||||||
LlvmAsmDialect::Intel
|
llvm::AsmDialect::Intel
|
||||||
}
|
}
|
||||||
_ => LlvmAsmDialect::Att,
|
_ => llvm::AsmDialect::Att,
|
||||||
};
|
};
|
||||||
let result = inline_asm_call(
|
let result = inline_asm_call(
|
||||||
self,
|
self,
|
||||||
|
@ -455,7 +358,7 @@ pub(crate) fn inline_asm_call<'ll>(
|
||||||
output: &'ll llvm::Type,
|
output: &'ll llvm::Type,
|
||||||
volatile: bool,
|
volatile: bool,
|
||||||
alignstack: bool,
|
alignstack: bool,
|
||||||
dia: LlvmAsmDialect,
|
dia: llvm::AsmDialect,
|
||||||
line_spans: &[Span],
|
line_spans: &[Span],
|
||||||
unwind: bool,
|
unwind: bool,
|
||||||
dest_catch_funclet: Option<(
|
dest_catch_funclet: Option<(
|
||||||
|
@ -498,7 +401,7 @@ pub(crate) fn inline_asm_call<'ll>(
|
||||||
cons.len(),
|
cons.len(),
|
||||||
volatile,
|
volatile,
|
||||||
alignstack,
|
alignstack,
|
||||||
llvm::AsmDialect::from_generic(dia),
|
dia,
|
||||||
can_throw,
|
can_throw,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -522,7 +425,7 @@ pub(crate) fn inline_asm_call<'ll>(
|
||||||
// we just encode the start position of each line.
|
// we just encode the start position of each line.
|
||||||
// FIXME: Figure out a way to pass the entire line spans.
|
// FIXME: Figure out a way to pass the entire line spans.
|
||||||
let mut srcloc = vec![];
|
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
|
// LLVM inserts an extra line to add the ".intel_syntax", so add
|
||||||
// a dummy srcloc entry for it.
|
// a dummy srcloc entry for it.
|
||||||
//
|
//
|
||||||
|
|
|
@ -7,7 +7,6 @@ use crate::type_of::LayoutLlvmExt;
|
||||||
use crate::va_arg::emit_va_arg;
|
use crate::va_arg::emit_va_arg;
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
||||||
use rustc_ast as ast;
|
|
||||||
use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
|
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::span_invalid_monomorphization_error;
|
||||||
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
|
||||||
|
@ -351,7 +350,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
|
||||||
self.type_void(),
|
self.type_void(),
|
||||||
true,
|
true,
|
||||||
false,
|
false,
|
||||||
ast::LlvmAsmDialect::Att,
|
llvm::AsmDialect::Att,
|
||||||
&[span],
|
&[span],
|
||||||
false,
|
false,
|
||||||
None,
|
None,
|
||||||
|
|
|
@ -423,22 +423,13 @@ pub enum MetadataType {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// LLVMRustAsmDialect
|
/// LLVMRustAsmDialect
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub enum AsmDialect {
|
pub enum AsmDialect {
|
||||||
Att,
|
Att,
|
||||||
Intel,
|
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
|
/// LLVMRustCodeGenOptLevel
|
||||||
#[derive(Copy, Clone, PartialEq)]
|
#[derive(Copy, Clone, PartialEq)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|
|
@ -211,7 +211,6 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
|
||||||
|
|
||||||
PlaceContext::MutatingUse(
|
PlaceContext::MutatingUse(
|
||||||
MutatingUseContext::Store
|
MutatingUseContext::Store
|
||||||
| MutatingUseContext::LlvmAsmOutput
|
|
||||||
| MutatingUseContext::AsmOutput
|
| MutatingUseContext::AsmOutput
|
||||||
| MutatingUseContext::Borrow
|
| MutatingUseContext::Borrow
|
||||||
| MutatingUseContext::AddressOf
|
| MutatingUseContext::AddressOf
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
use rustc_errors::struct_span_err;
|
|
||||||
use rustc_middle::mir;
|
use rustc_middle::mir;
|
||||||
|
|
||||||
use super::FunctionCx;
|
use super::FunctionCx;
|
||||||
use super::LocalRef;
|
use super::LocalRef;
|
||||||
use super::OperandValue;
|
|
||||||
use crate::traits::BuilderMethods;
|
use crate::traits::BuilderMethods;
|
||||||
use crate::traits::*;
|
use crate::traits::*;
|
||||||
|
|
||||||
|
@ -66,51 +64,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
||||||
}
|
}
|
||||||
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) => {
|
mir::StatementKind::Coverage(box ref coverage) => {
|
||||||
self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
|
self.codegen_coverage(&mut bx, coverage.clone(), statement.source_info.scope);
|
||||||
bx
|
bx
|
||||||
|
|
|
@ -3,7 +3,6 @@ use crate::mir::operand::OperandRef;
|
||||||
use crate::mir::place::PlaceRef;
|
use crate::mir::place::PlaceRef;
|
||||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||||
use rustc_hir::def_id::DefId;
|
use rustc_hir::def_id::DefId;
|
||||||
use rustc_hir::LlvmInlineAsmInner;
|
|
||||||
use rustc_middle::ty::Instance;
|
use rustc_middle::ty::Instance;
|
||||||
use rustc_span::Span;
|
use rustc_span::Span;
|
||||||
use rustc_target::asm::InlineAsmRegOrRegClass;
|
use rustc_target::asm::InlineAsmRegOrRegClass;
|
||||||
|
@ -42,15 +41,6 @@ pub enum GlobalAsmOperandRef {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait AsmBuilderMethods<'tcx>: BackendTypes {
|
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
|
/// Take an inline assembly expression and splat it out via LLVM
|
||||||
fn codegen_inline_asm(
|
fn codegen_inline_asm(
|
||||||
&mut self,
|
&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
|
// Defined to do nothing. These are added by optimization passes, to avoid changing the
|
||||||
// size of MIR constantly.
|
// size of MIR constantly.
|
||||||
Nop => {}
|
Nop => {}
|
||||||
|
|
||||||
LlvmInlineAsm { .. } => throw_unsup_format!("inline assembly is not supported"),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self.stack_mut()[frame_idx].loc.as_mut().unwrap().statement_index += 1;
|
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);
|
self.super_statement(statement, location);
|
||||||
|
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::LlvmInlineAsm { .. } => {
|
|
||||||
self.check_op(ops::InlineAsm);
|
|
||||||
}
|
|
||||||
|
|
||||||
StatementKind::Assign(..)
|
StatementKind::Assign(..)
|
||||||
| StatementKind::SetDiscriminant { .. }
|
| StatementKind::SetDiscriminant { .. }
|
||||||
| StatementKind::FakeRead(..)
|
| StatementKind::FakeRead(..)
|
||||||
|
|
|
@ -352,7 +352,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
|
||||||
StatementKind::SetDiscriminant { .. }
|
StatementKind::SetDiscriminant { .. }
|
||||||
| StatementKind::StorageLive(..)
|
| StatementKind::StorageLive(..)
|
||||||
| StatementKind::StorageDead(..)
|
| StatementKind::StorageDead(..)
|
||||||
| StatementKind::LlvmInlineAsm(..)
|
|
||||||
| StatementKind::Retag(_, _)
|
| StatementKind::Retag(_, _)
|
||||||
| StatementKind::Coverage(_)
|
| StatementKind::Coverage(_)
|
||||||
| StatementKind::Nop => {}
|
| StatementKind::Nop => {}
|
||||||
|
|
|
@ -30,7 +30,6 @@ macro_rules! arena_types {
|
||||||
[] impl_item_ref: rustc_hir::ImplItemRef,
|
[] impl_item_ref: rustc_hir::ImplItemRef,
|
||||||
[] item: rustc_hir::Item<'tcx>,
|
[] item: rustc_hir::Item<'tcx>,
|
||||||
[] inline_asm: rustc_hir::InlineAsm<'tcx>,
|
[] inline_asm: rustc_hir::InlineAsm<'tcx>,
|
||||||
[] llvm_inline_asm: rustc_hir::LlvmInlineAsm<'tcx>,
|
|
||||||
[] local: rustc_hir::Local<'tcx>,
|
[] local: rustc_hir::Local<'tcx>,
|
||||||
[] mod_: rustc_hir::Mod<'tcx>,
|
[] mod_: rustc_hir::Mod<'tcx>,
|
||||||
[] owner_info: rustc_hir::OwnerInfo<'tcx>,
|
[] owner_info: rustc_hir::OwnerInfo<'tcx>,
|
||||||
|
|
|
@ -5,8 +5,8 @@ use crate::intravisit::FnKind;
|
||||||
use crate::LangItem;
|
use crate::LangItem;
|
||||||
|
|
||||||
use rustc_ast::util::parser::ExprPrecedence;
|
use rustc_ast::util::parser::ExprPrecedence;
|
||||||
use rustc_ast::{self as ast, CrateSugar, LlvmAsmDialect};
|
use rustc_ast::{self as ast, CrateSugar};
|
||||||
use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, StrStyle, TraitObjectSyntax, UintTy};
|
use rustc_ast::{Attribute, FloatTy, IntTy, Label, LitKind, TraitObjectSyntax, UintTy};
|
||||||
pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
|
pub use rustc_ast::{BorrowKind, ImplPolarity, IsAuto};
|
||||||
pub use rustc_ast::{CaptureBy, Movability, Mutability};
|
pub use rustc_ast::{CaptureBy, Movability, Mutability};
|
||||||
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
|
||||||
|
@ -1471,7 +1471,6 @@ impl Expr<'_> {
|
||||||
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
ExprKind::Continue(..) => ExprPrecedence::Continue,
|
||||||
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
ExprKind::Ret(..) => ExprPrecedence::Ret,
|
||||||
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
|
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
|
||||||
ExprKind::LlvmInlineAsm(..) => ExprPrecedence::InlineAsm,
|
|
||||||
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
ExprKind::Struct(..) => ExprPrecedence::Struct,
|
||||||
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
|
||||||
ExprKind::Yield(..) => ExprPrecedence::Yield,
|
ExprKind::Yield(..) => ExprPrecedence::Yield,
|
||||||
|
@ -1531,7 +1530,6 @@ impl Expr<'_> {
|
||||||
| ExprKind::Loop(..)
|
| ExprKind::Loop(..)
|
||||||
| ExprKind::Assign(..)
|
| ExprKind::Assign(..)
|
||||||
| ExprKind::InlineAsm(..)
|
| ExprKind::InlineAsm(..)
|
||||||
| ExprKind::LlvmInlineAsm(..)
|
|
||||||
| ExprKind::AssignOp(..)
|
| ExprKind::AssignOp(..)
|
||||||
| ExprKind::Lit(_)
|
| ExprKind::Lit(_)
|
||||||
| ExprKind::ConstBlock(..)
|
| ExprKind::ConstBlock(..)
|
||||||
|
@ -1614,7 +1612,6 @@ impl Expr<'_> {
|
||||||
| ExprKind::Loop(..)
|
| ExprKind::Loop(..)
|
||||||
| ExprKind::Assign(..)
|
| ExprKind::Assign(..)
|
||||||
| ExprKind::InlineAsm(..)
|
| ExprKind::InlineAsm(..)
|
||||||
| ExprKind::LlvmInlineAsm(..)
|
|
||||||
| ExprKind::AssignOp(..)
|
| ExprKind::AssignOp(..)
|
||||||
| ExprKind::ConstBlock(..)
|
| ExprKind::ConstBlock(..)
|
||||||
| ExprKind::Box(..)
|
| ExprKind::Box(..)
|
||||||
|
@ -1755,8 +1752,6 @@ pub enum ExprKind<'hir> {
|
||||||
|
|
||||||
/// Inline assembly (from `asm!`), with its outputs and inputs.
|
/// Inline assembly (from `asm!`), with its outputs and inputs.
|
||||||
InlineAsm(&'hir InlineAsm<'hir>),
|
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.
|
/// A struct or struct-like variant literal expression.
|
||||||
///
|
///
|
||||||
|
@ -2368,36 +2363,6 @@ pub struct InlineAsm<'hir> {
|
||||||
pub line_spans: &'hir [Span],
|
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.
|
/// Represents a parameter in a function header.
|
||||||
#[derive(Debug, HashStable_Generic)]
|
#[derive(Debug, HashStable_Generic)]
|
||||||
pub struct Param<'hir> {
|
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) => {
|
ExprKind::InlineAsm(ref asm) => {
|
||||||
walk_inline_asm(visitor, 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, _) => {
|
ExprKind::Yield(ref subexpression, _) => {
|
||||||
visitor.visit_expr(subexpression);
|
visitor.visit_expr(subexpression);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1581,67 +1581,6 @@ impl<'a> State<'a> {
|
||||||
self.word("asm!");
|
self.word("asm!");
|
||||||
self.print_inline_asm(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, _) => {
|
hir::ExprKind::Yield(ref expr, _) => {
|
||||||
self.word_space("yield");
|
self.word_space("yield");
|
||||||
self.print_expr_maybe_paren(&expr, parser::PREC_JUMP);
|
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.
|
/// End the current live range for the storage of the local.
|
||||||
StorageDead(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
|
/// 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
|
/// part of the Stacked Borrows model. These statements are currently only interpreted
|
||||||
/// by miri and only generated when "-Z mir-emit-retag" is passed.
|
/// by miri and only generated when "-Z mir-emit-retag" is passed.
|
||||||
|
@ -1688,13 +1684,6 @@ pub enum FakeReadCause {
|
||||||
ForIndex,
|
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<'_> {
|
impl Debug for Statement<'_> {
|
||||||
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
|
||||||
use self::StatementKind::*;
|
use self::StatementKind::*;
|
||||||
|
@ -1719,9 +1708,6 @@ impl Debug for Statement<'_> {
|
||||||
SetDiscriminant { ref place, variant_index } => {
|
SetDiscriminant { ref place, variant_index } => {
|
||||||
write!(fmt, "discriminant({:?}) = {:?}", 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) => {
|
AscribeUserType(box (ref place, ref c_ty), ref variance) => {
|
||||||
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
|
write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty)
|
||||||
}
|
}
|
||||||
|
|
|
@ -245,7 +245,6 @@ pub fn statement_kind_name(statement: &Statement<'_>) -> &'static str {
|
||||||
SetDiscriminant { .. } => "SetDiscriminant",
|
SetDiscriminant { .. } => "SetDiscriminant",
|
||||||
StorageLive(..) => "StorageLive",
|
StorageLive(..) => "StorageLive",
|
||||||
StorageDead(..) => "StorageDead",
|
StorageDead(..) => "StorageDead",
|
||||||
LlvmInlineAsm(..) => "LlvmInlineAsm",
|
|
||||||
Retag(..) => "Retag",
|
Retag(..) => "Retag",
|
||||||
AscribeUserType(..) => "AscribeUserType",
|
AscribeUserType(..) => "AscribeUserType",
|
||||||
Coverage(..) => "Coverage",
|
Coverage(..) => "Coverage",
|
||||||
|
|
|
@ -408,19 +408,6 @@ macro_rules! make_mir_visitor {
|
||||||
location
|
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) => {
|
StatementKind::Retag(kind, place) => {
|
||||||
self.visit_retag(kind, place, location);
|
self.visit_retag(kind, place, location);
|
||||||
}
|
}
|
||||||
|
@ -1178,10 +1165,6 @@ pub enum NonMutatingUseContext {
|
||||||
pub enum MutatingUseContext {
|
pub enum MutatingUseContext {
|
||||||
/// Appears as LHS of an assignment.
|
/// Appears as LHS of an assignment.
|
||||||
Store,
|
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.
|
/// Output operand of an inline assembly block.
|
||||||
AsmOutput,
|
AsmOutput,
|
||||||
/// Destination of a call.
|
/// Destination of a call.
|
||||||
|
@ -1271,7 +1254,6 @@ impl PlaceContext {
|
||||||
PlaceContext::MutatingUse(
|
PlaceContext::MutatingUse(
|
||||||
MutatingUseContext::Store
|
MutatingUseContext::Store
|
||||||
| MutatingUseContext::Call
|
| MutatingUseContext::Call
|
||||||
| MutatingUseContext::LlvmAsmOutput
|
|
||||||
| MutatingUseContext::AsmOutput,
|
| MutatingUseContext::AsmOutput,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
|
@ -431,12 +431,6 @@ pub enum ExprKind<'tcx> {
|
||||||
},
|
},
|
||||||
/// An expression taking a reference to a thread local.
|
/// An expression taking a reference to a thread local.
|
||||||
ThreadLocalRef(DefId),
|
ThreadLocalRef(DefId),
|
||||||
/// Inline LLVM assembly, i.e. `llvm_asm!()`.
|
|
||||||
LlvmInlineAsm {
|
|
||||||
asm: &'tcx hir::LlvmInlineAsmInner,
|
|
||||||
outputs: Box<[ExprId]>,
|
|
||||||
inputs: Box<[ExprId]>,
|
|
||||||
},
|
|
||||||
/// A `yield` expression.
|
/// A `yield` expression.
|
||||||
Yield {
|
Yield {
|
||||||
value: ExprId,
|
value: ExprId,
|
||||||
|
|
|
@ -145,14 +145,6 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ThreadLocalRef(_) => {}
|
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]),
|
Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -225,7 +225,6 @@ TrivialTypeFoldableAndLiftImpls! {
|
||||||
::rustc_hir::def_id::DefId,
|
::rustc_hir::def_id::DefId,
|
||||||
::rustc_hir::def_id::LocalDefId,
|
::rustc_hir::def_id::LocalDefId,
|
||||||
::rustc_hir::HirId,
|
::rustc_hir::HirId,
|
||||||
::rustc_hir::LlvmInlineAsmInner,
|
|
||||||
::rustc_hir::MatchSource,
|
::rustc_hir::MatchSource,
|
||||||
::rustc_hir::Mutability,
|
::rustc_hir::Mutability,
|
||||||
::rustc_hir::Unsafety,
|
::rustc_hir::Unsafety,
|
||||||
|
|
|
@ -570,7 +570,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
| ExprKind::ConstBlock { .. }
|
| ExprKind::ConstBlock { .. }
|
||||||
| ExprKind::StaticRef { .. }
|
| ExprKind::StaticRef { .. }
|
||||||
| ExprKind::InlineAsm { .. }
|
| ExprKind::InlineAsm { .. }
|
||||||
| ExprKind::LlvmInlineAsm { .. }
|
|
||||||
| ExprKind::Yield { .. }
|
| ExprKind::Yield { .. }
|
||||||
| ExprKind::ThreadLocalRef(_)
|
| ExprKind::ThreadLocalRef(_)
|
||||||
| ExprKind::Call { .. } => {
|
| ExprKind::Call { .. } => {
|
||||||
|
|
|
@ -350,7 +350,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
| ExprKind::Continue { .. }
|
| ExprKind::Continue { .. }
|
||||||
| ExprKind::Return { .. }
|
| ExprKind::Return { .. }
|
||||||
| ExprKind::InlineAsm { .. }
|
| ExprKind::InlineAsm { .. }
|
||||||
| ExprKind::LlvmInlineAsm { .. }
|
|
||||||
| ExprKind::PlaceTypeAscription { .. }
|
| ExprKind::PlaceTypeAscription { .. }
|
||||||
| ExprKind::ValueTypeAscription { .. } => {
|
| ExprKind::ValueTypeAscription { .. } => {
|
||||||
// these do not have corresponding `Rvalue` variants,
|
// these do not have corresponding `Rvalue` variants,
|
||||||
|
|
|
@ -67,8 +67,7 @@ impl Category {
|
||||||
| ExprKind::Repeat { .. }
|
| ExprKind::Repeat { .. }
|
||||||
| ExprKind::Assign { .. }
|
| ExprKind::Assign { .. }
|
||||||
| ExprKind::AssignOp { .. }
|
| ExprKind::AssignOp { .. }
|
||||||
| ExprKind::ThreadLocalRef(_)
|
| ExprKind::ThreadLocalRef(_) => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
|
||||||
| ExprKind::LlvmInlineAsm { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
|
|
||||||
|
|
||||||
ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => {
|
ExprKind::ConstBlock { .. } | ExprKind::Literal { .. } | ExprKind::StaticRef { .. } => {
|
||||||
Some(Category::Constant)
|
Some(Category::Constant)
|
||||||
|
|
|
@ -477,9 +477,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// These cases don't actually need a destination
|
// These cases don't actually need a destination
|
||||||
ExprKind::Assign { .. }
|
ExprKind::Assign { .. } | ExprKind::AssignOp { .. } => {
|
||||||
| ExprKind::AssignOp { .. }
|
|
||||||
| ExprKind::LlvmInlineAsm { .. } => {
|
|
||||||
unpack!(block = this.stmt_expr(block, expr, None));
|
unpack!(block = this.stmt_expr(block, expr, None));
|
||||||
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
|
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
|
||||||
block.unit()
|
block.unit()
|
||||||
|
|
|
@ -101,38 +101,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
||||||
BreakableTarget::Return,
|
BreakableTarget::Return,
|
||||||
source_info,
|
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!(
|
assert!(
|
||||||
statement_scope.is_some(),
|
statement_scope.is_some(),
|
||||||
|
|
|
@ -329,7 +329,6 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
|
||||||
| ExprKind::Box { .. }
|
| ExprKind::Box { .. }
|
||||||
| ExprKind::If { .. }
|
| ExprKind::If { .. }
|
||||||
| ExprKind::InlineAsm { .. }
|
| ExprKind::InlineAsm { .. }
|
||||||
| ExprKind::LlvmInlineAsm { .. }
|
|
||||||
| ExprKind::LogicalOp { .. }
|
| ExprKind::LogicalOp { .. }
|
||||||
| ExprKind::Use { .. } => {
|
| ExprKind::Use { .. } => {
|
||||||
// We don't need to save the old value and restore it
|
// 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);
|
self.requires_unsafe(expr.span, DerefOfRawPointer);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ExprKind::InlineAsm { .. } | ExprKind::LlvmInlineAsm { .. } => {
|
ExprKind::InlineAsm { .. } => {
|
||||||
self.requires_unsafe(expr.span, UseOfInlineAssembly);
|
self.requires_unsafe(expr.span, UseOfInlineAssembly);
|
||||||
}
|
}
|
||||||
ExprKind::Adt(box Adt {
|
ExprKind::Adt(box Adt {
|
||||||
|
|
|
@ -570,12 +570,6 @@ impl<'tcx> Cx<'tcx> {
|
||||||
line_spans: asm.line_spans,
|
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) => {
|
hir::ExprKind::ConstBlock(ref anon_const) => {
|
||||||
let anon_const_def_id = self.tcx.hir().local_def_id(anon_const.hir_id);
|
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);
|
let value = ty::Const::from_inline_const(self.tcx, anon_const_def_id);
|
||||||
|
|
|
@ -176,7 +176,6 @@ impl DefUse {
|
||||||
// All other contexts are uses...
|
// All other contexts are uses...
|
||||||
PlaceContext::MutatingUse(
|
PlaceContext::MutatingUse(
|
||||||
MutatingUseContext::AddressOf
|
MutatingUseContext::AddressOf
|
||||||
| MutatingUseContext::LlvmAsmOutput
|
|
||||||
| MutatingUseContext::Borrow
|
| MutatingUseContext::Borrow
|
||||||
| MutatingUseContext::Drop
|
| MutatingUseContext::Drop
|
||||||
| MutatingUseContext::Retag,
|
| MutatingUseContext::Retag,
|
||||||
|
|
|
@ -134,11 +134,6 @@ impl<'mir, 'tcx> crate::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tc
|
||||||
| StatementKind::SetDiscriminant { box place, .. } => {
|
| StatementKind::SetDiscriminant { box place, .. } => {
|
||||||
trans.gen(place.local);
|
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
|
// Nothing to do for these. Match exhaustively so this fails to compile when new
|
||||||
// variants are added.
|
// variants are added.
|
||||||
|
|
|
@ -4,7 +4,6 @@ use rustc_middle::mir::*;
|
||||||
use rustc_middle::ty::{self, TyCtxt};
|
use rustc_middle::ty::{self, TyCtxt};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
use std::iter;
|
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use super::abs_domain::Lift;
|
use super::abs_domain::Lift;
|
||||||
|
@ -293,16 +292,6 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
|
||||||
StatementKind::FakeRead(box (_, place)) => {
|
StatementKind::FakeRead(box (_, place)) => {
|
||||||
self.create_move_path(*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::StorageLive(_) => {}
|
||||||
StatementKind::StorageDead(local) => {
|
StatementKind::StorageDead(local) => {
|
||||||
self.gather_move(Place::from(*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)
|
// safe (at least as emitted during MIR construction)
|
||||||
}
|
}
|
||||||
|
|
||||||
StatementKind::LlvmInlineAsm { .. } => self.require_unsafe(
|
|
||||||
UnsafetyViolationKind::General,
|
|
||||||
UnsafetyViolationDetails::UseOfInlineAssembly,
|
|
||||||
),
|
|
||||||
StatementKind::CopyNonOverlapping(..) => unreachable!(),
|
StatementKind::CopyNonOverlapping(..) => unreachable!(),
|
||||||
}
|
}
|
||||||
self.super_statement(statement, location);
|
self.super_statement(statement, location);
|
||||||
|
@ -208,7 +204,6 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
|
||||||
MutatingUseContext::Store
|
MutatingUseContext::Store
|
||||||
| MutatingUseContext::Drop
|
| MutatingUseContext::Drop
|
||||||
| MutatingUseContext::AsmOutput
|
| MutatingUseContext::AsmOutput
|
||||||
| MutatingUseContext::LlvmAsmOutput
|
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
// If this is just an assignment, determine if the assigned type needs dropping.
|
// 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
|
// These could be propagated with a smarter analysis or just some careful thinking about
|
||||||
// whether they'd be fine right now.
|
// whether they'd be fine right now.
|
||||||
MutatingUse(MutatingUseContext::LlvmAsmOutput)
|
MutatingUse(MutatingUseContext::Yield)
|
||||||
| MutatingUse(MutatingUseContext::Yield)
|
|
||||||
| MutatingUse(MutatingUseContext::Drop)
|
| MutatingUse(MutatingUseContext::Drop)
|
||||||
| MutatingUse(MutatingUseContext::Retag)
|
| MutatingUse(MutatingUseContext::Retag)
|
||||||
// These can't ever be propagated under any scheme, as we can't reason about indirect
|
// 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::CopyNonOverlapping(..)
|
||||||
| StatementKind::Assign(_)
|
| StatementKind::Assign(_)
|
||||||
| StatementKind::SetDiscriminant { .. }
|
| StatementKind::SetDiscriminant { .. }
|
||||||
| StatementKind::LlvmInlineAsm(_)
|
|
||||||
| StatementKind::Retag(_, _)
|
| StatementKind::Retag(_, _)
|
||||||
| StatementKind::AscribeUserType(_, _) => {
|
| StatementKind::AscribeUserType(_, _) => {
|
||||||
Some(statement.source_info.span)
|
Some(statement.source_info.span)
|
||||||
|
|
|
@ -534,25 +534,6 @@ impl<'a> Conflicts<'a> {
|
||||||
// eliminate the resulting self-assignments automatically.
|
// eliminate the resulting self-assignments automatically.
|
||||||
StatementKind::Assign(_) => {}
|
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::SetDiscriminant { .. }
|
||||||
| StatementKind::StorageLive(..)
|
| StatementKind::StorageLive(..)
|
||||||
| StatementKind::StorageDead(..)
|
| StatementKind::StorageDead(..)
|
||||||
|
|
|
@ -1449,9 +1449,6 @@ impl<'tcx> Visitor<'tcx> for EnsureGeneratorFieldAssignmentsNeverAlias<'_> {
|
||||||
self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
|
self.check_assigned_place(*lhs, |this| this.visit_rvalue(rhs, location));
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: Does `llvm_asm!` have any aliasing requirements?
|
|
||||||
StatementKind::LlvmInlineAsm(_) => {}
|
|
||||||
|
|
||||||
StatementKind::FakeRead(..)
|
StatementKind::FakeRead(..)
|
||||||
| StatementKind::SetDiscriminant { .. }
|
| StatementKind::SetDiscriminant { .. }
|
||||||
| StatementKind::StorageLive(_)
|
| StatementKind::StorageLive(_)
|
||||||
|
|
|
@ -50,7 +50,6 @@ impl RemoveNoopLandingPads {
|
||||||
|
|
||||||
StatementKind::Assign { .. }
|
StatementKind::Assign { .. }
|
||||||
| StatementKind::SetDiscriminant { .. }
|
| StatementKind::SetDiscriminant { .. }
|
||||||
| StatementKind::LlvmInlineAsm { .. }
|
|
||||||
| StatementKind::CopyNonOverlapping(..)
|
| StatementKind::CopyNonOverlapping(..)
|
||||||
| StatementKind::Retag { .. } => {
|
| StatementKind::Retag { .. } => {
|
||||||
return false;
|
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
|
// These statements have no influence on the place
|
||||||
// we are interested in
|
// we are interested in
|
||||||
StatementKind::FakeRead(_)
|
StatementKind::FakeRead(_)
|
||||||
|
@ -320,10 +316,6 @@ fn find_determining_place<'tcx>(
|
||||||
| StatementKind::CopyNonOverlapping(_)
|
| StatementKind::CopyNonOverlapping(_)
|
||||||
| StatementKind::Nop => {}
|
| 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
|
// If the discriminant is set, it is always set
|
||||||
// as a constant, so the job is already done.
|
// as a constant, so the job is already done.
|
||||||
// As we are **ignoring projections**, if the place
|
// As we are **ignoring projections**, if the place
|
||||||
|
|
|
@ -483,8 +483,7 @@ impl UsedLocals {
|
||||||
impl<'tcx> Visitor<'tcx> for UsedLocals {
|
impl<'tcx> Visitor<'tcx> for UsedLocals {
|
||||||
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
fn visit_statement(&mut self, statement: &Statement<'tcx>, location: Location) {
|
||||||
match statement.kind {
|
match statement.kind {
|
||||||
StatementKind::LlvmInlineAsm(..)
|
StatementKind::CopyNonOverlapping(..)
|
||||||
| StatementKind::CopyNonOverlapping(..)
|
|
||||||
| StatementKind::Retag(..)
|
| StatementKind::Retag(..)
|
||||||
| StatementKind::Coverage(..)
|
| StatementKind::Coverage(..)
|
||||||
| StatementKind::FakeRead(..)
|
| StatementKind::FakeRead(..)
|
||||||
|
|
|
@ -631,10 +631,6 @@ impl<'tcx> SimplifyBranchSameOptimizationFinder<'_, 'tcx> {
|
||||||
.filter(|(_, bb)| {
|
.filter(|(_, bb)| {
|
||||||
// Reaching `unreachable` is UB so assume it doesn't happen.
|
// Reaching `unreachable` is UB so assume it doesn't happen.
|
||||||
bb.terminator().kind != TerminatorKind::Unreachable
|
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();
|
.peekable();
|
||||||
|
|
||||||
|
|
|
@ -23,23 +23,14 @@ impl MirPass<'_> for UnreachablePropagation {
|
||||||
|
|
||||||
for (bb, bb_data) in traversal::postorder(body) {
|
for (bb, bb_data) in traversal::postorder(body) {
|
||||||
let terminator = bb_data.terminator();
|
let terminator = bb_data.terminator();
|
||||||
// HACK: If the block contains any asm statement it is not regarded as unreachable.
|
if terminator.kind == TerminatorKind::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() {
|
|
||||||
unreachable_blocks.insert(bb);
|
unreachable_blocks.insert(bb);
|
||||||
} else {
|
} else {
|
||||||
let is_unreachable = |succ: BasicBlock| unreachable_blocks.contains(&succ);
|
let is_unreachable = |succ: BasicBlock| unreachable_blocks.contains(&succ);
|
||||||
let terminator_kind_opt = remove_successors(&terminator.kind, is_unreachable);
|
let terminator_kind_opt = remove_successors(&terminator.kind, is_unreachable);
|
||||||
|
|
||||||
if let Some(terminator_kind) = terminator_kind_opt {
|
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);
|
unreachable_blocks.insert(bb);
|
||||||
}
|
}
|
||||||
replacements.insert(bb, terminator_kind);
|
replacements.insert(bb, terminator_kind);
|
||||||
|
|
|
@ -103,7 +103,6 @@ use rustc_span::Span;
|
||||||
use std::collections::VecDeque;
|
use std::collections::VecDeque;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::prelude::*;
|
use std::io::prelude::*;
|
||||||
use std::iter;
|
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
mod rwu_table;
|
mod rwu_table;
|
||||||
|
@ -470,7 +469,6 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
|
||||||
| hir::ExprKind::Struct(..)
|
| hir::ExprKind::Struct(..)
|
||||||
| hir::ExprKind::Repeat(..)
|
| hir::ExprKind::Repeat(..)
|
||||||
| hir::ExprKind::InlineAsm(..)
|
| hir::ExprKind::InlineAsm(..)
|
||||||
| hir::ExprKind::LlvmInlineAsm(..)
|
|
||||||
| hir::ExprKind::Box(..)
|
| hir::ExprKind::Box(..)
|
||||||
| hir::ExprKind::Type(..)
|
| hir::ExprKind::Type(..)
|
||||||
| hir::ExprKind::Err
|
| hir::ExprKind::Err
|
||||||
|
@ -1091,26 +1089,6 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
|
||||||
succ
|
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::Lit(..)
|
||||||
| hir::ExprKind::ConstBlock(..)
|
| hir::ExprKind::ConstBlock(..)
|
||||||
| hir::ExprKind::Err
|
| 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) => {
|
hir::ExprKind::Let(let_expr) => {
|
||||||
this.check_unused_vars_in_pat(let_expr.pat, None, |_, _, _, _| {});
|
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);
|
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 => {
|
ExprKind::DropTemps(..) | ExprKind::Block(..) | ExprKind::Err => {
|
||||||
hir::intravisit::walk_expr(self, expr);
|
hir::intravisit::walk_expr(self, expr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -786,7 +786,6 @@ symbols! {
|
||||||
linkage,
|
linkage,
|
||||||
lint_reasons,
|
lint_reasons,
|
||||||
literal,
|
literal,
|
||||||
llvm_asm,
|
|
||||||
load,
|
load,
|
||||||
loaded_from_disk,
|
loaded_from_disk,
|
||||||
local,
|
local,
|
||||||
|
|
|
@ -480,7 +480,7 @@ impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> {
|
||||||
// let expressions imply control flow
|
// let expressions imply control flow
|
||||||
ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } =>
|
ExprKind::Match { .. } | ExprKind::If { .. } | ExprKind::Let { .. } =>
|
||||||
self.error(node.span, "control flow is not supported in generic constants")?,
|
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")?
|
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::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]),
|
||||||
ExprKind::InlineAsm(asm) => self.check_expr_asm(asm),
|
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) => {
|
ExprKind::Break(destination, ref expr_opt) => {
|
||||||
self.check_expr_break(destination, expr_opt.as_deref(), expr)
|
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::mir::FakeReadCause;
|
||||||
use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
|
use rustc_middle::ty::{self, adjustment, AdtKind, Ty, TyCtxt};
|
||||||
use rustc_target::abi::VariantIdx;
|
use rustc_target::abi::VariantIdx;
|
||||||
use std::iter;
|
|
||||||
|
|
||||||
use crate::mem_categorization as mc;
|
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::Continue(..)
|
||||||
| hir::ExprKind::Lit(..)
|
| hir::ExprKind::Lit(..)
|
||||||
| hir::ExprKind::ConstBlock(..)
|
| hir::ExprKind::ConstBlock(..)
|
||||||
|
|
|
@ -378,7 +378,6 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
|
||||||
| hir::ExprKind::Struct(..)
|
| hir::ExprKind::Struct(..)
|
||||||
| hir::ExprKind::Repeat(..)
|
| hir::ExprKind::Repeat(..)
|
||||||
| hir::ExprKind::InlineAsm(..)
|
| hir::ExprKind::InlineAsm(..)
|
||||||
| hir::ExprKind::LlvmInlineAsm(..)
|
|
||||||
| hir::ExprKind::Box(..)
|
| hir::ExprKind::Box(..)
|
||||||
| hir::ExprKind::Err => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
|
| hir::ExprKind::Err => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,7 +180,6 @@
|
||||||
#![feature(intrinsics)]
|
#![feature(intrinsics)]
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
#![feature(link_llvm_intrinsics)]
|
#![feature(link_llvm_intrinsics)]
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![feature(min_specialization)]
|
#![feature(min_specialization)]
|
||||||
#![feature(mixed_integer_ops)]
|
#![feature(mixed_integer_ops)]
|
||||||
#![feature(must_not_suspend)]
|
#![feature(must_not_suspend)]
|
||||||
|
|
|
@ -1373,32 +1373,6 @@ pub(crate) mod builtin {
|
||||||
($cond:expr, $($arg:tt)+) => {{ /* compiler built-in */ }};
|
($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.
|
/// Prints passed tokens into the standard output.
|
||||||
#[unstable(
|
#[unstable(
|
||||||
feature = "log_syntax",
|
feature = "log_syntax",
|
||||||
|
|
|
@ -56,8 +56,8 @@ pub use crate::hash::macros::Hash;
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
|
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,
|
format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
|
||||||
option_env, stringify, trace_macros,
|
stringify, trace_macros,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[unstable(
|
#[unstable(
|
||||||
|
|
|
@ -294,7 +294,6 @@
|
||||||
#![feature(intra_doc_pointers)]
|
#![feature(intra_doc_pointers)]
|
||||||
#![feature(lang_items)]
|
#![feature(lang_items)]
|
||||||
#![feature(linkage)]
|
#![feature(linkage)]
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![feature(log_syntax)]
|
#![feature(log_syntax)]
|
||||||
#![feature(map_try_insert)]
|
#![feature(map_try_insert)]
|
||||||
#![feature(maybe_uninit_extra)]
|
#![feature(maybe_uninit_extra)]
|
||||||
|
@ -572,8 +571,8 @@ pub use core::{
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub use core::{
|
pub use core::{
|
||||||
assert, assert_matches, cfg, column, compile_error, concat, concat_idents, const_format_args,
|
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,
|
env, file, format_args, format_args_nl, include, include_bytes, include_str, line, log_syntax,
|
||||||
log_syntax, module_path, option_env, stringify, trace_macros,
|
module_path, option_env, stringify, trace_macros,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[unstable(
|
#[unstable(
|
||||||
|
|
|
@ -40,9 +40,8 @@ pub use crate::result::Result::{self, Err, Ok};
|
||||||
#[doc(no_inline)]
|
#[doc(no_inline)]
|
||||||
pub use core::prelude::v1::{
|
pub use core::prelude::v1::{
|
||||||
assert, cfg, column, compile_error, concat, concat_idents, env, file, format_args,
|
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,
|
format_args_nl, include, include_bytes, include_str, line, log_syntax, module_path, option_env,
|
||||||
option_env, stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq,
|
stringify, trace_macros, Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd,
|
||||||
PartialOrd,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[unstable(
|
#[unstable(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue