implemented most binary and unary operations for DSCS compiler (excl memory ops and boolean logic)

This commit is contained in:
2026-08-23 00:00:06 +01:00
parent e35ba0e511
commit 97e43b8b85
2 changed files with 198 additions and 13 deletions
@@ -1,9 +1,8 @@
use std::any::Any;
use dsa_tasks::ProcessAgent; use dsa_tasks::ProcessAgent;
use crate::model::ast::{ use crate::model::ast::{BinaryOperator, Block, Call, Declaration, Expression, Number, Program, Statement, TypeId, UnaryOperator, Variable};
Block, Call, Declaration, Expression, Number, Program, Statement, TypeId, Variable, use crate::model::dsa_ir::{BasicBlock, IRProgram, Label, Literal, PrimitiveOperation, PrimitiveUnaryOperation, Terminator, VirtualReg};
};
use crate::model::dsa_ir::{BasicBlock, IRProgram, Label, Literal, Terminator, VirtualReg};
use crate::model::{CompilerError, dsa_ir as IR}; use crate::model::{CompilerError, dsa_ir as IR};
pub struct IrLoweringCodeGenerator { pub struct IrLoweringCodeGenerator {
@@ -383,8 +382,8 @@ impl IrLoweringCodeGenerator {
} }
// TODO! all of the below: // TODO! all of the below:
Expression::Binary { .. } => Ok(()), Expression::Binary { op, left, right, .. } => self.collapse_binary_expr(left, right, op, ctx, v_reg),
Expression::Unary { .. } => Ok(()), Expression::Unary { op, operand, .. } => self.collapse_unary_op(operand, op, ctx, v_reg),
Expression::UnaryPostfix { .. } => Ok(()), Expression::UnaryPostfix { .. } => Ok(()),
Expression::TypeCast { .. } => Ok(()), Expression::TypeCast { .. } => Ok(()),
Expression::IndexAccess { .. } => Ok(()), Expression::IndexAccess { .. } => Ok(()),
@@ -394,6 +393,139 @@ impl IrLoweringCodeGenerator {
Expression::StructLiteral { .. } => Ok(()), Expression::StructLiteral { .. } => Ok(()),
} }
} }
fn collapse_unary_op(
&self,
expr: &Expression,
op: &UnaryOperator,
ctx: &mut FunctionContext,
result_reg: VirtualReg,
) -> Result<(), CompilerError> {
let intermediate_reg = ctx.new_vreg();
self.collapse_expression(expr, ctx, intermediate_reg)?;
let ir_stmt = match op {
UnaryOperator::Plus => IR::Statement::UnaryOp {
// use the identity operation as '+x' on an integer 'x' is a no-op
op: PrimitiveUnaryOperation::Identity,
operand: intermediate_reg,
result: result_reg,
},
UnaryOperator::Minus => IR::Statement::UnaryOp {
op: PrimitiveUnaryOperation::Negation,
operand: intermediate_reg,
result: result_reg,
},
// allocating a vreg for an incrementation isn't very elegant but it can be easily optimised out.
UnaryOperator::Increment => {
let right_vreg = ctx.new_vreg();
ctx.push_stmt(IR::Statement::Const(right_vreg, Literal::Int(1)));
IR::Statement::BinaryOp {
left: intermediate_reg,
op: PrimitiveOperation::Add,
right: right_vreg,
result: result_reg,
}
},
UnaryOperator::Decrement => {
let right_vreg = ctx.new_vreg();
ctx.push_stmt(IR::Statement::Const(right_vreg, Literal::Int(1)));
IR::Statement::BinaryOp {
left: intermediate_reg,
op: PrimitiveOperation::Sub,
right: right_vreg,
result: result_reg,
}
},
// TODO: for now we assume all values are primitives.
// hence this implementation is *not correct* for structs and will produce UB.
UnaryOperator::Dereference => IR::Statement::Load {
address: intermediate_reg,
result: result_reg,
},
// TODO: this may be quite complex as we have to guarantee ahead of time that this value has a memory address!
UnaryOperator::AddressOf => todo!(),
// TODO: if the expression is pure, we don't need to evaluate it to know the size.
UnaryOperator::SizeOf => {
let size = expr.type_id()
.map_err(|_| CompilerError::generic("All types are expected to be sized at this stage"))?
.size();
IR::Statement::Const(result_reg, Literal::Int(size as isize))
},
UnaryOperator::BitwiseNot => IR::Statement::UnaryOp {
op: PrimitiveUnaryOperation::Not,
operand: intermediate_reg,
result: result_reg,
},
// TODO: the IR can't represent boolean operators yet. do we add it to the IR or do something here instead?
UnaryOperator::LogicalNot => todo!(),
};
ctx.push_stmt(ir_stmt);
Ok(())
}
fn collapse_binary_expr(
&self,
left: &Expression,
right: &Expression,
op: &BinaryOperator,
ctx: &mut FunctionContext,
result_vreg: VirtualReg,
) -> Result<(), CompilerError> {
let left_vreg = ctx.new_vreg();
self.collapse_expression(left, ctx, left_vreg)?;
let right_vreg = ctx.new_vreg();
self.collapse_expression(right, ctx, right_vreg)?;
let primitive_operation = match op {
// arithmetic
BinaryOperator::Add => PrimitiveOperation::Add,
BinaryOperator::Sub => PrimitiveOperation::Sub,
// bitwise logic
BinaryOperator::BitwiseAnd => PrimitiveOperation::And,
BinaryOperator::BitwiseOr => PrimitiveOperation::Or,
BinaryOperator::BitwiseXor => PrimitiveOperation::Xor,
BinaryOperator::LeftShift => PrimitiveOperation::LeftShift,
BinaryOperator::RightShift => PrimitiveOperation::RightShift,
// comparison logic
BinaryOperator::Equal => PrimitiveOperation::IsEqual,
BinaryOperator::NotEqual => PrimitiveOperation::NotEqual,
BinaryOperator::LessThan => PrimitiveOperation::LessThan,
BinaryOperator::GreaterThan => PrimitiveOperation::GreaterThan,
BinaryOperator::LessOrEqual => PrimitiveOperation::LessOrEqual,
BinaryOperator::GreaterOrEqual => PrimitiveOperation::GreaterOrEqual,
// boolean logic
BinaryOperator::LogicalAnd => todo!(),
BinaryOperator::LogicalOr => todo!(),
// non-primitive arithmetic (TODO: requires library support)
BinaryOperator::Mul => todo!(),
BinaryOperator::Div => todo!(),
BinaryOperator::Mod => todo!(),
};
ctx.push_stmt(IR::Statement::BinaryOp {
left: left_vreg,
op: primitive_operation,
right: right_vreg,
result: result_vreg,
});
Ok(())
}
} }
struct BasicBlockBuilder { struct BasicBlockBuilder {
+60 -7
View File
@@ -12,6 +12,11 @@ pub enum Statement {
right: VirtualReg, right: VirtualReg,
result: VirtualReg, result: VirtualReg,
}, },
UnaryOp {
op: PrimitiveUnaryOperation,
operand: VirtualReg,
result: VirtualReg,
},
Copy { Copy {
src: VirtualReg, src: VirtualReg,
dst: VirtualReg, dst: VirtualReg,
@@ -124,6 +129,18 @@ pub enum Literal {
Char(char), Char(char),
} }
#[derive(Clone, Debug)]
pub enum PrimitiveUnaryOperation {
// used by compilers for no-ops such as the unary addition operation
// this should be optimised out in almost all cases.
Identity,
// negate a given value
Negation,
// Invert the bits of the given operation.
Not,
}
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
pub enum PrimitiveOperation { pub enum PrimitiveOperation {
Add, Add,
@@ -133,6 +150,16 @@ pub enum PrimitiveOperation {
Xor, Xor,
Nor, Nor,
Nand, Nand,
LeftShift,
RightShift,
IsEqual,
NotEqual,
LessThan,
LessOrEqual,
GreaterThan,
GreaterOrEqual,
} }
impl fmt::Display for VirtualReg { impl fmt::Display for VirtualReg {
@@ -158,13 +185,32 @@ impl fmt::Display for Literal {
impl fmt::Display for PrimitiveOperation { impl fmt::Display for PrimitiveOperation {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let s = match self { let s = match self {
PrimitiveOperation::Add => "+", Self::Add => "+",
PrimitiveOperation::Sub => "-", Self::Sub => "-",
PrimitiveOperation::And => "&", Self::And => "&",
PrimitiveOperation::Or => "|", Self::Or => "|",
PrimitiveOperation::Xor => "^", Self::Xor => "^",
PrimitiveOperation::Nor => "nor", Self::Nor => "nor",
PrimitiveOperation::Nand => "nand", Self::Nand => "nand",
Self::LeftShift => "<<",
Self::RightShift => ">>",
Self::IsEqual => "==",
Self::NotEqual => "!=",
Self::LessThan => "<",
Self::LessOrEqual => "<=",
Self::GreaterThan => ">",
Self::GreaterOrEqual => ">=",
};
write!(f, "{}", s)
}
}
impl fmt::Display for PrimitiveUnaryOperation {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let s = match self {
Self::Identity => "+",
Self::Negation => "-",
Self::Not => "~",
}; };
write!(f, "{}", s) write!(f, "{}", s)
} }
@@ -174,6 +220,13 @@ impl fmt::Display for Statement {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self { match self {
Statement::Const(dst, lit) => write!(f, "{} = literal {}", dst, lit), Statement::Const(dst, lit) => write!(f, "{} = literal {}", dst, lit),
Statement::UnaryOp {
op,
operand,
result,
} => {
write!(f, "{} = {}{}", result, op, operand)
}
Statement::BinaryOp { Statement::BinaryOp {
left, left,
op, op,