boolean arithmetic

This commit is contained in:
Janis 2024-08-30 19:31:44 +02:00
parent cbc416dcaa
commit 48bbcdec5e
3 changed files with 350 additions and 56 deletions

View file

@ -374,7 +374,7 @@ impl Type {
Self::Void Self::Void
} }
pub fn bool() -> Type { pub fn bool() -> Type {
Self::Void Self::Bool
} }
pub fn comptime_number() -> Type { pub fn comptime_number() -> Type {
Self::ComptimeNumber Self::ComptimeNumber

View file

@ -1,5 +1,6 @@
//! Machine-level Intermediate Representation //! Machine-level Intermediate Representation
use std::cmp::Ordering;
use std::collections::btree_map::Entry; use std::collections::btree_map::Entry;
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet}; use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
use std::fmt::Display; use std::fmt::Display;
@ -177,6 +178,8 @@ pub enum Inst {
BitXOr(Type), BitXOr(Type),
/// lhs /// lhs
Negate(Type), Negate(Type),
/// lhs
Not(Type),
/// lhs, rhs /// lhs, rhs
ShiftLeft(Type), ShiftLeft(Type),
/// lhs, rhs /// lhs, rhs
@ -194,6 +197,20 @@ pub enum Inst {
/// lhs /// lhs
IsZero(Type), IsZero(Type),
//FunctionStart, //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 { impl Inst {
@ -211,6 +228,7 @@ impl Inst {
| Inst::ConstantQWord | Inst::ConstantQWord
| Inst::ConstantSinglePrecision | Inst::ConstantSinglePrecision
| Inst::ConstantDoublePrecision | Inst::ConstantDoublePrecision
| Inst::Cmp(_)
| Inst::Return => None, | Inst::Return => None,
Inst::GetElementPtr(ty) Inst::GetElementPtr(ty)
| Inst::Load(ty) | Inst::Load(ty)
@ -231,12 +249,19 @@ impl Inst {
| Inst::BitOr(ty) | Inst::BitOr(ty)
| Inst::BitXOr(ty) | Inst::BitXOr(ty)
| Inst::Negate(ty) | Inst::Negate(ty)
| Inst::Not(ty)
| Inst::SignExtend(ty) | Inst::SignExtend(ty)
| Inst::ZeroExtend(ty) | Inst::ZeroExtend(ty)
| Inst::ShiftLeft(ty) | Inst::ShiftLeft(ty)
| Inst::ShiftRightSigned(ty) | Inst::ShiftRightSigned(ty)
| Inst::ShiftRightUnsigned(ty) => Some(*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)] #[allow(dead_code)]
@ -256,6 +281,7 @@ impl Inst {
| Inst::Alloca | Inst::Alloca
| Inst::Store(_) | Inst::Store(_)
| Inst::ReturnValue(_) | Inst::ReturnValue(_)
| Inst::Cmp(_)
| Inst::Return => false, | Inst::Return => false,
Inst::GetElementPtr(_) Inst::GetElementPtr(_)
| Inst::Load(_) | Inst::Load(_)
@ -276,9 +302,16 @@ impl Inst {
| Inst::BitOr(_) | Inst::BitOr(_)
| Inst::BitXOr(_) | Inst::BitXOr(_)
| Inst::Negate(_) | Inst::Negate(_)
| Inst::Not(_)
| Inst::SignExtend(_) | Inst::SignExtend(_)
| Inst::ZeroExtend(_) | Inst::ZeroExtend(_)
| Inst::IsZero(_) | Inst::IsZero(_)
| Inst::IsEq(_)
| Inst::IsNeq(_)
| Inst::IsGt(_)
| Inst::IsLt(_)
| Inst::IsGe(_)
| Inst::IsLe(_)
| Inst::ShiftLeft(_) | Inst::ShiftLeft(_)
| Inst::ShiftRightSigned(_) | Inst::ShiftRightSigned(_)
| Inst::ShiftRightUnsigned(_) => true, | Inst::ShiftRightUnsigned(_) => true,
@ -412,7 +445,7 @@ bitflags! {
} }
impl OperandKinds { impl OperandKinds {
/// works for: add,sub,or,and,sbb,adc /// works for: add,sub,or,and,sbb,adc,cmp
fn add() -> Self { fn add() -> Self {
Self::RegImm | Self::MemImm | Self::RegMem | Self::MemReg | Self::RegReg 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 { fn new_add_or_and_xor_adc(mir: &'a mut Mir) -> Self {
Self::new(mir, true, OperandKinds::add()) 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()) Self::new(mir, false, OperandKinds::add())
} }
fn new_sse(mir: &'a mut Mir) -> Self { fn new_sse(mir: &'a mut Mir) -> Self {
@ -753,46 +786,7 @@ impl Mir {
} }
pub fn is_register(&self, node: u32) -> bool { pub fn is_register(&self, node: u32) -> bool {
match self.nodes[node as usize] { self.nodes[node as usize].result_is_register()
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,
}
} }
pub fn is_imm(&self, node: u32) -> bool { 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 { pub fn gen_is_zero(&mut self, ty: Type, src: u32) -> u32 {
self.push(Inst::IsZero(ty), Data::node(src)) 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 { pub fn gen_load_register(&mut self, ty: Type, src: u32) -> u32 {
self.push(Inst::LoadRegister(ty), Data::node(src)) self.push(Inst::LoadRegister(ty), Data::node(src))
} }
@ -910,7 +971,7 @@ impl Mir {
// 1111_1111 << 4 = 1111_0000 // 1111_1111 << 4 = 1111_0000
// mask = 0000_1111; // mask = 0000_1111;
// shift = 8 - 4; // 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 truncated = self.gen_truncate_integer(src, src_ty, from.signed, from.bits);
let dst_ty = Type::from_bitsize_int(to.bits as u32); let dst_ty = Type::from_bitsize_int(to.bits as u32);
@ -942,7 +1003,7 @@ impl Mir {
let (lhs, rhs) = if ty.is_floating() { let (lhs, rhs) = if ty.is_floating() {
BinaryOperands::new_sse(self).wrangle(lhs, ty, rhs, ty) BinaryOperands::new_sse(self).wrangle(lhs, ty, rhs, ty)
} else { } 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)) self.push(Inst::Sub(ty), Data::binary(lhs, rhs))
} }
@ -1027,6 +1088,10 @@ impl Mir {
let src = self.imm_to_reg(src); let src = self.imm_to_reg(src);
self.push(Inst::Negate(ty), Data::node(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")] #[doc(alias = "gen_shift_left")]
pub fn gen_shl(&mut self, ty: Type, src: u32, shift: u32) -> u32 { pub fn gen_shl(&mut self, ty: Type, src: u32, shift: u32) -> u32 {
@ -1171,6 +1236,10 @@ impl Mir {
let lhs = data.as_node(); let lhs = data.as_node();
writeln!(w, "%{node} = negate {ty} %{lhs}") writeln!(w, "%{node} = negate {ty} %{lhs}")
} }
Inst::Not(ty) => {
let lhs = data.as_node();
writeln!(w, "%{node} = bitwise not {ty} %{lhs}")
}
Inst::SignExtend(ty) => { Inst::SignExtend(ty) => {
let lhs = data.as_node(); let lhs = data.as_node();
writeln!(w, "%{node} = sign extend {ty} %{lhs}") writeln!(w, "%{node} = sign extend {ty} %{lhs}")
@ -1183,6 +1252,34 @@ impl Mir {
let lhs = data.as_node(); let lhs = data.as_node();
writeln!(w, "%{node} = is zero {ty} %{lhs}") 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) => { Inst::ShiftLeft(ty) => {
let (lhs, rhs) = data.as_binary(); let (lhs, rhs) = data.as_binary();
writeln!(w, "%{node} = shift left {ty} %{lhs}, {ty} %{rhs}") writeln!(w, "%{node} = shift left {ty} %{lhs}, {ty} %{rhs}")
@ -1445,12 +1542,20 @@ pub mod liveness {
| Inst::SignExtend(_) | Inst::SignExtend(_)
| Inst::ZeroExtend(_) | Inst::ZeroExtend(_)
| Inst::Negate(_) | Inst::Negate(_)
| Inst::Not(_)
| Inst::IsZero(_) | Inst::IsZero(_)
| Inst::IsEq(_)
| Inst::IsNeq(_)
| Inst::IsGt(_)
| Inst::IsGe(_)
| Inst::IsLt(_)
| Inst::IsLe(_)
| Inst::Load(_) | Inst::Load(_)
| Inst::LoadRegister(_) => { | Inst::LoadRegister(_) => {
references.insert((data.as_noderef(), node)); references.insert((data.as_noderef(), node));
} }
Inst::Store(_) Inst::Cmp(_)
| Inst::Store(_)
| Inst::Add(_) | Inst::Add(_)
| Inst::Sub(_) | Inst::Sub(_)
| Inst::Mul(_) | Inst::Mul(_)
@ -1641,7 +1746,7 @@ impl Mir {
let (lhs, _) = data.as_binary_noderefs(); let (lhs, _) = data.as_binary_noderefs();
Some(lhs) Some(lhs)
} }
Inst::Negate(_) => { Inst::Not(_) | Inst::Negate(_) => {
let lhs = data.as_noderef(); let lhs = data.as_noderef();
Some(lhs) Some(lhs)
} }
@ -1670,6 +1775,13 @@ impl Mir {
| Inst::DivSigned(_) | Inst::DivSigned(_)
| Inst::Rem(_) | Inst::Rem(_)
| Inst::RemSigned(_) | Inst::RemSigned(_)
| Inst::Cmp(_)
| Inst::IsEq(_)
| Inst::IsNeq(_)
| Inst::IsGt(_)
| Inst::IsLt(_)
| Inst::IsGe(_)
| Inst::IsLe(_)
| Inst::IsZero(_) => None, | Inst::IsZero(_) => None,
} }
} }
@ -1978,6 +2090,7 @@ impl Mir {
| Inst::BitOr(ty) | Inst::BitOr(ty)
| Inst::BitXOr(ty) | Inst::BitXOr(ty)
| Inst::Negate(ty) | Inst::Negate(ty)
| Inst::Not(ty)
| Inst::ShiftLeft(ty) | Inst::ShiftLeft(ty)
| Inst::ShiftRightSigned(ty) | Inst::ShiftRightSigned(ty)
| Inst::ShiftRightUnsigned(ty) | Inst::ShiftRightUnsigned(ty)
@ -1988,6 +2101,16 @@ impl Mir {
| Inst::LoadRegister(ty) => ty | Inst::LoadRegister(ty) => ty
.register_width(liveness.get_register(node.into()).unwrap()) .register_width(liveness.get_register(node.into()).unwrap())
.into(), .into(),
Inst::IsEq(_)
| Inst::IsGt(_)
| Inst::IsLt(_)
| Inst::IsGe(_)
| Inst::IsLe(_)
| Inst::IsNeq(_) => liveness
.get_register(node.into())
.unwrap()
.into_byte()
.into(),
Inst::Alloca => { Inst::Alloca => {
let (offset, size) = *mapping.get(&(node as usize)).unwrap(); let (offset, size) = *mapping.get(&(node as usize)).unwrap();
ImmRegMem::Mem(StackMem::new(offset, size)) ImmRegMem::Mem(StackMem::new(offset, size))
@ -2775,6 +2898,16 @@ impl Mir {
writeln!(func.current_branch(), "mov {dst}, {lhs}")?; 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) => { Inst::Negate(ty) => {
let dst = ty.register_width(liveness.get_register(node.into()).unwrap()); let dst = ty.register_width(liveness.get_register(node.into()).unwrap());
let lhs = data.as_node(); 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) => { Inst::IsZero(ty) => {
let dst = ty.register_width(liveness.get_register(node.into()).unwrap()); let dst = ty.register_width(liveness.get_register(node.into()).unwrap());
let lhs = data.as_node(); let lhs = data.as_node();
@ -2916,13 +3081,17 @@ impl Mir {
let lhs = data.as_node(); let lhs = data.as_node();
let lhs = self.node_as_operand(&liveness, &mapping, &mut func, strings, lhs); let lhs = self.node_as_operand(&liveness, &mapping, &mut func, strings, lhs);
if ty.is_floating() { 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 { } else {
writeln!( if !lhs.occupy_same_register(Register::rax) {
func.current_branch(), writeln!(
"mov {}, {lhs}", func.current_branch(),
Register::rax.into_bytesize(lhs.byte_width()) "mov {}, {lhs}",
)?; Register::rax.into_bytesize(lhs.byte_width())
)?;
}
} }
writeln!(func.current_branch(), "jmp {name}__epilogue")?; writeln!(func.current_branch(), "jmp {name}__epilogue")?;
} }

View file

@ -1,6 +1,9 @@
#![allow(dead_code)] #![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::{ use crate::{
ast::{IntegralType, Node as AstNode, Tag, Type}, ast::{IntegralType, Node as AstNode, Tag, Type},
@ -154,6 +157,20 @@ pub enum Inst {
/// lhs /// lhs
Negate(Type2), Negate(Type2),
/// lhs /// 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), ExplicitCast(Type2, Type2),
/// lhs /// lhs
ReturnValue(Type2), ReturnValue(Type2),
@ -290,7 +307,8 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
} }
fn visit(&mut self, node: AstNode) -> Node { 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 } => { Tag::FunctionDecl { proto, body } => {
variant!( variant!(
Tag::FunctionProto { Tag::FunctionProto {
@ -424,6 +442,36 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
self.ir self.ir
.push(Inst::BitXOr(ty.into()), Some(Data::new(lhs, rhs))) .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 } => { Tag::Mul { lhs, rhs } => {
let ty = self.tree.type_of_node(node); let ty = self.tree.type_of_node(node);
let lhs = self.visit(*lhs); let lhs = self.visit(*lhs);
@ -436,6 +484,11 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
let lhs = self.visit(*lhs); let lhs = self.visit(*lhs);
self.ir.push(Inst::Negate(ty.into()), Some(Data::lhs(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 } => { Tag::Shl { lhs, rhs } => {
let ty = self.tree.type_of_node(node); let ty = self.tree.type_of_node(node);
let lhs = self.visit(*lhs); let lhs = self.visit(*lhs);
@ -578,6 +631,30 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
let (lhs, rhs) = data.as_lhs_rhs(); let (lhs, rhs) = data.as_lhs_rhs();
writeln_indented!(indent, w, "%{} = sub_{ty}(%{} - %{})", node, 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) => { Inst::Mul(ty) => {
let (lhs, rhs) = data.as_lhs_rhs(); let (lhs, rhs) = data.as_lhs_rhs();
writeln_indented!(indent, w, "%{} = mul_{ty}(%{} * %{})", node, lhs, rhs)?; writeln_indented!(indent, w, "%{} = mul_{ty}(%{} * %{})", node, lhs, rhs)?;
@ -585,6 +662,9 @@ impl<'tree, 'ir> IRBuilder<'tree, 'ir> {
Inst::Negate(ty) => { Inst::Negate(ty) => {
writeln_indented!(indent, w, "%{} = negate_{ty}(%{})", node, data.lhs)?; 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) => { Inst::ExplicitCast(from, to) => {
writeln_indented!(indent, w, "%{} = cast_{from}_to_{to}(%{})", node, data.lhs)?; writeln_indented!(indent, w, "%{} = cast_{from}_to_{to}(%{})", node, data.lhs)?;
} }
@ -1170,6 +1250,12 @@ impl<'a> Assembler<'a> {
allocas.insert(node, stack_offset); allocas.insert(node, stack_offset);
registers.insert(param_reg, node); 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) => { Inst::Add(ty) => {
let (src, dst) = data.unwrap().as_lhs_rhs(); let (src, dst) = data.unwrap().as_lhs_rhs();
let (&src_reg, _) = registers.iter().find(|(_, node)| node == &&src).unwrap(); let (&src_reg, _) = registers.iter().find(|(_, node)| node == &&src).unwrap();
@ -1255,6 +1341,7 @@ impl<'a> Assembler<'a> {
Inst::BitOr(_) => todo!(), Inst::BitOr(_) => todo!(),
Inst::BitXOr(_) => todo!(), Inst::BitXOr(_) => todo!(),
Inst::Negate(_) => todo!(), Inst::Negate(_) => todo!(),
Inst::Not(_) => todo!(),
Inst::ExplicitCast(_, _) => todo!(), Inst::ExplicitCast(_, _) => todo!(),
Inst::ReturnValue(_) => { Inst::ReturnValue(_) => {
let val = data.unwrap().lhs; let val = data.unwrap().lhs;
@ -1411,6 +1498,29 @@ impl<'a> MirBuilder<'a> {
// let (size, _) = data.unwrap().as_lhs_rhs(); // let (size, _) = data.unwrap().as_lhs_rhs();
mir.gen_param(ty.into()) 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) => { Inst::Add(ty) => {
let (src, dst) = data.unwrap().as_lhs_rhs(); let (src, dst) = data.unwrap().as_lhs_rhs();
let lhs = *mapping.get(&src).unwrap(); let lhs = *mapping.get(&src).unwrap();
@ -1629,6 +1739,21 @@ impl<'a> MirBuilder<'a> {
_ => unreachable!(), _ => 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) => { Inst::Negate(ty) => {
let lhs = data.unwrap().as_u32(); let lhs = data.unwrap().as_u32();