Skip to content

Commit

Permalink
feat: adds update operators and diagnostics
Browse files Browse the repository at this point in the history
  • Loading branch information
baszalmstra committed Oct 30, 2019
1 parent 40db1e3 commit eefa40c
Show file tree
Hide file tree
Showing 20 changed files with 389 additions and 235 deletions.
168 changes: 121 additions & 47 deletions crates/mun_codegen/src/ir/body.rs
Expand Up @@ -11,8 +11,7 @@ use mun_hir::{
};
use std::{collections::HashMap, mem, sync::Arc};

mod name;
use name::OptName;
use inkwell::values::PointerValue;

pub(crate) struct BodyIrGenerator<'a, 'b, D: IrDatabase> {
db: &'a D,
Expand Down Expand Up @@ -73,8 +72,10 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
Pat::Bind { name } => {
let name = name.to_string();
let param = self.fn_value.get_nth_param(i as u32).unwrap();
param.set_name(&name); // Assign a name to the IR value consistent with the code.
self.pat_to_param.insert(*pat, param);
let builder = self.new_alloca_builder();
let param_ptr = builder.build_alloca(param.get_type(), &name);
builder.build_store(param_ptr, param);
self.pat_to_local.insert(*pat, param_ptr);
self.pat_to_name.insert(*pat, name);
}
Pat::Wild => {
Expand Down Expand Up @@ -115,7 +116,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
}
Expr::Literal(lit) => Some(self.gen_literal(lit)),
Expr::BinaryOp { lhs, rhs, op } => {
Some(self.gen_binary_op(expr, *lhs, *rhs, op.expect("missing op")))
self.gen_binary_op(expr, *lhs, *rhs, op.expect("missing op"))
}
Expr::Call {
ref callee,
Expand Down Expand Up @@ -247,28 +248,40 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
}
}

/// Generates IR for looking up a certain path expression.
fn gen_path_place_expr(
&self,
path: &Path,
_expr: ExprId,
resolver: &Resolver,
) -> inkwell::values::PointerValue {
let resolution = resolver
.resolve_path_without_assoc_items(self.db, path)
.take_values()
.expect("unknown path");

match resolution {
Resolution::LocalBinding(pat) => *self
.pat_to_local
.get(&pat)
.expect("unresolved local binding"),
Resolution::Def(_) => panic!("no support for module definitions"),
}
}

/// Generates IR to calculate a binary operation between two expressions.
fn gen_binary_op(
&mut self,
_tgt_expr: ExprId,
lhs: ExprId,
rhs: ExprId,
op: BinaryOp,
) -> BasicValueEnum {
let lhs_value = self.gen_expr(lhs).expect("no lhs value");
let rhs_value = self.gen_expr(rhs).expect("no rhs value");
) -> Option<BasicValueEnum> {
let lhs_type = self.infer[lhs].clone();
let rhs_type = self.infer[rhs].clone();

match lhs_type.as_simple() {
Some(TypeCtor::Float) => self.gen_binary_op_float(
*lhs_value.as_float_value(),
*rhs_value.as_float_value(),
op,
),
Some(TypeCtor::Int) => {
self.gen_binary_op_int(*lhs_value.as_int_value(), *rhs_value.as_int_value(), op)
}
Some(TypeCtor::Float) => self.gen_binary_op_float(lhs, rhs, op),
Some(TypeCtor::Int) => self.gen_binary_op_int(lhs, rhs, op),
_ => unimplemented!(
"unimplemented operation {0}op{1}",
lhs_type.display(self.db),
Expand All @@ -280,21 +293,20 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
/// Generates IR to calculate a binary operation between two floating point values.
fn gen_binary_op_float(
&mut self,
lhs: FloatValue,
rhs: FloatValue,
lhs_expr: ExprId,
rhs_expr: ExprId,
op: BinaryOp,
) -> BasicValueEnum {
) -> Option<BasicValueEnum> {
let lhs = self
.gen_expr(lhs_expr)
.expect("no lhs value")
.into_float_value();
let rhs = self
.gen_expr(rhs_expr)
.expect("no rhs value")
.into_float_value();
match op {
BinaryOp::ArithOp(ArithOp::Add) => self.builder.build_float_add(lhs, rhs, "add").into(),
BinaryOp::ArithOp(ArithOp::Subtract) => {
self.builder.build_float_sub(lhs, rhs, "sub").into()
}
BinaryOp::ArithOp(ArithOp::Divide) => {
self.builder.build_float_div(lhs, rhs, "div").into()
}
BinaryOp::ArithOp(ArithOp::Multiply) => {
self.builder.build_float_mul(lhs, rhs, "mul").into()
}
BinaryOp::ArithOp(op) => Some(self.gen_arith_bin_op_float(lhs, rhs, op).into()),
BinaryOp::CmpOp(op) => {
let (name, predicate) = match op {
CmpOp::Eq { negated: false } => ("eq", FloatPredicate::OEQ),
Expand All @@ -316,27 +328,42 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
strict: true,
} => ("greater", FloatPredicate::OGT),
};
self.builder
.build_float_compare(predicate, lhs, rhs, name)
.into()
Some(
self.builder
.build_float_compare(predicate, lhs, rhs, name)
.into(),
)
}
BinaryOp::Assignment { op } => {
let rhs = match op {
Some(op) => self.gen_arith_bin_op_float(lhs, rhs, op),
None => rhs,
};
let place = self.gen_place_expr(lhs_expr);
self.builder.build_store(place, rhs);
None
}
_ => unimplemented!("Operator {:?} is not implemented for float", op),
}
}

/// Generates IR to calculate a binary operation between two integer values.
fn gen_binary_op_int(&mut self, lhs: IntValue, rhs: IntValue, op: BinaryOp) -> BasicValueEnum {
fn gen_binary_op_int(
&mut self,
lhs_expr: ExprId,
rhs_expr: ExprId,
op: BinaryOp,
) -> Option<BasicValueEnum> {
let lhs = self
.gen_expr(lhs_expr)
.expect("no lhs value")
.into_int_value();
let rhs = self
.gen_expr(rhs_expr)
.expect("no rhs value")
.into_int_value();
match op {
BinaryOp::ArithOp(ArithOp::Add) => self.builder.build_int_add(lhs, rhs, "add").into(),
BinaryOp::ArithOp(ArithOp::Subtract) => {
self.builder.build_int_sub(lhs, rhs, "sub").into()
}
BinaryOp::ArithOp(ArithOp::Divide) => {
self.builder.build_int_signed_div(lhs, rhs, "div").into()
}
BinaryOp::ArithOp(ArithOp::Multiply) => {
self.builder.build_int_mul(lhs, rhs, "mul").into()
}
BinaryOp::ArithOp(op) => Some(self.gen_arith_bin_op_int(lhs, rhs, op).into()),
BinaryOp::CmpOp(op) => {
let (name, predicate) = match op {
CmpOp::Eq { negated: false } => ("eq", IntPredicate::EQ),
Expand All @@ -358,14 +385,61 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
strict: true,
} => ("greater", IntPredicate::SGT),
};
self.builder
.build_int_compare(predicate, lhs, rhs, name)
.into()
Some(
self.builder
.build_int_compare(predicate, lhs, rhs, name)
.into(),
)
}
BinaryOp::Assignment { op } => {
let rhs = match op {
Some(op) => self.gen_arith_bin_op_int(lhs, rhs, op),
None => rhs,
};
let place = self.gen_place_expr(lhs_expr);
self.builder.build_store(place, rhs);
None
}
_ => unreachable!(format!("Operator {:?} is not implemented for integer", op)),
}
}

fn gen_arith_bin_op_int(&mut self, lhs: IntValue, rhs: IntValue, op: ArithOp) -> IntValue {
match op {
ArithOp::Add => self.builder.build_int_add(lhs, rhs, "add"),
ArithOp::Subtract => self.builder.build_int_sub(lhs, rhs, "sub"),
ArithOp::Divide => self.builder.build_int_signed_div(lhs, rhs, "div"),
ArithOp::Multiply => self.builder.build_int_mul(lhs, rhs, "mul"),
}
}

fn gen_arith_bin_op_float(
&mut self,
lhs: FloatValue,
rhs: FloatValue,
op: ArithOp,
) -> FloatValue {
match op {
ArithOp::Add => self.builder.build_float_add(lhs, rhs, "add"),
ArithOp::Subtract => self.builder.build_float_sub(lhs, rhs, "sub"),
ArithOp::Divide => self.builder.build_float_div(lhs, rhs, "div"),
ArithOp::Multiply => self.builder.build_float_mul(lhs, rhs, "mul"),
}
}

/// Given an expression generate code that results in a memory address that can be used for
/// other place operations.
fn gen_place_expr(&mut self, expr: ExprId) -> PointerValue {
let body = self.body.clone();
match &body[expr] {
Expr::Path(ref p) => {
let resolver = mun_hir::resolver_for_expr(self.body.clone(), self.db, expr);
self.gen_path_place_expr(p, expr, &resolver)
}
_ => unreachable!("invalid place expression"),
}
}

// TODO: Implement me!
fn should_use_dispatch_table(&self) -> bool {
true
Expand Down
30 changes: 0 additions & 30 deletions crates/mun_codegen/src/ir/body/name.rs

This file was deleted.

12 changes: 6 additions & 6 deletions crates/mun_codegen/src/snapshots/test__binary_expressions.snap
Expand Up @@ -5,21 +5,21 @@ expression: "fn add(a:int, b:int):int {\n a+b\n}\n\nfn subtract(a:int, b:int):i
; ModuleID = 'main.mun'
source_filename = "main.mun"

define i64 @add(i64 %a, i64 %b) {
define i64 @add(i64, i64) {
body:
%add = add i64 %a, %b
%add = add i64 %0, %1
ret i64 %add
}

define i64 @subtract(i64 %a, i64 %b) {
define i64 @subtract(i64, i64) {
body:
%sub = sub i64 %a, %b
%sub = sub i64 %0, %1
ret i64 %sub
}

define i64 @multiply(i64 %a, i64 %b) {
define i64 @multiply(i64, i64) {
body:
%mul = mul i64 %a, %b
%mul = mul i64 %0, %1
ret i64 %mul
}

48 changes: 24 additions & 24 deletions crates/mun_codegen/src/snapshots/test__equality_operands.snap
Expand Up @@ -5,75 +5,75 @@ expression: "fn equals(a:int, b:int):bool { a == b }\nfn not_equa
; ModuleID = 'main.mun'
source_filename = "main.mun"

define i1 @equals(i64 %a, i64 %b) {
define i1 @equals(i64, i64) {
body:
%eq = icmp eq i64 %a, %b
%eq = icmp eq i64 %0, %1
ret i1 %eq
}

define i1 @not_equals(i64 %a, i64 %b) {
define i1 @not_equals(i64, i64) {
body:
%neq = icmp ne i64 %a, %b
%neq = icmp ne i64 %0, %1
ret i1 %neq
}

define i1 @less(i64 %a, i64 %b) {
define i1 @less(i64, i64) {
body:
%less = icmp slt i64 %a, %b
%less = icmp slt i64 %0, %1
ret i1 %less
}

define i1 @less_equal(i64 %a, i64 %b) {
define i1 @less_equal(i64, i64) {
body:
%lesseq = icmp sle i64 %a, %b
%lesseq = icmp sle i64 %0, %1
ret i1 %lesseq
}

define i1 @greater(i64 %a, i64 %b) {
define i1 @greater(i64, i64) {
body:
%greater = icmp sgt i64 %a, %b
%greater = icmp sgt i64 %0, %1
ret i1 %greater
}

define i1 @greater_equal(i64 %a, i64 %b) {
define i1 @greater_equal(i64, i64) {
body:
%greatereq = icmp sge i64 %a, %b
%greatereq = icmp sge i64 %0, %1
ret i1 %greatereq
}

define i1 @equalsf(double %a, double %b) {
define i1 @equalsf(double, double) {
body:
%eq = fcmp oeq double %a, %b
%eq = fcmp oeq double %0, %1
ret i1 %eq
}

define i1 @not_equalsf(double %a, double %b) {
define i1 @not_equalsf(double, double) {
body:
%neq = fcmp one double %a, %b
%neq = fcmp one double %0, %1
ret i1 %neq
}

define i1 @lessf(double %a, double %b) {
define i1 @lessf(double, double) {
body:
%less = fcmp olt double %a, %b
%less = fcmp olt double %0, %1
ret i1 %less
}

define i1 @less_equalf(double %a, double %b) {
define i1 @less_equalf(double, double) {
body:
%lesseq = fcmp ole double %a, %b
%lesseq = fcmp ole double %0, %1
ret i1 %lesseq
}

define i1 @greaterf(double %a, double %b) {
define i1 @greaterf(double, double) {
body:
%greater = fcmp ogt double %a, %b
%greater = fcmp ogt double %0, %1
ret i1 %greater
}

define i1 @greater_equalf(double %a, double %b) {
define i1 @greater_equalf(double, double) {
body:
%greatereq = fcmp oge double %a, %b
%greatereq = fcmp oge double %0, %1
ret i1 %greatereq
}

0 comments on commit eefa40c

Please sign in to comment.