slices (offsets now real in backend)

This commit is contained in:
2024-12-07 23:56:00 -05:00
parent 0e0dbd647d
commit 606cb30c6b
14 changed files with 305 additions and 215 deletions

View File

@@ -9,6 +9,9 @@ pub struct FnID(pub usize);
#[derive(Clone, Copy, Eq, Hash, PartialEq)]
pub struct DataID(pub usize);
pub type Size = u32;
pub type Len = u32;
impl Debug for VarID {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "var{}", self.0)

View File

@@ -7,8 +7,9 @@ use std::collections::HashMap;
pub struct IRLFunction {
pub name: String,
pub instructions: Vec<IRLInstruction>,
pub stack: HashMap<VarID, usize>,
pub args: Vec<(VarID, usize)>,
pub stack: HashMap<VarID, Size>,
pub args: Vec<(VarID, Size)>,
pub makes_call: bool,
}
#[derive(Debug)]
@@ -23,12 +24,19 @@ pub enum IRLInstruction {
},
LoadAddr {
dest: VarID,
offset: Size,
src: Symbol,
},
LoadData {
dest: VarID,
offset: Size,
src: Symbol,
len: Len,
},
Call {
dest: VarID,
f: Symbol,
args: Vec<(VarID, usize)>,
args: Vec<(VarID, Size)>,
},
AsmBlock {
instructions: Vec<RV64Instruction>,

View File

@@ -2,7 +2,7 @@ use std::collections::HashMap;
use crate::ir::{FnID, SymbolSpace};
use super::{IRLFunction, IRLInstruction, IRUInstruction, Namespace, Symbol, VarID};
use super::{IRLFunction, IRLInstruction, IRUInstruction, Len, Namespace, Symbol, VarID};
pub struct IRLProgram {
sym_space: SymbolSpace,
@@ -14,10 +14,9 @@ pub struct IRLProgram {
impl IRLProgram {
pub fn create(ns: &Namespace) -> Option<Self> {
let mut start = None;
for (i, f) in ns.fns.iter().enumerate() {
let f = f.as_ref()?;
if f.name == "start" {
start = Some(FnID(i));
for (i, f) in ns.iter_fns() {
if f?.name == "start" {
start = Some(i);
}
}
let start = start?;
@@ -25,78 +24,121 @@ impl IRLProgram {
let entry = builder.func(&start);
while let Some((sym, i)) = builder.pop_fn() {
let f = ns.fns[i.0].as_ref().unwrap();
let mut instructions = Vec::new();
let mut instrs = Vec::new();
let mut stack = HashMap::new();
let mut alloc_stack = |i: &VarID| {
if !stack.contains_key(i) {
stack.insert(*i, 8);
}
let mut makes_call = false;
let mut alloc_stack = |i: &VarID| -> bool {
let size = *stack
.entry(*i)
.or_insert(ns.size_of_var(i).expect("unsized type"));
size == 0
};
for i in &f.instructions {
instructions.push(match i {
match i {
IRUInstruction::Mv { dest, src } => {
alloc_stack(dest);
IRLInstruction::Mv {
if alloc_stack(dest) {
continue;
}
instrs.push(IRLInstruction::Mv {
dest: *dest,
src: *src,
}
});
}
IRUInstruction::Ref { dest, src } => {
alloc_stack(dest);
IRLInstruction::Ref {
if alloc_stack(dest) {
continue;
}
instrs.push(IRLInstruction::Ref {
dest: *dest,
src: *src,
}
});
}
IRUInstruction::LoadData { dest, src } => {
alloc_stack(dest);
let addr = builder.ro_data(src, &ns.data[src.0]);
IRLInstruction::LoadAddr {
dest: *dest,
src: addr,
if alloc_stack(dest) {
continue;
}
let data = &ns.data[src.0];
let sym = builder.ro_data(src, data);
instrs.push(IRLInstruction::LoadData {
dest: *dest,
offset: 0,
len: data.len() as Len,
src: sym,
});
}
IRUInstruction::LoadSlice { dest, src, len } => {
if alloc_stack(dest) {
continue;
}
let sym = builder.ro_data(src, &ns.data[src.0]);
instrs.push(IRLInstruction::LoadAddr {
dest: *dest,
offset: 0,
src: sym,
});
let sym = builder.anon_ro_data(&(*len as u64).to_le_bytes());
instrs.push(IRLInstruction::LoadData {
dest: *dest,
offset: 8,
len: 8,
src: sym,
});
}
IRUInstruction::LoadFn { dest, src } => {
alloc_stack(dest);
let sym = builder.func(src);
IRLInstruction::LoadAddr {
dest: *dest,
src: sym,
if alloc_stack(dest) {
continue;
}
let sym = builder.func(src);
instrs.push(IRLInstruction::LoadAddr {
dest: *dest,
offset: 0,
src: sym,
});
}
IRUInstruction::Call { dest, f, args } => {
alloc_stack(dest);
makes_call = true;
let fid = &ns.fn_map[f];
let sym = builder.func(fid);
IRLInstruction::Call {
instrs.push(IRLInstruction::Call {
dest: *dest,
f: sym,
args: args.iter().map(|a| (*a, 8)).collect(),
}
args: args
.iter()
.map(|a| (*a, ns.size_of_var(a).expect("unsized type")))
.collect(),
});
}
IRUInstruction::AsmBlock { instructions, args } => IRLInstruction::AsmBlock {
instructions: instructions.clone(),
args: args.clone(),
},
IRUInstruction::Ret { src } => IRLInstruction::Ret { src: *src },
});
IRUInstruction::AsmBlock { instructions, args } => {
instrs.push(IRLInstruction::AsmBlock {
instructions: instructions.clone(),
args: args.clone(),
})
}
IRUInstruction::Ret { src } => instrs.push(IRLInstruction::Ret { src: *src }),
};
}
builder.write_fn(
sym,
IRLFunction {
name: f.name.clone(),
instructions,
args: f.args.iter().map(|a| (*a, 8)).collect(),
instructions: instrs,
makes_call,
args: f
.args
.iter()
.map(|a| (*a, ns.size_of_var(a).expect("unsized type")))
.collect(),
stack,
},
);
}
let sym_space = builder.finish().expect("we failed the mission");
println!("fns:");
for (a, f) in sym_space.fns() {
println!(" {:?}: {}", a, f.name);
}
println!("datas: {}", sym_space.ro_data().len());
// println!("fns:");
// for (a, f) in sym_space.fns() {
// println!(" {:?}: {}", a, f.name);
// }
// println!("datas: {}", sym_space.ro_data().len());
Some(Self { sym_space, entry })
}

View File

@@ -56,13 +56,17 @@ impl SymbolSpaceBuilder {
pub fn pop_fn(&mut self) -> Option<(WritableSymbol, FnID)> {
self.unwritten_fns.pop()
}
pub fn ro_data(&mut self, id: &DataID, data: &Vec<u8>) -> Symbol {
pub fn anon_ro_data(&mut self, data: &[u8]) -> Symbol {
let sym = self.reserve();
self.write_ro_data(sym, data.to_vec())
}
pub fn ro_data(&mut self, id: &DataID, data: &[u8]) -> Symbol {
match self.data_map.get(id) {
Some(s) => *s,
None => {
let sym = self.reserve();
self.data_map.insert(*id, *sym);
self.write_ro_data(sym, data.clone())
self.write_ro_data(sym, data.to_vec())
}
}
}

View File

@@ -1,8 +1,8 @@
use crate::compiler::arch::riscv64::Reg;
use std::fmt::Write;
use super::{arch::riscv64::RV64Instruction, DataID, FnID, VarID};
use super::{arch::riscv64::RV64Instruction, DataID, FnID, Len, VarID};
use crate::{compiler::arch::riscv64::Reg, util::Padder};
#[derive(Debug)]
pub struct IRUFunction {
pub name: String,
pub args: Vec<VarID>,
@@ -22,6 +22,11 @@ pub enum IRUInstruction {
dest: VarID,
src: DataID,
},
LoadSlice {
dest: VarID,
src: DataID,
len: Len,
},
LoadFn {
dest: VarID,
src: FnID,
@@ -70,6 +75,7 @@ impl std::fmt::Debug for IRUInstruction {
Self::Ref { dest, src } => write!(f, "{dest:?} <- &{src:?}"),
Self::LoadData { dest, src } => write!(f, "{dest:?} <- {src:?}"),
Self::LoadFn { dest, src } => write!(f, "{dest:?} <- {src:?}"),
Self::LoadSlice { dest, src, len } => write!(f, "{dest:?} <- &[{src:?}; {len}]"),
Self::Call {
dest,
f: func,
@@ -80,3 +86,21 @@ impl std::fmt::Debug for IRUInstruction {
}
}
}
impl std::fmt::Debug for IRUFunction {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}{:?}", &self.name, self.args)?;
if !self.instructions.is_empty() {
f.write_str("{\n ")?;
let mut padder = Padder::new(f);
for i in &self.instructions {
// they don't expose wrap_buf :grief:
padder.write_str(&format!("{i:?};\n"))?;
}
f.write_char('}')?;
} else {
f.write_str("{}")?;
}
Ok(())
}
}

View File

@@ -19,7 +19,7 @@ pub struct Namespace {
impl Namespace {
pub fn new() -> Self {
let mut s = Self {
Self {
fn_defs: Vec::new(),
var_defs: Vec::new(),
type_defs: Vec::new(),
@@ -28,11 +28,7 @@ impl Namespace {
fns: Vec::new(),
temp: 0,
stack: vec![HashMap::new()],
};
for b in BuiltinType::enumerate() {
s.def_type(b.def());
}
s
}
pub fn push(&mut self) -> NamespaceGuard {
self.stack.push(HashMap::new());
@@ -76,6 +72,27 @@ impl Namespace {
self.var_defs.push(var);
VarID(i)
}
pub fn size_of_type(&self, ty: &Type) -> Option<Size> {
// TODO: target matters
Some(match ty {
Type::Concrete(id) => {
let def = &self.type_defs[id.0];
todo!()
}
Type::Bits(b) => *b,
Type::Generic { base, args } => todo!(),
Type::Fn { args, ret } => todo!(),
Type::Ref(_) => 64,
Type::Array(ty, len) => self.size_of_type(ty)? * len,
Type::Slice(_) => 128,
Type::Infer => return None,
Type::Error => return None,
Type::Unit => 0,
})
}
pub fn size_of_var(&self, var: &VarID) -> Option<Size> {
self.size_of_type(&self.var_defs[var.0].ty)
}
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarID {
let v = self.def_var(VarDef {
name: format!("temp{}", self.temp),
@@ -151,7 +168,9 @@ impl Namespace {
Type::Error => str += "{error}",
Type::Infer => str += "{inferred}",
Type::Bits(size) => str += &format!("b{}", size),
Type::Array(t) => str += &format!("[{}]", self.type_name(t)),
Type::Array(t, len) => str += &format!("[{}; {len}]", self.type_name(t)),
Type::Unit => str += "()",
Type::Slice(t) => str += &format!("&[{}]", self.type_name(t)),
}
str
}
@@ -167,6 +186,16 @@ impl Namespace {
pub fn write_fn(&mut self, id: FnID, f: IRUFunction) {
self.fns[id.0] = Some(f);
}
pub fn iter_vars(&self) -> impl Iterator<Item = (VarID, &VarDef)> {
(0..self.var_defs.len())
.map(|i| VarID(i))
.zip(self.var_defs.iter())
}
pub fn iter_fns(&self) -> impl Iterator<Item = (FnID, Option<&IRUFunction>)> {
(0..self.fns.len())
.map(|i| FnID(i))
.zip(self.fns.iter().map(|f| f.as_ref()))
}
}
pub struct NamespaceGuard<'a>(&'a mut Namespace);

View File

@@ -1,4 +1,4 @@
use super::{Origin, TypeDef, TypeID};
use super::{Len, TypeID};
#[derive(Clone)]
pub enum Type {
@@ -7,47 +7,21 @@ pub enum Type {
Generic { base: TypeID, args: Vec<Type> },
Fn { args: Vec<Type>, ret: Box<Type> },
Ref(Box<Type>),
Array(Box<Type>),
Slice(Box<Type>),
Array(Box<Type>, Len),
Infer,
Error,
Unit,
}
impl Type {
pub fn rf(self) -> Self {
Self::Ref(Box::new(self))
}
pub fn arr(self) -> Self {
Self::Array(Box::new(self))
pub fn arr(self, len: Len) -> Self {
Self::Array(Box::new(self), len)
}
pub fn slice(self) -> Self {
Self::Slice(Box::new(self))
}
}
#[repr(usize)]
#[derive(Debug, Clone, Copy)]
pub enum BuiltinType {
Unit,
}
impl BuiltinType {
pub fn enumerate() -> &'static [Self; 1] {
&[Self::Unit]
}
pub fn def(&self) -> TypeDef {
match self {
BuiltinType::Unit => TypeDef {
name: "()".to_string(),
args: 0,
origin: Origin::Builtin,
},
}
}
pub fn id(&self) -> TypeID {
TypeID::builtin(self)
}
}
impl TypeID {
pub fn builtin(ty: &BuiltinType) -> Self {
Self(*ty as usize)
}
}