Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: adds update operators and diagnostics #29

Merged
merged 2 commits into from Oct 31, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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
}