Skip to content

feat: add assignment, bit, and boolean operators #144

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

Merged
merged 1 commit into from
Apr 30, 2020
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
149 changes: 142 additions & 7 deletions crates/mun_codegen/src/ir/body.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use crate::{
};
use hir::{
ArenaId, ArithOp, BinaryOp, Body, CmpOp, Expr, ExprId, HirDisplay, InferenceResult, Literal,
Name, Ordering, Pat, PatId, Path, Resolution, Resolver, Statement, TypeCtor, UnaryOp,
LogicOp, Name, Ordering, Pat, PatId, Path, Resolution, Resolver, Statement, TypeCtor, UnaryOp,
};
use inkwell::{
builder::Builder,
Expand Down Expand Up @@ -613,15 +613,25 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
op: BinaryOp,
) -> Option<BasicValueEnum> {
let lhs_type = self.infer[lhs].clone();
let rhs_type = self.infer[rhs].clone();
match lhs_type.as_simple() {
Some(TypeCtor::Bool) => self.gen_binary_op_bool(lhs, rhs, op),
Some(TypeCtor::Float(_ty)) => self.gen_binary_op_float(lhs, rhs, op),
Some(TypeCtor::Int(ty)) => self.gen_binary_op_int(lhs, rhs, op, ty.signedness),
_ => unimplemented!(
"unimplemented operation {0}op{1}",
lhs_type.display(self.db),
rhs_type.display(self.db)
),
Some(TypeCtor::Struct(s)) => {
if s.data(self.db).memory_kind == hir::StructMemoryKind::Value {
self.gen_binary_op_value_struct(lhs, rhs, op)
} else {
self.gen_binary_op_heap_struct(lhs, rhs, op)
}
}
_ => {
let rhs_type = self.infer[rhs].clone();
unimplemented!(
"unimplemented operation {0}op{1}",
lhs_type.display(self.db),
rhs_type.display(self.db)
)
}
}
}

Expand Down Expand Up @@ -687,6 +697,39 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
}
}

/// Generates IR to calculate a binary operation between two boolean value.
fn gen_binary_op_bool(
&mut self,
lhs_expr: ExprId,
rhs_expr: ExprId,
op: BinaryOp,
) -> Option<BasicValueEnum> {
let lhs: IntValue = self
.gen_expr(lhs_expr)
.map(|value| self.opt_deref_value(self.infer[lhs_expr].clone(), value))
.expect("no lhs value")
.into_int_value();
let rhs: IntValue = self
.gen_expr(rhs_expr)
.map(|value| self.opt_deref_value(self.infer[rhs_expr].clone(), value))
.expect("no rhs value")
.into_int_value();
match op {
BinaryOp::ArithOp(op) => Some(self.gen_arith_bin_op_bool(lhs, rhs, op).into()),
BinaryOp::Assignment { op } => {
let rhs = match op {
Some(op) => self.gen_arith_bin_op_bool(lhs, rhs, op),
None => rhs,
};
let place = self.gen_place_expr(lhs_expr);
self.builder.build_store(place, rhs);
Some(self.gen_empty())
}
BinaryOp::LogicOp(op) => Some(self.gen_logic_bin_op(lhs, rhs, op).into()),
_ => unimplemented!("Operator {:?} is not implemented for boolean", op),
}
}

/// Generates IR to calculate a binary operation between two floating point values.
fn gen_binary_op_float(
&mut self,
Expand Down Expand Up @@ -832,6 +875,76 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
}
}

/// Generates IR to calculate a binary operation between two heap struct values (e.g. a Mun
/// `struct(gc)`).
fn gen_binary_op_heap_struct(
&mut self,
lhs_expr: ExprId,
rhs_expr: ExprId,
op: BinaryOp,
) -> Option<BasicValueEnum> {
let rhs = self
.gen_expr(rhs_expr)
.expect("no rhs value")
.into_pointer_value();
match op {
BinaryOp::Assignment { op } => {
let rhs = match op {
Some(op) => unimplemented!(
"Assignment with {:?} operator is not implemented for struct",
op
),
None => rhs,
};
let place = self.gen_place_expr(lhs_expr);
self.builder.build_store(place, rhs);
Some(self.gen_empty())
}
_ => unimplemented!("Operator {:?} is not implemented for struct", op),
}
}

/// Generates IR to calculate a binary operation between two value struct values, denoted in
/// Mun as `struct(value)`.
fn gen_binary_op_value_struct(
&mut self,
lhs_expr: ExprId,
rhs_expr: ExprId,
op: BinaryOp,
) -> Option<BasicValueEnum> {
let rhs = self
.gen_expr(rhs_expr)
.expect("no rhs value")
.into_struct_value();
match op {
BinaryOp::Assignment { op } => {
let rhs = match op {
Some(op) => unimplemented!(
"Assignment with {:?} operator is not implemented for struct",
op
),
None => rhs,
};
let place = self.gen_place_expr(lhs_expr);
self.builder.build_store(place, rhs);
Some(self.gen_empty())
}
_ => unimplemented!("Operator {:?} is not implemented for struct", op),
}
}

fn gen_arith_bin_op_bool(&mut self, lhs: IntValue, rhs: IntValue, op: ArithOp) -> IntValue {
match op {
ArithOp::BitAnd => self.builder.build_and(lhs, rhs, "bit_and"),
ArithOp::BitOr => self.builder.build_or(lhs, rhs, "bit_or"),
ArithOp::BitXor => self.builder.build_xor(lhs, rhs, "bit_xor"),
_ => unimplemented!(
"Assignment with {:?} operator is not implemented for boolean",
op
),
}
}

fn gen_arith_bin_op_int(
&mut self,
lhs: IntValue,
Expand All @@ -851,6 +964,14 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
hir::Signedness::Signed => self.builder.build_int_signed_rem(lhs, rhs, "rem"),
hir::Signedness::Unsigned => self.builder.build_int_unsigned_rem(lhs, rhs, "rem"),
},
ArithOp::LeftShift => self.builder.build_left_shift(lhs, rhs, "left_shift"),
ArithOp::RightShift => {
self.builder
.build_right_shift(lhs, rhs, signedness.is_signed(), "right_shift")
}
ArithOp::BitAnd => self.builder.build_and(lhs, rhs, "bit_and"),
ArithOp::BitOr => self.builder.build_or(lhs, rhs, "bit_or"),
ArithOp::BitXor => self.builder.build_xor(lhs, rhs, "bit_xor"),
}
}

Expand All @@ -866,6 +987,20 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> {
ArithOp::Divide => self.builder.build_float_div(lhs, rhs, "div"),
ArithOp::Multiply => self.builder.build_float_mul(lhs, rhs, "mul"),
ArithOp::Remainder => self.builder.build_float_rem(lhs, rhs, "rem"),
ArithOp::LeftShift
| ArithOp::RightShift
| ArithOp::BitAnd
| ArithOp::BitOr
| ArithOp::BitXor => {
unreachable!(format!("Operator {:?} is not implemented for float", op))
}
}
}

fn gen_logic_bin_op(&mut self, lhs: IntValue, rhs: IntValue, op: LogicOp) -> IntValue {
match op {
LogicOp::And => self.builder.build_and(lhs, rhs, "and"),
LogicOp::Or => self.builder.build_or(lhs, rhs, "or"),
}
}

Expand Down
53 changes: 53 additions & 0 deletions crates/mun_codegen/src/snapshots/test__arithmetic_op_f32.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
source: crates/mun_codegen/src/test.rs
expression: "pub fn add(a: f32, b: f32) -> f32 { a + b }\npub fn subtract(a: f32, b: f32) -> f32 { a - b }\npub fn multiply(a: f32, b: f32) -> f32 { a * b }\npub fn divide(a: f32, b: f32) -> f32 { a / b }\npub fn remainder(a: f32, b: f32) -> f32 { a % b }"
---
; == FILE IR =====================================
; ModuleID = 'main.mun'
source_filename = "main.mun"

%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i32, i8, i8 }

@global_type_table = external global [1 x %struct.MunTypeInfo addrspace(4)*]

define float @add(float, float) {
body:
%add = fadd float %0, %1
ret float %add
}

define float @subtract(float, float) {
body:
%sub = fsub float %0, %1
ret float %sub
}

define float @multiply(float, float) {
body:
%mul = fmul float %0, %1
ret float %mul
}

define float @divide(float, float) {
body:
%div = fdiv float %0, %1
ret float %div
}

define float @remainder(float, float) {
body:
%rem = frem float %0, %1
ret float %rem
}


; == GROUP IR ====================================
; ModuleID = 'group_name'
source_filename = "group_name"

%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i32, i8, i8 }

@"type_info::<core::f32>::name" = private unnamed_addr constant [10 x i8] c"core::f32\00"
@"type_info::<core::f32>" = private unnamed_addr constant %struct.MunTypeInfo { [16 x i8] c"P\19b7\A8k\F2\81P\FB\83\F5P\B0\82!", [10 x i8]* @"type_info::<core::f32>::name", i32 32, i8 4, i8 0 }
@global_type_table = global [1 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::<core::f32>"]

53 changes: 53 additions & 0 deletions crates/mun_codegen/src/snapshots/test__arithmetic_op_f64.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
source: crates/mun_codegen/src/test.rs
expression: "pub fn add(a: f64, b: f64) -> f64 { a + b }\npub fn subtract(a: f64, b: f64) -> f64 { a - b }\npub fn multiply(a: f64, b: f64) -> f64 { a * b }\npub fn divide(a: f64, b: f64) -> f64 { a / b }\npub fn remainder(a: f64, b: f64) -> f64 { a % b }"
---
; == FILE IR =====================================
; ModuleID = 'main.mun'
source_filename = "main.mun"

%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i32, i8, i8 }

@global_type_table = external global [1 x %struct.MunTypeInfo addrspace(4)*]

define double @add(double, double) {
body:
%add = fadd double %0, %1
ret double %add
}

define double @subtract(double, double) {
body:
%sub = fsub double %0, %1
ret double %sub
}

define double @multiply(double, double) {
body:
%mul = fmul double %0, %1
ret double %mul
}

define double @divide(double, double) {
body:
%div = fdiv double %0, %1
ret double %div
}

define double @remainder(double, double) {
body:
%rem = frem double %0, %1
ret double %rem
}


; == GROUP IR ====================================
; ModuleID = 'group_name'
source_filename = "group_name"

%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i32, i8, i8 }

@"type_info::<core::f64>::name" = private unnamed_addr constant [10 x i8] c"core::f64\00"
@"type_info::<core::f64>" = private unnamed_addr constant %struct.MunTypeInfo { [16 x i8] c"`\DBF\9C?YJ%G\AD4\9F\D5\92%A", [10 x i8]* @"type_info::<core::f64>::name", i32 64, i8 8, i8 0 }
@global_type_table = global [1 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::<core::f64>"]

53 changes: 53 additions & 0 deletions crates/mun_codegen/src/snapshots/test__arithmetic_op_float.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
source: crates/mun_codegen/src/test.rs
expression: "pub fn add(a: float, b: float) -> float { a + b }\npub fn subtract(a: float, b: float) -> float { a - b }\npub fn multiply(a: float, b: float) -> float { a * b }\npub fn divide(a: float, b: float) -> float { a / b }\npub fn remainder(a: float, b: float) -> float { a % b }"
---
; == FILE IR =====================================
; ModuleID = 'main.mun'
source_filename = "main.mun"

%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i32, i8, i8 }

@global_type_table = external global [1 x %struct.MunTypeInfo addrspace(4)*]

define double @add(double, double) {
body:
%add = fadd double %0, %1
ret double %add
}

define double @subtract(double, double) {
body:
%sub = fsub double %0, %1
ret double %sub
}

define double @multiply(double, double) {
body:
%mul = fmul double %0, %1
ret double %mul
}

define double @divide(double, double) {
body:
%div = fdiv double %0, %1
ret double %div
}

define double @remainder(double, double) {
body:
%rem = frem double %0, %1
ret double %rem
}


; == GROUP IR ====================================
; ModuleID = 'group_name'
source_filename = "group_name"

%struct.MunTypeInfo = type { [16 x i8], i8 addrspace(4)*, i32, i8, i8 }

@"type_info::<core::f64>::name" = private unnamed_addr constant [10 x i8] c"core::f64\00"
@"type_info::<core::f64>" = private unnamed_addr constant %struct.MunTypeInfo { [16 x i8] c"`\DBF\9C?YJ%G\AD4\9F\D5\92%A", [10 x i8]* @"type_info::<core::f64>::name", i32 64, i8 8, i8 0 }
@global_type_table = global [1 x %struct.MunTypeInfo addrspace(4)*] [%struct.MunTypeInfo addrspace(4)* @"type_info::<core::f64>"]

Loading