asm output, random fixes
This commit is contained in:
116
data/test.lang
116
data/test.lang
@@ -1,10 +1,12 @@
|
||||
struct Test {
|
||||
a: 64,
|
||||
b: 64,
|
||||
a: 64,
|
||||
b: 64,
|
||||
}
|
||||
|
||||
fn start() {
|
||||
println("Helld!");
|
||||
print_hex(rem(10, 7));
|
||||
println("");
|
||||
println("Hello World!!!!!");
|
||||
thinger();
|
||||
let x = 3;
|
||||
@@ -14,7 +16,7 @@ fn start() {
|
||||
println("before:");
|
||||
x = 0;
|
||||
loop {
|
||||
if not(lt(x, 5)) {
|
||||
if not(lt(x, 10)) {
|
||||
break;
|
||||
};
|
||||
println("RAAAAA");
|
||||
@@ -28,7 +30,11 @@ fn start() {
|
||||
};
|
||||
arger("a", "b", "c");
|
||||
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) {
|
||||
@@ -48,7 +54,7 @@ fn println(msg: slice<8>) {
|
||||
}
|
||||
|
||||
fn print(msg: slice<8>) {
|
||||
asm (a1 = msg) {
|
||||
asm (a1 = &msg) {
|
||||
ld a2, 8, a1
|
||||
ld a1, 0, a1
|
||||
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 {
|
||||
let c: 64 = 0;
|
||||
asm (t0 = a, t1 = b, a0 = c) {
|
||||
ld t0, 0, t0
|
||||
ld t1, 0, t1
|
||||
asm (t0 = a, t1 = b, out = t0) {
|
||||
add t0, t0, t1
|
||||
sd t0, 0, a0
|
||||
};
|
||||
c
|
||||
}
|
||||
}
|
||||
|
||||
fn mul(a: 64, b: 64) -> 64 {
|
||||
let c: 64 = 0;
|
||||
asm (t0 = a, t1 = b, a0 = c) {
|
||||
ld t0, 0, t0
|
||||
ld t1, 0, t1
|
||||
asm (t0 = a, t1 = b, out = t0) {
|
||||
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 {
|
||||
let c: 64 = 0;
|
||||
asm (t0 = a, t1 = b, a0 = c) {
|
||||
ld t0, 0, t0
|
||||
ld t1, 0, t1
|
||||
asm (t0 = a, t1 = b, out = t0) {
|
||||
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 {
|
||||
let c: 64 = 0;
|
||||
asm (t0 = a, t1 = b, a0 = c) {
|
||||
ld t0, 0, t0
|
||||
ld t1, 0, t1
|
||||
asm (t0 = a, t1 = b, out = t0) {
|
||||
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 {
|
||||
let c: 64 = 0;
|
||||
asm (t0 = a, a0 = c) {
|
||||
ld t0, 0, t0
|
||||
asm (t0 = a, out = t0) {
|
||||
xori t0, t0, 1
|
||||
sd t0, 0, a0
|
||||
};
|
||||
c
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
asm (a0 = status) {
|
||||
ld a0, 0, a0
|
||||
li a7, 93
|
||||
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::{
|
||||
compiler::program::{Addr, Instr, SymTable},
|
||||
ir::Symbol,
|
||||
util::LabeledFmt,
|
||||
util::{Bits32, LabeledFmt},
|
||||
};
|
||||
|
||||
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 {
|
||||
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 {
|
||||
@@ -89,7 +93,7 @@ impl Instr for LinkerInstruction {
|
||||
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 {
|
||||
op,
|
||||
funct,
|
||||
@@ -113,8 +117,17 @@ impl Instr for LinkerInstruction {
|
||||
Self::La { dest, src } => {
|
||||
if let Some(addr) = sym_map.get(*src) {
|
||||
let offset = addr.val() as i32 - pos.val() as i32;
|
||||
data.extend(auipc(*dest, BitsI32::new(0)).to_le_bytes());
|
||||
addi(*dest, *dest, BitsI32::new(offset))
|
||||
let sign = offset.signum();
|
||||
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 {
|
||||
data.extend_from_slice(&[0; 2 * 4]);
|
||||
return Some(*src);
|
||||
|
||||
@@ -106,7 +106,10 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
||||
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 } => {
|
||||
v.extend([
|
||||
LI::La {
|
||||
@@ -142,9 +145,13 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
||||
}
|
||||
v.push(LI::Call(*f));
|
||||
}
|
||||
IRI::AsmBlock { args, instructions } => {
|
||||
for (reg, var) in args {
|
||||
v.push(LI::addi(*reg, sp, stack[var]));
|
||||
IRI::AsmBlock {
|
||||
inputs,
|
||||
outputs,
|
||||
instructions,
|
||||
} => {
|
||||
for (reg, var) in inputs {
|
||||
v.push(LI::ld(*reg, stack[var], sp));
|
||||
}
|
||||
fn r(rr: RegRef) -> Reg {
|
||||
match rr {
|
||||
@@ -223,6 +230,9 @@ pub fn compile(program: &IRLProgram) -> UnlinkedProgram<LI> {
|
||||
AI::Branch { .. } => todo!(),
|
||||
}
|
||||
}
|
||||
for (reg, var) in outputs {
|
||||
v.push(LI::sd(*reg, stack[var], sp));
|
||||
}
|
||||
}
|
||||
IRI::Ret { src } => {
|
||||
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 {
|
||||
r_type(funct, src2, src1, op, dest, OP)
|
||||
}
|
||||
pub fn opi(op: Funct3, dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> RawInstruction {
|
||||
i_type(imm.to_u(), src, op, dest, IMM_OP)
|
||||
pub fn opi(op: Funct3, dest: Reg, src: Reg, imm: Bits32<11, 0>) -> RawInstruction {
|
||||
i_type(imm, src, op, dest, IMM_OP)
|
||||
}
|
||||
pub fn opif7(op: Funct3, funct: Funct7, dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I {
|
||||
i_type(
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use crate::compiler::arch::riscv::Reg;
|
||||
|
||||
use super::VarID;
|
||||
|
||||
#[derive(Clone)]
|
||||
@@ -11,3 +13,4 @@ pub enum RegRef {
|
||||
Var(VarID),
|
||||
Reg(String),
|
||||
}
|
||||
|
||||
|
||||
@@ -42,7 +42,8 @@ pub enum IRLInstruction {
|
||||
},
|
||||
AsmBlock {
|
||||
instructions: Vec<RV64Instruction>,
|
||||
args: Vec<(Reg, VarID)>,
|
||||
inputs: Vec<(Reg, VarID)>,
|
||||
outputs: Vec<(Reg, VarID)>,
|
||||
},
|
||||
Ret {
|
||||
src: VarID,
|
||||
@@ -56,3 +57,4 @@ pub enum IRLInstruction {
|
||||
},
|
||||
Mark(Symbol),
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::ir::{IRUFunction, IRUInstrInst, Size, SymbolSpace};
|
||||
use crate::ir::{AsmBlockArgType, IRUFunction, IRUInstrInst, Size, SymbolSpace};
|
||||
|
||||
use super::{
|
||||
IRLFunction, IRLInstruction, IRUInstruction, IRUProgram, Len, Symbol, SymbolSpaceBuilder, Type,
|
||||
@@ -161,9 +161,21 @@ impl<'a> IRLFunctionBuilder<'a> {
|
||||
});
|
||||
}
|
||||
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 {
|
||||
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 }),
|
||||
|
||||
@@ -39,11 +39,7 @@ pub struct DataDef {
|
||||
pub label: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum Origin {
|
||||
Builtin,
|
||||
File(FileSpan),
|
||||
}
|
||||
pub type Origin = FileSpan;
|
||||
|
||||
impl FnDef {
|
||||
pub fn ty(&self) -> Type {
|
||||
|
||||
@@ -45,7 +45,7 @@ pub enum IRUInstruction {
|
||||
},
|
||||
AsmBlock {
|
||||
instructions: Vec<RV64Instruction>,
|
||||
args: Vec<(Reg, VarInst)>,
|
||||
args: Vec<AsmBlockArg>,
|
||||
},
|
||||
Ret {
|
||||
src: VarInst,
|
||||
@@ -64,6 +64,19 @@ pub enum IRUInstruction {
|
||||
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 {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
@@ -77,7 +90,9 @@ impl std::fmt::Debug for IRUInstruction {
|
||||
f: 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::Construct { dest, fields } => write!(f, "{dest:?} <- {fields:?}")?,
|
||||
Self::Access { dest, src, field } => write!(f, "{dest:?} <- {src:?}.{field}")?,
|
||||
|
||||
@@ -1,7 +1,4 @@
|
||||
use std::{
|
||||
collections::HashMap,
|
||||
fmt::Debug,
|
||||
};
|
||||
use std::{collections::HashMap, fmt::Debug};
|
||||
|
||||
use crate::common::FileSpan;
|
||||
|
||||
@@ -98,10 +95,10 @@ impl IRUProgram {
|
||||
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) -> VarInst {
|
||||
pub fn temp_var(&mut self, origin: Origin, ty: Type) -> VarInst {
|
||||
let v = self.def_var(VarDef {
|
||||
name: format!("temp{}", self.temp),
|
||||
origin: super::Origin::File(origin),
|
||||
origin,
|
||||
ty,
|
||||
});
|
||||
self.temp += 1;
|
||||
|
||||
@@ -1,12 +1,19 @@
|
||||
// TODO: move this into ir, not parser
|
||||
use super::{IRUInstrInst, IRUInstruction, IRUProgram, Type};
|
||||
use crate::common::{CompilerMsg, CompilerOutput};
|
||||
use crate::common::{CompilerMsg, CompilerOutput, FileSpan};
|
||||
|
||||
impl IRUProgram {
|
||||
pub fn validate(&self) -> CompilerOutput {
|
||||
let mut output = CompilerOutput::new();
|
||||
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
|
||||
}
|
||||
@@ -14,10 +21,13 @@ impl IRUProgram {
|
||||
pub fn validate_fn(
|
||||
&self,
|
||||
instructions: &[IRUInstrInst],
|
||||
origin: FileSpan,
|
||||
ret: &Type,
|
||||
output: &mut CompilerOutput,
|
||||
needs_ret: bool,
|
||||
breakable: bool,
|
||||
) {
|
||||
let mut no_ret = true;
|
||||
for i in instructions {
|
||||
match &i.i {
|
||||
IRUInstruction::Mv { dest, src } => {
|
||||
@@ -25,7 +35,9 @@ impl IRUProgram {
|
||||
let src = self.get_var(src.id);
|
||||
output.check_assign(self, &src.ty, &dest.ty, i.span);
|
||||
}
|
||||
IRUInstruction::Ref { dest, src } => todo!(),
|
||||
IRUInstruction::Ref { dest, src } => {
|
||||
// TODO
|
||||
}
|
||||
IRUInstruction::LoadData { dest, src } => {
|
||||
let dest = self.get_var(dest.id);
|
||||
let src = self.get_data(*src);
|
||||
@@ -64,6 +76,7 @@ impl IRUProgram {
|
||||
IRUInstruction::Ret { src } => {
|
||||
let srcty = &self.get_var(src.id).ty;
|
||||
output.check_assign(self, srcty, ret, src.span);
|
||||
no_ret = false;
|
||||
}
|
||||
IRUInstruction::Construct { dest, fields } => {
|
||||
let dest_def = self.get_var(dest.id);
|
||||
@@ -120,10 +133,10 @@ impl IRUProgram {
|
||||
IRUInstruction::If { cond, body } => {
|
||||
let cond = self.get_var(cond.id);
|
||||
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 } => {
|
||||
self.validate_fn(body, ret, output, true);
|
||||
self.validate_fn(body, origin, ret, output, false, true);
|
||||
}
|
||||
IRUInstruction::Break => {
|
||||
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::{
|
||||
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 {
|
||||
type Output = RV64Instruction;
|
||||
@@ -14,9 +19,35 @@ impl FnLowerable for PInstruction {
|
||||
}
|
||||
|
||||
impl FnLowerable for PAsmBlock {
|
||||
type Output = ();
|
||||
type Output = VarInst;
|
||||
|
||||
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 {
|
||||
instructions: {
|
||||
let mut v = Vec::new();
|
||||
@@ -27,27 +58,25 @@ impl FnLowerable for PAsmBlock {
|
||||
}
|
||||
v
|
||||
},
|
||||
args: {
|
||||
let mut v = Vec::new();
|
||||
for a in &self.args {
|
||||
if let Some(a) = a.lower(ctx) {
|
||||
v.push(a);
|
||||
}
|
||||
}
|
||||
v
|
||||
},
|
||||
args,
|
||||
};
|
||||
ctx.push(block);
|
||||
Some(())
|
||||
output
|
||||
}
|
||||
}
|
||||
|
||||
impl FnLowerable for PAsmBlockArg {
|
||||
type Output = (Reg, VarInst);
|
||||
impl FnLowerable for PUAsmBlockArg {
|
||||
type Output = PLAsmBlockArg;
|
||||
|
||||
fn lower(&self, ctx: &mut FnLowerCtx) -> Option<Self::Output> {
|
||||
let var = ctx.get_var(&self.var)?;
|
||||
let reg = Reg::from_ident(&self.reg, ctx)?;
|
||||
Some((reg, var))
|
||||
Some(match self {
|
||||
PAsmBlockArg::In { reg, var } => PLAsmBlockArg::In {
|
||||
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};
|
||||
|
||||
impl Node<PVarDef> {
|
||||
pub fn lower(
|
||||
&self,
|
||||
program: &mut IRUProgram,
|
||||
output: &mut CompilerOutput,
|
||||
) -> Option<VarDef> {
|
||||
pub fn lower(&self, program: &mut IRUProgram, output: &mut CompilerOutput) -> Option<VarDef> {
|
||||
let s = self.as_ref()?;
|
||||
let name = s.name.as_ref()?.to_string();
|
||||
let ty = match &s.ty {
|
||||
@@ -17,7 +13,7 @@ impl Node<PVarDef> {
|
||||
Some(VarDef {
|
||||
name,
|
||||
ty,
|
||||
origin: Origin::File(self.span),
|
||||
origin: self.span,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use super::{func::FnLowerCtx, FnLowerable, PExpr, UnaryOp};
|
||||
use crate::{
|
||||
ir::{DataDef, IRUInstruction, Origin, Type, VarInst},
|
||||
ir::{DataDef, IRUInstruction, Type, VarInst},
|
||||
parser::PInfixOp,
|
||||
};
|
||||
|
||||
@@ -15,7 +15,7 @@ impl FnLowerable for PExpr {
|
||||
let src = ctx.program.def_data(
|
||||
DataDef {
|
||||
ty: Type::Bits(8).arr(data.len() as u32),
|
||||
origin: Origin::File(l.span),
|
||||
origin: l.span,
|
||||
label: format!("string \"{}\"", s.replace("\n", "\\n")),
|
||||
},
|
||||
data,
|
||||
@@ -29,7 +29,7 @@ impl FnLowerable for PExpr {
|
||||
let src = ctx.program.def_data(
|
||||
DataDef {
|
||||
ty,
|
||||
origin: Origin::File(l.span),
|
||||
origin: l.span,
|
||||
label: format!("char '{c}'"),
|
||||
},
|
||||
c.to_string().as_bytes().to_vec(),
|
||||
@@ -44,7 +44,7 @@ impl FnLowerable for PExpr {
|
||||
let src = ctx.program.def_data(
|
||||
DataDef {
|
||||
ty,
|
||||
origin: Origin::File(l.span),
|
||||
origin: l.span,
|
||||
label: format!("num {n:?}"),
|
||||
},
|
||||
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::AsmBlock(b) => {
|
||||
b.lower(ctx);
|
||||
return None;
|
||||
}
|
||||
PExpr::AsmBlock(b) => b.lower(ctx)?,
|
||||
PExpr::Call(e, args) => {
|
||||
let fe = e.lower(ctx)?;
|
||||
let mut nargs = Vec::new();
|
||||
|
||||
@@ -31,7 +31,7 @@ impl PFunction {
|
||||
.map(|a| {
|
||||
a.lower(map, output).unwrap_or(VarDef {
|
||||
name: "{error}".to_string(),
|
||||
origin: Origin::File(a.span),
|
||||
origin: a.span,
|
||||
ty: Type::Error,
|
||||
})
|
||||
})
|
||||
@@ -42,7 +42,7 @@ impl PFunction {
|
||||
};
|
||||
Some(map.def_fn(FnDef {
|
||||
name: name.to_string(),
|
||||
origin: Origin::File(self.header.span),
|
||||
origin: self.header.span,
|
||||
args,
|
||||
ret,
|
||||
}))
|
||||
|
||||
@@ -81,7 +81,7 @@ impl PStruct {
|
||||
};
|
||||
p.def_type(StructDef {
|
||||
name: self.name.as_ref()?.to_string(),
|
||||
origin: Origin::File(span),
|
||||
origin: span,
|
||||
size: offset,
|
||||
fields,
|
||||
});
|
||||
|
||||
@@ -1,17 +1,19 @@
|
||||
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 instructions: Vec<Node<PInstruction>>,
|
||||
pub args: Vec<Node<PAsmBlockArg>>,
|
||||
pub args: Vec<Node<PUAsmBlockArg>>,
|
||||
}
|
||||
|
||||
pub struct PAsmBlockArg {
|
||||
pub reg: Node<PIdent>,
|
||||
pub var: Node<PIdent>,
|
||||
pub enum PAsmBlockArg<R, V> {
|
||||
In { reg: R, var: V },
|
||||
Out { reg: R },
|
||||
}
|
||||
|
||||
pub type PUAsmBlockArg = PAsmBlockArg<Node<PIdent>, Node<PExpr>>;
|
||||
|
||||
impl Parsable for PAsmBlock {
|
||||
fn parse(ctx: &mut ParserCtx) -> ParseResult<Self> {
|
||||
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> {
|
||||
let reg = ctx.parse()?;
|
||||
ctx.expect_sym(Symbol::Equals)?;
|
||||
let var = ctx.parse()?;
|
||||
ParseResult::Ok(Self { reg, var })
|
||||
let reg = ctx.parse::<PIdent>()?;
|
||||
ParseResult::Ok(if reg.inner.as_ref().is_some_and(|s| s.0 == "out") {
|
||||
ctx.expect_sym(Symbol::Equals)?;
|
||||
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