linker/zombies: keep &Instruction for OpLine, instead of extracting operands.

This commit is contained in:
Eduard-Mihai Burtescu 2023-05-25 03:33:50 +03:00 committed by Eduard-Mihai Burtescu
parent a42b7edbea
commit 0160d1dc75
2 changed files with 51 additions and 52 deletions

View File

@ -326,12 +326,19 @@ impl<'a> SpanRegenerator<'a> {
.map(|zombie| zombie.decode()) .map(|zombie| zombie.decode())
} }
pub fn src_loc_from_op_line( /// Extract the equivalent `SrcLocDecoration` from a debug instruction that
&mut self, /// specifies some source location (currently only `OpLine` is supported).
file_id: Word, pub fn src_loc_from_debug_inst(&mut self, inst: &Instruction) -> Option<SrcLocDecoration<'a>> {
line: u32, assert_eq!(inst.class.opcode, Op::Line);
col: u32, let (file_id, line, col) = match inst.class.opcode {
) -> Option<SrcLocDecoration<'a>> { Op::Line => (
inst.operands[0].unwrap_id_ref(),
inst.operands[1].unwrap_literal_int32(),
inst.operands[2].unwrap_literal_int32(),
),
_ => unreachable!("src_loc_from_debug_inst({inst:?})"),
};
self.spv_debug_info self.spv_debug_info
.get_or_insert_with(|| SpvDebugInfo::collect(self.module)) .get_or_insert_with(|| SpvDebugInfo::collect(self.module))
.id_to_op_string .id_to_op_string

View File

@ -4,7 +4,7 @@ use super::{get_name, get_names};
use crate::custom_decorations::{CustomDecoration, SpanRegenerator, ZombieDecoration}; use crate::custom_decorations::{CustomDecoration, SpanRegenerator, ZombieDecoration};
use rspirv::dr::{Instruction, Module, Operand}; use rspirv::dr::{Instruction, Module, Operand};
use rspirv::spirv::{Op, Word}; use rspirv::spirv::{Op, Word};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap}; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed}; use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed};
use rustc_session::Session; use rustc_session::Session;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
@ -13,22 +13,22 @@ use smallvec::SmallVec;
#[derive(Copy, Clone)] #[derive(Copy, Clone)]
struct Zombie<'a> { struct Zombie<'a> {
id: Word, id: Word,
kind: &'a ZombieKind, kind: &'a ZombieKind<'a>,
} }
enum ZombieKind { enum ZombieKind<'a> {
/// Definition annotated with `ZombieDecoration`. /// Definition annotated with `ZombieDecoration`.
Leaf, Leaf,
/// Transitively zombie'd by using other zombies, from an instruction. /// Transitively zombie'd by using other zombies, from an instruction.
Uses(Vec<ZombieUse>), Uses(Vec<ZombieUse<'a>>),
} }
struct ZombieUse { struct ZombieUse<'a> {
used_zombie_id: Word, used_zombie_id: Word,
/// Operands of the active `OpLine` at the time of the use, if any. /// Active `OpLine` instruction at the time of the use, if any.
use_file_id_line_col: Option<(Word, u32, u32)>, use_debug_src_loc_inst: Option<&'a Instruction>,
origin: UseOrigin, origin: UseOrigin,
} }
@ -39,11 +39,11 @@ enum UseOrigin {
CallCalleeOperand { caller_func_id: Word }, CallCalleeOperand { caller_func_id: Word },
} }
struct Zombies { struct Zombies<'a> {
id_to_zombie_kind: FxIndexMap<Word, ZombieKind>, id_to_zombie_kind: FxIndexMap<Word, ZombieKind<'a>>,
} }
impl Zombies { impl<'a> Zombies<'a> {
// FIXME(eddyb) rename all the other methods to say `_inst` explicitly. // FIXME(eddyb) rename all the other methods to say `_inst` explicitly.
fn get_zombie_by_id(&self, id: Word) -> Option<Zombie<'_>> { fn get_zombie_by_id(&self, id: Word) -> Option<Zombie<'_>> {
self.id_to_zombie_kind self.id_to_zombie_kind
@ -51,31 +51,25 @@ impl Zombies {
.map(|kind| Zombie { id, kind }) .map(|kind| Zombie { id, kind })
} }
fn zombies_used_from_inst<'a>( fn zombies_used_from_inst<'b>(
&'a self, &'b self,
inst: &'a Instruction, inst: &'b Instruction,
) -> impl Iterator<Item = Zombie<'a>> + 'a { ) -> impl Iterator<Item = Zombie<'b>> + 'b {
inst.result_type inst.result_type
.into_iter() .into_iter()
.chain(inst.operands.iter().filter_map(|op| op.id_ref_any())) .chain(inst.operands.iter().filter_map(|op| op.id_ref_any()))
.filter_map(move |id| self.get_zombie_by_id(id)) .filter_map(move |id| self.get_zombie_by_id(id))
} }
fn spread(&mut self, module: &Module) -> bool { fn spread(&mut self, module: &'a Module) -> bool {
let mut any = false; let mut any = false;
// globals are easy // globals are easy
{ {
let mut file_id_line_col = None; let mut debug_src_loc_inst = None;
for inst in module.global_inst_iter() { for inst in module.global_inst_iter() {
match inst.class.opcode { match inst.class.opcode {
Op::Line => { Op::Line => debug_src_loc_inst = Some(inst),
file_id_line_col = Some(( Op::NoLine => debug_src_loc_inst = None,
inst.operands[0].unwrap_id_ref(),
inst.operands[1].unwrap_literal_int32(),
inst.operands[2].unwrap_literal_int32(),
));
}
Op::NoLine => file_id_line_col = None,
_ => {} _ => {}
} }
@ -87,7 +81,7 @@ impl Zombies {
.zombies_used_from_inst(inst) .zombies_used_from_inst(inst)
.map(|zombie| ZombieUse { .map(|zombie| ZombieUse {
used_zombie_id: zombie.id, used_zombie_id: zombie.id,
use_file_id_line_col: file_id_line_col, use_debug_src_loc_inst: debug_src_loc_inst,
origin: UseOrigin::GlobalOperandOrResultType, origin: UseOrigin::GlobalOperandOrResultType,
}) })
.collect(); .collect();
@ -113,17 +107,12 @@ impl Zombies {
} }
let mut all_zombie_uses_in_func = vec![]; let mut all_zombie_uses_in_func = vec![];
let mut file_id_line_col = None; let mut debug_src_loc_inst = None;
for inst in func.all_inst_iter() { for inst in func.all_inst_iter() {
match inst.class.opcode { match inst.class.opcode {
Op::Line => { Op::Line => debug_src_loc_inst = Some(inst),
file_id_line_col = Some(( // NOTE(eddyb) each block starts out with cleared debuginfo.
inst.operands[0].unwrap_id_ref(), Op::Label | Op::NoLine => debug_src_loc_inst = None,
inst.operands[1].unwrap_literal_int32(),
inst.operands[2].unwrap_literal_int32(),
));
}
Op::NoLine => file_id_line_col = None,
_ => {} _ => {}
} }
@ -136,7 +125,7 @@ impl Zombies {
.zombies_used_from_inst(inst) .zombies_used_from_inst(inst)
.map(|zombie| ZombieUse { .map(|zombie| ZombieUse {
used_zombie_id: zombie.id, used_zombie_id: zombie.id,
use_file_id_line_col: file_id_line_col, use_debug_src_loc_inst: debug_src_loc_inst,
origin: UseOrigin::IntraFuncOperandOrResultType { origin: UseOrigin::IntraFuncOperandOrResultType {
parent_func_id: func_id, parent_func_id: func_id,
}, },
@ -169,7 +158,7 @@ impl Zombies {
}; };
ZombieUse { ZombieUse {
used_zombie_id: zombie.id, used_zombie_id: zombie.id,
use_file_id_line_col: file_id_line_col, use_debug_src_loc_inst: debug_src_loc_inst,
origin, origin,
} }
}), }),
@ -188,13 +177,13 @@ impl Zombies {
struct ZombieReporter<'a> { struct ZombieReporter<'a> {
sess: &'a Session, sess: &'a Session,
module: &'a Module, module: &'a Module,
zombies: &'a Zombies, zombies: &'a Zombies<'a>,
id_to_name: Option<FxHashMap<Word, &'a str>>, id_to_name: Option<FxHashMap<Word, &'a str>>,
span_regen: SpanRegenerator<'a>, span_regen: SpanRegenerator<'a>,
} }
impl<'a> ZombieReporter<'a> { impl<'a> ZombieReporter<'a> {
fn new(sess: &'a Session, module: &'a Module, zombies: &'a Zombies) -> Self { fn new(sess: &'a Session, module: &'a Module, zombies: &'a Zombies<'a>) -> Self {
Self { Self {
sess, sess,
module, module,
@ -227,7 +216,7 @@ impl<'a> ZombieReporter<'a> {
err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>, err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>,
span: Span, span: Span,
zombie: Zombie<'_>, zombie: Zombie<'_>,
zombie_use: &ZombieUse, zombie_use: &ZombieUse<'_>,
) { ) {
let mut id_to_name = |id, kind| { let mut id_to_name = |id, kind| {
self.id_to_name self.id_to_name
@ -252,12 +241,9 @@ impl<'a> ZombieReporter<'a> {
format!("called by {}", id_to_name(caller_func_id, "function")) format!("called by {}", id_to_name(caller_func_id, "function"))
} }
}; };
let span = zombie_use let span = zombie_use
.use_file_id_line_col .use_debug_src_loc_inst
.and_then(|(file_id, line, col)| { .and_then(|inst| self.span_regen.src_loc_from_debug_inst(inst))
self.span_regen.src_loc_from_op_line(file_id, line, col)
})
.and_then(|src_loc| self.span_regen.src_loc_to_rustc(src_loc)) .and_then(|src_loc| self.span_regen.src_loc_to_rustc(src_loc))
.unwrap_or(span); .unwrap_or(span);
err.span_note(span, note); err.span_note(span, note);
@ -372,11 +358,17 @@ pub fn report_and_remove_zombies(
// FIXME(eddyb) this should be unnecessary, either something is unused, and // FIXME(eddyb) this should be unnecessary, either something is unused, and
// it will get DCE'd *anyway*, or it caused an error. // it will get DCE'd *anyway*, or it caused an error.
{ {
// HACK(eddyb) cannot use the original map because it borrows the `Module`.
let all_zombies: FxHashSet<_> = zombies.id_to_zombie_kind.into_keys().collect();
let keep = |inst: &Instruction| { let keep = |inst: &Instruction| {
if let Some(result_id) = inst.result_id { if let Some(result_id) = inst.result_id {
zombies.get_zombie_by_id(result_id).is_none() !all_zombies.contains(&result_id)
} else { } else {
zombies.zombies_used_from_inst(inst).next().is_none() let mut inst_ids = inst
.result_type
.into_iter()
.chain(inst.operands.iter().filter_map(|op| op.id_ref_any()));
!inst_ids.any(|id| all_zombies.contains(&id))
} }
}; };
module.capabilities.retain(keep); module.capabilities.retain(keep);