Skip to content

Commit

Permalink
fasm target support
Browse files Browse the repository at this point in the history
  • Loading branch information
hyouteki committed Aug 15, 2024
1 parent e9b2647 commit ab80835
Show file tree
Hide file tree
Showing 17 changed files with 303 additions and 74 deletions.
43 changes: 25 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,27 +26,34 @@ The corrected AST then proceeds to the optimization ([`opt`](./src/opt)) module,

The optimized CFG is then passed to the translation (`trn`) module, which translates it into assembly code tailored to the target architecture.

### Supported Targets
| flag | Status | Notes |
|------------------------|----------------|----------------------------------|
| `fasm-linux-x86_64` | ✖️ In Progress | Future support under development |
| `fasm-windows-x86_64` | ✖️ Planned | Future support under development |
| `wasm` | ✖️ Planned | Future support under development |

### Getting Started
``` asm
function fib, 1
arg n
a = 0
b = 1
i = 1
label begin
if (i == n) goto end
t = b
b = a + b
a = t
i = i + 1
goto begin
label end
ret b
arg n
a = 0
b = 1
i = 1
label begin
if (i == n) goto end
t = b
b = a + b
a = t
i = i + 1
goto begin
label end
ret b
function main, 0
param 3
a = call fib, 1
ret a
param 3
a = call fib, 1
ret a
```
``` bash
cargo run -- compile -f ./eg/fib.irl --cfg
Expand All @@ -68,7 +75,7 @@ Options:
-v, --verbose Sets info level to verbose
--wat Generates WAT (Web Assembly Text)
--wasm Generates WASM (Web Assembly)
--fasm Generates FASM (Flat Assembly)
--fasm-linux-x86_64 Generates FASM (Flat Assembly)
-h, --help Print help
```

Expand All @@ -81,5 +88,5 @@ Options:
- [flatassembler - tgrysztar](https://flatassembler.net/)
- [wabt - webassembly](https://github.com/WebAssembly/wabt)

### Cortesy
### Courtesy
- [fasm-mode - emacsattic](https://github.com/emacsattic/fasm-mode/)
27 changes: 27 additions & 0 deletions eg/fib.fasm
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
format ELF64 executable 3
entry main
segment gnustack
segment executable
fib:
sub rsp, 20
jmp fib_label_1
fib_label_1:
jmp fib_label_begin
fib_label_begin:
jmp fib_label_4
fib_label_end:
mov r14, [rsp+0]
add rsp, 20
mov rax, r14
ret
fib_label_4:
jmp fib_label_begin
main:
sub rsp, 4
jmp main_label_1
main_label_1:
mov r14, [rsp+0]
add rsp, 4
mov rax, 60
mov rdi, r14
syscall
Binary file added eg/test
Binary file not shown.
42 changes: 28 additions & 14 deletions eg/test.fasm
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@
format ELF64
section '.text' executable
function_fib:
goto label_1
label_1:
goto label_begin
label_begin:
goto label_4
label_end:
label_4:
goto label_begin
function_main:
goto label_1
label_1:
format ELF64 executable 3
entry main
segment gnustack
segment executable
fib:
sub rsp, 20
jmp fib_label_1
fib_label_1:
jmp fib_label_begin
fib_label_begin:
jmp fib_label_4
fib_label_end:
mov rax, [rsp+12]
add rsp, 20
ret
fib_label_4:
jmp fib_label_begin
main:
sub rsp, 4
jmp main_label_1
main_label_1:
mov rdi, 3
call fib
mov [rsp+0], rax
mov rax, 60
mov rdi, [rsp+0]
add rsp, 4
syscall
2 changes: 1 addition & 1 deletion eg/test.irl
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ function fib, 1
function main, 0
param 3
a = call fib, 1
ret a
ret a
2 changes: 1 addition & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub fn cli() -> Command {
.action(ArgAction::SetTrue)
.help("Generates WASM (Web Assembly)"))
.arg(Arg::new("fasm")
.long("fasm")
.long("fasm-linux-x86_64")
.required(false)
.action(ArgAction::SetTrue)
.help("Generates FASM (Flat Assembly)"))
Expand Down
55 changes: 54 additions & 1 deletion src/fe/ast.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use std::collections::HashMap;
use std::collections::{HashMap, HashSet};
use crate::fe::{loc::Loc, token::{Token, TokenKind}};

fn print_indent(f: &mut std::fmt::Formatter, indent_sz: usize) {
Expand Down Expand Up @@ -597,6 +597,59 @@ impl AstNode {
AstNode::Ret(_) => {},
};
}
pub fn value_operands(&self) -> HashSet<String> {
match self {
AstNode::Iden(iden_node) => HashSet::from([iden_node.name.clone()]),
AstNode::Num(_) => HashSet::new(),
AstNode::Call(call_node) => HashSet::from([call_node.id.clone()]),
AstNode::Arith(arith_node) => {
let mut res = arith_node.lhs.value_operands();
res.extend(arith_node.rhs.value_operands());
res
},
AstNode::Relop(relop_node) => {
let mut res = relop_node.lhs.value_operands();
res.extend(relop_node.rhs.value_operands());
res
},
AstNode::Unary(unary_node) => unary_node.var.value_operands(),
AstNode::Function(function_node) => {
let mut res = HashSet::new();
for arg in function_node.args.iter() {res.extend(arg.value_operands())}
for node in function_node.body.iter() {res.extend(node.value_operands())}
res
},
AstNode::Assignment(assignment_node) => {
let mut res = HashSet::from([assignment_node.name.clone()]);
res.extend(assignment_node.var.value_operands());
res
},
AstNode::Goto(_) => HashSet::new(),
AstNode::Label(label_node) => {
let mut res = HashSet::new();
for node in label_node.body.iter() {res.extend(node.value_operands())}
res
},
AstNode::If(if_node) => if_node.condition.value_operands(),
AstNode::Ret(ret_node) => ret_node.var.value_operands(),
}
}
pub fn loc(&self) -> Loc {
match self {
AstNode::Iden(node) => node.loc.clone(),
AstNode::Num(node) => node.loc.clone(),
AstNode::Call(node) => node.loc.clone(),
AstNode::Arith(node) => node.loc.clone(),
AstNode::Relop(node) => node.loc.clone(),
AstNode::Unary(node) => node.loc.clone(),
AstNode::Function(node) => node.loc.clone(),
AstNode::Assignment(node) => node.loc.clone(),
AstNode::Goto(node) => node.loc.clone(),
AstNode::Label(node) => node.loc.clone(),
AstNode::If(node) => node.loc.clone(),
AstNode::Ret(node) => node.loc.clone(),
}
}
}

impl std::fmt::Display for AstNode {
Expand Down
4 changes: 4 additions & 0 deletions src/fe/loc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ impl Loc {
eprintln!("{}: error: {}", self, message);
std::process::exit(1);
}
pub fn program_error(&self, message: String) {
eprintln!("{}: error: {}", self.filepath, message);
std::process::exit(1);
}
pub fn message(&self, message: String) {
eprintln!("{}: {}", self, message);
}
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ fn main() {
options.verbose_message(String::from("FE over"));

// module: mw
run_default_ast_pass_manager(&mut ast);
run_default_ast_pass_manager(&mut ast, &options);
options.verbose_message(String::from("MW over"));
if options.debug {
println!("MW Optimized AST");
Expand Down
1 change: 1 addition & 0 deletions src/mw/add_goto_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ impl AstPass for AddGotoPass {
fn apply(&self, nodes: &mut Vec<AstNode>) {
let _ = helper(nodes, 0);
}
fn name(&self) -> String {String::from("add_goto_pass")}
}

fn helper(nodes: &mut Vec<AstNode>, ix: usize) -> bool {
Expand Down
22 changes: 22 additions & 0 deletions src/mw/asm_validation_pass.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
use std::collections::HashSet;
use crate::{fe::ast::*, mw::pass::AstPass};

pub struct AsmValidationPass;

impl AstPass for AsmValidationPass {
fn apply(&self, nodes: &mut Vec<AstNode>) {
if nodes.len() == 0 {return;}
let mut function_names: HashSet<String> = HashSet::new();
for node in nodes.iter() {
if let AstNode::Function(function_node) = node {
function_names.insert(function_node.name.clone());
} else {
node.loc().error(String::from("expected top level function instruction"));
}
}
if !function_names.contains(&String::from("main")) {
nodes[0].loc().program_error(String::from("program entry point aka function 'main' not found"));
}
}
fn name(&self) -> String {String::from("asm_validation_pass")}
}
7 changes: 5 additions & 2 deletions src/mw/default_ast_pass_manager.rs
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
use crate::{fe::ast::AstNode, mw::pass::*};
use crate::cli::CliOptions;
use crate::mw::validate_iden_pass::ValidateIdenPass;
use crate::mw::add_goto_pass::AddGotoPass;
use crate::mw::asm_validation_pass::AsmValidationPass;

const PASS_MAX_APPLICATION_LIMIT: usize = 1;

pub fn run_default_ast_pass_manager(nodes: &mut Vec<AstNode>) {
pub fn run_default_ast_pass_manager(nodes: &mut Vec<AstNode>, options: &CliOptions) {
let mut ast_pass_manager: AstPassManager = AstPassManager::new();
ast_pass_manager.add(AsmValidationPass{});
ast_pass_manager.add(ValidateIdenPass{});
ast_pass_manager.add(AddGotoPass{});

for _ in 0..PASS_MAX_APPLICATION_LIMIT {
let prev_nodes: Vec<AstNode> = nodes.clone();
ast_pass_manager.run(nodes);
ast_pass_manager.run(nodes, options);
if prev_nodes == *nodes {break;}
}
}
1 change: 1 addition & 0 deletions src/mw/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ pub mod pass;
pub mod validate_iden_pass;
pub mod add_goto_pass;
pub mod default_ast_pass_manager;
pub mod asm_validation_pass;
5 changes: 4 additions & 1 deletion src/mw/pass.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
use crate::fe::ast::AstNode;
use crate::cli::CliOptions;

pub trait AstPass {
fn apply(&self, nodes: &mut Vec<AstNode>);
fn name(&self) -> String;
}

pub struct AstPassManager {
Expand All @@ -15,8 +17,9 @@ impl AstPassManager {
pub fn add<T: AstPass + 'static>(&mut self, pass: T) {
self.passes.push(Box::new(pass));
}
pub fn run(&self, nodes: &mut Vec<AstNode>) {
pub fn run(&self, nodes: &mut Vec<AstNode>, options: &CliOptions) {
for pass in self.passes.iter() {
options.verbose_message(format!("running '{}'", pass.name()));
pass.apply(nodes);
}
}
Expand Down
1 change: 1 addition & 0 deletions src/mw/validate_iden_pass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ impl AstPass for ValidateIdenPass {
validate_label(node, &context);
}
}
fn name(&self) -> String {String::from("validate_iden_pass")}
}

fn validate_node(node: &AstNode, context: &mut Context) {
Expand Down
Loading

0 comments on commit ab80835

Please sign in to comment.