boolean arithmetic
This commit is contained in:
parent
cbc416dcaa
commit
48bbcdec5e
|
@ -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
|
||||||
|
|
275
src/mir.rs
275
src/mir.rs
|
@ -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")?;
|
||||||
}
|
}
|
||||||
|
|
129
src/triples.rs
129
src/triples.rs
|
@ -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();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue