Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 91021de

Browse files
committed
LLVM codgen support for unwinding inline assembly
1 parent 491dd1f commit 91021de

File tree

7 files changed

+109
-18
lines changed

7 files changed

+109
-18
lines changed

compiler/rustc_codegen_cranelift/src/base.rs

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -239,7 +239,8 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
239239
fx.add_comment(inst, terminator_head);
240240
}
241241

242-
fx.set_debug_loc(bb_data.terminator().source_info);
242+
let source_info = bb_data.terminator().source_info;
243+
fx.set_debug_loc(source_info);
243244

244245
match &bb_data.terminator().kind {
245246
TerminatorKind::Goto { target } => {
@@ -295,19 +296,19 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
295296
let len = codegen_operand(fx, len).load_scalar(fx);
296297
let index = codegen_operand(fx, index).load_scalar(fx);
297298
let location = fx
298-
.get_caller_location(bb_data.terminator().source_info.span)
299+
.get_caller_location(source_info.span)
299300
.load_scalar(fx);
300301

301302
codegen_panic_inner(
302303
fx,
303304
rustc_hir::LangItem::PanicBoundsCheck,
304305
&[index, len, location],
305-
bb_data.terminator().source_info.span,
306+
source_info.span,
306307
);
307308
}
308309
_ => {
309310
let msg_str = msg.description();
310-
codegen_panic(fx, msg_str, bb_data.terminator().source_info.span);
311+
codegen_panic(fx, msg_str, source_info.span);
311312
}
312313
}
313314
}
@@ -378,10 +379,18 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
378379
options,
379380
destination,
380381
line_spans: _,
382+
cleanup,
381383
} => {
384+
if cleanup.is_some() {
385+
fx.tcx.sess.span_fatal(
386+
source_info.span,
387+
"cranelift doesn't support unwinding from inline assembly.",
388+
);
389+
}
390+
382391
crate::inline_asm::codegen_inline_asm(
383392
fx,
384-
bb_data.terminator().source_info.span,
393+
source_info.span,
385394
template,
386395
operands,
387396
*options,
@@ -415,7 +424,7 @@ fn codegen_fn_content(fx: &mut FunctionCx<'_, '_, '_>) {
415424
}
416425
TerminatorKind::Drop { place, target, unwind: _ } => {
417426
let drop_place = codegen_place(fx, *place);
418-
crate::abi::codegen_drop(fx, bb_data.terminator().source_info.span, drop_place);
427+
crate::abi::codegen_drop(fx, source_info.span, drop_place);
419428

420429
let target_block = fx.get_block(*target);
421430
fx.bcx.ins().jump(target_block, &[]);

compiler/rustc_codegen_llvm/src/asm.rs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::builder::Builder;
2+
use crate::common::Funclet;
23
use crate::context::CodegenCx;
34
use crate::llvm;
5+
use crate::llvm_util;
46
use crate::type_::Type;
57
use crate::type_of::LayoutLlvmExt;
68
use crate::value::Value;
@@ -98,6 +100,8 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
98100
ia.alignstack,
99101
ia.dialect,
100102
&[span],
103+
false,
104+
None,
101105
);
102106
if r.is_none() {
103107
return false;
@@ -121,6 +125,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
121125
options: InlineAsmOptions,
122126
line_spans: &[Span],
123127
instance: Instance<'_>,
128+
dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
124129
) {
125130
let asm_arch = self.tcx.sess.asm_arch.unwrap();
126131

@@ -355,6 +360,8 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> {
355360
alignstack,
356361
dialect,
357362
line_spans,
363+
options.contains(InlineAsmOptions::MAY_UNWIND),
364+
dest_catch_funclet,
358365
)
359366
.unwrap_or_else(|| span_bug!(line_spans[0], "LLVM asm constraint validation failed"));
360367

@@ -447,10 +454,16 @@ pub(crate) fn inline_asm_call(
447454
alignstack: bool,
448455
dia: LlvmAsmDialect,
449456
line_spans: &[Span],
457+
unwind: bool,
458+
dest_catch_funclet: Option<(
459+
&'ll llvm::BasicBlock,
460+
&'ll llvm::BasicBlock,
461+
Option<&Funclet<'ll>>,
462+
)>,
450463
) -> Option<&'ll Value> {
451464
let volatile = if volatile { llvm::True } else { llvm::False };
452465
let alignstack = if alignstack { llvm::True } else { llvm::False };
453-
let can_throw = llvm::False;
466+
let can_throw = if unwind { llvm::True } else { llvm::False };
454467

455468
let argtys = inputs
456469
.iter()
@@ -467,6 +480,13 @@ pub(crate) fn inline_asm_call(
467480
let constraints_ok = llvm::LLVMRustInlineAsmVerify(fty, cons.as_ptr().cast(), cons.len());
468481
debug!("constraint verification result: {:?}", constraints_ok);
469482
if constraints_ok {
483+
if unwind && llvm_util::get_version() < (13, 0, 0) {
484+
bx.cx.sess().span_fatal(
485+
line_spans[0],
486+
"unwinding from inline assembly is only supported on llvm >= 13.",
487+
);
488+
}
489+
470490
let v = llvm::LLVMRustInlineAsm(
471491
fty,
472492
asm.as_ptr().cast(),
@@ -478,7 +498,12 @@ pub(crate) fn inline_asm_call(
478498
llvm::AsmDialect::from_generic(dia),
479499
can_throw,
480500
);
481-
let call = bx.call(fty, v, inputs, None);
501+
502+
let call = if let Some((dest, catch, funclet)) = dest_catch_funclet {
503+
bx.invoke(fty, v, inputs, dest, catch, funclet)
504+
} else {
505+
bx.call(fty, v, inputs, None)
506+
};
482507

483508
// Store mark in a metadata node so we can map LLVM errors
484509
// back to source locations. See #17552.

compiler/rustc_codegen_llvm/src/intrinsic.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,8 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> {
350350
false,
351351
ast::LlvmAsmDialect::Att,
352352
&[span],
353+
false,
354+
None,
353355
)
354356
.unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
355357

compiler/rustc_codegen_ssa/src/mir/analyze.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,9 +276,9 @@ pub fn cleanup_kinds(mir: &mir::Body<'_>) -> IndexVec<mir::BasicBlock, CleanupKi
276276
| TerminatorKind::SwitchInt { .. }
277277
| TerminatorKind::Yield { .. }
278278
| TerminatorKind::FalseEdge { .. }
279-
| TerminatorKind::FalseUnwind { .. }
280-
| TerminatorKind::InlineAsm { .. } => { /* nothing to do */ }
279+
| TerminatorKind::FalseUnwind { .. } => { /* nothing to do */ }
281280
TerminatorKind::Call { cleanup: unwind, .. }
281+
| TerminatorKind::InlineAsm { cleanup: unwind, .. }
282282
| TerminatorKind::Assert { cleanup: unwind, .. }
283283
| TerminatorKind::DropAndReplace { unwind, .. }
284284
| TerminatorKind::Drop { unwind, .. } => {

compiler/rustc_codegen_ssa/src/mir/block.rs

Lines changed: 54 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::traits::*;
1010
use crate::MemFlags;
1111

1212
use rustc_ast as ast;
13+
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
1314
use rustc_hir::lang_items::LangItem;
1415
use rustc_index::vec::Idx;
1516
use rustc_middle::mir::AssertKind;
@@ -174,6 +175,45 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
174175
}
175176
}
176177
}
178+
179+
/// Generates inline assembly with optional `destination` and `cleanup`.
180+
fn do_inlineasm<Bx: BuilderMethods<'a, 'tcx>>(
181+
&self,
182+
fx: &mut FunctionCx<'a, 'tcx, Bx>,
183+
bx: &mut Bx,
184+
template: &[InlineAsmTemplatePiece],
185+
operands: &[InlineAsmOperandRef<'tcx, Bx>],
186+
options: InlineAsmOptions,
187+
line_spans: &[Span],
188+
destination: Option<mir::BasicBlock>,
189+
cleanup: Option<mir::BasicBlock>,
190+
instance: Instance<'_>,
191+
) {
192+
if let Some(cleanup) = cleanup {
193+
let ret_llbb = if let Some(target) = destination {
194+
fx.llbb(target)
195+
} else {
196+
fx.unreachable_block()
197+
};
198+
199+
bx.codegen_inline_asm(
200+
template,
201+
&operands,
202+
options,
203+
line_spans,
204+
instance,
205+
Some((ret_llbb, self.llblock(fx, cleanup), self.funclet(fx))),
206+
);
207+
} else {
208+
bx.codegen_inline_asm(template, &operands, options, line_spans, instance, None);
209+
210+
if let Some(target) = destination {
211+
self.funclet_br(fx, bx, target);
212+
} else {
213+
bx.unreachable();
214+
}
215+
}
216+
}
177217
}
178218

179219
/// Codegen implementations for some terminator variants.
@@ -877,6 +917,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
877917
options: ast::InlineAsmOptions,
878918
line_spans: &[Span],
879919
destination: Option<mir::BasicBlock>,
920+
cleanup: Option<mir::BasicBlock>,
880921
instance: Instance<'_>,
881922
) {
882923
let span = terminator.source_info.span;
@@ -931,13 +972,17 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
931972
})
932973
.collect();
933974

934-
bx.codegen_inline_asm(template, &operands, options, line_spans, instance);
935-
936-
if let Some(target) = destination {
937-
helper.funclet_br(self, &mut bx, target);
938-
} else {
939-
bx.unreachable();
940-
}
975+
helper.do_inlineasm(
976+
self,
977+
&mut bx,
978+
template,
979+
&operands,
980+
options,
981+
line_spans,
982+
destination,
983+
cleanup,
984+
instance,
985+
);
941986
}
942987
}
943988

@@ -1041,7 +1086,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10411086
options,
10421087
line_spans,
10431088
destination,
1044-
cleanup: _, // TODO
1089+
cleanup,
10451090
} => {
10461091
self.codegen_asm_terminator(
10471092
helper,
@@ -1052,6 +1097,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10521097
options,
10531098
line_spans,
10541099
destination,
1100+
cleanup,
10551101
self.instance,
10561102
);
10571103
}

compiler/rustc_codegen_ssa/src/traits/asm.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
5959
options: InlineAsmOptions,
6060
line_spans: &[Span],
6161
instance: Instance<'_>,
62+
dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
6263
);
6364
}
6465

compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,11 +446,19 @@ LLVMRustInlineAsm(LLVMTypeRef Ty, char *AsmString, size_t AsmStringLen,
446446
char *Constraints, size_t ConstraintsLen,
447447
LLVMBool HasSideEffects, LLVMBool IsAlignStack,
448448
LLVMRustAsmDialect Dialect, LLVMBool CanThrow) {
449+
#if LLVM_VERSION_GE(13, 0)
449450
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
450451
StringRef(AsmString, AsmStringLen),
451452
StringRef(Constraints, ConstraintsLen),
452453
HasSideEffects, IsAlignStack,
453454
fromRust(Dialect), CanThrow));
455+
#else
456+
return wrap(InlineAsm::get(unwrap<FunctionType>(Ty),
457+
StringRef(AsmString, AsmStringLen),
458+
StringRef(Constraints, ConstraintsLen),
459+
HasSideEffects, IsAlignStack,
460+
fromRust(Dialect)));
461+
#endif
454462
}
455463

456464
extern "C" bool LLVMRustInlineAsmVerify(LLVMTypeRef Ty, char *Constraints,

0 commit comments

Comments
 (0)