Skip to content

Commit 3cb6323

Browse files
committed
Auto merge of rust-lang#119365 - nbdd0121:asm-goto, r=Amanieu
Add asm goto support to `asm!` Tracking issue: rust-lang#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`
2 parents 8c0b1fc + 626a5f5 commit 3cb6323

File tree

75 files changed

+853
-196
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

75 files changed

+853
-196
lines changed

compiler/rustc_ast/src/ast.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -2294,6 +2294,9 @@ pub enum InlineAsmOperand {
22942294
Sym {
22952295
sym: InlineAsmSym,
22962296
},
2297+
Label {
2298+
block: P<Block>,
2299+
},
22972300
}
22982301

22992302
impl InlineAsmOperand {
@@ -2303,7 +2306,7 @@ impl InlineAsmOperand {
23032306
| Self::Out { reg, .. }
23042307
| Self::InOut { reg, .. }
23052308
| Self::SplitInOut { reg, .. } => Some(reg),
2306-
Self::Const { .. } | Self::Sym { .. } => None,
2309+
Self::Const { .. } | Self::Sym { .. } | Self::Label { .. } => None,
23072310
}
23082311
}
23092312
}

compiler/rustc_ast/src/mut_visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1330,6 +1330,7 @@ pub fn noop_visit_inline_asm<T: MutVisitor>(asm: &mut InlineAsm, vis: &mut T) {
13301330
}
13311331
InlineAsmOperand::Const { anon_const } => vis.visit_anon_const(anon_const),
13321332
InlineAsmOperand::Sym { sym } => vis.visit_inline_asm_sym(sym),
1333+
InlineAsmOperand::Label { block } => vis.visit_block(block),
13331334
}
13341335
}
13351336
}

compiler/rustc_ast/src/visit.rs

+1
Original file line numberDiff line numberDiff line change
@@ -885,6 +885,7 @@ pub fn walk_inline_asm<'a, V: Visitor<'a>>(visitor: &mut V, asm: &'a InlineAsm)
885885
try_visit!(visitor.visit_anon_const(anon_const))
886886
}
887887
InlineAsmOperand::Sym { sym } => try_visit!(visitor.visit_inline_asm_sym(sym)),
888+
InlineAsmOperand::Label { block } => try_visit!(visitor.visit_block(block)),
888889
}
889890
}
890891
V::Result::output()

compiler/rustc_ast_lowering/messages.ftl

+3
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ ast_lowering_invalid_abi_suggestion = did you mean
8888
ast_lowering_invalid_asm_template_modifier_const =
8989
asm template modifiers are not allowed for `const` arguments
9090
91+
ast_lowering_invalid_asm_template_modifier_label =
92+
asm template modifiers are not allowed for `label` arguments
93+
9194
ast_lowering_invalid_asm_template_modifier_reg_class =
9295
invalid asm template modifier for this register class
9396

compiler/rustc_ast_lowering/src/asm.rs

+23-4
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ use crate::{ImplTraitContext, ImplTraitPosition, ParamMode, ResolverAstLoweringE
33
use super::errors::{
44
AbiSpecifiedMultipleTimes, AttSyntaxOnlyX86, ClobberAbiNotSupported,
55
InlineAsmUnsupportedTarget, InvalidAbiClobberAbi, InvalidAsmTemplateModifierConst,
6-
InvalidAsmTemplateModifierRegClass, InvalidAsmTemplateModifierRegClassSub,
7-
InvalidAsmTemplateModifierSym, InvalidRegister, InvalidRegisterClass, RegisterClassOnlyClobber,
8-
RegisterConflict,
6+
InvalidAsmTemplateModifierLabel, InvalidAsmTemplateModifierRegClass,
7+
InvalidAsmTemplateModifierRegClassSub, InvalidAsmTemplateModifierSym, InvalidRegister,
8+
InvalidRegisterClass, RegisterClassOnlyClobber, RegisterConflict,
99
};
1010
use super::LoweringContext;
1111

@@ -236,6 +236,18 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
236236
}
237237
}
238238
}
239+
InlineAsmOperand::Label { block } => {
240+
if !self.tcx.features().asm_goto {
241+
feature_err(
242+
sess,
243+
sym::asm_goto,
244+
*op_sp,
245+
"label operands for inline assembly are unstable",
246+
)
247+
.emit();
248+
}
249+
hir::InlineAsmOperand::Label { block: self.lower_block(block, false) }
250+
}
239251
};
240252
(op, self.lower_span(*op_sp))
241253
})
@@ -295,6 +307,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
295307
op_span: op_sp,
296308
});
297309
}
310+
hir::InlineAsmOperand::Label { .. } => {
311+
self.dcx().emit_err(InvalidAsmTemplateModifierLabel {
312+
placeholder_span,
313+
op_span: op_sp,
314+
});
315+
}
298316
}
299317
}
300318
}
@@ -334,7 +352,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
334352

335353
hir::InlineAsmOperand::Const { .. }
336354
| hir::InlineAsmOperand::SymFn { .. }
337-
| hir::InlineAsmOperand::SymStatic { .. } => {
355+
| hir::InlineAsmOperand::SymStatic { .. }
356+
| hir::InlineAsmOperand::Label { .. } => {
338357
unreachable!("{op:?} is not a register operand");
339358
}
340359
};

compiler/rustc_ast_lowering/src/errors.rs

+10
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,16 @@ pub struct InvalidAsmTemplateModifierSym {
262262
pub op_span: Span,
263263
}
264264

265+
#[derive(Diagnostic, Clone, Copy)]
266+
#[diag(ast_lowering_invalid_asm_template_modifier_label)]
267+
pub struct InvalidAsmTemplateModifierLabel {
268+
#[primary_span]
269+
#[label(ast_lowering_template_modifier)]
270+
pub placeholder_span: Span,
271+
#[label(ast_lowering_argument)]
272+
pub op_span: Span,
273+
}
274+
265275
#[derive(Diagnostic, Clone, Copy)]
266276
#[diag(ast_lowering_register_class_only_clobber)]
267277
pub struct RegisterClassOnlyClobber {

compiler/rustc_ast_pretty/src/pprust/state.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1331,6 +1331,10 @@ impl<'a> State<'a> {
13311331
s.print_path(&sym.path, true, 0);
13321332
}
13331333
}
1334+
InlineAsmOperand::Label { block } => {
1335+
s.head("label");
1336+
s.print_block(block);
1337+
}
13341338
}
13351339
}
13361340
AsmArg::ClobberAbi(abi) => {

compiler/rustc_borrowck/src/lib.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -723,7 +723,7 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
723723
operands,
724724
options: _,
725725
line_spans: _,
726-
destination: _,
726+
targets: _,
727727
unwind: _,
728728
} => {
729729
for op in operands {
@@ -749,7 +749,8 @@ impl<'cx, 'tcx, R> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx, R> for MirBorro
749749
}
750750
InlineAsmOperand::Const { value: _ }
751751
| InlineAsmOperand::SymFn { value: _ }
752-
| InlineAsmOperand::SymStatic { def_id: _ } => {}
752+
| InlineAsmOperand::SymStatic { def_id: _ }
753+
| InlineAsmOperand::Label { target_index: _ } => {}
753754
}
754755
}
755756
}

compiler/rustc_borrowck/src/polonius/loan_invalidations.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
161161
operands,
162162
options: _,
163163
line_spans: _,
164-
destination: _,
164+
targets: _,
165165
unwind: _,
166166
} => {
167167
for op in operands {
@@ -182,7 +182,8 @@ impl<'cx, 'tcx> Visitor<'tcx> for LoanInvalidationsGenerator<'cx, 'tcx> {
182182
}
183183
InlineAsmOperand::Const { value: _ }
184184
| InlineAsmOperand::SymFn { value: _ }
185-
| InlineAsmOperand::SymStatic { def_id: _ } => {}
185+
| InlineAsmOperand::SymStatic { def_id: _ }
186+
| InlineAsmOperand::Label { target_index: _ } => {}
186187
}
187188
}
188189
}

compiler/rustc_borrowck/src/type_check/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1771,8 +1771,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
17711771
self.assert_iscleanup(body, block_data, real_target, is_cleanup);
17721772
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);
17731773
}
1774-
TerminatorKind::InlineAsm { destination, unwind, .. } => {
1775-
if let Some(target) = destination {
1774+
TerminatorKind::InlineAsm { ref targets, unwind, .. } => {
1775+
for &target in targets {
17761776
self.assert_iscleanup(body, block_data, target, is_cleanup);
17771777
}
17781778
self.assert_iscleanup_unwind(body, block_data, unwind, is_cleanup);

compiler/rustc_builtin_macros/messages.ftl

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
1919
2020
builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
2121
22+
builtin_macros_asm_mayunwind = asm labels are not allowed with the `may_unwind` option
23+
2224
builtin_macros_asm_modifier_invalid = asm template modifier must be a single character
2325
2426
builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive

compiler/rustc_builtin_macros/src/asm.rs

+10
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ pub fn parse_asm_args<'a>(
167167
path: path.clone(),
168168
};
169169
ast::InlineAsmOperand::Sym { sym }
170+
} else if !is_global_asm && p.eat_keyword(sym::label) {
171+
let block = p.parse_block()?;
172+
ast::InlineAsmOperand::Label { block }
170173
} else if allow_templates {
171174
let template = p.parse_expr()?;
172175
// If it can't possibly expand to a string, provide diagnostics here to include other
@@ -243,6 +246,7 @@ pub fn parse_asm_args<'a>(
243246
let mut have_real_output = false;
244247
let mut outputs_sp = vec![];
245248
let mut regclass_outputs = vec![];
249+
let mut labels_sp = vec![];
246250
for (op, op_sp) in &args.operands {
247251
match op {
248252
ast::InlineAsmOperand::Out { reg, expr, .. }
@@ -260,6 +264,9 @@ pub fn parse_asm_args<'a>(
260264
regclass_outputs.push(*op_sp);
261265
}
262266
}
267+
ast::InlineAsmOperand::Label { .. } => {
268+
labels_sp.push(*op_sp);
269+
}
263270
_ => {}
264271
}
265272
}
@@ -271,6 +278,9 @@ pub fn parse_asm_args<'a>(
271278
// Bail out now since this is likely to confuse MIR
272279
return Err(err);
273280
}
281+
if args.options.contains(ast::InlineAsmOptions::MAY_UNWIND) && !labels_sp.is_empty() {
282+
dcx.emit_err(errors::AsmMayUnwind { labels_sp });
283+
}
274284

275285
if args.clobber_abis.len() > 0 {
276286
if is_global_asm {

compiler/rustc_builtin_macros/src/errors.rs

+7
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,13 @@ pub(crate) struct AsmNoReturn {
787787
pub(crate) outputs_sp: Vec<Span>,
788788
}
789789

790+
#[derive(Diagnostic)]
791+
#[diag(builtin_macros_asm_mayunwind)]
792+
pub(crate) struct AsmMayUnwind {
793+
#[primary_span]
794+
pub(crate) labels_sp: Vec<Span>,
795+
}
796+
790797
#[derive(Diagnostic)]
791798
#[diag(builtin_macros_global_asm_clobber_abi)]
792799
pub(crate) struct GlobalAsmClobberAbi {

compiler/rustc_codegen_cranelift/src/base.rs

+14-2
Original file line numberDiff line numberDiff line change
@@ -445,7 +445,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
445445
template,
446446
operands,
447447
options,
448-
destination,
448+
targets,
449449
line_spans: _,
450450
unwind: _,
451451
} => {
@@ -456,13 +456,25 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
456456
);
457457
}
458458

459+
let have_labels = if options.contains(InlineAsmOptions::NORETURN) {
460+
!targets.is_empty()
461+
} else {
462+
targets.len() > 1
463+
};
464+
if have_labels {
465+
fx.tcx.dcx().span_fatal(
466+
source_info.span,
467+
"cranelift doesn't support labels in inline assembly.",
468+
);
469+
}
470+
459471
crate::inline_asm::codegen_inline_asm_terminator(
460472
fx,
461473
source_info.span,
462474
template,
463475
operands,
464476
*options,
465-
*destination,
477+
targets.get(0).copied(),
466478
);
467479
}
468480
TerminatorKind::UnwindTerminate(reason) => {

compiler/rustc_codegen_cranelift/src/global_asm.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ pub(crate) fn codegen_global_asm_item(tcx: TyCtxt<'_>, global_asm: &mut String,
7878
InlineAsmOperand::In { .. }
7979
| InlineAsmOperand::Out { .. }
8080
| InlineAsmOperand::InOut { .. }
81-
| InlineAsmOperand::SplitInOut { .. } => {
81+
| InlineAsmOperand::SplitInOut { .. }
82+
| InlineAsmOperand::Label { .. } => {
8283
span_bug!(op_sp, "invalid operand type for global_asm!")
8384
}
8485
}

compiler/rustc_codegen_cranelift/src/inline_asm.rs

+3
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,9 @@ pub(crate) fn codegen_inline_asm_terminator<'tcx>(
129129
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
130130
CInlineAsmOperand::Symbol { symbol: fx.tcx.symbol_name(instance).name.to_owned() }
131131
}
132+
InlineAsmOperand::Label { .. } => {
133+
span_bug!(span, "asm! label operands are not yet supported");
134+
}
132135
})
133136
.collect::<Vec<_>>();
134137

compiler/rustc_codegen_gcc/src/asm.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ enum ConstraintOrRegister {
107107

108108

109109
impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
110-
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>)>) {
110+
fn codegen_inline_asm(&mut self, template: &[InlineAsmTemplatePiece], rust_operands: &[InlineAsmOperandRef<'tcx, Self>], options: InlineAsmOptions, span: &[Span], instance: Instance<'_>, dest: Option<Self::BasicBlock>, _catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>) {
111111
if options.contains(InlineAsmOptions::MAY_UNWIND) {
112112
self.sess().dcx()
113113
.create_err(UnwindingInlineAsm { span: span[0] })
@@ -126,6 +126,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
126126
// added to `outputs.len()`
127127
let mut inputs = vec![];
128128

129+
// GCC index of a label equals its position in the array added to
130+
// `outputs.len() + inputs.len()`.
131+
let mut labels = vec![];
132+
129133
// Clobbers collected from `out("explicit register") _` and `inout("expl_reg") var => _`
130134
let mut clobbers = vec![];
131135

@@ -269,6 +273,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
269273
// some targets to add a leading underscore (Mach-O).
270274
constants_len += self.tcx.symbol_name(Instance::mono(self.tcx, def_id)).name.len();
271275
}
276+
277+
InlineAsmOperandRef::Label { label } => {
278+
labels.push(label);
279+
}
272280
}
273281
}
274282

@@ -368,6 +376,10 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
368376
InlineAsmOperandRef::Const { .. } => {
369377
// processed in the previous pass
370378
}
379+
380+
InlineAsmOperandRef::Label { .. } => {
381+
// processed in the previous pass
382+
}
371383
}
372384
}
373385

@@ -454,6 +466,14 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
454466
InlineAsmOperandRef::Const { ref string } => {
455467
template_str.push_str(string);
456468
}
469+
470+
InlineAsmOperandRef::Label { label } => {
471+
let label_gcc_index = labels.iter()
472+
.position(|&l| l == label)
473+
.expect("wrong rust index");
474+
let gcc_index = label_gcc_index + outputs.len() + inputs.len();
475+
push_to_template(Some('l'), gcc_index);
476+
}
457477
}
458478
}
459479
}
@@ -466,7 +486,12 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
466486
// 4. Generate Extended Asm block
467487

468488
let block = self.llbb();
469-
let extended_asm = block.add_extended_asm(None, &template_str);
489+
let extended_asm = if let Some(dest) = dest {
490+
assert!(!labels.is_empty());
491+
block.end_with_extended_asm_goto(None, &template_str, &labels, Some(dest))
492+
} else {
493+
block.add_extended_asm(None, &template_str)
494+
};
470495

471496
for op in &outputs {
472497
extended_asm.add_output_operand(None, &op.to_constraint(), op.tmp_var);
@@ -494,7 +519,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
494519
if !options.contains(InlineAsmOptions::NOSTACK) {
495520
// TODO(@Commeownist): figure out how to align stack
496521
}
497-
if options.contains(InlineAsmOptions::NORETURN) {
522+
if dest.is_none() && options.contains(InlineAsmOptions::NORETURN) {
498523
let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
499524
let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) };
500525
self.call(self.type_void(), None, None, builtin_unreachable, &[], None);

0 commit comments

Comments
 (0)