From 9690523ee85f87c288559df220e4eddaa7810f9d Mon Sep 17 00:00:00 2001 From: shadow cat Date: Sat, 22 Mar 2025 20:14:44 -0400 Subject: [PATCH] refactored asm --- data/test.lang | 13 +- src/compiler/arch/riscv64/asm.rs | 153 ++++++++++++++++----- src/compiler/arch/riscv64/base.rs | 4 +- src/compiler/arch/riscv64/compile.rs | 193 ++++++++++++--------------- src/compiler/arch/riscv64/funct.rs | 112 +++++++++++++--- src/compiler/arch/riscv64/mod.rs | 2 +- src/compiler/arch/riscv64/single.rs | 51 +++---- src/ir/arch/riscv64.rs | 67 +++++++++- src/parser/v3/lower/arch/riscv64.rs | 162 +++++++++++++++++----- src/util/bits.rs | 4 +- 10 files changed, 518 insertions(+), 243 deletions(-) diff --git a/data/test.lang b/data/test.lang index 0ee8494..aff7dd0 100644 --- a/data/test.lang +++ b/data/test.lang @@ -5,7 +5,7 @@ fn start() { println("what"); print(tester()); arger("a", "b", "c"); - exit(add(35, 4)); + exit(sub(add(35, 5), 1)); } fn thinger() { @@ -42,6 +42,17 @@ fn add(a: 64, b: 64) -> 64 { c } +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 + sub t0, t0, t1 + sd t0, 0, a0 + }; + c +} + fn arger(a: slice<8>, b: slice<8>, c: slice<8>) { print(a); print(b); diff --git a/src/compiler/arch/riscv64/asm.rs b/src/compiler/arch/riscv64/asm.rs index 6b76923..525fd74 100644 --- a/src/compiler/arch/riscv64/asm.rs +++ b/src/compiler/arch/riscv64/asm.rs @@ -1,30 +1,74 @@ -use crate::{compiler::program::{Addr, Instr, SymTable}, ir::Symbol}; +use crate::{ + compiler::program::{Addr, Instr, SymTable}, + ir::Symbol, +}; use super::*; #[derive(Debug, Clone)] pub enum LinkerInstruction { - Add { dest: Reg, src1: Reg, src2: Reg }, - Addi { dest: Reg, src: Reg, imm: i32 }, - Andi { dest: Reg, src: Reg, imm: i32 }, - Slli { dest: Reg, src: Reg, imm: i32 }, - Srli { dest: Reg, src: Reg, imm: i32 }, - Sd { src: Reg, offset: i32, base: Reg }, - Sw { src: Reg, offset: i32, base: Reg }, - Sh { src: Reg, offset: i32, base: Reg }, - Sb { src: Reg, offset: i32, base: Reg }, - Ld { dest: Reg, offset: i32, base: Reg }, - Lw { dest: Reg, offset: i32, base: Reg }, - Lh { dest: Reg, offset: i32, base: Reg }, - Lb { dest: Reg, offset: i32, base: Reg }, - Mv { dest: Reg, src: Reg }, - La { dest: Reg, src: Symbol }, - Jal { dest: Reg, offset: i32 }, + Op { + op: Op, + dest: Reg, + src1: Reg, + src2: Reg, + }, + OpF7 { + op: Op, + funct: Funct7, + dest: Reg, + src1: Reg, + src2: Reg, + }, + OpImm { + op: Op, + dest: Reg, + src: Reg, + imm: i32, + }, + OpImmF7 { + op: Op, + funct: Funct7, + dest: Reg, + src: Reg, + imm: i32, + }, + Store { + width: Width, + src: Reg, + offset: i32, + base: Reg, + }, + Load { + width: Width, + dest: Reg, + offset: i32, + base: Reg, + }, + Mv { + dest: Reg, + src: Reg, + }, + La { + dest: Reg, + src: Symbol, + }, + Jal { + dest: Reg, + offset: i32, + }, Call(Symbol), J(Symbol), Ret, Ecall, - Li { dest: Reg, imm: i64 }, + Li { + dest: Reg, + imm: i64, + }, +} + +pub const fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> RawInstruction { + opi(Op::Add, dest, src, imm) } impl Instr for LinkerInstruction { @@ -36,19 +80,39 @@ impl Instr for LinkerInstruction { missing: bool, ) -> Option { let last = match self { - Self::Add { dest, src1, src2 } => add(*dest, *src1, *src2), - Self::Addi { dest, src, imm } => addi(*dest, *src, BitsI32::new(*imm)), - Self::Andi { dest, src, imm } => andi(*dest, *src, BitsI32::new(*imm)), - Self::Slli { dest, src, imm } => slli(*dest, *src, BitsI32::new(*imm)), - Self::Srli { dest, src, imm } => srli(*dest, *src, BitsI32::new(*imm)), - Self::Sd { src, offset, base } => sd(*src, BitsI32::new(*offset), *base), - Self::Sw { src, offset, base } => sw(*src, BitsI32::new(*offset), *base), - Self::Sh { src, offset, base } => sh(*src, BitsI32::new(*offset), *base), - Self::Sb { src, offset, base } => sb(*src, BitsI32::new(*offset), *base), - Self::Ld { dest, offset, base } => ld(*dest, BitsI32::new(*offset), *base), - Self::Lw { dest, offset, base } => lw(*dest, BitsI32::new(*offset), *base), - Self::Lh { dest, offset, base } => lh(*dest, BitsI32::new(*offset), *base), - Self::Lb { dest, offset, base } => lb(*dest, BitsI32::new(*offset), *base), + Self::Op { + op, + dest, + src1, + src2, + } => opr(*op, *dest, *src1, *src2), + Self::OpF7 { + op, + funct, + dest, + src1, + src2, + } => oprf7(*op, *funct, *dest, *src1, *src2), + Self::OpImm { op, dest, src, imm } => opi(*op, *dest, *src, BitsI32::new(*imm)), + Self::OpImmF7 { + op, + funct, + dest, + src, + imm, + } => opif7(*op, *funct, *dest, *src, BitsI32::new(*imm)), + Self::Store { + width, + src, + offset, + base, + } => store(*width, *src, BitsI32::new(*offset), *base), + Self::Load { + width, + dest, + offset, + base, + } => load(*width, *dest, BitsI32::new(*offset), *base), Self::Mv { dest, src } => addi(*dest, *src, BitsI32::new(0)), Self::La { dest, src } => { if let Some(addr) = sym_map.get(*src) { @@ -87,3 +151,30 @@ impl Instr for LinkerInstruction { None } } + +impl LinkerInstruction { + pub fn addi(dest: Reg, src: Reg, imm: i32) -> Self { + Self::OpImm { + op: Op::Add, + dest, + src, + imm, + } + } + pub fn sd(src: Reg, offset: i32, base: Reg) -> Self { + Self::Store { + width: Width::D, + src, + offset, + base, + } + } + pub fn ld(dest: Reg, offset: i32, base: Reg) -> Self { + Self::Load { + width: Width::D, + dest, + offset, + base, + } + } +} diff --git a/src/compiler/arch/riscv64/base.rs b/src/compiler/arch/riscv64/base.rs index f40e66a..7f4b3d0 100644 --- a/src/compiler/arch/riscv64/base.rs +++ b/src/compiler/arch/riscv64/base.rs @@ -1,6 +1,6 @@ use crate::util::Bits32; -use super::Reg; +use super::{Funct3, Reg}; pub struct RawInstruction(u32); @@ -15,8 +15,6 @@ impl RawInstruction { } } -pub type Funct3 = Bits32<2, 0>; - pub const fn r_type( funct7: Bits32<6, 0>, rs2: Reg, diff --git a/src/compiler/arch/riscv64/compile.rs b/src/compiler/arch/riscv64/compile.rs index eaa22bc..5201e0f 100644 --- a/src/compiler/arch/riscv64/compile.rs +++ b/src/compiler/arch/riscv64/compile.rs @@ -24,69 +24,26 @@ fn mov_mem( mut len: Len, ) { let mut off = 0; - while len >= 8 { - v.extend([ - LI::Ld { - dest: temp, - offset: src_offset + off, - base: src, - }, - LI::Sd { - src: temp, - offset: dest_offset + off, - base: dest, - }, - ]); - len -= 8; - off += 8; - } - while len >= 4 { - v.extend([ - LI::Lw { - dest: temp, - offset: src_offset + off, - base: src, - }, - LI::Sw { - src: temp, - offset: dest_offset + off, - base: dest, - }, - ]); - len -= 4; - off += 4; - } - while len >= 2 { - v.extend([ - LI::Lh { - dest: temp, - offset: src_offset + off, - base: src, - }, - LI::Sh { - src: temp, - offset: dest_offset + off, - base: dest, - }, - ]); - len -= 2; - off += 2; - } - while len >= 1 { - v.extend([ - LI::Lb { - dest: temp, - offset: src_offset + off, - base: src, - }, - LI::Sb { - src: temp, - offset: dest_offset + off, - base: dest, - }, - ]); - len -= 1; - off += 1; + for width in Width::MAIN.iter().rev() { + let wl = width.len(); + while len >= wl { + v.extend([ + LI::Load { + width: *width, + dest: temp, + offset: src_offset + off, + base: src, + }, + LI::Store { + width: *width, + src: temp, + offset: dest_offset + off, + base: dest, + }, + ]); + len -= wl; + off += wl as i32; + } } } @@ -119,19 +76,11 @@ pub fn compile(program: IRLProgram) -> (Vec, Option) { stack_rva = Some(stack_len); stack_len += align(&f.ret_size); } - v.push(LI::Addi { - dest: sp, - src: sp, - imm: -stack_len, - }); + v.push(LI::addi(sp, sp, -stack_len)); let has_stack = stack_len > 0; if has_stack { if let Some(stack_ra) = stack_ra { - v.push(LI::Sd { - src: ra, - offset: stack_ra, - base: sp, - }); + v.push(LI::sd(ra, stack_ra, sp)); } } for i in &f.instructions { @@ -144,11 +93,7 @@ pub fn compile(program: IRLProgram) -> (Vec, Option) { dest: t0, src: *src, }, - LI::Sd { - src: t0, - offset: stack[dest] + *offset as i32, - base: sp, - }, + LI::sd(t0, stack[dest] + *offset as i32, sp), ]); } IRI::LoadData { @@ -167,16 +112,8 @@ pub fn compile(program: IRLProgram) -> (Vec, Option) { let mut offset = 0; if let Some((dest, s)) = dest { offset -= align(s); - v.push(LI::Addi { - dest: t0, - src: sp, - imm: stack[&dest], - }); - v.push(LI::Sd { - src: t0, - offset, - base: sp, - }) + v.push(LI::addi(t0, sp, stack[&dest])); + v.push(LI::sd(t0, offset, sp)) } for (arg, s) in args { let bs = align(s); @@ -187,11 +124,7 @@ pub fn compile(program: IRLProgram) -> (Vec, Option) { } IRI::AsmBlock { args, instructions } => { for (reg, var) in args { - v.push(LI::Addi { - dest: *reg, - imm: stack[var], - src: sp, - }); + v.push(LI::addi(*reg, sp, stack[var])); } fn r(rr: RegRef) -> Reg { match rr { @@ -208,21 +141,71 @@ pub fn compile(program: IRLProgram) -> (Vec, Option) { src: r(src), }), AI::La { dest, src } => todo!(), - AI::Ld { dest, base, offset } => v.push(LI::Ld { + AI::Load { + width, + dest, + base, + offset, + } => v.push(LI::Load { + width, dest: r(dest), offset: offset as i32, base: r(base), }), - AI::Sd { src, base, offset } => v.push(LI::Sd { + AI::Store { + width, + src, + base, + offset, + } => v.push(LI::Store { + width, src: r(src), offset: offset as i32, base: r(base), }), - AI::Add { dest, src1, src2 } => v.push(LI::Add { + AI::Op { + op, + dest, + src1, + src2, + } => v.push(LI::Op { + op, dest: r(dest), src1: r(src1), src2: r(src2), }), + AI::OpF7 { + op, + funct, + dest, + src1, + src2, + } => v.push(LI::OpF7 { + op, + funct, + dest: r(dest), + src1: r(src1), + src2: r(src2), + }), + AI::OpImm { op, dest, src, imm } => v.push(LI::OpImm { + op, + dest: r(dest), + src: r(src), + imm: imm as i32, + }), + AI::OpImmF7 { + op, + funct, + dest, + src, + imm, + } => v.push(LI::OpImmF7 { + op, + funct, + dest: r(dest), + src: r(src), + imm: imm as i32, + }), } } } @@ -230,28 +213,16 @@ pub fn compile(program: IRLProgram) -> (Vec, Option) { let Some(rva) = stack_rva else { panic!("no return value address on stack!") }; - v.push(LI::Ld { - dest: t0, - offset: rva, - base: sp, - }); + v.push(LI::ld(t0, rva, sp)); mov_mem(&mut v, sp, stack[src], t0, 0, t1, align(&f.ret_size) as u32); } } } if has_stack { if let Some(stack_ra) = stack_ra { - v.push(LI::Ld { - dest: ra, - offset: stack_ra, - base: sp, - }); + v.push(LI::ld(ra, stack_ra, sp)); } - v.push(LI::Addi { - dest: sp, - src: sp, - imm: stack_len, - }); + v.push(LI::addi(sp, sp, stack_len)); } v.push(LI::Ret); fns.push((v, *sym)); diff --git a/src/compiler/arch/riscv64/funct.rs b/src/compiler/arch/riscv64/funct.rs index 39c9be9..f06c335 100644 --- a/src/compiler/arch/riscv64/funct.rs +++ b/src/compiler/arch/riscv64/funct.rs @@ -1,24 +1,96 @@ -use super::Funct3; +use crate::{ir::Len, util::Bits32}; -pub mod op { - use super::*; - pub const ADD : Funct3 = Funct3::new(0b000); - pub const SLL : Funct3 = Funct3::new(0b001); - pub const SLT : Funct3 = Funct3::new(0b010); - pub const SLTU: Funct3 = Funct3::new(0b011); - pub const XOR : Funct3 = Funct3::new(0b100); - pub const SR : Funct3 = Funct3::new(0b101); - pub const OR : Funct3 = Funct3::new(0b110); - pub const AND : Funct3 = Funct3::new(0b111); +pub type Funct3 = Bits32<2, 0>; +pub type Funct7 = Bits32<6, 0>; + +#[repr(u32)] +#[derive(Clone, Copy, Debug)] +pub enum Op { + Add = 0b000, + Sl = 0b001, + Slt = 0b010, + Sltu = 0b011, + Xor = 0b100, + Sr = 0b101, + Or = 0b110, + And = 0b111, } -pub mod width { - use super::*; - pub const B : Funct3 = Funct3::new(0b000); - pub const H : Funct3 = Funct3::new(0b001); - pub const W : Funct3 = Funct3::new(0b010); - pub const D : Funct3 = Funct3::new(0b011); - pub const BU: Funct3 = Funct3::new(0b100); - pub const HU: Funct3 = Funct3::new(0b101); - pub const WU: Funct3 = Funct3::new(0b110); +impl Op { + pub const fn code(&self) -> Funct3 { + Funct3::new(*self as u32) + } + pub const fn str(&self) -> &str { + match self { + Op::Add => "add", + Op::Sl => "sl", + Op::Slt => "slt", + Op::Sltu => "sltu", + Op::Xor => "xor", + Op::Sr => "sr", + Op::Or => "or", + Op::And => "and", + } + } + pub fn fstr(&self, funct: Funct7) -> String { + match (self, funct) { + (Op::Add, funct7::ADD) => "add", + (Op::Add, funct7::SUB) => "sub", + (Op::Sl, funct7::LOGICAL) => "sll", + (Op::Sr, funct7::LOGICAL) => "srl", + (Op::Sr, funct7::ARITHMETIC) => "sra", + other => return self.str().to_string() + "?" + }.to_string() + } +} + +pub mod funct7 { + use super::Funct7; + + pub const LOGICAL: Funct7 = Funct7::new(0b0000000); + pub const ARITHMETIC: Funct7 = Funct7::new(0b0100000); + pub const ADD: Funct7 = Funct7::new(0b0000000); + pub const SUB: Funct7 = Funct7::new(0b0100000); +} + +#[repr(u32)] +#[derive(Clone, Copy, Debug)] +pub enum Width { + B = 0b000, + H = 0b001, + W = 0b010, + D = 0b011, + BU = 0b100, + HU = 0b101, + WU = 0b110, +} + +impl Width { + pub const MAIN: [Self; 4] = [Self::B, Self::H, Self::W, Self::D]; + + pub const fn code(&self) -> Funct3 { + Funct3::new(*self as u32) + } + pub const fn len(&self) -> Len { + match self { + Width::B => 1, + Width::H => 2, + Width::W => 4, + Width::D => 8, + Width::BU => 1, + Width::HU => 2, + Width::WU => 4, + } + } + pub const fn str(&self) -> &str { + match self { + Width::B => "b", + Width::H => "h", + Width::W => "w", + Width::D => "d", + Width::BU => "bu", + Width::HU => "hu", + Width::WU => "wu", + } + } } diff --git a/src/compiler/arch/riscv64/mod.rs b/src/compiler/arch/riscv64/mod.rs index 59a3a12..42c48e9 100644 --- a/src/compiler/arch/riscv64/mod.rs +++ b/src/compiler/arch/riscv64/mod.rs @@ -8,10 +8,10 @@ mod single; use crate::util::BitsI32; use base::*; -use funct::{op::*, width}; use opcode::*; use single::*; pub use asm::*; pub use compile::*; pub use reg::*; +pub use funct::*; diff --git a/src/compiler/arch/riscv64/single.rs b/src/compiler/arch/riscv64/single.rs index a63f5d7..6f3ddb5 100644 --- a/src/compiler/arch/riscv64/single.rs +++ b/src/compiler/arch/riscv64/single.rs @@ -14,46 +14,31 @@ pub const fn auipc(dest: Reg, imm: BitsI32<31, 12>) -> I { u_type(imm.to_u(), dest, AUIPC) } -pub const fn ld(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { - i_type(offset.to_u(), base, width::D, dest, LOAD) -} -pub const fn lw(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { - i_type(offset.to_u(), base, width::W, dest, LOAD) -} -pub const fn lh(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { - i_type(offset.to_u(), base, width::H, dest, LOAD) -} -pub const fn lb(dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { - i_type(offset.to_u(), base, width::B, dest, LOAD) +pub const fn load(width: Width, dest: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { + i_type(offset.to_u(), base, width.code(), dest, LOAD) } -pub const fn sd(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { - s_type(src, base, width::D, offset.to_u(), STORE) -} -pub const fn sb(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { - s_type(src, base, width::B, offset.to_u(), STORE) -} -pub const fn sh(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { - s_type(src, base, width::H, offset.to_u(), STORE) -} -pub const fn sw(src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { - s_type(src, base, width::W, offset.to_u(), STORE) +pub const fn store(width: Width, src: Reg, offset: BitsI32<11, 0>, base: Reg) -> I { + s_type(src, base, width.code(), offset.to_u(), STORE) } -pub const fn add(dest: Reg, src1: Reg, src2: Reg) -> I { - r_type(Bits32::new(0), src2, src1, ADD, dest, OP) +pub const fn opr(op: Op, dest: Reg, src1: Reg, src2: Reg) -> I { + r_type(Bits32::new(0), src2, src1, op.code(), dest, OP) } -pub const fn addi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> I { - i_type(imm.to_u(), src, ADD, dest, IMM_OP) +pub const fn oprf7(op: Op, funct: Funct7, dest: Reg, src1: Reg, src2: Reg) -> I { + r_type(funct, src2, src1, op.code(), dest, OP) } -pub const fn andi(dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> I { - i_type(imm.to_u(), src, AND, dest, IMM_OP) +pub const fn opi(op: Op, dest: Reg, src: Reg, imm: BitsI32<11, 0>) -> I { + i_type(imm.to_u(), src, op.code(), dest, IMM_OP) } -pub const fn slli(dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I { - i_type(Bits32::new(imm.to_u().val()), src, SLL, dest, IMM_OP) -} -pub const fn srli(dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I { - i_type(Bits32::new(imm.to_u().val()), src, SR, dest, IMM_OP) +pub const fn opif7(op: Op, funct: Funct7, dest: Reg, src: Reg, imm: BitsI32<4, 0>) -> I { + i_type( + Bits32::new(imm.to_u().val() + (funct.val() << 5)), + src, + op.code(), + dest, + IMM_OP, + ) } pub const fn jal(dest: Reg, offset: BitsI32<20, 1>) -> I { j_type(offset.to_u(), dest, JAL) diff --git a/src/ir/arch/riscv64.rs b/src/ir/arch/riscv64.rs index cc4dd98..3c56aa8 100644 --- a/src/ir/arch/riscv64.rs +++ b/src/ir/arch/riscv64.rs @@ -15,21 +15,44 @@ pub enum RV64Instruction { dest: RegRef, src: VarInst, }, - Ld { + Load { + width: Width, dest: RegRef, offset: i64, base: RegRef, }, - Sd { + Store { + width: Width, src: RegRef, offset: i64, base: RegRef, }, - Add { + Op { + op: Op, dest: RegRef, src1: RegRef, src2: RegRef, }, + OpF7 { + op: Op, + funct: Funct7, + dest: RegRef, + src1: RegRef, + src2: RegRef, + }, + OpImm { + op: Op, + dest: RegRef, + src: RegRef, + imm: i64, + }, + OpImmF7 { + op: Op, + funct: Funct7, + dest: RegRef, + src: RegRef, + imm: i64, + }, } #[derive(Copy, Clone)] @@ -54,9 +77,41 @@ impl std::fmt::Debug for RV64Instruction { Self::Li { dest, imm } => write!(f, "li {dest:?}, {imm:?}"), Self::Mv { dest, src } => write!(f, "mv {dest:?}, {src:?}"), Self::La { dest, src } => write!(f, "la {dest:?}, {src:?}"), - Self::Ld { dest, offset, base } => write!(f, "ld {dest:?}, {offset}({base:?})"), - Self::Sd { src, offset, base } => write!(f, "sd {src:?}, {offset}({base:?})"), - Self::Add { dest, src1, src2 } => write!(f, "add {dest:?}, {src1:?}, {src2:?}"), + Self::Load { + width, + dest, + offset, + base, + } => write!(f, "l{} {dest:?}, {offset}({base:?})", width.str()), + Self::Store { + width, + src, + offset, + base, + } => write!(f, "s{} {src:?}, {offset}({base:?})", width.str()), + Self::Op { + op, + dest, + src1, + src2, + } => write!(f, "{} {dest:?}, {src1:?}, {src2:?}", op.str()), + Self::OpF7 { + op, + funct, + dest, + src1, + src2, + } => write!(f, "{} {dest:?}, {src1:?}, {src2:?}", op.fstr(*funct)), + Self::OpImm { op, dest, src, imm } => { + write!(f, "{}i {dest:?}, {src:?}, {imm}", op.str()) + } + Self::OpImmF7 { + op, + funct, + dest, + src, + imm, + } => write!(f, "{}i {dest:?}, {src:?}, {imm}", op.fstr(*funct)), } } } diff --git a/src/parser/v3/lower/arch/riscv64.rs b/src/parser/v3/lower/arch/riscv64.rs index 07b10a2..f9a4055 100644 --- a/src/parser/v3/lower/arch/riscv64.rs +++ b/src/parser/v3/lower/arch/riscv64.rs @@ -10,7 +10,95 @@ use crate::{ impl RV64Instruction { pub fn parse(inst: &PInstruction, ctx: &mut FnLowerCtx) -> Option { let args = &inst.args[..]; - Some(match &**inst.op.inner.as_ref()? { + let opstr = &**inst.op.inner.as_ref()?; + let op = |ctx: &mut FnLowerCtx<'_, '_>, op: Op| -> Option { + let [dest, src1, src2] = args else { + ctx.err(format!("{opstr} requires 3 arguments")); + return None; + }; + let dest = RegRef::from_arg(dest, ctx)?; + let src1 = RegRef::from_arg(src1, ctx)?; + let src2 = RegRef::from_arg(src2, ctx)?; + Some(Self::Op { + op, + dest, + src1, + src2, + }) + }; + let opi = |ctx: &mut FnLowerCtx<'_, '_>, op: Op| -> Option { + let [dest, src, imm] = args else { + ctx.err(format!("{opstr} requires 3 arguments")); + return None; + }; + let dest = RegRef::from_arg(dest, ctx)?; + let src = RegRef::from_arg(src, ctx)?; + let imm = i64_from_arg(imm, ctx)?; + Some(Self::OpImm { op, dest, src, imm }) + }; + let opf7 = |ctx: &mut FnLowerCtx<'_, '_>, op: Op, funct: Funct7| -> Option { + let [dest, src1, src2] = args else { + ctx.err(format!("{opstr} requires 3 arguments")); + return None; + }; + let dest = RegRef::from_arg(dest, ctx)?; + let src1 = RegRef::from_arg(src1, ctx)?; + let src2 = RegRef::from_arg(src2, ctx)?; + Some(Self::OpF7 { + op, + funct, + dest, + src1, + src2, + }) + }; + let opif7 = |ctx: &mut FnLowerCtx<'_, '_>, op: Op, funct: Funct7| -> Option { + let [dest, src, imm] = args else { + ctx.err(format!("{opstr} requires 3 arguments")); + return None; + }; + let dest = RegRef::from_arg(dest, ctx)?; + let src = RegRef::from_arg(src, ctx)?; + let imm = i64_from_arg(imm, ctx)?; + Some(Self::OpImmF7 { + op, + funct, + dest, + src, + imm, + }) + }; + let store = |ctx: &mut FnLowerCtx<'_, '_>, width: Width| -> Option { + let [src, offset, base] = args else { + ctx.err(format!("{opstr} requires 3 arguments")); + return None; + }; + let src = RegRef::from_arg(src, ctx)?; + let offset = i64_from_arg(offset, ctx)?; + let base = RegRef::from_arg(base, ctx)?; + Some(Self::Store { + width, + src, + offset, + base, + }) + }; + let load = |ctx: &mut FnLowerCtx<'_, '_>, width: Width| -> Option { + let [dest, offset, base] = args else { + ctx.err("ld requires 3 arguments".to_string()); + return None; + }; + let dest = RegRef::from_arg(dest, ctx)?; + let offset = i64_from_arg(offset, ctx)?; + let base = RegRef::from_arg(base, ctx)?; + Some(Self::Load { + width, + dest, + offset, + base, + }) + }; + Some(match opstr { "ecall" => Self::Ecall, "li" => { let [dest, imm] = args else { @@ -30,26 +118,6 @@ impl RV64Instruction { let src = arg_to_var(src, ctx)?; Self::La { dest, src } } - "ld" => { - let [dest, offset, base] = args else { - ctx.err("ld requires 3 arguments".to_string()); - return None; - }; - let dest = RegRef::from_arg(dest, ctx)?; - let offset = i64_from_arg(offset, ctx)?; - let base = RegRef::from_arg(base, ctx)?; - Self::Ld { dest, offset, base } - } - "sd" => { - let [src, offset, base] = args else { - ctx.err("sd requires 3 arguments".to_string()); - return None; - }; - let src = RegRef::from_arg(src, ctx)?; - let offset = i64_from_arg(offset, ctx)?; - let base = RegRef::from_arg(base, ctx)?; - Self::Sd { src, offset, base } - } "mv" => { let [dest, src] = args else { ctx.err("la requires 2 arguments".to_string()); @@ -59,16 +127,42 @@ impl RV64Instruction { let src = RegRef::from_arg(src, ctx)?; Self::Mv { dest, src } } - "add" => { - let [dest, src1, src2] = args else { - ctx.err("add requires 3 arguments".to_string()); - return None; - }; - let dest = RegRef::from_arg(dest, ctx)?; - let src1 = RegRef::from_arg(src1, ctx)?; - let src2 = RegRef::from_arg(src2, ctx)?; - Self::Add { dest, src1, src2 } - } + + "lb" => load(ctx, Width::B)?, + "lh" => load(ctx, Width::H)?, + "lw" => load(ctx, Width::W)?, + "ld" => load(ctx, Width::D)?, + "lbu" => load(ctx, Width::BU)?, + "lhu" => load(ctx, Width::HU)?, + "lwu" => load(ctx, Width::WU)?, + + "sb" => store(ctx, Width::B)?, + "sh" => store(ctx, Width::H)?, + "sw" => store(ctx, Width::W)?, + "sd" => store(ctx, Width::D)?, + + "addi" => opi(ctx, Op::Add)?, + "slti" => opi(ctx, Op::Slt)?, + "sltiu" => opi(ctx, Op::Sltu)?, + "xori" => opi(ctx, Op::Xor)?, + "ori" => opi(ctx, Op::Or)?, + "andi" => opi(ctx, Op::And)?, + + "slli" => opif7(ctx, Op::Sl, funct7::LOGICAL)?, + "srli" => opif7(ctx, Op::Sr, funct7::LOGICAL)?, + "srla" => opif7(ctx, Op::Sr, funct7::ARITHMETIC)?, + + "add" => opf7(ctx, Op::Add, funct7::ADD)?, + "sub" => opf7(ctx, Op::Add, funct7::SUB)?, + "sll" => op(ctx, Op::Sl)?, + "slt" => op(ctx, Op::Slt)?, + "sltu" => op(ctx, Op::Sltu)?, + "xor" => op(ctx, Op::Xor)?, + "srl" => opf7(ctx, Op::Sr, funct7::LOGICAL)?, + "sra" => opf7(ctx, Op::Sr, funct7::ARITHMETIC)?, + "or" => op(ctx, Op::Or)?, + "and" => op(ctx, Op::And)?, + w => { ctx.err_at(inst.op.span, format!("Unknown instruction '{}'", w)); return None; @@ -92,9 +186,7 @@ impl RegRef { pub fn from_arg(node: &Node, ctx: &mut FnLowerCtx) -> Option { Some(match node.inner.as_ref()? { PAsmArg::Value(node) => { - let Some(reg) = Reg::from_ident(node, ctx) else { - return None; - }; + let reg = Reg::from_ident(node, ctx)?; Self::Reg(reg) } PAsmArg::Ref(node) => Self::Var(ctx.get_var(node)?), @@ -115,7 +207,7 @@ impl Reg { fn i64_from_arg(node: &Node, ctx: &mut FnLowerCtx) -> Option { let PAsmArg::Value(node) = node.inner.as_ref()? else { - ctx.err_at(node.span, format!("Expected an i64, found reference")); + ctx.err_at(node.span, "Expected an i64, found reference".to_string()); return None; }; let word = node.inner.as_ref()?; diff --git a/src/util/bits.rs b/src/util/bits.rs index 3b00463..c3a12af 100644 --- a/src/util/bits.rs +++ b/src/util/bits.rs @@ -10,9 +10,9 @@ pub const fn mask(h: u8, l: u8) -> u32 { base_mask(h - l) << l } -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct Bits32(u32); -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, PartialEq)] pub struct BitsI32(u32); impl Bits32 {