mirror of
https://github.com/EmbarkStudios/rust-gpu.git
synced 2024-11-22 06:45:13 +00:00
Don't initialize vars to undef (#68)
This commit is contained in:
parent
64e0f664e0
commit
9e90652622
@ -670,7 +670,6 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
|
|||||||
pointee: ty,
|
pointee: ty,
|
||||||
}
|
}
|
||||||
.def(self);
|
.def(self);
|
||||||
let undef_ty = self.undef(ty);
|
|
||||||
// "All OpVariable instructions in a function must be the first instructions in the first block."
|
// "All OpVariable instructions in a function must be the first instructions in the first block."
|
||||||
let mut builder = self.emit();
|
let mut builder = self.emit();
|
||||||
builder.select_block(Some(0)).unwrap();
|
builder.select_block(Some(0)).unwrap();
|
||||||
@ -696,16 +695,7 @@ impl<'a, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'tcx> {
|
|||||||
Op::Variable,
|
Op::Variable,
|
||||||
Some(ptr_ty),
|
Some(ptr_ty),
|
||||||
Some(result_id),
|
Some(result_id),
|
||||||
vec![
|
vec![Operand::StorageClass(StorageClass::Function)],
|
||||||
Operand::StorageClass(StorageClass::Function),
|
|
||||||
// TODO: Always include an undef initializer, because spir-v does not specify the
|
|
||||||
// value of an uninitialized variable. So, initialize it to undef.
|
|
||||||
// See #17 for tracking spec'ing this in spir-v:
|
|
||||||
// https://github.com/EmbarkStudios/rust-gpu/issues/17
|
|
||||||
// (This also helps out linker/mem2reg.rs in some places - it gives it a handy
|
|
||||||
// source of a deduped OpUndef so it doesn't have to do that work itself)
|
|
||||||
Operand::IdRef(undef_ty.def),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
builder.insert_into_block(index, inst).unwrap();
|
builder.insert_into_block(index, inst).unwrap();
|
||||||
result_id.with_type(ptr_ty)
|
result_id.with_type(ptr_ty)
|
||||||
|
@ -170,21 +170,6 @@ impl Inliner<'_, '_> {
|
|||||||
inst_id
|
inst_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn undef_for(&mut self, ty: Word) -> Word {
|
|
||||||
// TODO: This is horribly slow, fix this
|
|
||||||
let existing = self
|
|
||||||
.types_global_values
|
|
||||||
.iter()
|
|
||||||
.find(|inst| inst.class.opcode == Op::Undef && inst.result_type.unwrap() == ty);
|
|
||||||
if let Some(existing) = existing {
|
|
||||||
return existing.result_id.unwrap();
|
|
||||||
}
|
|
||||||
let inst_id = self.id();
|
|
||||||
self.types_global_values
|
|
||||||
.push(Instruction::new(Op::Undef, Some(ty), Some(inst_id), vec![]));
|
|
||||||
inst_id
|
|
||||||
}
|
|
||||||
|
|
||||||
fn inline_fn(&mut self, function: &mut Function) {
|
fn inline_fn(&mut self, function: &mut Function) {
|
||||||
let mut block_idx = 0;
|
let mut block_idx = 0;
|
||||||
while block_idx < function.blocks.len() {
|
while block_idx < function.blocks.len() {
|
||||||
@ -267,7 +252,6 @@ impl Inliner<'_, '_> {
|
|||||||
&mut caller.blocks[0],
|
&mut caller.blocks[0],
|
||||||
self.ptr_ty(call_result_type),
|
self.ptr_ty(call_result_type),
|
||||||
return_variable.unwrap(),
|
return_variable.unwrap(),
|
||||||
self.undef_for(call_result_type),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -360,7 +344,7 @@ fn get_inlined_blocks(
|
|||||||
blocks
|
blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert_opvariable(block: &mut Block, ptr_ty: Word, result_id: Word, undef_value: Word) {
|
fn insert_opvariable(block: &mut Block, ptr_ty: Word, result_id: Word) {
|
||||||
let index = block
|
let index = block
|
||||||
.instructions
|
.instructions
|
||||||
.iter()
|
.iter()
|
||||||
@ -376,11 +360,7 @@ fn insert_opvariable(block: &mut Block, ptr_ty: Word, result_id: Word, undef_val
|
|||||||
Op::Variable,
|
Op::Variable,
|
||||||
Some(ptr_ty),
|
Some(ptr_ty),
|
||||||
Some(result_id),
|
Some(result_id),
|
||||||
vec![
|
vec![Operand::StorageClass(StorageClass::Function)],
|
||||||
Operand::StorageClass(StorageClass::Function),
|
|
||||||
// See comment in `builder_methods.rs` `alloca` for why this undef is here.
|
|
||||||
Operand::IdRef(undef_value),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
match index {
|
match index {
|
||||||
Some(index) => block.instructions.insert(index, inst),
|
Some(index) => block.instructions.insert(index, inst),
|
||||||
|
@ -17,6 +17,7 @@ use std::collections::{hash_map, HashMap, HashSet};
|
|||||||
|
|
||||||
pub fn mem2reg(
|
pub fn mem2reg(
|
||||||
header: &mut ModuleHeader,
|
header: &mut ModuleHeader,
|
||||||
|
types_global_values: &mut Vec<Instruction>,
|
||||||
pointer_to_pointee: &HashMap<Word, Word>,
|
pointer_to_pointee: &HashMap<Word, Word>,
|
||||||
constants: &HashMap<Word, u32>,
|
constants: &HashMap<Word, u32>,
|
||||||
func: &mut Function,
|
func: &mut Function,
|
||||||
@ -26,6 +27,7 @@ pub fn mem2reg(
|
|||||||
let dominance_frontier = compute_dominance_frontier(&preds, &idom);
|
let dominance_frontier = compute_dominance_frontier(&preds, &idom);
|
||||||
insert_phis_all(
|
insert_phis_all(
|
||||||
header,
|
header,
|
||||||
|
types_global_values,
|
||||||
pointer_to_pointee,
|
pointer_to_pointee,
|
||||||
constants,
|
constants,
|
||||||
&mut func.blocks,
|
&mut func.blocks,
|
||||||
@ -110,6 +112,7 @@ fn compute_dominance_frontier(preds: &[Vec<usize>], idom: &[usize]) -> Vec<HashS
|
|||||||
|
|
||||||
fn insert_phis_all(
|
fn insert_phis_all(
|
||||||
header: &mut ModuleHeader,
|
header: &mut ModuleHeader,
|
||||||
|
types_global_values: &mut Vec<Instruction>,
|
||||||
pointer_to_pointee: &HashMap<Word, Word>,
|
pointer_to_pointee: &HashMap<Word, Word>,
|
||||||
constants: &HashMap<Word, u32>,
|
constants: &HashMap<Word, u32>,
|
||||||
blocks: &mut [Block],
|
blocks: &mut [Block],
|
||||||
@ -132,6 +135,7 @@ fn insert_phis_all(
|
|||||||
let blocks_with_phi = insert_phis(blocks, &dominance_frontier, var_map);
|
let blocks_with_phi = insert_phis(blocks, &dominance_frontier, var_map);
|
||||||
let mut renamer = Renamer {
|
let mut renamer = Renamer {
|
||||||
header,
|
header,
|
||||||
|
types_global_values,
|
||||||
blocks,
|
blocks,
|
||||||
blocks_with_phi,
|
blocks_with_phi,
|
||||||
base_var_type,
|
base_var_type,
|
||||||
@ -264,8 +268,38 @@ fn insert_phis(
|
|||||||
blocks_with_phi
|
blocks_with_phi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// These can't be part of the Renamer impl due to borrowck rules.
|
||||||
|
fn undef_for(
|
||||||
|
header: &mut ModuleHeader,
|
||||||
|
types_global_values: &mut Vec<Instruction>,
|
||||||
|
ty: Word,
|
||||||
|
) -> Word {
|
||||||
|
// TODO: This is horribly slow, fix this
|
||||||
|
let existing = types_global_values
|
||||||
|
.iter()
|
||||||
|
.find(|inst| inst.class.opcode == Op::Undef && inst.result_type.unwrap() == ty);
|
||||||
|
if let Some(existing) = existing {
|
||||||
|
return existing.result_id.unwrap();
|
||||||
|
}
|
||||||
|
let inst_id = id(header);
|
||||||
|
types_global_values.push(Instruction::new(Op::Undef, Some(ty), Some(inst_id), vec![]));
|
||||||
|
inst_id
|
||||||
|
}
|
||||||
|
fn top_stack_or_undef(
|
||||||
|
header: &mut ModuleHeader,
|
||||||
|
types_global_values: &mut Vec<Instruction>,
|
||||||
|
stack: &[Word],
|
||||||
|
ty: Word,
|
||||||
|
) -> Word {
|
||||||
|
match stack.last() {
|
||||||
|
Some(&top) => top,
|
||||||
|
None => undef_for(header, types_global_values, ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Renamer<'a> {
|
struct Renamer<'a> {
|
||||||
header: &'a mut ModuleHeader,
|
header: &'a mut ModuleHeader,
|
||||||
|
types_global_values: &'a mut Vec<Instruction>,
|
||||||
blocks: &'a mut [Block],
|
blocks: &'a mut [Block],
|
||||||
blocks_with_phi: HashSet<usize>,
|
blocks_with_phi: HashSet<usize>,
|
||||||
base_var_type: Word,
|
base_var_type: Word,
|
||||||
@ -284,7 +318,12 @@ impl Renamer<'_> {
|
|||||||
let existing_phi = self.blocks[block].instructions.iter_mut().find(|inst| {
|
let existing_phi = self.blocks[block].instructions.iter_mut().find(|inst| {
|
||||||
inst.class.opcode == Op::Phi && phi_defs.contains(&inst.result_id.unwrap())
|
inst.class.opcode == Op::Phi && phi_defs.contains(&inst.result_id.unwrap())
|
||||||
});
|
});
|
||||||
let top_def = *self.stack.last().unwrap();
|
let top_def = top_stack_or_undef(
|
||||||
|
self.header,
|
||||||
|
self.types_global_values,
|
||||||
|
&self.stack,
|
||||||
|
self.base_var_type,
|
||||||
|
);
|
||||||
match existing_phi {
|
match existing_phi {
|
||||||
None => {
|
None => {
|
||||||
let new_id = id(self.header);
|
let new_id = id(self.header);
|
||||||
@ -344,7 +383,12 @@ impl Renamer<'_> {
|
|||||||
self.stack.push(val);
|
self.stack.push(val);
|
||||||
} else {
|
} else {
|
||||||
let new_id = id(self.header);
|
let new_id = id(self.header);
|
||||||
let prev_comp = *self.stack.last().unwrap();
|
let prev_comp = top_stack_or_undef(
|
||||||
|
self.header,
|
||||||
|
self.types_global_values,
|
||||||
|
&self.stack,
|
||||||
|
self.base_var_type,
|
||||||
|
);
|
||||||
let mut operands = vec![Operand::IdRef(val), Operand::IdRef(prev_comp)];
|
let mut operands = vec![Operand::IdRef(val), Operand::IdRef(prev_comp)];
|
||||||
operands
|
operands
|
||||||
.extend(var_info.indices.iter().copied().map(Operand::LiteralInt32));
|
.extend(var_info.indices.iter().copied().map(Operand::LiteralInt32));
|
||||||
@ -361,7 +405,13 @@ impl Renamer<'_> {
|
|||||||
let ptr = inst.operands[0].id_ref_any().unwrap();
|
let ptr = inst.operands[0].id_ref_any().unwrap();
|
||||||
if let Some(var_info) = self.var_map.get(&ptr) {
|
if let Some(var_info) = self.var_map.get(&ptr) {
|
||||||
let loaded_val = inst.result_id.unwrap();
|
let loaded_val = inst.result_id.unwrap();
|
||||||
let current_obj = *self.stack.last().unwrap();
|
// TODO: Should this do something more sane if it's undef?
|
||||||
|
let current_obj = top_stack_or_undef(
|
||||||
|
self.header,
|
||||||
|
self.types_global_values,
|
||||||
|
&self.stack,
|
||||||
|
self.base_var_type,
|
||||||
|
);
|
||||||
if var_info.indices.is_empty() {
|
if var_info.indices.is_empty() {
|
||||||
*inst = Instruction::new(Op::Nop, None, None, vec![]);
|
*inst = Instruction::new(Op::Nop, None, None, vec![]);
|
||||||
self.rewrite_rules.insert(loaded_val, current_obj);
|
self.rewrite_rules.insert(loaded_val, current_obj);
|
||||||
|
@ -184,6 +184,7 @@ pub fn link(sess: Option<&Session>, inputs: &mut [&mut Module], opts: &Options)
|
|||||||
// Note: mem2reg requires functions to be in RPO order (i.e. block_ordering_pass)
|
// Note: mem2reg requires functions to be in RPO order (i.e. block_ordering_pass)
|
||||||
mem2reg::mem2reg(
|
mem2reg::mem2reg(
|
||||||
output.header.as_mut().unwrap(),
|
output.header.as_mut().unwrap(),
|
||||||
|
&mut output.types_global_values,
|
||||||
&pointer_to_pointee,
|
&pointer_to_pointee,
|
||||||
&constants,
|
&constants,
|
||||||
func,
|
func,
|
||||||
|
Loading…
Reference in New Issue
Block a user