Fiddle around with if-expression codegen
This commit is contained in:
parent
c50474cc8e
commit
d757ac4eb3
@ -1,8 +1,8 @@
|
||||
use reid_lib::{ConstValue, Context, InstructionKind, CmpPredicate, TerminatorKind, Type};
|
||||
use reid_lib::{ConstValue, Context, Instr, CmpPredicate, TerminatorKind, Type};
|
||||
|
||||
fn main() {
|
||||
use ConstValue::*;
|
||||
use InstructionKind::*;
|
||||
use Instr::*;
|
||||
|
||||
let context = Context::new();
|
||||
|
||||
|
@ -4,8 +4,8 @@
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
use crate::{
|
||||
BlockData, ConstValue, FunctionData, InstructionData, InstructionKind, ModuleData,
|
||||
TerminatorKind, Type, util::match_types,
|
||||
BlockData, ConstValue, FunctionData, Instr, InstructionData, ModuleData, TerminatorKind, Type,
|
||||
util::match_types,
|
||||
};
|
||||
|
||||
#[derive(Clone, Hash, Copy, PartialEq, Eq)]
|
||||
@ -196,7 +196,7 @@ impl Builder {
|
||||
}
|
||||
|
||||
pub fn check_instruction(&self, instruction: &InstructionValue) -> Result<(), ()> {
|
||||
use super::InstructionKind::*;
|
||||
use super::Instr::*;
|
||||
unsafe {
|
||||
match self.instr_data(&instruction).kind {
|
||||
Param(_) => Ok(()),
|
||||
@ -228,6 +228,11 @@ impl Builder {
|
||||
Phi(vals) => {
|
||||
let mut iter = vals.iter();
|
||||
// TODO error: Phi must contain at least one item
|
||||
|
||||
// TODO error: compile can actually crash here if any of the
|
||||
// incoming values come from blocks that are added later
|
||||
// than the one where this one exists.
|
||||
|
||||
let first = iter.next().ok_or(())?;
|
||||
for item in iter {
|
||||
match_types(first, item, &self)?;
|
||||
@ -241,7 +246,7 @@ impl Builder {
|
||||
|
||||
impl InstructionValue {
|
||||
pub(crate) fn get_type(&self, builder: &Builder) -> Result<Type, ()> {
|
||||
use InstructionKind::*;
|
||||
use Instr::*;
|
||||
unsafe {
|
||||
match &builder.instr_data(self).kind {
|
||||
Param(nth) => builder
|
||||
@ -323,7 +328,7 @@ impl TerminatorKind {
|
||||
use TerminatorKind::*;
|
||||
match self {
|
||||
Ret(instr_val) => instr_val.get_type(builder),
|
||||
Branch(_) => Ok(Type::Void),
|
||||
Br(_) => Ok(Type::Void),
|
||||
CondBr(_, _, _) => Ok(Type::Void),
|
||||
}
|
||||
}
|
||||
|
@ -253,7 +253,7 @@ impl InstructionHolder {
|
||||
) -> LLVMValue {
|
||||
let _ty = self.value.get_type(module.builder).unwrap();
|
||||
let val = unsafe {
|
||||
use super::InstructionKind::*;
|
||||
use super::Instr::*;
|
||||
match &self.data.kind {
|
||||
Param(nth) => LLVMGetParam(function.value_ref, *nth as u32),
|
||||
Constant(val) => val.as_llvm(module.context_ref),
|
||||
@ -348,7 +348,7 @@ impl TerminatorKind {
|
||||
let value = module.values.get(val).unwrap();
|
||||
LLVMBuildRet(module.builder_ref, value.value_ref)
|
||||
}
|
||||
TerminatorKind::Branch(block_value) => {
|
||||
TerminatorKind::Br(block_value) => {
|
||||
let dest = *module.blocks.get(block_value).unwrap();
|
||||
LLVMBuildBr(module.builder_ref, dest)
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
use std::fmt::{Debug, Write};
|
||||
|
||||
use crate::{CmpPredicate, InstructionData, InstructionKind, TerminatorKind, builder::*};
|
||||
use crate::{CmpPredicate, Instr, InstructionData, TerminatorKind, builder::*};
|
||||
|
||||
impl Debug for Builder {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
@ -81,7 +81,7 @@ impl Debug for InstructionValue {
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for InstructionKind {
|
||||
impl Debug for Instr {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Self::Param(nth) => fmt_call(f, &"Param", &nth),
|
||||
@ -141,7 +141,7 @@ impl Debug for TerminatorKind {
|
||||
write!(f, "Ret ")?;
|
||||
val.fmt(f)
|
||||
}
|
||||
Self::Branch(val) => {
|
||||
Self::Br(val) => {
|
||||
write!(f, "Br ")?;
|
||||
val.fmt(f)
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ pub struct Block<'builder> {
|
||||
}
|
||||
|
||||
impl<'builder> Block<'builder> {
|
||||
pub fn build(&mut self, instruction: InstructionKind) -> Result<InstructionValue, ()> {
|
||||
pub fn build(&mut self, instruction: Instr) -> Result<InstructionValue, ()> {
|
||||
unsafe {
|
||||
self.builder
|
||||
.add_instruction(&self.value, InstructionData { kind: instruction })
|
||||
@ -137,7 +137,7 @@ impl<'builder> Block<'builder> {
|
||||
|
||||
#[derive(Clone, Hash)]
|
||||
pub struct InstructionData {
|
||||
kind: InstructionKind,
|
||||
kind: Instr,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Hash)]
|
||||
@ -151,7 +151,7 @@ pub enum CmpPredicate {
|
||||
}
|
||||
|
||||
#[derive(Clone, Hash)]
|
||||
pub enum InstructionKind {
|
||||
pub enum Instr {
|
||||
Param(usize),
|
||||
Constant(ConstValue),
|
||||
Add(InstructionValue, InstructionValue),
|
||||
@ -200,6 +200,6 @@ pub enum ConstValue {
|
||||
#[derive(Clone, Hash)]
|
||||
pub enum TerminatorKind {
|
||||
Ret(InstructionValue),
|
||||
Branch(BlockValue),
|
||||
Br(BlockValue),
|
||||
CondBr(InstructionValue, BlockValue, BlockValue),
|
||||
}
|
||||
|
@ -5,8 +5,10 @@ fn main() -> bool {
|
||||
|
||||
// Fibonacci
|
||||
fn fibonacci(value: u16) -> u16 {
|
||||
if value <= 2 {
|
||||
return 1;
|
||||
}
|
||||
return fibonacci(value - 1) + fibonacci(value - 2);
|
||||
let ret = if value <= 2 {
|
||||
1
|
||||
} else {
|
||||
fibonacci(value - 1) + fibonacci(value - 2)
|
||||
};
|
||||
ret
|
||||
}
|
||||
|
@ -1,3 +1,6 @@
|
||||
//! This is the module that contains relevant code to parsing Reid, that is to
|
||||
//! say transforming a Vec of FullTokens into a loose parsed AST that can be
|
||||
//! used for unwrapping syntax sugar, and then be transformed into Reid MIR.
|
||||
use crate::token_stream::TokenRange;
|
||||
|
||||
pub mod parse;
|
||||
|
@ -204,10 +204,17 @@ impl Parse for FunctionCallExpression {
|
||||
impl Parse for IfExpression {
|
||||
fn parse(mut stream: TokenStream) -> Result<Self, Error> {
|
||||
stream.expect(Token::If)?;
|
||||
let cond = stream.parse()?;
|
||||
let then_b = stream.parse()?;
|
||||
let else_b = if let Ok(_) = stream.expect(Token::Else) {
|
||||
Some(stream.parse()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ok(IfExpression(
|
||||
stream.parse()?,
|
||||
stream.parse()?,
|
||||
None,
|
||||
cond,
|
||||
then_b,
|
||||
else_b,
|
||||
stream.get_range().unwrap(),
|
||||
))
|
||||
}
|
||||
@ -324,7 +331,7 @@ impl Parse for Block {
|
||||
ReturnType::Hard => {
|
||||
return_stmt = Some((*r_type, e.clone()));
|
||||
break; // Return has to be the last statement
|
||||
// TODO: Make a mechanism that "can" parse even after this
|
||||
// TODO: Make a mechanism that "can" parse even after this
|
||||
}
|
||||
ReturnType::Soft => {
|
||||
return_stmt = Some((*r_type, e.clone()));
|
||||
|
@ -1,11 +1,11 @@
|
||||
use std::{collections::HashMap, mem};
|
||||
|
||||
use reid_lib::{
|
||||
builder::InstructionValue, Block, CmpPredicate, ConstValue, Context, Function, InstructionKind,
|
||||
Module, TerminatorKind, Type,
|
||||
Block, CmpPredicate, ConstValue, Context, Function, Instr, Module, TerminatorKind as Term,
|
||||
Type, builder::InstructionValue,
|
||||
};
|
||||
|
||||
use crate::mir::{self, types::ReturnType, TypeKind, VariableReference};
|
||||
use crate::mir::{self, TypeKind, VariableReference, types::ReturnType};
|
||||
|
||||
/// Context that contains all of the given modules as complete codegenerated
|
||||
/// LLIR that can then be finally compiled into LLVM IR.
|
||||
@ -74,10 +74,7 @@ impl mir::Module {
|
||||
|
||||
let mut stack_values = HashMap::new();
|
||||
for (i, (p_name, _)) in mir_function.parameters.iter().enumerate() {
|
||||
stack_values.insert(
|
||||
p_name.clone(),
|
||||
entry.build(InstructionKind::Param(i)).unwrap(),
|
||||
);
|
||||
stack_values.insert(p_name.clone(), entry.build(Instr::Param(i)).unwrap());
|
||||
}
|
||||
|
||||
let mut scope = Scope {
|
||||
@ -91,7 +88,7 @@ impl mir::Module {
|
||||
match &mir_function.kind {
|
||||
mir::FunctionDefinitionKind::Local(block, _) => {
|
||||
if let Some(ret) = block.codegen(&mut scope) {
|
||||
scope.block.terminate(TerminatorKind::Ret(ret)).unwrap();
|
||||
scope.block.terminate(Term::Ret(ret)).unwrap();
|
||||
}
|
||||
}
|
||||
mir::FunctionDefinitionKind::Extern => {}
|
||||
@ -155,62 +152,53 @@ impl mir::IfExpression {
|
||||
let condition = self.0.codegen(scope).unwrap();
|
||||
|
||||
// Create blocks
|
||||
let then_bb = scope.function.block("then");
|
||||
let after_bb = scope.function.block("after");
|
||||
let mut before_bb = scope.swap_block(after_bb);
|
||||
let then_b = scope.function.block("then");
|
||||
let mut else_b = scope.function.block("else");
|
||||
let after_b = scope.function.block("after");
|
||||
|
||||
let mut then_scope = scope.with_block(then_bb);
|
||||
// Store for convenience
|
||||
let then_bb = then_b.value();
|
||||
let else_bb = else_b.value();
|
||||
let after_bb = after_b.value();
|
||||
|
||||
// Generate then-block content
|
||||
let mut then_scope = scope.with_block(then_b);
|
||||
let then_res = self.1.codegen(&mut then_scope);
|
||||
then_scope
|
||||
.block
|
||||
.terminate(TerminatorKind::Branch(scope.block.value()))
|
||||
.ok();
|
||||
|
||||
let else_bb = scope.function.block("else");
|
||||
let mut else_scope = scope.with_block(else_bb);
|
||||
then_scope.block.terminate(Term::Br(after_bb)).ok();
|
||||
|
||||
let else_res = if let Some(else_block) = &self.2 {
|
||||
before_bb
|
||||
.terminate(TerminatorKind::CondBr(
|
||||
condition,
|
||||
then_scope.block.value(),
|
||||
else_scope.block.value(),
|
||||
))
|
||||
let mut else_scope = scope.with_block(else_b);
|
||||
scope
|
||||
.block
|
||||
.terminate(Term::CondBr(condition, then_bb, else_bb))
|
||||
.unwrap();
|
||||
|
||||
let opt = else_block.codegen(&mut else_scope);
|
||||
|
||||
if let Some(ret) = opt {
|
||||
else_scope
|
||||
.block
|
||||
.terminate(TerminatorKind::Branch(scope.block.value()))
|
||||
.ok();
|
||||
else_scope.block.terminate(Term::Br(after_bb)).ok();
|
||||
Some(ret)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else {
|
||||
else_scope
|
||||
else_b.terminate(Term::Br(after_bb)).unwrap();
|
||||
scope
|
||||
.block
|
||||
.terminate(TerminatorKind::Branch(scope.block.value()))
|
||||
.unwrap();
|
||||
before_bb
|
||||
.terminate(TerminatorKind::CondBr(
|
||||
condition,
|
||||
then_scope.block.value(),
|
||||
scope.block.value(),
|
||||
))
|
||||
.terminate(Term::CondBr(condition, then_bb, after_bb))
|
||||
.unwrap();
|
||||
None
|
||||
};
|
||||
|
||||
// Swap block to the after-block so that construction can continue correctly
|
||||
scope.swap_block(after_b);
|
||||
|
||||
if then_res.is_none() && else_res.is_none() {
|
||||
None
|
||||
} else {
|
||||
let mut inc = Vec::from(then_res.as_slice());
|
||||
inc.extend(else_res);
|
||||
|
||||
Some(scope.block.build(InstructionKind::Phi(vec![])).unwrap())
|
||||
let mut incoming = Vec::from(then_res.as_slice());
|
||||
incoming.extend(else_res);
|
||||
Some(scope.block.build(Instr::Phi(incoming)).unwrap())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -242,21 +230,13 @@ impl mir::Expression {
|
||||
let lhs = lhs_exp.codegen(scope).expect("lhs has no return value");
|
||||
let rhs = rhs_exp.codegen(scope).expect("rhs has no return value");
|
||||
Some(match binop {
|
||||
mir::BinaryOperator::Add => {
|
||||
scope.block.build(InstructionKind::Add(lhs, rhs)).unwrap()
|
||||
}
|
||||
mir::BinaryOperator::Minus => {
|
||||
scope.block.build(InstructionKind::Sub(lhs, rhs)).unwrap()
|
||||
}
|
||||
mir::BinaryOperator::Mult => {
|
||||
scope.block.build(InstructionKind::Mult(lhs, rhs)).unwrap()
|
||||
}
|
||||
mir::BinaryOperator::And => {
|
||||
scope.block.build(InstructionKind::And(lhs, rhs)).unwrap()
|
||||
}
|
||||
mir::BinaryOperator::Add => scope.block.build(Instr::Add(lhs, rhs)).unwrap(),
|
||||
mir::BinaryOperator::Minus => scope.block.build(Instr::Sub(lhs, rhs)).unwrap(),
|
||||
mir::BinaryOperator::Mult => scope.block.build(Instr::Mult(lhs, rhs)).unwrap(),
|
||||
mir::BinaryOperator::And => scope.block.build(Instr::And(lhs, rhs)).unwrap(),
|
||||
mir::BinaryOperator::Cmp(l) => scope
|
||||
.block
|
||||
.build(InstructionKind::ICmp(l.int_predicate(), lhs, rhs))
|
||||
.build(Instr::ICmp(l.int_predicate(), lhs, rhs))
|
||||
.unwrap(),
|
||||
})
|
||||
}
|
||||
@ -277,7 +257,7 @@ impl mir::Expression {
|
||||
Some(
|
||||
scope
|
||||
.block
|
||||
.build(InstructionKind::FunctionCall(callee.value(), params))
|
||||
.build(Instr::FunctionCall(callee.value(), params))
|
||||
.unwrap(),
|
||||
)
|
||||
}
|
||||
@ -287,7 +267,7 @@ impl mir::Expression {
|
||||
if let Some(ret) = block.codegen(&mut inner_scope) {
|
||||
inner_scope
|
||||
.block
|
||||
.terminate(TerminatorKind::Branch(scope.block.value()))
|
||||
.terminate(Term::Br(scope.block.value()))
|
||||
.unwrap();
|
||||
Some(ret)
|
||||
} else {
|
||||
@ -321,7 +301,7 @@ impl mir::Block {
|
||||
let ret = expr.codegen(&mut scope).unwrap();
|
||||
match kind {
|
||||
mir::ReturnKind::Hard => {
|
||||
scope.block.terminate(TerminatorKind::Ret(ret)).unwrap();
|
||||
scope.block.terminate(Term::Ret(ret)).unwrap();
|
||||
None
|
||||
}
|
||||
mir::ReturnKind::Soft => Some(ret),
|
||||
@ -337,8 +317,8 @@ impl mir::Literal {
|
||||
block.build(self.as_const_kind()).unwrap()
|
||||
}
|
||||
|
||||
fn as_const_kind(&self) -> InstructionKind {
|
||||
InstructionKind::Constant(match *self {
|
||||
fn as_const_kind(&self) -> Instr {
|
||||
Instr::Constant(match *self {
|
||||
mir::Literal::I8(val) => ConstValue::I8(val),
|
||||
mir::Literal::I16(val) => ConstValue::I16(val),
|
||||
mir::Literal::I32(val) => ConstValue::I32(val),
|
||||
|
@ -22,6 +22,8 @@ pub enum Token {
|
||||
Arrow,
|
||||
/// `if`
|
||||
If,
|
||||
/// `else`
|
||||
Else,
|
||||
/// `true`
|
||||
True,
|
||||
/// `false`
|
||||
@ -172,6 +174,7 @@ pub fn tokenize<T: Into<String>>(to_tokenize: T) -> Result<Vec<FullToken>, Error
|
||||
"return" => Token::ReturnKeyword,
|
||||
"fn" => Token::FnKeyword,
|
||||
"if" => Token::If,
|
||||
"else" => Token::Else,
|
||||
"true" => Token::True,
|
||||
"false" => Token::False,
|
||||
_ => Token::Identifier(value),
|
||||
|
@ -87,6 +87,8 @@ pub fn compile(source: &str) -> Result<String, ReidError> {
|
||||
dbg!(&ast_module);
|
||||
let mut mir_context = mir::Context::from(vec![ast_module]);
|
||||
|
||||
println!("{}", &mir_context);
|
||||
|
||||
let state = mir_context.pass(&mut TypeCheck);
|
||||
dbg!(&state);
|
||||
|
||||
|
@ -76,7 +76,7 @@ impl Display for Block {
|
||||
if let Some(ret) = &self.return_expression {
|
||||
match ret.0 {
|
||||
ReturnKind::Hard => writeln!(inner_f, "Return(Hard): {}", ret.1),
|
||||
ReturnKind::Soft => writeln!(inner_f, "Return(Hard): {}", ret.1),
|
||||
ReturnKind::Soft => writeln!(inner_f, "Return(Soft): {}", ret.1),
|
||||
}?;
|
||||
} else {
|
||||
writeln!(inner_f, "No Return")?;
|
||||
|
@ -252,7 +252,18 @@ impl Expression {
|
||||
} else {
|
||||
Vague(Unknown)
|
||||
};
|
||||
then_ret_t.collapse_into(&else_ret_t)
|
||||
|
||||
let collapsed = then_ret_t.collapse_into(&else_ret_t)?;
|
||||
if let Some(rhs) = rhs {
|
||||
// If rhs existed, typecheck both sides to perform type
|
||||
// coercion.
|
||||
let lhs_res = lhs.typecheck(state, Some(collapsed));
|
||||
let rhs_res = rhs.typecheck(state, Some(collapsed));
|
||||
state.ok(lhs_res, lhs.meta);
|
||||
state.ok(rhs_res, rhs.meta);
|
||||
}
|
||||
|
||||
Ok(collapsed)
|
||||
}
|
||||
ExprKind::Block(block) => block.typecheck(state, hint_t),
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user