From 503a2a50617c8da2d1355ea3f84c35d81ca57950 Mon Sep 17 00:00:00 2001 From: molikto Date: Tue, 17 May 2022 10:53:51 +0800 Subject: [PATCH 01/10] warn when inline(never) is not respected --- .../rustc_codegen_spirv/src/linker/inline.rs | 20 +++++++++++++++++++ tests/ui/lang/consts/nested-ref.stderr | 6 ++++++ 2 files changed, 26 insertions(+) create mode 100644 tests/ui/lang/consts/nested-ref.stderr diff --git a/crates/rustc_codegen_spirv/src/linker/inline.rs b/crates/rustc_codegen_spirv/src/linker/inline.rs index c8ec854504..9da4873957 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline.rs @@ -35,8 +35,12 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { // Drop all the functions we'll be inlining. (This also means we won't waste time processing // inlines in functions that will get inlined) let mut dropped_ids = FxHashSet::default(); + let mut inlined_dont_inlines = Vec::new(); module.functions.retain(|f| { if should_inline(&disallowed_argument_types, &disallowed_return_types, f) { + if has_dont_inline(f) { + inlined_dont_inlines.push(f.def_id().unwrap()); + } // TODO: We should insert all defined IDs in this function. dropped_ids.insert(f.def_id().unwrap()); false @@ -44,6 +48,16 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { true } }); + if !inlined_dont_inlines.is_empty() { + let names = get_names(module); + for f in inlined_dont_inlines { + sess.warn(&format!( + "function `{}` has `dont_inline` attribute, but need to be inlined because it has illegal argument or return types", + get_name(&names, f) + )); + } + } + // Drop OpName etc. for inlined functions module.debug_names.retain(|inst| { !inst.operands.iter().any(|op| { @@ -204,6 +218,12 @@ fn compute_disallowed_argument_and_return_types( (disallowed_argument_types, disallowed_return_types) } +fn has_dont_inline(function: &Function) -> bool { + let def = function.def.as_ref().unwrap(); + let control = def.operands[0].unwrap_function_control(); + control.contains(FunctionControl::DONT_INLINE) +} + fn should_inline( disallowed_argument_types: &FxHashSet, disallowed_return_types: &FxHashSet, diff --git a/tests/ui/lang/consts/nested-ref.stderr b/tests/ui/lang/consts/nested-ref.stderr new file mode 100644 index 0000000000..e1718942f2 --- /dev/null +++ b/tests/ui/lang/consts/nested-ref.stderr @@ -0,0 +1,6 @@ +warning: function `nested_ref::deep_load` has `dont_inline` attribute, but need to be inlined because it has illegal argument or return types + +warning: function `nested_ref::deep_transpose` has `dont_inline` attribute, but need to be inlined because it has illegal argument or return types + +warning: 2 warnings emitted + From af7c91c13356b90c590992a749a280e5aac2d6ee Mon Sep 17 00:00:00 2001 From: molikto Date: Mon, 4 Apr 2022 15:35:49 +0800 Subject: [PATCH 02/10] inline globals! --- .../rustc_codegen_spirv/src/linker/inline.rs | 8 +- .../src/linker/inline_globals.rs | 259 ++++++++++++++++++ crates/rustc_codegen_spirv/src/linker/mod.rs | 24 +- tests/ui/arch/inline_global.rs | 14 + 4 files changed, 302 insertions(+), 3 deletions(-) create mode 100644 crates/rustc_codegen_spirv/src/linker/inline_globals.rs create mode 100644 tests/ui/arch/inline_global.rs diff --git a/crates/rustc_codegen_spirv/src/linker/inline.rs b/crates/rustc_codegen_spirv/src/linker/inline.rs index 9da4873957..b6ae3d8d09 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline.rs @@ -231,12 +231,16 @@ fn should_inline( ) -> bool { let def = function.def.as_ref().unwrap(); let control = def.operands[0].unwrap_function_control(); - control.contains(FunctionControl::INLINE) + let should = control.contains(FunctionControl::INLINE) || function .parameters .iter() .any(|inst| disallowed_argument_types.contains(inst.result_type.as_ref().unwrap())) - || disallowed_return_types.contains(&function.def.as_ref().unwrap().result_type.unwrap()) + || disallowed_return_types.contains(&function.def.as_ref().unwrap().result_type.unwrap()); + // if should && control.contains(FunctionControl::DONT_INLINE) { + // println!("should not be inlined!"); + // } + should } // This should be more general, but a very common problem is passing an OpAccessChain to an diff --git a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs new file mode 100644 index 0000000000..1b178fd54a --- /dev/null +++ b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs @@ -0,0 +1,259 @@ +use rspirv::binary::Disassemble; +use rspirv::dr::{Instruction, Module, Operand}; +use rspirv::spirv::Op; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_session::Session; + +#[derive(Debug, Clone, PartialEq)] +enum FunctionArg { + Invalid, + Insts(Vec), +} + +pub fn inline_global_varaibles(sess: &Session, module: &mut Module) -> super::Result<()> { + let mut i = 0; + let mut cont = true; + std::fs::write("res0.txt", module.disassemble()); + while cont { + cont = inline_global_varaibles_rec(sess, module)?; + i += 1; + std::fs::write(format!("res{}.txt", i), module.disassemble()); + } + Ok(()) +} + +fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Result { + // first collect global stuff + let mut variables: FxHashSet = FxHashSet::default(); + let mut function_types: FxHashMap = FxHashMap::default(); + for global_inst in &module.types_global_values { + let opcode = global_inst.class.opcode; + if opcode == Op::Variable || opcode == Op::Constant { + variables.insert(global_inst.result_id.unwrap()); + } else if opcode == Op::TypeFunction { + function_types.insert(global_inst.result_id.unwrap(), global_inst.clone()); + } + } + // then we keep track of which function parameter are always called with the same expression that only uses global variables + let mut function_args: FxHashMap<(u32, u32), FunctionArg> = FxHashMap::default(); + for caller in &module.functions { + let mut insts: FxHashMap = FxHashMap::default(); + for block in &caller.blocks { + for inst in &block.instructions { + if inst.result_id.is_some() { + insts.insert(inst.result_id.unwrap(), inst.clone()); + } + if inst.class.opcode == Op::FunctionCall { + let function_id = match &inst.operands[0] { + &Operand::IdRef(w) => w, + _ => panic!(), + }; + for i in 1..inst.operands.len() { + let key = (function_id, i as u32 - 1); + match &inst.operands[i] { + &Operand::IdRef(w) => match &function_args.get(&key) { + None => match get_const_arg_insts(&variables, &insts, w) { + Some(insts) => { + function_args.insert(key, FunctionArg::Insts(insts)); + } + None => { + function_args.insert(key, FunctionArg::Invalid); + } + }, + Some(FunctionArg::Insts(w2)) => { + let new_insts = get_const_arg_insts(&variables, &insts, w); + match new_insts { + Some(new_insts) => { + if new_insts != *w2 { + function_args.insert(key, FunctionArg::Invalid); + } + } + None => { + function_args.insert(key, FunctionArg::Invalid); + } + } + } + _ => { + function_args.insert(key, FunctionArg::Invalid); + } + }, + _ => { + function_args.insert(key, FunctionArg::Invalid); + } + }; + } + } + } + } + } + function_args.retain(|_, k| match k { + FunctionArg::Invalid => false, + FunctionArg::Insts(v) => !v.is_empty(), + }); + if function_args.is_empty() { + return Ok(false); + } + let mut bound = module.header.as_ref().unwrap().bound; + for function in &mut module.functions { + let def = function.def.as_mut().unwrap(); + let fid = def.result_id.unwrap(); + let mut insts: Vec = Vec::new(); + let mut j: u32 = 0; + let mut i = 0; + let mut removed_indexes: Vec = Vec::new(); + // callee side. remove parameters from function def + while i < function.parameters.len() { + let mut removed = false; + match &function_args.get(&(fid, j)) { + Some(FunctionArg::Insts(arg)) => { + let parameter = function.parameters.remove(i); + let mut arg = arg.clone(); + arg.reverse(); + insts_replacing_captured_ids(&mut arg, &mut bound); + let index = arg.len() - 1; + arg[index].result_id = parameter.result_id; + insts.extend(arg); + removed_indexes.push(j); + removed = true; + } + _ => (), + } + if !removed { + i += 1; + } + j += 1; + } + // callee side. and add a new function type in global section + if removed_indexes.len() > 0 { + if let Operand::IdRef(tid) = def.operands[1] { + let mut function_type: Instruction = function_types.get(&tid).unwrap().clone(); + let tid: u32 = bound; + bound += 1; + for i in removed_indexes.iter().rev() { + let i = *i as usize + 1; + function_type.operands.remove(i); + function_type.result_id = Some(tid); + } + def.operands[1] = Operand::IdRef(tid); + module.types_global_values.push(function_type); + } + } + // callee side. insert initialization instructions, which reuse the ids of the removed parameters + if !function.blocks.is_empty() { + let first_block = &mut function.blocks[0]; + // skip some instructions that must be at top of block + let mut i = 0; + loop { + if i >= first_block.instructions.len() { + break; + } + let inst = &first_block.instructions[i]; + if inst.class.opcode == Op::Label || inst.class.opcode == Op::Variable { + } else { + break; + } + i += 1; + } + first_block.instructions.splice(i..i, insts); + } + // caller side, remove parameters from function call + for block in &mut function.blocks { + for inst in &mut block.instructions { + if inst.class.opcode == Op::FunctionCall { + let function_id = match &inst.operands[0] { + &Operand::IdRef(w) => w, + _ => panic!(), + }; + let mut removed_size = 0; + for i in 0..inst.operands.len() - 1 { + if function_args.contains_key(&(function_id, i as u32)) { + inst.operands.remove(i - removed_size + 1); + removed_size += 1; + } + } + } + } + } + } + if let Some(header) = &mut module.header { + header.bound = bound; + } + Ok(true) +} + +fn insts_replacing_captured_ids(arg: &mut Vec, bound: &mut u32) { + let mut id_map: FxHashMap = FxHashMap::default(); + for ins in arg { + if let Some(id) = &mut ins.result_id { + for op in &mut ins.operands { + match op { + Operand::IdRef(id) => match id_map.get(id) { + Some(new_id) => { + *id = *new_id; + } + _ => {} + }, + _ => {} + } + } + id_map.insert(*id, *bound); + *id = *bound; + *bound += 1; + } + } +} + +fn get_const_arg_operands( + variables: &FxHashSet, + insts: &FxHashMap, + operand: &Operand, +) -> Option> { + match operand { + Operand::IdRef(id) => { + let insts = get_const_arg_insts(variables, insts, *id)?; + return Some(insts); + } + Operand::LiteralInt32(_) => {}, + Operand::LiteralInt64(_) => {}, + Operand::LiteralFloat32(_) => {}, + Operand::LiteralFloat64(_) => {}, + Operand::LiteralExtInstInteger(_) => {}, + Operand::LiteralSpecConstantOpInteger(_) => {}, + Operand::LiteralString(_) => {}, + _ => { + // TOOD add more cases + return None; + } + } + return Some(Vec::new()); +} + +fn get_const_arg_insts( + variables: &FxHashSet, + insts: &FxHashMap, + id: u32, +) -> Option> { + let mut result: Vec = Vec::new(); + if variables.contains(&id) { + return Some(result); + } + let par: &Instruction = insts.get(&id)?; + if par.class.opcode == Op::AccessChain { + result.push(par.clone()); + for oprand in &par.operands { + let insts = get_const_arg_operands(variables, insts, oprand)?; + result.extend(insts); + } + } else if par.class.opcode == Op::FunctionCall { + result.push(par.clone()); + // skip first, first is function id + for oprand in &par.operands[1..] { + let insts = get_const_arg_operands(variables, insts, oprand)?; + result.extend(insts); + } + } else { + // TOOD add more cases + return None; + } + Some(result) +} diff --git a/crates/rustc_codegen_spirv/src/linker/mod.rs b/crates/rustc_codegen_spirv/src/linker/mod.rs index 5df298dd5d..26d2f19fe2 100644 --- a/crates/rustc_codegen_spirv/src/linker/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/mod.rs @@ -6,6 +6,8 @@ mod destructure_composites; mod duplicates; mod entry_interface; mod import_export_link; +mod simpl_op_store_var; +mod inline_globals; mod inline; mod ipo; mod mem2reg; @@ -20,7 +22,7 @@ use std::borrow::Cow; use crate::codegen_cx::SpirvMetadata; use crate::decorations::{CustomDecoration, UnrollLoopsDecoration}; -use rspirv::binary::{Assemble, Consumer}; +use rspirv::binary::{Assemble, Consumer, Disassemble}; use rspirv::dr::{Block, Instruction, Loader, Module, ModuleHeader, Operand}; use rspirv::spirv::{Op, StorageClass, Word}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; @@ -152,6 +154,7 @@ pub fn link(sess: &Session, mut inputs: Vec, opts: &Options) -> Result, opts: &Options) -> Result, opts: &Options) -> Result, opts: &Options) -> Result f32{ + (con[1] - con[0]) as f32 +} + +#[spirv(fragment)] +pub fn main( + #[spirv(descriptor_set = 0, binding = 0, storage_buffer)] runtime_array: &mut [u32], +) { + sdf(runtime_array); +} From 213843e326b7e00bba0d2eec07f9a3eba460580f Mon Sep 17 00:00:00 2001 From: molikto Date: Tue, 5 Apr 2022 12:14:05 +0800 Subject: [PATCH 03/10] fix: support load store indirection --- .../src/linker/inline_globals.rs | 211 +++++++++++++----- crates/rustc_codegen_spirv/src/linker/mod.rs | 17 +- 2 files changed, 163 insertions(+), 65 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs index 1b178fd54a..54f7f647d8 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs @@ -1,13 +1,80 @@ use rspirv::binary::Disassemble; use rspirv::dr::{Instruction, Module, Operand}; -use rspirv::spirv::Op; +use rspirv::spirv::{Op, StorageClass}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_session::Session; +// bool is if this needs stored +#[derive(Debug, Clone, PartialEq)] +struct NormalizedInstructions { + vars: Vec, + insts: Vec, + root: u32, +} + +impl NormalizedInstructions { + fn new(id: u32) -> Self { + NormalizedInstructions { + vars: Vec::new(), + insts: Vec::new(), + root: id, + } + } + + fn extend(&mut self, o: NormalizedInstructions) { + self.vars.extend(o.vars); + self.insts.extend(o.insts); + } + + fn is_empty(&self) -> bool { + self.insts.is_empty() && self.vars.is_empty() + } + + fn fix_ids(&mut self, bound: &mut u32, new_root: u32) { + let mut id_map: FxHashMap = FxHashMap::default(); + id_map.insert(self.root, new_root); + for inst in &mut self.vars { + Self::fix_instruction(self.root, inst, &mut id_map, bound, new_root); + } + for inst in &mut self.insts { + Self::fix_instruction(self.root, inst, &mut id_map, bound, new_root); + } + } + + fn fix_instruction( + root: u32, + inst: &mut Instruction, + id_map: &mut FxHashMap, + bound: &mut u32, + new_root: u32, + ) { + for op in &mut inst.operands { + match op { + Operand::IdRef(id) => match id_map.get(id) { + Some(new_id) => { + *id = *new_id; + } + _ => {} + }, + _ => {} + } + } + if let Some(id) = &mut inst.result_id { + if *id != root { + id_map.insert(*id, *bound); + *id = *bound; + *bound += 1; + } else { + *id = new_root; + } + } + } +} + #[derive(Debug, Clone, PartialEq)] enum FunctionArg { Invalid, - Insts(Vec), + Insts(NormalizedInstructions), } pub fn inline_global_varaibles(sess: &Session, module: &mut Module) -> super::Result<()> { @@ -36,14 +103,30 @@ fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Re } // then we keep track of which function parameter are always called with the same expression that only uses global variables let mut function_args: FxHashMap<(u32, u32), FunctionArg> = FxHashMap::default(); + let mut bound = module.header.as_ref().unwrap().bound; for caller in &module.functions { let mut insts: FxHashMap = FxHashMap::default(); + // for variables that only stored once and it's stored as a ref + let mut ref_stores: FxHashMap> = FxHashMap::default(); for block in &caller.blocks { for inst in &block.instructions { if inst.result_id.is_some() { insts.insert(inst.result_id.unwrap(), inst.clone()); } - if inst.class.opcode == Op::FunctionCall { + if inst.class.opcode == Op::Store { + if let Operand::IdRef(to) = inst.operands[0] { + if let Operand::IdRef(from) = inst.operands[1] { + match ref_stores.get(&to) { + None => { + ref_stores.insert(to, Some(from)); + } + Some(_) => { + ref_stores.insert(to, None); + } + } + } + } + } else if inst.class.opcode == Op::FunctionCall { let function_id = match &inst.operands[0] { &Operand::IdRef(w) => w, _ => panic!(), @@ -52,16 +135,19 @@ fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Re let key = (function_id, i as u32 - 1); match &inst.operands[i] { &Operand::IdRef(w) => match &function_args.get(&key) { - None => match get_const_arg_insts(&variables, &insts, w) { - Some(insts) => { - function_args.insert(key, FunctionArg::Insts(insts)); - } - None => { - function_args.insert(key, FunctionArg::Invalid); + None => { + match get_const_arg_insts(bound, &variables, &insts, &ref_stores, w) { + Some(insts) => { + function_args.insert(key, FunctionArg::Insts(insts)); + } + None => { + function_args.insert(key, FunctionArg::Invalid); + } } - }, + } Some(FunctionArg::Insts(w2)) => { - let new_insts = get_const_arg_insts(&variables, &insts, w); + let new_insts = + get_const_arg_insts(bound, &variables, &insts, &ref_stores, w); match new_insts { Some(new_insts) => { if new_insts != *w2 { @@ -93,11 +179,10 @@ fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Re if function_args.is_empty() { return Ok(false); } - let mut bound = module.header.as_ref().unwrap().bound; for function in &mut module.functions { let def = function.def.as_mut().unwrap(); let fid = def.result_id.unwrap(); - let mut insts: Vec = Vec::new(); + let mut insts = NormalizedInstructions::new(0); let mut j: u32 = 0; let mut i = 0; let mut removed_indexes: Vec = Vec::new(); @@ -108,10 +193,7 @@ fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Re Some(FunctionArg::Insts(arg)) => { let parameter = function.parameters.remove(i); let mut arg = arg.clone(); - arg.reverse(); - insts_replacing_captured_ids(&mut arg, &mut bound); - let index = arg.len() - 1; - arg[index].result_id = parameter.result_id; + arg.fix_ids(&mut bound, parameter.result_id.unwrap()); insts.extend(arg); removed_indexes.push(j); removed = true; @@ -132,8 +214,8 @@ fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Re for i in removed_indexes.iter().rev() { let i = *i as usize + 1; function_type.operands.remove(i); - function_type.result_id = Some(tid); } + function_type.result_id = Some(tid); def.operands[1] = Operand::IdRef(tid); module.types_global_values.push(function_type); } @@ -141,6 +223,7 @@ fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Re // callee side. insert initialization instructions, which reuse the ids of the removed parameters if !function.blocks.is_empty() { let first_block = &mut function.blocks[0]; + first_block.instructions.splice(0..0, insts.vars); // skip some instructions that must be at top of block let mut i = 0; loop { @@ -154,7 +237,7 @@ fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Re } i += 1; } - first_block.instructions.splice(i..i, insts); + first_block.instructions.splice(i..i, insts.insts); } // caller side, remove parameters from function call for block in &mut function.blocks { @@ -181,76 +264,90 @@ fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Re Ok(true) } -fn insts_replacing_captured_ids(arg: &mut Vec, bound: &mut u32) { - let mut id_map: FxHashMap = FxHashMap::default(); - for ins in arg { - if let Some(id) = &mut ins.result_id { - for op in &mut ins.operands { - match op { - Operand::IdRef(id) => match id_map.get(id) { - Some(new_id) => { - *id = *new_id; - } - _ => {} - }, - _ => {} - } - } - id_map.insert(*id, *bound); - *id = *bound; - *bound += 1; - } - } -} - fn get_const_arg_operands( variables: &FxHashSet, insts: &FxHashMap, + ref_stores: &FxHashMap>, operand: &Operand, -) -> Option> { +) -> Option { match operand { Operand::IdRef(id) => { - let insts = get_const_arg_insts(variables, insts, *id)?; + let insts = get_const_arg_insts_rec(variables, insts, ref_stores, *id)?; return Some(insts); } - Operand::LiteralInt32(_) => {}, - Operand::LiteralInt64(_) => {}, - Operand::LiteralFloat32(_) => {}, - Operand::LiteralFloat64(_) => {}, - Operand::LiteralExtInstInteger(_) => {}, - Operand::LiteralSpecConstantOpInteger(_) => {}, - Operand::LiteralString(_) => {}, + Operand::LiteralInt32(_) => {} + Operand::LiteralInt64(_) => {} + Operand::LiteralFloat32(_) => {} + Operand::LiteralFloat64(_) => {} + Operand::LiteralExtInstInteger(_) => {} + Operand::LiteralSpecConstantOpInteger(_) => {} + Operand::LiteralString(_) => {} _ => { // TOOD add more cases return None; } } - return Some(Vec::new()); + return Some(NormalizedInstructions::new(0)); } fn get_const_arg_insts( + mut bound: u32, + variables: &FxHashSet, + insts: &FxHashMap, + ref_stores: &FxHashMap>, + id: u32, +) -> Option { + let mut res = get_const_arg_insts_rec(variables, insts, ref_stores, id)?; + res.insts.reverse(); + // the bound passed in is always the same + // we need to normalize the ids, so they are the same when compared + let fake_root = bound; + bound += 1; + res.fix_ids(&mut bound, fake_root); + res.root = fake_root; + Some(res) +} + +fn get_const_arg_insts_rec( variables: &FxHashSet, insts: &FxHashMap, + ref_stores: &FxHashMap>, id: u32, -) -> Option> { - let mut result: Vec = Vec::new(); +) -> Option { + let mut result = NormalizedInstructions::new(id); if variables.contains(&id) { return Some(result); } let par: &Instruction = insts.get(&id)?; if par.class.opcode == Op::AccessChain { - result.push(par.clone()); + result.insts.push(par.clone()); for oprand in &par.operands { - let insts = get_const_arg_operands(variables, insts, oprand)?; + let insts = get_const_arg_operands(variables, insts, ref_stores, oprand)?; result.extend(insts); } } else if par.class.opcode == Op::FunctionCall { - result.push(par.clone()); + result.insts.push(par.clone()); // skip first, first is function id for oprand in &par.operands[1..] { - let insts = get_const_arg_operands(variables, insts, oprand)?; + let insts = get_const_arg_operands(variables, insts, ref_stores, oprand)?; result.extend(insts); } + } else if par.class.opcode == Op::Variable { + result.vars.push(par.clone()); + let stored = ref_stores.get(&id)?; + let stored = (*stored)?; + result.insts.push(Instruction::new( + Op::Store, + None, + None, + vec![Operand::IdRef(id), Operand::IdRef(stored)], + )); + let new_insts = get_const_arg_insts_rec(variables, insts, ref_stores, stored)?; + result.extend(new_insts); + } else if par.class.opcode == Op::ArrayLength { + result.insts.push(par.clone()); + let insts = get_const_arg_operands(variables, insts, ref_stores, &par.operands[0])?; + result.extend(insts); } else { // TOOD add more cases return None; diff --git a/crates/rustc_codegen_spirv/src/linker/mod.rs b/crates/rustc_codegen_spirv/src/linker/mod.rs index 26d2f19fe2..b1e11e3645 100644 --- a/crates/rustc_codegen_spirv/src/linker/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/mod.rs @@ -220,19 +220,20 @@ pub fn link(sess: &Session, mut inputs: Vec, opts: &Options) -> Result, opts: &Options) -> Result Date: Tue, 5 Apr 2022 12:18:28 +0800 Subject: [PATCH 04/10] fix: warns --- .../rustc_codegen_spirv/src/linker/inline.rs | 51 ++++++++----------- .../src/linker/inline_globals.rs | 4 +- crates/rustc_codegen_spirv/src/linker/mod.rs | 2 - 3 files changed, 22 insertions(+), 35 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/linker/inline.rs b/crates/rustc_codegen_spirv/src/linker/inline.rs index b6ae3d8d09..904dc565e8 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline.rs @@ -10,7 +10,6 @@ use super::{get_name, get_names}; use rspirv::dr::{Block, Function, Instruction, Module, ModuleHeader, Operand}; use rspirv::spirv::{FunctionControl, Op, StorageClass, Word}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_errors::ErrorGuaranteed; use rustc_session::Session; use std::mem::take; @@ -18,8 +17,9 @@ type FunctionMap = FxHashMap; pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { // This algorithm gets real sad if there's recursion - but, good news, SPIR-V bans recursion - deny_recursion_in_module(sess, module)?; - + if module_has_recursion(sess, module) { + return Err(rustc_errors::ErrorReported); + } let functions = module .functions .iter() @@ -35,11 +35,13 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { // Drop all the functions we'll be inlining. (This also means we won't waste time processing // inlines in functions that will get inlined) let mut dropped_ids = FxHashSet::default(); - let mut inlined_dont_inlines = Vec::new(); module.functions.retain(|f| { if should_inline(&disallowed_argument_types, &disallowed_return_types, f) { if has_dont_inline(f) { - inlined_dont_inlines.push(f.def_id().unwrap()); + sess.warn(&format!( + "Function `{}` has `dont_inline` attribute, but need to be inlined because it has illegal argument or return types", + get_name(&get_names(module), f.def_id().unwrap()) + )); } // TODO: We should insert all defined IDs in this function. dropped_ids.insert(f.def_id().unwrap()); @@ -48,16 +50,6 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { true } }); - if !inlined_dont_inlines.is_empty() { - let names = get_names(module); - for f in inlined_dont_inlines { - sess.warn(&format!( - "function `{}` has `dont_inline` attribute, but need to be inlined because it has illegal argument or return types", - get_name(&names, f) - )); - } - } - // Drop OpName etc. for inlined functions module.debug_names.retain(|inst| { !inst.operands.iter().any(|op| { @@ -81,7 +73,7 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { } // https://stackoverflow.com/a/53995651 -fn deny_recursion_in_module(sess: &Session, module: &Module) -> super::Result<()> { +fn module_has_recursion(sess: &Session, module: &Module) -> bool { let func_to_index: FxHashMap = module .functions .iter() @@ -90,7 +82,7 @@ fn deny_recursion_in_module(sess: &Session, module: &Module) -> super::Result<() .collect(); let mut discovered = vec![false; module.functions.len()]; let mut finished = vec![false; module.functions.len()]; - let mut has_recursion = None; + let mut has_recursion = false; for index in 0..module.functions.len() { if !discovered[index] && !finished[index] { visit( @@ -111,7 +103,7 @@ fn deny_recursion_in_module(sess: &Session, module: &Module) -> super::Result<() current: usize, discovered: &mut Vec, finished: &mut Vec, - has_recursion: &mut Option, + has_recursion: &mut bool, func_to_index: &FxHashMap, ) { discovered[current] = true; @@ -121,10 +113,11 @@ fn deny_recursion_in_module(sess: &Session, module: &Module) -> super::Result<() let names = get_names(module); let current_name = get_name(&names, module.functions[current].def_id().unwrap()); let next_name = get_name(&names, module.functions[next].def_id().unwrap()); - *has_recursion = Some(sess.err(&format!( + sess.err(&format!( "module has recursion, which is not allowed: `{}` calls `{}`", current_name, next_name - ))); + )); + *has_recursion = true; break; } @@ -158,10 +151,7 @@ fn deny_recursion_in_module(sess: &Session, module: &Module) -> super::Result<() }) } - match has_recursion { - Some(err) => Err(err), - None => Ok(()), - } + has_recursion } fn compute_disallowed_argument_and_return_types( @@ -218,12 +208,15 @@ fn compute_disallowed_argument_and_return_types( (disallowed_argument_types, disallowed_return_types) } -fn has_dont_inline(function: &Function) -> bool { +fn has_dont_inline( + function: &Function, +) -> bool { let def = function.def.as_ref().unwrap(); let control = def.operands[0].unwrap_function_control(); control.contains(FunctionControl::DONT_INLINE) } + fn should_inline( disallowed_argument_types: &FxHashSet, disallowed_return_types: &FxHashSet, @@ -231,16 +224,12 @@ fn should_inline( ) -> bool { let def = function.def.as_ref().unwrap(); let control = def.operands[0].unwrap_function_control(); - let should = control.contains(FunctionControl::INLINE) + control.contains(FunctionControl::INLINE) || function .parameters .iter() .any(|inst| disallowed_argument_types.contains(inst.result_type.as_ref().unwrap())) - || disallowed_return_types.contains(&function.def.as_ref().unwrap().result_type.unwrap()); - // if should && control.contains(FunctionControl::DONT_INLINE) { - // println!("should not be inlined!"); - // } - should + || disallowed_return_types.contains(&function.def.as_ref().unwrap().result_type.unwrap()) } // This should be more general, but a very common problem is passing an OpAccessChain to an diff --git a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs index 54f7f647d8..959f2f91fd 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs @@ -80,11 +80,11 @@ enum FunctionArg { pub fn inline_global_varaibles(sess: &Session, module: &mut Module) -> super::Result<()> { let mut i = 0; let mut cont = true; - std::fs::write("res0.txt", module.disassemble()); + //std::fs::write("res0.txt", module.disassemble()); while cont { cont = inline_global_varaibles_rec(sess, module)?; i += 1; - std::fs::write(format!("res{}.txt", i), module.disassemble()); + //std::fs::write(format!("res{}.txt", i), module.disassemble()); } Ok(()) } diff --git a/crates/rustc_codegen_spirv/src/linker/mod.rs b/crates/rustc_codegen_spirv/src/linker/mod.rs index b1e11e3645..eeba6c72b7 100644 --- a/crates/rustc_codegen_spirv/src/linker/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/mod.rs @@ -321,8 +321,6 @@ pub fn link(sess: &Session, mut inputs: Vec, opts: &Options) -> Result Date: Tue, 5 Apr 2022 12:22:54 +0800 Subject: [PATCH 05/10] refactor --- crates/rustc_codegen_spirv/src/linker/inline_globals.rs | 9 +++++++++ crates/rustc_codegen_spirv/src/linker/mod.rs | 6 ------ 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs index 959f2f91fd..7ca2894a89 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs @@ -80,12 +80,19 @@ enum FunctionArg { pub fn inline_global_varaibles(sess: &Session, module: &mut Module) -> super::Result<()> { let mut i = 0; let mut cont = true; + let mut has_run = false; //std::fs::write("res0.txt", module.disassemble()); while cont { cont = inline_global_varaibles_rec(sess, module)?; + has_run = has_run || cont; i += 1; //std::fs::write(format!("res{}.txt", i), module.disassemble()); } + // needed because inline global create duplicate types... + if has_run { + let _timer = sess.timer("link_remove_duplicate_types_round_2"); + super::duplicates::remove_duplicate_types(&mut module); + } Ok(()) } @@ -172,6 +179,7 @@ fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Re } } } + // retain ones can rewrite function_args.retain(|_, k| match k { FunctionArg::Invalid => false, FunctionArg::Insts(v) => !v.is_empty(), @@ -179,6 +187,7 @@ fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Re if function_args.is_empty() { return Ok(false); } + // start rewrite for function in &mut module.functions { let def = function.def.as_mut().unwrap(); let fid = def.result_id.unwrap(); diff --git a/crates/rustc_codegen_spirv/src/linker/mod.rs b/crates/rustc_codegen_spirv/src/linker/mod.rs index eeba6c72b7..7cfd84b3be 100644 --- a/crates/rustc_codegen_spirv/src/linker/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/mod.rs @@ -230,12 +230,6 @@ pub fn link(sess: &Session, mut inputs: Vec, opts: &Options) -> Result Date: Tue, 5 Apr 2022 12:24:07 +0800 Subject: [PATCH 06/10] remove wrong code --- crates/rustc_codegen_spirv/src/linker/mod.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/linker/mod.rs b/crates/rustc_codegen_spirv/src/linker/mod.rs index 7cfd84b3be..12c25ba728 100644 --- a/crates/rustc_codegen_spirv/src/linker/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/mod.rs @@ -6,7 +6,6 @@ mod destructure_composites; mod duplicates; mod entry_interface; mod import_export_link; -mod simpl_op_store_var; mod inline_globals; mod inline; mod ipo; @@ -22,7 +21,7 @@ use std::borrow::Cow; use crate::codegen_cx::SpirvMetadata; use crate::decorations::{CustomDecoration, UnrollLoopsDecoration}; -use rspirv::binary::{Assemble, Consumer, Disassemble}; +use rspirv::binary::{Assemble, Consumer}; use rspirv::dr::{Block, Instruction, Loader, Module, ModuleHeader, Operand}; use rspirv::spirv::{Op, StorageClass, Word}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; From 4bf2f9b5d08555978f4c8cebaeeba78404cd81f1 Mon Sep 17 00:00:00 2001 From: molikto Date: Tue, 5 Apr 2022 12:50:20 +0800 Subject: [PATCH 07/10] fixes --- .../rustc_codegen_spirv/src/linker/inline.rs | 21 +++++++----- .../src/linker/inline_globals.rs | 9 +++--- crates/rustc_codegen_spirv/src/linker/mod.rs | 6 ---- tests/ui/dis/index_user_dst.stderr | 32 ++----------------- tests/ui/dis/ptr_read.stderr | 2 +- tests/ui/dis/ptr_read_method.stderr | 2 +- tests/ui/lang/consts/nested-ref.stderr | 4 +-- tests/ui/{arch => lang}/inline_global.rs | 0 8 files changed, 23 insertions(+), 53 deletions(-) rename tests/ui/{arch => lang}/inline_global.rs (100%) diff --git a/crates/rustc_codegen_spirv/src/linker/inline.rs b/crates/rustc_codegen_spirv/src/linker/inline.rs index 904dc565e8..5fd1eb891a 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline.rs @@ -35,13 +35,11 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { // Drop all the functions we'll be inlining. (This also means we won't waste time processing // inlines in functions that will get inlined) let mut dropped_ids = FxHashSet::default(); + let mut inlined_dont_inlines = Vec::new(); module.functions.retain(|f| { if should_inline(&disallowed_argument_types, &disallowed_return_types, f) { if has_dont_inline(f) { - sess.warn(&format!( - "Function `{}` has `dont_inline` attribute, but need to be inlined because it has illegal argument or return types", - get_name(&get_names(module), f.def_id().unwrap()) - )); + inlined_dont_inlines.push(f.def_id().unwrap()); } // TODO: We should insert all defined IDs in this function. dropped_ids.insert(f.def_id().unwrap()); @@ -50,6 +48,16 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { true } }); + if !inlined_dont_inlines.is_empty() { + let names = get_names(module); + for f in inlined_dont_inlines { + sess.warn(&format!( + "Function `{}` has `dont_inline` attribute, but need to be inlined because it has illegal argument or return types", + get_name(&names, f) + )); + } + } + // Drop OpName etc. for inlined functions module.debug_names.retain(|inst| { !inst.operands.iter().any(|op| { @@ -208,15 +216,12 @@ fn compute_disallowed_argument_and_return_types( (disallowed_argument_types, disallowed_return_types) } -fn has_dont_inline( - function: &Function, -) -> bool { +fn has_dont_inline(function: &Function) -> bool { let def = function.def.as_ref().unwrap(); let control = def.operands[0].unwrap_function_control(); control.contains(FunctionControl::DONT_INLINE) } - fn should_inline( disallowed_argument_types: &FxHashSet, disallowed_return_types: &FxHashSet, diff --git a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs index 7ca2894a89..5e92a330be 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs @@ -1,6 +1,5 @@ -use rspirv::binary::Disassemble; use rspirv::dr::{Instruction, Module, Operand}; -use rspirv::spirv::{Op, StorageClass}; +use rspirv::spirv::{Op}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_session::Session; @@ -83,7 +82,7 @@ pub fn inline_global_varaibles(sess: &Session, module: &mut Module) -> super::Re let mut has_run = false; //std::fs::write("res0.txt", module.disassemble()); while cont { - cont = inline_global_varaibles_rec(sess, module)?; + cont = inline_global_varaibles_rec(module)?; has_run = has_run || cont; i += 1; //std::fs::write(format!("res{}.txt", i), module.disassemble()); @@ -91,12 +90,12 @@ pub fn inline_global_varaibles(sess: &Session, module: &mut Module) -> super::Re // needed because inline global create duplicate types... if has_run { let _timer = sess.timer("link_remove_duplicate_types_round_2"); - super::duplicates::remove_duplicate_types(&mut module); + super::duplicates::remove_duplicate_types(module); } Ok(()) } -fn inline_global_varaibles_rec(sess: &Session, module: &mut Module) -> super::Result { +fn inline_global_varaibles_rec(module: &mut Module) -> super::Result { // first collect global stuff let mut variables: FxHashSet = FxHashSet::default(); let mut function_types: FxHashMap = FxHashMap::default(); diff --git a/crates/rustc_codegen_spirv/src/linker/mod.rs b/crates/rustc_codegen_spirv/src/linker/mod.rs index 12c25ba728..5fd0ad0f05 100644 --- a/crates/rustc_codegen_spirv/src/linker/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/mod.rs @@ -218,12 +218,6 @@ pub fn link(sess: &Session, mut inputs: Vec, opts: &Options) -> Result Date: Tue, 5 Apr 2022 13:19:31 +0800 Subject: [PATCH 08/10] refactor --- .../src/linker/inline_globals.rs | 29 ++++++++----------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs index 5e92a330be..59bfa13626 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs @@ -3,7 +3,6 @@ use rspirv::spirv::{Op}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_session::Session; -// bool is if this needs stored #[derive(Debug, Clone, PartialEq)] struct NormalizedInstructions { vars: Vec, @@ -38,6 +37,7 @@ impl NormalizedInstructions { for inst in &mut self.insts { Self::fix_instruction(self.root, inst, &mut id_map, bound, new_root); } + self.root = new_root; } fn fix_instruction( @@ -139,16 +139,17 @@ fn inline_global_varaibles_rec(module: &mut Module) -> super::Result { }; for i in 1..inst.operands.len() { let key = (function_id, i as u32 - 1); + // default to invalid to avoid duplicated code + let mut is_invalid = true; match &inst.operands[i] { &Operand::IdRef(w) => match &function_args.get(&key) { None => { match get_const_arg_insts(bound, &variables, &insts, &ref_stores, w) { Some(insts) => { + is_invalid = false; function_args.insert(key, FunctionArg::Insts(insts)); } - None => { - function_args.insert(key, FunctionArg::Invalid); - } + None => {} } } Some(FunctionArg::Insts(w2)) => { @@ -156,23 +157,18 @@ fn inline_global_varaibles_rec(module: &mut Module) -> super::Result { get_const_arg_insts(bound, &variables, &insts, &ref_stores, w); match new_insts { Some(new_insts) => { - if new_insts != *w2 { - function_args.insert(key, FunctionArg::Invalid); - } - } - None => { - function_args.insert(key, FunctionArg::Invalid); + is_invalid = new_insts != *w2; } + None => {} } } - _ => { - function_args.insert(key, FunctionArg::Invalid); - } + _ => {} }, - _ => { - function_args.insert(key, FunctionArg::Invalid); - } + _ => {} }; + if is_invalid { + function_args.insert(key, FunctionArg::Invalid); + } } } } @@ -312,7 +308,6 @@ fn get_const_arg_insts( let fake_root = bound; bound += 1; res.fix_ids(&mut bound, fake_root); - res.root = fake_root; Some(res) } From 815161d958526827b656b3bea19ceea5330ae33e Mon Sep 17 00:00:00 2001 From: molikto Date: Tue, 5 Apr 2022 13:21:56 +0800 Subject: [PATCH 09/10] comment debug code --- crates/rustc_codegen_spirv/src/linker/inline_globals.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs index 59bfa13626..707e765901 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs @@ -77,14 +77,14 @@ enum FunctionArg { } pub fn inline_global_varaibles(sess: &Session, module: &mut Module) -> super::Result<()> { - let mut i = 0; let mut cont = true; let mut has_run = false; + //let mut i = 0; //std::fs::write("res0.txt", module.disassemble()); while cont { cont = inline_global_varaibles_rec(module)?; has_run = has_run || cont; - i += 1; + // i += 1; //std::fs::write(format!("res{}.txt", i), module.disassemble()); } // needed because inline global create duplicate types... From d31bb5f393e6b988abbab05d5da3c1d8a69b7d45 Mon Sep 17 00:00:00 2001 From: molikto Date: Tue, 17 May 2022 11:01:41 +0800 Subject: [PATCH 10/10] cleanup --- .../rustc_codegen_spirv/src/linker/inline.rs | 24 ++++++------ .../src/linker/inline_globals.rs | 37 ++++++++++++------- crates/rustc_codegen_spirv/src/linker/mod.rs | 4 +- tests/ui/lang/consts/nested-ref.stderr | 4 +- 4 files changed, 40 insertions(+), 29 deletions(-) diff --git a/crates/rustc_codegen_spirv/src/linker/inline.rs b/crates/rustc_codegen_spirv/src/linker/inline.rs index 5fd1eb891a..9da4873957 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline.rs @@ -10,6 +10,7 @@ use super::{get_name, get_names}; use rspirv::dr::{Block, Function, Instruction, Module, ModuleHeader, Operand}; use rspirv::spirv::{FunctionControl, Op, StorageClass, Word}; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::ErrorGuaranteed; use rustc_session::Session; use std::mem::take; @@ -17,9 +18,8 @@ type FunctionMap = FxHashMap; pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { // This algorithm gets real sad if there's recursion - but, good news, SPIR-V bans recursion - if module_has_recursion(sess, module) { - return Err(rustc_errors::ErrorReported); - } + deny_recursion_in_module(sess, module)?; + let functions = module .functions .iter() @@ -52,7 +52,7 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { let names = get_names(module); for f in inlined_dont_inlines { sess.warn(&format!( - "Function `{}` has `dont_inline` attribute, but need to be inlined because it has illegal argument or return types", + "function `{}` has `dont_inline` attribute, but need to be inlined because it has illegal argument or return types", get_name(&names, f) )); } @@ -81,7 +81,7 @@ pub fn inline(sess: &Session, module: &mut Module) -> super::Result<()> { } // https://stackoverflow.com/a/53995651 -fn module_has_recursion(sess: &Session, module: &Module) -> bool { +fn deny_recursion_in_module(sess: &Session, module: &Module) -> super::Result<()> { let func_to_index: FxHashMap = module .functions .iter() @@ -90,7 +90,7 @@ fn module_has_recursion(sess: &Session, module: &Module) -> bool { .collect(); let mut discovered = vec![false; module.functions.len()]; let mut finished = vec![false; module.functions.len()]; - let mut has_recursion = false; + let mut has_recursion = None; for index in 0..module.functions.len() { if !discovered[index] && !finished[index] { visit( @@ -111,7 +111,7 @@ fn module_has_recursion(sess: &Session, module: &Module) -> bool { current: usize, discovered: &mut Vec, finished: &mut Vec, - has_recursion: &mut bool, + has_recursion: &mut Option, func_to_index: &FxHashMap, ) { discovered[current] = true; @@ -121,11 +121,10 @@ fn module_has_recursion(sess: &Session, module: &Module) -> bool { let names = get_names(module); let current_name = get_name(&names, module.functions[current].def_id().unwrap()); let next_name = get_name(&names, module.functions[next].def_id().unwrap()); - sess.err(&format!( + *has_recursion = Some(sess.err(&format!( "module has recursion, which is not allowed: `{}` calls `{}`", current_name, next_name - )); - *has_recursion = true; + ))); break; } @@ -159,7 +158,10 @@ fn module_has_recursion(sess: &Session, module: &Module) -> bool { }) } - has_recursion + match has_recursion { + Some(err) => Err(err), + None => Ok(()), + } } fn compute_disallowed_argument_and_return_types( diff --git a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs index 707e765901..ab712ba11e 100644 --- a/crates/rustc_codegen_spirv/src/linker/inline_globals.rs +++ b/crates/rustc_codegen_spirv/src/linker/inline_globals.rs @@ -1,5 +1,5 @@ use rspirv::dr::{Instruction, Module, Operand}; -use rspirv::spirv::{Op}; +use rspirv::spirv::Op; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_session::Session; @@ -47,17 +47,17 @@ impl NormalizedInstructions { bound: &mut u32, new_root: u32, ) { - for op in &mut inst.operands { - match op { - Operand::IdRef(id) => match id_map.get(id) { - Some(new_id) => { - *id = *new_id; - } - _ => {} - }, + for op in &mut inst.operands { + match op { + Operand::IdRef(id) => match id_map.get(id) { + Some(new_id) => { + *id = *new_id; + } _ => {} - } + }, + _ => {} } + } if let Some(id) = &mut inst.result_id { if *id != root { id_map.insert(*id, *bound); @@ -144,7 +144,13 @@ fn inline_global_varaibles_rec(module: &mut Module) -> super::Result { match &inst.operands[i] { &Operand::IdRef(w) => match &function_args.get(&key) { None => { - match get_const_arg_insts(bound, &variables, &insts, &ref_stores, w) { + match get_const_arg_insts( + bound, + &variables, + &insts, + &ref_stores, + w, + ) { Some(insts) => { is_invalid = false; function_args.insert(key, FunctionArg::Insts(insts)); @@ -153,8 +159,13 @@ fn inline_global_varaibles_rec(module: &mut Module) -> super::Result { } } Some(FunctionArg::Insts(w2)) => { - let new_insts = - get_const_arg_insts(bound, &variables, &insts, &ref_stores, w); + let new_insts = get_const_arg_insts( + bound, + &variables, + &insts, + &ref_stores, + w, + ); match new_insts { Some(new_insts) => { is_invalid = new_insts != *w2; diff --git a/crates/rustc_codegen_spirv/src/linker/mod.rs b/crates/rustc_codegen_spirv/src/linker/mod.rs index 5fd0ad0f05..d9f896ac0b 100644 --- a/crates/rustc_codegen_spirv/src/linker/mod.rs +++ b/crates/rustc_codegen_spirv/src/linker/mod.rs @@ -6,8 +6,8 @@ mod destructure_composites; mod duplicates; mod entry_interface; mod import_export_link; -mod inline_globals; mod inline; +mod inline_globals; mod ipo; mod mem2reg; mod param_weakening; @@ -153,7 +153,6 @@ pub fn link(sess: &Session, mut inputs: Vec, opts: &Options) -> Result, opts: &Options) -> Result