BRANCHING (TURING COMPLETE????)

This commit is contained in:
2025-03-29 15:08:15 -04:00
parent 021434d2f1
commit f57af3b2b5
25 changed files with 780 additions and 486 deletions
+37 -5
View File
@@ -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"),
}
}
+30 -8
View File
@@ -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(),
}
}
+2 -1
View File
@@ -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)
+26
View File
@@ -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
View File
@@ -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,