Skip to content

Commit e528fd1

Browse files
committed
Implement asm goto for LLVM backend
1 parent 29ed7cc commit e528fd1

File tree

4 files changed

+56
-19
lines changed

4 files changed

+56
-19
lines changed

compiler/rustc_codegen_llvm/src/asm.rs

+19-10
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
2828
options: InlineAsmOptions,
2929
line_spans: &[Span],
3030
instance: Instance<'_>,
31-
dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
31+
dest: Option<Self::BasicBlock>,
32+
catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>,
3233
) {
3334
let asm_arch = self.tcx.sess.asm_arch.unwrap();
3435

@@ -165,6 +166,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
165166
}
166167

167168
// Build the template string
169+
let mut labels = vec![];
168170
let mut template_str = String::new();
169171
for piece in template {
170172
match *piece {
@@ -205,6 +207,11 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
205207
// Only emit the raw symbol name
206208
template_str.push_str(&format!("${{{}:c}}", op_idx[&operand_idx]));
207209
}
210+
InlineAsmOperandRef::Label { label } => {
211+
template_str.push_str(&format!("${{{}:l}}", constraints.len()));
212+
constraints.push("!i".to_owned());
213+
labels.push(label);
214+
}
208215
}
209216
}
210217
}
@@ -292,12 +299,14 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
292299
&constraints.join(","),
293300
&inputs,
294301
output_type,
302+
&labels,
295303
volatile,
296304
alignstack,
297305
dialect,
298306
line_spans,
299307
options.contains(InlineAsmOptions::MAY_UNWIND),
300-
dest_catch_funclet,
308+
dest,
309+
catch_funclet,
301310
)
302311
.unwrap_or_else(|| span_bug!(line_spans[0], "LLVM asm constraint validation failed"));
303312

@@ -317,7 +326,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
317326
attributes::apply_to_callsite(result, llvm::AttributePlace::Function, &{ attrs });
318327

319328
// Switch to the 'normal' basic block if we did an `invoke` instead of a `call`
320-
if let Some((dest, _, _)) = dest_catch_funclet {
329+
if let Some(dest) = dest {
321330
self.switch_to_block(dest);
322331
}
323332

@@ -415,16 +424,14 @@ pub(crate) fn inline_asm_call<'ll>(
415424
cons: &str,
416425
inputs: &[&'ll Value],
417426
output: &'ll llvm::Type,
427+
labels: &[&'ll llvm::BasicBlock],
418428
volatile: bool,
419429
alignstack: bool,
420430
dia: llvm::AsmDialect,
421431
line_spans: &[Span],
422432
unwind: bool,
423-
dest_catch_funclet: Option<(
424-
&'ll llvm::BasicBlock,
425-
&'ll llvm::BasicBlock,
426-
Option<&Funclet<'ll>>,
427-
)>,
433+
dest: Option<&'ll llvm::BasicBlock>,
434+
catch_funclet: Option<(&'ll llvm::BasicBlock, Option<&Funclet<'ll>>)>,
428435
) -> Option<&'ll Value> {
429436
let volatile = if volatile { llvm::True } else { llvm::False };
430437
let alignstack = if alignstack { llvm::True } else { llvm::False };
@@ -457,8 +464,10 @@ pub(crate) fn inline_asm_call<'ll>(
457464
can_throw,
458465
);
459466

460-
let call = if let Some((dest, catch, funclet)) = dest_catch_funclet {
461-
bx.invoke(fty, None, None, v, inputs, dest, catch, funclet)
467+
let call = if !labels.is_empty() {
468+
bx.callbr(fty, None, None, v, inputs, dest.unwrap(), labels, None)
469+
} else if let Some((catch, funclet)) = catch_funclet {
470+
bx.invoke(fty, None, None, v, inputs, dest.unwrap(), catch, funclet)
462471
} else {
463472
bx.call(fty, None, None, v, inputs, None)
464473
};

compiler/rustc_codegen_llvm/src/intrinsic.rs

+2
Original file line numberDiff line numberDiff line change
@@ -362,12 +362,14 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
362362
constraint,
363363
inputs,
364364
self.type_void(),
365+
&[],
365366
true,
366367
false,
367368
llvm::AsmDialect::Att,
368369
&[span],
369370
false,
370371
None,
372+
None,
371373
)
372374
.unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
373375

compiler/rustc_codegen_ssa/src/mir/block.rs

+30-8
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
264264
mir::UnwindAction::Unreachable => None,
265265
};
266266

267-
if let Some(cleanup) = unwind_target {
267+
if operands.iter().any(|x| matches!(x, InlineAsmOperandRef::Label { .. })) {
268268
let ret_llbb = if let Some(target) = destination {
269269
fx.llbb(target)
270270
} else {
@@ -277,11 +277,29 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
277277
options,
278278
line_spans,
279279
instance,
280-
Some((ret_llbb, cleanup, self.funclet(fx))),
280+
Some(ret_llbb),
281+
None,
282+
);
283+
MergingSucc::False
284+
} else if let Some(cleanup) = unwind_target {
285+
let ret_llbb = if let Some(target) = destination {
286+
fx.llbb(target)
287+
} else {
288+
fx.unreachable_block()
289+
};
290+
291+
bx.codegen_inline_asm(
292+
template,
293+
operands,
294+
options,
295+
line_spans,
296+
instance,
297+
Some(ret_llbb),
298+
Some((cleanup, self.funclet(fx))),
281299
);
282300
MergingSucc::False
283301
} else {
284-
bx.codegen_inline_asm(template, operands, options, line_spans, instance, None);
302+
bx.codegen_inline_asm(template, operands, options, line_spans, instance, None, None);
285303

286304
if let Some(target) = destination {
287305
self.funclet_br(fx, bx, target, mergeable_succ)
@@ -1058,7 +1076,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10581076
operands: &[mir::InlineAsmOperand<'tcx>],
10591077
options: ast::InlineAsmOptions,
10601078
line_spans: &[Span],
1061-
destination: Option<mir::BasicBlock>,
1079+
targets: &[mir::BasicBlock],
10621080
unwind: mir::UnwindAction,
10631081
instance: Instance<'_>,
10641082
mergeable_succ: bool,
@@ -1110,8 +1128,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11101128
mir::InlineAsmOperand::SymStatic { def_id } => {
11111129
InlineAsmOperandRef::SymStatic { def_id }
11121130
}
1113-
mir::InlineAsmOperand::Label { target_index: _ } => {
1114-
todo!();
1131+
mir::InlineAsmOperand::Label { target_index } => {
1132+
InlineAsmOperandRef::Label { label: self.llbb(targets[target_index]) }
11151133
}
11161134
})
11171135
.collect();
@@ -1123,7 +1141,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11231141
&operands,
11241142
options,
11251143
line_spans,
1126-
destination,
1144+
if options.contains(InlineAsmOptions::NORETURN) {
1145+
None
1146+
} else {
1147+
targets.get(0).copied()
1148+
},
11271149
unwind,
11281150
instance,
11291151
mergeable_succ,
@@ -1289,7 +1311,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12891311
operands,
12901312
options,
12911313
line_spans,
1292-
targets.get(0).copied(),
1314+
targets,
12931315
unwind,
12941316
self.instance,
12951317
mergeable_succ(),

compiler/rustc_codegen_ssa/src/traits/asm.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ pub enum InlineAsmOperandRef<'tcx, B: BackendTypes + ?Sized> {
3333
SymStatic {
3434
def_id: DefId,
3535
},
36+
Label {
37+
label: B::BasicBlock,
38+
},
3639
}
3740

3841
#[derive(Debug)]
@@ -51,7 +54,8 @@ pub trait AsmBuilderMethods<'tcx>: BackendTypes {
5154
options: InlineAsmOptions,
5255
line_spans: &[Span],
5356
instance: Instance<'_>,
54-
dest_catch_funclet: Option<(Self::BasicBlock, Self::BasicBlock, Option<&Self::Funclet>)>,
57+
dest: Option<Self::BasicBlock>,
58+
catch_funclet: Option<(Self::BasicBlock, Option<&Self::Funclet>)>,
5559
);
5660
}
5761

0 commit comments

Comments
 (0)