use super::*;
pub(in crate::passes) fn zero_initialize_workgroup_memory(ctx: &mut Ctx, entry_idx: usize) {
let vars: Vec<(Word, Word)> = ctx
.module
.types_global_values
.iter()
.chain(ctx.new_globals.iter())
.filter(|inst| {
inst.class.opcode == Op::Variable
&& inst.operands.first() == Some(&Operand::StorageClass(StorageClass::Workgroup))
})
.filter_map(|inst| Some((inst.result_id?, inst.result_type?)))
.collect();
if vars.is_empty() {
return;
}
let mut null_by_pointee: HashMap<Word, Word> = HashMap::new();
let mut prologue = Vec::new();
for (var, ptr_ty) in vars {
let Some(ptr_def) = type_def_of(ctx, ptr_ty) else {
continue;
};
if ptr_def.class.opcode != Op::TypePointer {
continue;
}
let Some(&Operand::IdRef(pointee)) = ptr_def.operands.get(1) else {
continue;
};
let null_id = *null_by_pointee.entry(pointee).or_insert_with(|| {
let id = ctx.module.fresh_id();
ctx.new_globals.push(Instruction::new(
Op::ConstantNull,
Some(pointee),
Some(id),
vec![],
));
id
});
prologue.push(Instruction::new(
Op::Store,
None,
None,
vec![Operand::IdRef(var), Operand::IdRef(null_id)],
));
}
if prologue.is_empty() {
return;
}
let scope = ctx.const_uint(Scope::Workgroup as u32);
let semantics = ctx
.const_uint((MemorySemantics::ACQUIRE_RELEASE | MemorySemantics::WORKGROUP_MEMORY).bits());
prologue.push(Instruction::new(
Op::ControlBarrier,
None,
None,
vec![
Operand::IdScope(scope),
Operand::IdScope(scope),
Operand::IdMemorySemantics(semantics),
],
));
let Some(block) = ctx.module.functions[entry_idx].blocks.first_mut() else {
return;
};
let insert_at = block
.instructions
.iter()
.position(|inst| inst.class.opcode != Op::Variable)
.unwrap_or(block.instructions.len());
block.instructions.splice(insert_at..insert_at, prologue);
}