From f6c9e619742ffa3c89134e386f3c71aa876dc4fb Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 9 Sep 2025 11:40:02 +0300 Subject: [PATCH 1/8] Update `spirt` for `ControlRegion` -> `Region` rename. --- Cargo.lock | 3 +- crates/rustc_codegen_spirv/Cargo.toml | 4 +- .../src/linker/spirt_passes/controlflow.rs | 4 +- .../linker/spirt_passes/explicit_layout.rs | 4 +- .../src/linker/spirt_passes/fuse_selects.rs | 12 ++-- .../src/linker/spirt_passes/mod.rs | 46 +++++++------- .../src/linker/spirt_passes/reduce.rs | 60 +++++++++---------- 7 files changed, 62 insertions(+), 71 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5bbf4b56269..d8ba2ee808c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5795,8 +5795,7 @@ dependencies = [ [[package]] name = "spirt" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2d5968bd2a36466468aac637b355776f080edfb0c6f769b2b99b9708260c42a" +source = "git+https://github.com/Rust-GPU/spirt?rev=7e519e2b#7e519e2b700af0b922f002496763488feb38bdd3" dependencies = [ "arrayvec", "bytemuck", diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index 5f1794560b0..8ea47abcefe 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -55,7 +55,9 @@ spirv-std-types = { workspace = true, features = ["std"] } rustc-demangle = "0.1.21" sanitize-filename = "0.6.0" smallvec = { version = "1.6.1", features = ["const_generics", "const_new", "union"] } -spirt = "0.4.0" +# HACK(eddyb) temporary until a new SPIR-T release contains the following: +# - https://github.com/Rust-GPU/spirt/pull/7 +spirt = { git = "https://github.com/Rust-GPU/spirt", rev = "7e519e2b" } spirv-tools.workspace = true lazy_static = "1.4.0" itertools = "0.14.0" diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs index 9be7cb4dc5c..fe80fe14b8c 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs @@ -194,7 +194,7 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( .expect("Abort->OpReturn can only be done on unstructured CFGs") .rev_post_order(func_def_body); for region in rpo_regions { - let region_def = &func_def_body.control_regions[region]; + let region_def = &func_def_body.regions[region]; let control_node_def = match region_def.children.iter().last { Some(last_node) => &mut func_def_body.control_nodes[last_node], _ => continue, @@ -218,7 +218,7 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( // mutably borrowing other parts of `FuncDefBody`. let func_at_block_insts = FuncAt { control_nodes: &EntityDefs::new(), - control_regions: &EntityDefs::new(), + regions: &EntityDefs::new(), data_insts: &func_def_body.data_insts, position: *block_insts, diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs index fc509bea44e..e4e293fb96f 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs @@ -171,9 +171,9 @@ impl Transformer for SelectiveEraser<'_> { // region input/node output declarations in the function body may change. if let DeclDef::Present(func_def_body) = &mut func_decl.def { let mut errors_to_attach = vec![]; - func_def_body.inner_visit_with(&mut super::VisitAllControlRegionsAndNodes { + func_def_body.inner_visit_with(&mut super::VisitAllRegionsAndNodes { state: (), - visit_control_region: |_: &mut _, _| {}, + visit_region: |_: &mut _, _| {}, visit_control_node: |_: &mut _, func_at_node: FuncAt<'_, ControlNode>| { if let ControlNodeKind::Block { insts } = func_at_node.def().kind { for func_at_inst in func_at_node.at(insts) { diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/fuse_selects.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/fuse_selects.rs index 5421cd62928..726174332a0 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/fuse_selects.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/fuse_selects.rs @@ -1,20 +1,20 @@ use spirt::func_at::FuncAt; use spirt::transform::InnerInPlaceTransform; use spirt::visit::InnerVisit; -use spirt::{Context, ControlNodeKind, ControlRegion, FuncDefBody, SelectionKind, Value}; +use spirt::{Context, ControlNodeKind, FuncDefBody, Region, SelectionKind, Value}; use std::mem; -use super::{ReplaceValueWith, VisitAllControlRegionsAndNodes}; +use super::{ReplaceValueWith, VisitAllRegionsAndNodes}; /// Combine consecutive `Select`s in `func_def_body`. pub(crate) fn fuse_selects_in_func(_cx: &Context, func_def_body: &mut FuncDefBody) { // HACK(eddyb) this kind of random-access is easier than using `spirt::transform`. let mut all_regions = vec![]; - func_def_body.inner_visit_with(&mut VisitAllControlRegionsAndNodes { + func_def_body.inner_visit_with(&mut VisitAllRegionsAndNodes { state: (), - visit_control_region: |_: &mut (), func_at_control_region: FuncAt<'_, ControlRegion>| { - all_regions.push(func_at_control_region.position); + visit_region: |_: &mut (), func_at_region: FuncAt<'_, Region>| { + all_regions.push(func_at_region.position); }, visit_control_node: |_: &mut (), _| {}, }); @@ -86,7 +86,7 @@ pub(crate) fn fuse_selects_in_func(_cx: &Context, func_def_body: &mut FuncDefBod }, )); - func.control_regions[base_case] + func.regions[base_case] .children .append(children_of_case_to_fuse, func.control_nodes); } diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs index f41dc5aa4d1..f82db6c9d64 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs @@ -14,9 +14,9 @@ use spirt::func_at::FuncAt; use spirt::transform::InnerInPlaceTransform; use spirt::visit::{InnerVisit, Visitor}; use spirt::{ - AttrSet, Const, Context, ControlNode, ControlNodeKind, ControlRegion, DataInstDef, - DataInstForm, DataInstFormDef, DataInstKind, DeclDef, EntityOrientedDenseMap, Func, - FuncDefBody, GlobalVar, Module, Type, Value, spv, + AttrSet, Const, Context, ControlNode, ControlNodeKind, DataInstDef, DataInstForm, + DataInstFormDef, DataInstKind, DeclDef, EntityOrientedDenseMap, Func, FuncDefBody, GlobalVar, + Module, Region, Type, Value, spv, }; use std::collections::VecDeque; use std::iter; @@ -249,20 +249,16 @@ impl Visitor<'_> for ReachableUseCollector<'_> { } // FIXME(eddyb) maybe this should be provided by `spirt::visit`. -struct VisitAllControlRegionsAndNodes { +struct VisitAllRegionsAndNodes { state: S, - visit_control_region: VCR, + visit_region: VCR, visit_control_node: VCN, } const _: () = { use spirt::{func_at::*, visit::*, *}; - impl< - 'a, - S, - VCR: FnMut(&mut S, FuncAt<'a, ControlRegion>), - VCN: FnMut(&mut S, FuncAt<'a, ControlNode>), - > Visitor<'a> for VisitAllControlRegionsAndNodes + impl<'a, S, VCR: FnMut(&mut S, FuncAt<'a, Region>), VCN: FnMut(&mut S, FuncAt<'a, ControlNode>)> + Visitor<'a> for VisitAllRegionsAndNodes { // FIXME(eddyb) this is excessive, maybe different kinds of // visitors should exist for module-level and func-level? @@ -273,9 +269,9 @@ const _: () = { fn visit_global_var_use(&mut self, _: GlobalVar) {} fn visit_func_use(&mut self, _: Func) {} - fn visit_control_region_def(&mut self, func_at_control_region: FuncAt<'a, ControlRegion>) { - (self.visit_control_region)(&mut self.state, func_at_control_region); - func_at_control_region.inner_visit_with(self); + fn visit_region_def(&mut self, func_at_region: FuncAt<'a, Region>) { + (self.visit_region)(&mut self.state, func_at_region); + func_at_region.inner_visit_with(self); } fn visit_control_node_def(&mut self, func_at_control_node: FuncAt<'a, ControlNode>) { (self.visit_control_node)(&mut self.state, func_at_control_node); @@ -297,7 +293,7 @@ const _: () = { }; /// Clean up after a pass by removing unused (pure) `Value` definitions from -/// a function body (both `DataInst`s and `ControlRegion` inputs/outputs). +/// a function body (both `DataInst`s and `Region` inputs/outputs). // // FIXME(eddyb) should this be a dedicated pass? fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { @@ -309,10 +305,10 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { let wk = &SpvSpecWithExtras::get().well_known; struct Propagator { - func_body_region: ControlRegion, + func_body_region: Region, // FIXME(eddyb) maybe this kind of "parent map" should be provided by SPIR-T? - loop_body_to_loop: EntityOrientedDenseMap, + loop_body_to_loop: EntityOrientedDenseMap, // FIXME(eddyb) entity-keyed dense sets might be better for performance, // but would require separate sets/maps for separate `Value` cases. @@ -325,7 +321,7 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { if let Value::Const(_) = v { return; } - if let Value::ControlRegionInput { + if let Value::RegionInput { region, input_idx: _, } = v @@ -341,7 +337,7 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { while let Some(v) = self.queue.pop_front() { match v { Value::Const(_) => unreachable!(), - Value::ControlRegionInput { region, input_idx } => { + Value::RegionInput { region, input_idx } => { let loop_node = self.loop_body_to_loop[region]; let initial_inputs = match &func.at(loop_node).def().kind { ControlNodeKind::Loop { initial_inputs, .. } => initial_inputs, @@ -377,14 +373,14 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { // HACK(eddyb) it's simpler to first ensure `loop_body_to_loop` is computed, // just to allow the later unordered propagation to always work. let propagator = { - let mut visitor = VisitAllControlRegionsAndNodes { + let mut visitor = VisitAllRegionsAndNodes { state: Propagator { func_body_region: func_def_body.body, loop_body_to_loop: Default::default(), used: Default::default(), queue: Default::default(), }, - visit_control_region: |_: &mut _, _| {}, + visit_region: |_: &mut _, _| {}, visit_control_node: |propagator: &mut Propagator, func_at_control_node: FuncAt<'_, ControlNode>| { if let ControlNodeKind::Loop { body, .. } = func_at_control_node.def().kind { @@ -402,9 +398,9 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { let mut all_control_nodes = vec![]; let used_values = { - let mut visitor = VisitAllControlRegionsAndNodes { + let mut visitor = VisitAllRegionsAndNodes { state: propagator, - visit_control_region: |_: &mut _, _| {}, + visit_region: |_: &mut _, _| {}, visit_control_node: |propagator: &mut Propagator, func_at_control_node: FuncAt<'_, ControlNode>| { all_control_nodes.push(func_at_control_node.position); @@ -551,7 +547,7 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { let mut new_idx = 0; for original_idx in 0..initial_inputs.len() { - let original_input = Value::ControlRegionInput { + let original_input = Value::RegionInput { region: body, input_idx: original_idx as u32, }; @@ -572,7 +568,7 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { // Record remappings for any still-used inputs that got "shifted over". if original_idx != new_idx { - let new_input = Value::ControlRegionInput { + let new_input = Value::RegionInput { region: body, input_idx: new_idx as u32, }; diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs index 5954109de64..ea44d8428b5 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs @@ -5,14 +5,14 @@ use spirt::transform::InnerInPlaceTransform; use spirt::visit::InnerVisit; use spirt::{ Const, ConstDef, ConstKind, Context, ControlNode, ControlNodeDef, ControlNodeKind, - ControlNodeOutputDecl, ControlRegion, ControlRegionInputDecl, DataInst, DataInstDef, - DataInstFormDef, DataInstKind, EntityOrientedDenseMap, FuncDefBody, SelectionKind, Type, - TypeDef, TypeKind, Value, spv, + ControlNodeOutputDecl, DataInst, DataInstDef, DataInstFormDef, DataInstKind, + EntityOrientedDenseMap, FuncDefBody, Region, RegionInputDecl, SelectionKind, Type, TypeDef, + TypeKind, Value, spv, }; use std::collections::hash_map::Entry; use std::{iter, slice}; -use super::{ReplaceValueWith, VisitAllControlRegionsAndNodes}; +use super::{ReplaceValueWith, VisitAllRegionsAndNodes}; use std::rc::Rc; /// Apply "reduction rules" to `func_def_body`, replacing (pure) computations @@ -161,7 +161,7 @@ pub(crate) fn reduce_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { for (i, (&initial_input, &body_output)) in initial_inputs.iter().zip(body_outputs).enumerate() { - let body_input = Value::ControlRegionInput { + let body_input = Value::RegionInput { region: *body, input_idx: i as u32, }; @@ -178,9 +178,9 @@ pub(crate) fn reduce_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { .. } => {} }; - func_def_body.inner_visit_with(&mut VisitAllControlRegionsAndNodes { + func_def_body.inner_visit_with(&mut VisitAllRegionsAndNodes { state: (), - visit_control_region: |_: &mut (), _| {}, + visit_region: |_: &mut (), _| {}, visit_control_node: |_: &mut (), func_at_control_node| { handle_control_node(func_at_control_node); }, @@ -269,23 +269,20 @@ pub(crate) fn reduce_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { #[derive(Default)] struct ParentMap { data_inst_parent: EntityOrientedDenseMap, - control_node_parent: EntityOrientedDenseMap, - control_region_parent: EntityOrientedDenseMap, + control_node_parent: EntityOrientedDenseMap, + region_parent: EntityOrientedDenseMap, } impl ParentMap { fn new(func_def_body: &FuncDefBody) -> Self { - let mut visitor = VisitAllControlRegionsAndNodes { + let mut visitor = VisitAllRegionsAndNodes { state: Self::default(), - visit_control_region: - |this: &mut Self, func_at_control_region: FuncAt<'_, ControlRegion>| { - for func_at_child_control_node in func_at_control_region.at_children() { - this.control_node_parent.insert( - func_at_child_control_node.position, - func_at_control_region.position, - ); - } - }, + visit_region: |this: &mut Self, func_at_region: FuncAt<'_, Region>| { + for func_at_child_control_node in func_at_region.at_children() { + this.control_node_parent + .insert(func_at_child_control_node.position, func_at_region.position); + } + }, visit_control_node: |this: &mut Self, func_at_control_node: FuncAt<'_, ControlNode>| { let child_regions = match &func_at_control_node.def().kind { &ControlNodeKind::Block { insts } => { @@ -301,7 +298,7 @@ impl ParentMap { ControlNodeKind::ExitInvocation { .. } => &[][..], }; for &child_region in child_regions { - this.control_region_parent + this.region_parent .insert(child_region, func_at_control_node.position); } }, @@ -380,7 +377,7 @@ fn try_reduce_select( // allow lifting an use of it outside the `Select`. let region_defining_x = match x { Value::Const(_) => unreachable!(), - Value::ControlRegionInput { region, .. } => region, + Value::RegionInput { region, .. } => region, Value::ControlNodeOutput { control_node, .. } => { *parent_map.control_node_parent.get(control_node)? } @@ -391,8 +388,7 @@ fn try_reduce_select( // Fast-reject: if `x` is defined immediately inside one of // `select_control_node`'s cases, it's not a dominator. - if parent_map.control_region_parent.get(region_defining_x) - == Some(&select_control_node) + if parent_map.region_parent.get(region_defining_x) == Some(&select_control_node) { return None; } @@ -412,11 +408,9 @@ fn try_reduce_select( if region_containing_select == region_defining_x { return Some(()); } - region_containing_select = *parent_map.control_node_parent.get( - *parent_map - .control_region_parent - .get(region_containing_select)?, - )?; + region_containing_select = *parent_map + .control_node_parent + .get(*parent_map.region_parent.get(region_containing_select)?)?; } }; if is_x_valid_outside_select().is_some() { @@ -743,11 +737,11 @@ impl Reducible { ) -> Option { match self.input { Value::Const(ct) => self.with_input(ct).try_reduce_const(cx).map(Value::Const), - Value::ControlRegionInput { + Value::RegionInput { region, input_idx: state_idx, } => { - let loop_node = *parent_map.control_region_parent.get(region)?; + let loop_node = *parent_map.region_parent.get(region)?; // HACK(eddyb) this can't be a closure due to lifetime elision. fn loop_initial_states( func_at_loop_node: FuncAtMut<'_, ControlNode>, @@ -778,7 +772,7 @@ impl Reducible { let loop_state_decls = &mut func.reborrow().at(region).def().inputs; let new_loop_state_idx = u32::try_from(loop_state_decls.len()).unwrap(); - loop_state_decls.push(ControlRegionInputDecl { + loop_state_decls.push(RegionInputDecl { attrs: Default::default(), ty: self.output_type, }); @@ -823,7 +817,7 @@ impl Reducible { } .into(), ); - func.control_regions[region] + func.regions[region] .children .insert_last(new_block, func.control_nodes); new_block @@ -835,7 +829,7 @@ impl Reducible { _ => unreachable!(), } - Some(Value::ControlRegionInput { + Some(Value::RegionInput { region, input_idx: new_loop_state_idx, }) From 2a4c947f86ae479c0ef841632addd669f1331b5c Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 9 Sep 2025 11:40:02 +0300 Subject: [PATCH 2/8] Update `spirt` for `ControlNode` -> `Node` rename. --- Cargo.lock | 2 +- crates/rustc_codegen_spirv/Cargo.toml | 3 +- .../src/linker/spirt_passes/controlflow.rs | 16 +- .../src/linker/spirt_passes/debuginfo.rs | 20 +- .../src/linker/spirt_passes/diagnostics.rs | 14 +- .../linker/spirt_passes/explicit_layout.rs | 36 +- .../src/linker/spirt_passes/fuse_selects.rs | 28 +- .../src/linker/spirt_passes/mod.rs | 155 ++++---- .../src/linker/spirt_passes/reduce.rs | 339 +++++++++--------- 9 files changed, 291 insertions(+), 322 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d8ba2ee808c..d799734f633 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5795,7 +5795,7 @@ dependencies = [ [[package]] name = "spirt" version = "0.4.0" -source = "git+https://github.com/Rust-GPU/spirt?rev=7e519e2b#7e519e2b700af0b922f002496763488feb38bdd3" +source = "git+https://github.com/Rust-GPU/spirt?rev=3cabf188#3cabf188f8c28d89903ab34633e3ebaae8ef9821" dependencies = [ "arrayvec", "bytemuck", diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index 8ea47abcefe..726f31661a3 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -57,7 +57,8 @@ sanitize-filename = "0.6.0" smallvec = { version = "1.6.1", features = ["const_generics", "const_new", "union"] } # HACK(eddyb) temporary until a new SPIR-T release contains the following: # - https://github.com/Rust-GPU/spirt/pull/7 -spirt = { git = "https://github.com/Rust-GPU/spirt", rev = "7e519e2b" } +# - https://github.com/Rust-GPU/spirt/pull/8 +spirt = { git = "https://github.com/Rust-GPU/spirt", rev = "3cabf188" } spirv-tools.workspace = true lazy_static = "1.4.0" itertools = "0.14.0" diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs index fe80fe14b8c..7623edde859 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs @@ -4,8 +4,8 @@ use crate::custom_insts::{self, CustomInst, CustomOp}; use smallvec::SmallVec; use spirt::func_at::FuncAt; use spirt::{ - Attr, AttrSet, ConstDef, ConstKind, ControlNodeKind, DataInstFormDef, DataInstKind, DeclDef, - EntityDefs, ExportKey, Exportee, Module, Type, TypeDef, TypeKind, TypeOrConst, Value, cfg, spv, + Attr, AttrSet, ConstDef, ConstKind, DataInstFormDef, DataInstKind, DeclDef, EntityDefs, + ExportKey, Exportee, Module, NodeKind, Type, TypeDef, TypeKind, TypeOrConst, Value, cfg, spv, }; use std::fmt::Write as _; @@ -105,7 +105,7 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( .into_iter() .next() .and_then(|func_at_first_node| match func_at_first_node.def().kind { - ControlNodeKind::Block { insts } => Some(insts), + NodeKind::Block { insts } => Some(insts), _ => None, }) .unwrap_or_default()) @@ -195,12 +195,12 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( .rev_post_order(func_def_body); for region in rpo_regions { let region_def = &func_def_body.regions[region]; - let control_node_def = match region_def.children.iter().last { - Some(last_node) => &mut func_def_body.control_nodes[last_node], + let node_def = match region_def.children.iter().last { + Some(last_node) => &mut func_def_body.nodes[last_node], _ => continue, }; - let block_insts = match &mut control_node_def.kind { - ControlNodeKind::Block { insts } => insts, + let block_insts = match &mut node_def.kind { + NodeKind::Block { insts } => insts, _ => continue, }; @@ -217,7 +217,7 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( // HACK(eddyb) this allows accessing the `DataInst` iterator while // mutably borrowing other parts of `FuncDefBody`. let func_at_block_insts = FuncAt { - control_nodes: &EntityDefs::new(), + nodes: &EntityDefs::new(), regions: &EntityDefs::new(), data_insts: &func_def_body.data_insts, diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs index 6ac52bb2b11..7a3b8cf9845 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs @@ -6,8 +6,8 @@ use smallvec::SmallVec; use spirt::transform::{InnerInPlaceTransform, Transformer}; use spirt::visit::InnerVisit; use spirt::{ - Attr, AttrSetDef, ConstKind, Context, ControlNode, ControlNodeKind, DataInstKind, InternedStr, - Module, OrdAssertEq, Value, spv, + Attr, AttrSetDef, ConstKind, Context, DataInstKind, InternedStr, Module, Node, NodeKind, + OrdAssertEq, Value, spv, }; /// Replace our custom extended instruction debuginfo with standard SPIR-V ones. @@ -56,25 +56,25 @@ struct CustomDebuginfoToSpv<'a> { } impl Transformer for CustomDebuginfoToSpv<'_> { - fn in_place_transform_control_node_def( + fn in_place_transform_node_def( &mut self, - mut func_at_control_node: spirt::func_at::FuncAtMut<'_, ControlNode>, + mut func_at_node: spirt::func_at::FuncAtMut<'_, Node>, ) { - // HACK(eddyb) this relies on the fact that `ControlNodeKind::Block` maps + // HACK(eddyb) this relies on the fact that `NodeKind::Block` maps // to one original SPIR-V block, which may not necessarily be true, and // steps should be taken elsewhere to explicitly unset debuginfo, instead // of relying on the end of a SPIR-V block implicitly unsetting it all. // NOTE(eddyb) allowing debuginfo to apply *outside* of a `Block` could // be useful in allowing *some* structured control-flow to have debuginfo, // but that would likely require more work on the SPIR-T side. - if let ControlNodeKind::Block { mut insts } = func_at_control_node.reborrow().def().kind { + if let NodeKind::Block { mut insts } = func_at_node.reborrow().def().kind { let mut current_file_line_col = None; // HACK(eddyb) buffering the `DataInst`s to remove from this block, // as iterating and modifying a list at the same time isn't supported. let mut insts_to_remove = SmallVec::<[_; 8]>::new(); - let mut func_at_inst_iter = func_at_control_node.reborrow().at(insts).into_iter(); + let mut func_at_inst_iter = func_at_node.reborrow().at(insts).into_iter(); while let Some(func_at_inst) = func_at_inst_iter.next() { let inst = func_at_inst.position; let data_inst_def = func_at_inst.def(); @@ -161,11 +161,11 @@ impl Transformer for CustomDebuginfoToSpv<'_> { // Finally remove the `DataInst`s buffered for removal earlier. for inst in insts_to_remove { - insts.remove(inst, func_at_control_node.data_insts); + insts.remove(inst, func_at_node.data_insts); } - func_at_control_node.reborrow().def().kind = ControlNodeKind::Block { insts }; + func_at_node.reborrow().def().kind = NodeKind::Block { insts }; } - func_at_control_node.inner_in_place_transform_with(self); + func_at_node.inner_in_place_transform_with(self); } } diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs index 74ef56086b8..4eedf531ac3 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs @@ -10,9 +10,9 @@ use smallvec::SmallVec; use spirt::func_at::FuncAt; use spirt::visit::{InnerVisit, Visitor}; use spirt::{ - Attr, AttrSet, AttrSetDef, Const, ConstKind, Context, ControlNode, ControlNodeKind, - DataInstDef, DataInstForm, DataInstKind, Diag, DiagLevel, ExportKey, Exportee, Func, FuncDecl, - GlobalVar, InternedStr, Module, Type, Value, spv, + Attr, AttrSet, AttrSetDef, Const, ConstKind, Context, DataInstDef, DataInstForm, DataInstKind, + Diag, DiagLevel, ExportKey, Exportee, Func, FuncDecl, GlobalVar, InternedStr, Module, Node, + NodeKind, Type, Value, spv, }; use std::marker::PhantomData; use std::{mem, str}; @@ -578,23 +578,23 @@ impl<'a> Visitor<'a> for DiagnosticReporter<'a> { self.use_stack.truncate(original_use_stack_len); } - fn visit_control_node_def(&mut self, func_at_control_node: FuncAt<'a, ControlNode>) { + fn visit_node_def(&mut self, func_at_node: FuncAt<'a, Node>) { let original_use_stack_len = self.use_stack.len(); - func_at_control_node.inner_visit_with(self); + func_at_node.inner_visit_with(self); // HACK(eddyb) avoid `use_stack` from growing due to having some // `PushInlinedCallFrame` without matching `PopInlinedCallFrame`. self.use_stack.truncate(original_use_stack_len); - // HACK(eddyb) this relies on the fact that `ControlNodeKind::Block` maps + // HACK(eddyb) this relies on the fact that `NodeKind::Block` maps // to one original SPIR-V block, which may not necessarily be true, and // steps should be taken elsewhere to explicitly unset debuginfo, instead // of relying on the end of a SPIR-V block implicitly unsetting it all. // NOTE(eddyb) allowing debuginfo to apply *outside* of a `Block` could // be useful in allowing *some* structured control-flow to have debuginfo, // but that would likely require more work on the SPIR-T side. - if let ControlNodeKind::Block { .. } = func_at_control_node.def().kind { + if let NodeKind::Block { .. } = func_at_node.def().kind { match self.use_stack.last_mut() { Some(UseOrigin::IntraFunc { last_debug_src_loc_inst, diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs index e4e293fb96f..ef026de027f 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs @@ -8,9 +8,9 @@ use spirt::func_at::{FuncAt, FuncAtMut}; use spirt::transform::{InnerInPlaceTransform, InnerTransform, Transformed, Transformer}; use spirt::visit::InnerVisit as _; use spirt::{ - AddrSpace, Attr, AttrSetDef, Const, ConstKind, Context, ControlNode, ControlNodeKind, DataInst, - DataInstDef, DataInstForm, DataInstFormDef, DataInstKind, DeclDef, Diag, Func, FuncDecl, - GlobalVar, GlobalVarDecl, Module, Type, TypeDef, TypeKind, TypeOrConst, Value, spv, + AddrSpace, Attr, AttrSetDef, Const, ConstKind, Context, DataInst, DataInstDef, DataInstForm, + DataInstFormDef, DataInstKind, DeclDef, Diag, Func, FuncDecl, GlobalVar, GlobalVarDecl, Module, + Node, NodeKind, Type, TypeDef, TypeKind, TypeOrConst, Value, spv, }; use std::cmp::Ordering; use std::collections::VecDeque; @@ -76,7 +76,7 @@ struct SelectiveEraser<'a> { // HACK(eddyb) this is to allow `in_place_transform_data_inst_def` inject // new instructions into its parent block. - parent_block: Option, + parent_block: Option, } impl Transformer for SelectiveEraser<'_> { @@ -174,8 +174,8 @@ impl Transformer for SelectiveEraser<'_> { func_def_body.inner_visit_with(&mut super::VisitAllRegionsAndNodes { state: (), visit_region: |_: &mut _, _| {}, - visit_control_node: |_: &mut _, func_at_node: FuncAt<'_, ControlNode>| { - if let ControlNodeKind::Block { insts } = func_at_node.def().kind { + visit_node: |_: &mut _, func_at_node: FuncAt<'_, Node>| { + if let NodeKind::Block { insts } = func_at_node.def().kind { for func_at_inst in func_at_node.at(insts) { if let Err(e) = self.pre_check_data_inst(func_at_inst) { errors_to_attach.push((func_at_inst.position, e)); @@ -196,15 +196,12 @@ impl Transformer for SelectiveEraser<'_> { func_decl.inner_in_place_transform_with(self); } - fn in_place_transform_control_node_def( - &mut self, - mut func_at_control_node: FuncAtMut<'_, ControlNode>, - ) { + fn in_place_transform_node_def(&mut self, mut func_at_node: FuncAtMut<'_, Node>) { let old_parent_block = self.parent_block.take(); - if let ControlNodeKind::Block { .. } = func_at_control_node.reborrow().def().kind { - self.parent_block = Some(func_at_control_node.position); + if let NodeKind::Block { .. } = func_at_node.reborrow().def().kind { + self.parent_block = Some(func_at_node.position); } - func_at_control_node.inner_in_place_transform_with(self); + func_at_node.inner_in_place_transform_with(self); self.parent_block = old_parent_block; } @@ -258,8 +255,7 @@ impl Transformer for SelectiveEraser<'_> { ty != value_type && ty == self.erase_explicit_layout_in_type(value_type) }) { let func = func_at_data_inst.at(()); - let ControlNodeKind::Block { insts } = - &mut func.control_nodes[self.parent_block.unwrap()].kind + let NodeKind::Block { insts } = &mut func.nodes[self.parent_block.unwrap()].kind else { unreachable!() }; @@ -299,8 +295,8 @@ impl Transformer for SelectiveEraser<'_> { } else { let original_stored_value = *stored_value; - let ControlNodeKind::Block { insts } = - &mut func.control_nodes[self.parent_block.unwrap()].kind + let NodeKind::Block { insts } = + &mut func.nodes[self.parent_block.unwrap()].kind else { unreachable!() }; @@ -347,8 +343,7 @@ impl Transformer for SelectiveEraser<'_> { }; let func = func_at_data_inst.at(()); - let ControlNodeKind::Block { insts } = - &mut func.control_nodes[self.parent_block.unwrap()].kind + let NodeKind::Block { insts } = &mut func.nodes[self.parent_block.unwrap()].kind else { unreachable!() }; @@ -548,8 +543,7 @@ impl<'a> SelectiveEraser<'a> { .into(), ); - let ControlNodeKind::Block { insts } = - &mut func.control_nodes[self.parent_block.unwrap()].kind + let NodeKind::Block { insts } = &mut func.nodes[self.parent_block.unwrap()].kind else { unreachable!() }; diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/fuse_selects.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/fuse_selects.rs index 726174332a0..bf69441f340 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/fuse_selects.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/fuse_selects.rs @@ -1,7 +1,7 @@ use spirt::func_at::FuncAt; use spirt::transform::InnerInPlaceTransform; use spirt::visit::InnerVisit; -use spirt::{Context, ControlNodeKind, FuncDefBody, Region, SelectionKind, Value}; +use spirt::{Context, FuncDefBody, NodeKind, Region, SelectionKind, Value}; use std::mem; use super::{ReplaceValueWith, VisitAllRegionsAndNodes}; @@ -16,14 +16,14 @@ pub(crate) fn fuse_selects_in_func(_cx: &Context, func_def_body: &mut FuncDefBod visit_region: |_: &mut (), func_at_region: FuncAt<'_, Region>| { all_regions.push(func_at_region.position); }, - visit_control_node: |_: &mut (), _| {}, + visit_node: |_: &mut (), _| {}, }); for region in all_regions { let mut func_at_children_iter = func_def_body.at_mut(region).at_children().into_iter(); while let Some(func_at_child) = func_at_children_iter.next() { - let base_control_node = func_at_child.position; - if let ControlNodeKind::Select { + let base_node = func_at_child.position; + if let NodeKind::Select { kind: SelectionKind::BoolCond, scrutinee, cases, @@ -41,9 +41,9 @@ pub(crate) fn fuse_selects_in_func(_cx: &Context, func_def_body: &mut FuncDefBod match &fusion_candidate_def.kind { // HACK(eddyb) ignore empty blocks (created by // e.g. `remove_unused_values_in_func`). - ControlNodeKind::Block { insts } if insts.is_empty() => {} + NodeKind::Block { insts } if insts.is_empty() => {} - ControlNodeKind::Select { + NodeKind::Select { kind: SelectionKind::BoolCond, scrutinee: fusion_candidate_cond, cases: fusion_candidate_cases, @@ -75,10 +75,9 @@ pub(crate) fn fuse_selects_in_func(_cx: &Context, func_def_body: &mut FuncDefBod .into_iter() .inner_in_place_transform_with(&mut ReplaceValueWith( |v| match v { - Value::ControlNodeOutput { - control_node, - output_idx, - } if control_node == base_control_node => { + Value::NodeOutput { node, output_idx } + if node == base_node => + { Some(outputs_of_base_case[output_idx as usize]) } @@ -88,15 +87,14 @@ pub(crate) fn fuse_selects_in_func(_cx: &Context, func_def_body: &mut FuncDefBod func.regions[base_case] .children - .append(children_of_case_to_fuse, func.control_nodes); + .append(children_of_case_to_fuse, func.nodes); } // HACK(eddyb) because we can't remove list elements yet, // we instead replace the `Select` with an empty `Block`. - func.reborrow().at(fusion_candidate).def().kind = - ControlNodeKind::Block { - insts: Default::default(), - }; + func.reborrow().at(fusion_candidate).def().kind = NodeKind::Block { + insts: Default::default(), + }; } _ => break, diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs index f82db6c9d64..5e771738c7f 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs @@ -14,9 +14,9 @@ use spirt::func_at::FuncAt; use spirt::transform::InnerInPlaceTransform; use spirt::visit::{InnerVisit, Visitor}; use spirt::{ - AttrSet, Const, Context, ControlNode, ControlNodeKind, DataInstDef, DataInstForm, - DataInstFormDef, DataInstKind, DeclDef, EntityOrientedDenseMap, Func, FuncDefBody, GlobalVar, - Module, Region, Type, Value, spv, + AttrSet, Const, Context, DataInstDef, DataInstForm, DataInstFormDef, DataInstKind, DeclDef, + EntityOrientedDenseMap, Func, FuncDefBody, GlobalVar, Module, Node, NodeKind, Region, Type, + Value, spv, }; use std::collections::VecDeque; use std::iter; @@ -252,12 +252,12 @@ impl Visitor<'_> for ReachableUseCollector<'_> { struct VisitAllRegionsAndNodes { state: S, visit_region: VCR, - visit_control_node: VCN, + visit_node: VCN, } const _: () = { use spirt::{func_at::*, visit::*, *}; - impl<'a, S, VCR: FnMut(&mut S, FuncAt<'a, Region>), VCN: FnMut(&mut S, FuncAt<'a, ControlNode>)> + impl<'a, S, VCR: FnMut(&mut S, FuncAt<'a, Region>), VCN: FnMut(&mut S, FuncAt<'a, Node>)> Visitor<'a> for VisitAllRegionsAndNodes { // FIXME(eddyb) this is excessive, maybe different kinds of @@ -273,9 +273,9 @@ const _: () = { (self.visit_region)(&mut self.state, func_at_region); func_at_region.inner_visit_with(self); } - fn visit_control_node_def(&mut self, func_at_control_node: FuncAt<'a, ControlNode>) { - (self.visit_control_node)(&mut self.state, func_at_control_node); - func_at_control_node.inner_visit_with(self); + fn visit_node_def(&mut self, func_at_node: FuncAt<'a, Node>) { + (self.visit_node)(&mut self.state, func_at_node); + func_at_node.inner_visit_with(self); } } }; @@ -308,7 +308,7 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { func_body_region: Region, // FIXME(eddyb) maybe this kind of "parent map" should be provided by SPIR-T? - loop_body_to_loop: EntityOrientedDenseMap, + loop_body_to_loop: EntityOrientedDenseMap, // FIXME(eddyb) entity-keyed dense sets might be better for performance, // but would require separate sets/maps for separate `Value` cases. @@ -340,19 +340,16 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { Value::RegionInput { region, input_idx } => { let loop_node = self.loop_body_to_loop[region]; let initial_inputs = match &func.at(loop_node).def().kind { - ControlNodeKind::Loop { initial_inputs, .. } => initial_inputs, + NodeKind::Loop { initial_inputs, .. } => initial_inputs, // NOTE(eddyb) only `Loop`s' bodies can have inputs right now. _ => unreachable!(), }; self.mark_used(initial_inputs[input_idx as usize]); self.mark_used(func.at(region).def().outputs[input_idx as usize]); } - Value::ControlNodeOutput { - control_node, - output_idx, - } => { - let cases = match &func.at(control_node).def().kind { - ControlNodeKind::Select { cases, .. } => cases, + Value::NodeOutput { node, output_idx } => { + let cases = match &func.at(node).def().kind { + NodeKind::Select { cases, .. } => cases, // NOTE(eddyb) only `Select`s can have outputs right now. _ => unreachable!(), }; @@ -381,70 +378,66 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { queue: Default::default(), }, visit_region: |_: &mut _, _| {}, - visit_control_node: - |propagator: &mut Propagator, func_at_control_node: FuncAt<'_, ControlNode>| { - if let ControlNodeKind::Loop { body, .. } = func_at_control_node.def().kind { - propagator - .loop_body_to_loop - .insert(body, func_at_control_node.position); - } - }, + visit_node: |propagator: &mut Propagator, func_at_node: FuncAt<'_, Node>| { + if let NodeKind::Loop { body, .. } = func_at_node.def().kind { + propagator + .loop_body_to_loop + .insert(body, func_at_node.position); + } + }, }; func_def_body.inner_visit_with(&mut visitor); visitor.state }; // HACK(eddyb) this kind of random-access is easier than using `spirt::transform`. - let mut all_control_nodes = vec![]; + let mut all_nodes = vec![]; let used_values = { let mut visitor = VisitAllRegionsAndNodes { state: propagator, visit_region: |_: &mut _, _| {}, - visit_control_node: - |propagator: &mut Propagator, func_at_control_node: FuncAt<'_, ControlNode>| { - all_control_nodes.push(func_at_control_node.position); - - let mut mark_used_and_propagate = |v| { - propagator.mark_used(v); - propagator.propagate_used(func_at_control_node.at(())); - }; - match &func_at_control_node.def().kind { - &ControlNodeKind::Block { insts } => { - for func_at_inst in func_at_control_node.at(insts) { - // Ignore pure instructions (i.e. they're only used - // if their output value is used, from somewhere else). - if let DataInstKind::SpvInst(spv_inst) = - &cx[func_at_inst.def().form].kind - { - // HACK(eddyb) small selection relevant for now, - // but should be extended using e.g. a bitset. - if [wk.OpNop, wk.OpCompositeInsert].contains(&spv_inst.opcode) { - continue; - } + visit_node: |propagator: &mut Propagator, func_at_node: FuncAt<'_, Node>| { + all_nodes.push(func_at_node.position); + + let mut mark_used_and_propagate = |v| { + propagator.mark_used(v); + propagator.propagate_used(func_at_node.at(())); + }; + match &func_at_node.def().kind { + &NodeKind::Block { insts } => { + for func_at_inst in func_at_node.at(insts) { + // Ignore pure instructions (i.e. they're only used + // if their output value is used, from somewhere else). + if let DataInstKind::SpvInst(spv_inst) = + &cx[func_at_inst.def().form].kind + { + // HACK(eddyb) small selection relevant for now, + // but should be extended using e.g. a bitset. + if [wk.OpNop, wk.OpCompositeInsert].contains(&spv_inst.opcode) { + continue; } - mark_used_and_propagate(Value::DataInstOutput( - func_at_inst.position, - )); } + mark_used_and_propagate(Value::DataInstOutput(func_at_inst.position)); } + } - &ControlNodeKind::Select { scrutinee: v, .. } - | &ControlNodeKind::Loop { - repeat_condition: v, - .. - } => mark_used_and_propagate(v), - - ControlNodeKind::ExitInvocation { - kind: spirt::cfg::ExitInvocationKind::SpvInst(_), - inputs, - } => { - for &v in inputs { - mark_used_and_propagate(v); - } + &NodeKind::Select { scrutinee: v, .. } + | &NodeKind::Loop { + repeat_condition: v, + .. + } => mark_used_and_propagate(v), + + NodeKind::ExitInvocation { + kind: spirt::cfg::ExitInvocationKind::SpvInst(_), + inputs, + } => { + for &v in inputs { + mark_used_and_propagate(v); } } - }, + } + }, }; func_def_body.inner_visit_with(&mut visitor); @@ -463,10 +456,10 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { let mut value_replacements = FxHashMap::default(); // Remove anything that didn't end up marked as used (directly or indirectly). - for control_node in all_control_nodes { - let control_node_def = func_def_body.at(control_node).def(); - match &control_node_def.kind { - &ControlNodeKind::Block { insts } => { + for node in all_nodes { + let node_def = func_def_body.at(node).def(); + match &node_def.kind { + &NodeKind::Block { insts } => { let mut all_nops = true; let mut func_at_inst_iter = func_def_body.at_mut(insts).into_iter(); while let Some(mut func_at_inst) = func_at_inst_iter.next() { @@ -496,30 +489,26 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { // HACK(eddyb) because we can't remove list elements yet, we // instead replace blocks of `OpNop`s with empty ones. if all_nops { - func_def_body.at_mut(control_node).def().kind = ControlNodeKind::Block { + func_def_body.at_mut(node).def().kind = NodeKind::Block { insts: Default::default(), }; } } - ControlNodeKind::Select { cases, .. } => { + NodeKind::Select { cases, .. } => { // FIXME(eddyb) remove this cloning. let cases = cases.clone(); let mut new_idx = 0; - for original_idx in 0..control_node_def.outputs.len() { - let original_output = Value::ControlNodeOutput { - control_node, + for original_idx in 0..node_def.outputs.len() { + let original_output = Value::NodeOutput { + node, output_idx: original_idx as u32, }; if !used_values.contains(&original_output) { // Remove the output definition and corresponding value from all cases. - func_def_body - .at_mut(control_node) - .def() - .outputs - .remove(new_idx); + func_def_body.at_mut(node).def().outputs.remove(new_idx); for &case in &cases { func_def_body.at_mut(case).def().outputs.remove(new_idx); } @@ -528,8 +517,8 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { // Record remappings for any still-used outputs that got "shifted over". if original_idx != new_idx { - let new_output = Value::ControlNodeOutput { - control_node, + let new_output = Value::NodeOutput { + node, output_idx: new_idx as u32, }; value_replacements.insert(original_output, new_output); @@ -538,7 +527,7 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { } } - ControlNodeKind::Loop { + NodeKind::Loop { body, initial_inputs, .. @@ -554,8 +543,8 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { if !used_values.contains(&original_input) { // Remove the input definition and corresponding values. - match &mut func_def_body.at_mut(control_node).def().kind { - ControlNodeKind::Loop { initial_inputs, .. } => { + match &mut func_def_body.at_mut(node).def().kind { + NodeKind::Loop { initial_inputs, .. } => { initial_inputs.remove(new_idx); } _ => unreachable!(), @@ -578,7 +567,7 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { } } - ControlNodeKind::ExitInvocation { .. } => {} + NodeKind::ExitInvocation { .. } => {} } } diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs index ea44d8428b5..fb75ffe777d 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs @@ -4,10 +4,9 @@ use spirt::func_at::{FuncAt, FuncAtMut}; use spirt::transform::InnerInPlaceTransform; use spirt::visit::InnerVisit; use spirt::{ - Const, ConstDef, ConstKind, Context, ControlNode, ControlNodeDef, ControlNodeKind, - ControlNodeOutputDecl, DataInst, DataInstDef, DataInstFormDef, DataInstKind, - EntityOrientedDenseMap, FuncDefBody, Region, RegionInputDecl, SelectionKind, Type, TypeDef, - TypeKind, Value, spv, + Const, ConstDef, ConstKind, Context, DataInst, DataInstDef, DataInstFormDef, DataInstKind, + EntityOrientedDenseMap, FuncDefBody, Node, NodeDef, NodeKind, NodeOutputDecl, Region, + RegionInputDecl, SelectionKind, Type, TypeDef, TypeKind, Value, spv, }; use std::collections::hash_map::Entry; use std::{iter, slice}; @@ -42,10 +41,10 @@ pub(crate) fn reduce_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { /// Replace uses of a `DataInst` with a reduced `Value`. DataInst(DataInst), - /// Replace an `OpSwitch` `ControlNode` with an `if`-`else` one. + /// Replace an `OpSwitch` `Node` with an `if`-`else` one. // - // HACK(eddyb) see comment in `handle_control_node` for more details. - SwitchToIfElse(ControlNode), + // HACK(eddyb) see comment in `handle_node` for more details. + SwitchToIfElse(Node), } loop { @@ -57,132 +56,130 @@ pub(crate) fn reduce_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { // // HACK(eddyb) ignore the above, for now it's pretty bad due to iterator // invalidation (see comment on `let reduction_queue` too). - let mut handle_control_node = - |func_at_control_node: FuncAt<'_, ControlNode>| match func_at_control_node.def() { - &ControlNodeDef { - kind: ControlNodeKind::Block { insts }, - .. - } => { - for func_at_inst in func_at_control_node.at(insts) { - if let Ok(redu) = Reducible::try_from((cx, func_at_inst.def())) { - let redu_target = ReductionTarget::DataInst(func_at_inst.position); - reduction_queue.push((redu_target, redu)); - } + let mut handle_node = |func_at_node: FuncAt<'_, Node>| match func_at_node.def() { + &NodeDef { + kind: NodeKind::Block { insts }, + .. + } => { + for func_at_inst in func_at_node.at(insts) { + if let Ok(redu) = Reducible::try_from((cx, func_at_inst.def())) { + let redu_target = ReductionTarget::DataInst(func_at_inst.position); + reduction_queue.push((redu_target, redu)); } } + } - ControlNodeDef { - kind: - ControlNodeKind::Select { + NodeDef { + kind: + NodeKind::Select { + kind, + scrutinee, + cases, + }, + outputs, + } => { + // FIXME(eddyb) this should probably be ran in the queue loop + // below, to more quickly benefit from previous reductions. + for i in 0..u32::try_from(outputs.len()).unwrap() { + let output = Value::NodeOutput { + node: func_at_node.position, + output_idx: i, + }; + if let Entry::Vacant(entry) = value_replacements.entry(output) { + let per_case_value = cases + .iter() + .map(|&case| func_at_node.at(case).def().outputs[i as usize]); + if let Some(reduced) = try_reduce_select( + cx, + &parent_map, + func_at_node.position, kind, - scrutinee, - cases, - }, - outputs, - } => { - // FIXME(eddyb) this should probably be ran in the queue loop - // below, to more quickly benefit from previous reductions. - for i in 0..u32::try_from(outputs.len()).unwrap() { - let output = Value::ControlNodeOutput { - control_node: func_at_control_node.position, - output_idx: i, - }; - if let Entry::Vacant(entry) = value_replacements.entry(output) { - let per_case_value = cases.iter().map(|&case| { - func_at_control_node.at(case).def().outputs[i as usize] - }); - if let Some(reduced) = try_reduce_select( - cx, - &parent_map, - func_at_control_node.position, - kind, - *scrutinee, - per_case_value, - ) { - entry.insert(reduced); - } + *scrutinee, + per_case_value, + ) { + entry.insert(reduced); } } + } - // HACK(eddyb) turn `switch x { case 0: A; case 1: B; default: ... }` - // into `if ... {B} else {A}`, when `x` ends up limited in `0..=1`, - // (such `switch`es come from e.g. `match`-ing enums w/ 2 variants) - // allowing us to bypass SPIR-T current (and temporary) lossiness - // wrt `default: OpUnreachable` (i.e. we prove the `default:` can't - // be entered based on `x` not having values other than `0` or `1`) - if let SelectionKind::SpvInst(spv_inst) = kind - && spv_inst.opcode == wk.OpSwitch - && cases.len() == 3 - { - // FIXME(eddyb) this kind of `OpSwitch` decoding logic should - // be done by SPIR-T ahead of time, not here. - let num_logical_imms = cases.len() - 1; - assert_eq!(spv_inst.imms.len() % num_logical_imms, 0); - let logical_imm_size = spv_inst.imms.len() / num_logical_imms; - // FIXME(eddyb) collect to array instead. - let logical_imms_as_u32s: SmallVec<[_; 2]> = spv_inst - .imms - .chunks(logical_imm_size) - .map(spv_imm_checked_trunc32) - .collect(); - - // FIMXE(eddyb) support more values than just `0..=1`. - if logical_imms_as_u32s[..] == [Some(0), Some(1)] { - let redu = Reducible { - op: PureOp::IntToBool, - output_type: cx.intern(TypeDef { - attrs: Default::default(), - kind: TypeKind::SpvInst { - spv_inst: wk.OpTypeBool.into(), - type_and_const_inputs: iter::empty().collect(), - }, - }), - input: *scrutinee, - }; - let redu_target = - ReductionTarget::SwitchToIfElse(func_at_control_node.position); - reduction_queue.push((redu_target, redu)); - } + // HACK(eddyb) turn `switch x { case 0: A; case 1: B; default: ... }` + // into `if ... {B} else {A}`, when `x` ends up limited in `0..=1`, + // (such `switch`es come from e.g. `match`-ing enums w/ 2 variants) + // allowing us to bypass SPIR-T current (and temporary) lossiness + // wrt `default: OpUnreachable` (i.e. we prove the `default:` can't + // be entered based on `x` not having values other than `0` or `1`) + if let SelectionKind::SpvInst(spv_inst) = kind + && spv_inst.opcode == wk.OpSwitch + && cases.len() == 3 + { + // FIXME(eddyb) this kind of `OpSwitch` decoding logic should + // be done by SPIR-T ahead of time, not here. + let num_logical_imms = cases.len() - 1; + assert_eq!(spv_inst.imms.len() % num_logical_imms, 0); + let logical_imm_size = spv_inst.imms.len() / num_logical_imms; + // FIXME(eddyb) collect to array instead. + let logical_imms_as_u32s: SmallVec<[_; 2]> = spv_inst + .imms + .chunks(logical_imm_size) + .map(spv_imm_checked_trunc32) + .collect(); + + // FIMXE(eddyb) support more values than just `0..=1`. + if logical_imms_as_u32s[..] == [Some(0), Some(1)] { + let redu = Reducible { + op: PureOp::IntToBool, + output_type: cx.intern(TypeDef { + attrs: Default::default(), + kind: TypeKind::SpvInst { + spv_inst: wk.OpTypeBool.into(), + type_and_const_inputs: iter::empty().collect(), + }, + }), + input: *scrutinee, + }; + let redu_target = ReductionTarget::SwitchToIfElse(func_at_node.position); + reduction_queue.push((redu_target, redu)); } } + } - ControlNodeDef { - kind: - ControlNodeKind::Loop { - body, - initial_inputs, - .. - }, - .. - } => { - // FIXME(eddyb) this should probably be ran in the queue loop - // below, to more quickly benefit from previous reductions. - let body_outputs = &func_at_control_node.at(*body).def().outputs; - for (i, (&initial_input, &body_output)) in - initial_inputs.iter().zip(body_outputs).enumerate() - { - let body_input = Value::RegionInput { - region: *body, - input_idx: i as u32, - }; - if body_output == body_input { - value_replacements - .entry(body_input) - .or_insert(initial_input); - } + NodeDef { + kind: + NodeKind::Loop { + body, + initial_inputs, + .. + }, + .. + } => { + // FIXME(eddyb) this should probably be ran in the queue loop + // below, to more quickly benefit from previous reductions. + let body_outputs = &func_at_node.at(*body).def().outputs; + for (i, (&initial_input, &body_output)) in + initial_inputs.iter().zip(body_outputs).enumerate() + { + let body_input = Value::RegionInput { + region: *body, + input_idx: i as u32, + }; + if body_output == body_input { + value_replacements + .entry(body_input) + .or_insert(initial_input); } } + } - &ControlNodeDef { - kind: ControlNodeKind::ExitInvocation { .. }, - .. - } => {} - }; + &NodeDef { + kind: NodeKind::ExitInvocation { .. }, + .. + } => {} + }; func_def_body.inner_visit_with(&mut VisitAllRegionsAndNodes { state: (), visit_region: |_: &mut (), _| {}, - visit_control_node: |_: &mut (), func_at_control_node| { - handle_control_node(func_at_control_node); + visit_node: |_: &mut (), func_at_node| { + handle_node(func_at_node); }, }); @@ -219,13 +216,13 @@ pub(crate) fn reduce_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { }; } - // HACK(eddyb) see comment in `handle_control_node` for more details. - ReductionTarget::SwitchToIfElse(control_node) => { - let control_node_def = func_def_body.at_mut(control_node).def(); - match &control_node_def.kind { - ControlNodeKind::Select { cases, .. } => match cases[..] { + // HACK(eddyb) see comment in `handle_node` for more details. + ReductionTarget::SwitchToIfElse(node) => { + let node_def = func_def_body.at_mut(node).def(); + match &node_def.kind { + NodeKind::Select { cases, .. } => match cases[..] { [_default, case_0, case_1] => { - control_node_def.kind = ControlNodeKind::Select { + node_def.kind = NodeKind::Select { kind: SelectionKind::BoolCond, scrutinee: v, cases: [case_1, case_0].iter().copied().collect(), @@ -268,9 +265,9 @@ pub(crate) fn reduce_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { // FIXME(eddyb) maybe this kind of "parent map" should be provided by SPIR-T? #[derive(Default)] struct ParentMap { - data_inst_parent: EntityOrientedDenseMap, - control_node_parent: EntityOrientedDenseMap, - region_parent: EntityOrientedDenseMap, + data_inst_parent: EntityOrientedDenseMap, + node_parent: EntityOrientedDenseMap, + region_parent: EntityOrientedDenseMap, } impl ParentMap { @@ -278,28 +275,28 @@ impl ParentMap { let mut visitor = VisitAllRegionsAndNodes { state: Self::default(), visit_region: |this: &mut Self, func_at_region: FuncAt<'_, Region>| { - for func_at_child_control_node in func_at_region.at_children() { - this.control_node_parent - .insert(func_at_child_control_node.position, func_at_region.position); + for func_at_child_node in func_at_region.at_children() { + this.node_parent + .insert(func_at_child_node.position, func_at_region.position); } }, - visit_control_node: |this: &mut Self, func_at_control_node: FuncAt<'_, ControlNode>| { - let child_regions = match &func_at_control_node.def().kind { - &ControlNodeKind::Block { insts } => { - for func_at_inst in func_at_control_node.at(insts) { + visit_node: |this: &mut Self, func_at_node: FuncAt<'_, Node>| { + let child_regions = match &func_at_node.def().kind { + &NodeKind::Block { insts } => { + for func_at_inst in func_at_node.at(insts) { this.data_inst_parent - .insert(func_at_inst.position, func_at_control_node.position); + .insert(func_at_inst.position, func_at_node.position); } &[][..] } - ControlNodeKind::Select { cases, .. } => cases, - ControlNodeKind::Loop { body, .. } => slice::from_ref(body), - ControlNodeKind::ExitInvocation { .. } => &[][..], + NodeKind::Select { cases, .. } => cases, + NodeKind::Loop { body, .. } => slice::from_ref(body), + NodeKind::ExitInvocation { .. } => &[][..], }; for &child_region in child_regions { this.region_parent - .insert(child_region, func_at_control_node.position); + .insert(child_region, func_at_node.position); } }, }; @@ -314,8 +311,8 @@ impl ParentMap { fn try_reduce_select( cx: &Context, parent_map: &ParentMap, - select_control_node: ControlNode, - // FIXME(eddyb) are these redundant with the `ControlNode` above? + select_node: Node, + // FIXME(eddyb) are these redundant with the `Node` above? kind: &SelectionKind, scrutinee: Value, cases: impl Iterator, @@ -378,18 +375,15 @@ fn try_reduce_select( let region_defining_x = match x { Value::Const(_) => unreachable!(), Value::RegionInput { region, .. } => region, - Value::ControlNodeOutput { control_node, .. } => { - *parent_map.control_node_parent.get(control_node)? - } + Value::NodeOutput { node, .. } => *parent_map.node_parent.get(node)?, Value::DataInstOutput(inst) => *parent_map - .control_node_parent + .node_parent .get(*parent_map.data_inst_parent.get(inst)?)?, }; // Fast-reject: if `x` is defined immediately inside one of - // `select_control_node`'s cases, it's not a dominator. - if parent_map.region_parent.get(region_defining_x) == Some(&select_control_node) - { + // `select_node`'s cases, it's not a dominator. + if parent_map.region_parent.get(region_defining_x) == Some(&select_node) { return None; } @@ -402,14 +396,13 @@ fn try_reduce_select( // FIXME(eddyb) this could be more efficient with some kind // of "region depth" precomputation but a potentially-slower // check doubles as a sanity check, for now. - let mut region_containing_select = - *parent_map.control_node_parent.get(select_control_node)?; + let mut region_containing_select = *parent_map.node_parent.get(select_node)?; loop { if region_containing_select == region_defining_x { return Some(()); } region_containing_select = *parent_map - .control_node_parent + .node_parent .get(*parent_map.region_parent.get(region_containing_select)?)?; } }; @@ -744,10 +737,10 @@ impl Reducible { let loop_node = *parent_map.region_parent.get(region)?; // HACK(eddyb) this can't be a closure due to lifetime elision. fn loop_initial_states( - func_at_loop_node: FuncAtMut<'_, ControlNode>, + func_at_loop_node: FuncAtMut<'_, Node>, ) -> &mut SmallVec<[Value; 2]> { match &mut func_at_loop_node.def().kind { - ControlNodeKind::Loop { initial_inputs, .. } => initial_inputs, + NodeKind::Loop { initial_inputs, .. } => initial_inputs, _ => unreachable!(), } } @@ -801,16 +794,13 @@ impl Reducible { .iter() .last .filter(|&node| { - matches!( - func.reborrow().at(node).def().kind, - ControlNodeKind::Block { .. } - ) + matches!(func.reborrow().at(node).def().kind, NodeKind::Block { .. }) }) .unwrap_or_else(|| { - let new_block = func.control_nodes.define( + let new_block = func.nodes.define( cx, - ControlNodeDef { - kind: ControlNodeKind::Block { + NodeDef { + kind: NodeKind::Block { insts: Default::default(), }, outputs: Default::default(), @@ -819,11 +809,11 @@ impl Reducible { ); func.regions[region] .children - .insert_last(new_block, func.control_nodes); + .insert_last(new_block, func.nodes); new_block }); - match &mut func.control_nodes[loop_body_last_block].kind { - ControlNodeKind::Block { insts } => { + match &mut func.nodes[loop_body_last_block].kind { + NodeKind::Block { insts } => { insts.insert_last(output_from_updated_state, func.data_insts); } _ => unreachable!(), @@ -834,12 +824,9 @@ impl Reducible { input_idx: new_loop_state_idx, }) } - Value::ControlNodeOutput { - control_node, - output_idx, - } => { - let cases = match &func.reborrow().at(control_node).def().kind { - ControlNodeKind::Select { cases, .. } => cases, + Value::NodeOutput { node, output_idx } => { + let cases = match &func.reborrow().at(node).def().kind { + NodeKind::Select { cases, .. } => cases, // NOTE(eddyb) only `Select`s can have outputs right now. _ => unreachable!(), }; @@ -864,8 +851,8 @@ impl Reducible { // Try to avoid introducing a new output, by reducing the merge // of the per-case output values to a single value, if possible. - let (kind, scrutinee) = match &func.reborrow().at(control_node).def().kind { - ControlNodeKind::Select { + let (kind, scrutinee) = match &func.reborrow().at(node).def().kind { + NodeKind::Select { kind, scrutinee, .. } => (kind, *scrutinee), _ => unreachable!(), @@ -873,7 +860,7 @@ impl Reducible { if let Some(v) = try_reduce_select( cx, parent_map, - control_node, + node, kind, scrutinee, per_case_new_output.iter().copied(), @@ -882,9 +869,9 @@ impl Reducible { } // Merge the per-case output values into a new output. - let control_node_output_decls = &mut func.reborrow().at(control_node).def().outputs; - let new_output_idx = u32::try_from(control_node_output_decls.len()).unwrap(); - control_node_output_decls.push(ControlNodeOutputDecl { + let node_output_decls = &mut func.reborrow().at(node).def().outputs; + let new_output_idx = u32::try_from(node_output_decls.len()).unwrap(); + node_output_decls.push(NodeOutputDecl { attrs: Default::default(), ty: self.output_type, }); @@ -893,8 +880,8 @@ impl Reducible { assert_eq!(per_case_outputs.len(), new_output_idx as usize); per_case_outputs.push(new_output); } - Some(Value::ControlNodeOutput { - control_node, + Some(Value::NodeOutput { + node, output_idx: new_output_idx, }) } From 97459e57ade7827601d378086db7c1a355eed0c2 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 9 Sep 2025 11:40:02 +0300 Subject: [PATCH 3/8] Update `spirt` for `Attr::DbgSrcLoc`. --- Cargo.lock | 2 +- crates/rustc_codegen_spirv/Cargo.toml | 3 +- .../rustc_codegen_spirv/src/codegen_cx/mod.rs | 7 - crates/rustc_codegen_spirv/src/linker/mod.rs | 65 ++- .../src/linker/spirt_passes/controlflow.rs | 152 +++--- .../src/linker/spirt_passes/debuginfo.rs | 362 +++++++++++--- .../src/linker/spirt_passes/diagnostics.rs | 442 ++++-------------- .../src/linker/spirt_passes/mod.rs | 23 +- docs/src/codegen-args.md | 9 - .../ui/dis/asm_op_decorate.stderr | 2 + .../ui/dis/custom_entry_point.stderr | 1 + .../ui/dis/generic-fn-op-name.stderr | 2 + .../issue-590-multiple-entry-points.stderr | 3 + tests/compiletests/ui/dis/issue-615.stderr | 2 + .../ui/dis/issue-723-output.stderr | 1 + 15 files changed, 495 insertions(+), 581 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d799734f633..135d2179db0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5795,7 +5795,7 @@ dependencies = [ [[package]] name = "spirt" version = "0.4.0" -source = "git+https://github.com/Rust-GPU/spirt?rev=3cabf188#3cabf188f8c28d89903ab34633e3ebaae8ef9821" +source = "git+https://github.com/Rust-GPU/spirt?rev=000ec78a#000ec78a7ec7ae213d9e21be64aefdf12fe8d4c1" dependencies = [ "arrayvec", "bytemuck", diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index 726f31661a3..a3609887733 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -58,7 +58,8 @@ smallvec = { version = "1.6.1", features = ["const_generics", "const_new", "unio # HACK(eddyb) temporary until a new SPIR-T release contains the following: # - https://github.com/Rust-GPU/spirt/pull/7 # - https://github.com/Rust-GPU/spirt/pull/8 -spirt = { git = "https://github.com/Rust-GPU/spirt", rev = "3cabf188" } +# - https://github.com/Rust-GPU/spirt/pull/9 +spirt = { git = "https://github.com/Rust-GPU/spirt", rev = "000ec78a" } spirv-tools.workspace = true lazy_static = "1.4.0" itertools = "0.14.0" diff --git a/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs b/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs index 91a319b9bdf..9e5449e90ac 100644 --- a/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs +++ b/crates/rustc_codegen_spirv/src/codegen_cx/mod.rs @@ -490,11 +490,6 @@ impl CodegenArgs { "dump the final SPIR-T module, to a (pair of) file(s) in DIR", "DIR", ); - opts.optflag( - "", - "spirt-strip-custom-debuginfo-from-dumps", - "strip custom debuginfo instructions when dumping SPIR-T", - ); opts.optflag( "", "spirt-keep-debug-sources-in-dumps", @@ -670,8 +665,6 @@ impl CodegenArgs { } [None, None] => None, }, - spirt_strip_custom_debuginfo_from_dumps: matches - .opt_present("spirt-strip-custom-debuginfo-from-dumps"), spirt_keep_debug_sources_in_dumps: matches .opt_present("spirt-keep-debug-sources-in-dumps"), spirt_keep_unstructured_cfg_in_dumps: matches diff --git a/crates/rustc_codegen_spirv/src/linker/mod.rs b/crates/rustc_codegen_spirv/src/linker/mod.rs index 98e076bf5fe..39ceb622c56 100644 --- a/crates/rustc_codegen_spirv/src/linker/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/mod.rs @@ -63,7 +63,6 @@ pub struct Options { pub dump_post_inline: Option, pub dump_post_split: Option, pub dump_spirt: Option<(PathBuf, DumpSpirtMode)>, - pub spirt_strip_custom_debuginfo_from_dumps: bool, pub spirt_keep_debug_sources_in_dumps: bool, pub spirt_keep_unstructured_cfg_in_dumps: bool, pub specializer_dump_instances: Option, @@ -151,9 +150,6 @@ fn get_name<'a>(names: &FxHashMap, id: Word) -> Cow<'a, str> { impl Options { // FIXME(eddyb) using a method on this type seems a bit sketchy. fn spirt_cleanup_for_dumping(&self, module: &mut spirt::Module) { - if self.spirt_strip_custom_debuginfo_from_dumps { - spirt_passes::debuginfo::convert_custom_debuginfo_to_spv(module); - } if !self.spirt_keep_debug_sources_in_dumps { const DOTS: &str = "⋯"; let dots_interned_str = module.cx().intern(DOTS); @@ -194,22 +190,31 @@ pub fn link( spirv_tools::binary::from_binary(&spv_words).to_vec() }; - // FIXME(eddyb) should've really been "spirt::Module::lower_from_spv_bytes". - let lower_from_spv_timer = sess.timer("spirt::Module::lower_from_spv_file"); let cx = std::rc::Rc::new(spirt::Context::new()); crate::custom_insts::register_to_spirt_context(&cx); - ( - spv_words, - spirt::Module::lower_from_spv_bytes(cx, spv_bytes), - // HACK(eddyb) this is only returned for `SpirtDumpGuard`. - lower_from_spv_timer, - ) + + // FIXME(eddyb) should've really been "spirt::Module::lower_from_spv_bytes". + let mut module = { + let _timer = sess.timer("spirt::Module::lower_from_spv_file"); + spirt::Module::lower_from_spv_bytes(cx, spv_bytes) + }; + + // Replace our custom debuginfo instructions as early as possible. + if let Ok(module) = &mut module { + let _timer = sess.timer( + "spirt_passes::debuginfo::convert_custom_decorations_and_debuginfo_to_spirt", + ); + spirt_passes::debuginfo::convert_custom_decorations_and_debuginfo_to_spirt( + opts, module, + ); + } + + (spv_words, module) }; // FIXME(eddyb) deduplicate with `SpirtDumpGuard`. let dump_spv_and_spirt = |spv_module: &Module, dump_file_path_stem: PathBuf| { - let (spv_words, spirt_module_or_err, _) = - spv_module_to_spv_words_and_spirt_module(spv_module); + let (spv_words, spirt_module_or_err) = spv_module_to_spv_words_and_spirt_module(spv_module); std::fs::write( dump_file_path_stem.with_extension("spv"), spirv_tools::binary::from_binary(&spv_words), @@ -494,8 +499,7 @@ pub fn link( // NOTE(eddyb) SPIR-T pipeline is entirely limited to this block. { - let (spv_words, module_or_err, lower_from_spv_timer) = - spv_module_to_spv_words_and_spirt_module(&output); + let (spv_words, module_or_err) = spv_module_to_spv_words_and_spirt_module(&output); let module = &mut module_or_err.map_err(|e| { let spv_path = outputs.temp_path_for_diagnostic("spirt-lower-from-spv-input.spv"); @@ -533,8 +537,8 @@ pub fn link( sess.timer(pass_name) }; - let mut after_pass = |module: Option<&spirt::Module>, timer| { - drop(timer); + let mut after_pass = |module: Option<&spirt::Module>, maybe_timer| { + drop(maybe_timer); let pass_name = dump_guard.in_progress_pass_name.take().unwrap(); if let Some(module) = module && matches!(opts.dump_spirt, Some((_, DumpSpirtMode::AllPasses))) @@ -548,7 +552,7 @@ pub fn link( // after SPIR-T 0.4.0 it's extremely verbose (due to def-use hermeticity). after_pass( (opts.spirt_keep_unstructured_cfg_in_dumps || !opts.structurize).then_some(&*module), - lower_from_spv_timer, + None, ); // NOTE(eddyb) this *must* run on unstructured CFGs, to do its job. @@ -560,13 +564,13 @@ pub fn link( "spirt_passes::controlflow::convert_custom_aborts_to_unstructured_returns_in_entry_points", ); spirt_passes::controlflow::convert_custom_aborts_to_unstructured_returns_in_entry_points(opts, module); - after_pass(None, timer); + after_pass(None, Some(timer)); } if opts.structurize { let timer = before_pass("spirt::legalize::structurize_func_cfgs"); spirt::passes::legalize::structurize_func_cfgs(module); - after_pass(Some(module), timer); + after_pass(Some(module), Some(timer)); } if !opts.spirt_passes.is_empty() { @@ -575,25 +579,25 @@ pub fn link( module, &opts.spirt_passes, |name, _module| before_pass(name), - &mut after_pass, + |module, timer| after_pass(module, Some(timer)), ); } { let timer = before_pass("spirt_passes::explicit_layout::erase_when_invalid"); spirt_passes::explicit_layout::erase_when_invalid(module); - after_pass(Some(module), timer); + after_pass(Some(module), Some(timer)); } { let timer = before_pass("spirt_passes::validate"); spirt_passes::validate::validate(module); - after_pass(Some(module), timer); + after_pass(Some(module), Some(timer)); } { let timer = before_pass("spirt_passes::diagnostics::report_diagnostics"); - spirt_passes::diagnostics::report_diagnostics(sess, opts, module).map_err( + spirt_passes::diagnostics::report_diagnostics(sess, module).map_err( |spirt_passes::diagnostics::ReportedDiagnostics { rustc_errors_guarantee, any_errors_were_spirt_bugs, @@ -602,20 +606,13 @@ pub fn link( rustc_errors_guarantee }, )?; - after_pass(None, timer); - } - - // Replace our custom debuginfo instructions just before lifting to SPIR-V. - { - let timer = before_pass("spirt_passes::debuginfo::convert_custom_debuginfo_to_spv"); - spirt_passes::debuginfo::convert_custom_debuginfo_to_spv(module); - after_pass(None, timer); + after_pass(None, Some(timer)); } let spv_words = { let timer = before_pass("spirt::Module::lift_to_spv_module_emitter"); let spv_words = module.lift_to_spv_module_emitter().unwrap().words; - after_pass(None, timer); + after_pass(None, Some(timer)); spv_words }; // FIXME(eddyb) dump both SPIR-T and `spv_words` if there's an error here. diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs index 7623edde859..d444cb0c886 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs @@ -4,8 +4,9 @@ use crate::custom_insts::{self, CustomInst, CustomOp}; use smallvec::SmallVec; use spirt::func_at::FuncAt; use spirt::{ - Attr, AttrSet, ConstDef, ConstKind, DataInstFormDef, DataInstKind, DeclDef, EntityDefs, - ExportKey, Exportee, Module, NodeKind, Type, TypeDef, TypeKind, TypeOrConst, Value, cfg, spv, + Attr, AttrSet, ConstDef, ConstKind, DataInstFormDef, DataInstKind, DbgSrcLoc, DeclDef, + EntityDefs, ExportKey, Exportee, Module, NodeKind, Type, TypeDef, TypeKind, TypeOrConst, Value, + cfg, spv, }; use std::fmt::Write as _; @@ -46,11 +47,11 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( // HACK(eddyb) deduplicate with `diagnostics`. let name_from_attrs = |attrs: AttrSet| { cx[attrs].attrs.iter().find_map(|attr| match attr { - Attr::SpvAnnotation(spv_inst) if spv_inst.opcode == wk.OpName => Some( - super::diagnostics::decode_spv_lit_str_with(&spv_inst.imms, |name| { + Attr::SpvAnnotation(spv_inst) if spv_inst.opcode == wk.OpName => { + Some(super::decode_spv_lit_str_with(&spv_inst.imms, |name| { name.to_string() - }), - ), + })) + } _ => None, }) }; @@ -88,7 +89,7 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( match entry_point_imms[..] { [spv::Imm::Short(em_kind, _), ref name_imms @ ..] => { assert_eq!(em_kind, wk.ExecutionModel); - super::diagnostics::decode_spv_lit_str_with(name_imms, |name| { + super::decode_spv_lit_str_with(name_imms, |name| { fmt += &name.replace('%', "%%"); }); } @@ -223,26 +224,23 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( position: *block_insts, }; - let block_insts_maybe_custom = func_at_block_insts.into_iter().map(|func_at_inst| { - let data_inst_def = func_at_inst.def(); - ( - func_at_inst, + let custom_terminator_inst = func_at_block_insts + .into_iter() + .next_back() + .and_then(|func_at_inst| { + let data_inst_def = func_at_inst.def(); match cx[data_inst_def.form].kind { DataInstKind::SpvExtInst { ext_set, inst } if ext_set == custom_ext_inst_set => { - Some(CustomOp::decode(inst).with_operands(&data_inst_def.inputs)) + Some(( + func_at_inst, + CustomOp::decode(inst).with_operands(&data_inst_def.inputs), + )) } _ => None, - }, - ) - }); - let custom_terminator_inst = block_insts_maybe_custom - .clone() - .rev() - .take_while(|(_, custom)| custom.is_some()) - .map(|(func_at_inst, custom)| (func_at_inst, custom.unwrap())) - .find(|(_, custom)| !custom.op().is_debuginfo()) + } + }) .filter(|(_, custom)| custom.op().is_terminator()); if let Some(( func_at_abort_inst, @@ -273,19 +271,6 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( &ConstKind::SpvStringLiteralForExtInst(s) => s, _ => unreachable!(), }; - let const_u32 = |v: Value| match const_kind(v) { - ConstKind::SpvInst { - spv_inst_and_const_inputs, - } => { - let (spv_inst, _const_inputs) = &**spv_inst_and_const_inputs; - assert!(spv_inst.opcode == wk.OpConstant); - match spv_inst.imms[..] { - [spv::Imm::Short(_, x)] => x, - _ => unreachable!(), - } - } - _ => unreachable!(), - }; let mk_const_str = |s| { cx.intern(ConstDef { attrs: Default::default(), @@ -297,48 +282,6 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( }) }; - let mut current_debug_src_loc = None; - let mut call_stack = SmallVec::<[_; 8]>::new(); - let block_insts_custom = block_insts_maybe_custom - .filter_map(|(func_at_inst, custom)| Some((func_at_inst, custom?))); - for (func_at_inst, custom) in block_insts_custom { - // Stop at the abort, that we don't undo its debug context. - if func_at_inst.position == abort_inst { - break; - } - - match custom { - CustomInst::SetDebugSrcLoc { - file, - line_start, - line_end: _, - col_start, - col_end: _, - } => { - current_debug_src_loc = Some(( - &cx[const_str(file)], - const_u32(line_start), - const_u32(col_start), - )); - } - CustomInst::ClearDebugSrcLoc => current_debug_src_loc = None, - CustomInst::PushInlinedCallFrame { callee_name } => { - if backtrace { - call_stack.push(( - current_debug_src_loc.take(), - const_str(callee_name), - )); - } - } - CustomInst::PopInlinedCallFrame => { - if let Some((callsite_debug_src_loc, _)) = call_stack.pop() { - current_debug_src_loc = callsite_debug_src_loc; - } - } - CustomInst::Abort { .. } => {} - } - } - let mut fmt = String::new(); let (message_debug_printf_fmt_str, message_debug_printf_args) = @@ -347,7 +290,10 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( .map(|(&fmt_str, args)| (&cx[const_str(fmt_str)], args)) .unwrap_or_default(); - let fmt_dbg_src_loc = |(file, line, col)| { + let fmt_dbg_src_loc = |dbg_src_loc: DbgSrcLoc| { + let file = &cx[dbg_src_loc.file_path]; + let (line, col) = dbg_src_loc.start_line_col; + // FIXME(eddyb) figure out what is going on with // these column number conventions, below is a // related comment from `spirt::print`: @@ -375,7 +321,9 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( } }; - if let Some(loc) = current_debug_src_loc.take() { + let mut dbg_src_loc = func_at_abort_inst.def().attrs.dbg_src_loc(cx); + + if let Some(loc) = dbg_src_loc { fmt += " at "; fmt += &fmt_dbg_src_loc(loc); } @@ -384,27 +332,37 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( fmt += &message_debug_printf_fmt_str.replace('\n', "\n "); let mut innermost = true; - let mut append_call = |callsite_debug_src_loc, callee: &str| { - if innermost { - innermost = false; - fmt += "\n in "; - } else if current_debug_src_loc.is_some() { - fmt += "\n by "; - } else { - // HACK(eddyb) previous call didn't have a `called at` line. - fmt += "\n called by "; - } - fmt += callee; - if let Some(loc) = callsite_debug_src_loc { - fmt += "\n called at "; - fmt += &fmt_dbg_src_loc(loc); + let mut append_call = + |callee_name: &str, call_site_loc, callee_loc: Option<_>| { + if innermost { + innermost = false; + fmt += "\n in "; + } else if callee_loc.is_some() { + fmt += "\n by "; + } else { + // HACK(eddyb) previous call didn't have a `called at` line. + fmt += "\n called by "; + } + fmt += callee_name; + if let Some(loc) = call_site_loc { + fmt += "\n called at "; + fmt += &fmt_dbg_src_loc(loc); + } + }; + if backtrace { + while let Some((callee_name, call_site_attrs)) = + dbg_src_loc.and_then(|loc| loc.inlined_callee_name_and_call_site) + { + let call_site_loc = call_site_attrs.dbg_src_loc(cx); + append_call( + &cx[callee_name].replace('%', "%%"), + call_site_loc, + dbg_src_loc, + ); + dbg_src_loc = call_site_loc; } - current_debug_src_loc = callsite_debug_src_loc; - }; - while let Some((callsite_debug_src_loc, callee)) = call_stack.pop() { - append_call(callsite_debug_src_loc, &cx[callee].replace('%', "%%")); } - append_call(None, &debug_printf_context_fmt_str); + append_call(&debug_printf_context_fmt_str, None, dbg_src_loc); fmt += "\n"; diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs index 7a3b8cf9845..aac58151f2f 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs @@ -1,24 +1,32 @@ //! SPIR-T passes related to debuginfo. +use crate::custom_decorations::{CustomDecoration, SrcLocDecoration, ZombieDecoration}; use crate::custom_insts::{self, CustomInst, CustomOp}; -use rustc_data_structures::fx::FxIndexSet; +use either::Either; +use rustc_data_structures::fx::{FxHashMap, FxIndexSet}; use smallvec::SmallVec; -use spirt::transform::{InnerInPlaceTransform, Transformer}; +use spirt::func_at::FuncAtMut; +use spirt::transform::{InnerInPlaceTransform as _, Transformed, Transformer}; use spirt::visit::InnerVisit; use spirt::{ - Attr, AttrSetDef, ConstKind, Context, DataInstKind, InternedStr, Module, Node, NodeKind, - OrdAssertEq, Value, spv, + Attr, AttrSet, AttrSetDef, Const, ConstKind, Context, DataInstForm, DataInstKind, DbgSrcLoc, + Diag, InternedStr, Module, Node, NodeKind, Type, Value, spv, }; +use std::marker::PhantomData; +use std::str; -/// Replace our custom extended instruction debuginfo with standard SPIR-V ones. +/// Replace our custom decorations ([`SrcLocDecoration`] and [`ZombieDecoration`]) +/// and custom extended instruction debuginfo, with SPIR-T equivalents. // -// FIXME(eddyb) also handle `SrcLocDecoration`s (when `rspirv` isn't used on the -// SPIR-V output of `spirt::spv::lift`, as it's lossy wrt `OpLine`). -pub fn convert_custom_debuginfo_to_spv(module: &mut Module) { +// FIXME(eddyb) rename this module because it's not just about debuginfo. +pub fn convert_custom_decorations_and_debuginfo_to_spirt( + linker_options: &crate::linker::Options, + module: &mut Module, +) { let cx = &module.cx(); // FIXME(eddyb) reuse this collection work in some kind of "pass manager". - let all_funcs = { + let (all_global_vars, all_funcs) = { let mut collector = super::ReachableUseCollector { cx, module, @@ -33,33 +41,183 @@ pub fn convert_custom_debuginfo_to_spv(module: &mut Module) { export_key.inner_visit_with(&mut collector); exportee.inner_visit_with(&mut collector); } - collector.seen_funcs + (collector.seen_global_vars, collector.seen_funcs) }; - let mut transformer = CustomDebuginfoToSpv { + let mut transformer = CustomDecorationsAndDebuginfoToSpirt { + linker_options, cx, wk: &super::SpvSpecWithExtras::get().well_known, custom_ext_inst_set: cx.intern(&custom_insts::CUSTOM_EXT_INST_SET[..]), + transformed_types: FxHashMap::default(), + transformed_consts: FxHashMap::default(), + transformed_data_inst_forms: FxHashMap::default(), }; + for gv in all_global_vars { + transformer.in_place_transform_global_var_decl(&mut module.global_vars[gv]); + } for func in all_funcs { transformer.in_place_transform_func_decl(&mut module.funcs[func]); } } -struct CustomDebuginfoToSpv<'a> { +// HACK(eddyb) version of `decorations::LazilyDecoded` that works for SPIR-T. +struct LazilyDecoded { + encoded: String, + _marker: PhantomData, +} + +impl LazilyDecoded { + fn try_from_prefixed<'a>(prefixed_encoded: &str) -> Option + where + D: CustomDecoration<'a>, + { + let encoded = prefixed_encoded.strip_prefix(D::ENCODING_PREFIX)?; + + Some(Self { + encoded: encoded.to_string(), + _marker: PhantomData, + }) + } + + fn decode<'a>(&'a self) -> D + where + D: CustomDecoration<'a>, + { + D::decode(&self.encoded) + } +} + +fn decode_all_custom_decorations( + attrs_def: &AttrSetDef, +) -> impl Iterator< + Item = ( + &Attr, + Either>, LazilyDecoded>>, + ), +> + '_ { + let wk = &super::SpvSpecWithExtras::get().well_known; + + attrs_def.attrs.iter().filter_map(|attr| { + let spv_inst = match attr { + Attr::SpvAnnotation(spv_inst) if spv_inst.opcode == wk.OpDecorateString => spv_inst, + _ => return None, + }; + let str_imms = spv_inst + .imms + .strip_prefix(&[spv::Imm::Short(wk.Decoration, wk.UserTypeGOOGLE)])?; + + super::decode_spv_lit_str_with(str_imms, |prefixed_encoded| { + Option::or( + LazilyDecoded::>::try_from_prefixed(prefixed_encoded) + .map(Either::Left), + LazilyDecoded::>::try_from_prefixed(prefixed_encoded) + .map(Either::Right), + ) + }) + .map(|decoded| (attr, decoded)) + }) +} + +struct CustomDecorationsAndDebuginfoToSpirt<'a> { + linker_options: &'a crate::linker::Options, + cx: &'a Context, wk: &'static super::SpvWellKnownWithExtras, /// Interned name for our custom "extended instruction set" /// (see `crate::custom_insts` for more details). custom_ext_inst_set: InternedStr, + + // FIXME(eddyb) build some automation to avoid ever repeating these. + transformed_types: FxHashMap>, + transformed_consts: FxHashMap>, + transformed_data_inst_forms: FxHashMap>, } -impl Transformer for CustomDebuginfoToSpv<'_> { - fn in_place_transform_node_def( +impl Transformer for CustomDecorationsAndDebuginfoToSpirt<'_> { + // FIXME(eddyb) build some automation to avoid ever repeating these. + fn transform_type_use(&mut self, ty: Type) -> Transformed { + if let Some(&cached) = self.transformed_types.get(&ty) { + return cached; + } + let transformed = self + .transform_type_def(&self.cx[ty]) + .map(|ty_def| self.cx.intern(ty_def)); + self.transformed_types.insert(ty, transformed); + transformed + } + fn transform_const_use(&mut self, ct: Const) -> Transformed { + if let Some(&cached) = self.transformed_consts.get(&ct) { + return cached; + } + let transformed = self + .transform_const_def(&self.cx[ct]) + .map(|ct_def| self.cx.intern(ct_def)); + self.transformed_consts.insert(ct, transformed); + transformed + } + fn transform_data_inst_form_use( &mut self, - mut func_at_node: spirt::func_at::FuncAtMut<'_, Node>, - ) { + data_inst_form: DataInstForm, + ) -> Transformed { + if let Some(&cached) = self.transformed_data_inst_forms.get(&data_inst_form) { + return cached; + } + let transformed = self + .transform_data_inst_form_def(&self.cx[data_inst_form]) + .map(|data_inst_form_def| self.cx.intern(data_inst_form_def)); + self.transformed_data_inst_forms + .insert(data_inst_form, transformed); + transformed + } + + fn transform_attr_set_use(&mut self, attrs: AttrSet) -> Transformed { + let orig_attrs = attrs; + let mut attrs = attrs; + for (original_attr, src_loc_or_zombie) in decode_all_custom_decorations(&self.cx[attrs]) { + let src_loc_or_zombie = src_loc_or_zombie + .as_ref() + .map_either(|src_loc| src_loc.decode(), |zombie| zombie.decode()); + attrs.mutate(self.cx, |attrs| { + // FIXME(eddyb) there should be a more efficient way to replace + // attributes as they're being iterated, or something similar. + attrs.attrs.remove(original_attr); + + match src_loc_or_zombie { + Either::Left(SrcLocDecoration { + file_name, + line_start, + line_end, + col_start, + col_end, + }) => attrs.set_dbg_src_loc(DbgSrcLoc { + file_path: self.cx.intern(file_name), + start_line_col: (line_start, col_start), + end_line_col: (line_end, col_end), + inlined_callee_name_and_call_site: None, + }), + Either::Right(ZombieDecoration { reason }) => { + let diag = if self.linker_options.early_report_zombies { + Diag::bug([ + format!("zombie should've been reported already: {reason}").into() + ]) + } else { + Diag::err([reason.to_string().into()]) + }; + attrs.push_diag(diag); + } + } + }); + } + if attrs != orig_attrs { + Transformed::Changed(attrs) + } else { + Transformed::Unchanged + } + } + + fn in_place_transform_node_def(&mut self, mut func_at_node: FuncAtMut<'_, Node>) { // HACK(eddyb) this relies on the fact that `NodeKind::Block` maps // to one original SPIR-V block, which may not necessarily be true, and // steps should be taken elsewhere to explicitly unset debuginfo, instead @@ -67,9 +225,14 @@ impl Transformer for CustomDebuginfoToSpv<'_> { // NOTE(eddyb) allowing debuginfo to apply *outside* of a `Block` could // be useful in allowing *some* structured control-flow to have debuginfo, // but that would likely require more work on the SPIR-T side. - if let NodeKind::Block { mut insts } = func_at_node.reborrow().def().kind { - let mut current_file_line_col = None; + let mut dbg_src_loc = None; + + // HACK(eddyb) only needed becasue `dbg_src_loc` can be `None`, but when + // `dbg_src_loc` is `Some`, its `inlined_callee_name_and_call_site` field + // must have the same value as this variable. + let mut inlined_callee_name_and_call_site = None; + if let NodeKind::Block { mut insts } = func_at_node.reborrow().def().kind { // HACK(eddyb) buffering the `DataInst`s to remove from this block, // as iterating and modifying a list at the same time isn't supported. let mut insts_to_remove = SmallVec::<[_; 8]>::new(); @@ -80,58 +243,116 @@ impl Transformer for CustomDebuginfoToSpv<'_> { let data_inst_def = func_at_inst.def(); // FIXME(eddyb) deduplicate with `spirt_passes::diagnostics`. - if let DataInstKind::SpvExtInst { - ext_set, - inst: ext_inst, - } = self.cx[data_inst_def.form].kind - && ext_set == self.custom_ext_inst_set - { - let custom_op = CustomOp::decode(ext_inst); - match custom_op.with_operands(&data_inst_def.inputs) { + let maybe_custom_inst = match self.cx[data_inst_def.form].kind { + DataInstKind::SpvExtInst { + ext_set, + inst: ext_inst, + } if ext_set == self.custom_ext_inst_set => { + Some(CustomOp::decode(ext_inst).with_operands(&data_inst_def.inputs)) + } + _ => None, + }; + if let Some(custom_inst) = maybe_custom_inst { + let mut mark_for_removal = || insts_to_remove.push(inst); + let expect_const = |v| match v { + Value::Const(ct) => ct, + _ => unreachable!(), + }; + let const_str = |v| match self.cx[expect_const(v)].kind { + ConstKind::SpvStringLiteralForExtInst(s) => s, + _ => unreachable!(), + }; + let const_u32 = |v| match &self.cx[expect_const(v)].kind { + ConstKind::SpvInst { + spv_inst_and_const_inputs, + } => { + let (spv_inst, _const_inputs) = &**spv_inst_and_const_inputs; + assert!(spv_inst.opcode == self.wk.OpConstant); + match spv_inst.imms[..] { + [spv::Imm::Short(_, x)] => x, + _ => unreachable!(), + } + } + _ => unreachable!(), + }; + match custom_inst { CustomInst::SetDebugSrcLoc { file, - line_start: line, - line_end: _, - col_start: col, - col_end: _, + line_start, + line_end, + col_start, + col_end, } => { - let const_kind = |v: Value| match v { - Value::Const(ct) => &self.cx[ct].kind, - _ => unreachable!(), - }; - let const_str = |v: Value| match const_kind(v) { - &ConstKind::SpvStringLiteralForExtInst(s) => s, - _ => unreachable!(), - }; - let const_u32 = |v: Value| match const_kind(v) { - ConstKind::SpvInst { - spv_inst_and_const_inputs, - } => { - let (spv_inst, _const_inputs) = &**spv_inst_and_const_inputs; - assert!(spv_inst.opcode == self.wk.OpConstant); - match spv_inst.imms[..] { - [spv::Imm::Short(_, x)] => x, - _ => unreachable!(), - } - } - _ => unreachable!(), - }; - current_file_line_col = - Some((const_str(file), const_u32(line), const_u32(col))); - insts_to_remove.push(inst); + dbg_src_loc = Some(DbgSrcLoc { + file_path: const_str(file), + start_line_col: (const_u32(line_start), const_u32(col_start)), + end_line_col: (const_u32(line_end), const_u32(col_end)), + inlined_callee_name_and_call_site, + }); + mark_for_removal(); continue; } CustomInst::ClearDebugSrcLoc => { - current_file_line_col = None; - insts_to_remove.push(inst); + dbg_src_loc = None; + mark_for_removal(); continue; } - CustomInst::PushInlinedCallFrame { .. } - | CustomInst::PopInlinedCallFrame => { - insts_to_remove.push(inst); + CustomInst::PushInlinedCallFrame { callee_name } => { + let mut call_site_attrs = AttrSet::default(); + let mut call_site_loc = dbg_src_loc.take(); + + // HACK(eddyb) this accounts for the same situation + // described later below (missing `SetDebugSrcLoc`), + // but between consecutive `PushInlinedCallFrame`s. + if inlined_callee_name_and_call_site.is_some() { + call_site_loc + .get_or_insert_with(|| DbgSrcLoc { + file_path: self.cx.intern(""), + start_line_col: (0, 0), + end_line_col: (0, 0), + inlined_callee_name_and_call_site: None, + }) + .inlined_callee_name_and_call_site = + inlined_callee_name_and_call_site; + } + + if let Some(call_site_loc) = call_site_loc { + call_site_attrs.set_dbg_src_loc(self.cx, call_site_loc); + } + inlined_callee_name_and_call_site = + Some((const_str(callee_name), call_site_attrs)); + + // HACK(eddyb) work around missing `SetDebugSrcLoc` + // in the callee, by continuing to use the callsite + // for anything in the callee before `SetDebugSrcLoc`. + dbg_src_loc = call_site_loc; + + mark_for_removal(); continue; } + CustomInst::PopInlinedCallFrame => { + if let Some((_, call_site_attrs)) = inlined_callee_name_and_call_site { + let call_site_loc = call_site_attrs.dbg_src_loc(self.cx); + (dbg_src_loc, inlined_callee_name_and_call_site) = ( + call_site_loc, + call_site_loc.and_then(|call_site_loc| { + call_site_loc.inlined_callee_name_and_call_site + }), + ); + mark_for_removal(); + continue; + } else { + data_inst_def.attrs.push_diag( + self.cx, + Diag::bug([ + "`PopInlinedCallFrame` without matching `PushInlinedCallFrame`" + .into() + ]), + ); + } + } CustomInst::Abort { .. } => { + let custom_op = custom_inst.op(); assert!( !custom_op.is_debuginfo(), "`CustomOp::{custom_op:?}` debuginfo not lowered" @@ -140,23 +361,12 @@ impl Transformer for CustomDebuginfoToSpv<'_> { } } - // Add/remove the equivalent `Attr::SpvDebugLine` attribute. - // FIXME(eddyb) this could use more caching. - data_inst_def.attrs = self.cx.intern(AttrSetDef { - attrs: self.cx[data_inst_def.attrs] - .attrs - .iter() - .filter(|attr| !matches!(attr, Attr::SpvDebugLine { .. })) - .cloned() - .chain( - current_file_line_col.map(|(file, line, col)| Attr::SpvDebugLine { - file_path: OrdAssertEq(file), - line, - col, - }), - ) - .collect(), - }); + let attrs = &mut data_inst_def.attrs; + + // Set the equivalent `Attr::DbgSrcLoc` attribute. + if let Some(dbg_src_loc) = dbg_src_loc { + attrs.set_dbg_src_loc(self.cx, dbg_src_loc); + } } // Finally remove the `DataInst`s buffered for removal earlier. diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs index 4eedf531ac3..71ba6989369 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs @@ -1,20 +1,14 @@ -use crate::custom_decorations::{ - CustomDecoration, SpanRegenerator, SrcLocDecoration, ZombieDecoration, -}; -use crate::custom_insts::{self, CustomInst, CustomOp}; +use crate::custom_decorations::{SpanRegenerator, SrcLocDecoration}; use rustc_data_structures::fx::FxIndexSet; use rustc_errors::EmissionGuarantee; use rustc_session::Session; -use rustc_span::{DUMMY_SP, Span}; +use rustc_span::Span; use smallvec::SmallVec; -use spirt::func_at::FuncAt; use spirt::visit::{InnerVisit, Visitor}; use spirt::{ - Attr, AttrSet, AttrSetDef, Const, ConstKind, Context, DataInstDef, DataInstForm, DataInstKind, - Diag, DiagLevel, ExportKey, Exportee, Func, FuncDecl, GlobalVar, InternedStr, Module, Node, - NodeKind, Type, Value, spv, + Attr, AttrSet, Const, ConstKind, Context, DataInstDef, DataInstForm, DataInstKind, DbgSrcLoc, + Diag, DiagLevel, ExportKey, Exportee, Func, GlobalVar, InternedStr, Module, Type, spv, }; -use std::marker::PhantomData; use std::{mem, str}; pub(crate) struct ReportedDiagnostics { @@ -24,17 +18,14 @@ pub(crate) struct ReportedDiagnostics { pub(crate) fn report_diagnostics( sess: &Session, - linker_options: &crate::linker::Options, module: &Module, ) -> Result<(), ReportedDiagnostics> { let cx = &module.cx(); let mut reporter = DiagnosticReporter { sess, - linker_options, cx, - custom_ext_inst_set: cx.intern(&custom_insts::CUSTOM_EXT_INST_SET[..]), module, @@ -57,7 +48,6 @@ pub(crate) fn report_diagnostics( reporter.use_stack.push(UseOrigin::IntraFunc { func_attrs: func_decl.attrs, special_func: Some(SpecialFunc::Exported(export_key)), - last_debug_src_loc_inst: None, inst_attrs: AttrSet::default(), origin: IntraFuncUseOrigin::Other, }); @@ -81,78 +71,13 @@ pub(crate) fn report_diagnostics( }) } -// HACK(eddyb) version of `decorations::LazilyDecoded` that works for SPIR-T. -struct LazilyDecoded { - encoded: String, - _marker: PhantomData, -} - -impl LazilyDecoded { - fn decode<'a>(&'a self) -> D - where - D: CustomDecoration<'a>, - { - D::decode(&self.encoded) - } -} - -pub(super) fn decode_spv_lit_str_with(imms: &[spv::Imm], f: impl FnOnce(&str) -> R) -> R { - let wk = &super::SpvSpecWithExtras::get().well_known; - - // FIXME(eddyb) deduplicate with `spirt::spv::extract_literal_string`. - let words = imms.iter().enumerate().map(|(i, &imm)| match (i, imm) { - (0, spirt::spv::Imm::Short(k, w) | spirt::spv::Imm::LongStart(k, w)) - | (1.., spirt::spv::Imm::LongCont(k, w)) => { - assert_eq!(k, wk.LiteralString); - w - } - _ => unreachable!(), - }); - let bytes: SmallVec<[u8; 64]> = words - .flat_map(u32::to_le_bytes) - .take_while(|&byte| byte != 0) - .collect(); - - f(str::from_utf8(&bytes).expect("invalid UTF-8 in string literal")) -} - -fn try_decode_custom_decoration<'a, D: CustomDecoration<'a>>( - attrs_def: &AttrSetDef, -) -> Option> { - let wk = &super::SpvSpecWithExtras::get().well_known; - - attrs_def.attrs.iter().find_map(|attr| { - let spv_inst = match attr { - Attr::SpvAnnotation(spv_inst) if spv_inst.opcode == wk.OpDecorateString => spv_inst, - _ => return None, - }; - let str_imms = spv_inst - .imms - .strip_prefix(&[spv::Imm::Short(wk.Decoration, wk.UserTypeGOOGLE)])?; - - decode_spv_lit_str_with(str_imms, |prefixed_encoded| { - let encoded = prefixed_encoded.strip_prefix(D::ENCODING_PREFIX)?; - - Some(LazilyDecoded { - encoded: encoded.to_string(), - _marker: PhantomData, - }) - }) - }) -} - // FIXME(eddyb) this looks a lot like `ReachableUseCollector`, maybe some // automation should be built around "deep visitors" in general? struct DiagnosticReporter<'a> { sess: &'a Session, - linker_options: &'a crate::linker::Options, cx: &'a Context, - /// Interned name for our custom "extended instruction set" - /// (see `crate::custom_insts` for more details). - custom_ext_inst_set: InternedStr, - module: &'a Module, seen_attrs: FxIndexSet, @@ -176,10 +101,6 @@ enum UseOrigin<'a> { func_attrs: AttrSet, special_func: Option>, - /// Active debug "source location" instruction at the time of the use, if any - /// (only `CustomInst::SetDebugSrcLoc` is supported). - last_debug_src_loc_inst: Option<&'a DataInstDef>, - inst_attrs: AttrSet, origin: IntraFuncUseOrigin, }, @@ -191,115 +112,60 @@ enum SpecialFunc<'a> { Exported(&'a ExportKey), /// This function doesn't have its own `FuncDecl`, but rather is an inlined - /// callee (i.e. instructions sandwiched by `{Push,Pop}InlinedCallFrame`). + /// callee (i.e. through `DbgSrcLoc`'s `inlined_callee_name_and_call_site`). Inlined { callee_name: InternedStr }, } +#[derive(Copy, Clone)] enum IntraFuncUseOrigin { CallCallee, Other, } impl SpanRegenerator<'_> { - fn spirt_attrs_to_rustc_span(&mut self, cx: &Context, attrs: AttrSet) -> Option { - let attrs_def = &cx[attrs]; - attrs_def - .attrs - .iter() - .find_map(|attr| match attr { - &Attr::SpvDebugLine { - file_path, - line, - col, - } => self.src_loc_to_rustc(SrcLocDecoration { - file_name: &cx[file_path.0], - line_start: line, - line_end: line, - col_start: col, - col_end: col, + fn dbg_src_loc_to_rustc_span_and_outer_scope<'a>( + &mut self, + cx: &Context, + dbg_src_loc: Option, + ) -> (Span, Option>) { + let (span, outer_scope) = match dbg_src_loc { + Some(DbgSrcLoc { + file_path, + start_line_col: (line_start, col_start), + end_line_col: (line_end, col_end), + inlined_callee_name_and_call_site, + }) => ( + self.src_loc_to_rustc(SrcLocDecoration { + file_name: &cx[file_path], + line_start, + col_start, + line_end, + col_end, }), - _ => None, - }) - .or_else(|| { - self.src_loc_to_rustc( - try_decode_custom_decoration::>(attrs_def)?.decode(), - ) - }) + inlined_callee_name_and_call_site.map(|(callee_name, call_site_attrs)| { + UseOrigin::IntraFunc { + func_attrs: AttrSet::default(), + special_func: Some(SpecialFunc::Inlined { callee_name }), + inst_attrs: call_site_attrs, + origin: IntraFuncUseOrigin::Other, + } + }), + ), + None => (None, None), + }; + (span.unwrap_or_default(), outer_scope) } } impl UseOrigin<'_> { - fn to_rustc_span(&self, cx: &Context, span_regen: &mut SpanRegenerator<'_>) -> Option { + fn dbg_src_loc(&self, cx: &Context) -> Option { match *self { - Self::Global { attrs, .. } => span_regen.spirt_attrs_to_rustc_span(cx, attrs), + Self::Global { attrs, .. } => attrs.dbg_src_loc(cx), Self::IntraFunc { func_attrs, - last_debug_src_loc_inst, inst_attrs, .. - } => span_regen - .spirt_attrs_to_rustc_span(cx, inst_attrs) - .or_else(|| { - let debug_inst_def = last_debug_src_loc_inst?; - - let wk = &super::SpvSpecWithExtras::get().well_known; - - // FIXME(eddyb) deduplicate with `spirt_passes::diagnostics`. - let custom_op = match cx[debug_inst_def.form].kind { - DataInstKind::SpvExtInst { - ext_set, - inst: ext_inst, - } => { - // FIXME(eddyb) inefficient (ideally the `InternedStr` - // should be available), but this is the error case. - assert_eq!(&cx[ext_set], &custom_insts::CUSTOM_EXT_INST_SET[..]); - - CustomOp::decode(ext_inst) - } - _ => unreachable!(), - }; - let (file, line_start, line_end, col_start, col_end) = - match custom_op.with_operands(&debug_inst_def.inputs) { - CustomInst::SetDebugSrcLoc { - file, - line_start, - line_end, - col_start, - col_end, - } => (file, line_start, line_end, col_start, col_end), - _ => unreachable!(), - }; - let const_kind = |v: Value| match v { - Value::Const(ct) => &cx[ct].kind, - _ => unreachable!(), - }; - let const_str = |v: Value| match const_kind(v) { - &ConstKind::SpvStringLiteralForExtInst(s) => s, - _ => unreachable!(), - }; - let const_u32 = |v: Value| match const_kind(v) { - ConstKind::SpvInst { - spv_inst_and_const_inputs, - } => { - let (spv_inst, _const_inputs) = &**spv_inst_and_const_inputs; - assert!(spv_inst.opcode == wk.OpConstant); - match spv_inst.imms[..] { - [spv::Imm::Short(_, x)] => x, - _ => unreachable!(), - } - } - _ => unreachable!(), - }; - - span_regen.src_loc_to_rustc(SrcLocDecoration { - file_name: &cx[const_str(file)], - line_start: const_u32(line_start), - line_end: const_u32(line_end), - col_start: const_u32(col_start), - col_end: const_u32(col_end), - }) - }) - .or_else(|| span_regen.spirt_attrs_to_rustc_span(cx, func_attrs)), + } => (inst_attrs.dbg_src_loc(cx)).or_else(|| func_attrs.dbg_src_loc(cx)), } } @@ -317,7 +183,7 @@ impl UseOrigin<'_> { .iter() .find_map(|attr| match attr { Attr::SpvAnnotation(spv_inst) if spv_inst.opcode == wk.OpName => { - Some(decode_spv_lit_str_with(&spv_inst.imms, |name| { + Some(super::decode_spv_lit_str_with(&spv_inst.imms, |name| { format!("`{name}`") })) } @@ -332,7 +198,6 @@ impl UseOrigin<'_> { Self::IntraFunc { func_attrs, special_func, - last_debug_src_loc_inst: _, inst_attrs: _, origin, } => { @@ -348,7 +213,7 @@ impl UseOrigin<'_> { assert_eq!(em_kind, wk.ExecutionModel); let em = spv::print::operand_from_imms([em]).concat_to_plain_text(); - decode_spv_lit_str_with(name_imms, |name| { + super::decode_spv_lit_str_with(name_imms, |name| { format!( "{} entry-point `{name}`", em.strip_prefix("ExecutionModel.").unwrap() @@ -371,17 +236,22 @@ impl UseOrigin<'_> { } }; - let span = self.to_rustc_span(cx, span_regen).unwrap_or(DUMMY_SP); + let (span, outer_scope) = + span_regen.dbg_src_loc_to_rustc_span_and_outer_scope(cx, self.dbg_src_loc(cx)); err.span_note(span, note); + if let Some(outer_scope) = outer_scope { + outer_scope.note(cx, span_regen, err); + } } } impl DiagnosticReporter<'_> { - fn report_from_attrs(&mut self, attrs: AttrSet) { - if attrs == AttrSet::default() { - return; - } - + fn diag_build_note_all_and_emit( + &mut self, + attrs: AttrSet, + f: impl FnOnce(rustc_errors::DiagCtxtHandle<'_>, Span) -> rustc_errors::Diag<'_, G>, + g: impl FnOnce(G::EmitResult) -> crate::linker::Result<()>, + ) { // Split off the last entry in `self.use_stack` if it's for the definition // that `attrs` come from - this should almost always be the case, except // for instructions inside a function body, or visitor bugs. @@ -404,36 +274,32 @@ impl DiagnosticReporter<'_> { (Some(current), stack) }); - let attrs_def = &self.cx[attrs]; - if !self.linker_options.early_report_zombies - && let Some(zombie) = try_decode_custom_decoration::>(attrs_def) - { - let ZombieDecoration { reason } = zombie.decode(); - let def_span = current_def - .and_then(|def| def.to_rustc_span(self.cx, &mut self.span_regen)) - .or_else(|| { - // If there's no clear source for the span, try to get - // it from the same attrs as the zombie, which could - // be missing from `use_stack` in some edge cases - // (such as zombied function parameters). - self.span_regen.spirt_attrs_to_rustc_span(self.cx, attrs) - }) - .unwrap_or(DUMMY_SP); - let mut err = self - .sess - .dcx() - .struct_span_err(def_span, reason.to_string()); - for use_origin in use_stack_for_def.iter().rev() { - use_origin.note(self.cx, &mut self.span_regen, &mut err); - } - self.overall_result = Err(err.emit()); + let (def_span, def_outer_scope) = + self.span_regen.dbg_src_loc_to_rustc_span_and_outer_scope( + self.cx, + current_def + .and_then(|def| def.dbg_src_loc(self.cx)) + .or_else(|| { + // If there's no clear source for the span, try to get + // it from the same attrs as the diagnostic, which could + // be missing from `use_stack` in some edge cases + // (e.g. function parameters). + attrs.dbg_src_loc(self.cx) + }), + ); + + let mut diag = f(self.sess.dcx(), def_span); + if let Some(def_outer_scope) = def_outer_scope { + def_outer_scope.note(self.cx, &mut self.span_regen, &mut diag); + } + for use_origin in use_stack_for_def.iter().rev() { + use_origin.note(self.cx, &mut self.span_regen, &mut diag); } + self.overall_result = self.overall_result.and(g(diag.emit())); + } - let diags = attrs_def.attrs.iter().flat_map(|attr| match attr { - Attr::Diagnostics(diags) => diags.0.iter(), - _ => [].iter(), - }); - for diag in diags { + fn report_from_attrs(&mut self, attrs: AttrSet) { + for diag in attrs.diags(self.cx) { let Diag { level, message } = diag; let prefix = match level { @@ -457,25 +323,18 @@ impl DiagnosticReporter<'_> { "".to_string() }; - let def_span = current_def - .and_then(|def| def.to_rustc_span(self.cx, &mut self.span_regen)) - .unwrap_or(DUMMY_SP); - let msg = [prefix, msg.to_string(), suffix].concat(); match level { - DiagLevel::Bug(_) | DiagLevel::Error => { - let mut err = self.sess.dcx().struct_span_err(def_span, msg); - for use_origin in use_stack_for_def.iter().rev() { - use_origin.note(self.cx, &mut self.span_regen, &mut err); - } - self.overall_result = Err(err.emit()); - } - DiagLevel::Warning => { - let mut warn = self.sess.dcx().struct_span_warn(def_span, msg); - for use_origin in use_stack_for_def.iter().rev() { - use_origin.note(self.cx, &mut self.span_regen, &mut warn); - } - } + DiagLevel::Bug(_) | DiagLevel::Error => self.diag_build_note_all_and_emit( + attrs, + |dcx, def_span| dcx.struct_span_err(def_span, msg), + Err, + ), + DiagLevel::Warning => self.diag_build_note_all_and_emit( + attrs, + |dcx, def_span| dcx.struct_span_warn(def_span, msg), + Ok, + ), } self.any_spirt_bugs = matches!(level, DiagLevel::Bug(_)); } @@ -544,7 +403,6 @@ impl<'a> Visitor<'a> for DiagnosticReporter<'a> { self.use_stack.push(UseOrigin::IntraFunc { func_attrs: func_decl.attrs, special_func: None, - last_debug_src_loc_inst: None, inst_attrs: AttrSet::default(), origin: IntraFuncUseOrigin::Other, }); @@ -553,58 +411,6 @@ impl<'a> Visitor<'a> for DiagnosticReporter<'a> { } } - fn visit_func_decl(&mut self, func_decl: &'a FuncDecl) { - // Intra-function the `use_stack` can gather extra entries, and there's - // a risk they'd pile up without being popped, so here's a sanity check. - let original_use_stack_len = self.use_stack.len(); - - func_decl.inner_visit_with(self); - - assert!(self.use_stack.len() >= original_use_stack_len); - let extra = self.use_stack.len() - original_use_stack_len; - if extra > 0 { - // HACK(eddyb) synthesize a diagnostic to report right away. - self.report_from_attrs( - AttrSet::default().append_diag( - self.cx, - Diag::bug([format!( - "{extra} extraneous `use_stack` frame(s) found \ - (missing `PopInlinedCallFrame`?)" - ) - .into()]), - ), - ); - } - self.use_stack.truncate(original_use_stack_len); - } - - fn visit_node_def(&mut self, func_at_node: FuncAt<'a, Node>) { - let original_use_stack_len = self.use_stack.len(); - - func_at_node.inner_visit_with(self); - - // HACK(eddyb) avoid `use_stack` from growing due to having some - // `PushInlinedCallFrame` without matching `PopInlinedCallFrame`. - self.use_stack.truncate(original_use_stack_len); - - // HACK(eddyb) this relies on the fact that `NodeKind::Block` maps - // to one original SPIR-V block, which may not necessarily be true, and - // steps should be taken elsewhere to explicitly unset debuginfo, instead - // of relying on the end of a SPIR-V block implicitly unsetting it all. - // NOTE(eddyb) allowing debuginfo to apply *outside* of a `Block` could - // be useful in allowing *some* structured control-flow to have debuginfo, - // but that would likely require more work on the SPIR-T side. - if let NodeKind::Block { .. } = func_at_node.def().kind { - match self.use_stack.last_mut() { - Some(UseOrigin::IntraFunc { - last_debug_src_loc_inst, - .. - }) => *last_debug_src_loc_inst = None, - _ => unreachable!(), - } - } - } - fn visit_data_inst_def(&mut self, data_inst_def: &'a DataInstDef) { let replace_origin = |this: &mut Self, new_origin| match this.use_stack.last_mut() { Some(UseOrigin::IntraFunc { origin, .. }) => mem::replace(origin, new_origin), @@ -612,82 +418,8 @@ impl<'a> Visitor<'a> for DiagnosticReporter<'a> { }; match self.use_stack.last_mut() { - Some(UseOrigin::IntraFunc { - inst_attrs, - last_debug_src_loc_inst, - .. - }) => { + Some(UseOrigin::IntraFunc { inst_attrs, .. }) => { *inst_attrs = data_inst_def.attrs; - - // FIXME(eddyb) deduplicate with `spirt_passes::debuginfo`. - if let DataInstKind::SpvExtInst { - ext_set, - inst: ext_inst, - } = self.cx[data_inst_def.form].kind - && ext_set == self.custom_ext_inst_set - { - match CustomOp::decode(ext_inst) { - CustomOp::SetDebugSrcLoc => { - *last_debug_src_loc_inst = Some(data_inst_def); - } - CustomOp::ClearDebugSrcLoc => { - *last_debug_src_loc_inst = None; - } - op => match op.with_operands(&data_inst_def.inputs) { - CustomInst::SetDebugSrcLoc { .. } | CustomInst::ClearDebugSrcLoc => { - unreachable!() - } - CustomInst::PushInlinedCallFrame { callee_name } => { - // Treat this like a call, in the caller. - replace_origin(self, IntraFuncUseOrigin::CallCallee); - - let const_kind = |v: Value| match v { - Value::Const(ct) => &self.cx[ct].kind, - _ => unreachable!(), - }; - let const_str = |v: Value| match const_kind(v) { - &ConstKind::SpvStringLiteralForExtInst(s) => s, - _ => unreachable!(), - }; - self.use_stack.push(UseOrigin::IntraFunc { - func_attrs: AttrSet::default(), - special_func: Some(SpecialFunc::Inlined { - callee_name: const_str(callee_name), - }), - last_debug_src_loc_inst: None, - inst_attrs: AttrSet::default(), - origin: IntraFuncUseOrigin::Other, - }); - } - CustomInst::PopInlinedCallFrame => { - match self.use_stack.last() { - Some(UseOrigin::IntraFunc { special_func, .. }) => { - if let Some(SpecialFunc::Inlined { .. }) = special_func { - self.use_stack.pop().unwrap(); - // Undo what `PushInlinedCallFrame` did to the - // original `UseOrigin::IntraFunc`. - replace_origin(self, IntraFuncUseOrigin::Other); - } else { - // HACK(eddyb) synthesize a diagnostic to report right away. - self.report_from_attrs( - AttrSet::default().append_diag( - self.cx, - Diag::bug([ - "`PopInlinedCallFrame` without an \ - inlined call frame in `use_stack`" - .into(), - ]), - ), - ); - } - } - _ => unreachable!(), - } - } - CustomInst::Abort { .. } => {} - }, - } - } } _ => unreachable!(), } diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs index 5e771738c7f..3a59ad462bb 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs @@ -10,6 +10,7 @@ pub(crate) mod validate; use lazy_static::lazy_static; use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; +use smallvec::SmallVec; use spirt::func_at::FuncAt; use spirt::transform::InnerInPlaceTransform; use spirt::visit::{InnerVisit, Visitor}; @@ -19,7 +20,7 @@ use spirt::{ Value, spv, }; use std::collections::VecDeque; -use std::iter; +use std::{iter, str}; // HACK(eddyb) `spv::spec::Spec` with extra `WellKnown`s (that should be upstreamed). macro_rules! def_spv_spec_with_extra_well_known { @@ -204,6 +205,26 @@ pub(super) fn run_func_passes

( } } +fn decode_spv_lit_str_with(imms: &[spv::Imm], f: impl FnOnce(&str) -> R) -> R { + let wk = &SpvSpecWithExtras::get().well_known; + + // FIXME(eddyb) deduplicate with `spirt::spv::extract_literal_string`. + let words = imms.iter().enumerate().map(|(i, &imm)| match (i, imm) { + (0, spirt::spv::Imm::Short(k, w) | spirt::spv::Imm::LongStart(k, w)) + | (1.., spirt::spv::Imm::LongCont(k, w)) => { + assert_eq!(k, wk.LiteralString); + w + } + _ => unreachable!(), + }); + let bytes: SmallVec<[u8; 64]> = words + .flat_map(u32::to_le_bytes) + .take_while(|&byte| byte != 0) + .collect(); + + f(str::from_utf8(&bytes).expect("invalid UTF-8 in string literal")) +} + // FIXME(eddyb) this is just copy-pasted from `spirt` and should be reusable. struct ReachableUseCollector<'a> { cx: &'a Context, diff --git a/docs/src/codegen-args.md b/docs/src/codegen-args.md index 687baf0cf09..f8d50dee8ea 100644 --- a/docs/src/codegen-args.md +++ b/docs/src/codegen-args.md @@ -183,15 +183,6 @@ Dump the `SPIR-🇹` module, similar to `--dump-spirt-passes`, but only the fina Mutually exclusive with `--dump-spirt-passes` (which takes precedence over this). -### `--spirt-strip-custom-debuginfo-from-dumps` - -When dumping (pretty-printed) `SPIR-🇹` (e.g. with `--dump-spirt-passes`), strip -all the custom (Rust-GPU-specific) debuginfo instructions, by converting them -to the standard SPIR-V debuginfo (which `SPIR-🇹` understands more directly). - -The default (keeping the custom instructions) is more verbose, but also lossless, -if you want to see all instructions exactly as e.g. `--spirt-passes` see them. - ### `--spirt-keep-debug-sources-in-dumps` When dumping (pretty-printed) `SPIR-🇹` (e.g. with `--dump-spirt-passes`), preserve diff --git a/tests/compiletests/ui/dis/asm_op_decorate.stderr b/tests/compiletests/ui/dis/asm_op_decorate.stderr index 1029fbd7baa..b20c349ab18 100644 --- a/tests/compiletests/ui/dis/asm_op_decorate.stderr +++ b/tests/compiletests/ui/dis/asm_op_decorate.stderr @@ -20,3 +20,5 @@ %5 = OpVariable %_ptr_UniformConstant__runtimearr_10 UniformConstant %u32 = OpTypeInt 32 0 %u32_1 = OpConstant %u32 1 + OpLine %2 54 7 + OpLine %2 27 3 diff --git a/tests/compiletests/ui/dis/custom_entry_point.stderr b/tests/compiletests/ui/dis/custom_entry_point.stderr index 284be7c69e0..cb79117947e 100644 --- a/tests/compiletests/ui/dis/custom_entry_point.stderr +++ b/tests/compiletests/ui/dis/custom_entry_point.stderr @@ -6,3 +6,4 @@ OpName %custom_entry_point__main "custom_entry_point::main" %void = OpTypeVoid %5 = OpTypeFunction %void + OpLine %2 16 7 diff --git a/tests/compiletests/ui/dis/generic-fn-op-name.stderr b/tests/compiletests/ui/dis/generic-fn-op-name.stderr index 2968741b54a..7c6df373ec7 100644 --- a/tests/compiletests/ui/dis/generic-fn-op-name.stderr +++ b/tests/compiletests/ui/dis/generic-fn-op-name.stderr @@ -7,3 +7,5 @@ OpName %generic_fn_op_name__generic___f32___generic_fn_op_name__Dimensionality__TwoD__ "generic_fn_op_name::generic::" %void = OpTypeVoid %6 = OpTypeFunction %void + OpLine %2 34 7 + OpLine %2 31 3 diff --git a/tests/compiletests/ui/dis/issue-590-multiple-entry-points.stderr b/tests/compiletests/ui/dis/issue-590-multiple-entry-points.stderr index 92dfce8fe43..c9b6fd6823d 100644 --- a/tests/compiletests/ui/dis/issue-590-multiple-entry-points.stderr +++ b/tests/compiletests/ui/dis/issue-590-multiple-entry-points.stderr @@ -23,3 +23,6 @@ %i32 = OpTypeInt 32 1 %_ptr_Input_i32 = OpTypePointer Input %i32 %_v = OpVariable %_ptr_Input_i32 Input + OpLine %6 24 7 + OpLine %6 21 7 + OpLine %6 18 7 diff --git a/tests/compiletests/ui/dis/issue-615.stderr b/tests/compiletests/ui/dis/issue-615.stderr index 6ada78eacd7..46343cec998 100644 --- a/tests/compiletests/ui/dis/issue-615.stderr +++ b/tests/compiletests/ui/dis/issue-615.stderr @@ -42,3 +42,5 @@ %26 = OpTypeFunction %u32 %_ptr_Function_Tri %27 = OpUndef %u32 %out = OpVariable %_ptr_Output_u32 Output + OpLine %5 42 3 + OpLine %5 50 3 diff --git a/tests/compiletests/ui/dis/issue-723-output.stderr b/tests/compiletests/ui/dis/issue-723-output.stderr index d123b74ea50..b72f2edb6b4 100644 --- a/tests/compiletests/ui/dis/issue-723-output.stderr +++ b/tests/compiletests/ui/dis/issue-723-output.stderr @@ -6,3 +6,4 @@ OpName %issue_723_output__main "issue_723_output::main" %void = OpTypeVoid %5 = OpTypeFunction %void + OpLine %2 28 7 From 1eabd15ab09bcdcd44582b094e0f520d8f59eee2 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 9 Sep 2025 11:40:02 +0300 Subject: [PATCH 4/8] Update `spirt` for `DataInstForm` "uninterning". --- Cargo.lock | 2 +- crates/rustc_codegen_spirv/Cargo.toml | 3 +- .../src/linker/spirt_passes/controlflow.rs | 23 ++-- .../src/linker/spirt_passes/debuginfo.rs | 23 +--- .../src/linker/spirt_passes/diagnostics.rs | 11 +- .../linker/spirt_passes/explicit_layout.rs | 103 ++++++------------ .../src/linker/spirt_passes/mod.rs | 32 ++---- .../src/linker/spirt_passes/reduce.rs | 39 +++---- .../src/linker/spirt_passes/validate.rs | 22 +--- .../ui/arch/non_uniform/buffer.stderr | 4 +- .../ui/arch/non_uniform/buffer_uniform.stderr | 4 +- .../byte_addressable_buffer.stderr | 2 +- .../byte_addressable_buffer_uniform.stderr | 2 +- .../ui/arch/non_uniform/image.stderr | 4 +- .../ui/arch/non_uniform/image_uniform.stderr | 4 +- .../ui/arch/non_uniform/storage_image.stderr | 4 +- .../non_uniform/storage_image_uniform.stderr | 4 +- .../ui/arch/shared/dce_shared.stderr | 2 +- .../ui/dis/asm_op_decorate.stderr | 2 +- .../ui/dis/const-narrowing-cast.stderr | 2 +- tests/compiletests/ui/dis/issue-615.stderr | 4 +- .../ui/dis/non-writable-storage_buffer.stderr | 2 +- .../ui/dis/panic_builtin_bounds_check.stderr | 4 +- .../ui/dis/panic_sequential_many.stderr | 2 +- .../compiletests/ui/dis/scalars.nocaps.stderr | 9 ++ .../ui/dis/spec_constant_array.stderr | 2 +- .../ui/entry/asm/entry2_global_asm.stderr | 2 +- .../ui/entry/asm/entry2_reference.stderr | 2 +- .../ui/entry/asm/entry3_generic_asm.stderr | 2 +- .../ui/entry/asm/entry3_global_asm.stderr | 2 +- .../ui/entry/asm/entry3_reference.stderr | 2 +- tests/compiletests/ui/image/write_comp.stderr | 2 +- .../ui/image/write_comp_format.stderr | 2 +- .../explicit_overlap.stderr | 2 +- .../location_assignment/explict.stderr | 2 +- .../many_f32_struct.stderr | 2 +- .../location_assignment/mesh_shader.stderr | 10 +- .../location_assignment/struct.stderr | 2 +- .../location_assignment/vec3_f32.stderr | 2 +- 39 files changed, 128 insertions(+), 221 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 135d2179db0..43a5ff82440 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5795,7 +5795,7 @@ dependencies = [ [[package]] name = "spirt" version = "0.4.0" -source = "git+https://github.com/Rust-GPU/spirt?rev=000ec78a#000ec78a7ec7ae213d9e21be64aefdf12fe8d4c1" +source = "git+https://github.com/Rust-GPU/spirt?rev=5c426149#5c4261490c6510cb755fc444a76a5c4d5e06705d" dependencies = [ "arrayvec", "bytemuck", diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index a3609887733..b42d173d82e 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -59,7 +59,8 @@ smallvec = { version = "1.6.1", features = ["const_generics", "const_new", "unio # - https://github.com/Rust-GPU/spirt/pull/7 # - https://github.com/Rust-GPU/spirt/pull/8 # - https://github.com/Rust-GPU/spirt/pull/9 -spirt = { git = "https://github.com/Rust-GPU/spirt", rev = "000ec78a" } +# - https://github.com/Rust-GPU/spirt/pull/12 +spirt = { git = "https://github.com/Rust-GPU/spirt", rev = "5c426149" } spirv-tools.workspace = true lazy_static = "1.4.0" itertools = "0.14.0" diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs index d444cb0c886..1bc70de9c11 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs @@ -4,9 +4,8 @@ use crate::custom_insts::{self, CustomInst, CustomOp}; use smallvec::SmallVec; use spirt::func_at::FuncAt; use spirt::{ - Attr, AttrSet, ConstDef, ConstKind, DataInstFormDef, DataInstKind, DbgSrcLoc, DeclDef, - EntityDefs, ExportKey, Exportee, Module, NodeKind, Type, TypeDef, TypeKind, TypeOrConst, Value, - cfg, spv, + Attr, AttrSet, ConstDef, ConstKind, DataInstKind, DbgSrcLoc, DeclDef, EntityDefs, ExportKey, + Exportee, Module, NodeKind, Type, TypeDef, TypeKind, TypeOrConst, Value, cfg, spv, }; use std::fmt::Write as _; @@ -113,8 +112,7 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( .into_iter() .filter_map(|func_at_inst| { let data_inst_def = func_at_inst.def(); - let data_inst_form_def = &cx[data_inst_def.form]; - if let DataInstKind::SpvInst(spv_inst) = &data_inst_form_def.kind + if let DataInstKind::SpvInst(spv_inst) = &data_inst_def.kind && spv_inst.opcode == wk.OpLoad && let Value::Const(ct) = data_inst_def.inputs[0] && let ConstKind::PtrToGlobalVar(gv) = cx[ct].kind @@ -122,7 +120,7 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( { return Some(( gv, - data_inst_form_def.output_type.unwrap(), + data_inst_def.output_type.unwrap(), Value::DataInstOutput(func_at_inst.position), )); } @@ -229,7 +227,7 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( .next_back() .and_then(|func_at_inst| { let data_inst_def = func_at_inst.def(); - match cx[data_inst_def.form].kind { + match data_inst_def.kind { DataInstKind::SpvExtInst { ext_set, inst } if ext_set == custom_ext_inst_set => { @@ -367,13 +365,10 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( fmt += "\n"; let abort_inst_def = &mut func_def_body.data_insts[abort_inst]; - abort_inst_def.form = cx.intern(DataInstFormDef { - kind: DataInstKind::SpvExtInst { - ext_set: cx.intern("NonSemantic.DebugPrintf"), - inst: 1, - }, - output_type: cx[abort_inst_def.form].output_type, - }); + abort_inst_def.kind = DataInstKind::SpvExtInst { + ext_set: cx.intern("NonSemantic.DebugPrintf"), + inst: 1, + }; abort_inst_def.inputs = [Value::Const(mk_const_str(cx.intern(fmt)))] .into_iter() .chain(message_debug_printf_args.iter().copied()) diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs index aac58151f2f..0fb111f425b 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs @@ -9,8 +9,8 @@ use spirt::func_at::FuncAtMut; use spirt::transform::{InnerInPlaceTransform as _, Transformed, Transformer}; use spirt::visit::InnerVisit; use spirt::{ - Attr, AttrSet, AttrSetDef, Const, ConstKind, Context, DataInstForm, DataInstKind, DbgSrcLoc, - Diag, InternedStr, Module, Node, NodeKind, Type, Value, spv, + Attr, AttrSet, AttrSetDef, Const, ConstKind, Context, DataInstKind, DbgSrcLoc, Diag, + InternedStr, Module, Node, NodeKind, Type, Value, spv, }; use std::marker::PhantomData; use std::str; @@ -33,7 +33,6 @@ pub fn convert_custom_decorations_and_debuginfo_to_spirt( seen_types: FxIndexSet::default(), seen_consts: FxIndexSet::default(), - seen_data_inst_forms: FxIndexSet::default(), seen_global_vars: FxIndexSet::default(), seen_funcs: FxIndexSet::default(), }; @@ -51,7 +50,6 @@ pub fn convert_custom_decorations_and_debuginfo_to_spirt( custom_ext_inst_set: cx.intern(&custom_insts::CUSTOM_EXT_INST_SET[..]), transformed_types: FxHashMap::default(), transformed_consts: FxHashMap::default(), - transformed_data_inst_forms: FxHashMap::default(), }; for gv in all_global_vars { transformer.in_place_transform_global_var_decl(&mut module.global_vars[gv]); @@ -132,7 +130,6 @@ struct CustomDecorationsAndDebuginfoToSpirt<'a> { // FIXME(eddyb) build some automation to avoid ever repeating these. transformed_types: FxHashMap>, transformed_consts: FxHashMap>, - transformed_data_inst_forms: FxHashMap>, } impl Transformer for CustomDecorationsAndDebuginfoToSpirt<'_> { @@ -157,20 +154,6 @@ impl Transformer for CustomDecorationsAndDebuginfoToSpirt<'_> { self.transformed_consts.insert(ct, transformed); transformed } - fn transform_data_inst_form_use( - &mut self, - data_inst_form: DataInstForm, - ) -> Transformed { - if let Some(&cached) = self.transformed_data_inst_forms.get(&data_inst_form) { - return cached; - } - let transformed = self - .transform_data_inst_form_def(&self.cx[data_inst_form]) - .map(|data_inst_form_def| self.cx.intern(data_inst_form_def)); - self.transformed_data_inst_forms - .insert(data_inst_form, transformed); - transformed - } fn transform_attr_set_use(&mut self, attrs: AttrSet) -> Transformed { let orig_attrs = attrs; @@ -243,7 +226,7 @@ impl Transformer for CustomDecorationsAndDebuginfoToSpirt<'_> { let data_inst_def = func_at_inst.def(); // FIXME(eddyb) deduplicate with `spirt_passes::diagnostics`. - let maybe_custom_inst = match self.cx[data_inst_def.form].kind { + let maybe_custom_inst = match data_inst_def.kind { DataInstKind::SpvExtInst { ext_set, inst: ext_inst, diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs index 71ba6989369..edc46c05d02 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs @@ -6,8 +6,8 @@ use rustc_span::Span; use smallvec::SmallVec; use spirt::visit::{InnerVisit, Visitor}; use spirt::{ - Attr, AttrSet, Const, ConstKind, Context, DataInstDef, DataInstForm, DataInstKind, DbgSrcLoc, - Diag, DiagLevel, ExportKey, Exportee, Func, GlobalVar, InternedStr, Module, Type, spv, + Attr, AttrSet, Const, ConstKind, Context, DataInstDef, DataInstKind, DbgSrcLoc, Diag, + DiagLevel, ExportKey, Exportee, Func, GlobalVar, InternedStr, Module, Type, spv, }; use std::{mem, str}; @@ -378,11 +378,6 @@ impl<'a> Visitor<'a> for DiagnosticReporter<'a> { } } } - fn visit_data_inst_form_use(&mut self, data_inst_form: DataInstForm) { - // NOTE(eddyb) this contains no deduplication because each `DataInstDef` - // will have any diagnostics reported separately. - self.visit_data_inst_form_def(&self.cx[data_inst_form]); - } fn visit_global_var_use(&mut self, gv: GlobalVar) { if self.seen_global_vars.insert(gv) { @@ -424,7 +419,7 @@ impl<'a> Visitor<'a> for DiagnosticReporter<'a> { _ => unreachable!(), } - if let DataInstKind::FuncCall(func) = self.cx[data_inst_def.form].kind { + if let DataInstKind::FuncCall(func) = data_inst_def.kind { // HACK(eddyb) visit `func` early, to control its `use_stack`, with // the later visit from `inner_visit_with` ignored as a duplicate. let old_origin = replace_origin(self, IntraFuncUseOrigin::CallCallee); diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs index ef026de027f..f4d58edfdc0 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs @@ -8,9 +8,9 @@ use spirt::func_at::{FuncAt, FuncAtMut}; use spirt::transform::{InnerInPlaceTransform, InnerTransform, Transformed, Transformer}; use spirt::visit::InnerVisit as _; use spirt::{ - AddrSpace, Attr, AttrSetDef, Const, ConstKind, Context, DataInst, DataInstDef, DataInstForm, - DataInstFormDef, DataInstKind, DeclDef, Diag, Func, FuncDecl, GlobalVar, GlobalVarDecl, Module, - Node, NodeKind, Type, TypeDef, TypeKind, TypeOrConst, Value, spv, + AddrSpace, Attr, AttrSetDef, Const, ConstKind, Context, DataInst, DataInstDef, DataInstKind, + DeclDef, Diag, Func, FuncDecl, GlobalVar, GlobalVarDecl, Module, Node, NodeKind, Type, TypeDef, + TypeKind, TypeOrConst, Value, spv, }; use std::cmp::Ordering; use std::collections::VecDeque; @@ -29,7 +29,6 @@ pub fn erase_when_invalid(module: &mut Module) { transformed_types: FxHashMap::default(), transformed_consts: FxHashMap::default(), - transformed_data_inst_forms: FxHashMap::default(), seen_global_vars: FxHashSet::default(), global_var_queue: VecDeque::new(), seen_funcs: FxHashSet::default(), @@ -62,7 +61,6 @@ struct SelectiveEraser<'a> { // FIXME(eddyb) build some automation to avoid ever repeating these. transformed_types: FxHashMap>, transformed_consts: FxHashMap>, - transformed_data_inst_forms: FxHashMap>, seen_global_vars: FxHashSet, global_var_queue: VecDeque, seen_funcs: FxHashSet, @@ -101,20 +99,6 @@ impl Transformer for SelectiveEraser<'_> { self.transformed_consts.insert(ct, transformed); transformed } - fn transform_data_inst_form_use( - &mut self, - data_inst_form: DataInstForm, - ) -> Transformed { - if let Some(&cached) = self.transformed_data_inst_forms.get(&data_inst_form) { - return cached; - } - let transformed = self - .transform_data_inst_form_def(&self.cx[data_inst_form]) - .map(|data_inst_form_def| self.cx.intern(data_inst_form_def)); - self.transformed_data_inst_forms - .insert(data_inst_form, transformed); - transformed - } fn transform_global_var_use(&mut self, gv: GlobalVar) -> Transformed { if self.seen_global_vars.insert(gv) { @@ -216,7 +200,6 @@ impl Transformer for SelectiveEraser<'_> { let func_at_data_inst_frozen = func_at_data_inst.reborrow().freeze(); let data_inst = func_at_data_inst_frozen.position; let data_inst_def = func_at_data_inst_frozen.def(); - let data_inst_form_def = &cx[data_inst_def.form]; let func = func_at_data_inst_frozen.at(()); let type_of_val = |v: Value| func.at(v).type_of(cx); let pointee_type_of_ptr_val = |p: Value| match &cx[type_of_val(p)].kind { @@ -230,7 +213,7 @@ impl Transformer for SelectiveEraser<'_> { _ => None, }; - let DataInstKind::SpvInst(spv_inst) = &data_inst_form_def.kind else { + let DataInstKind::SpvInst(spv_inst) = &data_inst_def.kind else { return; }; @@ -240,16 +223,14 @@ impl Transformer for SelectiveEraser<'_> { let mk_bitcast_def = |in_value, out_type| DataInstDef { attrs, - form: cx.intern(DataInstFormDef { - kind: DataInstKind::SpvInst(wk.OpBitcast.into()), - output_type: Some(out_type), - }), + kind: DataInstKind::SpvInst(wk.OpBitcast.into()), inputs: [in_value].into_iter().collect(), + output_type: Some(out_type), }; if spv_inst.opcode == wk.OpLoad { let pointee_type = pointee_type_of_ptr_val(data_inst_def.inputs[0]); - let value_type = data_inst_form_def.output_type.unwrap(); + let value_type = data_inst_def.output_type.unwrap(); // FIXME(eddyb) leave a BUG diagnostic in the `None` case? if pointee_type.is_some_and(|ty| { ty != value_type && ty == self.erase_explicit_layout_in_type(value_type) @@ -263,12 +244,8 @@ impl Transformer for SelectiveEraser<'_> { let fixed_load_inst = func.data_insts.define( cx, DataInstDef { - attrs, - form: cx.intern(DataInstFormDef { - kind: data_inst_form_def.kind.clone(), - output_type: Some(pointee_type.unwrap()), - }), - inputs: func.data_insts[data_inst].inputs.clone(), + output_type: Some(pointee_type.unwrap()), + ..DataInstDef::clone(&func.data_insts[data_inst]) } .into(), ); @@ -342,6 +319,9 @@ impl Transformer for SelectiveEraser<'_> { _ => unreachable!(), }; + let [dst_imms, src_imms] = + [dst_imms, src_imms].map(|imms| imms.iter().copied().collect()); + let func = func_at_data_inst.at(()); let NodeKind::Block { insts } = &mut func.nodes[self.parent_block.unwrap()].kind else { @@ -352,14 +332,12 @@ impl Transformer for SelectiveEraser<'_> { cx, DataInstDef { attrs, - form: cx.intern(DataInstFormDef { - kind: DataInstKind::SpvInst(spv::Inst { - opcode: wk.OpLoad, - imms: src_imms.iter().copied().collect(), - }), - output_type: Some(src_pointee_type.unwrap()), + kind: DataInstKind::SpvInst(spv::Inst { + opcode: wk.OpLoad, + imms: src_imms, }), inputs: [src_ptr].into_iter().collect(), + output_type: Some(src_pointee_type.unwrap()), } .into(), ); @@ -373,16 +351,14 @@ impl Transformer for SelectiveEraser<'_> { *func.data_insts[data_inst] = DataInstDef { attrs, - form: cx.intern(DataInstFormDef { - kind: DataInstKind::SpvInst(spv::Inst { - opcode: wk.OpStore, - imms: dst_imms.iter().copied().collect(), - }), - output_type: None, + kind: DataInstKind::SpvInst(spv::Inst { + opcode: wk.OpStore, + imms: dst_imms, }), inputs: [dst_ptr, Value::DataInstOutput(cast_inst)] .into_iter() .collect(), + output_type: None, }; self.disaggregate_bitcast(func.at(cast_inst)); @@ -475,15 +451,14 @@ impl<'a> SelectiveEraser<'a> { let cast_inst = func_at_cast_inst.position; let cast_def = func_at_cast_inst.reborrow().freeze().def().clone(); - let cast_form_def = &cx[cast_def.form]; // FIXME(eddyb) filter attributes into debuginfo and // semantic, and understand the semantic ones. let attrs = cast_def.attrs; - assert!(cast_form_def.kind == DataInstKind::SpvInst(wk.OpBitcast.into())); + assert!(cast_def.kind == DataInstKind::SpvInst(wk.OpBitcast.into())); let in_value = cast_def.inputs[0]; - let out_type = cast_form_def.output_type.unwrap(); + let out_type = cast_def.output_type.unwrap(); let mut func = func_at_cast_inst.reborrow(); let in_type = func.reborrow().freeze().at(in_value).type_of(cx); @@ -529,16 +504,14 @@ impl<'a> SelectiveEraser<'a> { cx, DataInstDef { attrs, - form: cx.intern(DataInstFormDef { - kind: DataInstKind::SpvInst(spv::Inst { - opcode: wk.OpCompositeExtract, - imms: [spv::Imm::Short(wk.LiteralInteger, component_idx)] - .into_iter() - .collect(), - }), - output_type: Some(component_in_type), + kind: DataInstKind::SpvInst(spv::Inst { + opcode: wk.OpCompositeExtract, + imms: [spv::Imm::Short(wk.LiteralInteger, component_idx)] + .into_iter() + .collect(), }), inputs: [in_value].into_iter().collect(), + output_type: Some(component_in_type), } .into(), ); @@ -554,13 +527,11 @@ impl<'a> SelectiveEraser<'a> { cx, DataInstDef { attrs, - form: cx.intern(DataInstFormDef { - kind: DataInstKind::SpvInst(wk.OpBitcast.into()), - output_type: Some(component_out_type), - }), + kind: DataInstKind::SpvInst(wk.OpBitcast.into()), inputs: [Value::DataInstOutput(component_extract_inst)] .into_iter() .collect(), + output_type: Some(component_out_type), } .into(), ); @@ -579,11 +550,9 @@ impl<'a> SelectiveEraser<'a> { *func.at(cast_inst).def() = DataInstDef { attrs, - form: cx.intern(DataInstFormDef { - kind: DataInstKind::SpvInst(wk.OpCompositeConstruct.into()), - output_type: Some(out_type), - }), + kind: DataInstKind::SpvInst(wk.OpCompositeConstruct.into()), inputs: components, + output_type: Some(out_type), }; } @@ -595,10 +564,9 @@ impl<'a> SelectiveEraser<'a> { let wk = self.wk; let data_inst_def = func_at_inst.def(); - let data_inst_form_def = &cx[data_inst_def.form]; // FIXME(eddyb) consider preserving the actual type change in the error. - let any_types_will_change = (data_inst_form_def.output_type.into_iter()) + let any_types_will_change = (data_inst_def.output_type.into_iter()) .chain( data_inst_def .inputs @@ -614,7 +582,7 @@ impl<'a> SelectiveEraser<'a> { return Ok(()); } - let spv_inst = match &data_inst_form_def.kind { + let spv_inst = match &data_inst_def.kind { DataInstKind::FuncCall(_) => return Ok(()), DataInstKind::SpvInst(spv_inst) @@ -769,9 +737,6 @@ impl Transformer for EraseExplicitLayout<'_, '_> { .insert(ct, transformed); transformed } - fn transform_data_inst_form_use(&mut self, _: DataInstForm) -> Transformed { - unreachable!() - } fn transform_global_var_use(&mut self, gv: GlobalVar) -> Transformed { self.0.transform_global_var_use(gv) diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs index 3a59ad462bb..715b8cb26e8 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/mod.rs @@ -15,9 +15,8 @@ use spirt::func_at::FuncAt; use spirt::transform::InnerInPlaceTransform; use spirt::visit::{InnerVisit, Visitor}; use spirt::{ - AttrSet, Const, Context, DataInstDef, DataInstForm, DataInstFormDef, DataInstKind, DeclDef, - EntityOrientedDenseMap, Func, FuncDefBody, GlobalVar, Module, Node, NodeKind, Region, Type, - Value, spv, + AttrSet, Const, Context, DataInstDef, DataInstKind, DeclDef, EntityOrientedDenseMap, Func, + FuncDefBody, GlobalVar, Module, Node, NodeKind, Region, Type, Value, spv, }; use std::collections::VecDeque; use std::{iter, str}; @@ -146,7 +145,6 @@ pub(super) fn run_func_passes

( seen_types: FxIndexSet::default(), seen_consts: FxIndexSet::default(), - seen_data_inst_forms: FxIndexSet::default(), seen_global_vars: FxIndexSet::default(), seen_funcs: FxIndexSet::default(), }; @@ -198,7 +196,7 @@ pub(super) fn run_func_passes

( pass_fn(cx, func_def_body); // FIXME(eddyb) avoid doing this except where changes occurred. - remove_unused_values_in_func(cx, func_def_body); + remove_unused_values_in_func(func_def_body); } } after_pass(Some(module), profiler); @@ -233,7 +231,6 @@ struct ReachableUseCollector<'a> { // FIXME(eddyb) build some automation to avoid ever repeating these. seen_types: FxIndexSet, seen_consts: FxIndexSet, - seen_data_inst_forms: FxIndexSet, seen_global_vars: FxIndexSet, seen_funcs: FxIndexSet, } @@ -251,11 +248,6 @@ impl Visitor<'_> for ReachableUseCollector<'_> { self.visit_const_def(&self.cx[ct]); } } - fn visit_data_inst_form_use(&mut self, data_inst_form: DataInstForm) { - if self.seen_data_inst_forms.insert(data_inst_form) { - self.visit_data_inst_form_def(&self.cx[data_inst_form]); - } - } fn visit_global_var_use(&mut self, gv: GlobalVar) { if self.seen_global_vars.insert(gv) { @@ -286,7 +278,6 @@ const _: () = { fn visit_attr_set_use(&mut self, _: AttrSet) {} fn visit_type_use(&mut self, _: Type) {} fn visit_const_use(&mut self, _: Const) {} - fn visit_data_inst_form_use(&mut self, _: DataInstForm) {} fn visit_global_var_use(&mut self, _: GlobalVar) {} fn visit_func_use(&mut self, _: Func) {} @@ -317,7 +308,7 @@ const _: () = { /// a function body (both `DataInst`s and `Region` inputs/outputs). // // FIXME(eddyb) should this be a dedicated pass? -fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { +fn remove_unused_values_in_func(func_def_body: &mut FuncDefBody) { // Avoid having to support unstructured control-flow. if func_def_body.unstructured_cfg.is_some() { return; @@ -430,9 +421,7 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { for func_at_inst in func_at_node.at(insts) { // Ignore pure instructions (i.e. they're only used // if their output value is used, from somewhere else). - if let DataInstKind::SpvInst(spv_inst) = - &cx[func_at_inst.def().form].kind - { + if let DataInstKind::SpvInst(spv_inst) = &func_at_inst.def().kind { // HACK(eddyb) small selection relevant for now, // but should be extended using e.g. a bitset. if [wk.OpNop, wk.OpCompositeInsert].contains(&spv_inst.opcode) { @@ -484,8 +473,7 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { let mut all_nops = true; let mut func_at_inst_iter = func_def_body.at_mut(insts).into_iter(); while let Some(mut func_at_inst) = func_at_inst_iter.next() { - if let DataInstKind::SpvInst(spv_inst) = - &cx[func_at_inst.reborrow().def().form].kind + if let DataInstKind::SpvInst(spv_inst) = &func_at_inst.reborrow().def().kind && spv_inst.opcode == wk.OpNop { continue; @@ -493,15 +481,11 @@ fn remove_unused_values_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { if !used_values.contains(&Value::DataInstOutput(func_at_inst.position)) { // Replace the removed `DataInstDef` itself with `OpNop`, // removing the ability to use its "name" as a value. - // - // FIXME(eddyb) cache the interned `OpNop`. *func_at_inst.def() = DataInstDef { attrs: Default::default(), - form: cx.intern(DataInstFormDef { - kind: DataInstKind::SpvInst(wk.OpNop.into()), - output_type: None, - }), + kind: DataInstKind::SpvInst(wk.OpNop.into()), inputs: iter::empty().collect(), + output_type: None, }; continue; } diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs index fb75ffe777d..65f88b07fa8 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/reduce.rs @@ -4,7 +4,7 @@ use spirt::func_at::{FuncAt, FuncAtMut}; use spirt::transform::InnerInPlaceTransform; use spirt::visit::InnerVisit; use spirt::{ - Const, ConstDef, ConstKind, Context, DataInst, DataInstDef, DataInstFormDef, DataInstKind, + Const, ConstDef, ConstKind, Context, DataInst, DataInstDef, DataInstKind, EntityOrientedDenseMap, FuncDefBody, Node, NodeDef, NodeKind, NodeOutputDecl, Region, RegionInputDecl, SelectionKind, Type, TypeDef, TypeKind, Value, spv, }; @@ -62,7 +62,7 @@ pub(crate) fn reduce_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { .. } => { for func_at_inst in func_at_node.at(insts) { - if let Ok(redu) = Reducible::try_from((cx, func_at_inst.def())) { + if let Ok(redu) = Reducible::try_from(func_at_inst.def()) { let redu_target = ReductionTarget::DataInst(func_at_inst.position); reduction_queue.push((redu_target, redu)); } @@ -204,15 +204,11 @@ pub(crate) fn reduce_in_func(cx: &Context, func_def_body: &mut FuncDefBody) { // Replace the reduced `DataInstDef` itself with `OpNop`, // removing the ability to use its "name" as a value. - // - // FIXME(eddyb) cache the interned `OpNop`. *func_def_body.at_mut(inst).def() = DataInstDef { attrs: Default::default(), - form: cx.intern(DataInstFormDef { - kind: DataInstKind::SpvInst(wk.OpNop.into()), - output_type: None, - }), + kind: DataInstKind::SpvInst(wk.OpNop.into()), inputs: iter::empty().collect(), + output_type: None, }; } @@ -492,14 +488,12 @@ impl Reducible { } } -// FIXME(eddyb) instead of taking a `&Context`, could `Reducible` hold a `DataInstForm`? -impl TryFrom<(&Context, &DataInstDef)> for Reducible { +impl TryFrom<&DataInstDef> for Reducible { type Error = (); - fn try_from((cx, inst_def): (&Context, &DataInstDef)) -> Result { - let inst_form_def = &cx[inst_def.form]; - if let DataInstKind::SpvInst(spv_inst) = &inst_form_def.kind { + fn try_from(inst_def: &DataInstDef) -> Result { + if let DataInstKind::SpvInst(spv_inst) = &inst_def.kind { let op = PureOp::try_from(spv_inst)?; - let output_type = inst_form_def.output_type.unwrap(); + let output_type = inst_def.output_type.unwrap(); if let [input] = inst_def.inputs[..] { return Ok(Self { op, @@ -514,7 +508,7 @@ impl TryFrom<(&Context, &DataInstDef)> for Reducible { impl Reducible { // HACK(eddyb) `IntToBool` is the only reason this can return `None`. - fn try_into_inst(self, cx: &Context) -> Option { + fn try_into_inst(self) -> Option { let Self { op, output_type, @@ -522,11 +516,9 @@ impl Reducible { } = self; Some(DataInstDef { attrs: Default::default(), - form: cx.intern(DataInstFormDef { - kind: DataInstKind::SpvInst(op.try_into().ok()?), - output_type: Some(output_type), - }), + kind: DataInstKind::SpvInst(op.try_into().ok()?), inputs: iter::once(input).collect(), + output_type: Some(output_type), }) } } @@ -642,11 +634,11 @@ enum ReductionStep { impl Reducible<&DataInstDef> { // FIXME(eddyb) force the input to actually be itself some kind of pure op. - fn try_reduce_output_of_data_inst(&self, cx: &Context) -> Option { + fn try_reduce_output_of_data_inst(&self, _cx: &Context) -> Option { let wk = &super::SpvSpecWithExtras::get().well_known; let input_inst_def = self.input; - if let DataInstKind::SpvInst(input_spv_inst) = &cx[input_inst_def.form].kind { + if let DataInstKind::SpvInst(input_spv_inst) = &input_inst_def.kind { // NOTE(eddyb) do not destroy information left in e.g. comments. #[allow(clippy::match_same_arms)] match self.op { @@ -755,9 +747,8 @@ impl Reducible { .try_reduce(cx, func.reborrow(), value_replacements, parent_map, cache)?; // HACK(eddyb) this is here because it can fail, see the comment // on `output_from_updated_state` for what's actually going on. - let output_from_updated_state_inst = self - .with_input(input_from_updated_state) - .try_into_inst(cx)?; + let output_from_updated_state_inst = + self.with_input(input_from_updated_state).try_into_inst()?; // Now that the reduction succeeded for the initial state, // we can proceed with augmenting the loop with the extra state. diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs index 8e54ed50d65..8b772f1be99 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs @@ -2,8 +2,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexSet}; use spirt::func_at::FuncAtMut; use spirt::transform::{InnerInPlaceTransform, InnerTransform, Transformed, Transformer}; use spirt::{ - Const, ConstDef, ConstKind, Context, DataInst, DataInstForm, DataInstKind, Diag, Func, - GlobalVar, Module, ModuleDialect, Type, TypeDef, TypeKind, spv, + Const, ConstDef, ConstKind, Context, DataInst, DataInstKind, Diag, Func, GlobalVar, Module, + ModuleDialect, Type, TypeDef, TypeKind, spv, }; use std::collections::VecDeque; @@ -25,7 +25,6 @@ pub fn validate(module: &mut Module) { transformed_types: FxHashMap::default(), transformed_consts: FxHashMap::default(), - transformed_data_inst_forms: FxHashMap::default(), seen_global_vars: FxHashSet::default(), global_var_queue: VecDeque::new(), seen_funcs: FxHashSet::default(), @@ -64,7 +63,6 @@ struct Validator<'a> { // FIXME(eddyb) build some automation to avoid ever repeating these. transformed_types: FxHashMap>, transformed_consts: FxHashMap>, - transformed_data_inst_forms: FxHashMap>, seen_global_vars: FxHashSet, global_var_queue: VecDeque, seen_funcs: FxHashSet, @@ -93,20 +91,6 @@ impl Transformer for Validator<'_> { self.transformed_consts.insert(ct, transformed); transformed } - fn transform_data_inst_form_use( - &mut self, - data_inst_form: DataInstForm, - ) -> Transformed { - if let Some(&cached) = self.transformed_data_inst_forms.get(&data_inst_form) { - return cached; - } - let transformed = self - .transform_data_inst_form_def(&self.cx[data_inst_form]) - .map(|data_inst_form_def| self.cx.intern(data_inst_form_def)); - self.transformed_data_inst_forms - .insert(data_inst_form, transformed); - transformed - } fn transform_global_var_use(&mut self, gv: GlobalVar) -> Transformed { if self.seen_global_vars.insert(gv) { @@ -180,7 +164,7 @@ impl Transformer for Validator<'_> { .inner_in_place_transform_with(self); let inst_def = func_at_data_inst.def(); - let valid = match &self.cx[inst_def.form].kind { + let valid = match &inst_def.kind { DataInstKind::SpvInst(spv_inst) => self.validate_spv_inst(spv_inst), DataInstKind::FuncCall(_) | DataInstKind::QPtr(_) | DataInstKind::SpvExtInst { .. } => { diff --git a/tests/compiletests/ui/arch/non_uniform/buffer.stderr b/tests/compiletests/ui/arch/non_uniform/buffer.stderr index 67ba35f967c..a6c4c102c58 100644 --- a/tests/compiletests/ui/arch/non_uniform/buffer.stderr +++ b/tests/compiletests/ui/arch/non_uniform/buffer.stderr @@ -27,10 +27,10 @@ %void = OpTypeVoid %18 = OpTypeFunction %void %index = OpVariable %_ptr_Input_u32 Input -%_ptr_StorageBuffer__struct_8 = OpTypePointer StorageBuffer %_struct_8 %buffers = OpVariable %_ptr_StorageBuffer__runtimearr__struct_8 StorageBuffer -%_ptr_StorageBuffer_v4f32 = OpTypePointer StorageBuffer %v4f32 +%_ptr_StorageBuffer__struct_8 = OpTypePointer StorageBuffer %_struct_8 %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer_v4f32 = OpTypePointer StorageBuffer %v4f32 %out = OpVariable %_ptr_Output_v4f32 Output %1 = OpFunction %void None %18 %22 = OpLabel diff --git a/tests/compiletests/ui/arch/non_uniform/buffer_uniform.stderr b/tests/compiletests/ui/arch/non_uniform/buffer_uniform.stderr index eb422cd7bc6..6d3824c8f9d 100644 --- a/tests/compiletests/ui/arch/non_uniform/buffer_uniform.stderr +++ b/tests/compiletests/ui/arch/non_uniform/buffer_uniform.stderr @@ -24,10 +24,10 @@ %void = OpTypeVoid %17 = OpTypeFunction %void %index = OpVariable %_ptr_Input_u32 Input -%_ptr_StorageBuffer__struct_8 = OpTypePointer StorageBuffer %_struct_8 %buffers = OpVariable %_ptr_StorageBuffer__runtimearr__struct_8 StorageBuffer -%_ptr_StorageBuffer_v4f32 = OpTypePointer StorageBuffer %v4f32 +%_ptr_StorageBuffer__struct_8 = OpTypePointer StorageBuffer %_struct_8 %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer_v4f32 = OpTypePointer StorageBuffer %v4f32 %out = OpVariable %_ptr_Output_v4f32 Output %1 = OpFunction %void None %17 %21 = OpLabel diff --git a/tests/compiletests/ui/arch/non_uniform/byte_addressable_buffer.stderr b/tests/compiletests/ui/arch/non_uniform/byte_addressable_buffer.stderr index a777e71178c..407c9a5e7c5 100644 --- a/tests/compiletests/ui/arch/non_uniform/byte_addressable_buffer.stderr +++ b/tests/compiletests/ui/arch/non_uniform/byte_addressable_buffer.stderr @@ -35,9 +35,9 @@ %void = OpTypeVoid %24 = OpTypeFunction %void %index = OpVariable %_ptr_Input_u32 Input -%_ptr_StorageBuffer__runtimearr_u32 = OpTypePointer StorageBuffer %_runtimearr_u32 %buffer = OpVariable %_ptr_StorageBuffer__struct_8 StorageBuffer %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer__runtimearr_u32 = OpTypePointer StorageBuffer %_runtimearr_u32 %u32_16 = OpConstant %u32 16 %u32_2 = OpConstant %u32 2 %_ptr_StorageBuffer_u32 = OpTypePointer StorageBuffer %u32 diff --git a/tests/compiletests/ui/arch/non_uniform/byte_addressable_buffer_uniform.stderr b/tests/compiletests/ui/arch/non_uniform/byte_addressable_buffer_uniform.stderr index ab8589ad9b8..1cfebf95519 100644 --- a/tests/compiletests/ui/arch/non_uniform/byte_addressable_buffer_uniform.stderr +++ b/tests/compiletests/ui/arch/non_uniform/byte_addressable_buffer_uniform.stderr @@ -25,9 +25,9 @@ %void = OpTypeVoid %16 = OpTypeFunction %void %index = OpVariable %_ptr_Input_u32 Input -%_ptr_StorageBuffer__runtimearr_u32 = OpTypePointer StorageBuffer %_runtimearr_u32 %buffer = OpVariable %_ptr_StorageBuffer__struct_8 StorageBuffer %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer__runtimearr_u32 = OpTypePointer StorageBuffer %_runtimearr_u32 %u32_16 = OpConstant %u32 16 %u32_2 = OpConstant %u32 2 %_ptr_StorageBuffer_u32 = OpTypePointer StorageBuffer %u32 diff --git a/tests/compiletests/ui/arch/non_uniform/image.stderr b/tests/compiletests/ui/arch/non_uniform/image.stderr index 1287cc386ab..7f2bb1624f8 100644 --- a/tests/compiletests/ui/arch/non_uniform/image.stderr +++ b/tests/compiletests/ui/arch/non_uniform/image.stderr @@ -27,10 +27,10 @@ %void = OpTypeVoid %21 = OpTypeFunction %void %index = OpVariable %_ptr_Input_u32 Input -%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15 %images = OpVariable %_ptr_UniformConstant__runtimearr_15 UniformConstant - %v2u32 = OpTypeVector %u32 2 +%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15 %u32_1 = OpConstant %u32 1 + %v2u32 = OpTypeVector %u32 2 %u32_2 = OpConstant %u32 2 %u32_0 = OpConstant %u32 0 %27 = OpTypeFunction %v4f32 %v4f32 diff --git a/tests/compiletests/ui/arch/non_uniform/image_uniform.stderr b/tests/compiletests/ui/arch/non_uniform/image_uniform.stderr index 46dccdbe708..e35ac5931ab 100644 --- a/tests/compiletests/ui/arch/non_uniform/image_uniform.stderr +++ b/tests/compiletests/ui/arch/non_uniform/image_uniform.stderr @@ -22,10 +22,10 @@ %void = OpTypeVoid %18 = OpTypeFunction %void %index = OpVariable %_ptr_Input_u32 Input -%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 %images = OpVariable %_ptr_UniformConstant__runtimearr_12 UniformConstant - %v2u32 = OpTypeVector %u32 2 +%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 %u32_1 = OpConstant %u32 1 + %v2u32 = OpTypeVector %u32 2 %u32_2 = OpConstant %u32 2 %u32_0 = OpConstant %u32 0 %24 = OpTypeFunction %v4f32 %v4f32 diff --git a/tests/compiletests/ui/arch/non_uniform/storage_image.stderr b/tests/compiletests/ui/arch/non_uniform/storage_image.stderr index d09b5703023..4cbf76ace3e 100644 --- a/tests/compiletests/ui/arch/non_uniform/storage_image.stderr +++ b/tests/compiletests/ui/arch/non_uniform/storage_image.stderr @@ -29,10 +29,10 @@ %void = OpTypeVoid %21 = OpTypeFunction %void %index = OpVariable %_ptr_Input_u32 Input -%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15 %images = OpVariable %_ptr_UniformConstant__runtimearr_15 UniformConstant - %v2u32 = OpTypeVector %u32 2 +%_ptr_UniformConstant_15 = OpTypePointer UniformConstant %15 %u32_1 = OpConstant %u32 1 + %v2u32 = OpTypeVector %u32 2 %u32_2 = OpConstant %u32 2 %26 = OpTypeFunction %v4f32 %v4f32 %out = OpVariable %_ptr_Output_v4f32 Output diff --git a/tests/compiletests/ui/arch/non_uniform/storage_image_uniform.stderr b/tests/compiletests/ui/arch/non_uniform/storage_image_uniform.stderr index f4cfbe8e638..54ecf8f9aba 100644 --- a/tests/compiletests/ui/arch/non_uniform/storage_image_uniform.stderr +++ b/tests/compiletests/ui/arch/non_uniform/storage_image_uniform.stderr @@ -24,10 +24,10 @@ %void = OpTypeVoid %18 = OpTypeFunction %void %index = OpVariable %_ptr_Input_u32 Input -%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 %images = OpVariable %_ptr_UniformConstant__runtimearr_12 UniformConstant - %v2u32 = OpTypeVector %u32 2 +%_ptr_UniformConstant_12 = OpTypePointer UniformConstant %12 %u32_1 = OpConstant %u32 1 + %v2u32 = OpTypeVector %u32 2 %u32_2 = OpConstant %u32 2 %23 = OpTypeFunction %v4f32 %v4f32 %out = OpVariable %_ptr_Output_v4f32 Output diff --git a/tests/compiletests/ui/arch/shared/dce_shared.stderr b/tests/compiletests/ui/arch/shared/dce_shared.stderr index 48bb41ce49f..0a82bafe52d 100644 --- a/tests/compiletests/ui/arch/shared/dce_shared.stderr +++ b/tests/compiletests/ui/arch/shared/dce_shared.stderr @@ -23,9 +23,9 @@ %_ptr_Input_u32 = OpTypePointer Input %u32 %void = OpTypeVoid %16 = OpTypeFunction %void -%_ptr_StorageBuffer_f32 = OpTypePointer StorageBuffer %f32 %input = OpVariable %_ptr_StorageBuffer__struct_8 StorageBuffer %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer_f32 = OpTypePointer StorageBuffer %f32 %output = OpVariable %_ptr_StorageBuffer__struct_8 StorageBuffer %inv_id = OpVariable %_ptr_Input_u32 Input %bool = OpTypeBool diff --git a/tests/compiletests/ui/dis/asm_op_decorate.stderr b/tests/compiletests/ui/dis/asm_op_decorate.stderr index b20c349ab18..8bfc03d9b47 100644 --- a/tests/compiletests/ui/dis/asm_op_decorate.stderr +++ b/tests/compiletests/ui/dis/asm_op_decorate.stderr @@ -14,11 +14,11 @@ %f32 = OpTypeFloat 32 %9 = OpTypeImage %f32 2D 0 0 0 1 Unknown %10 = OpTypeSampledImage %9 -%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10 %_runtimearr_10 = OpTypeRuntimeArray %10 %_ptr_UniformConstant__runtimearr_10 = OpTypePointer UniformConstant %_runtimearr_10 %5 = OpVariable %_ptr_UniformConstant__runtimearr_10 UniformConstant %u32 = OpTypeInt 32 0 %u32_1 = OpConstant %u32 1 +%_ptr_UniformConstant_10 = OpTypePointer UniformConstant %10 OpLine %2 54 7 OpLine %2 27 3 diff --git a/tests/compiletests/ui/dis/const-narrowing-cast.stderr b/tests/compiletests/ui/dis/const-narrowing-cast.stderr index e65b057c766..7c4a8de03b1 100644 --- a/tests/compiletests/ui/dis/const-narrowing-cast.stderr +++ b/tests/compiletests/ui/dis/const-narrowing-cast.stderr @@ -10,7 +10,7 @@ %_ptr_Output_u32 = OpTypePointer Output %u32 %void = OpTypeVoid %7 = OpTypeFunction %void - %u8 = OpTypeInt 8 0 %u32_300 = OpConstant %u32 300 + %u8 = OpTypeInt 8 0 %output = OpVariable %_ptr_Output_u32 Output %u32_20 = OpConstant %u32 20 diff --git a/tests/compiletests/ui/dis/issue-615.stderr b/tests/compiletests/ui/dis/issue-615.stderr index 46343cec998..49a92961b5f 100644 --- a/tests/compiletests/ui/dis/issue-615.stderr +++ b/tests/compiletests/ui/dis/issue-615.stderr @@ -30,10 +30,10 @@ %Tri = OpTypeStruct %u32 %u32 %u32 %u32 %_ptr_Function_Tri = OpTypePointer Function %Tri %i = OpVariable %_ptr_Input_u32 Input - %bool = OpTypeBool %u32_0 = OpConstant %u32 0 -%_ptr_Function_u32 = OpTypePointer Function %u32 + %bool = OpTypeBool %u32_1 = OpConstant %u32 1 +%_ptr_Function_u32 = OpTypePointer Function %u32 %u32_2 = OpConstant %u32 2 %u32_3 = OpConstant %u32 3 %23 = OpTypeFunction %u32 %_ptr_Function_Multi diff --git a/tests/compiletests/ui/dis/non-writable-storage_buffer.stderr b/tests/compiletests/ui/dis/non-writable-storage_buffer.stderr index 3e597c05702..3680e21a22d 100644 --- a/tests/compiletests/ui/dis/non-writable-storage_buffer.stderr +++ b/tests/compiletests/ui/dis/non-writable-storage_buffer.stderr @@ -18,10 +18,10 @@ %void = OpTypeVoid %8 = OpTypeFunction %void %u32 = OpTypeInt 32 0 -%_ptr_StorageBuffer_u32 = OpTypePointer StorageBuffer %u32 %_struct_6 = OpTypeStruct %u32 %_ptr_StorageBuffer__struct_6 = OpTypePointer StorageBuffer %_struct_6 %buf_imm = OpVariable %_ptr_StorageBuffer__struct_6 StorageBuffer %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer_u32 = OpTypePointer StorageBuffer %u32 %buf_mut = OpVariable %_ptr_StorageBuffer__struct_6 StorageBuffer %buf_interior_mut = OpVariable %_ptr_StorageBuffer__struct_6 StorageBuffer diff --git a/tests/compiletests/ui/dis/panic_builtin_bounds_check.stderr b/tests/compiletests/ui/dis/panic_builtin_bounds_check.stderr index 16063e6b9f1..b75ea3d7d31 100644 --- a/tests/compiletests/ui/dis/panic_builtin_bounds_check.stderr +++ b/tests/compiletests/ui/dis/panic_builtin_bounds_check.stderr @@ -14,13 +14,13 @@ %u32_4 = OpConstant %u32 4 %11 = OpTypeArray %u32 %u32_4 %_ptr_Function_11 = OpTypePointer Function %11 - %6 = OpTypeArray %u32 %u32_4 %u32_0 = OpConstant %u32 0 + %6 = OpTypeArray %u32 %u32_4 %u32_1 = OpConstant %u32 1 %u32_2 = OpConstant %u32 2 %u32_3 = OpConstant %u32 3 - %bool = OpTypeBool %u32_5 = OpConstant %u32 5 + %bool = OpTypeBool %_ptr_Function_u32 = OpTypePointer Function %u32 %2 = OpFunction %void None %8 %20 = OpLabel diff --git a/tests/compiletests/ui/dis/panic_sequential_many.stderr b/tests/compiletests/ui/dis/panic_sequential_many.stderr index 7f8bcdb72d3..f5253b37988 100644 --- a/tests/compiletests/ui/dis/panic_sequential_many.stderr +++ b/tests/compiletests/ui/dis/panic_sequential_many.stderr @@ -22,8 +22,8 @@ %13 = OpTypeFunction %void %x = OpVariable %_ptr_Input_u32 Input %y = OpVariable %_ptr_Input_u32 Input - %bool = OpTypeBool %u32_0 = OpConstant %u32 0 + %bool = OpTypeBool %o = OpVariable %_ptr_Output_u32 Output %2 = OpFunction %void None %13 %16 = OpLabel diff --git a/tests/compiletests/ui/dis/scalars.nocaps.stderr b/tests/compiletests/ui/dis/scalars.nocaps.stderr index 6d368d723a5..9f250dc2c0e 100644 --- a/tests/compiletests/ui/dis/scalars.nocaps.stderr +++ b/tests/compiletests/ui/dis/scalars.nocaps.stderr @@ -1,5 +1,6 @@ error: `u8` type used without `OpCapability Int8` | + = note: used by unnamed type note: used from within Fragment entry-point `main` --> <$DIR/scalars.rs>:25:5 | @@ -8,6 +9,7 @@ LL | #[spirv(flat)] in_u8: u8, error: `u16` type used without `OpCapability Int16` | + = note: used by unnamed type note: used from within Fragment entry-point `main` --> <$DIR/scalars.rs>:26:5 | @@ -16,6 +18,7 @@ LL | #[spirv(flat)] in_u16: u16, error: `u64` type used without `OpCapability Int64` | + = note: used by unnamed type note: used from within Fragment entry-point `main` --> <$DIR/scalars.rs>:28:5 | @@ -24,6 +27,7 @@ LL | #[spirv(flat)] in_u64: u64, error: `u128` type unsupported in SPIR-V | + = note: used by unnamed type note: used from within Fragment entry-point `main` --> <$DIR/scalars.rs>:30:5 | @@ -34,6 +38,7 @@ LL | | in_u128: u128, error: `i8` type used without `OpCapability Int8` | + = note: used by unnamed type note: used from within Fragment entry-point `main` --> <$DIR/scalars.rs>:34:5 | @@ -42,6 +47,7 @@ LL | #[spirv(flat)] in_i8: i8, error: `i16` type used without `OpCapability Int16` | + = note: used by unnamed type note: used from within Fragment entry-point `main` --> <$DIR/scalars.rs>:35:5 | @@ -50,6 +56,7 @@ LL | #[spirv(flat)] in_i16: i16, error: `i64` type used without `OpCapability Int64` | + = note: used by unnamed type note: used from within Fragment entry-point `main` --> <$DIR/scalars.rs>:37:5 | @@ -58,6 +65,7 @@ LL | #[spirv(flat)] in_i64: i64, error: `i128` type unsupported in SPIR-V | + = note: used by unnamed type note: used from within Fragment entry-point `main` --> <$DIR/scalars.rs>:39:5 | @@ -68,6 +76,7 @@ LL | | in_i128: i128, error: `f64` type used without `OpCapability Float64` | + = note: used by unnamed type note: used from within Fragment entry-point `main` --> <$DIR/scalars.rs>:44:5 | diff --git a/tests/compiletests/ui/dis/spec_constant_array.stderr b/tests/compiletests/ui/dis/spec_constant_array.stderr index 792242385fb..2098e00b947 100644 --- a/tests/compiletests/ui/dis/spec_constant_array.stderr +++ b/tests/compiletests/ui/dis/spec_constant_array.stderr @@ -17,9 +17,9 @@ %_ptr_StorageBuffer__struct_4 = OpTypePointer StorageBuffer %_struct_4 %void = OpTypeVoid %12 = OpTypeFunction %void -%_ptr_StorageBuffer_u32 = OpTypePointer StorageBuffer %u32 %out = OpVariable %_ptr_StorageBuffer__struct_4 StorageBuffer %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer_u32 = OpTypePointer StorageBuffer %u32 %5 = OpSpecConstant %u32 69 %6 = OpSpecConstant %u32 69 %7 = OpSpecConstant %u32 69 diff --git a/tests/compiletests/ui/entry/asm/entry2_global_asm.stderr b/tests/compiletests/ui/entry/asm/entry2_global_asm.stderr index aeb4a30bdfe..ee7682bf90a 100644 --- a/tests/compiletests/ui/entry/asm/entry2_global_asm.stderr +++ b/tests/compiletests/ui/entry/asm/entry2_global_asm.stderr @@ -26,12 +26,12 @@ %_ptr_Input_v4f32 = OpTypePointer Input %v4f32 %frag_coord = OpVariable %_ptr_Input_v4f32 Input %v2f32 = OpTypeVector %f32 2 -%_ptr_StorageBuffer_v2f32 = OpTypePointer StorageBuffer %v2f32 %_struct_11 = OpTypeStruct %v2f32 %_ptr_StorageBuffer__struct_11 = OpTypePointer StorageBuffer %_struct_11 %viewport_size = OpVariable %_ptr_StorageBuffer__struct_11 StorageBuffer %u32 = OpTypeInt 32 0 %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer_v2f32 = OpTypePointer StorageBuffer %v2f32 %_ptr_StorageBuffer_f32 = OpTypePointer StorageBuffer %f32 %u32_1 = OpConstant %u32 1 %_spirv_std__glam__Vec2__f32__f32_ = OpTypeStruct %v2f32 %f32 %f32 diff --git a/tests/compiletests/ui/entry/asm/entry2_reference.stderr b/tests/compiletests/ui/entry/asm/entry2_reference.stderr index aca4bbc7797..f265ec0dbe7 100644 --- a/tests/compiletests/ui/entry/asm/entry2_reference.stderr +++ b/tests/compiletests/ui/entry/asm/entry2_reference.stderr @@ -29,10 +29,10 @@ %void = OpTypeVoid %18 = OpTypeFunction %void %frag_coord = OpVariable %_ptr_Input_v4f32 Input -%_ptr_StorageBuffer_v2f32 = OpTypePointer StorageBuffer %v2f32 %viewport_size = OpVariable %_ptr_StorageBuffer__struct_10 StorageBuffer %u32 = OpTypeInt 32 0 %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer_v2f32 = OpTypePointer StorageBuffer %v2f32 %_ptr_StorageBuffer_f32 = OpTypePointer StorageBuffer %f32 %u32_1 = OpConstant %u32 1 %_spirv_std__glam__Vec2__f32__f32_ = OpTypeStruct %v2f32 %f32 %f32 diff --git a/tests/compiletests/ui/entry/asm/entry3_generic_asm.stderr b/tests/compiletests/ui/entry/asm/entry3_generic_asm.stderr index 4099b903597..66417c958b0 100644 --- a/tests/compiletests/ui/entry/asm/entry3_generic_asm.stderr +++ b/tests/compiletests/ui/entry/asm/entry3_generic_asm.stderr @@ -19,11 +19,11 @@ %_ptr_Input_v3u32 = OpTypePointer Input %v3u32 %2 = OpVariable %_ptr_Input_v3u32 Input %_runtimearr_u32 = OpTypeRuntimeArray %u32 -%_ptr_StorageBuffer__runtimearr_u32 = OpTypePointer StorageBuffer %_runtimearr_u32 %_struct_9 = OpTypeStruct %_runtimearr_u32 %_ptr_StorageBuffer__struct_9 = OpTypePointer StorageBuffer %_struct_9 %3 = OpVariable %_ptr_StorageBuffer__struct_9 StorageBuffer %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer__runtimearr_u32 = OpTypePointer StorageBuffer %_runtimearr_u32 %_ptr_StorageBuffer_u32 = OpTypePointer StorageBuffer %u32 %4 = OpVariable %_ptr_StorageBuffer__struct_9 StorageBuffer %entry3_generic_asm__entry = OpFunction %void None %11 diff --git a/tests/compiletests/ui/entry/asm/entry3_global_asm.stderr b/tests/compiletests/ui/entry/asm/entry3_global_asm.stderr index 97793f37d54..74bdea6c939 100644 --- a/tests/compiletests/ui/entry/asm/entry3_global_asm.stderr +++ b/tests/compiletests/ui/entry/asm/entry3_global_asm.stderr @@ -22,11 +22,11 @@ %_ptr_Input_v3u32 = OpTypePointer Input %v3u32 %gid = OpVariable %_ptr_Input_v3u32 Input %_runtimearr_u32 = OpTypeRuntimeArray %u32 -%_ptr_StorageBuffer__runtimearr_u32 = OpTypePointer StorageBuffer %_runtimearr_u32 %_struct_9 = OpTypeStruct %_runtimearr_u32 %_ptr_StorageBuffer__struct_9 = OpTypePointer StorageBuffer %_struct_9 %input = OpVariable %_ptr_StorageBuffer__struct_9 StorageBuffer %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer__runtimearr_u32 = OpTypePointer StorageBuffer %_runtimearr_u32 %_ptr_StorageBuffer_u32 = OpTypePointer StorageBuffer %u32 %output = OpVariable %_ptr_StorageBuffer__struct_9 StorageBuffer %entry3_global_asm__entry = OpFunction %void None %11 diff --git a/tests/compiletests/ui/entry/asm/entry3_reference.stderr b/tests/compiletests/ui/entry/asm/entry3_reference.stderr index 98da08ffc1a..3759a0b9293 100644 --- a/tests/compiletests/ui/entry/asm/entry3_reference.stderr +++ b/tests/compiletests/ui/entry/asm/entry3_reference.stderr @@ -23,9 +23,9 @@ %void = OpTypeVoid %15 = OpTypeFunction %void %gid = OpVariable %_ptr_Input_v3u32 Input -%_ptr_StorageBuffer__runtimearr_u32 = OpTypePointer StorageBuffer %_runtimearr_u32 %input = OpVariable %_ptr_StorageBuffer__struct_9 StorageBuffer %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer__runtimearr_u32 = OpTypePointer StorageBuffer %_runtimearr_u32 %_ptr_StorageBuffer_u32 = OpTypePointer StorageBuffer %u32 %output = OpVariable %_ptr_StorageBuffer__struct_9 StorageBuffer %1 = OpFunction %void None %15 diff --git a/tests/compiletests/ui/image/write_comp.stderr b/tests/compiletests/ui/image/write_comp.stderr index a2192b70a99..a8c155d5d8f 100644 --- a/tests/compiletests/ui/image/write_comp.stderr +++ b/tests/compiletests/ui/image/write_comp.stderr @@ -26,9 +26,9 @@ %void = OpTypeVoid %18 = OpTypeFunction %void %global_id = OpVariable %_ptr_Input_v3u32 Input -%_ptr_StorageBuffer_v4f32 = OpTypePointer StorageBuffer %v4f32 %fill_color = OpVariable %_ptr_StorageBuffer__struct_8 StorageBuffer %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer_v4f32 = OpTypePointer StorageBuffer %v4f32 %v2u32 = OpTypeVector %u32 2 %image = OpVariable %_ptr_UniformConstant_15 UniformConstant %1 = OpFunction %void None %18 diff --git a/tests/compiletests/ui/image/write_comp_format.stderr b/tests/compiletests/ui/image/write_comp_format.stderr index d2a2908d5a9..31febe5ff80 100644 --- a/tests/compiletests/ui/image/write_comp_format.stderr +++ b/tests/compiletests/ui/image/write_comp_format.stderr @@ -26,9 +26,9 @@ %void = OpTypeVoid %18 = OpTypeFunction %void %global_id = OpVariable %_ptr_Input_v3u32 Input -%_ptr_StorageBuffer_v2f32 = OpTypePointer StorageBuffer %v2f32 %fill_color = OpVariable %_ptr_StorageBuffer__struct_8 StorageBuffer %u32_0 = OpConstant %u32 0 +%_ptr_StorageBuffer_v2f32 = OpTypePointer StorageBuffer %v2f32 %_ptr_StorageBuffer_f32 = OpTypePointer StorageBuffer %f32 %u32_1 = OpConstant %u32 1 %v2u32 = OpTypeVector %u32 2 diff --git a/tests/compiletests/ui/spirv-attr/location_assignment/explicit_overlap.stderr b/tests/compiletests/ui/spirv-attr/location_assignment/explicit_overlap.stderr index e0c014e1ddf..a88ae474f88 100644 --- a/tests/compiletests/ui/spirv-attr/location_assignment/explicit_overlap.stderr +++ b/tests/compiletests/ui/spirv-attr/location_assignment/explicit_overlap.stderr @@ -26,10 +26,10 @@ %17 = OpConstantComposite %v4f32 %f32_0 %f32_0 %f32_1 %f32_0 %18 = OpConstantComposite %v4f32 %f32_0 %f32_0 %f32_0 %f32_1 %19 = OpConstantComposite %spirv_std__glam__Mat4 %15 %16 %17 %18 -%_ptr_Output_f32 = OpTypePointer Output %f32 %out2 = OpVariable %_ptr_Output_v2f32 Output %u32 = OpTypeInt 32 0 %u32_0 = OpConstant %u32 0 +%_ptr_Output_f32 = OpTypePointer Output %f32 %u32_1 = OpConstant %u32 1 %1 = OpFunction %void None %12 %24 = OpLabel diff --git a/tests/compiletests/ui/spirv-attr/location_assignment/explict.stderr b/tests/compiletests/ui/spirv-attr/location_assignment/explict.stderr index 4775680d76d..d5a4f37e5e8 100644 --- a/tests/compiletests/ui/spirv-attr/location_assignment/explict.stderr +++ b/tests/compiletests/ui/spirv-attr/location_assignment/explict.stderr @@ -33,9 +33,9 @@ %_ptr_Output_f32 = OpTypePointer Output %f32 %void = OpTypeVoid %18 = OpTypeFunction %void -%LargerThanVec4 = OpTypeStruct %v4f32 %v2f32 %f32_0 = OpConstant %f32 0 %20 = OpConstantComposite %v4f32 %f32_0 %f32_0 %f32_0 %f32_0 +%LargerThanVec4 = OpTypeStruct %v4f32 %v2f32 %21 = OpUndef %LargerThanVec4 %out1 = OpVariable %_ptr_Output_LargerThanVec4 Output %out2 = OpVariable %_ptr_Output_v2f32 Output diff --git a/tests/compiletests/ui/spirv-attr/location_assignment/many_f32_struct.stderr b/tests/compiletests/ui/spirv-attr/location_assignment/many_f32_struct.stderr index fec30479d1c..5a8660afcbb 100644 --- a/tests/compiletests/ui/spirv-attr/location_assignment/many_f32_struct.stderr +++ b/tests/compiletests/ui/spirv-attr/location_assignment/many_f32_struct.stderr @@ -22,8 +22,8 @@ %_ptr_Output_f32 = OpTypePointer Output %f32 %void = OpTypeVoid %11 = OpTypeFunction %void - %ManyFloats = OpTypeStruct %f32 %f32 %f32 %f32_0 = OpConstant %f32 0 + %ManyFloats = OpTypeStruct %f32 %f32 %f32 %out1 = OpVariable %_ptr_Output_ManyFloats Output %out2 = OpVariable %_ptr_Output_f32 Output %1 = OpFunction %void None %11 diff --git a/tests/compiletests/ui/spirv-attr/location_assignment/mesh_shader.stderr b/tests/compiletests/ui/spirv-attr/location_assignment/mesh_shader.stderr index 241d2f518ff..ceb075f1b22 100644 --- a/tests/compiletests/ui/spirv-attr/location_assignment/mesh_shader.stderr +++ b/tests/compiletests/ui/spirv-attr/location_assignment/mesh_shader.stderr @@ -47,8 +47,8 @@ %_ptr_Output_33 = OpTypePointer Output %33 %void = OpTypeVoid %36 = OpTypeFunction %void -%core__ops__Range_usize_ = OpTypeStruct %u32 %u32 %u32_0 = OpConstant %u32 0 +%core__ops__Range_usize_ = OpTypeStruct %u32 %u32 %38 = OpUndef %core__ops__Range_usize_ %bool = OpTypeBool %bool_false = OpConstantFalse %bool @@ -59,15 +59,15 @@ %f32_0_5 = OpConstant %f32 0.5 %f32_0 = OpConstant %f32 0 %f32_1 = OpConstant %f32 1 -%_ptr_Output_v4f32 = OpTypePointer Output %v4f32 %positions = OpVariable %_ptr_Output_22 Output +%_ptr_Output_v4f32 = OpTypePointer Output %v4f32 %u32_2 = OpConstant %u32 2 -%_ptr_Output_u32 = OpTypePointer Output %u32 %out_per_vertex = OpVariable %_ptr_Output_28 Output -%_ptr_Output_f32 = OpTypePointer Output %f32 +%_ptr_Output_u32 = OpTypePointer Output %u32 %out_per_vertex2 = OpVariable %_ptr_Output_30 Output -%_ptr_Output_v3u32 = OpTypePointer Output %v3u32 +%_ptr_Output_f32 = OpTypePointer Output %f32 %indices = OpVariable %_ptr_Output_26 Output +%_ptr_Output_v3u32 = OpTypePointer Output %v3u32 %out_per_primitive = OpVariable %_ptr_Output_ops__try_trait__NeverShortCircuit__char__3__ Output %u32_42 = OpConstant %u32 42 %out_per_primitive2 = OpVariable %_ptr_Output_33 Output diff --git a/tests/compiletests/ui/spirv-attr/location_assignment/struct.stderr b/tests/compiletests/ui/spirv-attr/location_assignment/struct.stderr index 7039b2e0401..e85425b320b 100644 --- a/tests/compiletests/ui/spirv-attr/location_assignment/struct.stderr +++ b/tests/compiletests/ui/spirv-attr/location_assignment/struct.stderr @@ -33,9 +33,9 @@ %_ptr_Output_f32 = OpTypePointer Output %f32 %void = OpTypeVoid %18 = OpTypeFunction %void -%LargerThanVec4 = OpTypeStruct %v4f32 %v2f32 %f32_0 = OpConstant %f32 0 %20 = OpConstantComposite %v4f32 %f32_0 %f32_0 %f32_0 %f32_0 +%LargerThanVec4 = OpTypeStruct %v4f32 %v2f32 %21 = OpUndef %LargerThanVec4 %out1 = OpVariable %_ptr_Output_LargerThanVec4 Output %out2 = OpVariable %_ptr_Output_v2f32 Output diff --git a/tests/compiletests/ui/spirv-attr/location_assignment/vec3_f32.stderr b/tests/compiletests/ui/spirv-attr/location_assignment/vec3_f32.stderr index c38fb84c823..b6e060c9dcd 100644 --- a/tests/compiletests/ui/spirv-attr/location_assignment/vec3_f32.stderr +++ b/tests/compiletests/ui/spirv-attr/location_assignment/vec3_f32.stderr @@ -20,9 +20,9 @@ %_ptr_Output_f32 = OpTypePointer Output %f32 %void = OpTypeVoid %12 = OpTypeFunction %void -%Vec3AndFloat = OpTypeStruct %v3f32 %f32 %f32_0 = OpConstant %f32 0 %14 = OpConstantComposite %v3f32 %f32_0 %f32_0 %f32_0 +%Vec3AndFloat = OpTypeStruct %v3f32 %f32 %out1 = OpVariable %_ptr_Output_Vec3AndFloat Output %out2 = OpVariable %_ptr_Output_f32 Output %1 = OpFunction %void None %12 From b7f7190ee9bb6f3139e7d9b127438ec327adf821 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Tue, 13 Oct 2026 12:24:47 +0300 Subject: [PATCH 5/8] Update `spirt` for newer SPIR-V support (matching Vulkan SDK 1.4.363.0). --- Cargo.lock | 2 +- crates/rustc_codegen_spirv/Cargo.toml | 3 ++- .../src/linker/spirt_passes/validate.rs | 12 ++++-------- 3 files changed, 7 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 43a5ff82440..19f812c2d3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5795,7 +5795,7 @@ dependencies = [ [[package]] name = "spirt" version = "0.4.0" -source = "git+https://github.com/Rust-GPU/spirt?rev=5c426149#5c4261490c6510cb755fc444a76a5c4d5e06705d" +source = "git+https://github.com/Rust-GPU/spirt?branch=eddyb%2Fvulkan-sdk-1.4.363.0#487c502fcd79a85277730ae809bfe5f563e08d15" dependencies = [ "arrayvec", "bytemuck", diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index b42d173d82e..7e5d093a55c 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -60,7 +60,8 @@ smallvec = { version = "1.6.1", features = ["const_generics", "const_new", "unio # - https://github.com/Rust-GPU/spirt/pull/8 # - https://github.com/Rust-GPU/spirt/pull/9 # - https://github.com/Rust-GPU/spirt/pull/12 -spirt = { git = "https://github.com/Rust-GPU/spirt", rev = "5c426149" } +# - https://github.com/Rust-GPU/spirt/pull/49 +spirt = { git = "https://github.com/Rust-GPU/spirt", branch = "eddyb/vulkan-sdk-1.4.363.0" } spirv-tools.workspace = true lazy_static = "1.4.0" itertools = "0.14.0" diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs index 8b772f1be99..0b0ba026ce4 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs @@ -53,7 +53,7 @@ struct Validator<'a> { cx: &'a Context, wk: &'static super::SpvWellKnownWithExtras, spv_spec_caps: &'static spv::spec::indexed::NamedIdxMap< - u16, + u32, spv::spec::Enumerant, spv::spec::indexed::KhrSegmented, >, @@ -242,9 +242,7 @@ impl Validator<'_> { if !enabled_by_default_or_cap { let caps = caps_enabling .map(|cap| { - let cap_name = u16::try_from(cap) - .ok() - .and_then(|cap| Some(self.spv_spec_caps.get_named(cap)?.0)); + let cap_name = self.spv_spec_caps.get_named(cap).map(|(name, _)| name); match cap_name { Some(name) => format!("`{name}`"), None => format!(""), @@ -283,7 +281,7 @@ impl Validator<'_> { let int_or_float = |type_name: &str, cap_name: &str| { // FIXME(eddyb) find a consistent style between all the error messages // (mentioning `OpCapability` seems unfortunate, for example). - match self.spv_spec_caps.lookup(cap_name).map(u32::from) { + match self.spv_spec_caps.lookup(cap_name) { None => Err(format!("`{type_name}` type unsupported in SPIR-V")), Some(cap) if !self.module_spv_dialect.capabilities.contains(&cap) => Err(format!( "`{type_name}` type used without `OpCapability {cap_name}`" @@ -330,9 +328,7 @@ impl Validator<'_> { let (enum_name, enum_def) = kind.name_and_def(); let enumerant_name = match enum_def { spv::spec::OperandKindDef::ValueEnum { variants } => { - u16::try_from(imm) - .ok() - .and_then(|imm| Some(variants.get_named(imm)?.0)) + variants.get_named(imm).map(|(name, _)| name) } _ => None, }; From c23baadc92cc273e5f881c6a2734643ab02c6d2d Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 15 Oct 2026 14:43:42 +0300 Subject: [PATCH 6/8] Update `spirt` for several SPIR-V "future-compat" style fixes. --- Cargo.lock | 2 +- crates/rustc_codegen_spirv/Cargo.toml | 3 ++- .../src/linker/spirt_passes/controlflow.rs | 7 ++++++- .../src/linker/spirt_passes/debuginfo.rs | 9 +++++++- .../src/linker/spirt_passes/diagnostics.rs | 10 ++++++--- .../linker/spirt_passes/explicit_layout.rs | 21 ++++++++++++------- .../src/linker/spirt_passes/validate.rs | 8 +++++-- 7 files changed, 43 insertions(+), 17 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 19f812c2d3b..54308c72da1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5795,7 +5795,7 @@ dependencies = [ [[package]] name = "spirt" version = "0.4.0" -source = "git+https://github.com/Rust-GPU/spirt?branch=eddyb%2Fvulkan-sdk-1.4.363.0#487c502fcd79a85277730ae809bfe5f563e08d15" +source = "git+https://github.com/Rust-GPU/spirt?branch=eddyb%2Fmisc-flex#64d7eb37ad1fda1d81ef0cb39fb84ec73a286902" dependencies = [ "arrayvec", "bytemuck", diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index 7e5d093a55c..d63a425038d 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -61,7 +61,8 @@ smallvec = { version = "1.6.1", features = ["const_generics", "const_new", "unio # - https://github.com/Rust-GPU/spirt/pull/9 # - https://github.com/Rust-GPU/spirt/pull/12 # - https://github.com/Rust-GPU/spirt/pull/49 -spirt = { git = "https://github.com/Rust-GPU/spirt", branch = "eddyb/vulkan-sdk-1.4.363.0" } +# - https://github.com/Rust-GPU/spirt/pull/52 +spirt = { git = "https://github.com/Rust-GPU/spirt", branch = "eddyb/misc-flex" } spirv-tools.workspace = true lazy_static = "1.4.0" itertools = "0.14.0" diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs index 1bc70de9c11..36ff6680793 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/controlflow.rs @@ -46,7 +46,12 @@ pub fn convert_custom_aborts_to_unstructured_returns_in_entry_points( // HACK(eddyb) deduplicate with `diagnostics`. let name_from_attrs = |attrs: AttrSet| { cx[attrs].attrs.iter().find_map(|attr| match attr { - Attr::SpvAnnotation(spv_inst) if spv_inst.opcode == wk.OpName => { + Attr::SpvAnnotation { + spv_inst, + per_instance_const_inputs, + } if spv_inst.opcode == wk.OpName => { + assert!(per_instance_const_inputs.is_none()); + Some(super::decode_spv_lit_str_with(&spv_inst.imms, |name| { name.to_string() })) diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs index 0fb111f425b..a915f9ec569 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/debuginfo.rs @@ -98,7 +98,14 @@ fn decode_all_custom_decorations( attrs_def.attrs.iter().filter_map(|attr| { let spv_inst = match attr { - Attr::SpvAnnotation(spv_inst) if spv_inst.opcode == wk.OpDecorateString => spv_inst, + Attr::SpvAnnotation { + spv_inst, + per_instance_const_inputs, + } if spv_inst.opcode == wk.OpDecorateString => { + assert!(per_instance_const_inputs.is_none()); + + spv_inst + } _ => return None, }; let str_imms = spv_inst diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs index edc46c05d02..f0900e2b677 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/diagnostics.rs @@ -182,7 +182,12 @@ impl UseOrigin<'_> { .attrs .iter() .find_map(|attr| match attr { - Attr::SpvAnnotation(spv_inst) if spv_inst.opcode == wk.OpName => { + Attr::SpvAnnotation { + spv_inst, + per_instance_const_inputs, + } if spv_inst.opcode == wk.OpName => { + assert!(per_instance_const_inputs.is_none()); + Some(super::decode_spv_lit_str_with(&spv_inst.imms, |name| { format!("`{name}`") })) @@ -211,8 +216,7 @@ impl UseOrigin<'_> { match imms[..] { [em @ spv::Imm::Short(em_kind, _), ref name_imms @ ..] => { assert_eq!(em_kind, wk.ExecutionModel); - let em = - spv::print::operand_from_imms([em]).concat_to_plain_text(); + let em = spv::print::operand([em], []).concat_to_plain_text(); super::decode_spv_lit_str_with(name_imms, |name| { format!( "{} entry-point `{name}`", diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs index f4d58edfdc0..47a56bedc82 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs @@ -778,15 +778,20 @@ impl Transformer for EraseExplicitLayout<'_, '_> { // FIXME(eddyb) `rustfmt` breaks down for `matches!`. #[allow(clippy::match_like_matches_macro)] let is_explicit_layout_decoration = match attr { - Attr::SpvAnnotation(attr_spv_inst) - if (attr_spv_inst.opcode == wk.OpDecorate - && [wk.ArrayStride, wk.MatrixStride] - .map(|d| spv::Imm::Short(wk.Decoration, d)) - .contains(&attr_spv_inst.imms[0])) - || (attr_spv_inst.opcode == wk.OpMemberDecorate - && attr_spv_inst.imms[1] - == spv::Imm::Short(wk.Decoration, wk.Offset)) => + Attr::SpvAnnotation { + spv_inst: attr_spv_inst, + per_instance_const_inputs, + } if (attr_spv_inst.opcode == wk.OpDecorate + && [wk.ArrayStride, wk.MatrixStride] + .map(|d| spv::Imm::Short(wk.Decoration, d)) + .contains(&attr_spv_inst.imms[0])) + || (attr_spv_inst.opcode == wk.OpMemberDecorate + && attr_spv_inst.imms[1] + == spv::Imm::Short(wk.Decoration, wk.Offset)) => { + // FIXME(eddyb) support `ArrayStrideId` and `OffsetId`. + assert!(per_instance_const_inputs.is_none()); + true } diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs index 0b0ba026ce4..fcfdba3ba26 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs @@ -114,7 +114,9 @@ impl Transformer for Validator<'_> { type_and_const_inputs: _, } => self.validate_spv_inst(spv_inst), - TypeKind::QPtr | TypeKind::SpvStringLiteralForExtInst => Ok(()), + TypeKind::QPtr | TypeKind::SpvTypeOperand | TypeKind::SpvStringLiteralForExtInst => { + Ok(()) + } }; let transformed = ty_def.inner_transform_with(self); match valid { @@ -140,7 +142,9 @@ impl Transformer for Validator<'_> { self.validate_spv_inst(spv_inst) } - ConstKind::PtrToGlobalVar(_) | ConstKind::SpvStringLiteralForExtInst(_) => Ok(()), + ConstKind::PtrToGlobalVar(_) + | ConstKind::SpvTypeOperand(_) + | ConstKind::SpvStringLiteralForExtInst(_) => Ok(()), }; let transformed = ct_def.inner_transform_with(self); match valid { From 24e3fbd32310c4a3df0b942ba83538a04b70bae3 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 15 Oct 2026 16:19:49 +0300 Subject: [PATCH 7/8] Update `spirt` for minimal `OpSpecConstantOp` and `OpConstantFunctionPointerINTEL` support. --- Cargo.lock | 2 +- crates/rustc_codegen_spirv/Cargo.toml | 3 ++- crates/rustc_codegen_spirv/src/builder_spirv.rs | 13 ------------- .../src/linker/spirt_passes/explicit_layout.rs | 3 +++ .../src/linker/spirt_passes/validate.rs | 5 +++++ 5 files changed, 11 insertions(+), 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 54308c72da1..768789d70f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5795,7 +5795,7 @@ dependencies = [ [[package]] name = "spirt" version = "0.4.0" -source = "git+https://github.com/Rust-GPU/spirt?branch=eddyb%2Fmisc-flex#64d7eb37ad1fda1d81ef0cb39fb84ec73a286902" +source = "git+https://github.com/LykenSol/spirt?branch=min-fn-ptr#85fa656ccc05f076131008090b19ffdfcbfc4665" dependencies = [ "arrayvec", "bytemuck", diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index d63a425038d..fdbf2933167 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -62,7 +62,8 @@ smallvec = { version = "1.6.1", features = ["const_generics", "const_new", "unio # - https://github.com/Rust-GPU/spirt/pull/12 # - https://github.com/Rust-GPU/spirt/pull/49 # - https://github.com/Rust-GPU/spirt/pull/52 -spirt = { git = "https://github.com/Rust-GPU/spirt", branch = "eddyb/misc-flex" } +# - https://github.com/Rust-GPU/spirt/pull/22 +spirt = { git = "https://github.com/LykenSol/spirt", branch = "min-fn-ptr" } spirv-tools.workspace = true lazy_static = "1.4.0" itertools = "0.14.0" diff --git a/crates/rustc_codegen_spirv/src/builder_spirv.rs b/crates/rustc_codegen_spirv/src/builder_spirv.rs index c6ee3114293..4e6b6b1567a 100644 --- a/crates/rustc_codegen_spirv/src/builder_spirv.rs +++ b/crates/rustc_codegen_spirv/src/builder_spirv.rs @@ -596,19 +596,6 @@ impl<'tcx> BuilderSpirv<'tcx> { // FIXME(eddyb) make this an extension method on `rspirv::dr::Builder`? let const_op = |builder: &mut Builder, op, lhs, maybe_rhs: Option<_>| { - // HACK(eddyb) remove after `OpSpecConstantOp` support gets added to SPIR-T. - let spirt_has_const_op = false; - - if !spirt_has_const_op { - let zombie = builder.undef(ty, None); - cx.zombie_with_span( - zombie, - DUMMY_SP, - &format!("unsupported constant of type `{}`", cx.debug_type(ty)), - ); - return zombie; - } - let id = builder.id(); builder .module_mut() diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs index 47a56bedc82..4782ef21e08 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/explicit_layout.rs @@ -378,6 +378,9 @@ impl<'a> SelectiveEraser<'a> { wk.Uniform, wk.StorageBuffer, wk.PhysicalStorageBuffer, + // HACK(eddyb) not directly useful/needed, but avoiding (shallow) + // layout erasure in function pointers can reduce diagnostic noise. + wk.CodeSectionINTEL, ] .map(AddrSpace::SpvStorageClass) .contains(&addr_space) diff --git a/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs b/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs index fcfdba3ba26..d063f734ac4 100644 --- a/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs +++ b/crates/rustc_codegen_spirv/src/linker/spirt_passes/validate.rs @@ -142,6 +142,11 @@ impl Transformer for Validator<'_> { self.validate_spv_inst(spv_inst) } + // HACK(eddyb) check against the equivalent SPIR-V instruction. + ConstKind::PtrToFunc(_) => { + self.validate_spv_inst(&self.wk.OpConstantFunctionPointerINTEL.into()) + } + ConstKind::PtrToGlobalVar(_) | ConstKind::SpvTypeOperand(_) | ConstKind::SpvStringLiteralForExtInst(_) => Ok(()), From 6537c00d208e1ddcdcd167cd319f0fbd685df9b5 Mon Sep 17 00:00:00 2001 From: Eduard-Mihai Burtescu Date: Thu, 11 Sep 2025 19:04:30 +0300 Subject: [PATCH 8/8] Update `spirt` for `spv::lift` emitting "merge edge"s. --- Cargo.lock | 2 +- crates/rustc_codegen_spirv/Cargo.toml | 3 +- .../compiletests/ui/dis/index_user_dst.stderr | 8 +- .../ui/dis/panic_builtin_bounds_check.stderr | 12 +- .../ui/dis/panic_sequential_many.stderr | 260 ++++++++---------- 5 files changed, 124 insertions(+), 161 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 768789d70f0..4457133f8be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5795,7 +5795,7 @@ dependencies = [ [[package]] name = "spirt" version = "0.4.0" -source = "git+https://github.com/LykenSol/spirt?branch=min-fn-ptr#85fa656ccc05f076131008090b19ffdfcbfc4665" +source = "git+https://github.com/LykenSol/spirt?branch=bypass-merge-blocks#4b5f5293ba24733240afa3918a584ac10060ff89" dependencies = [ "arrayvec", "bytemuck", diff --git a/crates/rustc_codegen_spirv/Cargo.toml b/crates/rustc_codegen_spirv/Cargo.toml index fdbf2933167..275e1d0a4e4 100644 --- a/crates/rustc_codegen_spirv/Cargo.toml +++ b/crates/rustc_codegen_spirv/Cargo.toml @@ -63,7 +63,8 @@ smallvec = { version = "1.6.1", features = ["const_generics", "const_new", "unio # - https://github.com/Rust-GPU/spirt/pull/49 # - https://github.com/Rust-GPU/spirt/pull/52 # - https://github.com/Rust-GPU/spirt/pull/22 -spirt = { git = "https://github.com/LykenSol/spirt", branch = "min-fn-ptr" } +# - https://github.com/Rust-GPU/spirt/pull/28 +spirt = { git = "https://github.com/LykenSol/spirt", branch = "bypass-merge-blocks" } spirv-tools.workspace = true lazy_static = "1.4.0" itertools = "0.14.0" diff --git a/tests/compiletests/ui/dis/index_user_dst.stderr b/tests/compiletests/ui/dis/index_user_dst.stderr index 8a430e41539..f37aa2bfa47 100644 --- a/tests/compiletests/ui/dis/index_user_dst.stderr +++ b/tests/compiletests/ui/dis/index_user_dst.stderr @@ -7,15 +7,13 @@ %12 = OpULessThan %13 %9 %10 OpNoLine OpSelectionMerge %14 None - OpBranchConditional %12 %15 %16 + OpBranchConditional %12 %14 %15 %15 = OpLabel - OpBranch %14 - %16 = OpLabel OpReturn %14 = OpLabel OpLine %5 10 21 - %17 = OpInBoundsAccessChain %18 %6 %9 - %19 = OpLoad %20 %17 + %16 = OpInBoundsAccessChain %17 %6 %9 + %18 = OpLoad %19 %16 OpNoLine OpReturn OpFunctionEnd diff --git a/tests/compiletests/ui/dis/panic_builtin_bounds_check.stderr b/tests/compiletests/ui/dis/panic_builtin_bounds_check.stderr index b75ea3d7d31..34a6f6ace5a 100644 --- a/tests/compiletests/ui/dis/panic_builtin_bounds_check.stderr +++ b/tests/compiletests/ui/dis/panic_builtin_bounds_check.stderr @@ -38,19 +38,17 @@ %28 = OpULessThan %bool %u32_5 %u32_4 OpNoLine OpSelectionMerge %29 None - OpBranchConditional %28 %30 %31 + OpBranchConditional %28 %29 %30 %30 = OpLabel - OpBranch %29 - %31 = OpLabel OpLine %4 271 4 - %32 = OpExtInst %void %1 1 %3 %u32_4 %u32_5 + %31 = OpExtInst %void %1 1 %3 %u32_4 %u32_5 OpNoLine OpReturn %29 = OpLabel OpLine %5 27 4 - %33 = OpIAdd %u32 %u32_0 %u32_5 - %34 = OpInBoundsAccessChain %_ptr_Function_u32 %21 %33 - %35 = OpLoad %u32 %34 + %32 = OpIAdd %u32 %u32_0 %u32_5 + %33 = OpInBoundsAccessChain %_ptr_Function_u32 %21 %32 + %34 = OpLoad %u32 %33 OpNoLine OpReturn OpFunctionEnd diff --git a/tests/compiletests/ui/dis/panic_sequential_many.stderr b/tests/compiletests/ui/dis/panic_sequential_many.stderr index f5253b37988..1bc73af1cf8 100644 --- a/tests/compiletests/ui/dis/panic_sequential_many.stderr +++ b/tests/compiletests/ui/dis/panic_sequential_many.stderr @@ -35,242 +35,208 @@ %19 = OpIEqual %bool %18 %u32_0 OpNoLine OpSelectionMerge %20 None - OpBranchConditional %19 %21 %22 + OpBranchConditional %19 %21 %20 %21 = OpLabel OpLine %7 187 4 - %23 = OpExtInst %void %1 1 %6 + %22 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %22 = OpLabel - OpBranch %20 %20 = OpLabel OpLine %8 31 9 - %24 = OpUDiv %u32 %17 %18 - %25 = OpIEqual %bool %18 %u32_0 + %23 = OpUDiv %u32 %17 %18 + %24 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %26 None - OpBranchConditional %25 %27 %28 - %27 = OpLabel + OpSelectionMerge %25 None + OpBranchConditional %24 %26 %25 + %26 = OpLabel OpLine %7 187 4 - %29 = OpExtInst %void %1 1 %6 + %27 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %28 = OpLabel - OpBranch %26 - %26 = OpLabel + %25 = OpLabel OpLine %8 31 9 - %30 = OpUDiv %u32 %24 %18 - %31 = OpIEqual %bool %18 %u32_0 + %28 = OpUDiv %u32 %23 %18 + %29 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %32 None - OpBranchConditional %31 %33 %34 - %33 = OpLabel + OpSelectionMerge %30 None + OpBranchConditional %29 %31 %30 + %31 = OpLabel OpLine %7 187 4 - %35 = OpExtInst %void %1 1 %6 + %32 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %34 = OpLabel - OpBranch %32 - %32 = OpLabel + %30 = OpLabel OpLine %8 31 9 - %36 = OpUDiv %u32 %30 %18 - %37 = OpIEqual %bool %18 %u32_0 + %33 = OpUDiv %u32 %28 %18 + %34 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %38 None - OpBranchConditional %37 %39 %40 - %39 = OpLabel + OpSelectionMerge %35 None + OpBranchConditional %34 %36 %35 + %36 = OpLabel OpLine %7 187 4 - %41 = OpExtInst %void %1 1 %6 + %37 = OpExtInst %void %1 1 %6 + OpNoLine + OpReturn + %35 = OpLabel + OpLine %8 31 9 + %38 = OpUDiv %u32 %33 %18 + %39 = OpIEqual %bool %18 %u32_0 + OpNoLine + OpSelectionMerge %40 None + OpBranchConditional %39 %41 %40 + %41 = OpLabel + OpLine %7 187 4 + %42 = OpExtInst %void %1 1 %6 OpNoLine OpReturn %40 = OpLabel - OpBranch %38 - %38 = OpLabel OpLine %8 31 9 - %42 = OpUDiv %u32 %36 %18 - %43 = OpIEqual %bool %18 %u32_0 + %43 = OpUDiv %u32 %38 %18 + %44 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %44 None - OpBranchConditional %43 %45 %46 - %45 = OpLabel + OpSelectionMerge %45 None + OpBranchConditional %44 %46 %45 + %46 = OpLabel OpLine %7 187 4 %47 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %46 = OpLabel - OpBranch %44 - %44 = OpLabel + %45 = OpLabel OpLine %8 31 9 - %48 = OpUDiv %u32 %42 %18 + %48 = OpUDiv %u32 %43 %18 %49 = OpIEqual %bool %18 %u32_0 OpNoLine OpSelectionMerge %50 None - OpBranchConditional %49 %51 %52 + OpBranchConditional %49 %51 %50 %51 = OpLabel OpLine %7 187 4 - %53 = OpExtInst %void %1 1 %6 + %52 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %52 = OpLabel - OpBranch %50 %50 = OpLabel OpLine %8 31 9 - %54 = OpUDiv %u32 %48 %18 - %55 = OpIEqual %bool %18 %u32_0 + %53 = OpUDiv %u32 %48 %18 + %54 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %56 None - OpBranchConditional %55 %57 %58 - %57 = OpLabel + OpSelectionMerge %55 None + OpBranchConditional %54 %56 %55 + %56 = OpLabel OpLine %7 187 4 - %59 = OpExtInst %void %1 1 %6 + %57 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %58 = OpLabel - OpBranch %56 - %56 = OpLabel + %55 = OpLabel + OpLine %8 31 9 + %58 = OpUDiv %u32 %53 %18 + %59 = OpIEqual %bool %18 %u32_0 + OpNoLine + OpSelectionMerge %60 None + OpBranchConditional %59 %61 %60 + %61 = OpLabel + OpLine %7 187 4 + %62 = OpExtInst %void %1 1 %6 + OpNoLine + OpReturn + %60 = OpLabel OpLine %8 31 9 - %60 = OpUDiv %u32 %54 %18 - %61 = OpIEqual %bool %18 %u32_0 + %63 = OpUDiv %u32 %58 %18 + %64 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %62 None - OpBranchConditional %61 %63 %64 - %63 = OpLabel + OpSelectionMerge %65 None + OpBranchConditional %64 %66 %65 + %66 = OpLabel OpLine %7 187 4 - %65 = OpExtInst %void %1 1 %6 + %67 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %64 = OpLabel - OpBranch %62 - %62 = OpLabel + %65 = OpLabel OpLine %8 31 9 - %66 = OpUDiv %u32 %60 %18 - %67 = OpIEqual %bool %18 %u32_0 + %68 = OpUDiv %u32 %63 %18 + %69 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %68 None - OpBranchConditional %67 %69 %70 - %69 = OpLabel + OpSelectionMerge %70 None + OpBranchConditional %69 %71 %70 + %71 = OpLabel OpLine %7 187 4 - %71 = OpExtInst %void %1 1 %6 + %72 = OpExtInst %void %1 1 %6 OpNoLine OpReturn %70 = OpLabel - OpBranch %68 - %68 = OpLabel OpLine %8 31 9 - %72 = OpUDiv %u32 %66 %18 - %73 = OpIEqual %bool %18 %u32_0 + %73 = OpUDiv %u32 %68 %18 + %74 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %74 None - OpBranchConditional %73 %75 %76 - %75 = OpLabel + OpSelectionMerge %75 None + OpBranchConditional %74 %76 %75 + %76 = OpLabel OpLine %7 187 4 %77 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %76 = OpLabel - OpBranch %74 - %74 = OpLabel + %75 = OpLabel OpLine %8 31 9 - %78 = OpUDiv %u32 %72 %18 + %78 = OpUDiv %u32 %73 %18 %79 = OpIEqual %bool %18 %u32_0 OpNoLine OpSelectionMerge %80 None - OpBranchConditional %79 %81 %82 + OpBranchConditional %79 %81 %80 %81 = OpLabel OpLine %7 187 4 - %83 = OpExtInst %void %1 1 %6 + %82 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %82 = OpLabel - OpBranch %80 %80 = OpLabel OpLine %8 31 9 - %84 = OpUDiv %u32 %78 %18 - %85 = OpIEqual %bool %18 %u32_0 + %83 = OpUDiv %u32 %78 %18 + %84 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %86 None - OpBranchConditional %85 %87 %88 - %87 = OpLabel - OpLine %7 187 4 - %89 = OpExtInst %void %1 1 %6 - OpNoLine - OpReturn - %88 = OpLabel - OpBranch %86 + OpSelectionMerge %85 None + OpBranchConditional %84 %86 %85 %86 = OpLabel - OpLine %8 31 9 - %90 = OpUDiv %u32 %84 %18 - %91 = OpIEqual %bool %18 %u32_0 - OpNoLine - OpSelectionMerge %92 None - OpBranchConditional %91 %93 %94 - %93 = OpLabel - OpLine %7 187 4 - %95 = OpExtInst %void %1 1 %6 - OpNoLine - OpReturn - %94 = OpLabel - OpBranch %92 - %92 = OpLabel - OpLine %8 31 9 - %96 = OpUDiv %u32 %90 %18 - %97 = OpIEqual %bool %18 %u32_0 - OpNoLine - OpSelectionMerge %98 None - OpBranchConditional %97 %99 %100 - %99 = OpLabel OpLine %7 187 4 - %101 = OpExtInst %void %1 1 %6 + %87 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %100 = OpLabel - OpBranch %98 - %98 = OpLabel + %85 = OpLabel OpLine %8 31 9 - %102 = OpUDiv %u32 %96 %18 - %103 = OpIEqual %bool %18 %u32_0 + %88 = OpUDiv %u32 %83 %18 + %89 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %104 None - OpBranchConditional %103 %105 %106 - %105 = OpLabel + OpSelectionMerge %90 None + OpBranchConditional %89 %91 %90 + %91 = OpLabel OpLine %7 187 4 - %107 = OpExtInst %void %1 1 %6 + %92 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %106 = OpLabel - OpBranch %104 - %104 = OpLabel + %90 = OpLabel OpLine %8 31 9 - %108 = OpUDiv %u32 %102 %18 - %109 = OpIEqual %bool %18 %u32_0 + %93 = OpUDiv %u32 %88 %18 + %94 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %110 None - OpBranchConditional %109 %111 %112 - %111 = OpLabel + OpSelectionMerge %95 None + OpBranchConditional %94 %96 %95 + %96 = OpLabel OpLine %7 187 4 - %113 = OpExtInst %void %1 1 %6 + %97 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %112 = OpLabel - OpBranch %110 - %110 = OpLabel + %95 = OpLabel OpLine %8 31 9 - %114 = OpUDiv %u32 %108 %18 - %115 = OpIEqual %bool %18 %u32_0 + %98 = OpUDiv %u32 %93 %18 + %99 = OpIEqual %bool %18 %u32_0 OpNoLine - OpSelectionMerge %116 None - OpBranchConditional %115 %117 %118 - %117 = OpLabel + OpSelectionMerge %100 None + OpBranchConditional %99 %101 %100 + %101 = OpLabel OpLine %7 187 4 - %119 = OpExtInst %void %1 1 %6 + %102 = OpExtInst %void %1 1 %6 OpNoLine OpReturn - %118 = OpLabel - OpBranch %116 - %116 = OpLabel + %100 = OpLabel OpLine %8 31 4 - %120 = OpUDiv %u32 %114 %18 - OpStore %o %120 + %103 = OpUDiv %u32 %98 %18 + OpStore %o %103 OpNoLine OpReturn OpFunctionEnd