Path: blob/main/cranelift/codegen/src/ir/builder.rs
1693 views
//! Cranelift instruction builder.1//!2//! A `Builder` provides a convenient interface for inserting instructions into a Cranelift3//! function. Many of its methods are generated from the meta language instruction definitions.45use crate::ir;6use crate::ir::instructions::InstructionFormat;7use crate::ir::types;8use crate::ir::{BlockArg, Inst, Opcode, Type, Value};9use crate::ir::{DataFlowGraph, InstructionData};1011/// Base trait for instruction builders.12///13/// The `InstBuilderBase` trait provides the basic functionality required by the methods of the14/// generated `InstBuilder` trait. These methods should not normally be used directly. Use the15/// methods in the `InstBuilder` trait instead.16///17/// Any data type that implements `InstBuilderBase` also gets all the methods of the `InstBuilder`18/// trait.19pub trait InstBuilderBase<'f>: Sized {20/// Get an immutable reference to the data flow graph that will hold the constructed21/// instructions.22fn data_flow_graph(&self) -> &DataFlowGraph;23/// Get a mutable reference to the data flow graph that will hold the constructed24/// instructions.25fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph;2627/// Insert an instruction and return a reference to it, consuming the builder.28///29/// The result types may depend on a controlling type variable. For non-polymorphic30/// instructions with multiple results, pass `INVALID` for the `ctrl_typevar` argument.31fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph);32}3334// Include trait code generated by `cranelift-codegen/meta/src/gen_inst.rs`.35//36// This file defines the `InstBuilder` trait as an extension of `InstBuilderBase` with methods per37// instruction format and per opcode.38include!(concat!(env!("OUT_DIR"), "/inst_builder.rs"));3940/// Any type implementing `InstBuilderBase` gets all the `InstBuilder` methods for free.41impl<'f, T: InstBuilderBase<'f>> InstBuilder<'f> for T {}4243/// Base trait for instruction inserters.44///45/// This is an alternative base trait for an instruction builder to implement.46///47/// An instruction inserter can be adapted into an instruction builder by wrapping it in an48/// `InsertBuilder`. This provides some common functionality for instruction builders that insert49/// new instructions, as opposed to the `ReplaceBuilder` which overwrites existing instructions.50pub trait InstInserterBase<'f>: Sized {51/// Get an immutable reference to the data flow graph.52fn data_flow_graph(&self) -> &DataFlowGraph;5354/// Get a mutable reference to the data flow graph.55fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph;5657/// Insert a new instruction which belongs to the DFG.58fn insert_built_inst(self, inst: Inst) -> &'f mut DataFlowGraph;59}6061use core::marker::PhantomData;6263/// Builder that inserts an instruction at the current position.64///65/// An `InsertBuilder` is a wrapper for an `InstInserterBase` that turns it into an instruction66/// builder with some additional facilities for creating instructions that reuse existing values as67/// their results.68pub struct InsertBuilder<'f, IIB: InstInserterBase<'f>> {69inserter: IIB,70unused: PhantomData<&'f u32>,71}7273impl<'f, IIB: InstInserterBase<'f>> InsertBuilder<'f, IIB> {74/// Create a new builder which inserts instructions at `pos`.75/// The `dfg` and `pos.layout` references should be from the same `Function`.76pub fn new(inserter: IIB) -> Self {77Self {78inserter,79unused: PhantomData,80}81}8283/// Reuse result values in `reuse`.84///85/// Convert this builder into one that will reuse the provided result values instead of86/// allocating new ones. The provided values for reuse must not be attached to anything. Any87/// missing result values will be allocated as normal.88///89/// The `reuse` argument is expected to be an array of `Option<Value>`.90pub fn with_results<Array>(self, reuse: Array) -> InsertReuseBuilder<'f, IIB, Array>91where92Array: AsRef<[Option<Value>]>,93{94InsertReuseBuilder {95inserter: self.inserter,96reuse,97unused: PhantomData,98}99}100101/// Reuse a single result value.102///103/// Convert this into a builder that will reuse `v` as the single result value. The reused104/// result value `v` must not be attached to anything.105///106/// This method should only be used when building an instruction with exactly one result. Use107/// `with_results()` for the more general case.108pub fn with_result(self, v: Value) -> InsertReuseBuilder<'f, IIB, [Option<Value>; 1]> {109// TODO: Specialize this to return a different builder that just attaches `v` instead of110// calling `make_inst_results_reusing()`.111self.with_results([Some(v)])112}113}114115impl<'f, IIB: InstInserterBase<'f>> InstBuilderBase<'f> for InsertBuilder<'f, IIB> {116fn data_flow_graph(&self) -> &DataFlowGraph {117self.inserter.data_flow_graph()118}119120fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {121self.inserter.data_flow_graph_mut()122}123124fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {125let inst;126{127let dfg = self.inserter.data_flow_graph_mut();128inst = dfg.make_inst(data);129dfg.make_inst_results(inst, ctrl_typevar);130}131(inst, self.inserter.insert_built_inst(inst))132}133}134135/// Builder that inserts a new instruction like `InsertBuilder`, but reusing result values.136pub struct InsertReuseBuilder<'f, IIB, Array>137where138IIB: InstInserterBase<'f>,139Array: AsRef<[Option<Value>]>,140{141inserter: IIB,142reuse: Array,143unused: PhantomData<&'f u32>,144}145146impl<'f, IIB, Array> InstBuilderBase<'f> for InsertReuseBuilder<'f, IIB, Array>147where148IIB: InstInserterBase<'f>,149Array: AsRef<[Option<Value>]>,150{151fn data_flow_graph(&self) -> &DataFlowGraph {152self.inserter.data_flow_graph()153}154155fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {156self.inserter.data_flow_graph_mut()157}158159fn build(mut self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {160let inst;161{162let dfg = self.inserter.data_flow_graph_mut();163inst = dfg.make_inst(data);164// Make an `Iterator<Item = Option<Value>>`.165let ru = self.reuse.as_ref().iter().cloned();166dfg.make_inst_results_reusing(inst, ctrl_typevar, ru);167}168(inst, self.inserter.insert_built_inst(inst))169}170}171172/// Instruction builder that replaces an existing instruction.173///174/// The inserted instruction will have the same `Inst` number as the old one.175///176/// If the old instruction still has result values attached, it is assumed that the new instruction177/// produces the same number and types of results. The old result values are preserved. If the178/// replacement instruction format does not support multiple results, the builder panics. It is a179/// bug to leave result values dangling.180pub struct ReplaceBuilder<'f> {181dfg: &'f mut DataFlowGraph,182inst: Inst,183}184185impl<'f> ReplaceBuilder<'f> {186/// Create a `ReplaceBuilder` that will overwrite `inst`.187pub fn new(dfg: &'f mut DataFlowGraph, inst: Inst) -> Self {188Self { dfg, inst }189}190}191192impl<'f> InstBuilderBase<'f> for ReplaceBuilder<'f> {193fn data_flow_graph(&self) -> &DataFlowGraph {194self.dfg195}196197fn data_flow_graph_mut(&mut self) -> &mut DataFlowGraph {198self.dfg199}200201fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph) {202// Splat the new instruction on top of the old one.203self.dfg.insts[self.inst] = data;204205if !self.dfg.has_results(self.inst) {206// The old result values were either detached or non-existent.207// Construct new ones.208self.dfg.make_inst_results(self.inst, ctrl_typevar);209}210211(self.inst, self.dfg)212}213}214215#[cfg(test)]216mod tests {217use crate::cursor::{Cursor, FuncCursor};218use crate::ir::condcodes::*;219use crate::ir::types::*;220use crate::ir::{Function, InstBuilder, ValueDef};221222#[test]223fn types() {224let mut func = Function::new();225let block0 = func.dfg.make_block();226let arg0 = func.dfg.append_block_param(block0, I32);227let mut pos = FuncCursor::new(&mut func);228pos.insert_block(block0);229230// Explicit types.231let v0 = pos.ins().iconst(I32, 3);232assert_eq!(pos.func.dfg.value_type(v0), I32);233234// Inferred from inputs.235let v1 = pos.ins().iadd(arg0, v0);236assert_eq!(pos.func.dfg.value_type(v1), I32);237238// Formula.239let cmp = pos.ins().icmp(IntCC::Equal, arg0, v0);240assert_eq!(pos.func.dfg.value_type(cmp), I8);241}242243#[test]244fn reuse_results() {245let mut func = Function::new();246let block0 = func.dfg.make_block();247let arg0 = func.dfg.append_block_param(block0, I32);248let mut pos = FuncCursor::new(&mut func);249pos.insert_block(block0);250251let v0 = pos.ins().iadd_imm(arg0, 17);252assert_eq!(pos.func.dfg.value_type(v0), I32);253let iadd = pos.prev_inst().unwrap();254assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iadd, 0));255256// Detach v0 and reuse it for a different instruction.257pos.func.dfg.clear_results(iadd);258let v0b = pos.ins().with_result(v0).iconst(I32, 3);259assert_eq!(v0, v0b);260assert_eq!(pos.current_inst(), Some(iadd));261let iconst = pos.prev_inst().unwrap();262assert!(iadd != iconst);263assert_eq!(pos.func.dfg.value_def(v0), ValueDef::Result(iconst, 0));264}265266#[test]267#[should_panic]268#[cfg(debug_assertions)]269fn panics_when_inserting_wrong_opcode() {270use crate::ir::{Opcode, TrapCode};271272let mut func = Function::new();273let block0 = func.dfg.make_block();274let mut pos = FuncCursor::new(&mut func);275pos.insert_block(block0);276277// We are trying to create a Opcode::Return with the InstData::Trap, which is obviously wrong278pos.ins()279.Trap(Opcode::Return, I32, TrapCode::BAD_CONVERSION_TO_INTEGER);280}281}282283284