mir.rs changes for last commit's triples.rs changes
This commit is contained in:
parent
9d85eb1428
commit
3aee606ca2
487
src/mir.rs
487
src/mir.rs
|
@ -109,7 +109,7 @@ pub enum Inst {
|
||||||
/// imm64
|
/// imm64
|
||||||
ConstantQWord,
|
ConstantQWord,
|
||||||
/// src
|
/// src
|
||||||
LoadConstant(Type), // hint for loading constant into register
|
LoadRegister(Type), // hint for loading value into register
|
||||||
/// ast-node
|
/// ast-node
|
||||||
ExternRef,
|
ExternRef,
|
||||||
/// size, align
|
/// size, align
|
||||||
|
@ -162,18 +162,18 @@ impl Inst {
|
||||||
match self {
|
match self {
|
||||||
Inst::Label
|
Inst::Label
|
||||||
| Inst::ConstantBytes
|
| Inst::ConstantBytes
|
||||||
| Inst::ConstantByte
|
|
||||||
| Inst::ConstantWord
|
|
||||||
| Inst::ConstantDWord
|
|
||||||
| Inst::ConstantQWord
|
|
||||||
| Inst::ExternRef
|
| Inst::ExternRef
|
||||||
| Inst::Alloca
|
| Inst::Alloca
|
||||||
| Inst::ReturnValue
|
| Inst::ReturnValue
|
||||||
| Inst::Store(_)
|
| Inst::Store(_)
|
||||||
|
| Inst::ConstantByte
|
||||||
|
| Inst::ConstantWord
|
||||||
|
| Inst::ConstantDWord
|
||||||
|
| Inst::ConstantQWord
|
||||||
| Inst::Return => None,
|
| Inst::Return => None,
|
||||||
Inst::GetElementPtr(ty)
|
Inst::GetElementPtr(ty)
|
||||||
| Inst::Load(ty)
|
| Inst::Load(ty)
|
||||||
| Inst::LoadConstant(ty)
|
| Inst::LoadRegister(ty)
|
||||||
| Inst::Parameter(ty)
|
| Inst::Parameter(ty)
|
||||||
| Inst::Add(ty)
|
| Inst::Add(ty)
|
||||||
| Inst::Sub(ty)
|
| Inst::Sub(ty)
|
||||||
|
@ -194,6 +194,7 @@ impl Inst {
|
||||||
}
|
}
|
||||||
fn has_value(&self) -> bool {
|
fn has_value(&self) -> bool {
|
||||||
// basically, when an arithmetic instruction has two immediates, then just replace it with a mov into the dst reg
|
// basically, when an arithmetic instruction has two immediates, then just replace it with a mov into the dst reg
|
||||||
|
// TODO: need to account for spilled values eventually; probably move this to `Mir`.
|
||||||
match self {
|
match self {
|
||||||
Inst::Label
|
Inst::Label
|
||||||
| Inst::ConstantBytes
|
| Inst::ConstantBytes
|
||||||
|
@ -208,7 +209,7 @@ impl Inst {
|
||||||
| Inst::Return => false,
|
| Inst::Return => false,
|
||||||
Inst::GetElementPtr(_)
|
Inst::GetElementPtr(_)
|
||||||
| Inst::Load(_)
|
| Inst::Load(_)
|
||||||
| Inst::LoadConstant(_)
|
| Inst::LoadRegister(_)
|
||||||
| Inst::Parameter(_)
|
| Inst::Parameter(_)
|
||||||
| Inst::Add(_)
|
| Inst::Add(_)
|
||||||
| Inst::Sub(_)
|
| Inst::Sub(_)
|
||||||
|
@ -311,6 +312,281 @@ impl Data {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use bitflags::bitflags;
|
||||||
|
bitflags! {
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct BinaryOperandFlags: u8 {
|
||||||
|
const RhsReg = 0b00000001;
|
||||||
|
const RhsMem = 0b00000010;
|
||||||
|
const RhsImm = 0b00000100;
|
||||||
|
const LhsReg = 0b10000000;
|
||||||
|
const LhsMem = 0b01000000;
|
||||||
|
const LhsImm = 0b00100000;
|
||||||
|
|
||||||
|
const RegReg = 0b10000001;
|
||||||
|
const RegMem = 0b10000010;
|
||||||
|
const RegImm = 0b10000100;
|
||||||
|
const MemReg = 0b01000001;
|
||||||
|
const MemMem = 0b01000010;
|
||||||
|
const MemImm = 0b01000100;
|
||||||
|
|
||||||
|
const RhsAll = 0b00000111;
|
||||||
|
const LhsAll = 0b11100000;
|
||||||
|
|
||||||
|
const NULL = 0b0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bitflags! {
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
struct OperandKinds: u8 {
|
||||||
|
const RegReg = 0b00000001;
|
||||||
|
const RegMem = 0b00000010;
|
||||||
|
const RegImm = 0b00000100;
|
||||||
|
const MemReg = 0b00001000;
|
||||||
|
const MemMem = 0b00010000;
|
||||||
|
const MemImm = 0b00100000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OperandKinds {
|
||||||
|
/// works for: add,sub,or,and,sbb,adc
|
||||||
|
fn add() -> Self {
|
||||||
|
Self::RegImm | Self::MemImm | Self::RegMem | Self::MemReg | Self::RegReg
|
||||||
|
}
|
||||||
|
/// imul is special...
|
||||||
|
fn imul() -> Self {
|
||||||
|
Self::RegImm | Self::MemImm | Self::RegMem | Self::RegReg
|
||||||
|
}
|
||||||
|
/// works for: div,idiv,mul
|
||||||
|
fn mul() -> Self {
|
||||||
|
Self::RegMem | Self::RegReg
|
||||||
|
}
|
||||||
|
/// works for: mulss,mulsd,divss,divsd,addss,addsd,subss,subsd
|
||||||
|
fn sse() -> Self {
|
||||||
|
Self::RegMem | Self::RegReg
|
||||||
|
}
|
||||||
|
/// works for: shl,shr,sar,sal
|
||||||
|
fn shift() -> Self {
|
||||||
|
Self::RegReg | Self::RegImm | Self::MemImm | Self::MemReg
|
||||||
|
}
|
||||||
|
const fn to_rhs_binop(self) -> BinaryOperandFlags {
|
||||||
|
let reg = if self.intersects(Self::RegReg.union(Self::MemReg)) {
|
||||||
|
BinaryOperandFlags::RhsReg
|
||||||
|
} else {
|
||||||
|
BinaryOperandFlags::empty()
|
||||||
|
};
|
||||||
|
let mem = if self.intersects(Self::RegMem.union(Self::MemMem)) {
|
||||||
|
BinaryOperandFlags::RhsMem
|
||||||
|
} else {
|
||||||
|
BinaryOperandFlags::empty()
|
||||||
|
};
|
||||||
|
let imm = if self.intersects(Self::RegImm.union(Self::MemImm)) {
|
||||||
|
BinaryOperandFlags::RhsImm
|
||||||
|
} else {
|
||||||
|
BinaryOperandFlags::empty()
|
||||||
|
};
|
||||||
|
|
||||||
|
reg.union(mem).union(imm)
|
||||||
|
}
|
||||||
|
const fn to_lhs_binop(self) -> BinaryOperandFlags {
|
||||||
|
let reg = if self.intersects(Self::RegReg.union(Self::RegImm).union(Self::RegMem)) {
|
||||||
|
BinaryOperandFlags::LhsReg
|
||||||
|
} else {
|
||||||
|
BinaryOperandFlags::empty()
|
||||||
|
};
|
||||||
|
let mem = if self.intersects(Self::MemReg.union(Self::MemMem).union(Self::MemImm)) {
|
||||||
|
BinaryOperandFlags::LhsMem
|
||||||
|
} else {
|
||||||
|
BinaryOperandFlags::empty()
|
||||||
|
};
|
||||||
|
reg.union(mem)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn reduce_with_rhs(self, lhs: BinaryOperandFlags) -> OperandKinds {
|
||||||
|
let mut out = self;
|
||||||
|
if !lhs.contains(BinaryOperandFlags::RhsImm) {
|
||||||
|
out = out.difference(Self::MemImm | Self::RegImm);
|
||||||
|
}
|
||||||
|
if !lhs.contains(BinaryOperandFlags::RhsMem) {
|
||||||
|
out = out.difference(Self::MemMem | Self::RegMem);
|
||||||
|
}
|
||||||
|
if !lhs.contains(BinaryOperandFlags::RhsReg) {
|
||||||
|
out = out.difference(Self::RegReg | Self::MemReg);
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
fn reduce_with_lhs(self, lhs: BinaryOperandFlags) -> OperandKinds {
|
||||||
|
let mut out = self;
|
||||||
|
if !lhs.contains(BinaryOperandFlags::LhsMem) {
|
||||||
|
out = out.difference(Self::MemReg | Self::MemMem | Self::MemImm);
|
||||||
|
}
|
||||||
|
if !lhs.contains(BinaryOperandFlags::LhsReg) {
|
||||||
|
out = out.difference(Self::RegReg | Self::RegMem | Self::RegImm);
|
||||||
|
}
|
||||||
|
out
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum OperandKind {
|
||||||
|
Mem,
|
||||||
|
Imm,
|
||||||
|
Reg,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OperandKind {
|
||||||
|
const fn as_rhs(self) -> BinaryOperandFlags {
|
||||||
|
match self {
|
||||||
|
OperandKind::Mem => BinaryOperandFlags::RhsMem,
|
||||||
|
OperandKind::Imm => BinaryOperandFlags::RhsImm,
|
||||||
|
OperandKind::Reg => BinaryOperandFlags::RhsReg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const fn as_lhs(self) -> BinaryOperandFlags {
|
||||||
|
match self {
|
||||||
|
OperandKind::Mem => BinaryOperandFlags::LhsMem,
|
||||||
|
OperandKind::Imm => BinaryOperandFlags::LhsImm,
|
||||||
|
OperandKind::Reg => BinaryOperandFlags::LhsReg,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BinaryOperands<'a> {
|
||||||
|
mir: &'a mut Mir,
|
||||||
|
commutative: bool,
|
||||||
|
kinds: OperandKinds,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct BinaryOperandsRunner<'a> {
|
||||||
|
inner: BinaryOperands<'a>,
|
||||||
|
lhs: (u32, Type),
|
||||||
|
rhs: (u32, Type),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> BinaryOperandsRunner<'a> {
|
||||||
|
fn new(inner: BinaryOperands<'a>, lhs: u32, lhs_type: Type, rhs: u32, rhs_type: Type) -> Self {
|
||||||
|
Self {
|
||||||
|
inner,
|
||||||
|
lhs: (lhs, lhs_type),
|
||||||
|
rhs: (rhs, rhs_type),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn mir_mut(&mut self) -> &mut Mir {
|
||||||
|
self.inner.mir
|
||||||
|
}
|
||||||
|
fn mir(&self) -> &Mir {
|
||||||
|
self.inner.mir
|
||||||
|
}
|
||||||
|
fn lhs(&self) -> u32 {
|
||||||
|
self.lhs.0
|
||||||
|
}
|
||||||
|
fn rhs(&self) -> u32 {
|
||||||
|
self.rhs.0
|
||||||
|
}
|
||||||
|
fn lhs_type(&self) -> Type {
|
||||||
|
self.lhs.1
|
||||||
|
}
|
||||||
|
fn rhs_type(&self) -> Type {
|
||||||
|
self.rhs.1
|
||||||
|
}
|
||||||
|
fn lhs_rhs(&self) -> (u32, u32) {
|
||||||
|
(self.lhs(), self.rhs())
|
||||||
|
}
|
||||||
|
fn canonicalise_lhs_with_reduced_kinds(&mut self, kinds: OperandKinds) {
|
||||||
|
let (lhs, ty) = self.lhs;
|
||||||
|
|
||||||
|
let l_legal = kinds.to_lhs_binop();
|
||||||
|
let l_kind = self.mir().as_operand_kind(self.lhs()).as_lhs();
|
||||||
|
|
||||||
|
if l_legal.contains(l_kind) {
|
||||||
|
} else if l_legal.contains(BinaryOperandFlags::LhsReg) {
|
||||||
|
self.lhs.0 = self.mir_mut().to_reg(ty, lhs);
|
||||||
|
} else if l_legal.contains(BinaryOperandFlags::LhsMem) {
|
||||||
|
self.lhs.0 = self.mir_mut().gen_spill_value(lhs);
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_swap(&mut self) {
|
||||||
|
let (lhs, rhs) = self.lhs_rhs();
|
||||||
|
let l_legal = self.inner.kinds.to_lhs_binop();
|
||||||
|
let l_kind = self.mir().as_operand_kind(lhs).as_lhs();
|
||||||
|
let r_kind = self.mir().as_operand_kind(rhs).as_rhs();
|
||||||
|
|
||||||
|
if self.inner.commutative && (!l_legal.contains(l_kind) && l_legal.contains(r_kind)) {
|
||||||
|
core::mem::swap(&mut self.lhs, &mut self.rhs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn order(&mut self) {
|
||||||
|
self.try_swap();
|
||||||
|
let rhs = self.rhs();
|
||||||
|
let ty = self.rhs_type();
|
||||||
|
let r_legal = self.inner.kinds.to_rhs_binop();
|
||||||
|
let r_kind = self.mir().as_operand_kind(rhs).as_rhs();
|
||||||
|
|
||||||
|
if r_legal.contains(r_kind) {
|
||||||
|
} else if r_legal.contains(BinaryOperandFlags::RhsReg) {
|
||||||
|
self.rhs.0 = self.mir_mut().to_reg(ty, rhs);
|
||||||
|
} else if r_legal.contains(BinaryOperandFlags::RhsMem) {
|
||||||
|
self.rhs.0 = self.mir_mut().gen_spill_value(rhs);
|
||||||
|
} else {
|
||||||
|
unreachable!()
|
||||||
|
}
|
||||||
|
|
||||||
|
let rhs = self.rhs();
|
||||||
|
self.canonicalise_lhs_with_reduced_kinds(
|
||||||
|
self.inner
|
||||||
|
.kinds
|
||||||
|
.reduce_with_rhs(self.mir().as_operand_kind(rhs).as_rhs()),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> BinaryOperands<'a> {
|
||||||
|
fn new(mir: &'a mut Mir, commutative: bool, kinds: OperandKinds) -> Self {
|
||||||
|
Self {
|
||||||
|
mir,
|
||||||
|
commutative,
|
||||||
|
kinds,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
|
Self::new(mir, false, OperandKinds::add())
|
||||||
|
}
|
||||||
|
fn new_sse(mir: &'a mut Mir) -> Self {
|
||||||
|
Self::new(mir, true, OperandKinds::sse())
|
||||||
|
}
|
||||||
|
fn new_mul(mir: &'a mut Mir) -> Self {
|
||||||
|
Self::new(mir, true, OperandKinds::mul())
|
||||||
|
}
|
||||||
|
fn new_imul(mir: &'a mut Mir) -> Self {
|
||||||
|
Self::new(mir, true, OperandKinds::imul())
|
||||||
|
}
|
||||||
|
fn new_div_idiv_rem_irem(mir: &'a mut Mir) -> Self {
|
||||||
|
Self::new(mir, false, OperandKinds::mul())
|
||||||
|
}
|
||||||
|
fn new_shift(mir: &'a mut Mir) -> Self {
|
||||||
|
Self::new(mir, false, OperandKinds::shift())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wrangle(self, lhs: u32, lhs_type: Type, rhs: u32, rhs_type: Type) -> (u32, u32) {
|
||||||
|
let mut runner = BinaryOperandsRunner {
|
||||||
|
inner: self,
|
||||||
|
lhs: (lhs, lhs_type),
|
||||||
|
rhs: (rhs, rhs_type),
|
||||||
|
};
|
||||||
|
|
||||||
|
runner.order();
|
||||||
|
|
||||||
|
runner.lhs_rhs()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Mir {
|
pub struct Mir {
|
||||||
pub nodes: Vec<Inst>,
|
pub nodes: Vec<Inst>,
|
||||||
pub data: Vec<Data>,
|
pub data: Vec<Data>,
|
||||||
|
@ -324,6 +600,62 @@ impl Mir {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_operand_kind(&self, node: u32) -> OperandKind {
|
||||||
|
if self.is_imm(node) {
|
||||||
|
OperandKind::Imm
|
||||||
|
} else if self.is_register(node) {
|
||||||
|
OperandKind::Reg
|
||||||
|
} else {
|
||||||
|
OperandKind::Mem
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_reg(&mut self, ty: Type, node: u32) -> u32 {
|
||||||
|
if !self.is_register(node) {
|
||||||
|
self.gen_load_register(ty, node)
|
||||||
|
} else {
|
||||||
|
node
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_of_node(&self, node: u32) -> Option<Type> {
|
||||||
|
self.nodes[node as usize].value_type()
|
||||||
|
}
|
||||||
|
|
||||||
|
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::BitAnd(_)
|
||||||
|
| Inst::BitOr(_)
|
||||||
|
| Inst::BitXOr(_)
|
||||||
|
| Inst::Negate(_)
|
||||||
|
| Inst::ShiftLeft(_)
|
||||||
|
| Inst::ShiftRightSigned(_)
|
||||||
|
| Inst::ShiftRightUnsigned(_) => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_imm(&self, node: u32) -> bool {
|
||||||
|
match self.nodes[node as usize] {
|
||||||
|
Inst::ConstantByte | Inst::ConstantWord | Inst::ConstantDWord | Inst::ConstantQWord => {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn push(&mut self, inst: Inst, data: Data) -> u32 {
|
pub fn push(&mut self, inst: Inst, data: Data) -> u32 {
|
||||||
let node = self.nodes.len() as u32;
|
let node = self.nodes.len() as u32;
|
||||||
self.nodes.push(inst);
|
self.nodes.push(inst);
|
||||||
|
@ -344,8 +676,15 @@ impl Mir {
|
||||||
pub fn gen_u64(&mut self, value: u64) -> u32 {
|
pub fn gen_u64(&mut self, value: u64) -> u32 {
|
||||||
self.push(Inst::ConstantQWord, Data::imm64(value))
|
self.push(Inst::ConstantQWord, Data::imm64(value))
|
||||||
}
|
}
|
||||||
pub fn gen_load_const(&mut self, ty: Type, src: u32) -> u32 {
|
pub fn gen_load_register(&mut self, ty: Type, src: u32) -> u32 {
|
||||||
self.push(Inst::LoadConstant(ty), Data::node(src))
|
self.push(Inst::LoadRegister(ty), Data::node(src))
|
||||||
|
}
|
||||||
|
pub fn gen_spill_value(&mut self, src: u32) -> u32 {
|
||||||
|
let ty = self.type_of_node(src).unwrap();
|
||||||
|
let size = ty.bytes();
|
||||||
|
let alloc = self.gen_alloca(size, size);
|
||||||
|
_ = self.gen_store(ty, src, alloc);
|
||||||
|
alloc
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_label(&mut self, name: StringsIndex) -> u32 {
|
pub fn gen_label(&mut self, name: StringsIndex) -> u32 {
|
||||||
|
@ -394,76 +733,125 @@ impl Mir {
|
||||||
masked
|
masked
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fn imm_to_reg(&mut self, src: u32) -> u32 {
|
||||||
|
if self.is_imm(src) {
|
||||||
|
// SAFETY: imms have values and thus types
|
||||||
|
self.gen_load_register(self.type_of_node(src).unwrap(), src)
|
||||||
|
} else {
|
||||||
|
src
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn gen_add(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_add(&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_add_or_and_xor_adc(self).wrangle(lhs, ty, rhs, ty)
|
||||||
|
};
|
||||||
self.push(Inst::Add(ty), Data::binary(lhs, rhs))
|
self.push(Inst::Add(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
pub fn gen_sub(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_sub(&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(self).wrangle(lhs, ty, rhs, ty)
|
||||||
|
};
|
||||||
self.push(Inst::Sub(ty), Data::binary(lhs, rhs))
|
self.push(Inst::Sub(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
pub fn gen_mul(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_mul(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 {
|
||||||
if signed && !ty.is_floating() {
|
if ty.is_floating() {
|
||||||
|
self.gen_mul_sse(ty, lhs, rhs)
|
||||||
|
} else if signed {
|
||||||
self.gen_mul_signed(ty, lhs, rhs)
|
self.gen_mul_signed(ty, lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
self.gen_mul_unsigned(ty, lhs, rhs)
|
self.gen_mul_unsigned(ty, lhs, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn gen_mul_sse(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
|
let (lhs, rhs) = BinaryOperands::new_sse(self).wrangle(lhs, ty, rhs, ty);
|
||||||
|
self.push(Inst::Mul(ty), Data::binary(lhs, rhs))
|
||||||
|
}
|
||||||
pub fn gen_mul_unsigned(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_mul_unsigned(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
|
let (lhs, rhs) = BinaryOperands::new_mul(self).wrangle(lhs, ty, rhs, ty);
|
||||||
self.push(Inst::Mul(ty), Data::binary(lhs, rhs))
|
self.push(Inst::Mul(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
pub fn gen_mul_signed(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_mul_signed(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
|
let (lhs, rhs) = BinaryOperands::new_imul(self).wrangle(lhs, ty, rhs, ty);
|
||||||
self.push(Inst::MulSigned(ty), Data::binary(lhs, rhs))
|
self.push(Inst::MulSigned(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
pub fn gen_div(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_div(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 {
|
||||||
if signed && !ty.is_floating() {
|
if ty.is_floating() {
|
||||||
|
self.gen_div_sse(ty, lhs, rhs)
|
||||||
|
} else if signed {
|
||||||
self.gen_div_signed(ty, lhs, rhs)
|
self.gen_div_signed(ty, lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
self.gen_div_unsigned(ty, lhs, rhs)
|
self.gen_div_unsigned(ty, lhs, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn gen_div_sse(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
|
let (lhs, rhs) = BinaryOperands::new_sse(self).wrangle(lhs, ty, rhs, ty);
|
||||||
|
self.push(Inst::Div(ty), Data::binary(lhs, rhs))
|
||||||
|
}
|
||||||
pub fn gen_div_unsigned(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_div_unsigned(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
|
let (lhs, rhs) = BinaryOperands::new_div_idiv_rem_irem(self).wrangle(lhs, ty, rhs, ty);
|
||||||
self.push(Inst::Div(ty), Data::binary(lhs, rhs))
|
self.push(Inst::Div(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
pub fn gen_div_signed(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_div_signed(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
|
let (lhs, rhs) = BinaryOperands::new_div_idiv_rem_irem(self).wrangle(lhs, ty, rhs, ty);
|
||||||
self.push(Inst::DivSigned(ty), Data::binary(lhs, rhs))
|
self.push(Inst::DivSigned(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
pub fn gen_rem(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_rem(&mut self, ty: Type, signed: bool, lhs: u32, rhs: u32) -> u32 {
|
||||||
if signed && !ty.is_floating() {
|
if ty.is_floating() {
|
||||||
|
self.gen_rem_fp(ty, lhs, rhs)
|
||||||
|
} else if signed {
|
||||||
self.gen_rem_signed(ty, lhs, rhs)
|
self.gen_rem_signed(ty, lhs, rhs)
|
||||||
} else {
|
} else {
|
||||||
self.gen_rem_unsigned(ty, lhs, rhs)
|
self.gen_rem_unsigned(ty, lhs, rhs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pub fn gen_rem_fp(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
|
_ = (ty, lhs, rhs);
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
pub fn gen_rem_unsigned(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_rem_unsigned(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
|
let (lhs, rhs) = BinaryOperands::new_div_idiv_rem_irem(self).wrangle(lhs, ty, rhs, ty);
|
||||||
self.push(Inst::Rem(ty), Data::binary(lhs, rhs))
|
self.push(Inst::Rem(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
pub fn gen_rem_signed(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_rem_signed(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
|
let (lhs, rhs) = BinaryOperands::new_div_idiv_rem_irem(self).wrangle(lhs, ty, rhs, ty);
|
||||||
self.push(Inst::RemSigned(ty), Data::binary(lhs, rhs))
|
self.push(Inst::RemSigned(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gen_bitand(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_bitand(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
|
let (lhs, rhs) = BinaryOperands::new_add_or_and_xor_adc(self).wrangle(lhs, ty, rhs, ty);
|
||||||
self.push(Inst::BitAnd(ty), Data::binary(lhs, rhs))
|
self.push(Inst::BitAnd(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
pub fn gen_bitor(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_bitor(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
self.push(Inst::BitAnd(ty), Data::binary(lhs, rhs))
|
let (lhs, rhs) = BinaryOperands::new_add_or_and_xor_adc(self).wrangle(lhs, ty, rhs, ty);
|
||||||
|
self.push(Inst::BitOr(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
pub fn gen_bitxor(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
pub fn gen_bitxor(&mut self, ty: Type, lhs: u32, rhs: u32) -> u32 {
|
||||||
self.push(Inst::BitAnd(ty), Data::binary(lhs, rhs))
|
let (lhs, rhs) = BinaryOperands::new_add_or_and_xor_adc(self).wrangle(lhs, ty, rhs, ty);
|
||||||
|
self.push(Inst::BitXOr(ty), Data::binary(lhs, rhs))
|
||||||
}
|
}
|
||||||
pub fn gen_negate(&mut self, ty: Type, src: u32) -> u32 {
|
pub fn gen_negate(&mut self, ty: Type, src: u32) -> u32 {
|
||||||
|
let src = self.imm_to_reg(src);
|
||||||
self.push(Inst::Negate(ty), Data::node(src))
|
self.push(Inst::Negate(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 {
|
||||||
|
let (src, shift) = BinaryOperands::new_shift(self).wrangle(src, ty, shift, ty);
|
||||||
self.push(Inst::ShiftLeft(ty), Data::binary(src, shift))
|
self.push(Inst::ShiftLeft(ty), Data::binary(src, shift))
|
||||||
}
|
}
|
||||||
#[doc(alias = "gen_shift_right")]
|
#[doc(alias = "gen_shift_right")]
|
||||||
pub fn gen_shr(&mut self, ty: Type, src: u32, shift: u32) -> u32 {
|
pub fn gen_shr(&mut self, ty: Type, src: u32, shift: u32) -> u32 {
|
||||||
|
let (src, shift) = BinaryOperands::new_shift(self).wrangle(src, ty, shift, ty);
|
||||||
self.push(Inst::ShiftRightUnsigned(ty), Data::binary(src, shift))
|
self.push(Inst::ShiftRightUnsigned(ty), Data::binary(src, shift))
|
||||||
}
|
}
|
||||||
#[doc(alias = "gen_shift_right_signed")]
|
#[doc(alias = "gen_shift_right_signed")]
|
||||||
pub fn gen_sar(&mut self, ty: Type, src: u32, shift: u32) -> u32 {
|
pub fn gen_sar(&mut self, ty: Type, src: u32, shift: u32) -> u32 {
|
||||||
|
let (src, shift) = BinaryOperands::new_shift(self).wrangle(src, ty, shift, ty);
|
||||||
self.push(Inst::ShiftRightSigned(ty), Data::binary(src, shift))
|
self.push(Inst::ShiftRightSigned(ty), Data::binary(src, shift))
|
||||||
}
|
}
|
||||||
pub fn gen_ret_val(&mut self, val: u32) -> u32 {
|
pub fn gen_ret_val(&mut self, val: u32) -> u32 {
|
||||||
|
@ -501,9 +889,9 @@ impl Mir {
|
||||||
Inst::ConstantWord => writeln!(w, "%{node} = imm16({:x?})", data.as_imm16()),
|
Inst::ConstantWord => writeln!(w, "%{node} = imm16({:x?})", data.as_imm16()),
|
||||||
Inst::ConstantDWord => writeln!(w, "%{node} = imm32({:x?})", data.as_imm32()),
|
Inst::ConstantDWord => writeln!(w, "%{node} = imm32({:x?})", data.as_imm32()),
|
||||||
Inst::ConstantQWord => writeln!(w, "%{node} = imm64({:x?})", data.as_imm64()),
|
Inst::ConstantQWord => writeln!(w, "%{node} = imm64({:x?})", data.as_imm64()),
|
||||||
Inst::LoadConstant(ty) => {
|
Inst::LoadRegister(ty) => {
|
||||||
let src = data.as_node();
|
let src = data.as_node();
|
||||||
writeln!(w, "%{node} = load constant {ty} %{src}")
|
writeln!(w, "%{node} = load register {ty} %{src}")
|
||||||
}
|
}
|
||||||
Inst::ExternRef => writeln!(w, "%{node} = extern %%{}", data.as_node()),
|
Inst::ExternRef => writeln!(w, "%{node} = extern %%{}", data.as_node()),
|
||||||
Inst::Alloca => {
|
Inst::Alloca => {
|
||||||
|
@ -639,7 +1027,6 @@ impl Mir {
|
||||||
} else {
|
} else {
|
||||||
in_colors.pop()
|
in_colors.pop()
|
||||||
} {
|
} {
|
||||||
println!("prefering {reg} for param");
|
|
||||||
preferred_colors.insert(node, reg);
|
preferred_colors.insert(node, reg);
|
||||||
};
|
};
|
||||||
inouts.push(node);
|
inouts.push(node);
|
||||||
|
@ -667,7 +1054,6 @@ impl Mir {
|
||||||
|
|
||||||
if !ty.is_floating() {
|
if !ty.is_floating() {
|
||||||
_ = preferred_colors.try_insert(lhs, amd64::Register::rax);
|
_ = preferred_colors.try_insert(lhs, amd64::Register::rax);
|
||||||
_ = preferred_colors.try_insert(rhs, amd64::Register::rax);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// div wants lhs to be rax, idiv can do either.
|
// div wants lhs to be rax, idiv can do either.
|
||||||
|
@ -909,6 +1295,71 @@ impl Mir {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
use crate::asm::amd64::{self, Mnemonic, Operand, Operands};
|
||||||
|
use crate::variant;
|
||||||
|
type Asm = Vec<(Mnemonic, Operands)>;
|
||||||
|
|
||||||
|
#[allow(dead_code, unused)]
|
||||||
|
impl Mir {
|
||||||
|
fn assemble(&self, strings: &StringTable) {
|
||||||
|
let mut mapping = HashMap::<usize, (StringsIndex, usize)>::new();
|
||||||
|
let mut entry = Asm::new();
|
||||||
|
let mut branches = HashMap::<StringsIndex, Asm>::new();
|
||||||
|
let mut stack_offset = 0;
|
||||||
|
let mut current_branch = StringsIndex::none();
|
||||||
|
branches.insert(current_branch, Asm::new());
|
||||||
|
|
||||||
|
for i in 0..self.nodes.len() {
|
||||||
|
let inst = self.nodes[i];
|
||||||
|
let data = self.data[i];
|
||||||
|
|
||||||
|
let branch = branches.get_mut(¤t_branch).unwrap();
|
||||||
|
|
||||||
|
match inst {
|
||||||
|
Inst::Label => todo!(),
|
||||||
|
Inst::ConstantBytes => todo!(),
|
||||||
|
Inst::ConstantByte => todo!(),
|
||||||
|
Inst::ConstantWord => todo!(),
|
||||||
|
Inst::ConstantDWord => todo!(),
|
||||||
|
Inst::ConstantQWord => todo!(),
|
||||||
|
Inst::LoadRegister(ty) => todo!(),
|
||||||
|
Inst::ExternRef => todo!(),
|
||||||
|
Inst::Alloca => {
|
||||||
|
let (size, align) = data.as_binary();
|
||||||
|
let size = size.next_multiple_of(align);
|
||||||
|
stack_offset += size;
|
||||||
|
mapping.insert(i, (current_branch, branch.len()));
|
||||||
|
branch.push((Mnemonic::alloca, Operands::One(Operand::imm32(size))))
|
||||||
|
}
|
||||||
|
Inst::Load(ty) => {
|
||||||
|
// stuff
|
||||||
|
// branch.push((Mnemonic::mov, Operands::One(Operand::imm32(size))))
|
||||||
|
}
|
||||||
|
Inst::Store(ty) => todo!(),
|
||||||
|
Inst::GetElementPtr(ty) => todo!(),
|
||||||
|
Inst::Parameter(ty) => todo!(),
|
||||||
|
Inst::Add(_) => todo!(),
|
||||||
|
Inst::Sub(_) => todo!(),
|
||||||
|
Inst::Mul(_) => todo!(),
|
||||||
|
Inst::MulSigned(_) => todo!(),
|
||||||
|
Inst::Div(_) => todo!(),
|
||||||
|
Inst::DivSigned(_) => todo!(),
|
||||||
|
Inst::Rem(_) => todo!(),
|
||||||
|
Inst::RemSigned(_) => todo!(),
|
||||||
|
Inst::BitAnd(_) => todo!(),
|
||||||
|
Inst::BitOr(_) => todo!(),
|
||||||
|
Inst::BitXOr(_) => todo!(),
|
||||||
|
Inst::Negate(_) => todo!(),
|
||||||
|
Inst::ShiftLeft(_) => todo!(),
|
||||||
|
Inst::ShiftRightSigned(_) => todo!(),
|
||||||
|
Inst::ShiftRightUnsigned(_) => todo!(),
|
||||||
|
Inst::ReturnValue => todo!(),
|
||||||
|
Inst::Return => todo!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DisplayMir<'a, 'b> {
|
pub struct DisplayMir<'a, 'b> {
|
||||||
mir: &'a Mir,
|
mir: &'a Mir,
|
||||||
strings: &'b StringTable,
|
strings: &'b StringTable,
|
||||||
|
|
Loading…
Reference in a new issue