Skip to content

Commit 5e4fd6b

Browse files
committed
Implement asm goto for LLVM and GCC backend
1 parent 27e6ee1 commit 5e4fd6b

File tree

5 files changed

+84
-22
lines changed

5 files changed

+84
-22
lines changed

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);

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
@@ -377,12 +377,14 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
377377
constraint,
378378
inputs,
379379
self.type_void(),
380+
&[],
380381
true,
381382
false,
382383
llvm::AsmDialect::Att,
383384
&[span],
384385
false,
385386
None,
387+
None,
386388
)
387389
.unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
388390

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)
@@ -1067,7 +1085,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
10671085
operands: &[mir::InlineAsmOperand<'tcx>],
10681086
options: ast::InlineAsmOptions,
10691087
line_spans: &[Span],
1070-
destination: Option<mir::BasicBlock>,
1088+
targets: &[mir::BasicBlock],
10711089
unwind: mir::UnwindAction,
10721090
instance: Instance<'_>,
10731091
mergeable_succ: bool,
@@ -1119,8 +1137,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11191137
mir::InlineAsmOperand::SymStatic { def_id } => {
11201138
InlineAsmOperandRef::SymStatic { def_id }
11211139
}
1122-
mir::InlineAsmOperand::Label { target_index: _ } => {
1123-
todo!();
1140+
mir::InlineAsmOperand::Label { target_index } => {
1141+
InlineAsmOperandRef::Label { label: self.llbb(targets[target_index]) }
11241142
}
11251143
})
11261144
.collect();
@@ -1132,7 +1150,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
11321150
&operands,
11331151
options,
11341152
line_spans,
1135-
destination,
1153+
if options.contains(InlineAsmOptions::NORETURN) {
1154+
None
1155+
} else {
1156+
targets.get(0).copied()
1157+
},
11361158
unwind,
11371159
instance,
11381160
mergeable_succ,
@@ -1298,7 +1320,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
12981320
operands,
12991321
options,
13001322
line_spans,
1301-
targets.get(0).copied(),
1323+
targets,
13021324
unwind,
13031325
self.instance,
13041326
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)