From dba28887ef5b7897c9450464d6c7c76a33da33c5 Mon Sep 17 00:00:00 2001 From: Cr0a3 Date: Thu, 18 Jul 2024 19:55:11 +0200 Subject: [PATCH] [TARGET] creating registry for having the ability to use multiple different targets --- src/Target/compiler.rs | 22 +++++ src/Target/lexer.rs | 18 ++++ src/Target/mod.rs | 20 +++++ src/Target/registry.rs | 78 ++++++++++++++++++ src/Target/target_descr.rs | 27 +++++- src/Target/triple.rs | 58 ++++++++++++- src/Target/x64/asm/compiler.rs | 52 ++++++++++-- src/Target/x64/asm/lexer.rs | 26 ++++-- src/Target/x64/asm/mod.rs | 2 +- src/Target/x64/call.rs | 14 ++++ src/Target/x64/ir.rs | 141 ++++++++++++++++---------------- src/Target/x64/mod.rs | 14 +++- tools/ygen-mc/Cargo.toml | 4 + tools/ygen-mc/{src => }/main.rs | 20 ++++- 14 files changed, 400 insertions(+), 96 deletions(-) create mode 100644 src/Target/compiler.rs create mode 100644 src/Target/lexer.rs create mode 100644 src/Target/registry.rs rename tools/ygen-mc/{src => }/main.rs (79%) diff --git a/src/Target/compiler.rs b/src/Target/compiler.rs new file mode 100644 index 00000000..b7bae736 --- /dev/null +++ b/src/Target/compiler.rs @@ -0,0 +1,22 @@ +use std::error::Error; + +use super::Token; + +/// An wrapper trait for assembly compilers +pub trait Compiler { + /// Creates an new assembly compiler + fn new(&self, tokens: Vec) -> Box; + /// compiles an assembly string into machine code + fn parse(&mut self) -> Result<(), Box>; + /// Returns the output machine code + fn out(&self) -> Vec; + + #[doc(hidden)] + fn boxed(&self) -> Box; +} + +impl Clone for Box { + fn clone(&self) -> Self { + self.boxed() + } +} \ No newline at end of file diff --git a/src/Target/lexer.rs b/src/Target/lexer.rs new file mode 100644 index 00000000..8ccb5d32 --- /dev/null +++ b/src/Target/lexer.rs @@ -0,0 +1,18 @@ +use std::error::Error; + +use super::Token; + +/// The lexer trait +pub trait Lexer { + /// lexes the string + fn lex(&self, string: String) -> Result, Box>; + + /// Returns self into a boxed lexer trait + fn boxed(&self) -> Box; +} + +impl Clone for Box { + fn clone(&self) -> Self { + self.boxed() + } +} \ No newline at end of file diff --git a/src/Target/mod.rs b/src/Target/mod.rs index cbbd3fba..d1d19b78 100644 --- a/src/Target/mod.rs +++ b/src/Target/mod.rs @@ -2,10 +2,26 @@ mod triple; mod target_descr; mod x64; mod reg; +mod registry; pub use x64::*; pub(crate) use reg::Reg; pub use triple::Triple; pub use target_descr::TargetBackendDescr; +pub use registry::TargetRegistry; +pub use registry::RegistryError; +mod lexer; +mod compiler; +pub use lexer::Lexer; +pub use compiler::Compiler; + +/// Initializes all targets +pub fn initializeAllTargets<'a>() -> TargetRegistry<'a> { + let mut registry = TargetRegistry::new(); + + registry.add( Arch::X86_64, initializeX64Target(CallConv::SystemV) ); + + registry +} /// Target architecture #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -119,6 +135,10 @@ pub enum CallConv { WindowsFastCall, /// Linux standart SystemV, + /// Apple version of the aarch64 calling convention + AppleAarch64, + /// The webassembly calling convention + WasmBasicCAbi, } /// Vendor diff --git a/src/Target/registry.rs b/src/Target/registry.rs new file mode 100644 index 00000000..bf717aae --- /dev/null +++ b/src/Target/registry.rs @@ -0,0 +1,78 @@ +use std::{collections::HashMap, error::Error, fmt::Display}; + +use crate::prelude::{Block, Function}; + +use super::{Arch, CallConv, TargetBackendDescr, Triple}; + +/// The target registry: manages different targets +pub struct TargetRegistry<'a> { + targets: HashMap> +} + +impl<'a> TargetRegistry<'a> { + /// Creates an new backend registry + pub fn new() -> Self { + Self { + targets: HashMap::new() + } + } + + /// Adds an new target architecture + pub fn add(&mut self, arch: Arch, descr: TargetBackendDescr<'a>) { + self.targets.insert(arch, descr); + } + + /// Sets the calling convention to use for the specified architecture + /// If it isn't found the function does noting + pub fn setCallingConventionForTarget(&mut self, arch: Arch, call: CallConv) { + if let Some(target) = self.targets.get_mut(&arch) { + target.call = call; + } + } + + /// returns the `TargetBackendDescr` for the triple (also it adjusts it's calling convention ...) + pub fn getBasedOnTriple(&mut self, triple: Triple) -> Result<&mut TargetBackendDescr<'a>, Box> { + if let Some(descr) = self.targets.get_mut(&triple.arch) { + *descr = descr.init.unwrap()(triple.getCallConv()?); + + Ok(descr) + } else { + Err(Box::from( + RegistryError::UnsuportedArch(triple.arch) + )) + } + } + + /// Builds the ir of the given triple into text assembly code + pub fn buildAsmForTarget(&mut self, triple: Triple, block: &Block, funct: &Function) -> Result, Box> { + if let Some(org) = self.targets.get_mut(&triple.arch) { + Ok( + org.buildAsm.unwrap()( + &block, &funct, + &org.init.unwrap()(triple.getCallConv()?).call, // Unnessecary (and slow) but prevents + &mut org.init.unwrap()(triple.getCallConv()?)) // lifetime issues + ) + } else { + Err(Box::from( + RegistryError::UnsuportedArch(triple.arch) + )) + } + } +} + +/// Stores errors which can occure in the `getBasedOnTriple` function in the `TargetRegistry` +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum RegistryError { + /// An unsupported architecture + UnsuportedArch(Arch), +} + +impl Display for RegistryError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", match self { + RegistryError::UnsuportedArch(arch) => format!("unsuported architecture: {:?}", arch), + }) + } +} + +impl Error for RegistryError {} \ No newline at end of file diff --git a/src/Target/target_descr.rs b/src/Target/target_descr.rs index 26e2a0ca..0ab60e2c 100644 --- a/src/Target/target_descr.rs +++ b/src/Target/target_descr.rs @@ -1,9 +1,9 @@ use std::{collections::{HashMap, VecDeque}, fmt::Display}; use core::fmt::Debug; -use crate::prelude::{ir::*, Block, Type, TypeMetadata, Var}; +use crate::prelude::{ir::*, Block, Function, Type, TypeMetadata, Var}; -use super::{Reg, CallConv}; +use super::{CallConv, Compiler, Lexer, Reg}; #[derive(Debug)] pub(crate) struct BackendInfos { @@ -167,13 +167,19 @@ impl Display for VarStorage { pub(crate) type CompileFunc = fn(&T, &mut TargetBackendDescr) -> Vec; /// The TargetBackendDescr is used to store all the functions/information to compile ir nodes into assembly -#[derive(Debug)] pub struct TargetBackendDescr<'a> { funcForRetType: Option>>, funcForRetVar: Option>>, funcForConstAssign: Option>>, funcForAddVarVar: Option>>, funcForAddTypeType: Option>>, + + pub(crate) buildAsm: Option fn(&'b Block, &Function, &CallConv, &mut TargetBackendDescr<'b>) -> Vec>, + pub(crate) init: OptionTargetBackendDescr<'a>>, + + pub(crate) lexer: Option>, + pub(crate) compile: Option>, + pub(crate) block: Option<&'a Block>, pub(crate) backend: BackendInfos, pub(crate) call: CallConv, @@ -188,6 +194,11 @@ impl<'a> TargetBackendDescr<'a> { funcForConstAssign: None, funcForAddVarVar: None, funcForAddTypeType: None, + init: None, + buildAsm: None, + + lexer: None, + compile: None, block: None, @@ -255,4 +266,14 @@ impl<'a> TargetBackendDescr<'a> { func } else { todo!("an corresponding assembly handler needs to be registered in order to compile an AddTypeType ir node")} } + + /// Returns the lexer to use with the TargetBackendDescr + pub fn lexer(&self) -> Box { + self.lexer.clone().unwrap() + } + + /// Returns the compiler to use with the TargetBackendDescr + pub fn compiler(&self) -> Box { + self.compile.clone().unwrap() + } } \ No newline at end of file diff --git a/src/Target/triple.rs b/src/Target/triple.rs index f658385d..ef5ace45 100644 --- a/src/Target/triple.rs +++ b/src/Target/triple.rs @@ -1,4 +1,4 @@ -use std::{error::Error, fmt::Display}; +use std::{error::Error, fmt::Display, process::Command}; use crate::Support::Colorize; use super::*; @@ -29,6 +29,8 @@ pub enum TripleError { UnknownEnv(String), /// An unknown object file format UnknownObj(String), + /// An unsupported target triple + UnsuportedTriple(Triple), } impl Display for TripleError { @@ -39,6 +41,7 @@ impl Display for TripleError { TripleError::UnknownOs(name) => format!("Unknown operating system: '{}'", name), TripleError::UnknownEnv(name) => format!("Unknown environment (maybe unknown vendor cuz error handling isn't implemented the right way): '{}'", name), TripleError::UnknownObj(name) => format!("Unknown object file format: '{}'", name), + TripleError::UnsuportedTriple(triple) => format!("Unsupported triple: {:?}", triple), } }) } @@ -235,4 +238,57 @@ impl Triple { pub fn from(value: &str) -> Result { Triple::parse(value) } + + /// returns the calling convention used by the triple + pub fn getCallConv(&self) -> Result { + Ok(match self.os { + OS::Darwin | OS::Ios | OS::TvOS | OS::MacOS | OS::WatchOS => { + match self.arch { + Arch::Aarch64 => CallConv::AppleAarch64, + _ => CallConv::SystemV, + } + }, + + OS::Win32 => CallConv::WindowsFastCall, + + OS::Unknown => { + match self.arch { + Arch::Wasm32 | Arch::Wasm64 => CallConv::WasmBasicCAbi, + _ => Err(TripleError::UnsuportedTriple(self.clone()))? + } + } + + + _ => CallConv::SystemV, + }) + } + + /// Returns the host target triple + pub fn host() -> Triple { + Triple::parse(&getHostTargetTripleViaRustc()).unwrap() + } +} +use std::str; + +fn getHostTargetTripleViaRustc() -> String { + let output = Command::new("rustc") + .arg("--version") + .arg("--verbose") + .output() + .expect("Failed to execute rustc"); + + if output.status.success() { + let mut out = String::new(); + let stdout = str::from_utf8(&output.stdout).expect("Failed to parse output"); + for line in stdout.lines() { + if line.starts_with("host:") { + let target_triple = line.split_whitespace().nth(1).expect("Failed to parse target triple"); + out = target_triple.to_string(); + } + } + + return out; + } else { + panic!() + } } \ No newline at end of file diff --git a/src/Target/x64/asm/compiler.rs b/src/Target/x64/asm/compiler.rs index 116a9f08..5801dd94 100644 --- a/src/Target/x64/asm/compiler.rs +++ b/src/Target/x64/asm/compiler.rs @@ -6,19 +6,18 @@ use crate::Support::Colorize; use super::Token; use super::compile::*; -/// An assembly parser #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Compiler { +pub(crate) struct Compiler { tokens: VecDeque, /// the generated machine code - pub out: Vec, + pub(crate) out: Vec, index: usize, } impl Compiler { /// Creates a new parser - pub fn new(tokens: Vec) -> Self { + pub(crate) fn new(tokens: Vec) -> Self { Self { tokens: tokens.into(), out: vec![], @@ -27,7 +26,7 @@ impl Compiler { } /// Parses the tokens into expressions - pub fn parse(&mut self) -> Result<(), Box> { + pub(crate) fn parse(&mut self) -> Result<(), Box> { let out = if let Some(tok) = self.tokens.front() { match &tok { Token::btr => Some(compile_btr(&mut self.tokens)), @@ -149,4 +148,47 @@ impl Compiler { Ok(()) } +} + +/// The asm compiler for the x64 backend +/// +/// # Don't use!! It is for internal pourpuses only +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct x64Compiler { + pub(crate) inner: Option, +} + +impl x64Compiler { + /// Creates an new x64 backend + /// # Don't use!! This structure is for internal pourpuses only + pub fn new() -> Self { + Self { + inner: None, + } + } +} + +impl crate::Target::Compiler for x64Compiler { + fn parse(&mut self) -> Result<(), Box> { + let mut compiler = self.inner.clone().unwrap(); + compiler.parse()?; + self.inner = Some(compiler); + + Ok(()) + } + + fn boxed(&self) -> Box { + Box::from( self.clone() ) + } + + fn new(&self, tokens: Vec) -> Box { + Self { + inner: Some(Compiler::new(tokens)), + }.boxed() + } + + fn out(&self) -> Vec { + let compiler = self.inner.clone().unwrap(); + compiler.out + } } \ No newline at end of file diff --git a/src/Target/x64/asm/lexer.rs b/src/Target/x64/asm/lexer.rs index 79887ad7..f41b0b3e 100644 --- a/src/Target/x64/asm/lexer.rs +++ b/src/Target/x64/asm/lexer.rs @@ -2,7 +2,7 @@ use std::{error::Error, fmt::Display, num::ParseIntError}; use logos::Logos; -use crate::Target::{x64Reg, Reg}; +use crate::Target::{x64Reg, Lexer, Reg}; /// An error which can occure during lexing #[derive(Default, Debug, Clone, PartialEq)] @@ -340,13 +340,23 @@ impl Mem { } } -/// Lexes (Turns the source into tokens) the incoming assembly string and outputs tokens -pub fn lex(string: String) -> Result, Box> { - let mut tokens = vec![]; - for tok in Token::lexer(&string) { - tokens.push( tok? ); - } +/// A temporary structure which implements the Lexer trait +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct x64Lexer {} - Ok(tokens) +impl Lexer for x64Lexer { + fn lex(&self, string: String) -> Result, Box> { + let mut tokens = vec![]; + + for tok in Token::lexer(&string) { + tokens.push( tok? ); + } + + Ok(tokens) + } + + fn boxed(&self) -> Box { + Box::from( self.clone() ) + } } \ No newline at end of file diff --git a/src/Target/x64/asm/mod.rs b/src/Target/x64/asm/mod.rs index bad08390..b9c95c18 100644 --- a/src/Target/x64/asm/mod.rs +++ b/src/Target/x64/asm/mod.rs @@ -3,4 +3,4 @@ mod compiler; mod compile; pub use lexer::*; -pub use compiler::Compiler; \ No newline at end of file +pub use compiler::x64Compiler; \ No newline at end of file diff --git a/src/Target/x64/call.rs b/src/Target/x64/call.rs index ec8c8cd8..5c86423d 100644 --- a/src/Target/x64/call.rs +++ b/src/Target/x64/call.rs @@ -8,6 +8,8 @@ impl CallConv { match self { CallConv::SystemV => 6, CallConv::WindowsFastCall => 4, + CallConv::AppleAarch64 => todo!(), + CallConv::WasmBasicCAbi => todo!(), } } @@ -16,6 +18,8 @@ impl CallConv { match self { CallConv::SystemV => vec![x64Reg::Si, x64Reg::Di, x64Reg::Dx, x64Reg::Cx, x64Reg::R8w, x64Reg::R9w], CallConv::WindowsFastCall => vec![x64Reg::Dx, x64Reg::Cx, x64Reg::R8w, x64Reg::R9w], + CallConv::AppleAarch64 => todo!(), + CallConv::WasmBasicCAbi => todo!(), } } @@ -24,6 +28,8 @@ impl CallConv { match self { CallConv::SystemV => vec![x64Reg::Esi, x64Reg::Edi, x64Reg::Edx, x64Reg::Ecx, x64Reg::R8d, x64Reg::R9d], CallConv::WindowsFastCall => vec![x64Reg::Edx, x64Reg::Ecx, x64Reg::R8d, x64Reg::R9d], + CallConv::AppleAarch64 => todo!(), + CallConv::WasmBasicCAbi => todo!(), } } @@ -32,6 +38,8 @@ impl CallConv { match self { CallConv::SystemV => vec![x64Reg::Rsi, x64Reg::Rdi, x64Reg::Rdx, x64Reg::Rcx, x64Reg::R8, x64Reg::R9], CallConv::WindowsFastCall => vec![x64Reg::Rdx, x64Reg::Rcx, x64Reg::R8, x64Reg::R9], + CallConv::AppleAarch64 => todo!(), + CallConv::WasmBasicCAbi => todo!(), } } @@ -40,6 +48,8 @@ impl CallConv { match self { CallConv::WindowsFastCall => x64Reg::Ax, CallConv::SystemV => x64Reg::Ax, + CallConv::AppleAarch64 => todo!(), + CallConv::WasmBasicCAbi => todo!(), } } @@ -48,6 +58,8 @@ impl CallConv { match self { CallConv::WindowsFastCall =>x64Reg::Eax, CallConv::SystemV => x64Reg::Eax, + CallConv::AppleAarch64 => todo!(), + CallConv::WasmBasicCAbi => todo!(), } } @@ -56,6 +68,8 @@ impl CallConv { match self { CallConv::WindowsFastCall => x64Reg::Rax, CallConv::SystemV => x64Reg::Rax, + CallConv::AppleAarch64 => todo!(), + CallConv::WasmBasicCAbi => todo!(), } } } \ No newline at end of file diff --git a/src/Target/x64/ir.rs b/src/Target/x64/ir.rs index 0f04c03b..cde79cf5 100644 --- a/src/Target/x64/ir.rs +++ b/src/Target/x64/ir.rs @@ -38,13 +38,13 @@ pub(crate) fn CompileAddVarVar(add: &Add, registry: &mut TargetBa let boxed: Box = Box::new(add.clone()); - if !registry.block.unwrap().isVarUsedAfterNode(&boxed, &add.inner1) { + if !BlockX86FuncisVarUsedAfterNode(registry.block.unwrap(), &boxed, &add.inner1) { infos.drop(&add.inner1); } - if !registry.block.unwrap().isVarUsedAfterNode(&boxed, &add.inner2) { + if !BlockX86FuncisVarUsedAfterNode(registry.block.unwrap(), &boxed, &add.inner2) { infos.drop(&add.inner2); } - if !registry.block.unwrap().isVarUsedAfterNode(&boxed, &add.inner3) { + if !BlockX86FuncisVarUsedAfterNode(registry.block.unwrap(), &boxed, &add.inner3) { return vec![]; // all of these calculations don't need to be done: dead code removal } @@ -106,7 +106,7 @@ pub(crate) fn CompileConstAssign(assign: &ConstAssign, registry: &mut let boxed: Box = Box::new(assign.clone()); - if !registry.block.unwrap().isVarUsedAfterNode(&boxed, &assign.inner1) { + if !BlockX86FuncisVarUsedAfterNode(registry.block.unwrap(), &boxed, &assign.inner1) { return vec![]; // all of these calculations don't need to be done: dead code removal } @@ -144,7 +144,7 @@ pub(crate) fn CompileAddTyTy(add: &Add, registry: &mut TargetBa let boxed: Box = Box::new(add.clone()); - if !registry.block.unwrap().isVarUsedAfterNode(&boxed, &add.inner3) { + if !BlockX86FuncisVarUsedAfterNode(registry.block.unwrap(), &boxed, &add.inner3) { return vec![]; // all of these calculations don't need to be done: dead code removal } @@ -231,88 +231,85 @@ pub(crate) fn x64BuildEpilog(_: &Block, registry: &mut TargetBackendDescr) -> Ve res } -impl Block { - /// Builds the block to x86 assembly intel syntax - pub fn buildAsmX86<'a>(&'a self, func: &Function, call: &CallConv, registry: &mut TargetBackendDescr<'a>) -> Vec { - registry.block = Some(&self); - - let info = &mut registry.backend; - - let mut reg_vars = 0; - let mut stack_off = 0; - let mut var_index = 0; - - for (_, meta) in &func.ty.args { - let mut var = Var(&mut self.clone(), meta.to_owned()); - var.name = format!("%{}", var_index); - - info.insertVar(var, { - if reg_vars >= call.regArgs() { - let addend = match meta { - TypeMetadata::u16 | TypeMetadata::i16=> 2, - TypeMetadata::u32 | TypeMetadata::i32=> 4, - TypeMetadata::u64 | TypeMetadata::i64=> 8, - TypeMetadata::Void => continue, - }; - - stack_off += addend; - VarStorage::Memory(format!("[rbp - {}]", stack_off - addend)) - } else { - reg_vars += 1; - VarStorage::Register( match meta { - TypeMetadata::u16 | TypeMetadata::i16 => call.args16()[reg_vars - 1].boxed(), - TypeMetadata::u32 | TypeMetadata::i32 => call.args32()[reg_vars - 1].boxed(), - TypeMetadata::u64 | TypeMetadata::i64 => call.args64()[reg_vars - 1].boxed(), - TypeMetadata::Void => continue, - }) - } - }); - - var_index += 1; - } +pub(crate) fn buildAsmX86<'a>(block: &'a Block, func: &Function, call: &CallConv, registry: &mut TargetBackendDescr<'a>) -> Vec { + registry.block = Some(&block); + + let info = &mut registry.backend; + + let mut reg_vars = 0; + let mut stack_off = 0; + let mut var_index = 0; + + for (_, meta) in &func.ty.args { + let mut var = Var(&mut block.clone(), meta.to_owned()); + var.name = format!("%{}", var_index); + + info.insertVar(var, { + if reg_vars >= call.regArgs() { + let addend = match meta { + TypeMetadata::u16 | TypeMetadata::i16=> 2, + TypeMetadata::u32 | TypeMetadata::i32=> 4, + TypeMetadata::u64 | TypeMetadata::i64=> 8, + TypeMetadata::Void => continue, + }; + + stack_off += addend; + VarStorage::Memory(format!("[rbp - {}]", stack_off - addend)) + } else { + reg_vars += 1; + VarStorage::Register( match meta { + TypeMetadata::u16 | TypeMetadata::i16 => call.args16()[reg_vars - 1].boxed(), + TypeMetadata::u32 | TypeMetadata::i32 => call.args32()[reg_vars - 1].boxed(), + TypeMetadata::u64 | TypeMetadata::i64 => call.args64()[reg_vars - 1].boxed(), + TypeMetadata::Void => continue, + }) + } + }); - if reg_vars <= call.regArgs() { - info.dropReg(call.args64()[reg_vars].boxed()); - } + var_index += 1; + } - let mut out = VecDeque::new(); + if reg_vars <= call.regArgs() { + info.dropReg(call.args64()[reg_vars].boxed()); + } - for node in &self.nodes { - let compiled = node.compile(registry); + let mut out = VecDeque::new(); - out.extend(compiled); - } + for node in &block.nodes { + let compiled = node.compile(registry); + out.extend(compiled); + } - registry.block = None; - let mut prolog = x64BuildProlog(&self, registry); - prolog.reverse(); // cuz: push_front + registry.block = None; - for epAsm in prolog { - out.push_front(epAsm); - } + let mut prolog = x64BuildProlog(&block, registry); + prolog.reverse(); // cuz: push_front - out.extend(x64BuildEpilog(&self, registry)); - - Vec::from(out) + for epAsm in prolog { + out.push_front(epAsm); } - pub(crate) fn isVarUsedAfterNode(&self, startingNode: &Box, var: &Var) -> bool { - let mut used = false; - let mut started = false; + out.extend(x64BuildEpilog(&block, registry)); - for node in &self.nodes { - if node.uses(var) && started { - used = true; - } + Vec::from(out) +} - if node.is(startingNode) { - started = true; - } +pub(crate) fn BlockX86FuncisVarUsedAfterNode(block: &Block, startingNode: &Box, var: &Var) -> bool { + let mut used = false; + let mut started = false; + + for node in &block.nodes { + if node.uses(var) && started { + used = true; } - used + if node.is(startingNode) { + started = true; + } } + + used } \ No newline at end of file diff --git a/src/Target/x64/mod.rs b/src/Target/x64/mod.rs index e027bfa1..8fb51f24 100644 --- a/src/Target/x64/mod.rs +++ b/src/Target/x64/mod.rs @@ -6,7 +6,7 @@ use ir::*; use crate::prelude::Module; -use super::{Reg, CallConv, TargetBackendDescr}; +use super::{CallConv, Lexer, Reg, TargetBackendDescr}; mod reg; pub(crate) use reg::*; @@ -16,10 +16,18 @@ mod asm; pub use asm::*; +use crate::Target::Compiler; + /// Initializes the x86-64 target pub fn initializeX64Target<'a>(call_conv: CallConv) -> TargetBackendDescr<'a> { let mut target = TargetBackendDescr::new(); + target.init = Some(initializeX64Target); + target.buildAsm = Some(buildAsmX86); + + target.lexer = Some(x64Lexer {}.boxed()); + target.compile = Some(x64Compiler::new().boxed()); + target.backend.savedRegisters = vec![ x64Reg::R10.boxed(), x64Reg::R11.boxed(), x64Reg::R12.boxed(), x64Reg::R13.boxed(), x64Reg::R14.boxed(), x64Reg::R15.boxed(), ]; @@ -57,6 +65,8 @@ pub fn initializeX64Target<'a>(call_conv: CallConv) -> TargetBackendDescr<'a> { vec![x64Reg::R10b.boxed(), x64Reg::R11b.boxed(), x64Reg::R12b.boxed(), x64Reg::R13b.boxed(), x64Reg::R14b.boxed(), x64Reg::R15b.boxed()] ); }, + CallConv::AppleAarch64 => todo!(), + CallConv::WasmBasicCAbi => todo!(), } target.setCompileFuncForRetType(CompileRetType); @@ -88,7 +98,7 @@ impl Module { lines += &format!(" {}:\n", block.name) } - let asm_lines = block.buildAsmX86(&func, &call, &mut target); + let asm_lines = buildAsmX86(block, &func, &call, &mut target); for line in asm_lines { lines += &format!("\t{}\n", line); diff --git a/tools/ygen-mc/Cargo.toml b/tools/ygen-mc/Cargo.toml index a06edad3..690aa0fc 100644 --- a/tools/ygen-mc/Cargo.toml +++ b/tools/ygen-mc/Cargo.toml @@ -3,5 +3,9 @@ name = "ygen-mc" version = "0.1.0" edition = "2021" +[[bin]] +name = "ygen-mc" +path = "main.rs" + [dependencies] Ygen = { workspace = true } \ No newline at end of file diff --git a/tools/ygen-mc/src/main.rs b/tools/ygen-mc/main.rs similarity index 79% rename from tools/ygen-mc/src/main.rs rename to tools/ygen-mc/main.rs index f428d1cf..594b9a66 100644 --- a/tools/ygen-mc/src/main.rs +++ b/tools/ygen-mc/main.rs @@ -19,7 +19,7 @@ use std::error::Error; -use Ygen::{self, Support::Colorize}; +use Ygen::{self, Support::Colorize, Target::{initializeAllTargets, Triple}}; fn main() -> Result<(), Box> { let mut cli = Ygen::Support::Cli::new( @@ -42,14 +42,26 @@ fn main() -> Result<(), Box> { cli.version(); } + + let triple = { + if let Some(triple) = cli.arg_val("triple") { + Triple::parse(&triple)? + } else { + Triple::host() + } + }; + + let mut registry = initializeAllTargets(); + let backend = registry.getBasedOnTriple(triple)?; + let asm = cli.arg_val("as").expect("we said it was required"); - let lexed = Ygen::Target::lex(asm.clone())?; + let lexed = backend.lexer().lex(asm.clone())?; if cli.opt("lex") { println!("{}: {:?}", "Lexing result".gray(), lexed); } - let mut comp = Ygen::Target::Compiler::new(lexed); + let mut comp = backend.compiler().new(lexed); comp.parse()?; println!("{}: {}", "Asm string".gray(), asm); @@ -57,7 +69,7 @@ fn main() -> Result<(), Box> { println!("{}: {}", "Compilation result".gray(), { let mut fmt = String::from("0x"); - for byte in comp.out { + for byte in comp.out() { fmt += &format!("{:#04X}", byte).replace("0x", ""); }