Skip to content

Commit

Permalink
[TARGET] creating registry for having the ability to use multiple dif…
Browse files Browse the repository at this point in the history
…ferent targets
  • Loading branch information
Cr0a3 committed Jul 18, 2024
1 parent 1a17241 commit dba2888
Show file tree
Hide file tree
Showing 14 changed files with 400 additions and 96 deletions.
22 changes: 22 additions & 0 deletions src/Target/compiler.rs
Original file line number Diff line number Diff line change
@@ -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<Token>) -> Box<dyn Compiler>;
/// compiles an assembly string into machine code
fn parse(&mut self) -> Result<(), Box<dyn Error>>;
/// Returns the output machine code
fn out(&self) -> Vec<u8>;

#[doc(hidden)]
fn boxed(&self) -> Box<dyn Compiler>;
}

impl Clone for Box<dyn Compiler> {
fn clone(&self) -> Self {
self.boxed()
}
}
18 changes: 18 additions & 0 deletions src/Target/lexer.rs
Original file line number Diff line number Diff line change
@@ -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<Vec<Token>, Box<dyn Error>>;

/// Returns self into a boxed lexer trait
fn boxed(&self) -> Box<dyn Lexer>;
}

impl Clone for Box<dyn Lexer> {
fn clone(&self) -> Self {
self.boxed()
}
}
20 changes: 20 additions & 0 deletions src/Target/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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
Expand Down
78 changes: 78 additions & 0 deletions src/Target/registry.rs
Original file line number Diff line number Diff line change
@@ -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<Arch, TargetBackendDescr<'a>>
}

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<dyn Error>> {
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<Vec<String>, Box<dyn Error>> {
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 {}
27 changes: 24 additions & 3 deletions src/Target/target_descr.rs
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down Expand Up @@ -167,13 +167,19 @@ impl Display for VarStorage {
pub(crate) type CompileFunc<T> = fn(&T, &mut TargetBackendDescr) -> Vec<String>;

/// The TargetBackendDescr is used to store all the functions/information to compile ir nodes into assembly
#[derive(Debug)]
pub struct TargetBackendDescr<'a> {
funcForRetType: Option<CompileFunc<Return<Type>>>,
funcForRetVar: Option<CompileFunc<Return<Var>>>,
funcForConstAssign: Option<CompileFunc<ConstAssign<Var, Type>>>,
funcForAddVarVar: Option<CompileFunc<Add<Var, Var, Var>>>,
funcForAddTypeType: Option<CompileFunc<Add<Type, Type, Var>>>,

pub(crate) buildAsm: Option<for<'b> fn(&'b Block, &Function, &CallConv, &mut TargetBackendDescr<'b>) -> Vec<String>>,
pub(crate) init: Option<fn(CallConv)->TargetBackendDescr<'a>>,

pub(crate) lexer: Option<Box<dyn Lexer>>,
pub(crate) compile: Option<Box<dyn Compiler>>,

pub(crate) block: Option<&'a Block>,
pub(crate) backend: BackendInfos,
pub(crate) call: CallConv,
Expand All @@ -188,6 +194,11 @@ impl<'a> TargetBackendDescr<'a> {
funcForConstAssign: None,
funcForAddVarVar: None,
funcForAddTypeType: None,
init: None,
buildAsm: None,

lexer: None,
compile: None,

block: None,

Expand Down Expand Up @@ -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<dyn Lexer> {
self.lexer.clone().unwrap()
}

/// Returns the compiler to use with the TargetBackendDescr
pub fn compiler(&self) -> Box<dyn Compiler> {
self.compile.clone().unwrap()
}
}
58 changes: 57 additions & 1 deletion src/Target/triple.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::{error::Error, fmt::Display};
use std::{error::Error, fmt::Display, process::Command};
use crate::Support::Colorize;

use super::*;
Expand Down Expand Up @@ -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 {
Expand All @@ -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),
}
})
}
Expand Down Expand Up @@ -235,4 +238,57 @@ impl Triple {
pub fn from(value: &str) -> Result<Triple, TripleError> {
Triple::parse(value)
}

/// returns the calling convention used by the triple
pub fn getCallConv(&self) -> Result<CallConv, TripleError> {
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!()
}
}
52 changes: 47 additions & 5 deletions src/Target/x64/asm/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<Token>,

/// the generated machine code
pub out: Vec<u8>,
pub(crate) out: Vec<u8>,
index: usize,
}

impl Compiler {
/// Creates a new parser
pub fn new(tokens: Vec<Token>) -> Self {
pub(crate) fn new(tokens: Vec<Token>) -> Self {
Self {
tokens: tokens.into(),
out: vec![],
Expand All @@ -27,7 +26,7 @@ impl Compiler {
}

/// Parses the tokens into expressions
pub fn parse(&mut self) -> Result<(), Box<dyn Error>> {
pub(crate) fn parse(&mut self) -> Result<(), Box<dyn Error>> {
let out = if let Some(tok) = self.tokens.front() {
match &tok {
Token::btr => Some(compile_btr(&mut self.tokens)),
Expand Down Expand Up @@ -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<Compiler>,
}

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<dyn Error>> {
let mut compiler = self.inner.clone().unwrap();
compiler.parse()?;
self.inner = Some(compiler);

Ok(())
}

fn boxed(&self) -> Box<dyn crate::Target::Compiler> {
Box::from( self.clone() )
}

fn new(&self, tokens: Vec<Token>) -> Box<dyn crate::Target::Compiler> {
Self {
inner: Some(Compiler::new(tokens)),
}.boxed()
}

fn out(&self) -> Vec<u8> {
let compiler = self.inner.clone().unwrap();
compiler.out
}
}
Loading

0 comments on commit dba2888

Please sign in to comment.