Skip to content

Commit a5c6af8

Browse files
committed
Support use of asm goto with outputs and options(noreturn)
When labels are present, the `noreturn` option really means that asm block won't fallthrough -- if labels are present, then outputs can still be meaningfully used.
1 parent 9b2ed76 commit a5c6af8

File tree

5 files changed

+45
-5
lines changed

5 files changed

+45
-5
lines changed

Diff for: compiler/rustc_builtin_macros/src/asm.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,10 @@ pub fn parse_asm_args<'a>(
300300
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
301301
dcx.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
302302
}
303-
if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
303+
if args.options.contains(ast::InlineAsmOptions::NORETURN)
304+
&& !outputs_sp.is_empty()
305+
&& labels_sp.is_empty()
306+
{
304307
let err = dcx.create_err(errors::AsmNoReturn { outputs_sp });
305308
// Bail out now since this is likely to confuse MIR
306309
return Err(err);

Diff for: compiler/rustc_codegen_llvm/src/asm.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,14 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
334334
attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
335335

336336
// Write results to outputs. We need to do this for all possible control flow.
337-
for block in Some(dest).into_iter().chain(labels.iter().copied().map(Some)) {
337+
//
338+
// Note that `dest` maybe populated with unreachable_block when asm goto with outputs
339+
// is used (because we need to codegen callbr which always needs a destination), so
340+
// here we use the NORETURN option to determine if `dest` should be used.
341+
for block in (if options.contains(InlineAsmOptions::NORETURN) { None } else { Some(dest) })
342+
.into_iter()
343+
.chain(labels.iter().copied().map(Some))
344+
{
338345
if let Some(block) = block {
339346
self.switch_to_block(block);
340347
}

Diff for: tests/codegen/asm-goto.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,21 @@ pub unsafe fn asm_goto_with_outputs_use_in_label() -> u64 {
4343
// CHECK-LABEL: @asm_goto_noreturn
4444
#[no_mangle]
4545
pub unsafe fn asm_goto_noreturn() -> u64 {
46-
let out: u64;
4746
// CHECK: callbr void asm sideeffect alignstack inteldialect "
4847
// CHECK-NEXT: to label %unreachable [label %[[JUMPBB:[a-b0-9]+]]]
4948
asm!("jmp {}", label { return 1; }, options(noreturn));
5049
// CHECK: [[JUMPBB]]:
5150
// CHECK-NEXT: ret i64 1
51+
}
52+
53+
// CHECK-LABEL: @asm_goto_noreturn_with_outputs
54+
#[no_mangle]
55+
pub unsafe fn asm_goto_noreturn_with_outputs() -> u64 {
56+
let out: u64;
57+
// CHECK: [[RES:%[0-9]+]] = callbr i64 asm sideeffect alignstack inteldialect "
58+
// CHECK-NEXT: to label %[[FALLTHROUGHBB:[a-b0-9]+]] [label %[[JUMPBB:[a-b0-9]+]]]
59+
asm!("mov {}, 1", "jmp {}", out(reg) out, label { return out; });
60+
// CHECK: [[JUMPBB]]:
61+
// CHECK-NEXT: ret i64 [[RES]]
5262
out
5363
}

Diff for: tests/ui/asm/x86_64/goto.rs

+20
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,25 @@ fn goto_out_jump() {
6565
}
6666
}
6767

68+
fn goto_out_jump_noreturn() {
69+
unsafe {
70+
let mut value = false;
71+
let mut out: usize;
72+
asm!(
73+
"lea {}, [{} + 1]",
74+
"jmp {}",
75+
out(reg) out,
76+
in(reg) 0x12345678usize,
77+
label {
78+
value = true;
79+
assert_eq!(out, 0x12345679);
80+
},
81+
options(noreturn)
82+
);
83+
assert!(value);
84+
}
85+
}
86+
6887
// asm goto with outputs cause miscompilation in LLVM when multiple outputs are present.
6988
// The code sample below is adapted from https://github.com/llvm/llvm-project/issues/74483
7089
// and does not work with `-C opt-level=0`
@@ -131,6 +150,7 @@ fn main() {
131150
goto_jump();
132151
goto_out_fallthrough();
133152
goto_out_jump();
153+
goto_out_jump_noreturn();
134154
// goto_multi_out();
135155
goto_noreturn();
136156
goto_noreturn_diverge();

Diff for: tests/ui/asm/x86_64/goto.stderr

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
warning: unreachable statement
2-
--> $DIR/goto.rs:124:9
2+
--> $DIR/goto.rs:143:9
33
|
44
LL | / asm!(
55
LL | | "jmp {}",
@@ -13,7 +13,7 @@ LL | unreachable!();
1313
| ^^^^^^^^^^^^^^ unreachable statement
1414
|
1515
note: the lint level is defined here
16-
--> $DIR/goto.rs:114:8
16+
--> $DIR/goto.rs:133:8
1717
|
1818
LL | #[warn(unreachable_code)]
1919
| ^^^^^^^^^^^^^^^^

0 commit comments

Comments
 (0)