From 72db96f56c55045c0680198d525204f51a1d6b60 Mon Sep 17 00:00:00 2001 From: TheCPP Date: Thu, 29 Aug 2024 14:37:37 +0200 Subject: [PATCH] [CODE GEN] adding more stuff (i forgot what) --- src/CodeGen/calling_convention.rs | 43 +++++- src/CodeGen/compilation/assign.rs | 21 +++ src/CodeGen/compilation/call.rs | 11 ++ src/CodeGen/compilation/cast.rs | 10 ++ src/CodeGen/compilation/math.rs | 2 +- src/CodeGen/compilation/mod.rs | 29 ++++- src/CodeGen/compilation/ret.rs | 9 +- src/CodeGen/mod.rs | 4 +- src/CodeGen/reg_vec.rs | 7 + src/IR/nodes/mod.rs | 2 +- src/Target/mod.rs | 2 - src/Target/reg.rs | 49 ------- src/Target/target_descr.rs | 19 ++- src/Target/x64/asm/instr.rs | 34 ++--- src/Target/x64/asm/isa.rs | 8 +- src/Target/x64/asm/optimizer.rs | 12 +- src/Target/x64/asm/parser.rs | 14 +- src/Target/x64/mod.rs | 2 +- src/Target/x64/reg.rs | 208 ++++++++++++++++-------------- tests/x64_instruction_encoding.rs | 28 ++-- 20 files changed, 300 insertions(+), 214 deletions(-) create mode 100644 src/CodeGen/compilation/assign.rs create mode 100644 src/CodeGen/compilation/call.rs create mode 100644 src/CodeGen/compilation/cast.rs delete mode 100644 src/Target/reg.rs diff --git a/src/CodeGen/calling_convention.rs b/src/CodeGen/calling_convention.rs index 5d47bfc2..66b5681b 100644 --- a/src/CodeGen/calling_convention.rs +++ b/src/CodeGen/calling_convention.rs @@ -1,24 +1,27 @@ -use crate::Target::{x64Reg, Arch, CallConv}; +use crate::{Target::{x64Reg, Arch, CallConv}, IR::TypeMetadata}; use super::Reg; +/// A more machine specifc calling convention +/// (Just a wrapper around the normal calling convention but with some pretty handy functions) #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub struct MachineCallingConvention { pub(crate) call_conv: CallConv, } impl MachineCallingConvention { - pub fn return_reg(&self, arch: Arch) -> Reg { + /// returns the return register for the specific architecture and ty + pub fn return_reg(&self, arch: Arch, ty: TypeMetadata) -> Reg { match self.call_conv { CallConv::WindowsFastCall => { match arch { - Arch::X86_64 => Reg::x64(x64Reg::Rax), + Arch::X86_64 => Reg::x64(x64Reg::Rax.sub_ty(ty)), _ => todo!() } }, CallConv::SystemV => { match arch { - Arch::X86_64 => Reg::x64(x64Reg::Rax), + Arch::X86_64 => Reg::x64(x64Reg::Rax.sub_ty(ty)), _ => todo!() } }, @@ -26,4 +29,36 @@ impl MachineCallingConvention { CallConv::WasmBasicCAbi => todo!(), } } + + /// returns the args for the specifc architecture + pub fn args(&self, arch: Arch) -> Vec { + match self.call_conv { + CallConv::WindowsFastCall => { + match arch { + Arch::X86_64 => vec![ + Reg::x64(x64Reg::Rcx), Reg::x64(x64Reg::Rdx), + Reg::x64(x64Reg::R8), Reg::x64(x64Reg::R9) + ], + _ => todo!() + } + }, + CallConv::SystemV => { + match arch { + Arch::X86_64 => vec![ + Reg::x64(x64Reg::Rsi), Reg::x64(x64Reg::Rdi), + Reg::x64(x64Reg::Rcx), Reg::x64(x64Reg::Rdx), + Reg::x64(x64Reg::R8), Reg::x64(x64Reg::R9) + ], + _ => todo!() + } + }, + CallConv::AppleAarch64 => todo!(), + CallConv::WasmBasicCAbi => todo!(), + } + } + + /// returns how many arguments are stored in registers + pub fn num_reg_args(&self, arch: Arch) -> usize { + self.args(arch).len() + } } \ No newline at end of file diff --git a/src/CodeGen/compilation/assign.rs b/src/CodeGen/compilation/assign.rs new file mode 100644 index 00000000..15b8581f --- /dev/null +++ b/src/CodeGen/compilation/assign.rs @@ -0,0 +1,21 @@ +use crate::prelude::ConstAssign; +use crate::IR::{Block, Const, Type, Var}; +use super::CompilationHelper; +use crate::CodeGen::MachineInstr; + +impl CompilationHelper { + #[allow(missing_docs)] + pub fn compile_assign_var_type(&mut self, node: &ConstAssign, mc_sink: &mut Vec, block: &Block) { + todo!() + } + + #[allow(missing_docs)] + pub fn compile_assign_var_var(&mut self, node: &ConstAssign, mc_sink: &mut Vec, block: &Block) { + todo!() + } + + #[allow(missing_docs)] + pub fn compile_assign_var_const(&mut self, node: &ConstAssign, mc_sink: &mut Vec, block: &Block) { + todo!() + } +} \ No newline at end of file diff --git a/src/CodeGen/compilation/call.rs b/src/CodeGen/compilation/call.rs new file mode 100644 index 00000000..3af55725 --- /dev/null +++ b/src/CodeGen/compilation/call.rs @@ -0,0 +1,11 @@ +use crate::prelude::Call; +use crate::IR::{Block, Function, Var}; +use super::CompilationHelper; +use crate::CodeGen::MachineInstr; + +impl CompilationHelper { + #[allow(missing_docs)] + pub fn compile_call(&mut self, node: &Call, Var>, mc_sink: &mut Vec, block: &Block) { + todo!() + } +} \ No newline at end of file diff --git a/src/CodeGen/compilation/cast.rs b/src/CodeGen/compilation/cast.rs new file mode 100644 index 00000000..752b70e3 --- /dev/null +++ b/src/CodeGen/compilation/cast.rs @@ -0,0 +1,10 @@ +use crate::prelude::Cast; +use crate::IR::{Block, TypeMetadata, Var}; +use super::CompilationHelper; +use crate::CodeGen::MachineInstr; + +impl CompilationHelper { + pub fn compile_cast(&mut self, node: &Cast, mc_sink: &mut Vec, block: &Block) { + todo!() + } +} \ No newline at end of file diff --git a/src/CodeGen/compilation/math.rs b/src/CodeGen/compilation/math.rs index 33c86870..689987ae 100644 --- a/src/CodeGen/compilation/math.rs +++ b/src/CodeGen/compilation/math.rs @@ -59,7 +59,7 @@ macro_rules! MathVarType { ($func:ident, $node:ident, $mnemonic:expr) => { impl CompilationHelper { #[allow(missing_docs)] - pub(crate) fn $func(&mut self, node: &$node, mc_sink: &mut Vec, block: &Block) { + pub fn $func(&mut self, node: &$node, mc_sink: &mut Vec, block: &Block) { let src1 = *self.vars.get(&node.inner1).expect("expected valid variable"); let boxed: Box = Box::new(node.clone()); diff --git a/src/CodeGen/compilation/mod.rs b/src/CodeGen/compilation/mod.rs index 9a90feb3..6eaf5938 100644 --- a/src/CodeGen/compilation/mod.rs +++ b/src/CodeGen/compilation/mod.rs @@ -1,13 +1,17 @@ use std::collections::HashMap; -use crate::{Target::Arch, IR::Var}; +use crate::{Target::Arch, IR::{Function, Var}}; use super::{calling_convention::MachineCallingConvention, reg::Reg, reg_vec::RegVec, MCInstr, MachineInstr}; mod math; +mod cast; +mod call; mod ret; +mod assign; -pub(crate) struct CompilationHelper { +/// helps with compilation +pub struct CompilationHelper { pub(crate) regs: RegVec, pub(crate) arch: Arch, pub(crate) lower: Option) -> Vec>>, @@ -49,6 +53,27 @@ impl CompilationHelper { location } + + /// passes the arguments into the right register + pub(crate) fn build_argument_preprocessing(&mut self, func: &Function) { + let func = &func.ty; + + for (num, ty) in &func.args { + + let location = { + if let Some(reg) = self.call.args(self.arch).get(*num) { + VarLocation::Reg(*reg) + } else { + todo!("The new system currently doesn't support memory") + } + }; + + self.vars.insert( + Var { name: format!("%{}", num), ty: *ty }, + location + ); + } + } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] diff --git a/src/CodeGen/compilation/ret.rs b/src/CodeGen/compilation/ret.rs index ec16cca1..f7f8a0d5 100644 --- a/src/CodeGen/compilation/ret.rs +++ b/src/CodeGen/compilation/ret.rs @@ -3,18 +3,23 @@ use crate::{prelude::Return, CodeGen::{MachineInstr, MachineMnemonic, MachineOpe use super::CompilationHelper; impl CompilationHelper { + #[allow(missing_docs)] pub fn compile_ret_ty(&mut self, node: &Return, mc_sink: &mut Vec, _: &Block) { let mut instr = MachineInstr::new(MachineMnemonic::Move); - instr.add_operand(MachineOperand::Reg(self.call.return_reg(self.arch)) ); + + instr.add_operand(MachineOperand::Reg(self.call.return_reg(self.arch, node.inner1.into())) ); instr.add_operand(MachineOperand::Imm(node.inner1.val() as i64)); + mc_sink.push( MachineInstr::new(MachineMnemonic::Return) ); } + #[allow(missing_docs)] pub fn compile_ret_var(&mut self, node: &Return, mc_sink: &mut Vec, _: &Block) { let src = *self.vars.get(&node.inner1).expect("expected valid variable"); let mut instr = MachineInstr::new(MachineMnemonic::Move); - instr.add_operand(MachineOperand::Reg(self.call.return_reg(self.arch)) ); + + instr.add_operand(MachineOperand::Reg(self.call.return_reg(self.arch, node.inner1.ty)) ); match src { super::VarLocation::Reg(reg) => instr.add_operand(MachineOperand::Reg(reg)), diff --git a/src/CodeGen/mod.rs b/src/CodeGen/mod.rs index a52a3fa7..6e24d7c8 100644 --- a/src/CodeGen/mod.rs +++ b/src/CodeGen/mod.rs @@ -8,4 +8,6 @@ pub(crate) mod calling_convention; pub use reg_vec::*; pub use reg::*; pub use settings::*; -pub use instr::*; \ No newline at end of file +pub use instr::*; +pub use calling_convention::*; +pub use compilation::*; \ No newline at end of file diff --git a/src/CodeGen/reg_vec.rs b/src/CodeGen/reg_vec.rs index 368aa751..ecd5c3c9 100644 --- a/src/CodeGen/reg_vec.rs +++ b/src/CodeGen/reg_vec.rs @@ -30,4 +30,11 @@ impl RegVec { entry.pop() } else { None } } + + /// reversees the registers of the arch + pub fn reverse(&mut self, arch: Arch) { + if let Some(entry) = self.regs.get_mut(&arch) { + entry.reverse(); + } + } } diff --git a/src/IR/nodes/mod.rs b/src/IR/nodes/mod.rs index 8d92e881..09b90898 100644 --- a/src/IR/nodes/mod.rs +++ b/src/IR/nodes/mod.rs @@ -73,7 +73,7 @@ macro_rules! IrTypeWith1 { ($name:tt, $param1:tt) => { /// An Ir node #[derive(Debug, Clone, PartialEq, Eq, Hash)] - pub(crate) struct $name<$param1> { + pub struct $name<$param1> { /// inner value pub(crate) inner1: $param1, } diff --git a/src/Target/mod.rs b/src/Target/mod.rs index 9554ec23..1c8c89cb 100644 --- a/src/Target/mod.rs +++ b/src/Target/mod.rs @@ -1,10 +1,8 @@ mod triple; mod target_descr; mod x64; -mod reg; mod registry; pub use x64::*; -pub use reg::Reg; pub use triple::Triple; pub use target_descr::TargetBackendDescr; pub use registry::TargetRegistry; diff --git a/src/Target/reg.rs b/src/Target/reg.rs deleted file mode 100644 index 6f35744b..00000000 --- a/src/Target/reg.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::{any::Any, fmt::{Debug, Display}}; - -/// A register -pub trait Reg: Display + ToString + Debug + Any { - /// sub64 variant (e.g: eax -> rax (x64) or x0 -> x0 (aarch64)) - fn sub64(&self) -> String; - /// sub32 variant (e.g: rax -> eax (x64) or x0 -> x0 (aarch64)) - fn sub32(&self) -> String; - /// sub16 variant (e.g: rax -> ax (x64) or x0 -> x0 (aarch64)) - fn sub16(&self) -> String; - /// sub8 variant (e.g: rax -> al (x64) or x0 -> x0 (aarch64)) - fn sub8(&self) -> String; - - /// is general pourpus 64 bit wide - fn is_gr64(&self) -> bool; - /// is general pourpus 32 bit wide - fn is_gr32(&self) -> bool; - /// is general pourpus 16 bit wide - fn is_gr16(&self) -> bool; - #[allow(dead_code)] - /// is general pourpus 8 bit wide - fn is_gr8(&self) -> bool; - - /// return self as Box - fn boxed(&self) -> Box; - - /// encodes the register - fn enc(&self) -> u8; - - /// parses the string variant - fn from(&self, string: String) -> Box; - - #[doc(hidden)] - fn as_any(&self) -> &dyn Any; -} - -impl PartialEq for Box { - fn eq(&self, other: &Self) -> bool { - other.sub64() == self.sub64() - } -} - -impl Eq for Box {} - -impl Clone for Box { - fn clone(&self) -> Self { - self.boxed() - } -} \ No newline at end of file diff --git a/src/Target/target_descr.rs b/src/Target/target_descr.rs index 9a555a54..d2fc4e7b 100644 --- a/src/Target/target_descr.rs +++ b/src/Target/target_descr.rs @@ -4,9 +4,7 @@ use crate::CodeGen::{compilation::CompilationHelper, MachineInstr}; use crate::IR::{Const, Function, Type, TypeMetadata}; use super::Triple; -use super::{CallConv, Compiler, instr::Instr, Lexer}; - -pub(crate) type CompileFunc = fn(&T, &mut TargetBackendDescr) -> Vec; +use super::{CallConv, Compiler, Lexer}; /// The TargetBackendDescr is used to store all the functions/information to compile ir nodes into assembly #[allow(unused)] @@ -67,20 +65,31 @@ impl TargetBackendDescr { self.compile.clone().unwrap() } + /// builds all ir nodes of the current block into a vector of MachineInstr pub fn build_instrs(&mut self, func: &Function, triple: &Triple) -> Vec { + let helper = if let Some(helper) = &mut self.helper { helper } + else { panic!("no current compilation helper"); }; + + if helper.arch != triple.arch { + panic!("the architecture of the triple {:?} isn't the same as the one of the compilation helper {:?}", triple.arch, helper.arch) + } + let block = if let Some(block) = &self.block { block.clone() } else { - todo!("no current block"); + panic!("no current block"); }; + helper.build_argument_preprocessing(func); + for node in block.nodes { - node.compile(&mut self); + node.compile(self); } self.sink.clone() } + /// Used for lowering machine instructions into dyn MCInstr pub fn lower(&self, instrs: Vec) -> Vec> { if let Some(helper) = &self.helper { if let Some(lower) = helper.lower { diff --git a/src/Target/x64/asm/instr.rs b/src/Target/x64/asm/instr.rs index e3f582e5..fa3e68c1 100644 --- a/src/Target/x64/asm/instr.rs +++ b/src/Target/x64/asm/instr.rs @@ -1,12 +1,12 @@ use std::{fmt::Display, ops::{Add, Sub}, str::FromStr}; -use crate::{Obj::Link, Support::{ColorClass, ColorProfile}, Target::{isa::{buildOpcode, MandatoryPrefix, RexPrefix}, x64Reg, Reg}}; +use crate::{Obj::Link, Support::{ColorClass, ColorProfile}, Target::{isa::{buildOpcode, MandatoryPrefix, RexPrefix}, x64Reg}}; use super::isa::ModRm; /// The target instruction #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Instr { +pub struct X64MCInstr { /// The mnemonic to use pub mnemonic: Mnemonic, /// First operand @@ -15,7 +15,7 @@ pub struct Instr { pub op2: Option, } -impl Instr { +impl X64MCInstr { /// Creates the instruction with 0 operands pub fn with0(mne: Mnemonic) -> Self { Self { @@ -106,7 +106,7 @@ impl Instr { } else if let Some(Operand::Mem(mem)) = &self.op1 { op.push(r); rex.sync(mem.rex(true)); - let enc = &mem.encode(Some(reg.boxed())); + let enc = &mem.encode(Some(*reg)); op.extend_from_slice(&enc.1); } else { todo!() } @@ -130,7 +130,7 @@ impl Instr { } else {rex = Some(mem.rex(false))} } - let enc = &mem.encode(Some(op0.boxed())); + let enc = &mem.encode(Some(*op0)); op.extend_from_slice(&enc.1); } else { todo!() } @@ -445,7 +445,7 @@ impl Instr { } /// Returns if the current instruction is the other instruction but inverted - pub fn invert_of(&self, other: &Instr) -> bool { + pub fn invert_of(&self, other: &X64MCInstr) -> bool { let mut out = false; if self.mnemonic == Mnemonic::Mov && other.mnemonic == Mnemonic::Mov { @@ -497,7 +497,7 @@ impl Instr { } } -impl Display for Instr { +impl Display for X64MCInstr { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let mut string = format!("{}", self.mnemonic); @@ -516,7 +516,7 @@ impl Display for Instr { #[derive(Debug, Clone, PartialEq, Eq)] pub enum InstrEncodingError { /// The given instruction has an invalid variant - InvalidVariant(Instr, String), + InvalidVariant(X64MCInstr, String), } impl Display for InstrEncodingError { @@ -620,7 +620,7 @@ pub enum Operand { /// A number operand Imm(i64), /// A register operand - Reg(Box), + Reg(x64Reg), /// A memory displacement Mem(MemOp), /// The link destination @@ -658,9 +658,9 @@ impl Display for Operand { #[derive(Eq)] pub struct MemOp { /// The base register - pub base: Option>, + pub base: Option, /// The index register - pub index: Option>, + pub index: Option, /// The scale pub scale: isize, /// The displacement @@ -671,7 +671,7 @@ pub struct MemOp { impl MemOp { #[doc(hidden)] - pub fn encode(&self, basis: Option>) -> (/*modrm mod*/u8, Vec) { + pub fn encode(&self, basis: Option) -> (/*modrm mod*/u8, Vec) { let mut scale = match self.scale { 0 => 0, 1 => 0, @@ -781,7 +781,7 @@ impl Clone for MemOp { Self { base: self.base.clone(), index: { - if let Some(index) = &self.index { Some(index.boxed()) } + if let Some(index) = &self.index { Some(*index) } else { None } }, scale: self.scale.clone(), @@ -824,7 +824,7 @@ impl Add for x64Reg { fn add(self, rhs: u32) -> Self::Output { MemOp { - base: Some(self.boxed()), + base: Some(self), index: None, scale: 1, displ: rhs as isize, @@ -838,8 +838,8 @@ impl Add for x64Reg { fn add(self, rhs: x64Reg) -> Self::Output { MemOp { - base: Some(self.boxed()), - index: Some(rhs.boxed()), + base: Some(self), + index: Some(rhs), scale: 1, displ: 0, rip: false, @@ -852,7 +852,7 @@ impl Sub for x64Reg { fn sub(self, rhs: u32) -> Self::Output { MemOp { - base: Some(self.boxed()), + base: Some(self), index: None, scale: 1, displ: -(rhs as isize), diff --git a/src/Target/x64/asm/isa.rs b/src/Target/x64/asm/isa.rs index 8742cba0..064e22cf 100644 --- a/src/Target/x64/asm/isa.rs +++ b/src/Target/x64/asm/isa.rs @@ -1,4 +1,4 @@ -use crate::Target::{x64Reg, Reg}; +use crate::Target::x64Reg; use super::instr::MemOp; @@ -119,7 +119,7 @@ impl ModRm { } pub fn regM(reg: x64Reg, mem: MemOp) -> Vec { - let enc = mem.encode(Some(reg.boxed())); + let enc = mem.encode(Some(reg)); let mut out = vec![]; if let Some(_) = mem.index { @@ -131,8 +131,8 @@ impl ModRm { } pub fn memR(mem: MemOp, reg: x64Reg) -> Vec { - let mut out = vec![mem.encode(Some(reg.boxed())).0 << 6 | reg.enc() << 3 | 0b100]; - out.extend_from_slice(&mem.encode(Some(reg.boxed())).1); + let mut out = vec![mem.encode(Some(reg)).0 << 6 | reg.enc() << 3 | 0b100]; + out.extend_from_slice(&mem.encode(Some(reg)).1); out } diff --git a/src/Target/x64/asm/optimizer.rs b/src/Target/x64/asm/optimizer.rs index 6336b635..65fe2410 100644 --- a/src/Target/x64/asm/optimizer.rs +++ b/src/Target/x64/asm/optimizer.rs @@ -1,6 +1,6 @@ use crate::Target::x64Reg; -use super::instr::{Instr, Mnemonic, Operand}; +use super::instr::{X64MCInstr, Mnemonic, Operand}; /// used for optimizing pub trait Optimize { @@ -8,9 +8,9 @@ pub trait Optimize { fn optimize(&mut self) -> Self; } -impl Optimize for Vec { - fn optimize(&mut self) -> Vec { - let mut out: Vec = vec![]; +impl Optimize for Vec { + fn optimize(&mut self) -> Vec { + let mut out: Vec = vec![]; let mut optimize = false; @@ -37,7 +37,7 @@ impl Optimize for Vec { if let Some(Operand::Reg(reg)) = &instr.op1 { out.pop(); out.push( - Instr::with2( + X64MCInstr::with2( Mnemonic::Lea, Operand::Reg(reg.clone()), Operand::Mem(*op0.as_any().downcast_ref::().unwrap() @@ -66,7 +66,7 @@ impl Optimize for Vec { } if instr.mnemonic == Mnemonic::Ret && last.mnemonic == Mnemonic::Call { out.pop(); - out.push(Instr::with1(Mnemonic::Jmp, instr.op1.clone().expect("call needs to have one op"))); + out.push(X64MCInstr::with1(Mnemonic::Jmp, instr.op1.clone().expect("call needs to have one op"))); optimized = true; } if instr.mnemonic == Mnemonic::Ret { diff --git a/src/Target/x64/asm/parser.rs b/src/Target/x64/asm/parser.rs index c3c971ce..1dab6d69 100644 --- a/src/Target/x64/asm/parser.rs +++ b/src/Target/x64/asm/parser.rs @@ -1,6 +1,6 @@ use std::{collections::VecDeque, error::Error, fmt::Display, str::FromStr}; -use crate::{Support::ColorProfile, Target::{x64Reg, Compiler, Reg}}; +use crate::{Support::ColorProfile, Target::{x64Reg, Compiler}}; use super::{instr::*, Token}; @@ -9,7 +9,7 @@ use super::{instr::*, Token}; pub struct x64Parser { pub(crate) tokens: VecDeque, /// The output instruction - pub out: Option, + pub out: Option, } impl x64Parser { @@ -42,7 +42,7 @@ impl x64Parser { } fn parse_instr(&mut self, mne: Mnemonic) -> Result<(), Box> { - let mut instr = Instr { + let mut instr = X64MCInstr { mnemonic: mne, op1: None, op2: None, @@ -55,7 +55,7 @@ impl x64Parser { first_op = true; } else if let Some(Token::Ident(reg)) = self.tokens.front() { if let Some(reg) = x64Reg::parse(reg.to_string()) { - instr.op1 = Some(Operand::Reg(reg.boxed())) + instr.op1 = Some(Operand::Reg(reg)) } else { Err(ParsingError::UnknownRegOrUnexpectedIdent(reg.to_string()))? } @@ -75,7 +75,7 @@ impl x64Parser { self.tokens.pop_front(); // advance } else if let Some(Token::Ident(reg)) = self.tokens.front() { if let Some(reg) = x64Reg::parse(reg.to_string()) { - instr.op2 = Some(Operand::Reg(reg.boxed())) + instr.op2 = Some(Operand::Reg(reg)) } else { Err(ParsingError::UnknownRegOrUnexpectedIdent(reg.to_string()))? } @@ -115,7 +115,7 @@ impl x64Parser { self.tokens.pop_front(); // advance } else if let Some(Token::Ident(reg)) = self.tokens.front() { if let Some(reg) = x64Reg::parse(reg.to_string()) { - mem.base = Some(reg.boxed()); + mem.base = Some(reg); } else if "rip" == reg.as_str() { mem.rip = true; } else { @@ -139,7 +139,7 @@ impl x64Parser { self.tokens.pop_front(); // advance } else if let Some(Token::Ident(reg)) = self.tokens.front() { if let Some(reg) = x64Reg::parse(reg.to_string()) { - mem.index = Some(reg.boxed()); + mem.index = Some(reg); } else { Err(ParsingError::UnknownRegOrUnexpectedIdent(reg.to_string()))? } diff --git a/src/Target/x64/mod.rs b/src/Target/x64/mod.rs index a34d3f23..b13d549b 100644 --- a/src/Target/x64/mod.rs +++ b/src/Target/x64/mod.rs @@ -5,7 +5,7 @@ use std::collections::VecDeque; mod compilation; //use compilation::*; -use super::{CallConv, Lexer, Reg, TargetBackendDescr}; +use super::{CallConv, Lexer, TargetBackendDescr}; mod reg; use compilation::construct_compilation_helper; pub use reg::*; diff --git a/src/Target/x64/reg.rs b/src/Target/x64/reg.rs index 1ab28fb7..7f2d5b0e 100644 --- a/src/Target/x64/reg.rs +++ b/src/Target/x64/reg.rs @@ -1,6 +1,6 @@ use std::fmt::Display; -use super::Reg; +use crate::IR::TypeMetadata; /// A x64 register #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -69,120 +69,121 @@ impl x64Reg { _ => false, } } -} - -impl Display for x64Reg { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", format!("{:?}", self).to_lowercase()) - } -} -impl Reg for x64Reg { - fn sub64(&self) -> String { + /// The sub 64 bit wide variant of the register + pub fn sub64(&self) -> x64Reg { use x64Reg::*; match self { - Rax | Eax | Ax | Al => "rax", - Rbx | Ebx | Bx | Bl => "rbx", - Rcx | Ecx | Cx | Cl => "rcx", - Rdx | Edx | Dx | Dl => "rdx", - Rsi | Esi | Si | Sil => "rsi", - Rdi | Edi | Di | Dil => "rdi", - - Rsp | Esp | Sp | Spl => "rsp", - Rbp | Ebp | Bp | Bpl => "rbp", + Rax | Eax | Ax | Al => Rax, + Rbx | Ebx | Bx | Bl => Rbx, + Rcx | Ecx | Cx | Cl => Rcx, + Rdx | Edx | Dx | Dl => Rdx, + Rsi | Esi | Si | Sil => Rsi, + Rdi | Edi | Di | Dil => Rdi, + + Rsp | Esp | Sp | Spl => Rsp, + Rbp | Ebp | Bp | Bpl => Rbp, - R8 | R8d | R8w | R8b => "r8", - R9 | R9d | R9w | R9b => "r9", - R10 | R10d | R10w | R10b => "r10", - R11 | R11d | R11w | R11b => "r11", - R12 | R12d | R12w | R12b => "r12", - R13 | R13d | R13w | R13b => "r13", - R14 | R14d | R14w | R14b => "r14", - R15 | R15d | R15w | R15b => "r15", - }.to_string() + R8 | R8d | R8w | R8b => R8, + R9 | R9d | R9w | R9b => R9, + R10 | R10d | R10w | R10b => R10, + R11 | R11d | R11w | R11b => R11, + R12 | R12d | R12w | R12b => R12, + R13 | R13d | R13w | R13b => R13, + R14 | R14d | R14w | R14b => R14, + R15 | R15d | R15w | R15b => R15, + } } - fn sub32(&self) -> String { + /// The sub 32 bit wide variant of the register + pub fn sub32(&self) -> x64Reg { use x64Reg::*; match self { - Rax | Eax | Ax | Al => "eax", - Rbx | Ebx | Bx | Bl => "ebx", - Rcx | Ecx | Cx | Cl => "ecx", - Rdx | Edx | Dx | Dl => "edx", - Rsi | Esi | Si | Sil => "esi", - Rdi | Edi | Di | Dil => "edi", - - Rsp | Esp | Sp | Spl => "esp", - Rbp | Ebp | Bp | Bpl => "ebp", + Rax | Eax | Ax | Al => Eax, + Rbx | Ebx | Bx | Bl => Ebx, + Rcx | Ecx | Cx | Cl => Ecx, + Rdx | Edx | Dx | Dl => Edx, + Rsi | Esi | Si | Sil => Esi, + Rdi | Edi | Di | Dil => Edi, + + Rsp | Esp | Sp | Spl => Esp, + Rbp | Ebp | Bp | Bpl => Ebp, - R8 | R8d | R8w | R8b => "r8d", - R9 | R9d | R9w | R9b => "r9d", - R10 | R10d | R10w | R10b => "r10d", - R11 | R11d | R11w | R11b => "r11d", - R12 | R12d | R12w | R12b => "r12d", - R13 | R13d | R13w | R13b => "r13d", - R14 | R14d | R14w | R14b => "r14d", - R15 | R15d | R15w | R15b => "r15d", - }.to_string() + R8 | R8d | R8w | R8b => R8d, + R9 | R9d | R9w | R9b => R9d, + R10 | R10d | R10w | R10b => R10d, + R11 | R11d | R11w | R11b => R11d, + R12 | R12d | R12w | R12b => R12d, + R13 | R13d | R13w | R13b => R13d, + R14 | R14d | R14w | R14b => R14d, + R15 | R15d | R15w | R15b => R15d, + } } - fn sub16(&self) -> String { + /// The sub 16 bit wide variant of the register + pub fn sub16(&self) -> x64Reg { use x64Reg::*; match self { - Rax | Eax | Ax | Al => "ax", - Rbx | Ebx | Bx | Bl => "bx", - Rcx | Ecx | Cx | Cl => "cx", - Rdx | Edx | Dx | Dl => "dx", - Rsi | Esi | Si | Sil => "si", - Rdi | Edi | Di | Dil => "di", - - Rsp | Esp | Sp | Spl => "sp", - Rbp | Ebp | Bp | Bpl => "bp", + Rax | Eax | Ax | Al => Ax, + Rbx | Ebx | Bx | Bl => Bx, + Rcx | Ecx | Cx | Cl => Cx, + Rdx | Edx | Dx | Dl => Dx, + Rsi | Esi | Si | Sil => Si, + Rdi | Edi | Di | Dil => Di, + + Rsp | Esp | Sp | Spl => Sp, + Rbp | Ebp | Bp | Bpl => Bp, - R8 | R8d | R8w | R8b => "r8w", - R9 | R9d | R9w | R9b => "r9w", - R10 | R10d | R10w | R10b => "r10w", - R11 | R11d | R11w | R11b => "r11w", - R12 | R12d | R12w | R12b => "r12w", - R13 | R13d | R13w | R13b => "r13w", - R14 | R14d | R14w | R14b => "r14w", - R15 | R15d | R15w | R15b => "r15w", - }.to_string() + R8 | R8d | R8w | R8b => R8w, + R9 | R9d | R9w | R9b => R9w, + R10 | R10d | R10w | R10b => R10w, + R11 | R11d | R11w | R11b => R11w, + R12 | R12d | R12w | R12b => R12w, + R13 | R13d | R13w | R13b => R13w, + R14 | R14d | R14w | R14b => R14w, + R15 | R15d | R15w | R15b => R15w, + } } - fn sub8(&self) -> String { + /// The sub8 bit wide variant of the register + pub fn sub8(&self) -> x64Reg { use x64Reg::*; match self { - Rax | Eax | Ax | Al => "ax", - Rbx | Ebx | Bx | Bl => "bx", - Rcx | Ecx | Cx | Cl => "cx", - Rdx | Edx | Dx | Dl => "dx", - Rsi | Esi | Si | Sil => "sil", - Rdi | Edi | Di | Dil => "dil", - - Rsp | Esp | Sp | Spl => "spl", - Rbp | Ebp | Bp | Bpl => "bpl", - - R8 | R8d | R8w | R8b => "r8b", - R9 | R9d | R9w | R9b => "r9b", - R10 | R10d | R10w | R10b => "r10b", - R11 | R11d | R11w | R11b => "r11b", - R12 | R12d | R12w | R12b => "r12b", - R13 | R13d | R13w | R13b => "r13b", - R14 | R14d | R14w | R14b => "r14b", - R15 | R15d | R15w | R15b => "r15b", - }.to_string() - } + Rax | Eax | Ax | Al => Ax, + Rbx | Ebx | Bx | Bl => Bx, + Rcx | Ecx | Cx | Cl => Cx, + Rdx | Edx | Dx | Dl => Dx, + Rsi | Esi | Si | Sil => Sil, + Rdi | Edi | Di | Dil => Dil, - fn boxed(&self) -> Box { - Box::from(*self) + Rsp | Esp | Sp | Spl => Spl, + Rbp | Ebp | Bp | Bpl => Bpl, + + R8 | R8d | R8w | R8b => R8b, + R9 | R9d | R9w | R9b => R9b, + R10 | R10d | R10w | R10b => R10b, + R11 | R11d | R11w | R11b => R11b, + R12 | R12d | R12w | R12b => R12b, + R13 | R13d | R13w | R13b => R13b, + R14 | R14d | R14w | R14b => R14b, + R15 | R15d | R15w | R15b => R15b, + } } - fn from(&self, string: String) -> Box { - x64Reg::parse(string).expect("need valid register").boxed() + /// gets the subvariant based on the type + pub fn sub_ty(&self, ty: TypeMetadata) -> x64Reg { + match ty.byteSize() { + 8 => self.sub64(), + 4 => self.sub32(), + 2 => self.sub16(), + 1 => self.sub8(), + + _ => todo!("the type is to big for a single register"), + } } - - fn is_gr64(&self) -> bool { + + /// Is the register (or better the subvariant) 64 bit wide? + pub fn is_gr64(&self) -> bool { use x64Reg::*; match self { Rax | Rbx | Rcx | Rdx | Rsi | Rdi | @@ -193,7 +194,8 @@ impl Reg for x64Reg { } } - fn is_gr32(&self) -> bool { + /// Is the register (or better the subvariant) 32 bit wide? + pub fn is_gr32(&self) -> bool { use x64Reg::*; match self { Eax | Ebx | Ecx | Edx | Esi | Edi | @@ -204,7 +206,8 @@ impl Reg for x64Reg { } } - fn is_gr16(&self) -> bool { + /// Is the register (or better the subvariant) 16 bit wide? + pub fn is_gr16(&self) -> bool { use x64Reg::*; match self { Ax | Bx | Cx | Dx | Si | Di | @@ -215,7 +218,8 @@ impl Reg for x64Reg { } } - fn is_gr8(&self) -> bool { + /// Is the register (or better the subvariant) 8 bit wide? + pub fn is_gr8(&self) -> bool { use x64Reg::*; match self { Al | Bl | Cl | Dl | Sil | Dil | @@ -226,7 +230,8 @@ impl Reg for x64Reg { } } - fn enc(&self) -> u8 { + #[doc(hidden)] + pub fn enc(&self) -> u8 { match self { x64Reg::Rax | x64Reg::Eax | x64Reg::Ax | x64Reg::Al => 0, x64Reg::Rcx | x64Reg::Ecx | x64Reg::Cx | x64Reg::Cl => 1, @@ -249,7 +254,14 @@ impl Reg for x64Reg { } } - fn as_any(&self) -> &dyn std::any::Any { + #[doc(hidden)] + pub fn as_any(&self) -> &dyn std::any::Any { self } } + +impl Display for x64Reg { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", format!("{:?}", self).to_lowercase()) + } +} \ No newline at end of file diff --git a/tests/x64_instruction_encoding.rs b/tests/x64_instruction_encoding.rs index ad491fd0..74550359 100644 --- a/tests/x64_instruction_encoding.rs +++ b/tests/x64_instruction_encoding.rs @@ -1,18 +1,18 @@ -use ygen::{Optimizations::auto_max_optimize, Target::{instr::*, x64Reg, Reg}}; +use ygen::{Optimizations::auto_max_optimize, Target::{instr::*, x64Reg}}; #[test] pub fn test_mov() { - let instr = Instr::with2( + let instr = X64MCInstr::with2( Mnemonic::Mov, - Operand::Reg(x64Reg::Rcx.boxed()), - Operand::Mem(MemOp { base: Some(x64Reg::R15.boxed()), index: None, scale: 1, displ: 5, rip: false }) + Operand::Reg(x64Reg::Rcx), + Operand::Mem(MemOp { base: Some(x64Reg::R15), index: None, scale: 1, displ: 5, rip: false }) ); assert_eq!(instr.encode(), Ok((vec![0x49, 0x8B, 0x4F, 0x05], None))); - let instr = Instr::with2( + let instr = X64MCInstr::with2( Mnemonic::Mov, - Operand::Reg(x64Reg::R12b.boxed()), + Operand::Reg(x64Reg::R12b), Operand::Imm(12) ); @@ -21,7 +21,7 @@ pub fn test_mov() { #[test] pub fn test_ret() { - let instr = Instr::with0(Mnemonic::Ret); + let instr = X64MCInstr::with0(Mnemonic::Ret); assert_eq!(instr.encode(), Ok((vec![0xC3], None))); } @@ -29,16 +29,16 @@ pub fn test_ret() { #[test] pub fn test_optimization() { let mut instrs = vec![ - Instr::with0(Mnemonic::StartOptimization), - Instr::with2(Mnemonic::Mov, Operand::Reg(x64Reg::Rax.boxed()), Operand::Reg(x64Reg::Rcx.boxed())), - Instr::with2(Mnemonic::Add, Operand::Reg(x64Reg::Rax.boxed()), Operand::Reg(x64Reg::Rdx.boxed())), - Instr::with2(Mnemonic::Mov, Operand::Reg(x64Reg::Rcx.boxed()), Operand::Reg(x64Reg::Rax.boxed())), + X64MCInstr::with0(Mnemonic::StartOptimization), + X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(x64Reg::Rax), Operand::Reg(x64Reg::Rcx)), + X64MCInstr::with2(Mnemonic::Add, Operand::Reg(x64Reg::Rax), Operand::Reg(x64Reg::Rdx)), + X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(x64Reg::Rcx), Operand::Reg(x64Reg::Rax)), ]; let expected_optimized = vec![ - Instr::with0(Mnemonic::StartOptimization), - Instr::with2(Mnemonic::Lea, Operand::Reg(x64Reg::Rax.boxed()), Operand::Mem(x64Reg::Rcx + x64Reg::Rdx)), - Instr::with2(Mnemonic::Mov, Operand::Reg(x64Reg::Rcx.boxed()), Operand::Reg(x64Reg::Rax.boxed())), + X64MCInstr::with0(Mnemonic::StartOptimization), + X64MCInstr::with2(Mnemonic::Lea, Operand::Reg(x64Reg::Rax), Operand::Mem(x64Reg::Rcx + x64Reg::Rdx)), + X64MCInstr::with2(Mnemonic::Mov, Operand::Reg(x64Reg::Rcx), Operand::Reg(x64Reg::Rax)), ]; auto_max_optimize(&mut instrs);