From c80a0d912ef484d96b596402067a6bfe75991a79 Mon Sep 17 00:00:00 2001 From: Edgar Luque Date: Tue, 10 Dec 2024 09:45:15 -0300 Subject: [PATCH] expressiosn chapter --- docs/src/workshop_p3.md | 64 ++++++++++++++++++++++++++++++++++++++ src/codegen/expressions.rs | 20 +++++++----- 2 files changed, 76 insertions(+), 8 deletions(-) diff --git a/docs/src/workshop_p3.md b/docs/src/workshop_p3.md index 510bbb9..e34b6d6 100644 --- a/docs/src/workshop_p3.md +++ b/docs/src/workshop_p3.md @@ -1 +1,65 @@ # Workshop: Compiling Expressions + +To compile expressions, the following is needed: + +- Create a constant number. +- From a variable identifier, get it's value. +- Apply a binary operation to 2 other expressions. + + +```rust +// src/codegen/expressions.rs +pub fn compile_expr<'ctx: 'parent, 'parent>( + // Helper struct with the MLIR Context and Module + ctx: &ModuleCtx<'ctx>, + // Hashmap storing the local variables + locals: &HashMap>, + // The current block to work on. + block: &'parent Block<'ctx>, + // The expression to compile. + expr: &Expr, +) -> Value<'ctx, 'parent> { + match expr { + Expr::Number(_value) => { + todo!("implement constant numbers") + } + Expr::Variable(name) => { + todo!("implement loading values from the given variable name") + } + Expr::Op(lhs_expr, opcode, rhs_expr) => match opcode { + Opcode::Mul => todo!("implement mul"), + Opcode::Div => todo!("implement div"), + Opcode::Add => todo!("implement add"), + Opcode::Sub => todo!("implement sub"), + Opcode::Eq => todo!("implement eq"), + Opcode::Neq => todo!("implement neq"), + }, + } +} +``` + + +## Constants in MLIR + +There are various ways to create a constant, in our case, we have 2 dialects available to use: +- The [llvm](https://mlir.llvm.org/docs/Dialects/LLVM/) dialect. +- The [arith](https://mlir.llvm.org/docs/Dialects/ArithOps/) dialect. + +> You can find documentation about all dialects and their operations here: + +It is recommended to use the `arith` dialect in this case. + +Some useful types you will need: `Type`, `IntegerAttribute`, `IntegerType`, `Location`. + +## Loading a variable value + +To make things simpler, all variables are stored inside an `llvm.alloca`, which is an operation +that given a size gives a pointer to it. Thus, depending on the use a load/store operation is needed. This avoids dealing with Block arguments but makes the compiler rely on LLVM to optimize these `allocas` (which it does really well). + +For this case you can use the [llvm](https://mlir.llvm.org/docs/Dialects/LLVM/) dialect to **load** from the pointer. The variable pointer value can be found in the given hashmap `locals`. + +## Binary operations + +> To iterate is human, to recurse, divine + +Here you will need to use the `arith` dialect to compute the binary operations from computing the `lhs` and `rhs` expressions. diff --git a/src/codegen/expressions.rs b/src/codegen/expressions.rs index fa30731..33bd41d 100644 --- a/src/codegen/expressions.rs +++ b/src/codegen/expressions.rs @@ -12,25 +12,29 @@ use crate::ast::{Expr, Opcode}; use super::ModuleCtx; pub fn compile_expr<'ctx: 'parent, 'parent>( + // Helper struct with the MLIR Context and Module ctx: &ModuleCtx<'ctx>, + // Hashmap storing the local variables locals: &HashMap>, + // The current block to work on. block: &'parent Block<'ctx>, + // The expression to compile. expr: &Expr, ) -> Value<'ctx, 'parent> { match expr { Expr::Number(_value) => { - todo!() + todo!("implement constant numbers") } Expr::Variable(name) => { - todo!() + todo!("implement loading values from the given variable name") } Expr::Op(lhs_expr, opcode, rhs_expr) => match opcode { - Opcode::Mul => todo!(), - Opcode::Div => todo!(), - Opcode::Add => todo!(), - Opcode::Sub => todo!(), - Opcode::Eq => todo!(), - Opcode::Neq => todo!(), + Opcode::Mul => todo!("implement mul"), + Opcode::Div => todo!("implement div"), + Opcode::Add => todo!("implement add"), + Opcode::Sub => todo!("implement sub"), + Opcode::Eq => todo!("implement eq"), + Opcode::Neq => todo!("implement neq"), }, } }