use crate::ir;
use crate::ir::immediates::Imm64;
use crate::ir::instructions::InstructionFormat;
use crate::ir::types;
use crate::ir::{BlockArg, Inst, Layout, Opcode, Type, Value};
use crate::ir::{DataFlowGraph, InstructionData};
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);
fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst;
fn build_imm_const(
&mut self,
controlling_type: Type,
imm: Imm64,
base_opcode: Opcode,
) -> Value {
if controlling_type == types::I128 {
let mut data = InstructionData::UnaryImm {
opcode: Opcode::Iconst,
imm,
};
data.mask_immediates(types::I64);
let lo = self.build_aux_inst(data, types::I64);
let lo = self.data_flow_graph().first_result(lo);
let opcode = if matches!(
base_opcode,
Opcode::Iadd | Opcode::Imul | Opcode::Sdiv | Opcode::Srem | Opcode::Icmp
) {
Opcode::Sextend
} else {
Opcode::Uextend
};
let ext_inst =
self.build_aux_inst(InstructionData::Unary { opcode, arg: lo }, types::I128);
self.data_flow_graph().first_result(ext_inst)
} else {
let lane_type = controlling_type.lane_type();
let mut data = InstructionData::UnaryImm {
opcode: Opcode::Iconst,
imm,
};
data.mask_immediates(lane_type);
let inst = self.build_aux_inst(data, lane_type);
self.data_flow_graph().first_result(inst)
}
}
}
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;
fn insert_aux_inst(&mut self, inst: Inst);
}
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 dfg = self.inserter.data_flow_graph_mut();
let inst = dfg.make_inst(data);
dfg.make_inst_results(inst, ctrl_typevar);
(inst, self.inserter.insert_built_inst(inst))
}
fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst {
let dfg = self.inserter.data_flow_graph_mut();
let inst = dfg.make_inst(data);
dfg.make_inst_results(inst, ctrl_typevar);
self.inserter.insert_aux_inst(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 dfg = self.inserter.data_flow_graph_mut();
let inst = dfg.make_inst(data);
let reuse = self.reuse.as_ref().iter().cloned();
dfg.make_inst_results_reusing(inst, ctrl_typevar, reuse);
(inst, self.inserter.insert_built_inst(inst))
}
fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst {
let inst;
{
let dfg = self.inserter.data_flow_graph_mut();
inst = dfg.make_inst(data);
dfg.make_inst_results(inst, ctrl_typevar);
}
self.inserter.insert_aux_inst(inst);
inst
}
}
pub struct ReplaceBuilder<'f> {
dfg: &'f mut DataFlowGraph,
layout: &'f mut Layout,
inst: Inst,
}
impl<'f> ReplaceBuilder<'f> {
pub fn new(dfg: &'f mut DataFlowGraph, layout: &'f mut Layout, inst: Inst) -> Self {
Self { dfg, layout, 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.insts[self.inst] = data;
if !self.dfg.has_results(self.inst) {
self.dfg.make_inst_results(self.inst, ctrl_typevar);
}
(self.inst, self.dfg)
}
fn build_aux_inst(&mut self, data: InstructionData, ctrl_typevar: Type) -> Inst {
let inst = self.dfg.make_inst(data);
self.dfg.make_inst_results(inst, ctrl_typevar);
self.layout.insert_inst(inst, self.inst);
inst
}
}
#[cfg(test)]
mod tests {
use crate::cursor::{Cursor, FuncCursor};
use crate::ir::condcodes::*;
use crate::ir::types::*;
use crate::ir::{Function, InstBuilder, Opcode, 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), I8);
}
#[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]
fn replace_with_imm_method() {
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);
pos.ins().icmp(IntCC::Equal, arg0, arg0);
}
let inst = func.layout.last_inst(block0).unwrap();
assert_eq!(func.dfg.insts[inst].opcode(), Opcode::Icmp);
let result = func.replace(inst).icmp_imm(IntCC::Equal, arg0, 42);
assert_eq!(func.dfg.insts[inst].opcode(), Opcode::Icmp);
assert_eq!(func.dfg.value_type(result), I8);
let iconst = func.layout.prev_inst(inst).unwrap();
assert_eq!(func.dfg.insts[iconst].opcode(), Opcode::Iconst);
let iconst_result = func.dfg.first_result(iconst);
assert_eq!(func.dfg.value_type(iconst_result), I32);
assert_eq!(func.dfg.inst_args(inst), &[arg0, iconst_result]);
}
#[test]
#[should_panic]
#[cfg(debug_assertions)]
fn panics_when_inserting_wrong_opcode() {
use crate::ir::{Opcode, TrapCode};
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::BAD_CONVERSION_TO_INTEGER);
}
}