Skip to content

Commit 93afbf2

Browse files
committed
Revert "linker/inline: use OpPhi instead of OpVariable for return values."
This reverts commit fcd1b1e.
1 parent 9046395 commit 93afbf2

File tree

1 file changed

+69
-67
lines changed
  • crates/rustc_codegen_spirv/src/linker

1 file changed

+69
-67
lines changed

crates/rustc_codegen_spirv/src/linker/inline.rs

Lines changed: 69 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> {
9494
header,
9595
debug_string_source: &mut module.debug_string_source,
9696
annotations: &mut module.annotations,
97+
types_global_values: &mut module.types_global_values,
9798

9899
legal_globals,
99100

@@ -492,6 +493,7 @@ struct Inliner<'a, 'b> {
492493
header: &'b mut ModuleHeader,
493494
debug_string_source: &'b mut Vec<Instruction>,
494495
annotations: &'b mut Vec<Instruction>,
496+
types_global_values: &'b mut Vec<Instruction>,
495497

496498
legal_globals: FxHashMap<Word, LegalGlobal>,
497499
functions_that_may_abort: FxHashSet<Word>,
@@ -521,6 +523,29 @@ impl Inliner<'_, '_> {
521523
}
522524
}
523525

526+
fn ptr_ty(&mut self, pointee: Word) -> Word {
527+
// TODO: This is horribly slow, fix this
528+
let existing = self.types_global_values.iter().find(|inst| {
529+
inst.class.opcode == Op::TypePointer
530+
&& inst.operands[0].unwrap_storage_class() == StorageClass::Function
531+
&& inst.operands[1].unwrap_id_ref() == pointee
532+
});
533+
if let Some(existing) = existing {
534+
return existing.result_id.unwrap();
535+
}
536+
let inst_id = self.id();
537+
self.types_global_values.push(Instruction::new(
538+
Op::TypePointer,
539+
None,
540+
Some(inst_id),
541+
vec![
542+
Operand::StorageClass(StorageClass::Function),
543+
Operand::IdRef(pointee),
544+
],
545+
));
546+
inst_id
547+
}
548+
524549
fn inline_fn(
525550
&mut self,
526551
function: &mut Function,
@@ -597,19 +622,15 @@ impl Inliner<'_, '_> {
597622
.insert(caller.def_id().unwrap());
598623
}
599624

600-
let mut maybe_call_result_phi = {
625+
let call_result_type = {
601626
let ty = call_inst.result_type.unwrap();
602627
if ty == self.op_type_void_id {
603628
None
604629
} else {
605-
Some(Instruction::new(
606-
Op::Phi,
607-
Some(ty),
608-
Some(call_inst.result_id.unwrap()),
609-
vec![],
610-
))
630+
Some(ty)
611631
}
612632
};
633+
let call_result_id = call_inst.result_id.unwrap();
613634

614635
// Get the debug "source location" instruction that applies to the call.
615636
let custom_ext_inst_set_import = self.custom_ext_inst_set_import;
@@ -646,12 +667,17 @@ impl Inliner<'_, '_> {
646667
});
647668
let mut rewrite_rules = callee_parameters.zip(call_arguments).collect();
648669

670+
let return_variable = if call_result_type.is_some() {
671+
Some(self.id())
672+
} else {
673+
None
674+
};
649675
let return_jump = self.id();
650676
// Rewrite OpReturns of the callee.
651677
let mut inlined_callee_blocks = self.get_inlined_blocks(
652678
callee,
653679
call_debug_src_loc_inst,
654-
maybe_call_result_phi.as_mut(),
680+
return_variable,
655681
return_jump,
656682
);
657683
// Clone the IDs of the callee, because otherwise they'd be defined multiple times if the
@@ -660,55 +686,6 @@ impl Inliner<'_, '_> {
660686
apply_rewrite_rules(&rewrite_rules, &mut inlined_callee_blocks);
661687
self.apply_rewrite_for_decorations(&rewrite_rules);
662688

663-
if let Some(call_result_phi) = &mut maybe_call_result_phi {
664-
// HACK(eddyb) new IDs should be generated earlier, to avoid pushing
665-
// callee IDs to `call_result_phi.operands` only to rewrite them here.
666-
for op in &mut call_result_phi.operands {
667-
if let Some(id) = op.id_ref_any_mut()
668-
&& let Some(&rewrite) = rewrite_rules.get(id)
669-
{
670-
*id = rewrite;
671-
}
672-
}
673-
674-
// HACK(eddyb) this special-casing of the single-return case is
675-
// really necessary for passes like `mem2reg` which are not capable
676-
// of skipping through the extraneous `OpPhi`s on their own.
677-
if let [returned_value, _return_block] = &call_result_phi.operands[..] {
678-
let call_result_id = call_result_phi.result_id.unwrap();
679-
let returned_value_id = returned_value.unwrap_id_ref();
680-
681-
maybe_call_result_phi = None;
682-
683-
// HACK(eddyb) this is a conservative approximation of all the
684-
// instructions that could potentially reference the call result.
685-
let reaching_insts = {
686-
let (pre_call_blocks, call_and_post_call_blocks) =
687-
caller.blocks.split_at_mut(block_idx);
688-
(pre_call_blocks.iter_mut().flat_map(|block| {
689-
block
690-
.instructions
691-
.iter_mut()
692-
.take_while(|inst| inst.class.opcode == Op::Phi)
693-
}))
694-
.chain(
695-
call_and_post_call_blocks
696-
.iter_mut()
697-
.flat_map(|block| &mut block.instructions),
698-
)
699-
};
700-
for reaching_inst in reaching_insts {
701-
for op in &mut reaching_inst.operands {
702-
if let Some(id) = op.id_ref_any_mut()
703-
&& *id == call_result_id
704-
{
705-
*id = returned_value_id;
706-
}
707-
}
708-
}
709-
}
710-
}
711-
712689
// Split the block containing the `OpFunctionCall` into pre-call vs post-call.
713690
let pre_call_block_idx = block_idx;
714691
#[expect(unused)]
@@ -724,6 +701,18 @@ impl Inliner<'_, '_> {
724701
.unwrap();
725702
assert!(call.class.opcode == Op::FunctionCall);
726703

704+
if let Some(call_result_type) = call_result_type {
705+
// Generate the storage space for the return value: Do this *after* the split above,
706+
// because if block_idx=0, inserting a variable here shifts call_index.
707+
let ret_var_inst = Instruction::new(
708+
Op::Variable,
709+
Some(self.ptr_ty(call_result_type)),
710+
Some(return_variable.unwrap()),
711+
vec![Operand::StorageClass(StorageClass::Function)],
712+
);
713+
self.insert_opvariables(&mut caller.blocks[0], [ret_var_inst]);
714+
}
715+
727716
// Insert non-entry inlined callee blocks just after the pre-call block.
728717
let non_entry_inlined_callee_blocks = inlined_callee_blocks.drain(1..);
729718
let num_non_entry_inlined_callee_blocks = non_entry_inlined_callee_blocks.len();
@@ -732,9 +721,18 @@ impl Inliner<'_, '_> {
732721
non_entry_inlined_callee_blocks,
733722
);
734723

735-
if let Some(call_result_phi) = maybe_call_result_phi {
736-
// Add the `OpPhi` for the call result value, after the inlined function.
737-
post_call_block_insts.insert(0, call_result_phi);
724+
if let Some(call_result_type) = call_result_type {
725+
// Add the load of the result value after the inlined function. Note there's guaranteed no
726+
// OpPhi instructions since we just split this block.
727+
post_call_block_insts.insert(
728+
0,
729+
Instruction::new(
730+
Op::Load,
731+
Some(call_result_type),
732+
Some(call_result_id),
733+
vec![Operand::IdRef(return_variable.unwrap())],
734+
),
735+
);
738736
}
739737

740738
// Insert the post-call block, after all the inlined callee blocks.
@@ -901,7 +899,7 @@ impl Inliner<'_, '_> {
901899
&mut self,
902900
callee: &Function,
903901
call_debug_src_loc_inst: Option<&Instruction>,
904-
mut maybe_call_result_phi: Option<&mut Instruction>,
902+
return_variable: Option<Word>,
905903
return_jump: Word,
906904
) -> Vec<Block> {
907905
let Self {
@@ -999,13 +997,17 @@ impl Inliner<'_, '_> {
999997
if let Op::Return | Op::ReturnValue = terminator.class.opcode {
1000998
if Op::ReturnValue == terminator.class.opcode {
1001999
let return_value = terminator.operands[0].id_ref_any().unwrap();
1002-
let call_result_phi = maybe_call_result_phi.as_deref_mut().unwrap();
1003-
call_result_phi.operands.extend([
1004-
Operand::IdRef(return_value),
1005-
Operand::IdRef(block.label_id().unwrap()),
1006-
]);
1000+
block.instructions.push(Instruction::new(
1001+
Op::Store,
1002+
None,
1003+
None,
1004+
vec![
1005+
Operand::IdRef(return_variable.unwrap()),
1006+
Operand::IdRef(return_value),
1007+
],
1008+
));
10071009
} else {
1008-
assert!(maybe_call_result_phi.is_none());
1010+
assert!(return_variable.is_none());
10091011
}
10101012
terminator =
10111013
Instruction::new(Op::Branch, None, None, vec![Operand::IdRef(return_jump)]);

0 commit comments

Comments
 (0)