BRANCHING (TURING COMPLETE????)
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
use crate::{
|
||||
compiler::program::{Addr, Instr, SymTable}, ir::Symbol, util::LabeledFmt
|
||||
compiler::program::{Addr, Instr, SymTable},
|
||||
ir::Symbol,
|
||||
util::LabeledFmt,
|
||||
};
|
||||
|
||||
use super::*;
|
||||
@@ -52,6 +54,12 @@ pub enum LinkerInstruction<R = Reg, S = Symbol> {
|
||||
},
|
||||
Call(S),
|
||||
J(S),
|
||||
Branch {
|
||||
to: S,
|
||||
typ: Funct3,
|
||||
left: R,
|
||||
right: R,
|
||||
},
|
||||
Ret,
|
||||
ECall,
|
||||
EBreak,
|
||||
@@ -66,10 +74,10 @@ pub fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> RawInstruction {
|
||||
}
|
||||
|
||||
impl Instr for LinkerInstruction {
|
||||
fn push(
|
||||
fn push_to(
|
||||
&self,
|
||||
data: &mut Vec<u8>,
|
||||
sym_map: &SymTable,
|
||||
sym_map: &mut SymTable,
|
||||
pos: Addr,
|
||||
missing: bool,
|
||||
) -> Option<Symbol> {
|
||||
@@ -135,6 +143,20 @@ impl Instr for LinkerInstruction {
|
||||
Self::ECall => ecall(),
|
||||
Self::EBreak => ebreak(),
|
||||
Self::Li { dest, imm } => addi(*dest, zero, BitsI32::new(*imm)),
|
||||
Self::Branch {
|
||||
to,
|
||||
typ,
|
||||
left,
|
||||
right,
|
||||
} => {
|
||||
if let Some(addr) = sym_map.get(*to) {
|
||||
let offset = addr.val() as i32 - pos.val() as i32;
|
||||
branch(*typ, *left, *right, BitsI32::new(offset))
|
||||
} else {
|
||||
data.extend_from_slice(&[0; 4]);
|
||||
return Some(*to);
|
||||
}
|
||||
}
|
||||
};
|
||||
data.extend(last.to_le_bytes());
|
||||
None
|
||||
@@ -181,7 +203,11 @@ pub struct DebugInstr<'a, R, S, L: Fn(&mut std::fmt::Formatter<'_>, &S) -> std::
|
||||
}
|
||||
|
||||
impl<R: std::fmt::Debug, S: std::fmt::Debug> LabeledFmt<S> for LinkerInstruction<R, S> {
|
||||
fn fmt_label(&self, f: &mut std::fmt::Formatter<'_>, label: &dyn crate::util::Labeler<S>) -> std::fmt::Result {
|
||||
fn fmt_label(
|
||||
&self,
|
||||
f: &mut std::fmt::Formatter<'_>,
|
||||
label: &dyn crate::util::Labeler<S>,
|
||||
) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::ECall => write!(f, "ecall"),
|
||||
Self::EBreak => write!(f, "ebreak"),
|
||||
@@ -190,7 +216,7 @@ impl<R: std::fmt::Debug, S: std::fmt::Debug> LabeledFmt<S> for LinkerInstruction
|
||||
Self::La { dest, src } => {
|
||||
write!(f, "la {dest:?}, @")?;
|
||||
label(f, src)
|
||||
},
|
||||
}
|
||||
Self::Load {
|
||||
width,
|
||||
dest,
|
||||
@@ -229,6 +255,12 @@ impl<R: std::fmt::Debug, S: std::fmt::Debug> LabeledFmt<S> for LinkerInstruction
|
||||
write!(f, "j ")?;
|
||||
label(f, s)
|
||||
}
|
||||
Self::Branch {
|
||||
to,
|
||||
typ,
|
||||
left,
|
||||
right,
|
||||
} => write!(f, "b{} {left:?} {right:?} {to:?}", branch::str(*typ)),
|
||||
Self::Ret => write!(f, "ret"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::{
|
||||
compiler::{arch::riscv::Reg, debug::DebugInfo, UnlinkedProgram},
|
||||
compiler::{arch::riscv::Reg, debug::DebugInfo, UnlinkedFunction, UnlinkedProgram},
|
||||
ir::{
|
||||
arch::riscv64::{RV64Instruction as AI, RegRef},
|
||||
IRLInstruction as IRI, IRLProgram, Len, Size,
|
||||
@@ -84,6 +84,7 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
||||
v.push(LI::sd(ra, stack_ra, sp));
|
||||
}
|
||||
}
|
||||
let mut locations = HashMap::new();
|
||||
let mut irli = Vec::new();
|
||||
for i in &f.instructions {
|
||||
irli.push((v.len(), format!("{i:?}")));
|
||||
@@ -147,7 +148,7 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
||||
}
|
||||
fn r(rr: RegRef) -> Reg {
|
||||
match rr {
|
||||
RegRef::Var(var_ident) => todo!(),
|
||||
RegRef::Var(..) => todo!(),
|
||||
RegRef::Reg(reg) => reg,
|
||||
}
|
||||
}
|
||||
@@ -160,7 +161,7 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
||||
dest: r(dest),
|
||||
src: r(src),
|
||||
}),
|
||||
AI::La { dest, src } => todo!(),
|
||||
AI::La { .. } => todo!(),
|
||||
AI::Load {
|
||||
width,
|
||||
dest,
|
||||
@@ -216,9 +217,10 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
||||
imm,
|
||||
}),
|
||||
AI::Ret => v.push(LI::Ret),
|
||||
AI::Call(s) => todo!(),
|
||||
AI::Jal { dest, offset } => todo!(),
|
||||
AI::J(s) => todo!(),
|
||||
AI::Call(..) => todo!(),
|
||||
AI::Jal { .. } => todo!(),
|
||||
AI::J(..) => todo!(),
|
||||
AI::Branch { .. } => todo!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -229,6 +231,21 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
||||
v.push(LI::ld(t0, rva, sp));
|
||||
mov_mem(&mut v, sp, stack[src], t0, 0, t1, align(&f.ret_size) as u32);
|
||||
}
|
||||
IRI::Jump(location) => {
|
||||
v.push(LI::J(*location));
|
||||
}
|
||||
IRI::Branch { to, cond } => {
|
||||
v.push(LI::ld(t0, stack[cond], sp));
|
||||
v.push(LI::Branch {
|
||||
to: *to,
|
||||
typ: branch::EQ,
|
||||
left: t0,
|
||||
right: zero,
|
||||
})
|
||||
}
|
||||
IRI::Mark(location) => {
|
||||
locations.insert(v.len(), *location);
|
||||
}
|
||||
}
|
||||
}
|
||||
dbg.push_fn(irli);
|
||||
@@ -239,12 +256,17 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
||||
v.push(LI::addi(sp, sp, stack_len));
|
||||
}
|
||||
v.push(LI::Ret);
|
||||
fns.push((v, *sym));
|
||||
fns.push(UnlinkedFunction {
|
||||
instrs: v,
|
||||
sym: *sym,
|
||||
locations,
|
||||
});
|
||||
}
|
||||
UnlinkedProgram {
|
||||
fns: fns.into_iter().map(|(v, s, ..)| (v, s)).collect(),
|
||||
fns,
|
||||
ro_data: data,
|
||||
start: Some(program.entry()),
|
||||
dbg,
|
||||
sym_count: program.len(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ pub const IMM_OP: u32 = 0b0010011;
|
||||
pub const OP: u32 = 0b0110011;
|
||||
pub const JAL: u32 = 0b1101111;
|
||||
pub const JALR: u32 = 0b1100111;
|
||||
pub const BRANCH: u32 = 0b1100011;
|
||||
|
||||
pub type Funct3 = Bits32<2, 0>;
|
||||
pub type Funct7 = Bits32<6, 0>;
|
||||
@@ -59,7 +60,7 @@ pub const fn b_type(rs2: Reg, rs1: Reg, funct3: Funct3, imm: Bits32<12, 1>, opco
|
||||
+ (imm.bits(10, 5) << 25)
|
||||
+ (rs2.val() << 20)
|
||||
+ (rs1.val() << 15)
|
||||
+ (funct3.val() << 8)
|
||||
+ (funct3.val() << 12)
|
||||
+ (imm.bits(4, 1) << 8)
|
||||
+ (imm.bit(11) << 7)
|
||||
+ opcode)
|
||||
|
||||
@@ -63,6 +63,28 @@ pub mod width {
|
||||
}
|
||||
}
|
||||
|
||||
pub mod branch {
|
||||
use super::*;
|
||||
pub const EQ: Funct3 = Funct3::new(0b000);
|
||||
pub const NE: Funct3 = Funct3::new(0b001);
|
||||
pub const LT: Funct3 = Funct3::new(0b100);
|
||||
pub const GE: Funct3 = Funct3::new(0b101);
|
||||
pub const LTU: Funct3 = Funct3::new(0b110);
|
||||
pub const GEU: Funct3 = Funct3::new(0b111);
|
||||
|
||||
pub fn str(f: Funct3) -> &'static str {
|
||||
match f {
|
||||
EQ => "eq",
|
||||
NE => "ne",
|
||||
LT => "lt",
|
||||
GE => "ge",
|
||||
LTU => "ltu",
|
||||
GEU => "geu",
|
||||
_ => "?",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn ecall() -> RawInstruction {
|
||||
i_type(Bits32::new(0), zero, Bits32::new(0), zero, SYSTEM)
|
||||
}
|
||||
@@ -94,3 +116,7 @@ pub const fn j(offset: BitsI32<20, 1>) -> RawInstruction {
|
||||
pub const fn ret() -> RawInstruction {
|
||||
jalr(zero, BitsI32::new(0), ra)
|
||||
}
|
||||
|
||||
pub const fn branch(typ: Funct3, left: Reg, right: Reg, offset: BitsI32<12, 1>) -> RawInstruction {
|
||||
b_type(right, left, typ, offset.to_u(), BRANCH)
|
||||
}
|
||||
|
||||
+43
-24
@@ -13,40 +13,54 @@ pub struct LinkedProgram {
|
||||
}
|
||||
|
||||
pub struct UnlinkedProgram<I: Instr> {
|
||||
pub fns: Vec<(Vec<I>, Symbol)>,
|
||||
pub fns: Vec<UnlinkedFunction<I>>,
|
||||
pub ro_data: Vec<(Vec<u8>, Symbol)>,
|
||||
pub sym_count: usize,
|
||||
pub start: Option<Symbol>,
|
||||
pub dbg: DebugInfo,
|
||||
}
|
||||
|
||||
pub struct UnlinkedFunction<I: Instr> {
|
||||
pub instrs: Vec<I>,
|
||||
pub sym: Symbol,
|
||||
pub locations: HashMap<usize, Symbol>,
|
||||
}
|
||||
|
||||
impl<I: Instr> UnlinkedProgram<I> {
|
||||
pub fn link(self) -> LinkedProgram {
|
||||
let mut data = Vec::new();
|
||||
let mut sym_table = SymTable::new(self.fns.len() + self.ro_data.len());
|
||||
let mut sym_table = SymTable::new(self.sym_count);
|
||||
let mut missing = HashMap::<Symbol, Vec<(Addr, I)>>::new();
|
||||
for (val, id) in self.ro_data {
|
||||
sym_table.insert(id, Addr(data.len() as u64));
|
||||
data.extend(val);
|
||||
}
|
||||
data.resize(data.len() + (4 - data.len() % 4), 0);
|
||||
for (fun, id) in self.fns {
|
||||
sym_table.insert(id, Addr(data.len() as u64));
|
||||
for i in fun {
|
||||
for f in self.fns {
|
||||
let mut added = vec![f.sym];
|
||||
sym_table.insert(f.sym, Addr(data.len() as u64));
|
||||
for (i, instr) in f.instrs.into_iter().enumerate() {
|
||||
let i_pos = Addr(data.len() as u64);
|
||||
if let Some(sym) = i.push(&mut data, &sym_table, i_pos, false) {
|
||||
if let Some(sym) = f.locations.get(&i) {
|
||||
sym_table.insert(*sym, i_pos);
|
||||
added.push(*sym);
|
||||
}
|
||||
if let Some(sym) = instr.push_to(&mut data, &mut sym_table, i_pos, false) {
|
||||
if let Some(vec) = missing.get_mut(&sym) {
|
||||
vec.push((i_pos, i));
|
||||
vec.push((i_pos, instr));
|
||||
} else {
|
||||
missing.insert(sym, vec![(i_pos, i)]);
|
||||
missing.insert(sym, vec![(i_pos, instr)]);
|
||||
}
|
||||
}
|
||||
}
|
||||
if let Some(vec) = missing.remove(&id) {
|
||||
for (addr, i) in vec {
|
||||
let mut replace = Vec::new();
|
||||
i.push(&mut replace, &sym_table, addr, true);
|
||||
let pos = addr.val() as usize;
|
||||
data[pos..pos + replace.len()].copy_from_slice(&replace);
|
||||
for add in added {
|
||||
if let Some(vec) = missing.remove(&add) {
|
||||
for (addr, i) in vec {
|
||||
let mut replace = Vec::new();
|
||||
i.push_to(&mut replace, &mut sym_table, addr, true);
|
||||
let pos = addr.val() as usize;
|
||||
data[pos..pos + replace.len()].copy_from_slice(&replace);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -61,8 +75,13 @@ impl<I: Instr> UnlinkedProgram<I> {
|
||||
}
|
||||
|
||||
pub trait Instr {
|
||||
fn push(&self, data: &mut Vec<u8>, syms: &SymTable, pos: Addr, missing: bool)
|
||||
-> Option<Symbol>;
|
||||
fn push_to(
|
||||
&self,
|
||||
data: &mut Vec<u8>,
|
||||
syms: &mut SymTable,
|
||||
pos: Addr,
|
||||
missing: bool,
|
||||
) -> Option<Symbol>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
@@ -92,16 +111,16 @@ impl SymTable {
|
||||
|
||||
impl<I: Instr + Labelable<Symbol> + LabeledFmt<Symbol>> std::fmt::Debug for UnlinkedProgram<I> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
for ((v, s), irli) in self.fns.iter().zip(&self.dbg.ir_lower) {
|
||||
writeln!(f, "{}:", self.dbg.sym_label(*s).unwrap())?;
|
||||
for (fun, irli) in self.fns.iter().zip(&self.dbg.ir_lower) {
|
||||
writeln!(f, "{}:", self.dbg.sym_label(fun.sym).unwrap())?;
|
||||
let mut liter = irli.iter();
|
||||
let mut cur = liter.next();
|
||||
for (i, instr) in v.iter().enumerate() {
|
||||
if let Some(c) = cur {
|
||||
if i == c.0 {
|
||||
writeln!(f, " {}:", c.1)?;
|
||||
cur = liter.next();
|
||||
}
|
||||
for (i, instr) in fun.instrs.iter().enumerate() {
|
||||
while let Some(c) = cur
|
||||
&& i == c.0
|
||||
{
|
||||
writeln!(f, " {}:", c.1)?;
|
||||
cur = liter.next();
|
||||
}
|
||||
writeln!(
|
||||
f,
|
||||
|
||||
Reference in New Issue
Block a user