diff --git a/src/ast.rs b/src/ast.rs index d181b60..da43382 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -374,7 +374,7 @@ impl Type { Self::Void } pub fn bool() -> Type { - Self::Void + Self::Bool } pub fn comptime_number() -> Type { Self::ComptimeNumber diff --git a/src/mir.rs b/src/mir.rs index 42b080d..41a72f0 100644 --- a/src/mir.rs +++ b/src/mir.rs @@ -1,5 +1,6 @@ //! Machine-level Intermediate Representation +use std::cmp::Ordering; use std::collections::btree_map::Entry; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::fmt::Display; @@ -177,6 +178,8 @@ pub enum Inst { BitXOr(Type), /// lhs Negate(Type), + /// lhs + Not(Type), /// lhs, rhs ShiftLeft(Type), /// lhs, rhs @@ -194,6 +197,20 @@ pub enum Inst { /// lhs IsZero(Type), //FunctionStart, + /// lhs, rhs + Cmp(Type), + /// lhs + IsEq(bool), + /// lhs + IsNeq(bool), + /// lhs + IsGt(bool), + /// lhs + IsLt(bool), + /// lhs + IsGe(bool), + /// lhs + IsLe(bool), } impl Inst { @@ -211,6 +228,7 @@ impl Inst { | Inst::ConstantQWord | Inst::ConstantSinglePrecision | Inst::ConstantDoublePrecision + | Inst::Cmp(_) | Inst::Return => None, Inst::GetElementPtr(ty) | Inst::Load(ty) @@ -231,12 +249,19 @@ impl Inst { | Inst::BitOr(ty) | Inst::BitXOr(ty) | Inst::Negate(ty) + | Inst::Not(ty) | Inst::SignExtend(ty) | Inst::ZeroExtend(ty) | Inst::ShiftLeft(ty) | Inst::ShiftRightSigned(ty) | Inst::ShiftRightUnsigned(ty) => Some(*ty), - Inst::IsZero(_) => Some(Type::Byte), + Inst::IsZero(_) + | Inst::IsEq(_) + | Inst::IsNeq(_) + | Inst::IsGt(_) + | Inst::IsLt(_) + | Inst::IsGe(_) + | Inst::IsLe(_) => Some(Type::Byte), } } #[allow(dead_code)] @@ -256,6 +281,7 @@ impl Inst { | Inst::Alloca | Inst::Store(_) | Inst::ReturnValue(_) + | Inst::Cmp(_) | Inst::Return => false, Inst::GetElementPtr(_) | Inst::Load(_) @@ -276,9 +302,16 @@ impl Inst { | Inst::BitOr(_) | Inst::BitXOr(_) | Inst::Negate(_) + | Inst::Not(_) | Inst::SignExtend(_) | Inst::ZeroExtend(_) | Inst::IsZero(_) + | Inst::IsEq(_) + | Inst::IsNeq(_) + | Inst::IsGt(_) + | Inst::IsLt(_) + | Inst::IsGe(_) + | Inst::IsLe(_) | Inst::ShiftLeft(_) | Inst::ShiftRightSigned(_) | Inst::ShiftRightUnsigned(_) => true, @@ -412,7 +445,7 @@ bitflags! { } impl OperandKinds { - /// works for: add,sub,or,and,sbb,adc + /// works for: add,sub,or,and,sbb,adc,cmp fn add() -> Self { Self::RegImm | Self::MemImm | Self::RegMem | Self::MemReg | Self::RegReg } @@ -625,7 +658,7 @@ impl<'a> BinaryOperands<'a> { fn new_add_or_and_xor_adc(mir: &'a mut Mir) -> Self { Self::new(mir, true, OperandKinds::add()) } - fn new_sub_sbb(mir: &'a mut Mir) -> Self { + fn new_sub_sbb_cmp(mir: &'a mut Mir) -> Self { Self::new(mir, false, OperandKinds::add()) } fn new_sse(mir: &'a mut Mir) -> Self { @@ -753,46 +786,7 @@ impl Mir { } pub fn is_register(&self, node: u32) -> bool { - match self.nodes[node as usize] { - Inst::LoadRegister(_) - | Inst::Load(_) - | Inst::GetElementPtr(_) - | Inst::Parameter(_) - | Inst::Add(_) - | Inst::Sub(_) - | Inst::Mul(_) - | Inst::MulSigned(_) - | Inst::Div(_) - | Inst::DivSigned(_) - | Inst::Rem(_) - | Inst::RemSigned(_) - | Inst::MulSSE(_) - | Inst::DivSSE(_) - | Inst::RemFP(_) - | Inst::BitAnd(_) - | Inst::BitOr(_) - | Inst::BitXOr(_) - | Inst::Negate(_) - | Inst::SignExtend(_) - | Inst::ZeroExtend(_) - | Inst::IsZero(_) - | Inst::ShiftLeft(_) - | Inst::ShiftRightSigned(_) - | Inst::ShiftRightUnsigned(_) => true, - Inst::Label - | Inst::ConstantBytes - | Inst::ConstantByte - | Inst::ConstantWord - | Inst::ConstantDWord - | Inst::ConstantQWord - | Inst::ConstantSinglePrecision - | Inst::ConstantDoublePrecision - | Inst::ExternRef - | Inst::Alloca - | Inst::Store(_) - | Inst::ReturnValue(_) - | Inst::Return => false, - } + self.nodes[node as usize].result_is_register() } pub fn is_imm(&self, node: u32) -> bool { @@ -842,6 +836,73 @@ impl Mir { pub fn gen_is_zero(&mut self, ty: Type, src: u32) -> u32 { self.push(Inst::IsZero(ty), Data::node(src)) } + pub fn gen_cmp(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 { + let (lhs, rhs) = if ty.is_floating() { + BinaryOperands::new_sse(self).wrangle(lhs, ty, rhs, ty) + } else { + BinaryOperands::new_sub_sbb_cmp(self).wrangle(lhs, ty, rhs, ty) + }; + self.push(Inst::Cmp(ty), Data::binary(lhs, rhs)) + } + + pub fn gen_cmp_byte( + &mut self, + ty: Type, + signed: bool, + ordering: Ordering, + invert: bool, + lhs: u32, + rhs: u32, + ) -> u32 { + match ordering { + Ordering::Less => { + if invert { + self.gen_is_ge(ty, signed, lhs, rhs) + } else { + self.gen_is_lt(ty, signed, lhs, rhs) + } + } + Ordering::Equal => { + if invert { + self.gen_is_neq(ty, signed, lhs, rhs) + } else { + self.gen_is_eq(ty, signed, lhs, rhs) + } + } + Ordering::Greater => { + if invert { + self.gen_is_le(ty, signed, lhs, rhs) + } else { + self.gen_is_gt(ty, signed, lhs, rhs) + } + } + } + } + + pub fn gen_is_eq(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 { + let cmp = self.gen_cmp(ty, lhs, rhs); + self.push(Inst::IsEq(signed), Data::node(cmp)) + } + pub fn gen_is_neq(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 { + let cmp = self.gen_cmp(ty, lhs, rhs); + self.push(Inst::IsNeq(signed), Data::node(cmp)) + } + pub fn gen_is_gt(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 { + let cmp = self.gen_cmp(ty, lhs, rhs); + self.push(Inst::IsGt(signed), Data::node(cmp)) + } + pub fn gen_is_lt(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 { + let cmp = self.gen_cmp(ty, lhs, rhs); + self.push(Inst::IsLt(signed), Data::node(cmp)) + } + pub fn gen_is_ge(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 { + let cmp = self.gen_cmp(ty, lhs, rhs); + self.push(Inst::IsGe(signed), Data::node(cmp)) + } + pub fn gen_is_le(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 { + let cmp = self.gen_cmp(ty, lhs, rhs); + self.push(Inst::IsLe(signed), Data::node(cmp)) + } pub fn gen_load_register(&mut self, ty: Type, src: u32) -> u32 { self.push(Inst::LoadRegister(ty), Data::node(src)) } @@ -910,7 +971,7 @@ impl Mir { // 1111_1111 << 4 = 1111_0000 // mask = 0000_1111; // shift = 8 - 4; - let src_ty = self.type_of_node(src).unwrap(); + let src_ty = Type::from_bitsize_int(from.bits as u32); let truncated = self.gen_truncate_integer(src, src_ty, from.signed, from.bits); let dst_ty = Type::from_bitsize_int(to.bits as u32); @@ -942,7 +1003,7 @@ impl Mir { let (lhs, rhs) = if ty.is_floating() { BinaryOperands::new_sse(self).wrangle(lhs, ty, rhs, ty) } else { - BinaryOperands::new_sub_sbb(self).wrangle(lhs, ty, rhs, ty) + BinaryOperands::new_sub_sbb_cmp(self).wrangle(lhs, ty, rhs, ty) }; self.push(Inst::Sub(ty), Data::binary(lhs, rhs)) } @@ -1027,6 +1088,10 @@ impl Mir { let src = self.imm_to_reg(src); self.push(Inst::Negate(ty), Data::node(src)) } + pub fn gen_not(&mut self, ty: Type, src: u32) -> u32 { + let src = self.imm_to_reg(src); + self.push(Inst::Not(ty), Data::node(src)) + } #[doc(alias = "gen_shift_left")] pub fn gen_shl(&mut self, ty: Type, src: u32, shift: u32) -> u32 { @@ -1171,6 +1236,10 @@ impl Mir { let lhs = data.as_node(); writeln!(w, "%{node} = negate {ty} %{lhs}") } + Inst::Not(ty) => { + let lhs = data.as_node(); + writeln!(w, "%{node} = bitwise not {ty} %{lhs}") + } Inst::SignExtend(ty) => { let lhs = data.as_node(); writeln!(w, "%{node} = sign extend {ty} %{lhs}") @@ -1183,6 +1252,34 @@ impl Mir { let lhs = data.as_node(); writeln!(w, "%{node} = is zero {ty} %{lhs}") } + Inst::Cmp(ty) => { + let (lhs, rhs) = data.as_binary(); + writeln!(w, "%{node} = cmp {ty} %{lhs} {ty} %{rhs}") + } + Inst::IsEq(ty) => { + let lhs = data.as_node(); + writeln!(w, "%{node} = is eq %{lhs}") + } + Inst::IsNeq(ty) => { + let lhs = data.as_node(); + writeln!(w, "%{node} = is neq %{lhs}") + } + Inst::IsGt(ty) => { + let lhs = data.as_node(); + writeln!(w, "%{node} = is gt %{lhs}") + } + Inst::IsLt(ty) => { + let lhs = data.as_node(); + writeln!(w, "%{node} = is lt %{lhs}") + } + Inst::IsGe(ty) => { + let lhs = data.as_node(); + writeln!(w, "%{node} = is ge %{lhs}") + } + Inst::IsLe(ty) => { + let lhs = data.as_node(); + writeln!(w, "%{node} = is le %{lhs}") + } Inst::ShiftLeft(ty) => { let (lhs, rhs) = data.as_binary(); writeln!(w, "%{node} = shift left {ty} %{lhs}, {ty} %{rhs}") @@ -1445,12 +1542,20 @@ pub mod liveness { | Inst::SignExtend(_) | Inst::ZeroExtend(_) | Inst::Negate(_) + | Inst::Not(_) | Inst::IsZero(_) + | Inst::IsEq(_) + | Inst::IsNeq(_) + | Inst::IsGt(_) + | Inst::IsGe(_) + | Inst::IsLt(_) + | Inst::IsLe(_) | Inst::Load(_) | Inst::LoadRegister(_) => { references.insert((data.as_noderef(), node)); } - Inst::Store(_) + Inst::Cmp(_) + | Inst::Store(_) | Inst::Add(_) | Inst::Sub(_) | Inst::Mul(_) @@ -1641,7 +1746,7 @@ impl Mir { let (lhs, _) = data.as_binary_noderefs(); Some(lhs) } - Inst::Negate(_) => { + Inst::Not(_) | Inst::Negate(_) => { let lhs = data.as_noderef(); Some(lhs) } @@ -1670,6 +1775,13 @@ impl Mir { | Inst::DivSigned(_) | Inst::Rem(_) | Inst::RemSigned(_) + | Inst::Cmp(_) + | Inst::IsEq(_) + | Inst::IsNeq(_) + | Inst::IsGt(_) + | Inst::IsLt(_) + | Inst::IsGe(_) + | Inst::IsLe(_) | Inst::IsZero(_) => None, } } @@ -1978,6 +2090,7 @@ impl Mir { | Inst::BitOr(ty) | Inst::BitXOr(ty) | Inst::Negate(ty) + | Inst::Not(ty) | Inst::ShiftLeft(ty) | Inst::ShiftRightSigned(ty) | Inst::ShiftRightUnsigned(ty) @@ -1988,6 +2101,16 @@ impl Mir { | Inst::LoadRegister(ty) => ty .register_width(liveness.get_register(node.into()).unwrap()) .into(), + Inst::IsEq(_) + | Inst::IsGt(_) + | Inst::IsLt(_) + | Inst::IsGe(_) + | Inst::IsLe(_) + | Inst::IsNeq(_) => liveness + .get_register(node.into()) + .unwrap() + .into_byte() + .into(), Inst::Alloca => { let (offset, size) = *mapping.get(&(node as usize)).unwrap(); ImmRegMem::Mem(StackMem::new(offset, size)) @@ -2775,6 +2898,16 @@ impl Mir { writeln!(func.current_branch(), "mov {dst}, {lhs}")?; } } + Inst::Not(ty) => { + let dst = ty.register_width(liveness.get_register(node.into()).unwrap()); + let lhs = data.as_node(); + let lhs = self.node_as_operand(&liveness, &mapping, &mut func, strings, lhs); + writeln!(func.current_branch(), "not {lhs}")?; + + if !lhs.occupy_same_register(dst) { + writeln!(func.current_branch(), "mov {dst}, {lhs}")?; + } + } Inst::Negate(ty) => { let dst = ty.register_width(liveness.get_register(node.into()).unwrap()); let lhs = data.as_node(); @@ -2904,6 +3037,38 @@ impl Mir { } } } + Inst::Cmp(ty) => { + let (lhs, rhs) = data.as_binary(); + let lhs = self.node_as_operand(&liveness, &mapping, &mut func, strings, lhs); + let rhs = self.node_as_operand(&liveness, &mapping, &mut func, strings, rhs); + + if ty.is_floating() { + writeln!(func.current_branch(), "comiss {lhs}, {rhs}")?; + } else { + writeln!(func.current_branch(), "cmp {lhs}, {rhs}")?; + } + } + Inst::IsEq(signed) + | Inst::IsNeq(signed) + | Inst::IsGt(signed) + | Inst::IsLt(signed) + | Inst::IsGe(signed) + | Inst::IsLe(signed) => { + let dst = liveness.get_register(node.into()).unwrap().into_byte(); + + #[cfg_attr(rustfmt, rustfmt::skip)] + let mnemonic = match inst { + Inst::IsEq(_) => "sete", + Inst::IsNeq(_) => "setne", + Inst::IsGt(_) => if signed {"setg"} else {"seta"}, + Inst::IsLt(_) => if signed {"setl"} else {"setb"}, + Inst::IsGe(_) => if signed {"setge"} else {"setae"}, + Inst::IsLe(_) => if signed {"setle"} else {"setbe"}, + _ => unreachable!(), + }; + + writeln!(func.current_branch(), "{mnemonic} {dst}")?; + } Inst::IsZero(ty) => { let dst = ty.register_width(liveness.get_register(node.into()).unwrap()); let lhs = data.as_node(); @@ -2916,13 +3081,17 @@ impl Mir { let lhs = data.as_node(); let lhs = self.node_as_operand(&liveness, &mapping, &mut func, strings, lhs); if ty.is_floating() { - writeln!(func.current_branch(), "movss xmm0, {lhs}",)?; + if !lhs.occupy_same_register(Register::xmm0) { + writeln!(func.current_branch(), "movss xmm0, {lhs}",)?; + } } else { - writeln!( - func.current_branch(), - "mov {}, {lhs}", - Register::rax.into_bytesize(lhs.byte_width()) - )?; + if !lhs.occupy_same_register(Register::rax) { + writeln!( + func.current_branch(), + "mov {}, {lhs}", + Register::rax.into_bytesize(lhs.byte_width()) + )?; + } } writeln!(func.current_branch(), "jmp {name}__epilogue")?; } diff --git a/src/triples.rs b/src/triples.rs index 0c2adce..9a80acb 100644 --- a/src/triples.rs +++ b/src/triples.rs @@ -1,6 +1,9 @@ #![allow(dead_code)] -use std::collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap}; +use std::{ + cmp::Ordering, + collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap}, +}; use crate::{ ast::{IntegralType, Node as AstNode, Tag, Type}, @@ -154,6 +157,20 @@ pub enum Inst { /// lhs Negate(Type2), /// lhs + Not(Type2), + /// lhs, rhs + Eq(Type2), + /// lhs, rhs + Neq(Type2), + /// lhs, rhs + Gt(Type2), + /// lhs, rhs + Lt(Type2), + /// lhs, rhs + Ge(Type2), + /// lhs, rhs + Le(Type2), + /// lhs ExplicitCast(Type2, Type2), /// lhs ReturnValue(Type2), @@ -290,7 +307,8 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { } fn visit(&mut self, node: AstNode) -> Node { - match &self.tree.nodes[node].clone() { + let tag = &self.tree.nodes[node].clone(); + match tag { Tag::FunctionDecl { proto, body } => { variant!( Tag::FunctionProto { @@ -424,6 +442,36 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { self.ir .push(Inst::BitXOr(ty.into()), Some(Data::new(lhs, rhs))) } + Tag::Lt { lhs, rhs } + | Tag::Ge { lhs, rhs } + | Tag::Le { lhs, rhs } + | Tag::Eq { lhs, rhs } + | Tag::NEq { lhs, rhs } + | Tag::Gt { lhs, rhs } => { + let ty = self + .tree + .peer_type_of_nodes(*lhs, *rhs) + .expect({ + let at = self.tree.type_of_node(*lhs); + let bt = self.tree.type_of_node(*rhs); + &format!("incompatible types for %{lhs}({at}) and %{rhs}({bt})") + }) + .into(); + + let inst = match tag { + Tag::Eq { .. } => Inst::Eq(ty), + Tag::NEq { .. } => Inst::Neq(ty), + Tag::Gt { .. } => Inst::Gt(ty), + Tag::Lt { .. } => Inst::Lt(ty), + Tag::Ge { .. } => Inst::Ge(ty), + Tag::Le { .. } => Inst::Le(ty), + _ => unreachable!(), + }; + + let lhs = self.visit(*lhs); + let rhs = self.visit(*rhs); + self.ir.push(inst, Some(Data::new(lhs, rhs))) + } Tag::Mul { lhs, rhs } => { let ty = self.tree.type_of_node(node); let lhs = self.visit(*lhs); @@ -436,6 +484,11 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { let lhs = self.visit(*lhs); self.ir.push(Inst::Negate(ty.into()), Some(Data::lhs(lhs))) } + Tag::Not { lhs } => { + let ty = self.tree.type_of_node(node); + let lhs = self.visit(*lhs); + self.ir.push(Inst::Not(ty.into()), Some(Data::lhs(lhs))) + } Tag::Shl { lhs, rhs } => { let ty = self.tree.type_of_node(node); let lhs = self.visit(*lhs); @@ -578,6 +631,30 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { let (lhs, rhs) = data.as_lhs_rhs(); writeln_indented!(indent, w, "%{} = sub_{ty}(%{} - %{})", node, lhs, rhs)?; } + Inst::Eq(ty) => { + let (lhs, rhs) = data.as_lhs_rhs(); + writeln_indented!(indent, w, "%{} = eq_{ty}(%{} - %{})", node, lhs, rhs)?; + } + Inst::Neq(ty) => { + let (lhs, rhs) = data.as_lhs_rhs(); + writeln_indented!(indent, w, "%{} = neq_{ty}(%{} - %{})", node, lhs, rhs)?; + } + Inst::Gt(ty) => { + let (lhs, rhs) = data.as_lhs_rhs(); + writeln_indented!(indent, w, "%{} = gt_{ty}(%{} - %{})", node, lhs, rhs)?; + } + Inst::Lt(ty) => { + let (lhs, rhs) = data.as_lhs_rhs(); + writeln_indented!(indent, w, "%{} = lt_{ty}(%{} - %{})", node, lhs, rhs)?; + } + Inst::Ge(ty) => { + let (lhs, rhs) = data.as_lhs_rhs(); + writeln_indented!(indent, w, "%{} = ge_{ty}(%{} - %{})", node, lhs, rhs)?; + } + Inst::Le(ty) => { + let (lhs, rhs) = data.as_lhs_rhs(); + writeln_indented!(indent, w, "%{} = le_{ty}(%{} - %{})", node, lhs, rhs)?; + } Inst::Mul(ty) => { let (lhs, rhs) = data.as_lhs_rhs(); writeln_indented!(indent, w, "%{} = mul_{ty}(%{} * %{})", node, lhs, rhs)?; @@ -585,6 +662,9 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> { Inst::Negate(ty) => { writeln_indented!(indent, w, "%{} = negate_{ty}(%{})", node, data.lhs)?; } + Inst::Not(ty) => { + writeln_indented!(indent, w, "%{} = bitwise_not_{ty}(%{})", node, data.lhs)?; + } Inst::ExplicitCast(from, to) => { writeln_indented!(indent, w, "%{} = cast_{from}_to_{to}(%{})", node, data.lhs)?; } @@ -1170,6 +1250,12 @@ impl<'a> Assembler<'a> { allocas.insert(node, stack_offset); registers.insert(param_reg, node); } + Inst::Eq(ty) + | Inst::Neq(ty) + | Inst::Gt(ty) + | Inst::Lt(ty) + | Inst::Ge(ty) + | Inst::Le(ty) => {} Inst::Add(ty) => { let (src, dst) = data.unwrap().as_lhs_rhs(); let (&src_reg, _) = registers.iter().find(|(_, node)| node == &&src).unwrap(); @@ -1255,6 +1341,7 @@ impl<'a> Assembler<'a> { Inst::BitOr(_) => todo!(), Inst::BitXOr(_) => todo!(), Inst::Negate(_) => todo!(), + Inst::Not(_) => todo!(), Inst::ExplicitCast(_, _) => todo!(), Inst::ReturnValue(_) => { let val = data.unwrap().lhs; @@ -1411,6 +1498,29 @@ impl<'a> MirBuilder<'a> { // let (size, _) = data.unwrap().as_lhs_rhs(); mir.gen_param(ty.into()) } + Inst::Eq(ty) + | Inst::Neq(ty) + | Inst::Gt(ty) + | Inst::Lt(ty) + | Inst::Ge(ty) + | Inst::Le(ty) => { + let (src, dst) = data.unwrap().as_lhs_rhs(); + let lhs = *mapping.get(&src).unwrap(); + let rhs = *mapping.get(&dst).unwrap(); + + #[cfg_attr(rustfmt, rustfmt::skip)] + let (ord, invert)= match inst { + Inst::Eq(_) => (Ordering::Equal, false), + Inst::Neq(_) => (Ordering::Equal, true), + Inst::Gt(_) => (Ordering::Greater, false), + Inst::Le(_) => (Ordering::Greater, true), + Inst::Lt(_) => (Ordering::Less, false), + Inst::Ge(_) => (Ordering::Less, true), + _ => unreachable!(), + }; + + mir.gen_cmp_byte(ty.mir_type(), ty.is_signed(), ord, invert, lhs, rhs) + } Inst::Add(ty) => { let (src, dst) = data.unwrap().as_lhs_rhs(); let lhs = *mapping.get(&src).unwrap(); @@ -1629,6 +1739,21 @@ impl<'a> MirBuilder<'a> { _ => unreachable!(), } } + Inst::Not(ty) => { + let lhs = data.unwrap().as_u32(); + + let unalignment = ty.mir_unalignment(); + let ty = ty.mir_type(); + + let lhs = *mapping.get(&lhs).unwrap(); + + let sum = mir.gen_not(ty, lhs); + if let Some((signed, bits)) = unalignment { + mir.gen_truncate_integer(sum, ty, signed, bits) + } else { + sum + } + } Inst::Negate(ty) => { let lhs = data.unwrap().as_u32();