Skip to content

Commit

Permalink
Merge pull request #144 from Wodann/feature/all-operators
Browse files Browse the repository at this point in the history
feat: add assignment, bit, and boolean operators
  • Loading branch information
Wodann authored Apr 30, 2020
2 parents f1b49f2 + 78c9169 commit 0df0317
Show file tree
Hide file tree
Showing 127 changed files with 6,270 additions and 431 deletions.
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

0 comments on commit 0df0317

Please sign in to comment.