Add a preliminary codegen of case statement

This commit is contained in:
Guojie Luo 2022-03-22 10:27:05 +08:00
parent 47b085e249
commit 83dfd6e618
1 changed files with 96 additions and 9 deletions

View File

@ -1,4 +1,4 @@
use crate::cst::{Expression, ModuleContext, Statement, Tag, Tools}; use crate::cst::{Expression, ModuleContext, Statement, Tag, Tools, UnitContext};
use json::JsonValue; use json::JsonValue;
use llhd::ir::Block; use llhd::ir::Block;
@ -11,22 +11,109 @@ impl CaseStatement {
pub fn codegen(json: &JsonValue, context: &mut ModuleContext) -> Option<Block> { pub fn codegen(json: &JsonValue, context: &mut ModuleContext) -> Option<Block> {
let (json_expression, json_case_items, json_default_statement) = Self::analyze(json); let (json_expression, json_case_items, json_default_statement) = Self::analyze(json);
if context.unit_ctx.data.is_none() {
Expression::codegen(json_expression, context); Expression::codegen(json_expression, context);
for (json_case_expressions, json_statement) in json_case_items { for (json_case_expressions, json_statement) in json_case_items {
for json_case_expression in json_case_expressions { for json_case_expression in json_case_expressions {
Expression::codegen(json_case_expression, context); Expression::codegen(json_case_expression, context);
} }
Statement::codegen(json_statement, context); Self::visit_case_body(json_statement, context);
} }
if json_default_statement.is_some() { if json_default_statement.is_some() {
Statement::codegen(json_default_statement.unwrap(), context); Self::visit_case_body(json_default_statement.unwrap(), context);
} }
warn!("TODO: finish codegen()"); return None;
}
let expr = {
let e = Expression::codegen(json_expression, context);
assert!(e.is_some(), "FIXME: CST node '{}'", json_expression);
e.unwrap()
};
let mut bb_next = {
let unit_ctx = &mut context.unit_ctx;
let mut builder = UnitContext::builder(&mut unit_ctx.data);
builder.block()
};
let case_tails: Vec<_> = json_case_items
.iter()
.map(|(json_case_expressions, json_statement)| {
let case_expressions: Vec<_> = json_case_expressions
.iter()
.map(|x| Expression::codegen(x, context).unwrap())
.collect();
let bb_curr = {
let unit_ctx = &mut context.unit_ctx;
let mut builder = UnitContext::builder(&mut unit_ctx.data);
let bb_curr = bb_next;
bb_next = builder.block();
builder.append_to(unit_ctx.bb_head.pop().unwrap());
unit_ctx.bb_head.push(bb_next); // basic block for the next case
let case_expr = case_expressions
.into_iter()
.reduce(|x, y| builder.ins().or(x, y))
.unwrap();
let cond = builder.ins().eq(expr, case_expr);
builder.ins().br_cond(cond, bb_next, bb_curr);
bb_curr
};
context.unit_ctx.bb_head.push(bb_curr);
let stmt = Self::visit_case_body(json_statement, context);
context.unit_ctx.bb_head.pop();
stmt.unwrap()
})
.collect();
if json_default_statement.is_some() {
let stmt = Self::visit_case_body(json_default_statement.unwrap(), context);
let unit_ctx = &mut context.unit_ctx;
unit_ctx.bb_head.pop();
unit_ctx.bb_head.push(stmt.unwrap()); // basic block for the future statement
bb_next = stmt.unwrap();
}
let unit_ctx = &mut context.unit_ctx;
if unit_ctx.data.is_some() {
let mut builder = UnitContext::builder(&mut unit_ctx.data);
// merge dangling basic blocks at the end of each case
for case_tail in case_tails {
builder.replace_block_use(case_tail, bb_next);
builder.delete_block(case_tail);
}
}
Some(bb_next)
}
fn visit_case_body(json: &JsonValue, context: &mut ModuleContext) -> Option<Block> {
let stmt = Statement::codegen(json, context);
if context.unit_ctx.data.is_some() {
let unit_ctx = &mut context.unit_ctx;
let mut builder = UnitContext::builder(&mut unit_ctx.data);
let bb_dangled = builder.block();
builder.append_to(stmt.unwrap());
builder.ins().br(bb_dangled);
Some(bb_dangled)
} else {
None None
} }
}
fn analyze( fn analyze(
json: &JsonValue, json: &JsonValue,