1
Fork 0

Rollup merge of #119365 - nbdd0121:asm-goto, r=Amanieu

Add asm goto support to `asm!`

Tracking issue: #119364

This PR implements asm-goto support, using the syntax described in "future possibilities" section of [RFC2873](https://rust-lang.github.io/rfcs/2873-inline-asm.html#asm-goto).

Currently I have only implemented the `label` part, not the `fallthrough` part (i.e. fallthrough is implicit). This doesn't reduce the expressive though, since you can use label-break to get arbitrary control flow or simply set a value and rely on jump threading optimisation to get the desired control flow. I can add that later if deemed necessary.

r? ``@Amanieu``
cc ``@ojeda``
This commit is contained in:
Matthias Krüger 2024-03-08 08:19:17 +01:00 committed by GitHub
commit d774fbea7c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
76 changed files with 857 additions and 200 deletions

View file

@ -383,6 +383,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
line_spans,
}) => {
use rustc_middle::{mir, thir};
let destination_block = this.cfg.start_new_block();
let mut targets = if options.contains(InlineAsmOptions::NORETURN) {
vec![]
} else {
vec![destination_block]
};
let operands = operands
.into_iter()
.map(|op| match *op {
@ -438,14 +446,28 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
thir::InlineAsmOperand::SymStatic { def_id } => {
mir::InlineAsmOperand::SymStatic { def_id }
}
thir::InlineAsmOperand::Label { block } => {
let target = this.cfg.start_new_block();
let target_index = targets.len();
targets.push(target);
let tmp = this.get_unit_temp();
let target = unpack!(this.ast_block(tmp, target, block, source_info));
this.cfg.terminate(
target,
source_info,
TerminatorKind::Goto { target: destination_block },
);
mir::InlineAsmOperand::Label { target_index }
}
})
.collect();
if !options.contains(InlineAsmOptions::NORETURN) {
if !expr.ty.is_never() {
this.cfg.push_assign_unit(block, source_info, destination, this.tcx);
}
let destination_block = this.cfg.start_new_block();
this.cfg.terminate(
block,
source_info,
@ -454,11 +476,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
operands,
options,
line_spans,
destination: if options.contains(InlineAsmOptions::NORETURN) {
None
} else {
Some(destination_block)
},
targets,
unwind: if options.contains(InlineAsmOptions::MAY_UNWIND) {
UnwindAction::Continue
} else {

View file

@ -199,9 +199,10 @@ impl<'mir, 'tcx, C: TerminatorClassifier<'tcx>> TriColorVisitor<BasicBlocks<'tcx
| TerminatorKind::Unreachable
| TerminatorKind::Yield { .. } => ControlFlow::Break(NonRecursive),
// A diverging InlineAsm is treated as non-recursing
TerminatorKind::InlineAsm { destination, .. } => {
if destination.is_some() {
// A InlineAsm without targets (diverging and contains no labels)
// is treated as non-recursing.
TerminatorKind::InlineAsm { ref targets, .. } => {
if !targets.is_empty() {
ControlFlow::Continue(())
} else {
ControlFlow::Break(NonRecursive)

View file

@ -656,6 +656,9 @@ impl<'tcx> Cx<'tcx> {
hir::InlineAsmOperand::SymStatic { path: _, def_id } => {
InlineAsmOperand::SymStatic { def_id }
}
hir::InlineAsmOperand::Label { block } => {
InlineAsmOperand::Label { block: self.mirror_block(block) }
}
})
.collect(),
options: asm.options,

View file

@ -889,6 +889,12 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
print_indented!(self, "}", depth_lvl + 1);
}
InlineAsmOperand::Label { block } => {
print_indented!(self, "InlineAsmOperand::Block {", depth_lvl);
print_indented!(self, "block:", depth_lvl + 1);
self.print_block(*block, depth_lvl + 2);
print_indented!(self, "}", depth_lvl + 1);
}
}
}
}