use crate::ir;
use crate::ir::instructions::InstructionFormat;
use crate::ir::types;
use crate::ir::{DataFlowGraph, InstructionData};
use crate::ir::{Inst, Opcode, Type, Value};
pub trait InstBuilderBase<'f>: Sized {
fn data_flow_graph(&self) -> &DataFlowGraph;
fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph;
fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph);
}
include!(concat!(env!("OUT_DIR"), "/inst_builder.rs"));
impl<'f, T: InstBuilderBase<'f>> InstBuilder<'f> for T {}
pub trait InstInserterBase<'f>: Sized {
fn data_flow_graph(&self) -> &DataFlowGraph;
fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph;
fn insert_built_inst(self, inst: Inst) -> &'f mut DataFlowGraph;
}
use core::marker::PhantomData;
pub struct InsertBuilder<'f, IIB: InstInserterBase<'f>> {
inserter: IIB,
unused: PhantomData<&'f u32>,
}
impl<'f, IIB: InstInserterBase<'f>> InsertBuilder<'f, IIB> {
pub fn new(inserter: IIB) -> Self {
Self {
inserter,
unused: PhantomData,
}
}
pub fn with_results<Array>(self, reuse: Array) -> InsertReuseBuilder<'f, IIB, Array>
where
Array: AsRef<[Option<Value>]>,
{
InsertReuseBuilder {
inserter: self.inserter,
reuse,
unused: PhantomData,
}
}
pub fn with_result(self, v: Value) -> InsertReuseBuilder<'f, IIB, [Option<Value>; 1]> {
self.with_results([Some(v)])
}
}
impl<'f, IIB: InstInserterBase<'f>> InstBuilderBase<'f> for InsertBuilder<'f, IIB> {
fn data_flow_graph(&self) -> &DataFlowGraph {
self.inserter.data_flow_graph()
}
fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
self.inserter.data_flow_graph_mut()
}
fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
let inst;
{
let dfg = self.inserter.data_flow_graph_mut();
inst = dfg.make_inst(data);
dfg.make_inst_results(inst, ctrl_typevar);
}
(inst, self.inserter.insert_built_inst(inst))
}
}
pub struct InsertReuseBuilder<'f, IIB, Array>
where
IIB: InstInserterBase<'f>,
Array: AsRef<[Option<Value>]>,
{
inserter: IIB,
reuse: Array,
unused: PhantomData<&'f u32>,
}
impl<'f, IIB, Array> InstBuilderBase<'f> for InsertReuseBuilder<'f, IIB, Array>
where
IIB: InstInserterBase<'f>,
Array: AsRef<[Option<Value>]>,
{
fn data_flow_graph(&self) -> &DataFlowGraph {
self.inserter.data_flow_graph()
}
fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
self.inserter.data_flow_graph_mut()
}
fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
let inst;
{
let dfg = self.inserter.data_flow_graph_mut();
inst = dfg.make_inst(data);
let ru = self.reuse.as_ref().iter().cloned();
dfg.make_inst_results_reusing(inst, ctrl_typevar, ru);
}
(inst, self.inserter.insert_built_inst(inst))
}
}
pub struct ReplaceBuilder<'f> {
dfg: &'f mut DataFlowGraph,
inst: Inst,
}
impl<'f> ReplaceBuilder<'f> {
pub fn new(dfg: &'f mut DataFlowGraph, inst: Inst) -> Self {
Self { dfg, inst }
}
}
impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> {
fn data_flow_graph(&self) -> &DataFlowGraph {
self.dfg
}
fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {
self.dfg
}
fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {
self.dfg[self.inst] = data;
if !self.dfg.has_results(self.inst) {
self.dfg.make_inst_results(self.inst, ctrl_typevar);
}
(self.inst, self.dfg)
}
}
#[cfg(test)]
mod tests {
use crate::cursor::{Cursor, FuncCursor};
use crate::ir::condcodes::*;
use crate::ir::types::*;
use crate::ir::{Function, InstBuilder, Opcode, TrapCode, ValueDef};
#[test]
fn types() {
let mut func = Function::new();
let block0 = func.dfg.make_block();
let arg0 = func.dfg.append_block_param(block0, I32);
let mut pos = FuncCursor::new(&mut func);
pos.insert_block(block0);
let v0 = pos.ins().iconst(I32, 3);
assert_eq!(pos.func.dfg.value_type(v0), I32);
let v1 = pos.ins().iadd(arg0, v0);
assert_eq!(pos.func.dfg.value_type(v1), I32);
let cmp = pos.ins().icmp(IntCC::Equal, arg0, v0);
assert_eq!(pos.func.dfg.value_type(cmp), B1);
}
#[test]
fn reuse_results() {
let mut func = Function::new();
let block0 = func.dfg.make_block();
let arg0 = func.dfg.append_block_param(block0, I32);
let mut pos = FuncCursor::new(&mut func);
pos.insert_block(block0);
let v0 = pos.ins().iadd_imm(arg0, 17);
assert_eq!(pos.func.dfg.value_type(v0), I32);
let iadd = pos.prev_inst().unwrap();
assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iadd, 0));
pos.func.dfg.clear_results(iadd);
let v0b = pos.ins().with_result(v0).iconst(I32, 3);
assert_eq!(v0, v0b);
assert_eq!(pos.current_inst(), Some(iadd));
let iconst = pos.prev_inst().unwrap();
assert!(iadd != iconst);
assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iconst, 0));
}
#[test]
#[should_panic]
fn panics_when_inserting_wrong_opcode() {
let mut func = Function::new();
let block0 = func.dfg.make_block();
let mut pos = FuncCursor::new(&mut func);
pos.insert_block(block0);
pos.ins()
.Trap(Opcode::Return, I32, TrapCode::BadConversionToInteger);
}
}