asm output, random fixes
This commit is contained in:
116
data/test.lang
116
data/test.lang
@@ -1,10 +1,12 @@
|
|||||||
struct Test {
|
struct Test {
|
||||||
a: 64,
|
a: 64,
|
||||||
b: 64,
|
b: 64,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start() {
|
fn start() {
|
||||||
println("Helld!");
|
println("Helld!");
|
||||||
|
print_hex(rem(10, 7));
|
||||||
|
println("");
|
||||||
println("Hello World!!!!!");
|
println("Hello World!!!!!");
|
||||||
thinger();
|
thinger();
|
||||||
let x = 3;
|
let x = 3;
|
||||||
@@ -14,7 +16,7 @@ fn start() {
|
|||||||
println("before:");
|
println("before:");
|
||||||
x = 0;
|
x = 0;
|
||||||
loop {
|
loop {
|
||||||
if not(lt(x, 5)) {
|
if not(lt(x, 10)) {
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
println("RAAAAA");
|
println("RAAAAA");
|
||||||
@@ -28,7 +30,11 @@ fn start() {
|
|||||||
};
|
};
|
||||||
arger("a", "b", "c");
|
arger("a", "b", "c");
|
||||||
let z = sub(test.a, 10);
|
let z = sub(test.a, 10);
|
||||||
exit(add(mul(sub(add(5, test.b), 1), 3), z));
|
// exit(add(mul(sub(add(5, test.b), 1), 3), z));
|
||||||
|
print("test: 0x");
|
||||||
|
print_hex(31);
|
||||||
|
println("");
|
||||||
|
exit(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn structer(test: Test) {
|
fn structer(test: Test) {
|
||||||
@@ -48,7 +54,7 @@ fn println(msg: slice<8>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn print(msg: slice<8>) {
|
fn print(msg: slice<8>) {
|
||||||
asm (a1 = msg) {
|
asm (a1 = &msg) {
|
||||||
ld a2, 8, a1
|
ld a2, 8, a1
|
||||||
ld a1, 0, a1
|
ld a1, 0, a1
|
||||||
li a0, 1
|
li a0, 1
|
||||||
@@ -57,58 +63,89 @@ fn print(msg: slice<8>) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn print_hex(x: 64) {
|
||||||
|
let i = 32;
|
||||||
|
loop {
|
||||||
|
i = sub(i, 4);
|
||||||
|
let c = and(shr(x, i), 15);
|
||||||
|
if gt(c, 9) {
|
||||||
|
c = add(c, 7);
|
||||||
|
};
|
||||||
|
c = add(c, 48);
|
||||||
|
asm (a1 = &c) {
|
||||||
|
li a2, 1
|
||||||
|
li a0, 1
|
||||||
|
li a7, 64
|
||||||
|
ecall
|
||||||
|
};
|
||||||
|
if lt(i, 1) {
|
||||||
|
break;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn add(a: 64, b: 64) -> 64 {
|
fn add(a: 64, b: 64) -> 64 {
|
||||||
let c: 64 = 0;
|
asm (t0 = a, t1 = b, out = t0) {
|
||||||
asm (t0 = a, t1 = b, a0 = c) {
|
|
||||||
ld t0, 0, t0
|
|
||||||
ld t1, 0, t1
|
|
||||||
add t0, t0, t1
|
add t0, t0, t1
|
||||||
sd t0, 0, a0
|
}
|
||||||
};
|
|
||||||
c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mul(a: 64, b: 64) -> 64 {
|
fn mul(a: 64, b: 64) -> 64 {
|
||||||
let c: 64 = 0;
|
asm (t0 = a, t1 = b, out = t0) {
|
||||||
asm (t0 = a, t1 = b, a0 = c) {
|
|
||||||
ld t0, 0, t0
|
|
||||||
ld t1, 0, t1
|
|
||||||
mul t0, t0, t1
|
mul t0, t0, t1
|
||||||
sd t0, 0, a0
|
}
|
||||||
};
|
}
|
||||||
c
|
|
||||||
|
fn div(a: 64, b: 64) -> 64 {
|
||||||
|
asm (t0 = a, t1 = b, out = t0) {
|
||||||
|
div t0, t0, t1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub(a: 64, b: 64) -> 64 {
|
fn sub(a: 64, b: 64) -> 64 {
|
||||||
let c: 64 = 0;
|
asm (t0 = a, t1 = b, out = t0) {
|
||||||
asm (t0 = a, t1 = b, a0 = c) {
|
|
||||||
ld t0, 0, t0
|
|
||||||
ld t1, 0, t1
|
|
||||||
sub t0, t0, t1
|
sub t0, t0, t1
|
||||||
sd t0, 0, a0
|
}
|
||||||
};
|
}
|
||||||
c
|
|
||||||
|
fn rem(a: 64, b: 64) -> 64 {
|
||||||
|
asm (t0 = a, t1 = b, out = t0) {
|
||||||
|
rem t0, t0, t1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shr(a: 64, b: 64) -> 64 {
|
||||||
|
asm (t0 = a, t1 = b, out = t0) {
|
||||||
|
srl t0, t0, t1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shl(a: 64, b: 64) -> 64 {
|
||||||
|
asm (t0 = a, t1 = b, out = t0) {
|
||||||
|
sll t0, t0, t1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lt(a: 64, b: 64) -> 64 {
|
fn lt(a: 64, b: 64) -> 64 {
|
||||||
let c: 64 = 0;
|
asm (t0 = a, t1 = b, out = t0) {
|
||||||
asm (t0 = a, t1 = b, a0 = c) {
|
|
||||||
ld t0, 0, t0
|
|
||||||
ld t1, 0, t1
|
|
||||||
slt t0, t0, t1
|
slt t0, t0, t1
|
||||||
sd t0, 0, a0
|
}
|
||||||
};
|
}
|
||||||
c
|
|
||||||
|
fn gt(a: 64, b: 64) -> 64 {
|
||||||
|
lt(b, a)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn and(a: 64, b: 64) -> 64 {
|
||||||
|
asm (t0 = a, t1 = b, out = t0) {
|
||||||
|
and t0, t0, t1
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn not(a: 64) -> 64 {
|
fn not(a: 64) -> 64 {
|
||||||
let c: 64 = 0;
|
asm (t0 = a, out = t0) {
|
||||||
asm (t0 = a, a0 = c) {
|
|
||||||
ld t0, 0, t0
|
|
||||||
xori t0, t0, 1
|
xori t0, t0, 1
|
||||||
sd t0, 0, a0
|
}
|
||||||
};
|
|
||||||
c
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn arger(a: slice<8>, b: slice<8>, c: slice<8>) {
|
fn arger(a: slice<8>, b: slice<8>, c: slice<8>) {
|
||||||
@@ -119,7 +156,6 @@ fn arger(a: slice<8>, b: slice<8>, c: slice<8>) {
|
|||||||
|
|
||||||
fn exit(status: 64) {
|
fn exit(status: 64) {
|
||||||
asm (a0 = status) {
|
asm (a0 = status) {
|
||||||
ld a0, 0, a0
|
|
||||||
li a7, 93
|
li a7, 93
|
||||||
ecall
|
ecall
|
||||||
};
|
};
|
||||||
|
|||||||
13
data/test2.lang
Normal file
13
data/test2.lang
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
fn start() {
|
||||||
|
let x = asm(out = t0) {
|
||||||
|
li t0, 40
|
||||||
|
};
|
||||||
|
exit(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn exit(status: 64) {
|
||||||
|
asm (a0 = status) {
|
||||||
|
li a7, 93
|
||||||
|
ecall
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
compiler::program::{Addr, Instr, SymTable},
|
compiler::program::{Addr, Instr, SymTable},
|
||||||
ir::Symbol,
|
ir::Symbol,
|
||||||
util::LabeledFmt,
|
util::{Bits32, LabeledFmt},
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
@@ -70,7 +70,11 @@ pub enum LinkerInstruction<R = Reg, S = Symbol> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> RawInstruction {
|
pub fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> RawInstruction {
|
||||||
opi(op32i::ADD, dest, src, imm)
|
opi(op32i::ADD, dest, src, imm.to_u())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ori(dest: Reg, src: Reg, imm: Bits32<11, 0>) -> RawInstruction {
|
||||||
|
opi(op32i::OR, dest, src, imm)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instr for LinkerInstruction {
|
impl Instr for LinkerInstruction {
|
||||||
@@ -89,7 +93,7 @@ impl Instr for LinkerInstruction {
|
|||||||
src1,
|
src1,
|
||||||
src2,
|
src2,
|
||||||
} => opr(*op, *funct, *dest, *src1, *src2),
|
} => opr(*op, *funct, *dest, *src1, *src2),
|
||||||
Self::OpImm { op, dest, src, imm } => opi(*op, *dest, *src, BitsI32::new(*imm)),
|
Self::OpImm { op, dest, src, imm } => opi(*op, *dest, *src, BitsI32::new(*imm).to_u()),
|
||||||
Self::OpImmF7 {
|
Self::OpImmF7 {
|
||||||
op,
|
op,
|
||||||
funct,
|
funct,
|
||||||
@@ -113,8 +117,17 @@ impl Instr for LinkerInstruction {
|
|||||||
Self::La { dest, src } => {
|
Self::La { dest, src } => {
|
||||||
if let Some(addr) = sym_map.get(*src) {
|
if let Some(addr) = sym_map.get(*src) {
|
||||||
let offset = addr.val() as i32 - pos.val() as i32;
|
let offset = addr.val() as i32 - pos.val() as i32;
|
||||||
data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes());
|
let sign = offset.signum();
|
||||||
addi(*dest, *dest, BitsI32::new(offset))
|
let mut lower = offset % 0x1000;
|
||||||
|
let mut upper = offset - lower;
|
||||||
|
if (((lower >> 11) & 1) == 1) ^ (sign == -1) {
|
||||||
|
let add = sign << 12;
|
||||||
|
upper += add;
|
||||||
|
lower = offset - upper;
|
||||||
|
}
|
||||||
|
assert!(upper + (lower << 20 >> 20) == offset);
|
||||||
|
data.extend(auipc(*dest, BitsI32::new(upper)).to_le_bytes());
|
||||||
|
addi(*dest, *dest, BitsI32::new(lower))
|
||||||
} else {
|
} else {
|
||||||
data.extend_from_slice(&[0; 2 * 4]);
|
data.extend_from_slice(&[0; 2 * 4]);
|
||||||
return Some(*src);
|
return Some(*src);
|
||||||
|
|||||||
@@ -106,7 +106,10 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
|||||||
s,
|
s,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
IRI::Ref { dest, src } => todo!(),
|
IRI::Ref { dest, src } => {
|
||||||
|
v.push(LI::addi(t0, sp, stack[src]));
|
||||||
|
v.push(LI::sd(t0, stack[dest], sp));
|
||||||
|
}
|
||||||
IRI::LoadAddr { dest, offset, src } => {
|
IRI::LoadAddr { dest, offset, src } => {
|
||||||
v.extend([
|
v.extend([
|
||||||
LI::La {
|
LI::La {
|
||||||
@@ -142,9 +145,13 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
|||||||
}
|
}
|
||||||
v.push(LI::Call(*f));
|
v.push(LI::Call(*f));
|
||||||
}
|
}
|
||||||
IRI::AsmBlock { args, instructions } => {
|
IRI::AsmBlock {
|
||||||
for (reg, var) in args {
|
inputs,
|
||||||
v.push(LI::addi(*reg, sp, stack[var]));
|
outputs,
|
||||||
|
instructions,
|
||||||
|
} => {
|
||||||
|
for (reg, var) in inputs {
|
||||||
|
v.push(LI::ld(*reg, stack[var], sp));
|
||||||
}
|
}
|
||||||
fn r(rr: RegRef) -> Reg {
|
fn r(rr: RegRef) -> Reg {
|
||||||
match rr {
|
match rr {
|
||||||
@@ -223,6 +230,9 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
|||||||
AI::Branch { .. } => todo!(),
|
AI::Branch { .. } => todo!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (reg, var) in outputs {
|
||||||
|
v.push(LI::sd(*reg, stack[var], sp));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
IRI::Ret { src } => {
|
IRI::Ret { src } => {
|
||||||
let Some(rva) = stack_rva else {
|
let Some(rva) = stack_rva else {
|
||||||
|
|||||||
@@ -80,8 +80,8 @@ pub const fn j_type(imm: Bits32<20, 1>, rd: Reg, opcode: u32) -> I {
|
|||||||
pub fn opr(op: Funct3, funct: Funct7, dest: Reg, src1: Reg, src2: Reg) -> I {
|
pub fn opr(op: Funct3, funct: Funct7, dest: Reg, src1: Reg, src2: Reg) -> I {
|
||||||
r_type(funct, src2, src1, op, dest, OP)
|
r_type(funct, src2, src1, op, dest, OP)
|
||||||
}
|
}
|
||||||
pub fn opi(op: Funct3, dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> RawInstruction {
|
pub fn opi(op: Funct3, dest: Reg, src: Reg, imm: Bits32<11, 0>) -> RawInstruction {
|
||||||
i_type(imm.to_u(), src, op, dest, IMM_OP)
|
i_type(imm, src, op, dest, IMM_OP)
|
||||||
}
|
}
|
||||||
pub fn opif7(op: Funct3, funct: Funct7, dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I {
|
pub fn opif7(op: Funct3, funct: Funct7, dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I {
|
||||||
i_type(
|
i_type(
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
use crate::compiler::arch::riscv::Reg;
|
||||||
|
|
||||||
use super::VarID;
|
use super::VarID;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -11,3 +13,4 @@ pub enum RegRef {
|
|||||||
Var(VarID),
|
Var(VarID),
|
||||||
Reg(String),
|
Reg(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,8 @@ pub enum IRLInstruction {
|
|||||||
},
|
},
|
||||||
AsmBlock {
|
AsmBlock {
|
||||||
instructions: Vec<RV64Instruction>,
|
instructions: Vec<RV64Instruction>,
|
||||||
args: Vec<(Reg, VarID)>,
|
inputs: Vec<(Reg, VarID)>,
|
||||||
|
outputs: Vec<(Reg, VarID)>,
|
||||||
},
|
},
|
||||||
Ret {
|
Ret {
|
||||||
src: VarID,
|
src: VarID,
|
||||||
@@ -56,3 +57,4 @@ pub enum IRLInstruction {
|
|||||||
},
|
},
|
||||||
Mark(Symbol),
|
Mark(Symbol),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::ir::{IRUFunction, IRUInstrInst, Size, SymbolSpace};
|
use crate::ir::{AsmBlockArgType, IRUFunction, IRUInstrInst, Size, SymbolSpace};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
IRLFunction, IRLInstruction, IRUInstruction, IRUProgram, Len, Symbol, SymbolSpaceBuilder, Type,
|
IRLFunction, IRLInstruction, IRUInstruction, IRUProgram, Len, Symbol, SymbolSpaceBuilder, Type,
|
||||||
@@ -161,9 +161,21 @@ impl<'a> IRLFunctionBuilder<'a> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
IRUInstruction::AsmBlock { instructions, args } => {
|
IRUInstruction::AsmBlock { instructions, args } => {
|
||||||
|
let mut inputs = Vec::new();
|
||||||
|
let mut outputs = Vec::new();
|
||||||
|
for a in args {
|
||||||
|
match a.ty {
|
||||||
|
AsmBlockArgType::In => inputs.push((a.reg, a.var.id)),
|
||||||
|
AsmBlockArgType::Out => {
|
||||||
|
self.alloc_stack(a.var.id)?;
|
||||||
|
outputs.push((a.reg, a.var.id));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
self.instrs.push(IRLInstruction::AsmBlock {
|
self.instrs.push(IRLInstruction::AsmBlock {
|
||||||
instructions: instructions.clone(),
|
instructions: instructions.clone(),
|
||||||
args: args.iter().cloned().map(|(r, v)| (r, v.id)).collect(),
|
inputs,
|
||||||
|
outputs,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
IRUInstruction::Ret { src } => self.instrs.push(IRLInstruction::Ret { src: src.id }),
|
IRUInstruction::Ret { src } => self.instrs.push(IRLInstruction::Ret { src: src.id }),
|
||||||
|
|||||||
@@ -39,11 +39,7 @@ pub struct DataDef {
|
|||||||
pub label: String,
|
pub label: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
pub type Origin = FileSpan;
|
||||||
pub enum Origin {
|
|
||||||
Builtin,
|
|
||||||
File(FileSpan),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FnDef {
|
impl FnDef {
|
||||||
pub fn ty(&self) -> Type {
|
pub fn ty(&self) -> Type {
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ pub enum IRUInstruction {
|
|||||||
},
|
},
|
||||||
AsmBlock {
|
AsmBlock {
|
||||||
instructions: Vec<RV64Instruction>,
|
instructions: Vec<RV64Instruction>,
|
||||||
args: Vec<(Reg, VarInst)>,
|
args: Vec<AsmBlockArg>,
|
||||||
},
|
},
|
||||||
Ret {
|
Ret {
|
||||||
src: VarInst,
|
src: VarInst,
|
||||||
@@ -64,6 +64,19 @@ pub enum IRUInstruction {
|
|||||||
Break,
|
Break,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct AsmBlockArg {
|
||||||
|
pub var: VarInst,
|
||||||
|
pub reg: Reg,
|
||||||
|
pub ty: AsmBlockArgType,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum AsmBlockArgType {
|
||||||
|
In,
|
||||||
|
Out,
|
||||||
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for IRUInstruction {
|
impl std::fmt::Debug for IRUInstruction {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
@@ -77,7 +90,9 @@ impl std::fmt::Debug for IRUInstruction {
|
|||||||
f: func,
|
f: func,
|
||||||
args,
|
args,
|
||||||
} => write!(f, "{dest:?} <- {func:?}({args:?})")?,
|
} => write!(f, "{dest:?} <- {func:?}({args:?})")?,
|
||||||
Self::AsmBlock { args, instructions } => write!(f, "asm {args:?} {instructions:#?}")?,
|
Self::AsmBlock { args, instructions } => {
|
||||||
|
write!(f, "asm {args:?} {instructions:#?}")?
|
||||||
|
}
|
||||||
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish()?,
|
Self::Ret { src } => f.debug_struct("Ret").field("src", src).finish()?,
|
||||||
Self::Construct { dest, fields } => write!(f, "{dest:?} <- {fields:?}")?,
|
Self::Construct { dest, fields } => write!(f, "{dest:?} <- {fields:?}")?,
|
||||||
Self::Access { dest, src, field } => write!(f, "{dest:?} <- {src:?}.{field}")?,
|
Self::Access { dest, src, field } => write!(f, "{dest:?} <- {src:?}.{field}")?,
|
||||||
|
|||||||
@@ -1,7 +1,4 @@
|
|||||||
use std::{
|
use std::{collections::HashMap, fmt::Debug};
|
||||||
collections::HashMap,
|
|
||||||
fmt::Debug,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::common::FileSpan;
|
use crate::common::FileSpan;
|
||||||
|
|
||||||
@@ -98,10 +95,10 @@ impl IRUProgram {
|
|||||||
pub fn size_of_var(&self, var: VarID) -> Option<Size> {
|
pub fn size_of_var(&self, var: VarID) -> Option<Size> {
|
||||||
self.size_of_type(&self.var_defs[var.0].ty)
|
self.size_of_type(&self.var_defs[var.0].ty)
|
||||||
}
|
}
|
||||||
pub fn temp_var(&mut self, origin: FileSpan, ty: Type) -> VarInst {
|
pub fn temp_var(&mut self, origin: Origin, ty: Type) -> VarInst {
|
||||||
let v = self.def_var(VarDef {
|
let v = self.def_var(VarDef {
|
||||||
name: format!("temp{}", self.temp),
|
name: format!("temp{}", self.temp),
|
||||||
origin: super::Origin::File(origin),
|
origin,
|
||||||
ty,
|
ty,
|
||||||
});
|
});
|
||||||
self.temp += 1;
|
self.temp += 1;
|
||||||
|
|||||||
@@ -1,12 +1,19 @@
|
|||||||
// TODO: move this into ir, not parser
|
// TODO: move this into ir, not parser
|
||||||
use super::{IRUInstrInst, IRUInstruction, IRUProgram, Type};
|
use super::{IRUInstrInst, IRUInstruction, IRUProgram, Type};
|
||||||
use crate::common::{CompilerMsg, CompilerOutput};
|
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
||||||
|
|
||||||
impl IRUProgram {
|
impl IRUProgram {
|
||||||
pub fn validate(&self) -> CompilerOutput {
|
pub fn validate(&self) -> CompilerOutput {
|
||||||
let mut output = CompilerOutput::new();
|
let mut output = CompilerOutput::new();
|
||||||
for (f, fd) in self.fns.iter().flatten().zip(&self.fn_defs) {
|
for (f, fd) in self.fns.iter().flatten().zip(&self.fn_defs) {
|
||||||
self.validate_fn(&f.instructions, &fd.ret, &mut output, false);
|
self.validate_fn(
|
||||||
|
&f.instructions,
|
||||||
|
fd.origin,
|
||||||
|
&fd.ret,
|
||||||
|
&mut output,
|
||||||
|
true,
|
||||||
|
false,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
@@ -14,10 +21,13 @@ impl IRUProgram {
|
|||||||
pub fn validate_fn(
|
pub fn validate_fn(
|
||||||
&self,
|
&self,
|
||||||
instructions: &[IRUInstrInst],
|
instructions: &[IRUInstrInst],
|
||||||
|
origin: FileSpan,
|
||||||
ret: &Type,
|
ret: &Type,
|
||||||
output: &mut CompilerOutput,
|
output: &mut CompilerOutput,
|
||||||
|
needs_ret: bool,
|
||||||
breakable: bool,
|
breakable: bool,
|
||||||
) {
|
) {
|
||||||
|
let mut no_ret = true;
|
||||||
for i in instructions {
|
for i in instructions {
|
||||||
match &i.i {
|
match &i.i {
|
||||||
IRUInstruction::Mv { dest, src } => {
|
IRUInstruction::Mv { dest, src } => {
|
||||||
@@ -25,7 +35,9 @@ impl IRUProgram {
|
|||||||
let src = self.get_var(src.id);
|
let src = self.get_var(src.id);
|
||||||
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||||
}
|
}
|
||||||
IRUInstruction::Ref { dest, src } => todo!(),
|
IRUInstruction::Ref { dest, src } => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
IRUInstruction::LoadData { dest, src } => {
|
IRUInstruction::LoadData { dest, src } => {
|
||||||
let dest = self.get_var(dest.id);
|
let dest = self.get_var(dest.id);
|
||||||
let src = self.get_data(*src);
|
let src = self.get_data(*src);
|
||||||
@@ -64,6 +76,7 @@ impl IRUProgram {
|
|||||||
IRUInstruction::Ret { src } => {
|
IRUInstruction::Ret { src } => {
|
||||||
let srcty = &self.get_var(src.id).ty;
|
let srcty = &self.get_var(src.id).ty;
|
||||||
output.check_assign(self, srcty, ret, src.span);
|
output.check_assign(self, srcty, ret, src.span);
|
||||||
|
no_ret = false;
|
||||||
}
|
}
|
||||||
IRUInstruction::Construct { dest, fields } => {
|
IRUInstruction::Construct { dest, fields } => {
|
||||||
let dest_def = self.get_var(dest.id);
|
let dest_def = self.get_var(dest.id);
|
||||||
@@ -120,10 +133,10 @@ impl IRUProgram {
|
|||||||
IRUInstruction::If { cond, body } => {
|
IRUInstruction::If { cond, body } => {
|
||||||
let cond = self.get_var(cond.id);
|
let cond = self.get_var(cond.id);
|
||||||
output.check_assign(self, &cond.ty, &Type::Bits(64), i.span);
|
output.check_assign(self, &cond.ty, &Type::Bits(64), i.span);
|
||||||
self.validate_fn(body, ret, output, breakable);
|
self.validate_fn(body, origin, ret, output, false, breakable);
|
||||||
}
|
}
|
||||||
IRUInstruction::Loop { body } => {
|
IRUInstruction::Loop { body } => {
|
||||||
self.validate_fn(body, ret, output, true);
|
self.validate_fn(body, origin, ret, output, false, true);
|
||||||
}
|
}
|
||||||
IRUInstruction::Break => {
|
IRUInstruction::Break => {
|
||||||
if !breakable {
|
if !breakable {
|
||||||
@@ -136,5 +149,14 @@ impl IRUProgram {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if needs_ret && no_ret && *ret != Type::Unit {
|
||||||
|
output.err(CompilerMsg {
|
||||||
|
msg: format!(
|
||||||
|
"Function implicitly returns () at the end, must return {}",
|
||||||
|
self.type_name(ret)
|
||||||
|
),
|
||||||
|
spans: vec![origin],
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
compiler::arch::riscv::Reg,
|
compiler::arch::riscv::Reg,
|
||||||
ir::{arch::riscv64::RV64Instruction, IRUInstruction, VarInst},
|
ir::{
|
||||||
|
arch::riscv64::RV64Instruction, AsmBlockArg, AsmBlockArgType, IRUInstruction, Type, VarInst,
|
||||||
|
},
|
||||||
|
parser::PAsmBlockArg,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{FnLowerCtx, FnLowerable, PAsmBlock, PAsmBlockArg, PInstruction};
|
use super::{FnLowerCtx, FnLowerable, PAsmBlock, PInstruction, PUAsmBlockArg};
|
||||||
|
|
||||||
|
type PLAsmBlockArg = PAsmBlockArg<Reg, VarInst>;
|
||||||
|
|
||||||
impl FnLowerable for PInstruction {
|
impl FnLowerable for PInstruction {
|
||||||
type Output = RV64Instruction;
|
type Output = RV64Instruction;
|
||||||
@@ -14,9 +19,35 @@ impl FnLowerable for PInstruction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl FnLowerable for PAsmBlock {
|
impl FnLowerable for PAsmBlock {
|
||||||
type Output = ();
|
type Output = VarInst;
|
||||||
|
|
||||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
|
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
|
||||||
|
let mut args = Vec::new();
|
||||||
|
let mut output = None;
|
||||||
|
for a in &self.args {
|
||||||
|
if let Some(a) = a.lower(ctx) {
|
||||||
|
match a {
|
||||||
|
PAsmBlockArg::In { reg, var } => args.push(AsmBlockArg {
|
||||||
|
reg,
|
||||||
|
var,
|
||||||
|
ty: AsmBlockArgType::In,
|
||||||
|
}),
|
||||||
|
PAsmBlockArg::Out { reg } => {
|
||||||
|
if output.is_some() {
|
||||||
|
ctx.err("cannot evaluate to more than one register".to_string());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let var = ctx.temp(Type::Bits(64));
|
||||||
|
args.push(AsmBlockArg {
|
||||||
|
var,
|
||||||
|
reg,
|
||||||
|
ty: AsmBlockArgType::Out,
|
||||||
|
});
|
||||||
|
output = Some(var)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
let block = IRUInstruction::AsmBlock {
|
let block = IRUInstruction::AsmBlock {
|
||||||
instructions: {
|
instructions: {
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
@@ -27,27 +58,25 @@ impl FnLowerable for PAsmBlock {
|
|||||||
}
|
}
|
||||||
v
|
v
|
||||||
},
|
},
|
||||||
args: {
|
args,
|
||||||
let mut v = Vec::new();
|
|
||||||
for a in &self.args {
|
|
||||||
if let Some(a) = a.lower(ctx) {
|
|
||||||
v.push(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
v
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
ctx.push(block);
|
ctx.push(block);
|
||||||
Some(())
|
output
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FnLowerable for PAsmBlockArg {
|
impl FnLowerable for PUAsmBlockArg {
|
||||||
type Output = (Reg, VarInst);
|
type Output = PLAsmBlockArg;
|
||||||
|
|
||||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
|
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
|
||||||
let var = ctx.get_var(&self.var)?;
|
Some(match self {
|
||||||
let reg = Reg::from_ident(&self.reg, ctx)?;
|
PAsmBlockArg::In { reg, var } => PLAsmBlockArg::In {
|
||||||
Some((reg, var))
|
reg: Reg::from_ident(reg, ctx)?,
|
||||||
|
var: var.as_ref()?.lower(ctx)?,
|
||||||
|
},
|
||||||
|
PAsmBlockArg::Out { reg } => PLAsmBlockArg::Out {
|
||||||
|
reg: Reg::from_ident(reg, ctx)?,
|
||||||
|
},
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,7 @@ use crate::ir::{IRUProgram, Origin, Type, VarDef};
|
|||||||
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType, PVarDef};
|
use super::{CompilerMsg, CompilerOutput, FileSpan, Node, PType, PVarDef};
|
||||||
|
|
||||||
impl Node<PVarDef> {
|
impl Node<PVarDef> {
|
||||||
pub fn lower(
|
pub fn lower(&self, program: &mut IRUProgram, output: &mut CompilerOutput) -> Option<VarDef> {
|
||||||
&self,
|
|
||||||
program: &mut IRUProgram,
|
|
||||||
output: &mut CompilerOutput,
|
|
||||||
) -> Option<VarDef> {
|
|
||||||
let s = self.as_ref()?;
|
let s = self.as_ref()?;
|
||||||
let name = s.name.as_ref()?.to_string();
|
let name = s.name.as_ref()?.to_string();
|
||||||
let ty = match &s.ty {
|
let ty = match &s.ty {
|
||||||
@@ -17,7 +13,7 @@ impl Node<PVarDef> {
|
|||||||
Some(VarDef {
|
Some(VarDef {
|
||||||
name,
|
name,
|
||||||
ty,
|
ty,
|
||||||
origin: Origin::File(self.span),
|
origin: self.span,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
||||||
use crate::{
|
use crate::{
|
||||||
ir::{DataDef, IRUInstruction, Origin, Type, VarInst},
|
ir::{DataDef, IRUInstruction, Type, VarInst},
|
||||||
parser::PInfixOp,
|
parser::PInfixOp,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -15,7 +15,7 @@ impl FnLowerable for PExpr {
|
|||||||
let src = ctx.program.def_data(
|
let src = ctx.program.def_data(
|
||||||
DataDef {
|
DataDef {
|
||||||
ty: Type::Bits(8).arr(data.len() as u32),
|
ty: Type::Bits(8).arr(data.len() as u32),
|
||||||
origin: Origin::File(l.span),
|
origin: l.span,
|
||||||
label: format!("string \"{}\"", s.replace("\n", "\\n")),
|
label: format!("string \"{}\"", s.replace("\n", "\\n")),
|
||||||
},
|
},
|
||||||
data,
|
data,
|
||||||
@@ -29,7 +29,7 @@ impl FnLowerable for PExpr {
|
|||||||
let src = ctx.program.def_data(
|
let src = ctx.program.def_data(
|
||||||
DataDef {
|
DataDef {
|
||||||
ty,
|
ty,
|
||||||
origin: Origin::File(l.span),
|
origin: l.span,
|
||||||
label: format!("char '{c}'"),
|
label: format!("char '{c}'"),
|
||||||
},
|
},
|
||||||
c.to_string().as_bytes().to_vec(),
|
c.to_string().as_bytes().to_vec(),
|
||||||
@@ -44,7 +44,7 @@ impl FnLowerable for PExpr {
|
|||||||
let src = ctx.program.def_data(
|
let src = ctx.program.def_data(
|
||||||
DataDef {
|
DataDef {
|
||||||
ty,
|
ty,
|
||||||
origin: Origin::File(l.span),
|
origin: l.span,
|
||||||
label: format!("num {n:?}"),
|
label: format!("num {n:?}"),
|
||||||
},
|
},
|
||||||
n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
|
n.whole.parse::<i64>().unwrap().to_le_bytes().to_vec(),
|
||||||
@@ -131,10 +131,7 @@ impl FnLowerable for PExpr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
PExpr::Block(b) => b.lower(ctx)?,
|
PExpr::Block(b) => b.lower(ctx)?,
|
||||||
PExpr::AsmBlock(b) => {
|
PExpr::AsmBlock(b) => b.lower(ctx)?,
|
||||||
b.lower(ctx);
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
PExpr::Call(e, args) => {
|
PExpr::Call(e, args) => {
|
||||||
let fe = e.lower(ctx)?;
|
let fe = e.lower(ctx)?;
|
||||||
let mut nargs = Vec::new();
|
let mut nargs = Vec::new();
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ impl PFunction {
|
|||||||
.map(|a| {
|
.map(|a| {
|
||||||
a.lower(map, output).unwrap_or(VarDef {
|
a.lower(map, output).unwrap_or(VarDef {
|
||||||
name: "{error}".to_string(),
|
name: "{error}".to_string(),
|
||||||
origin: Origin::File(a.span),
|
origin: a.span,
|
||||||
ty: Type::Error,
|
ty: Type::Error,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@@ -42,7 +42,7 @@ impl PFunction {
|
|||||||
};
|
};
|
||||||
Some(map.def_fn(FnDef {
|
Some(map.def_fn(FnDef {
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
origin: Origin::File(self.header.span),
|
origin: self.header.span,
|
||||||
args,
|
args,
|
||||||
ret,
|
ret,
|
||||||
}))
|
}))
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ impl PStruct {
|
|||||||
};
|
};
|
||||||
p.def_type(StructDef {
|
p.def_type(StructDef {
|
||||||
name: self.name.as_ref()?.to_string(),
|
name: self.name.as_ref()?.to_string(),
|
||||||
origin: Origin::File(span),
|
origin: span,
|
||||||
size: offset,
|
size: offset,
|
||||||
fields,
|
fields,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
use super::{
|
use super::{
|
||||||
util::parse_list, PIdent, Node, Parsable, ParseResult, PInstruction, ParserCtx, Symbol,
|
util::parse_list, Node, PExpr, PIdent, PInstruction, Parsable, ParseResult, ParserCtx, Symbol,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub struct PAsmBlock {
|
pub struct PAsmBlock {
|
||||||
pub instructions: Vec<Node<PInstruction>>,
|
pub instructions: Vec<Node<PInstruction>>,
|
||||||
pub args: Vec<Node<PAsmBlockArg>>,
|
pub args: Vec<Node<PUAsmBlockArg>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PAsmBlockArg {
|
pub enum PAsmBlockArg<R, V> {
|
||||||
pub reg: Node<PIdent>,
|
In { reg: R, var: V },
|
||||||
pub var: Node<PIdent>,
|
Out { reg: R },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub type PUAsmBlockArg = PAsmBlockArg<Node<PIdent>, Node<PExpr>>;
|
||||||
|
|
||||||
impl Parsable for PAsmBlock {
|
impl Parsable for PAsmBlock {
|
||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
let args = if ctx.expect_peek()?.is_symbol(Symbol::OpenParen) {
|
let args = if ctx.expect_peek()?.is_symbol(Symbol::OpenParen) {
|
||||||
@@ -34,12 +36,18 @@ impl Parsable for PAsmBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parsable for PAsmBlockArg {
|
impl Parsable for PUAsmBlockArg {
|
||||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||||
let reg = ctx.parse()?;
|
let reg = ctx.parse::<PIdent>()?;
|
||||||
ctx.expect_sym(Symbol::Equals)?;
|
ParseResult::Ok(if reg.inner.as_ref().is_some_and(|s| s.0 == "out") {
|
||||||
let var = ctx.parse()?;
|
ctx.expect_sym(Symbol::Equals)?;
|
||||||
ParseResult::Ok(Self { reg, var })
|
let reg = ctx.parse()?;
|
||||||
|
Self::Out { reg }
|
||||||
|
} else {
|
||||||
|
ctx.expect_sym(Symbol::Equals)?;
|
||||||
|
let var = ctx.parse()?;
|
||||||
|
Self::In { reg, var }
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user