boolean arithmetic
This commit is contained in:
parent
cbc416dcaa
commit
48bbcdec5e
|
@ -374,7 +374,7 @@ impl Type {
|
|||
Self::Void
|
||||
}
|
||||
pub fn bool() -> Type {
|
||||
Self::Void
|
||||
Self::Bool
|
||||
}
|
||||
pub fn comptime_number() -> Type {
|
||||
Self::ComptimeNumber
|
||||
|
|
275
src/mir.rs
275
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")?;
|
||||
}
|
||||
|
|
129
src/triples.rs
129
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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue