Auto merge of #92816 - tmiasko:rm-llvm-asm, r=Amanieu
Remove deprecated LLVM-style inline assembly The `llvm_asm!` was deprecated back in #87590 1.56.0, with intention to remove it once `asm!` was stabilized, which already happened in #91728 1.59.0. Now it is time to remove `llvm_asm!` to avoid continued maintenance cost. Closes #70173. Closes #92794. Closes #87612. Closes #82065. cc `@rust-lang/wg-inline-asm` r? `@Amanieu`
This commit is contained in:
commit
a34c079752
171 changed files with 235 additions and 3297 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)),
|
||||||
|
@ -1286,38 +1285,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, LocalMutationIsAllowed, Read, ReadKind,
|
||||||
Read, ReadKind, ReadOrWrite, Reservation, Shallow, Write, WriteAndRead, WriteKind,
|
ReadOrWrite, Reservation, Shallow, Write, WriteKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) fn generate_invalidates<'tcx>(
|
pub(super) fn generate_invalidates<'tcx>(
|
||||||
|
@ -59,37 +58,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
StatementKind::Assign(box (lhs, rhs)) => {
|
StatementKind::Assign(box (lhs, rhs)) => {
|
||||||
self.consume_rvalue(location, rhs);
|
self.consume_rvalue(location, rhs);
|
||||||
|
|
||||||
self.mutate_place(location, *lhs, Shallow(None), JustWrite);
|
self.mutate_place(location, *lhs, Shallow(None));
|
||||||
}
|
}
|
||||||
StatementKind::FakeRead(box (_, _)) => {
|
StatementKind::FakeRead(box (_, _)) => {
|
||||||
// Only relevant for initialized/liveness/safety checks.
|
// Only relevant for initialized/liveness/safety checks.
|
||||||
}
|
}
|
||||||
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));
|
||||||
}
|
|
||||||
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,
|
||||||
|
@ -142,7 +117,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
target: _,
|
target: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
self.mutate_place(location, *drop_place, Deep, JustWrite);
|
self.mutate_place(location, *drop_place, Deep);
|
||||||
self.consume_operand(location, new_value);
|
self.consume_operand(location, new_value);
|
||||||
}
|
}
|
||||||
TerminatorKind::Call {
|
TerminatorKind::Call {
|
||||||
|
@ -158,7 +133,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
self.consume_operand(location, arg);
|
self.consume_operand(location, arg);
|
||||||
}
|
}
|
||||||
if let Some((dest, _ /*bb*/)) = destination {
|
if let Some((dest, _ /*bb*/)) = destination {
|
||||||
self.mutate_place(location, *dest, Deep, JustWrite);
|
self.mutate_place(location, *dest, Deep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
|
TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
|
||||||
|
@ -181,7 +156,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.mutate_place(location, *resume_arg, Deep, JustWrite);
|
self.mutate_place(location, *resume_arg, Deep);
|
||||||
}
|
}
|
||||||
TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
|
TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::GeneratorDrop => {
|
||||||
// Invalidate all borrows of local places
|
// Invalidate all borrows of local places
|
||||||
|
@ -208,13 +183,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
|
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
|
||||||
if let Some(place) = place {
|
if let Some(place) = place {
|
||||||
self.mutate_place(location, place, Shallow(None), JustWrite);
|
self.mutate_place(location, place, Shallow(None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
|
InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
|
||||||
self.consume_operand(location, in_value);
|
self.consume_operand(location, in_value);
|
||||||
if let Some(out_place) = out_place {
|
if let Some(out_place) = out_place {
|
||||||
self.mutate_place(location, out_place, Shallow(None), JustWrite);
|
self.mutate_place(location, out_place, Shallow(None));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InlineAsmOperand::Const { value: _ }
|
InlineAsmOperand::Const { value: _ }
|
||||||
|
@ -238,13 +213,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
|
||||||
|
|
||||||
impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
impl<'cx, 'tcx> InvalidationGenerator<'cx, 'tcx> {
|
||||||
/// Simulates mutation of a place.
|
/// Simulates mutation of a place.
|
||||||
fn mutate_place(
|
fn mutate_place(&mut self, location: Location, place: Place<'tcx>, kind: AccessDepth) {
|
||||||
&mut self,
|
|
||||||
location: Location,
|
|
||||||
place: Place<'tcx>,
|
|
||||||
kind: AccessDepth,
|
|
||||||
_mode: MutateMode,
|
|
||||||
) {
|
|
||||||
self.access_place(
|
self.access_place(
|
||||||
location,
|
location,
|
||||||
place,
|
place,
|
||||||
|
|
|
@ -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,6 @@ 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 facts::AllFacts;
|
use facts::AllFacts;
|
||||||
|
|
||||||
use self::path_utils::*;
|
use self::path_utils::*;
|
||||||
|
@ -630,7 +628,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
StatementKind::Assign(box (lhs, ref rhs)) => {
|
StatementKind::Assign(box (lhs, ref rhs)) => {
|
||||||
self.consume_rvalue(location, (rhs, span), flow_state);
|
self.consume_rvalue(location, (rhs, span), flow_state);
|
||||||
|
|
||||||
self.mutate_place(location, (*lhs, span), Shallow(None), JustWrite, flow_state);
|
self.mutate_place(location, (*lhs, span), Shallow(None), flow_state);
|
||||||
}
|
}
|
||||||
StatementKind::FakeRead(box (_, ref place)) => {
|
StatementKind::FakeRead(box (_, ref place)) => {
|
||||||
// Read for match doesn't access any memory and is used to
|
// Read for match doesn't access any memory and is used to
|
||||||
|
@ -651,41 +649,8 @@ 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), 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 {
|
||||||
..
|
..
|
||||||
}) => {
|
}) => {
|
||||||
|
@ -750,7 +715,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
target: _,
|
target: _,
|
||||||
unwind: _,
|
unwind: _,
|
||||||
} => {
|
} => {
|
||||||
self.mutate_place(loc, (drop_place, span), Deep, JustWrite, flow_state);
|
self.mutate_place(loc, (drop_place, span), Deep, flow_state);
|
||||||
self.consume_operand(loc, (new_value, span), flow_state);
|
self.consume_operand(loc, (new_value, span), flow_state);
|
||||||
}
|
}
|
||||||
TerminatorKind::Call {
|
TerminatorKind::Call {
|
||||||
|
@ -766,7 +731,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
self.consume_operand(loc, (arg, span), flow_state);
|
self.consume_operand(loc, (arg, span), flow_state);
|
||||||
}
|
}
|
||||||
if let Some((dest, _ /*bb*/)) = *destination {
|
if let Some((dest, _ /*bb*/)) = *destination {
|
||||||
self.mutate_place(loc, (dest, span), Deep, JustWrite, flow_state);
|
self.mutate_place(loc, (dest, span), Deep, flow_state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
|
TerminatorKind::Assert { ref cond, expected: _, ref msg, target: _, cleanup: _ } => {
|
||||||
|
@ -780,7 +745,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
|
|
||||||
TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => {
|
TerminatorKind::Yield { ref value, resume: _, resume_arg, drop: _ } => {
|
||||||
self.consume_operand(loc, (value, span), flow_state);
|
self.consume_operand(loc, (value, span), flow_state);
|
||||||
self.mutate_place(loc, (resume_arg, span), Deep, JustWrite, flow_state);
|
self.mutate_place(loc, (resume_arg, span), Deep, flow_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
TerminatorKind::InlineAsm {
|
TerminatorKind::InlineAsm {
|
||||||
|
@ -798,13 +763,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
}
|
}
|
||||||
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
|
InlineAsmOperand::Out { reg: _, late: _, place, .. } => {
|
||||||
if let Some(place) = place {
|
if let Some(place) = place {
|
||||||
self.mutate_place(
|
self.mutate_place(loc, (place, span), Shallow(None), flow_state);
|
||||||
loc,
|
|
||||||
(place, span),
|
|
||||||
Shallow(None),
|
|
||||||
JustWrite,
|
|
||||||
flow_state,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
|
InlineAsmOperand::InOut { reg: _, late: _, ref in_value, out_place } => {
|
||||||
|
@ -814,7 +773,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
loc,
|
loc,
|
||||||
(out_place, span),
|
(out_place, span),
|
||||||
Shallow(None),
|
Shallow(None),
|
||||||
JustWrite,
|
|
||||||
flow_state,
|
flow_state,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -886,12 +844,6 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
|
|
||||||
enum MutateMode {
|
|
||||||
JustWrite,
|
|
||||||
WriteAndRead,
|
|
||||||
}
|
|
||||||
|
|
||||||
use self::AccessDepth::{Deep, Shallow};
|
use self::AccessDepth::{Deep, Shallow};
|
||||||
use self::ReadOrWrite::{Activation, Read, Reservation, Write};
|
use self::ReadOrWrite::{Activation, Read, Reservation, Write};
|
||||||
|
|
||||||
|
@ -977,7 +929,6 @@ enum LocalMutationIsAllowed {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
enum InitializationRequiringAction {
|
enum InitializationRequiringAction {
|
||||||
Update,
|
|
||||||
Borrow,
|
Borrow,
|
||||||
MatchOn,
|
MatchOn,
|
||||||
Use,
|
Use,
|
||||||
|
@ -994,7 +945,6 @@ struct RootPlace<'tcx> {
|
||||||
impl InitializationRequiringAction {
|
impl InitializationRequiringAction {
|
||||||
fn as_noun(self) -> &'static str {
|
fn as_noun(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
InitializationRequiringAction::Update => "update",
|
|
||||||
InitializationRequiringAction::Borrow => "borrow",
|
InitializationRequiringAction::Borrow => "borrow",
|
||||||
InitializationRequiringAction::MatchOn => "use", // no good noun
|
InitializationRequiringAction::MatchOn => "use", // no good noun
|
||||||
InitializationRequiringAction::Use => "use",
|
InitializationRequiringAction::Use => "use",
|
||||||
|
@ -1005,7 +955,6 @@ impl InitializationRequiringAction {
|
||||||
|
|
||||||
fn as_verb_in_past_tense(self) -> &'static str {
|
fn as_verb_in_past_tense(self) -> &'static str {
|
||||||
match self {
|
match self {
|
||||||
InitializationRequiringAction::Update => "updated",
|
|
||||||
InitializationRequiringAction::Borrow => "borrowed",
|
InitializationRequiringAction::Borrow => "borrowed",
|
||||||
InitializationRequiringAction::MatchOn => "matched on",
|
InitializationRequiringAction::MatchOn => "matched on",
|
||||||
InitializationRequiringAction::Use => "used",
|
InitializationRequiringAction::Use => "used",
|
||||||
|
@ -1242,23 +1191,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
|
||||||
location: Location,
|
location: Location,
|
||||||
place_span: (Place<'tcx>, Span),
|
place_span: (Place<'tcx>, Span),
|
||||||
kind: AccessDepth,
|
kind: AccessDepth,
|
||||||
mode: MutateMode,
|
|
||||||
flow_state: &Flows<'cx, 'tcx>,
|
flow_state: &Flows<'cx, 'tcx>,
|
||||||
) {
|
) {
|
||||||
// Write of P[i] or *P, or WriteAndRead of any P, requires P init'd.
|
// Write of P[i] or *P requires P init'd.
|
||||||
match mode {
|
|
||||||
MutateMode::WriteAndRead => {
|
|
||||||
self.check_if_path_or_subpath_is_moved(
|
|
||||||
location,
|
|
||||||
InitializationRequiringAction::Update,
|
|
||||||
(place_span.0.as_ref(), place_span.1),
|
|
||||||
flow_state,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
MutateMode::JustWrite => {
|
|
||||||
self.check_if_assigned_path_is_moved(location, place_span, flow_state);
|
self.check_if_assigned_path_is_moved(location, place_span, flow_state);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Special case: you can assign an immutable local variable
|
// Special case: you can assign an immutable local variable
|
||||||
// (e.g., `x = ...`) so long as it has never been initialized
|
// (e.g., `x = ...`) so long as it has never been initialized
|
||||||
|
|
|
@ -1478,7 +1478,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);
|
||||||
|
|
|
@ -508,7 +508,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;
|
||||||
|
|
|
@ -751,10 +751,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 => {}
|
||||||
|
|
|
@ -1,12 +1,9 @@
|
||||||
|
#### Note: this error code is no longer emitted by the compiler.
|
||||||
|
|
||||||
The argument to the `llvm_asm` macro is not well-formed.
|
The argument to the `llvm_asm` macro is not well-formed.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0660
|
```ignore (no longer emitted)
|
||||||
llvm_asm!("nop" "nop");
|
llvm_asm!("nop" "nop");
|
||||||
```
|
```
|
||||||
|
|
||||||
Considering that this would be a long explanation, we instead recommend you
|
|
||||||
take a look at the [`llvm_asm`] chapter of the Unstable book:
|
|
||||||
|
|
||||||
[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
|
|
||||||
|
|
|
@ -1,13 +1,10 @@
|
||||||
|
#### Note: this error code is no longer emitted by the compiler.
|
||||||
|
|
||||||
An invalid syntax was passed to the second argument of an `llvm_asm` macro line.
|
An invalid syntax was passed to the second argument of an `llvm_asm` macro line.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0661
|
```ignore (no longer emitted)
|
||||||
let a;
|
let a;
|
||||||
llvm_asm!("nop" : "r"(a));
|
llvm_asm!("nop" : "r"(a));
|
||||||
```
|
```
|
||||||
|
|
||||||
Considering that this would be a long explanation, we instead recommend you
|
|
||||||
take a look at the [`llvm_asm`] chapter of the Unstable book:
|
|
||||||
|
|
||||||
[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
|
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
|
#### Note: this error code is no longer emitted by the compiler.
|
||||||
|
|
||||||
An invalid input operand constraint was passed to the `llvm_asm` macro
|
An invalid input operand constraint was passed to the `llvm_asm` macro
|
||||||
(third line).
|
(third line).
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0662
|
```ignore (no longer emitted)
|
||||||
llvm_asm!("xor %eax, %eax"
|
llvm_asm!("xor %eax, %eax"
|
||||||
:
|
:
|
||||||
: "=test"("a")
|
: "=test"("a")
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Considering that this would be a long explanation, we instead recommend you
|
|
||||||
take a look at the [`llvm_asm`] chapter of the Unstable book:
|
|
||||||
|
|
||||||
[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
|
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
|
#### Note: this error code is no longer emitted by the compiler.
|
||||||
|
|
||||||
An invalid input operand constraint was passed to the `llvm_asm` macro
|
An invalid input operand constraint was passed to the `llvm_asm` macro
|
||||||
(third line).
|
(third line).
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0663
|
```ignore (no longer emitted)
|
||||||
llvm_asm!("xor %eax, %eax"
|
llvm_asm!("xor %eax, %eax"
|
||||||
:
|
:
|
||||||
: "+test"("a")
|
: "+test"("a")
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Considering that this would be a long explanation, we instead recommend you
|
|
||||||
take a look at the [`llvm_asm`] chapter of the Unstable book:
|
|
||||||
|
|
||||||
[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
|
|
||||||
|
|
|
@ -1,16 +1,13 @@
|
||||||
|
#### Note: this error code is no longer emitted by the compiler.
|
||||||
|
|
||||||
A clobber was surrounded by braces in the `llvm_asm` macro.
|
A clobber was surrounded by braces in the `llvm_asm` macro.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0664
|
```ignore (no longer emitted)
|
||||||
llvm_asm!("mov $$0x200, %eax"
|
llvm_asm!("mov $$0x200, %eax"
|
||||||
:
|
:
|
||||||
:
|
:
|
||||||
: "{eax}"
|
: "{eax}"
|
||||||
);
|
);
|
||||||
```
|
```
|
||||||
|
|
||||||
Considering that this would be a long explanation, we instead recommend you
|
|
||||||
take a look at the [`llvm_asm`] chapter of the Unstable book:
|
|
||||||
|
|
||||||
[`llvm_asm`]: https://doc.rust-lang.org/stable/unstable-book/library-features/llvm-asm.html
|
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
#### Note: this error code is no longer emitted by the compiler.
|
||||||
|
|
||||||
Malformed inline assembly rejected by LLVM.
|
Malformed inline assembly rejected by LLVM.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0668
|
```ignore (no longer emitted)
|
||||||
#![feature(llvm_asm)]
|
#![feature(llvm_asm)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
|
#### Note: this error code is no longer emitted by the compiler.
|
||||||
|
|
||||||
Cannot convert inline assembly operand to a single LLVM value.
|
Cannot convert inline assembly operand to a single LLVM value.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,E0669
|
```ignore (no longer emitted)
|
||||||
#![feature(llvm_asm)]
|
#![feature(llvm_asm)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -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};
|
||||||
|
@ -1474,7 +1474,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,
|
||||||
|
@ -1534,7 +1533,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(..)
|
||||||
|
@ -1617,7 +1615,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(..)
|
||||||
|
@ -1758,8 +1755,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.
|
||||||
///
|
///
|
||||||
|
@ -2371,36 +2366,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> {
|
||||||
|
|
|
@ -1252,10 +1252,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);
|
||||||
|
|
|
@ -1566,10 +1566,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.
|
||||||
|
@ -1689,13 +1685,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::*;
|
||||||
|
@ -1720,9 +1709,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]),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,7 +219,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,
|
||||||
|
|
|
@ -569,7 +569,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.
|
||||||
|
|
|
@ -1032,8 +1032,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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -808,7 +808,6 @@ symbols! {
|
||||||
linkage,
|
linkage,
|
||||||
lint_reasons,
|
lint_reasons,
|
||||||
literal,
|
literal,
|
||||||
llvm_asm,
|
|
||||||
load,
|
load,
|
||||||
loaded_from_disk,
|
loaded_from_disk,
|
||||||
local,
|
local,
|
||||||
|
|
|
@ -479,7 +479,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)]
|
||||||
|
|
|
@ -1397,32 +1397,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_slice)]
|
#![feature(maybe_uninit_slice)]
|
||||||
|
@ -571,8 +570,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(
|
||||||
|
|
|
@ -1,190 +0,0 @@
|
||||||
# `llvm_asm`
|
|
||||||
|
|
||||||
The tracking issue for this feature is: [#70173]
|
|
||||||
|
|
||||||
[#70173]: https://github.com/rust-lang/rust/issues/70173
|
|
||||||
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
For extremely low-level manipulations and performance reasons, one
|
|
||||||
might wish to control the CPU directly. Rust supports using inline
|
|
||||||
assembly to do this via the `llvm_asm!` macro.
|
|
||||||
|
|
||||||
```rust,ignore (pseudo-code)
|
|
||||||
llvm_asm!(assembly template
|
|
||||||
: output operands
|
|
||||||
: input operands
|
|
||||||
: clobbers
|
|
||||||
: options
|
|
||||||
);
|
|
||||||
```
|
|
||||||
|
|
||||||
Any use of `llvm_asm` is feature gated (requires `#![feature(llvm_asm)]` on the
|
|
||||||
crate to allow) and of course requires an `unsafe` block.
|
|
||||||
|
|
||||||
> **Note**: the examples here are given in x86/x86-64 assembly, but
|
|
||||||
> all platforms are supported.
|
|
||||||
|
|
||||||
## Assembly template
|
|
||||||
|
|
||||||
The `assembly template` is the only required parameter and must be a
|
|
||||||
literal string (i.e. `""`)
|
|
||||||
|
|
||||||
```rust
|
|
||||||
#![feature(llvm_asm)]
|
|
||||||
|
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
||||||
fn foo() {
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("NOP");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Other platforms:
|
|
||||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
|
||||||
fn foo() { /* ... */ }
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
// ...
|
|
||||||
foo();
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
(The `feature(llvm_asm)` and `#[cfg]`s are omitted from now on.)
|
|
||||||
|
|
||||||
Output operands, input operands, clobbers and options are all optional
|
|
||||||
but you must add the right number of `:` if you skip them:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# #![feature(llvm_asm)]
|
|
||||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
||||||
# fn main() { unsafe {
|
|
||||||
llvm_asm!("xor %eax, %eax"
|
|
||||||
:
|
|
||||||
:
|
|
||||||
: "eax"
|
|
||||||
);
|
|
||||||
# } }
|
|
||||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
|
||||||
# fn main() {}
|
|
||||||
```
|
|
||||||
|
|
||||||
Whitespace also doesn't matter:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# #![feature(llvm_asm)]
|
|
||||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
||||||
# fn main() { unsafe {
|
|
||||||
llvm_asm!("xor %eax, %eax" ::: "eax");
|
|
||||||
# } }
|
|
||||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
|
||||||
# fn main() {}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Operands
|
|
||||||
|
|
||||||
Input and output operands follow the same format: `:
|
|
||||||
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
|
|
||||||
expressions must be mutable place, or not yet assigned:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# #![feature(llvm_asm)]
|
|
||||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
||||||
fn add(a: i32, b: i32) -> i32 {
|
|
||||||
let c: i32;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("add $2, $0"
|
|
||||||
: "=r"(c)
|
|
||||||
: "0"(a), "r"(b)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
c
|
|
||||||
}
|
|
||||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
|
||||||
# fn add(a: i32, b: i32) -> i32 { a + b }
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
assert_eq!(add(3, 14159), 14162)
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
If you would like to use real operands in this position, however,
|
|
||||||
you are required to put curly braces `{}` around the register that
|
|
||||||
you want, and you are required to put the specific size of the
|
|
||||||
operand. This is useful for very low level programming, where
|
|
||||||
which register you use is important:
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# #![feature(llvm_asm)]
|
|
||||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
||||||
# unsafe fn read_byte_in(port: u16) -> u8 {
|
|
||||||
let result: u8;
|
|
||||||
llvm_asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port));
|
|
||||||
result
|
|
||||||
# }
|
|
||||||
```
|
|
||||||
|
|
||||||
## Clobbers
|
|
||||||
|
|
||||||
Some instructions modify registers which might otherwise have held
|
|
||||||
different values so we use the clobbers list to indicate to the
|
|
||||||
compiler not to assume any values loaded into those registers will
|
|
||||||
stay valid.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# #![feature(llvm_asm)]
|
|
||||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
||||||
# fn main() { unsafe {
|
|
||||||
// Put the value 0x200 in eax:
|
|
||||||
llvm_asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
|
|
||||||
# } }
|
|
||||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
|
||||||
# fn main() {}
|
|
||||||
```
|
|
||||||
|
|
||||||
Input and output registers need not be listed since that information
|
|
||||||
is already communicated by the given constraints. Otherwise, any other
|
|
||||||
registers used either implicitly or explicitly should be listed.
|
|
||||||
|
|
||||||
If the assembly changes the condition code register `cc` should be
|
|
||||||
specified as one of the clobbers. Similarly, if the assembly modifies
|
|
||||||
memory, `memory` should also be specified.
|
|
||||||
|
|
||||||
## Options
|
|
||||||
|
|
||||||
The last section, `options` is specific to Rust. The format is comma
|
|
||||||
separated literal strings (i.e. `:"foo", "bar", "baz"`). It's used to
|
|
||||||
specify some extra info about the inline assembly:
|
|
||||||
|
|
||||||
Current valid options are:
|
|
||||||
|
|
||||||
1. `volatile` - specifying this is analogous to
|
|
||||||
`__asm__ __volatile__ (...)` in gcc/clang.
|
|
||||||
2. `alignstack` - certain instructions expect the stack to be
|
|
||||||
aligned a certain way (i.e. SSE) and specifying this indicates to
|
|
||||||
the compiler to insert its usual stack alignment code
|
|
||||||
3. `intel` - use intel syntax instead of the default AT&T.
|
|
||||||
|
|
||||||
```rust
|
|
||||||
# #![feature(llvm_asm)]
|
|
||||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
||||||
# fn main() {
|
|
||||||
let result: i32;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("mov eax, 2" : "={eax}"(result) : : : "intel")
|
|
||||||
}
|
|
||||||
println!("eax is currently {}", result);
|
|
||||||
# }
|
|
||||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
|
||||||
# fn main() {}
|
|
||||||
```
|
|
||||||
|
|
||||||
## More Information
|
|
||||||
|
|
||||||
The current implementation of the `llvm_asm!` macro is a direct binding to [LLVM's
|
|
||||||
inline assembler expressions][llvm-docs], so be sure to check out [their
|
|
||||||
documentation as well][llvm-docs] for more information about clobbers,
|
|
||||||
constraints, etc.
|
|
||||||
|
|
||||||
[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions
|
|
|
@ -1,14 +0,0 @@
|
||||||
// compile-flags: -O
|
|
||||||
|
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![crate_type = "lib"]
|
|
||||||
|
|
||||||
// Check that inline assembly expressions without any outputs
|
|
||||||
// are marked as having side effects / being volatile
|
|
||||||
|
|
||||||
// CHECK-LABEL: @assembly
|
|
||||||
#[no_mangle]
|
|
||||||
pub fn assembly() {
|
|
||||||
unsafe { llvm_asm!("") }
|
|
||||||
// CHECK: tail call void asm sideeffect "", {{.*}}
|
|
||||||
}
|
|
|
@ -18,22 +18,18 @@
|
||||||
|
|
||||||
#![allow(warnings)]
|
#![allow(warnings)]
|
||||||
#![feature(rustc_attrs)]
|
#![feature(rustc_attrs)]
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![crate_type="rlib"]
|
#![crate_type="rlib"]
|
||||||
|
|
||||||
|
use std::arch::asm;
|
||||||
|
|
||||||
// Change template
|
// Change template
|
||||||
#[cfg(any(cfail1,cfail4))]
|
#[cfg(any(cfail1,cfail4))]
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
pub fn change_template(a: i32) -> i32 {
|
pub fn change_template(_a: i32) -> i32 {
|
||||||
let c: i32;
|
let c: i32;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, 1",
|
||||||
: "=r"(c)
|
out(reg) c
|
||||||
: "0"(a)
|
|
||||||
:
|
|
||||||
:
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
c
|
c
|
||||||
|
@ -45,14 +41,11 @@ pub fn change_template(a: i32) -> i32 {
|
||||||
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
|
#[rustc_clean(cfg="cfail5", except="hir_owner_nodes, optimized_mir")]
|
||||||
#[rustc_clean(cfg="cfail6")]
|
#[rustc_clean(cfg="cfail6")]
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
pub fn change_template(a: i32) -> i32 {
|
pub fn change_template(_a: i32) -> i32 {
|
||||||
let c: i32;
|
let c: i32;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 2, $0"
|
asm!("mov {0}, 2",
|
||||||
: "=r"(c)
|
out(reg) c
|
||||||
: "0"(a)
|
|
||||||
:
|
|
||||||
:
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
c
|
c
|
||||||
|
@ -67,11 +60,9 @@ pub fn change_output(a: i32) -> i32 {
|
||||||
let mut _out1: i32 = 0;
|
let mut _out1: i32 = 0;
|
||||||
let mut _out2: i32 = 0;
|
let mut _out2: i32 = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, {1}",
|
||||||
: "=r"(_out1)
|
out(reg) _out1,
|
||||||
: "0"(a)
|
in(reg) a
|
||||||
:
|
|
||||||
:
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_out1
|
_out1
|
||||||
|
@ -87,11 +78,9 @@ pub fn change_output(a: i32) -> i32 {
|
||||||
let mut _out1: i32 = 0;
|
let mut _out1: i32 = 0;
|
||||||
let mut _out2: i32 = 0;
|
let mut _out2: i32 = 0;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, {1}",
|
||||||
: "=r"(_out2)
|
out(reg) _out2,
|
||||||
: "0"(a)
|
in(reg) a
|
||||||
:
|
|
||||||
:
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_out1
|
_out1
|
||||||
|
@ -105,11 +94,9 @@ pub fn change_output(a: i32) -> i32 {
|
||||||
pub fn change_input(_a: i32, _b: i32) -> i32 {
|
pub fn change_input(_a: i32, _b: i32) -> i32 {
|
||||||
let _out;
|
let _out;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, {1}",
|
||||||
: "=r"(_out)
|
out(reg) _out,
|
||||||
: "0"(_a)
|
in(reg) _a
|
||||||
:
|
|
||||||
:
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_out
|
_out
|
||||||
|
@ -124,11 +111,9 @@ pub fn change_input(_a: i32, _b: i32) -> i32 {
|
||||||
pub fn change_input(_a: i32, _b: i32) -> i32 {
|
pub fn change_input(_a: i32, _b: i32) -> i32 {
|
||||||
let _out;
|
let _out;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, {1}",
|
||||||
: "=r"(_out)
|
out(reg) _out,
|
||||||
: "0"(_b)
|
in(reg) _b
|
||||||
:
|
|
||||||
:
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_out
|
_out
|
||||||
|
@ -142,12 +127,10 @@ pub fn change_input(_a: i32, _b: i32) -> i32 {
|
||||||
pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
|
pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
|
||||||
let _out;
|
let _out;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, {1}",
|
||||||
: "=r"(_out)
|
out(reg) _out,
|
||||||
: "0"(_a), "r"(_b)
|
in(reg) _a,
|
||||||
:
|
in("eax") _b);
|
||||||
:
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_out
|
_out
|
||||||
}
|
}
|
||||||
|
@ -161,29 +144,25 @@ pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
|
||||||
pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
|
pub fn change_input_constraint(_a: i32, _b: i32) -> i32 {
|
||||||
let _out;
|
let _out;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, {1}",
|
||||||
: "=r"(_out)
|
out(reg) _out,
|
||||||
: "r"(_a), "0"(_b)
|
in(reg) _a,
|
||||||
:
|
in("ecx") _b);
|
||||||
:
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
_out
|
_out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Change clobber
|
// Change clobber
|
||||||
#[cfg(any(cfail1,cfail4))]
|
#[cfg(any(cfail1,cfail4))]
|
||||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||||
pub fn change_clobber(_a: i32) -> i32 {
|
pub fn change_clobber(_a: i32) -> i32 {
|
||||||
let _out;
|
let _out;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, {1}",
|
||||||
: "=r"(_out)
|
out(reg) _out,
|
||||||
: "0"(_a)
|
in(reg) _a,
|
||||||
:/*--*/
|
lateout("ecx") _
|
||||||
:
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_out
|
_out
|
||||||
|
@ -198,11 +177,10 @@ pub fn change_clobber(_a: i32) -> i32 {
|
||||||
pub fn change_clobber(_a: i32) -> i32 {
|
pub fn change_clobber(_a: i32) -> i32 {
|
||||||
let _out;
|
let _out;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, {1}",
|
||||||
: "=r"(_out)
|
out(reg) _out,
|
||||||
: "0"(_a)
|
in(reg) _a,
|
||||||
: "eax"
|
lateout("edx") _
|
||||||
:
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_out
|
_out
|
||||||
|
@ -216,11 +194,10 @@ pub fn change_clobber(_a: i32) -> i32 {
|
||||||
pub fn change_options(_a: i32) -> i32 {
|
pub fn change_options(_a: i32) -> i32 {
|
||||||
let _out;
|
let _out;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, {1}",
|
||||||
: "=r"(_out)
|
out(reg) _out,
|
||||||
: "0"(_a)
|
in(reg) _a,
|
||||||
:
|
options(readonly),
|
||||||
:/*-------*/
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_out
|
_out
|
||||||
|
@ -235,11 +212,10 @@ pub fn change_options(_a: i32) -> i32 {
|
||||||
pub fn change_options(_a: i32) -> i32 {
|
pub fn change_options(_a: i32) -> i32 {
|
||||||
let _out;
|
let _out;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("add 1, $0"
|
asm!("mov {0}, {1}",
|
||||||
: "=r"(_out)
|
out(reg) _out,
|
||||||
: "0"(_a)
|
in(reg) _a,
|
||||||
:
|
options(nomem ),
|
||||||
: "volatile"
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
_out
|
_out
|
||||||
|
|
|
@ -1,75 +0,0 @@
|
||||||
- // MIR for `main` before UnreachablePropagation
|
|
||||||
+ // MIR for `main` after UnreachablePropagation
|
|
||||||
|
|
||||||
fn main() -> () {
|
|
||||||
let mut _0: (); // return place in scope 0 at $DIR/unreachable_asm.rs:10:11: 10:11
|
|
||||||
let mut _1: std::option::Option<Empty>; // in scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30
|
|
||||||
let mut _2: isize; // in scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
|
|
||||||
let _3: Empty; // in scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
|
|
||||||
let mut _4: i32; // in scope 0 at $DIR/unreachable_asm.rs:12:13: 12:19
|
|
||||||
let _5: (); // in scope 0 at $DIR/unreachable_asm.rs:14:9: 18:10
|
|
||||||
let mut _6: bool; // in scope 0 at $DIR/unreachable_asm.rs:14:12: 14:16
|
|
||||||
let _7: (); // in scope 0 at $DIR/unreachable_asm.rs:21:9: 21:37
|
|
||||||
let mut _8: !; // in scope 0 at $DIR/unreachable_asm.rs:22:9: 22:21
|
|
||||||
scope 1 {
|
|
||||||
debug _x => _3; // in scope 1 at $DIR/unreachable_asm.rs:11:17: 11:19
|
|
||||||
}
|
|
||||||
scope 2 {
|
|
||||||
debug _y => _4; // in scope 2 at $DIR/unreachable_asm.rs:12:13: 12:19
|
|
||||||
scope 3 {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bb0: {
|
|
||||||
StorageLive(_1); // scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30
|
|
||||||
_1 = empty() -> bb1; // scope 0 at $DIR/unreachable_asm.rs:11:23: 11:30
|
|
||||||
// mir::Constant
|
|
||||||
// + span: $DIR/unreachable_asm.rs:11:23: 11:28
|
|
||||||
// + literal: Const { ty: fn() -> std::option::Option<Empty> {empty}, val: Value(Scalar(<ZST>)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
bb1: {
|
|
||||||
_2 = discriminant(_1); // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
|
|
||||||
switchInt(move _2) -> [1_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/unreachable_asm.rs:11:12: 11:20
|
|
||||||
}
|
|
||||||
|
|
||||||
bb2: {
|
|
||||||
StorageLive(_3); // scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
|
|
||||||
_3 = move ((_1 as Some).0: Empty); // scope 0 at $DIR/unreachable_asm.rs:11:17: 11:19
|
|
||||||
StorageLive(_4); // scope 0 at $DIR/unreachable_asm.rs:12:13: 12:19
|
|
||||||
StorageLive(_5); // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10
|
|
||||||
StorageLive(_6); // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
|
|
||||||
_6 = const true; // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
|
|
||||||
switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable_asm.rs:14:12: 14:16
|
|
||||||
}
|
|
||||||
|
|
||||||
bb3: {
|
|
||||||
_4 = const 21_i32; // scope 2 at $DIR/unreachable_asm.rs:15:13: 15:20
|
|
||||||
_5 = const (); // scope 2 at $DIR/unreachable_asm.rs:14:17: 16:10
|
|
||||||
goto -> bb5; // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10
|
|
||||||
}
|
|
||||||
|
|
||||||
bb4: {
|
|
||||||
_4 = const 42_i32; // scope 2 at $DIR/unreachable_asm.rs:17:13: 17:20
|
|
||||||
_5 = const (); // scope 2 at $DIR/unreachable_asm.rs:16:16: 18:10
|
|
||||||
goto -> bb5; // scope 2 at $DIR/unreachable_asm.rs:14:9: 18:10
|
|
||||||
}
|
|
||||||
|
|
||||||
bb5: {
|
|
||||||
StorageDead(_6); // scope 2 at $DIR/unreachable_asm.rs:18:9: 18:10
|
|
||||||
StorageDead(_5); // scope 2 at $DIR/unreachable_asm.rs:18:9: 18:10
|
|
||||||
StorageLive(_7); // scope 2 at $DIR/unreachable_asm.rs:21:9: 21:37
|
|
||||||
llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm.rs:21:18: 21:34
|
|
||||||
_7 = const (); // scope 3 at $DIR/unreachable_asm.rs:21:9: 21:37
|
|
||||||
StorageDead(_7); // scope 2 at $DIR/unreachable_asm.rs:21:36: 21:37
|
|
||||||
StorageLive(_8); // scope 2 at $DIR/unreachable_asm.rs:22:9: 22:21
|
|
||||||
unreachable; // scope 2 at $DIR/unreachable_asm.rs:22:15: 22:17
|
|
||||||
}
|
|
||||||
|
|
||||||
bb6: {
|
|
||||||
_0 = const (); // scope 0 at $DIR/unreachable_asm.rs:23:6: 23:6
|
|
||||||
StorageDead(_1); // scope 0 at $DIR/unreachable_asm.rs:24:1: 24:2
|
|
||||||
return; // scope 0 at $DIR/unreachable_asm.rs:24:2: 24:2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,24 +0,0 @@
|
||||||
#![feature(llvm_asm)]
|
|
||||||
|
|
||||||
enum Empty {}
|
|
||||||
|
|
||||||
fn empty() -> Option<Empty> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
// EMIT_MIR unreachable_asm.main.UnreachablePropagation.diff
|
|
||||||
fn main() {
|
|
||||||
if let Some(_x) = empty() {
|
|
||||||
let mut _y;
|
|
||||||
|
|
||||||
if true {
|
|
||||||
_y = 21;
|
|
||||||
} else {
|
|
||||||
_y = 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
// asm instruction stops unreachable propagation to if else blocks bb4 and bb5.
|
|
||||||
unsafe { llvm_asm!("NOP"); }
|
|
||||||
match _x { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,85 +0,0 @@
|
||||||
- // MIR for `main` before UnreachablePropagation
|
|
||||||
+ // MIR for `main` after UnreachablePropagation
|
|
||||||
|
|
||||||
fn main() -> () {
|
|
||||||
let mut _0: (); // return place in scope 0 at $DIR/unreachable_asm_2.rs:10:11: 10:11
|
|
||||||
let mut _1: std::option::Option<Empty>; // in scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30
|
|
||||||
let mut _2: isize; // in scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
|
|
||||||
let _3: Empty; // in scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
|
|
||||||
let mut _4: i32; // in scope 0 at $DIR/unreachable_asm_2.rs:12:13: 12:19
|
|
||||||
let _5: (); // in scope 0 at $DIR/unreachable_asm_2.rs:14:9: 22:10
|
|
||||||
let mut _6: bool; // in scope 0 at $DIR/unreachable_asm_2.rs:14:12: 14:16
|
|
||||||
let _7: (); // in scope 0 at $DIR/unreachable_asm_2.rs:16:13: 16:41
|
|
||||||
let _8: (); // in scope 0 at $DIR/unreachable_asm_2.rs:20:13: 20:41
|
|
||||||
let mut _9: !; // in scope 0 at $DIR/unreachable_asm_2.rs:24:9: 24:21
|
|
||||||
scope 1 {
|
|
||||||
debug _x => _3; // in scope 1 at $DIR/unreachable_asm_2.rs:11:17: 11:19
|
|
||||||
}
|
|
||||||
scope 2 {
|
|
||||||
debug _y => _4; // in scope 2 at $DIR/unreachable_asm_2.rs:12:13: 12:19
|
|
||||||
scope 3 {
|
|
||||||
}
|
|
||||||
scope 4 {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bb0: {
|
|
||||||
StorageLive(_1); // scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30
|
|
||||||
_1 = empty() -> bb1; // scope 0 at $DIR/unreachable_asm_2.rs:11:23: 11:30
|
|
||||||
// mir::Constant
|
|
||||||
// + span: $DIR/unreachable_asm_2.rs:11:23: 11:28
|
|
||||||
// + literal: Const { ty: fn() -> std::option::Option<Empty> {empty}, val: Value(Scalar(<ZST>)) }
|
|
||||||
}
|
|
||||||
|
|
||||||
bb1: {
|
|
||||||
_2 = discriminant(_1); // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
|
|
||||||
- switchInt(move _2) -> [1_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
|
|
||||||
+ switchInt(move _2) -> [1_isize: bb2, otherwise: bb5]; // scope 0 at $DIR/unreachable_asm_2.rs:11:12: 11:20
|
|
||||||
}
|
|
||||||
|
|
||||||
bb2: {
|
|
||||||
StorageLive(_3); // scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
|
|
||||||
_3 = move ((_1 as Some).0: Empty); // scope 0 at $DIR/unreachable_asm_2.rs:11:17: 11:19
|
|
||||||
StorageLive(_4); // scope 0 at $DIR/unreachable_asm_2.rs:12:13: 12:19
|
|
||||||
StorageLive(_5); // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
|
|
||||||
StorageLive(_6); // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
|
|
||||||
_6 = const true; // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
|
|
||||||
switchInt(move _6) -> [false: bb4, otherwise: bb3]; // scope 2 at $DIR/unreachable_asm_2.rs:14:12: 14:16
|
|
||||||
}
|
|
||||||
|
|
||||||
bb3: {
|
|
||||||
StorageLive(_7); // scope 2 at $DIR/unreachable_asm_2.rs:16:13: 16:41
|
|
||||||
llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 3 at $DIR/unreachable_asm_2.rs:16:22: 16:38
|
|
||||||
_7 = const (); // scope 3 at $DIR/unreachable_asm_2.rs:16:13: 16:41
|
|
||||||
StorageDead(_7); // scope 2 at $DIR/unreachable_asm_2.rs:16:40: 16:41
|
|
||||||
_4 = const 21_i32; // scope 2 at $DIR/unreachable_asm_2.rs:17:13: 17:20
|
|
||||||
_5 = const (); // scope 2 at $DIR/unreachable_asm_2.rs:14:17: 18:10
|
|
||||||
- goto -> bb5; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
|
|
||||||
+ unreachable; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
|
|
||||||
}
|
|
||||||
|
|
||||||
bb4: {
|
|
||||||
StorageLive(_8); // scope 2 at $DIR/unreachable_asm_2.rs:20:13: 20:41
|
|
||||||
llvm_asm!(LlvmInlineAsmInner { asm: "NOP", asm_str_style: Cooked, outputs: [], inputs: [], clobbers: [], volatile: true, alignstack: false, dialect: Att } : [] : []); // scope 4 at $DIR/unreachable_asm_2.rs:20:22: 20:38
|
|
||||||
_8 = const (); // scope 4 at $DIR/unreachable_asm_2.rs:20:13: 20:41
|
|
||||||
StorageDead(_8); // scope 2 at $DIR/unreachable_asm_2.rs:20:40: 20:41
|
|
||||||
_4 = const 42_i32; // scope 2 at $DIR/unreachable_asm_2.rs:21:13: 21:20
|
|
||||||
_5 = const (); // scope 2 at $DIR/unreachable_asm_2.rs:18:16: 22:10
|
|
||||||
- goto -> bb5; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
|
|
||||||
+ unreachable; // scope 2 at $DIR/unreachable_asm_2.rs:14:9: 22:10
|
|
||||||
}
|
|
||||||
|
|
||||||
bb5: {
|
|
||||||
- StorageDead(_6); // scope 2 at $DIR/unreachable_asm_2.rs:22:9: 22:10
|
|
||||||
- StorageDead(_5); // scope 2 at $DIR/unreachable_asm_2.rs:22:9: 22:10
|
|
||||||
- StorageLive(_9); // scope 2 at $DIR/unreachable_asm_2.rs:24:9: 24:21
|
|
||||||
- unreachable; // scope 2 at $DIR/unreachable_asm_2.rs:24:15: 24:17
|
|
||||||
- }
|
|
||||||
-
|
|
||||||
- bb6: {
|
|
||||||
_0 = const (); // scope 0 at $DIR/unreachable_asm_2.rs:25:6: 25:6
|
|
||||||
StorageDead(_1); // scope 0 at $DIR/unreachable_asm_2.rs:26:1: 26:2
|
|
||||||
return; // scope 0 at $DIR/unreachable_asm_2.rs:26:2: 26:2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
#![feature(llvm_asm)]
|
|
||||||
|
|
||||||
enum Empty {}
|
|
||||||
|
|
||||||
fn empty() -> Option<Empty> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
// EMIT_MIR unreachable_asm_2.main.UnreachablePropagation.diff
|
|
||||||
fn main() {
|
|
||||||
if let Some(_x) = empty() {
|
|
||||||
let mut _y;
|
|
||||||
|
|
||||||
if true {
|
|
||||||
// asm instruction stops unreachable propagation to block bb3.
|
|
||||||
unsafe { llvm_asm!("NOP"); }
|
|
||||||
_y = 21;
|
|
||||||
} else {
|
|
||||||
// asm instruction stops unreachable propagation to block bb3.
|
|
||||||
unsafe { llvm_asm!("NOP"); }
|
|
||||||
_y = 42;
|
|
||||||
}
|
|
||||||
|
|
||||||
match _x { }
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
#![feature(llvm_asm)]
|
|
||||||
|
|
||||||
pub fn main() { unsafe { llvm_asm!("" : : : "hello", "world") }; }
|
|
|
@ -1,11 +0,0 @@
|
||||||
#![feature(llvm_asm)]
|
|
||||||
|
|
||||||
// pp-exact
|
|
||||||
|
|
||||||
pub fn main() {
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("" : : : : "volatile");
|
|
||||||
llvm_asm!("" : : : : "alignstack");
|
|
||||||
llvm_asm!("" : : : : "intel");
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,8 +1,8 @@
|
||||||
// pp-exact
|
// pp-exact
|
||||||
|
|
||||||
#![feature(llvm_asm)]
|
|
||||||
|
|
||||||
#[cfg(foo = r#"just parse this"#)]
|
#[cfg(foo = r#"just parse this"#)]
|
||||||
extern crate blah as blah;
|
extern crate blah as blah;
|
||||||
|
|
||||||
fn main() { unsafe { llvm_asm!(r###"blah"###); } }
|
use std::arch::asm;
|
||||||
|
|
||||||
|
fn main() { unsafe { asm!(r###"blah"###); } }
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![crate_type="lib"]
|
#![crate_type="lib"]
|
||||||
|
use std::arch::asm;
|
||||||
|
|
||||||
#[deny(unreachable_code)]
|
#[deny(unreachable_code)]
|
||||||
pub fn exit(n: usize) -> i32 {
|
pub fn exit(n: usize) -> i32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Pretend this asm is an exit() syscall.
|
// Pretend this asm is an exit() syscall.
|
||||||
llvm_asm!("" :: "r"(n) :: "volatile");
|
asm!("/*{0}*/", in(reg) n);
|
||||||
// Can't actually reach this point, but rustc doesn't know that.
|
|
||||||
}
|
}
|
||||||
// This return value is just here to generate some extra code for a return
|
// This return value is just here to generate some extra code for a return
|
||||||
// value, making it easier for the test script to detect whether the
|
// value, making it easier for the test script to detect whether the
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
#![feature(llvm_asm, core_intrinsics)]
|
#![feature(core_intrinsics)]
|
||||||
#![crate_type="lib"]
|
#![crate_type="lib"]
|
||||||
|
use std::arch::asm;
|
||||||
|
|
||||||
use std::intrinsics;
|
use std::intrinsics;
|
||||||
|
|
||||||
|
@ -7,7 +8,7 @@ use std::intrinsics;
|
||||||
pub fn exit(n: usize) -> i32 {
|
pub fn exit(n: usize) -> i32 {
|
||||||
unsafe {
|
unsafe {
|
||||||
// Pretend this asm is an exit() syscall.
|
// Pretend this asm is an exit() syscall.
|
||||||
llvm_asm!("" :: "r"(n) :: "volatile");
|
asm!("/*{0}*/", in(reg) n);
|
||||||
intrinsics::unreachable()
|
intrinsics::unreachable()
|
||||||
}
|
}
|
||||||
// This return value is just here to generate some extra code for a return
|
// This return value is just here to generate some extra code for a return
|
||||||
|
|
|
@ -5,9 +5,7 @@
|
||||||
// ignore-android
|
// ignore-android
|
||||||
// ignore-arm
|
// ignore-arm
|
||||||
// ignore-aarch64
|
// ignore-aarch64
|
||||||
|
#![feature(asm_sym)]
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![allow(deprecated)] // llvm_asm!
|
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64,
|
pub extern "sysv64" fn all_the_registers(rdi: i64, rsi: i64, rdx: i64,
|
||||||
|
@ -54,37 +52,37 @@ pub extern "sysv64" fn large_struct_by_val(mut foo: LargeStruct) -> LargeStruct
|
||||||
|
|
||||||
#[cfg(target_arch = "x86_64")]
|
#[cfg(target_arch = "x86_64")]
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
|
use std::arch::asm;
|
||||||
|
|
||||||
let result: i64;
|
let result: i64;
|
||||||
unsafe {
|
unsafe {
|
||||||
llvm_asm!("mov rdi, 1;
|
asm!("mov rdi, 1",
|
||||||
mov rsi, 2;
|
"mov rsi, 2",
|
||||||
mov rdx, 3;
|
"mov rdx, 3",
|
||||||
mov rcx, 4;
|
"mov rcx, 4",
|
||||||
mov r8, 5;
|
"mov r8, 5",
|
||||||
mov r9, 6;
|
"mov r9, 6",
|
||||||
mov eax, 0x3F800000;
|
"mov eax, 0x3F800000",
|
||||||
movd xmm0, eax;
|
"movd xmm0, eax",
|
||||||
mov eax, 0x40000000;
|
"mov eax, 0x40000000",
|
||||||
movd xmm1, eax;
|
"movd xmm1, eax",
|
||||||
mov eax, 0x40800000;
|
"mov eax, 0x40800000",
|
||||||
movd xmm2, eax;
|
"movd xmm2, eax",
|
||||||
mov eax, 0x41000000;
|
"mov eax, 0x41000000",
|
||||||
movd xmm3, eax;
|
"movd xmm3, eax",
|
||||||
mov eax, 0x41800000;
|
"mov eax, 0x41800000",
|
||||||
movd xmm4, eax;
|
"movd xmm4, eax",
|
||||||
mov eax, 0x42000000;
|
"mov eax, 0x42000000",
|
||||||
movd xmm5, eax;
|
"movd xmm5, eax",
|
||||||
mov eax, 0x42800000;
|
"mov eax, 0x42800000",
|
||||||
movd xmm6, eax;
|
"movd xmm6, eax",
|
||||||
mov eax, 0x43000000;
|
"mov eax, 0x43000000",
|
||||||
movd xmm7, eax;
|
"movd xmm7, eax",
|
||||||
call r10
|
"call {0}",
|
||||||
"
|
sym all_the_registers,
|
||||||
: "={rax}"(result)
|
out("rax") result,
|
||||||
: "{r10}"(all_the_registers as usize)
|
clobber_abi("sysv64"),
|
||||||
: "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r11", "cc", "memory"
|
);
|
||||||
: "intel", "alignstack"
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
assert_eq!(result, 42);
|
assert_eq!(result, 42);
|
||||||
|
|
||||||
|
|
|
@ -3,12 +3,10 @@
|
||||||
// ignore-spirv
|
// ignore-spirv
|
||||||
// ignore-wasm32
|
// ignore-wasm32
|
||||||
|
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![feature(naked_functions)]
|
#![feature(naked_functions)]
|
||||||
#![feature(or_patterns)]
|
#![feature(or_patterns)]
|
||||||
#![feature(asm_const, asm_sym)]
|
#![feature(asm_const, asm_sym)]
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
#![allow(deprecated)] // llvm_asm!
|
|
||||||
|
|
||||||
use std::arch::asm;
|
use std::arch::asm;
|
||||||
|
|
||||||
|
@ -114,16 +112,6 @@ pub fn outer(x: u32) -> extern "C" fn(usize) -> usize {
|
||||||
inner
|
inner
|
||||||
}
|
}
|
||||||
|
|
||||||
#[naked]
|
|
||||||
unsafe extern "C" fn llvm() -> ! {
|
|
||||||
//~^ WARN naked functions must contain a single asm block
|
|
||||||
//~| WARN this was previously accepted
|
|
||||||
llvm_asm!("");
|
|
||||||
//~^ WARN LLVM-style inline assembly is unsupported in naked functions
|
|
||||||
//~| WARN this was previously accepted
|
|
||||||
core::hint::unreachable_unchecked();
|
|
||||||
}
|
|
||||||
|
|
||||||
#[naked]
|
#[naked]
|
||||||
unsafe extern "C" fn invalid_options() {
|
unsafe extern "C" fn invalid_options() {
|
||||||
asm!("", options(nomem, preserves_flags, noreturn));
|
asm!("", options(nomem, preserves_flags, noreturn));
|
||||||
|
|
|
@ -1,35 +1,35 @@
|
||||||
error: asm with the `pure` option must have at least one output
|
error: asm with the `pure` option must have at least one output
|
||||||
--> $DIR/naked-functions.rs:136:14
|
--> $DIR/naked-functions.rs:124:14
|
||||||
|
|
|
|
||||||
LL | asm!("", options(readonly, nostack), options(pure));
|
LL | asm!("", options(readonly, nostack), options(pure));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: patterns not allowed in naked function parameters
|
error: patterns not allowed in naked function parameters
|
||||||
--> $DIR/naked-functions.rs:23:5
|
--> $DIR/naked-functions.rs:21:5
|
||||||
|
|
|
|
||||||
LL | mut a: u32,
|
LL | mut a: u32,
|
||||||
| ^^^^^
|
| ^^^^^
|
||||||
|
|
||||||
error: patterns not allowed in naked function parameters
|
error: patterns not allowed in naked function parameters
|
||||||
--> $DIR/naked-functions.rs:25:5
|
--> $DIR/naked-functions.rs:23:5
|
||||||
|
|
|
|
||||||
LL | &b: &i32,
|
LL | &b: &i32,
|
||||||
| ^^
|
| ^^
|
||||||
|
|
||||||
error: patterns not allowed in naked function parameters
|
error: patterns not allowed in naked function parameters
|
||||||
--> $DIR/naked-functions.rs:27:6
|
--> $DIR/naked-functions.rs:25:6
|
||||||
|
|
|
|
||||||
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
|
LL | (None | Some(_)): Option<std::ptr::NonNull<u8>>,
|
||||||
| ^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^
|
||||||
|
|
||||||
error: patterns not allowed in naked function parameters
|
error: patterns not allowed in naked function parameters
|
||||||
--> $DIR/naked-functions.rs:29:5
|
--> $DIR/naked-functions.rs:27:5
|
||||||
|
|
|
|
||||||
LL | P { x, y }: P,
|
LL | P { x, y }: P,
|
||||||
| ^^^^^^^^^^
|
| ^^^^^^^^^^
|
||||||
|
|
||||||
error: referencing function parameters is not allowed in naked functions
|
error: referencing function parameters is not allowed in naked functions
|
||||||
--> $DIR/naked-functions.rs:39:5
|
--> $DIR/naked-functions.rs:37:5
|
||||||
|
|
|
|
||||||
LL | a + 1
|
LL | a + 1
|
||||||
| ^
|
| ^
|
||||||
|
@ -37,7 +37,7 @@ LL | a + 1
|
||||||
= help: follow the calling convention in asm block to use parameters
|
= help: follow the calling convention in asm block to use parameters
|
||||||
|
|
||||||
warning: naked functions must contain a single asm block
|
warning: naked functions must contain a single asm block
|
||||||
--> $DIR/naked-functions.rs:36:1
|
--> $DIR/naked-functions.rs:34:1
|
||||||
|
|
|
|
||||||
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
|
LL | / pub unsafe extern "C" fn inc(a: u32) -> u32 {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -53,7 +53,7 @@ LL | | }
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
error: referencing function parameters is not allowed in naked functions
|
error: referencing function parameters is not allowed in naked functions
|
||||||
--> $DIR/naked-functions.rs:45:31
|
--> $DIR/naked-functions.rs:43:31
|
||||||
|
|
|
|
||||||
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
|
||||||
| ^
|
| ^
|
||||||
|
@ -61,7 +61,7 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn));
|
||||||
= help: follow the calling convention in asm block to use parameters
|
= help: follow the calling convention in asm block to use parameters
|
||||||
|
|
||||||
warning: only `const` and `sym` operands are supported in naked functions
|
warning: only `const` and `sym` operands are supported in naked functions
|
||||||
--> $DIR/naked-functions.rs:45:23
|
--> $DIR/naked-functions.rs:43:23
|
||||||
|
|
|
|
||||||
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
|
LL | asm!("/* {0} */", in(reg) a, options(noreturn));
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -70,7 +70,7 @@ LL | asm!("/* {0} */", in(reg) a, options(noreturn));
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: naked functions must contain a single asm block
|
warning: naked functions must contain a single asm block
|
||||||
--> $DIR/naked-functions.rs:52:1
|
--> $DIR/naked-functions.rs:50:1
|
||||||
|
|
|
|
||||||
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
|
LL | / pub unsafe extern "C" fn inc_closure(a: u32) -> u32 {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -84,7 +84,7 @@ LL | | }
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: only `const` and `sym` operands are supported in naked functions
|
warning: only `const` and `sym` operands are supported in naked functions
|
||||||
--> $DIR/naked-functions.rs:72:10
|
--> $DIR/naked-functions.rs:70:10
|
||||||
|
|
|
|
||||||
LL | in(reg) a,
|
LL | in(reg) a,
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -102,7 +102,7 @@ LL | out(reg) e,
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: asm in naked functions must use `noreturn` option
|
warning: asm in naked functions must use `noreturn` option
|
||||||
--> $DIR/naked-functions.rs:69:5
|
--> $DIR/naked-functions.rs:67:5
|
||||||
|
|
|
|
||||||
LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
|
LL | / asm!("/* {0} {1} {2} {3} {4} {5} {6} */",
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -117,7 +117,7 @@ LL | | );
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: naked functions must contain a single asm block
|
warning: naked functions must contain a single asm block
|
||||||
--> $DIR/naked-functions.rs:59:1
|
--> $DIR/naked-functions.rs:57:1
|
||||||
|
|
|
|
||||||
LL | / pub unsafe extern "C" fn unsupported_operands() {
|
LL | / pub unsafe extern "C" fn unsupported_operands() {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -141,7 +141,7 @@ LL | | }
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: naked functions must contain a single asm block
|
warning: naked functions must contain a single asm block
|
||||||
--> $DIR/naked-functions.rs:85:1
|
--> $DIR/naked-functions.rs:83:1
|
||||||
|
|
|
|
||||||
LL | / pub extern "C" fn missing_assembly() {
|
LL | / pub extern "C" fn missing_assembly() {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -153,7 +153,7 @@ LL | | }
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: asm in naked functions must use `noreturn` option
|
warning: asm in naked functions must use `noreturn` option
|
||||||
--> $DIR/naked-functions.rs:94:5
|
--> $DIR/naked-functions.rs:92:5
|
||||||
|
|
|
|
||||||
LL | asm!("");
|
LL | asm!("");
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -162,7 +162,7 @@ LL | asm!("");
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: asm in naked functions must use `noreturn` option
|
warning: asm in naked functions must use `noreturn` option
|
||||||
--> $DIR/naked-functions.rs:97:5
|
--> $DIR/naked-functions.rs:95:5
|
||||||
|
|
|
|
||||||
LL | asm!("");
|
LL | asm!("");
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -171,7 +171,7 @@ LL | asm!("");
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: asm in naked functions must use `noreturn` option
|
warning: asm in naked functions must use `noreturn` option
|
||||||
--> $DIR/naked-functions.rs:100:5
|
--> $DIR/naked-functions.rs:98:5
|
||||||
|
|
|
|
||||||
LL | asm!("");
|
LL | asm!("");
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
@ -180,7 +180,7 @@ LL | asm!("");
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: naked functions must contain a single asm block
|
warning: naked functions must contain a single asm block
|
||||||
--> $DIR/naked-functions.rs:91:1
|
--> $DIR/naked-functions.rs:89:1
|
||||||
|
|
|
|
||||||
LL | / pub extern "C" fn too_many_asm_blocks() {
|
LL | / pub extern "C" fn too_many_asm_blocks() {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -202,7 +202,7 @@ LL | | }
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
error: referencing function parameters is not allowed in naked functions
|
error: referencing function parameters is not allowed in naked functions
|
||||||
--> $DIR/naked-functions.rs:111:11
|
--> $DIR/naked-functions.rs:109:11
|
||||||
|
|
|
|
||||||
LL | *&y
|
LL | *&y
|
||||||
| ^
|
| ^
|
||||||
|
@ -210,7 +210,7 @@ LL | *&y
|
||||||
= help: follow the calling convention in asm block to use parameters
|
= help: follow the calling convention in asm block to use parameters
|
||||||
|
|
||||||
warning: naked functions must contain a single asm block
|
warning: naked functions must contain a single asm block
|
||||||
--> $DIR/naked-functions.rs:108:5
|
--> $DIR/naked-functions.rs:106:5
|
||||||
|
|
|
|
||||||
LL | / pub extern "C" fn inner(y: usize) -> usize {
|
LL | / pub extern "C" fn inner(y: usize) -> usize {
|
||||||
LL | |
|
LL | |
|
||||||
|
@ -224,35 +224,8 @@ LL | | }
|
||||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: the LLVM-style inline assembly is unsupported in naked functions
|
|
||||||
--> $DIR/naked-functions.rs:121:5
|
|
||||||
|
|
|
||||||
LL | llvm_asm!("");
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
|
||||||
= help: use the new asm! syntax specified in RFC 2873
|
|
||||||
= note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
|
|
||||||
|
|
||||||
warning: naked functions must contain a single asm block
|
|
||||||
--> $DIR/naked-functions.rs:118:1
|
|
||||||
|
|
|
||||||
LL | / unsafe extern "C" fn llvm() -> ! {
|
|
||||||
LL | |
|
|
||||||
LL | |
|
|
||||||
LL | | llvm_asm!("");
|
|
||||||
... |
|
|
||||||
LL | | core::hint::unreachable_unchecked();
|
|
||||||
| | ------------------------------------ non-asm is unsupported in naked functions
|
|
||||||
LL | | }
|
|
||||||
| |_^
|
|
||||||
|
|
|
||||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
|
||||||
|
|
||||||
warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
|
warning: asm options unsupported in naked functions: `nomem`, `preserves_flags`
|
||||||
--> $DIR/naked-functions.rs:129:5
|
--> $DIR/naked-functions.rs:117:5
|
||||||
|
|
|
|
||||||
LL | asm!("", options(nomem, preserves_flags, noreturn));
|
LL | asm!("", options(nomem, preserves_flags, noreturn));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -261,7 +234,7 @@ LL | asm!("", options(nomem, preserves_flags, noreturn));
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
|
warning: asm options unsupported in naked functions: `nostack`, `pure`, `readonly`
|
||||||
--> $DIR/naked-functions.rs:136:5
|
--> $DIR/naked-functions.rs:124:5
|
||||||
|
|
|
|
||||||
LL | asm!("", options(readonly, nostack), options(pure));
|
LL | asm!("", options(readonly, nostack), options(pure));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -270,7 +243,7 @@ LL | asm!("", options(readonly, nostack), options(pure));
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: asm in naked functions must use `noreturn` option
|
warning: asm in naked functions must use `noreturn` option
|
||||||
--> $DIR/naked-functions.rs:136:5
|
--> $DIR/naked-functions.rs:124:5
|
||||||
|
|
|
|
||||||
LL | asm!("", options(readonly, nostack), options(pure));
|
LL | asm!("", options(readonly, nostack), options(pure));
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
@ -279,7 +252,7 @@ LL | asm!("", options(readonly, nostack), options(pure));
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: Rust ABI is unsupported in naked functions
|
warning: Rust ABI is unsupported in naked functions
|
||||||
--> $DIR/naked-functions.rs:145:15
|
--> $DIR/naked-functions.rs:133:15
|
||||||
|
|
|
|
||||||
LL | pub unsafe fn default_abi() {
|
LL | pub unsafe fn default_abi() {
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
|
@ -287,13 +260,13 @@ LL | pub unsafe fn default_abi() {
|
||||||
= note: `#[warn(undefined_naked_function_abi)]` on by default
|
= note: `#[warn(undefined_naked_function_abi)]` on by default
|
||||||
|
|
||||||
warning: Rust ABI is unsupported in naked functions
|
warning: Rust ABI is unsupported in naked functions
|
||||||
--> $DIR/naked-functions.rs:151:15
|
--> $DIR/naked-functions.rs:139:15
|
||||||
|
|
|
|
||||||
LL | pub unsafe fn rust_abi() {
|
LL | pub unsafe fn rust_abi() {
|
||||||
| ^^^^^^^^
|
| ^^^^^^^^
|
||||||
|
|
||||||
warning: naked functions cannot be inlined
|
warning: naked functions cannot be inlined
|
||||||
--> $DIR/naked-functions.rs:191:1
|
--> $DIR/naked-functions.rs:179:1
|
||||||
|
|
|
|
||||||
LL | #[inline]
|
LL | #[inline]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -302,7 +275,7 @@ LL | #[inline]
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: naked functions cannot be inlined
|
warning: naked functions cannot be inlined
|
||||||
--> $DIR/naked-functions.rs:199:1
|
--> $DIR/naked-functions.rs:187:1
|
||||||
|
|
|
|
||||||
LL | #[inline(always)]
|
LL | #[inline(always)]
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
@ -311,7 +284,7 @@ LL | #[inline(always)]
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: naked functions cannot be inlined
|
warning: naked functions cannot be inlined
|
||||||
--> $DIR/naked-functions.rs:207:1
|
--> $DIR/naked-functions.rs:195:1
|
||||||
|
|
|
|
||||||
LL | #[inline(never)]
|
LL | #[inline(never)]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
@ -320,7 +293,7 @@ LL | #[inline(never)]
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: naked functions cannot be inlined
|
warning: naked functions cannot be inlined
|
||||||
--> $DIR/naked-functions.rs:215:1
|
--> $DIR/naked-functions.rs:203:1
|
||||||
|
|
|
|
||||||
LL | #[inline]
|
LL | #[inline]
|
||||||
| ^^^^^^^^^
|
| ^^^^^^^^^
|
||||||
|
@ -329,7 +302,7 @@ LL | #[inline]
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: naked functions cannot be inlined
|
warning: naked functions cannot be inlined
|
||||||
--> $DIR/naked-functions.rs:218:1
|
--> $DIR/naked-functions.rs:206:1
|
||||||
|
|
|
|
||||||
LL | #[inline(always)]
|
LL | #[inline(always)]
|
||||||
| ^^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^^
|
||||||
|
@ -338,7 +311,7 @@ LL | #[inline(always)]
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
warning: naked functions cannot be inlined
|
warning: naked functions cannot be inlined
|
||||||
--> $DIR/naked-functions.rs:221:1
|
--> $DIR/naked-functions.rs:209:1
|
||||||
|
|
|
|
||||||
LL | #[inline(never)]
|
LL | #[inline(never)]
|
||||||
| ^^^^^^^^^^^^^^^^
|
| ^^^^^^^^^^^^^^^^
|
||||||
|
@ -346,5 +319,5 @@ LL | #[inline(never)]
|
||||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||||
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
= note: for more information, see issue #32408 <https://github.com/rust-lang/rust/issues/32408>
|
||||||
|
|
||||||
error: aborting due to 8 previous errors; 25 warnings emitted
|
error: aborting due to 8 previous errors; 23 warnings emitted
|
||||||
|
|
||||||
|
|
|
@ -8,9 +8,6 @@
|
||||||
// check-pass
|
// check-pass
|
||||||
// dont-check-compiler-stdout - don't check for any AST change.
|
// dont-check-compiler-stdout - don't check for any AST change.
|
||||||
|
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![allow(deprecated)] // llvm_asm!
|
|
||||||
|
|
||||||
enum V {
|
enum V {
|
||||||
A(i32),
|
A(i32),
|
||||||
B { f: [i64; 3 + 4] }
|
B { f: [i64; 3 + 4] }
|
||||||
|
@ -27,12 +24,6 @@ macro_rules! call_println {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
#[cfg(any(target_arch = "x86",
|
|
||||||
target_arch = "x86_64",
|
|
||||||
target_arch = "arm",
|
|
||||||
target_arch = "aarch64"))]
|
|
||||||
unsafe { llvm_asm!(""::::); }
|
|
||||||
|
|
||||||
let x: (i32) = 35;
|
let x: (i32) = 35;
|
||||||
let y = x as i64<> + 5;
|
let y = x as i64<> + 5;
|
||||||
|
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
// ignore-s390x
|
|
||||||
// ignore-emscripten
|
|
||||||
// ignore-powerpc
|
|
||||||
// ignore-powerpc64
|
|
||||||
// ignore-powerpc64le
|
|
||||||
// ignore-riscv64
|
|
||||||
// ignore-sparc
|
|
||||||
// ignore-sparc64
|
|
||||||
|
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![allow(deprecated)] // llvm_asm!
|
|
||||||
|
|
||||||
#[cfg(any(target_arch = "x86",
|
|
||||||
target_arch = "x86_64",
|
|
||||||
target_arch = "arm",
|
|
||||||
target_arch = "aarch64",
|
|
||||||
target_arch = "mips",
|
|
||||||
target_arch = "mips64"))]
|
|
||||||
mod test_cases {
|
|
||||||
fn is_move() {
|
|
||||||
let y: &mut isize;
|
|
||||||
let x = &mut 0isize;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("nop" : : "r"(x));
|
|
||||||
}
|
|
||||||
let z = x; //~ ERROR use of moved value: `x`
|
|
||||||
}
|
|
||||||
|
|
||||||
fn in_is_read() {
|
|
||||||
let mut x = 3;
|
|
||||||
let y = &mut x;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("nop" : : "r"(x)); //~ ERROR cannot use
|
|
||||||
}
|
|
||||||
let z = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn out_is_assign() {
|
|
||||||
let x = 3;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("nop" : "=r"(x)); //~ ERROR cannot assign twice
|
|
||||||
}
|
|
||||||
let mut a = &mut 3;
|
|
||||||
let b = &*a;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("nop" : "=r"(a)); // OK, Shallow write to `a`
|
|
||||||
}
|
|
||||||
let c = b;
|
|
||||||
let d = *a;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rw_is_assign() {
|
|
||||||
let x = 3;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("nop" : "+r"(x)); //~ ERROR cannot assign twice
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn indirect_is_not_init() {
|
|
||||||
let x: i32;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("nop" : "=*r"(x)); //~ ERROR use of possibly-uninitialized variable
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn rw_is_read() {
|
|
||||||
let mut x = &mut 3;
|
|
||||||
let y = &*x;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("nop" : "+r"(x)); //~ ERROR cannot assign to `x` because it is borrowed
|
|
||||||
}
|
|
||||||
let z = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn two_moves() {
|
|
||||||
let x = &mut 2;
|
|
||||||
unsafe {
|
|
||||||
llvm_asm!("nop" : : "r"(x), "r"(x) ); //~ ERROR use of moved value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {}
|
|
|
@ -1,81 +0,0 @@
|
||||||
error[E0382]: use of moved value: `x`
|
|
||||||
--> $DIR/borrowck-asm.rs:26:17
|
|
||||||
|
|
|
||||||
LL | let x = &mut 0isize;
|
|
||||||
| - move occurs because `x` has type `&mut isize`, which does not implement the `Copy` trait
|
|
||||||
LL | unsafe {
|
|
||||||
LL | llvm_asm!("nop" : : "r"(x));
|
|
||||||
| - value moved here
|
|
||||||
LL | }
|
|
||||||
LL | let z = x;
|
|
||||||
| ^ value used here after move
|
|
||||||
|
|
||||||
error[E0503]: cannot use `x` because it was mutably borrowed
|
|
||||||
--> $DIR/borrowck-asm.rs:33:37
|
|
||||||
|
|
|
||||||
LL | let y = &mut x;
|
|
||||||
| ------ borrow of `x` occurs here
|
|
||||||
LL | unsafe {
|
|
||||||
LL | llvm_asm!("nop" : : "r"(x));
|
|
||||||
| ^ use of borrowed `x`
|
|
||||||
LL | }
|
|
||||||
LL | let z = y;
|
|
||||||
| - borrow later used here
|
|
||||||
|
|
||||||
error[E0384]: cannot assign twice to immutable variable `x`
|
|
||||||
--> $DIR/borrowck-asm.rs:41:36
|
|
||||||
|
|
|
||||||
LL | let x = 3;
|
|
||||||
| -
|
|
||||||
| |
|
|
||||||
| first assignment to `x`
|
|
||||||
| help: consider making this binding mutable: `mut x`
|
|
||||||
LL | unsafe {
|
|
||||||
LL | llvm_asm!("nop" : "=r"(x));
|
|
||||||
| ^ cannot assign twice to immutable variable
|
|
||||||
|
|
||||||
error[E0384]: cannot assign twice to immutable variable `x`
|
|
||||||
--> $DIR/borrowck-asm.rs:55:36
|
|
||||||
|
|
|
||||||
LL | let x = 3;
|
|
||||||
| -
|
|
||||||
| |
|
|
||||||
| first assignment to `x`
|
|
||||||
| help: consider making this binding mutable: `mut x`
|
|
||||||
LL | unsafe {
|
|
||||||
LL | llvm_asm!("nop" : "+r"(x));
|
|
||||||
| ^ cannot assign twice to immutable variable
|
|
||||||
|
|
||||||
error[E0381]: use of possibly-uninitialized variable: `x`
|
|
||||||
--> $DIR/borrowck-asm.rs:62:37
|
|
||||||
|
|
|
||||||
LL | llvm_asm!("nop" : "=*r"(x));
|
|
||||||
| ^ use of possibly-uninitialized `x`
|
|
||||||
|
|
||||||
error[E0506]: cannot assign to `x` because it is borrowed
|
|
||||||
--> $DIR/borrowck-asm.rs:70:36
|
|
||||||
|
|
|
||||||
LL | let y = &*x;
|
|
||||||
| --- borrow of `x` occurs here
|
|
||||||
LL | unsafe {
|
|
||||||
LL | llvm_asm!("nop" : "+r"(x));
|
|
||||||
| ^ assignment to borrowed `x` occurs here
|
|
||||||
LL | }
|
|
||||||
LL | let z = y;
|
|
||||||
| - borrow later used here
|
|
||||||
|
|
||||||
error[E0382]: use of moved value: `x`
|
|
||||||
--> $DIR/borrowck-asm.rs:78:45
|
|
||||||
|
|
|
||||||
LL | let x = &mut 2;
|
|
||||||
| - move occurs because `x` has type `&mut i32`, which does not implement the `Copy` trait
|
|
||||||
LL | unsafe {
|
|
||||||
LL | llvm_asm!("nop" : : "r"(x), "r"(x) );
|
|
||||||
| - ^ value used here after move
|
|
||||||
| |
|
|
||||||
| value moved here
|
|
||||||
|
|
||||||
error: aborting due to 7 previous errors
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0381, E0382, E0384, E0503, E0506.
|
|
||||||
For more information about an error, try `rustc --explain E0381`.
|
|
|
@ -1,24 +1,13 @@
|
||||||
// compile-flags: -Zunleash-the-miri-inside-of-you
|
// compile-flags: -Zunleash-the-miri-inside-of-you
|
||||||
// only-x86_64
|
// only-x86_64
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![allow(const_err)]
|
#![allow(const_err)]
|
||||||
#![allow(deprecated)] // llvm_asm!
|
|
||||||
|
|
||||||
use std::arch::asm;
|
use std::arch::asm;
|
||||||
|
|
||||||
fn main() {}
|
fn main() {}
|
||||||
|
|
||||||
// Make sure we catch executing inline assembly.
|
// Make sure we catch executing inline assembly.
|
||||||
static TEST_BAD1: () = {
|
static TEST_BAD: () = {
|
||||||
unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
|
|
||||||
//~^ ERROR could not evaluate static initializer
|
|
||||||
//~| NOTE inline assembly is not supported
|
|
||||||
//~| NOTE in this expansion of llvm_asm!
|
|
||||||
//~| NOTE in this expansion of llvm_asm!
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make sure we catch executing inline assembly.
|
|
||||||
static TEST_BAD2: () = {
|
|
||||||
unsafe { asm!("nop"); }
|
unsafe { asm!("nop"); }
|
||||||
//~^ ERROR could not evaluate static initializer
|
//~^ ERROR could not evaluate static initializer
|
||||||
//~| NOTE inline assembly is not supported
|
//~| NOTE inline assembly is not supported
|
||||||
|
|
|
@ -1,13 +1,5 @@
|
||||||
error[E0080]: could not evaluate static initializer
|
error[E0080]: could not evaluate static initializer
|
||||||
--> $DIR/inline_asm.rs:13:14
|
--> $DIR/inline_asm.rs:11:14
|
||||||
|
|
|
||||||
LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ inline assembly is not supported
|
|
||||||
|
|
|
||||||
= note: this error originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
|
|
||||||
|
|
||||||
error[E0080]: could not evaluate static initializer
|
|
||||||
--> $DIR/inline_asm.rs:22:14
|
|
||||||
|
|
|
|
||||||
LL | unsafe { asm!("nop"); }
|
LL | unsafe { asm!("nop"); }
|
||||||
| ^^^^^^^^^^^ inline assembly is not supported
|
| ^^^^^^^^^^^ inline assembly is not supported
|
||||||
|
@ -15,17 +7,11 @@ LL | unsafe { asm!("nop"); }
|
||||||
warning: skipping const checks
|
warning: skipping const checks
|
||||||
|
|
|
|
||||||
help: skipping check that does not even have a feature gate
|
help: skipping check that does not even have a feature gate
|
||||||
--> $DIR/inline_asm.rs:13:14
|
--> $DIR/inline_asm.rs:11:14
|
||||||
|
|
|
||||||
LL | unsafe { llvm_asm!("xor %eax, %eax" ::: "eax"); }
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
help: skipping check that does not even have a feature gate
|
|
||||||
--> $DIR/inline_asm.rs:22:14
|
|
||||||
|
|
|
|
||||||
LL | unsafe { asm!("nop"); }
|
LL | unsafe { asm!("nop"); }
|
||||||
| ^^^^^^^^^^^
|
| ^^^^^^^^^^^
|
||||||
= note: this warning originates in the macro `llvm_asm` (in Nightly builds, run with -Z macro-backtrace for more info)
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors; 1 warning emitted
|
error: aborting due to previous error; 1 warning emitted
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0080`.
|
For more information about this error, try `rustc --explain E0080`.
|
||||||
|
|
|
@ -1,10 +0,0 @@
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![allow(deprecated)] // llvm_asm!
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let a;
|
|
||||||
llvm_asm!("nop" "nop");
|
|
||||||
//~^ ERROR E0660
|
|
||||||
llvm_asm!("nop" "nop" : "=r"(a));
|
|
||||||
//~^ ERROR E0660
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
error[E0660]: malformed inline assembly
|
|
||||||
--> $DIR/E0660.rs:6:5
|
|
||||||
|
|
|
||||||
LL | llvm_asm!("nop" "nop");
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error[E0660]: malformed inline assembly
|
|
||||||
--> $DIR/E0660.rs:8:5
|
|
||||||
|
|
|
||||||
LL | llvm_asm!("nop" "nop" : "=r"(a));
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0660`.
|
|
|
@ -1,10 +0,0 @@
|
||||||
// ignore-emscripten
|
|
||||||
|
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![allow(deprecated)] // llvm_asm!
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let a; //~ ERROR type annotations needed
|
|
||||||
llvm_asm!("nop" : "r"(a));
|
|
||||||
//~^ ERROR E0661
|
|
||||||
}
|
|
|
@ -1,16 +0,0 @@
|
||||||
error[E0661]: output operand constraint lacks '=' or '+'
|
|
||||||
--> $DIR/E0661.rs:8:23
|
|
||||||
|
|
|
||||||
LL | llvm_asm!("nop" : "r"(a));
|
|
||||||
| ^^^
|
|
||||||
|
|
||||||
error[E0282]: type annotations needed
|
|
||||||
--> $DIR/E0661.rs:7:9
|
|
||||||
|
|
|
||||||
LL | let a;
|
|
||||||
| ^ consider giving `a` a type
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
|
||||||
|
|
||||||
Some errors have detailed explanations: E0282, E0661.
|
|
||||||
For more information about an error, try `rustc --explain E0282`.
|
|
|
@ -1,11 +0,0 @@
|
||||||
// ignore-emscripten
|
|
||||||
|
|
||||||
#![feature(llvm_asm)]
|
|
||||||
#![allow(deprecated)] // llvm_asm!
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
llvm_asm!("xor %eax, %eax"
|
|
||||||
:
|
|
||||||
: "=test"("a") //~ ERROR E0662
|
|
||||||
);
|
|
||||||
}
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue