use std::collections::BTreeMap;
use crate::{KernelBody, KernelOp, KernelOpKind};
#[must_use]
pub(crate) fn operand_is_result_reference(kind: &KernelOpKind, pos: usize) -> bool {
use KernelOpKind::*;
match kind {
Literal => false,
LocalInvocationId | GlobalInvocationId | WorkgroupId => false,
SubgroupLocalId | SubgroupSize | LoopIndex { .. } => false,
LoopCarrierInit { .. } | LoopCarrier { .. } | LoopCarrierEnd { .. } => pos == 0,
LoadGlobal | LoadShared | LoadConstant => pos != 0,
BufferLength => false,
StoreGlobal | StoreShared => pos != 0,
Copy | BinOpKind(_) | UnOpKind(_) | Fma | MatrixMma { .. } | Select | Cast { .. } => true,
Atomic { .. } => pos != 0,
SubgroupBallot | SubgroupShuffle | SubgroupBroadcast | SubgroupReduce { .. } => true,
StructuredIfThen | StructuredIfThenElse => pos == 0,
StructuredForLoop { .. } => pos != 2,
StructuredBlock | Region { .. } => false,
Return | Barrier { .. } => false,
AsyncLoad { .. } | AsyncStore { .. } => pos >= 2,
AsyncWait { .. } => false,
Trap { .. } => pos == 0,
Resume { .. } => false,
IndirectDispatch { .. } => false,
Call { .. } => true,
OpaqueExpr(..) | OpaqueNode(..) => true,
}
}
#[must_use]
pub(crate) fn remap_body_result_ids(body: &KernelBody, id_map: &BTreeMap<u32, u32>) -> KernelBody {
let new_ops: Vec<KernelOp> = body
.ops
.iter()
.map(|op| {
let new_operands: Vec<u32> = op
.operands
.iter()
.enumerate()
.map(|(pos, val)| {
if operand_is_result_reference(&op.kind, pos) {
*id_map.get(val).unwrap_or(val)
} else {
*val
}
})
.collect();
KernelOp {
kind: op.kind.clone(),
operands: new_operands,
result: op.result.map(|r| *id_map.get(&r).unwrap_or(&r)),
}
})
.collect();
let new_children: Vec<KernelBody> = body
.child_bodies
.iter()
.map(|c| remap_body_result_ids(c, id_map))
.collect();
KernelBody {
ops: new_ops,
child_bodies: new_children,
literals: body.literals.clone(),
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::KernelOpKind;
#[test]
fn operand_classifier_separates_indices_from_result_ids() {
assert!(!operand_is_result_reference(&KernelOpKind::Literal, 0));
assert!(!operand_is_result_reference(&KernelOpKind::LoadGlobal, 0));
assert!(operand_is_result_reference(&KernelOpKind::LoadGlobal, 1));
assert!(!operand_is_result_reference(
&KernelOpKind::StructuredForLoop {
loop_var: "i".into(),
},
2,
));
assert!(operand_is_result_reference(
&KernelOpKind::StructuredForLoop {
loop_var: "i".into(),
},
1,
));
assert!(operand_is_result_reference(
&KernelOpKind::AsyncStore { tag: "copy".into() },
2,
));
assert!(!operand_is_result_reference(
&KernelOpKind::IndirectDispatch { count_offset: 0 },
0,
));
}
}