diff --git a/src/frontend.rs b/src/frontend.rs index a2f1e43..9268a6c 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -189,7 +189,8 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { | Operator::Call { .. } | Operator::LocalGet { .. } | Operator::LocalSet { .. } - | Operator::LocalTee { .. } => self.emit(op.clone())?, + | Operator::LocalTee { .. } + | Operator::I32Eqz => self.emit(op.clone())?, Operator::End => match self.ctrl_stack.pop() { None => { @@ -409,7 +410,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { fn emit_branch(&mut self, target: BlockId, args: &[ValueId]) { if let Some(block) = self.cur_block { - let args = args.iter().map(|&val| Operand::Value(val)).collect(); + let args = args.iter().map(|&val| Operand::value(val)).collect(); let target = BlockTarget { block: target, args, @@ -429,14 +430,14 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { if let Some(block) = self.cur_block { let if_true_args = if_true_args .iter() - .map(|&val| Operand::Value(val)) + .map(|&val| Operand::value(val)) .collect(); let if_false_args = if_false_args .iter() - .map(|&val| Operand::Value(val)) + .map(|&val| Operand::value(val)) .collect(); self.body.blocks[block].terminator = Terminator::CondBr { - cond: Operand::Value(cond), + cond: Operand::value(cond), if_true: BlockTarget { block: if_true, args: if_true_args, @@ -457,7 +458,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { args: &[ValueId], ) { if let Some(block) = self.cur_block { - let args: Vec> = args.iter().map(|&arg| Operand::Value(arg)).collect(); + let args: Vec> = args.iter().map(|&arg| Operand::value(arg)).collect(); let targets = indexed_targets .iter() .map(|&block| BlockTarget { @@ -470,7 +471,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { args: args.clone(), }; self.body.blocks[block].terminator = Terminator::Select { - value: Operand::Value(index), + value: Operand::value(index), targets, default, }; @@ -500,7 +501,7 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { { let stack_top = self.op_stack.pop().unwrap(); assert_eq!(self.body.values[stack_top].ty, input); - inputs.push(Operand::Value(stack_top)); + inputs.push(Operand::value(stack_top)); } inputs.reverse(); @@ -520,6 +521,13 @@ impl<'a, 'b> FunctionBodyBuilder<'a, 'b> { outputs, inputs, }); + } else { + let _ = self + .op_stack + .split_off(op_inputs(self.module, self.my_sig, &self.body.locals[..], &op)?.len()); + for _ in 0..op_outputs(self.module, &self.body.locals[..], &op)?.len() { + self.op_stack.push(NO_VALUE); + } } Ok(()) diff --git a/src/ir.rs b/src/ir.rs index eac9af7..fa7576e 100644 --- a/src/ir.rs +++ b/src/ir.rs @@ -8,6 +8,8 @@ pub type BlockId = usize; pub type InstId = usize; pub type ValueId = usize; +pub const NO_VALUE: ValueId = usize::MAX; + #[derive(Clone, Debug, Default)] pub struct Module<'a> { pub funcs: Vec>, @@ -64,8 +66,23 @@ pub struct Inst<'a> { #[derive(Clone, Debug)] pub enum Operand<'a> { + /// An SSA value. Value(ValueId), + /// Tree-ified instructions for Wasm emission. Sub(Box>), + /// Undef values are produced when code is unreachable and thus + /// removed/never executed. + Undef, +} + +impl<'a> Operand<'a> { + pub fn value(value: ValueId) -> Self { + if value == NO_VALUE { + Operand::Undef + } else { + Operand::Value(value) + } + } } #[derive(Clone, Debug)] diff --git a/src/op_traits.rs b/src/op_traits.rs index c0930bd..91cc2a8 100644 --- a/src/op_traits.rs +++ b/src/op_traits.rs @@ -24,6 +24,9 @@ pub fn op_inputs( } &Operator::LocalGet { .. } => Ok(vec![]), + &Operator::I32Eqz => Ok(vec![Type::I32]), + &Operator::I32Eq => Ok(vec![Type::I32, Type::I32]), + _ => bail!("Unknown operator in op_inputs(): {:?}", op), } } @@ -40,6 +43,8 @@ pub fn op_outputs(module: &Module, my_locals: &[Type], op: &Operator<'_>) -> Res &Operator::LocalSet { .. } | &Operator::LocalTee { .. } => Ok(vec![]), &Operator::LocalGet { local_index } => Ok(vec![my_locals[local_index as usize]]), + &Operator::I32Eqz | &Operator::I32Eq => Ok(vec![Type::I32]), + _ => bail!("Unknown operator in op_outputs(): {:?}", op), } }