Skip to content

Commit

Permalink
Add src/arm64, finish arm64/asm.rs
Browse files Browse the repository at this point in the history
  • Loading branch information
koba-e964 committed Dec 16, 2024
1 parent 8c3b3cb commit 748b7d2
Show file tree
Hide file tree
Showing 8 changed files with 1,666 additions and 4 deletions.
348 changes: 348 additions & 0 deletions src/arm64/asm.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,348 @@
use crate::id;
use crate::syntax::{FloatBin, IntBin, Type};
use std::collections::HashSet;
use std::fmt;

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum IdOrImm {
V(String),
C(i32),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Asm {
Ans(Exp),
Let(String, Type, Exp, Box<Asm>),
}

// We have GE because arm64 instructions are not symmetric
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CompBin {
Eq,
LE,
GE,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FCompBin {
Eq,
LE,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Exp {
Nop,
Set(i32),
SetL(id::L),
Mov(String),
Neg(String),
IntOp(IntBin, String, IdOrImm),
// Ld(x, y, disp) -> dword ptr [x + y * disp]
Ld(String, IdOrImm, i32),
St(String, String, IdOrImm, i32),
FMovD(String),
FNegD(String),
FloatOp(FloatBin, String, String),
LdDF(String, IdOrImm, i32),
StDF(String, String, IdOrImm, i32),
Comment(String),
// virtual instructions
IfComp(CompBin, String, IdOrImm, Box<Asm>, Box<Asm>),
IfFComp(FCompBin, String, String, Box<Asm>, Box<Asm>),
/// CallCls(Closure address, integer arguments, float arguments)
CallCls(String, Box<[String]>, Box<[String]>),
/// CallDir(Closure address, integer arguments, float arguments)
CallDir(id::L, Box<[String]>, Box<[String]>),
Save(String, String),
Restore(String),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Fundef {
pub name: id::L,
pub args: Box<[String]>,
pub fargs: Box<[String]>,
pub body: Asm,
pub ret: Type,
}

#[derive(Debug, Clone, PartialEq)]
pub struct Prog(pub Box<[(id::L, f64)]>, pub Box<[Fundef]>, pub Asm);

// Display
impl Asm {
fn fmt_with_indent(&self, f: &mut fmt::Formatter, level: usize) -> fmt::Result {
match self {
Asm::Ans(e) => {
write!(f, "ret ")?;
e.fmt_with_indent(f, level)
}
Asm::Let(x, t, e1, e2) => {
write!(f, "let {}: {} = ", x, t)?;
e1.fmt_with_indent(f, level)?;
writeln!(f, " in")?;
for _ in 0..level {
write!(f, " ")?;
}
e2.fmt_with_indent(f, level)
}
}
}
}
impl Exp {
fn fmt_with_indent(&self, f: &mut fmt::Formatter, level: usize) -> fmt::Result {
match self {
Exp::Nop => write!(f, "nop"),
Exp::Set(i) => write!(f, "set {}", i),
Exp::SetL(id::L(l)) => write!(f, "setl {}", l),
Exp::Mov(x) => write!(f, "set {}", x),
Exp::Neg(x) => write!(f, "neg {}", x),
Exp::IntOp(op, x, y) => {
let op_string = match op {
IntBin::Add => "add",
IntBin::Sub => "sub",
};
write!(f, "{} {} {}", op_string, x, y)
}
Exp::Ld(x, y, offset) => write!(f, "ld {} {} {}", x, y, offset),
Exp::St(z, x, y, offset) => write!(f, "st {} {} {} {}", z, x, y, offset),
Exp::FMovD(x) => write!(f, "fmov {}", x),
Exp::FNegD(x) => write!(f, "fneg {}", x),
Exp::FloatOp(op, x, y) => {
let op_string = match op {
FloatBin::FAdd => "fadd",
FloatBin::FSub => "fsub",
FloatBin::FMul => "fmul",
FloatBin::FDiv => "fdiv",
};
write!(f, "{} {} {}", op_string, x, y)
}
Exp::LdDF(x, y, offset) => write!(f, "lddf {} {} {}", x, y, offset),
Exp::StDF(z, x, y, offset) => write!(f, "stdf {} {} {} {}", z, x, y, offset),
Exp::Comment(comment) => write!(f, ";; {}", comment),
Exp::IfComp(op, x, y, e1, e2) => {
let op_string = match op {
CompBin::Eq => "eq",
CompBin::LE => "le",
CompBin::GE => "ge",
};
writeln!(f, "if {} {} {} then", op_string, x, y)?;
for _ in 0..level + 2 {
write!(f, " ")?;
}
e1.fmt_with_indent(f, level + 2)?;
writeln!(f)?;
for _ in 0..level {
write!(f, " ")?;
}
writeln!(f, "else")?;
for _ in 0..level + 2 {
write!(f, " ")?;
}
e2.fmt_with_indent(f, level + 2)
}
Exp::IfFComp(op, x, y, e1, e2) => {
let op_string = match op {
FCompBin::Eq => "feq",
FCompBin::LE => "fle",
};
writeln!(f, "if {} {} {} then", op_string, x, y)?;
for _ in 0..level + 2 {
write!(f, " ")?;
}
e1.fmt_with_indent(f, level + 2)?;
writeln!(f)?;
for _ in 0..level {
write!(f, " ")?;
}
writeln!(f, "else")?;
for _ in 0..level + 2 {
write!(f, " ")?;
}
e2.fmt_with_indent(f, level + 2)
}
Exp::CallCls(name, ys, zs) => {
write!(f, "[{}]", name)?;
for v in ys.iter() {
write!(f, " {}", v)?;
}
write!(f, ",")?;
for v in zs.iter() {
write!(f, " {}", v)?;
}
Ok(())
}
Exp::CallDir(id::L(name), ys, zs) => {
write!(f, "{}", name)?;
for v in ys.iter() {
write!(f, " {}", v)?;
}
for v in zs.iter() {
write!(f, " fl:{}", v)?;
}
Ok(())
}
Exp::Save(varname, regname) => write!(f, "SAVE {} {}", varname, regname),
Exp::Restore(x) => write!(f, "restore {}", x),
}
}
}
impl fmt::Display for IdOrImm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
IdOrImm::V(x) => write!(f, "{}", x),
IdOrImm::C(imm) => write!(f, "{}", imm),
}
}
}
impl fmt::Display for Asm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.fmt_with_indent(f, 0)
}
}
impl fmt::Display for Exp {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.fmt_with_indent(f, 0)
}
}
impl fmt::Display for Fundef {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Fundef {
name: id::L(name),
args,
fargs,
body,
ret,
} = self;
write!(f, "asm-define {}", name)?;
for y in args.iter() {
write!(f, " ({}: intptr)", y)?;
}
for y in fargs.iter() {
write!(f, " ({}: float)", y)?;
}
write!(f, ":{} {{\n ", ret)?;
body.fmt_with_indent(f, 2)?;
write!(f, "\n}}")
}
}
impl fmt::Display for Prog {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Prog(data, fundefs, e) = self;
for (id::L(name), value) in data.iter() {
writeln!(f, "{} => {}", name, value)?;
}
for fundef in fundefs.iter() {
writeln!(f, "{}", fundef)?;
}
write!(f, "{}", e)
}
}

pub fn fletd(x: String, e1: Exp, e2: Asm) -> Asm {
Asm::Let(x, Type::Float, e1, Box::new(e2))
}

pub fn seq(id_gen: &mut id::IdGen, e1: Exp, e2: Asm) -> Asm {
let id = id_gen.gen_tmp(&Type::Unit);
Asm::Let(id, Type::Unit, e1, Box::new(e2))
}

pub fn regs() -> Vec<String> {
let mut res = vec!["".to_string(); 4];
for (i, item) in res.iter_mut().enumerate() {
*item = format!("$x{i}");
}
res
}

pub fn fregs() -> Vec<String> {
let mut res = vec!["".to_string(); 32];
for (i, item) in res.iter_mut().enumerate() {
*item = format!("$v{i}");
}
res
}

/// closure address (caml2html: sparcasm_regcl)
pub fn reg_cl() -> &'static str {
"$x29"
}

pub const REG_SP: &str = "$sp";
pub const REG_HP: &str = "min_caml_hp";

pub fn is_reg(x: &str) -> bool {
let c = x.chars().next();
c == Some('$') || x == REG_HP
}

/// free variables in the order of use (for spilling) (caml2html: sparcasm_fv)
fn fv_id_or_imm(x: &IdOrImm) -> HashSet<String> {
match x {
IdOrImm::V(x) => build_set!(x),
IdOrImm::C(_) => build_set!(),
}
}

/// ys: integral parameters, zs: float parameters. Taylor-made for the following fn fv_exp().
fn fv_parameters(ys: &[String], zs: &[String]) -> HashSet<String> {
&ys.iter().cloned().collect::<HashSet<_>>() | &zs.iter().cloned().collect::<HashSet<_>>()
}

fn fv_exp(x: &Exp) -> HashSet<String> {
match x {
Exp::Nop | Exp::Set(_) | Exp::SetL(_) | Exp::Comment(_) | Exp::Restore(_) => build_set!(),
Exp::Mov(x) | Exp::Neg(x) | Exp::FMovD(x) | Exp::FNegD(x) | Exp::Save(x, _) => {
build_set!(x)
}
Exp::IntOp(_, x, yp) | Exp::Ld(x, yp, _) | Exp::LdDF(x, yp, _) => {
let mut ret = fv_id_or_imm(yp);
ret.insert(x.to_string());
ret
}
Exp::St(x, y, zp, _) | Exp::StDF(x, y, zp, _) => {
let mut ret = fv_id_or_imm(zp);
ret.insert(x.to_string());
ret.insert(y.to_string());
ret
}
Exp::FloatOp(_, x, y) => build_set!(x, y),
Exp::IfComp(_, x, yp, e1, e2) => {
let h = build_set!(x);
let s1 = fv(e1);
let s2 = fv(e2);
&(&h | &s1) | &(&s2 | &fv_id_or_imm(yp))
}
Exp::IfFComp(_, x, y, e1, e2) => {
let h = build_set!(x, y);
let s1 = fv(e1);
let s2 = fv(e2);
&(&h | &s1) | &s2
}
Exp::CallCls(x, ys, zs) => &build_set!(x) | &fv_parameters(ys, zs),
Exp::CallDir(_, ys, zs) => fv_parameters(ys, zs),
}
}

pub fn fv(e: &Asm) -> HashSet<String> {
match e {
Asm::Ans(exp) => fv_exp(exp),
Asm::Let(x, _, exp, e) => &fv_exp(exp) | &(&fv(e) - &build_set!(x)),
}
}

pub fn concat(e1: Asm, x: String, t: Type, e2: Asm) -> Asm {
match e1 {
Asm::Ans(exp) => Asm::Let(x, t, exp, Box::new(e2)),
Asm::Let(y, yt, exp, e1p) => Asm::Let(y, yt, exp, Box::new(concat(*e1p, x, t, e2))),
}
}

pub fn align(i: i32) -> i32 {
if i % 8 == 0 {
i
} else {
i + 4
}
}
4 changes: 4 additions & 0 deletions src/arm64/instr.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
enum Instr {
MovRR(R32, R32),
Ret,
}
4 changes: 4 additions & 0 deletions src/arm64/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod asm;
pub mod reg_alloc;
pub mod simm;
pub mod virtual_asm;
Loading

0 comments on commit 748b7d2

Please sign in to comment.