Move several functions from FunctionBuilder to Function.
With FuncEnvironment using FuncCursors in place of full FunctionBuilders, it's useful to move several of these convenience functions from FunctionBuilder to Function.
This commit is contained in:
@@ -7,6 +7,8 @@ use entity::{PrimaryMap, EntityMap};
|
|||||||
use ir;
|
use ir;
|
||||||
use ir::{FunctionName, CallConv, Signature, DataFlowGraph, Layout};
|
use ir::{FunctionName, CallConv, Signature, DataFlowGraph, Layout};
|
||||||
use ir::{InstEncodings, ValueLocations, JumpTables, StackSlots, EbbOffsets};
|
use ir::{InstEncodings, ValueLocations, JumpTables, StackSlots, EbbOffsets};
|
||||||
|
use ir::{Ebb, JumpTableData, JumpTable, StackSlotData, StackSlot, SigRef, ExtFuncData, FuncRef,
|
||||||
|
GlobalVarData, GlobalVar, HeapData, Heap};
|
||||||
use isa::TargetIsa;
|
use isa::TargetIsa;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use write::write_function;
|
use write::write_function;
|
||||||
@@ -93,6 +95,42 @@ impl Function {
|
|||||||
Self::with_name_signature(FunctionName::default(), Signature::new(CallConv::Native))
|
Self::with_name_signature(FunctionName::default(), Signature::new(CallConv::Native))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Creates a jump table in the function, to be used by `br_table` instructions.
|
||||||
|
pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable {
|
||||||
|
self.jump_tables.push(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Inserts an entry in a previously declared jump table.
|
||||||
|
pub fn insert_jump_table_entry(&mut self, jt: JumpTable, index: usize, ebb: Ebb) {
|
||||||
|
self.jump_tables[jt].set_entry(index, ebb);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and
|
||||||
|
/// `stack_addr` instructions.
|
||||||
|
pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot {
|
||||||
|
self.stack_slots.push(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a signature which can later be used to declare an external function import.
|
||||||
|
pub fn import_signature(&mut self, signature: Signature) -> SigRef {
|
||||||
|
self.dfg.signatures.push(signature)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declare an external function import.
|
||||||
|
pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef {
|
||||||
|
self.dfg.ext_funcs.push(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declares a global variable accessible to the function.
|
||||||
|
pub fn create_global_var(&mut self, data: GlobalVarData) -> GlobalVar {
|
||||||
|
self.global_vars.push(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declares a heap accessible to the function.
|
||||||
|
pub fn create_heap(&mut self, data: HeapData) -> Heap {
|
||||||
|
self.heaps.push(data)
|
||||||
|
}
|
||||||
|
|
||||||
/// Return an object that can display this function with correct ISA-specific annotations.
|
/// Return an object that can display this function with correct ISA-specific annotations.
|
||||||
pub fn display<'a, I: Into<Option<&'a TargetIsa>>>(&'a self, isa: I) -> DisplayFunction<'a> {
|
pub fn display<'a, I: Into<Option<&'a TargetIsa>>>(&'a self, isa: I) -> DisplayFunction<'a> {
|
||||||
DisplayFunction(self, isa.into())
|
DisplayFunction(self, isa.into())
|
||||||
|
|||||||
@@ -46,6 +46,11 @@ impl JumpTableData {
|
|||||||
self.table[idx] = dest.into();
|
self.table[idx] = dest.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Append a table entry.
|
||||||
|
pub fn push_entry(&mut self, dest: Ebb) {
|
||||||
|
self.table.push(dest.into())
|
||||||
|
}
|
||||||
|
|
||||||
/// Clear a table entry.
|
/// Clear a table entry.
|
||||||
///
|
///
|
||||||
/// The `br_table` instruction will fall through if given an index corresponding to a cleared
|
/// The `br_table` instruction will fall through if given an index corresponding to a cleared
|
||||||
|
|||||||
@@ -255,14 +255,8 @@ mod tests {
|
|||||||
fn stack_slot() {
|
fn stack_slot() {
|
||||||
let mut func = Function::new();
|
let mut func = Function::new();
|
||||||
|
|
||||||
let ss0 = func.stack_slots.push(StackSlotData::new(
|
let ss0 = func.create_stack_slot(StackSlotData::new(StackSlotKind::IncomingArg, 4));
|
||||||
StackSlotKind::IncomingArg,
|
let ss1 = func.create_stack_slot(StackSlotData::new(StackSlotKind::SpillSlot, 8));
|
||||||
4,
|
|
||||||
));
|
|
||||||
let ss1 = func.stack_slots.push(StackSlotData::new(
|
|
||||||
StackSlotKind::SpillSlot,
|
|
||||||
8,
|
|
||||||
));
|
|
||||||
assert_eq!(ss0.to_string(), "ss0");
|
assert_eq!(ss0.to_string(), "ss0");
|
||||||
assert_eq!(ss1.to_string(), "ss1");
|
assert_eq!(ss1.to_string(), "ss1");
|
||||||
|
|
||||||
|
|||||||
@@ -395,9 +395,7 @@ mod tests {
|
|||||||
f.name = FunctionName::new("foo");
|
f.name = FunctionName::new("foo");
|
||||||
assert_eq!(f.to_string(), "function %foo() native {\n}\n");
|
assert_eq!(f.to_string(), "function %foo() native {\n}\n");
|
||||||
|
|
||||||
f.stack_slots.push(
|
f.create_stack_slot(StackSlotData::new(StackSlotKind::Local, 4));
|
||||||
StackSlotData::new(StackSlotKind::Local, 4),
|
|
||||||
);
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
f.to_string(),
|
f.to_string(),
|
||||||
"function %foo() native {\n ss0 = local 4\n}\n"
|
"function %foo() native {\n ss0 = local 4\n}\n"
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
use cretonne::cursor::{Cursor, FuncCursor};
|
use cretonne::cursor::{Cursor, FuncCursor};
|
||||||
use cretonne::ir::{Ebb, Type, Value, Function, Inst, JumpTable, StackSlot, JumpTableData,
|
use cretonne::ir::{Ebb, Type, Value, Function, Inst, JumpTable, StackSlot, JumpTableData,
|
||||||
StackSlotData, DataFlowGraph, InstructionData, ExtFuncData, FuncRef, SigRef,
|
StackSlotData, DataFlowGraph, InstructionData, ExtFuncData, FuncRef, SigRef,
|
||||||
Signature, InstBuilderBase};
|
Signature, InstBuilderBase, GlobalVarData, GlobalVar, HeapData, Heap};
|
||||||
use cretonne::ir::instructions::BranchInfo;
|
use cretonne::ir::instructions::BranchInfo;
|
||||||
use cretonne::ir::function::DisplayFunction;
|
use cretonne::ir::function::DisplayFunction;
|
||||||
use cretonne::isa::TargetIsa;
|
use cretonne::isa::TargetIsa;
|
||||||
@@ -329,29 +329,39 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a jump table in the function, to be used by `br_table` instructions.
|
/// Creates a jump table in the function, to be used by `br_table` instructions.
|
||||||
pub fn create_jump_table(&mut self) -> JumpTable {
|
pub fn create_jump_table(&mut self, data: JumpTableData) -> JumpTable {
|
||||||
self.func.jump_tables.push(JumpTableData::new())
|
self.func.create_jump_table(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inserts an entry in a previously declared jump table.
|
/// Inserts an entry in a previously declared jump table.
|
||||||
pub fn insert_jump_table_entry(&mut self, jt: JumpTable, index: usize, ebb: Ebb) {
|
pub fn insert_jump_table_entry(&mut self, jt: JumpTable, index: usize, ebb: Ebb) {
|
||||||
self.func.jump_tables[jt].set_entry(index, ebb);
|
self.func.insert_jump_table_entry(jt, index, ebb)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and
|
/// Creates a stack slot in the function, to be used by `stack_load`, `stack_store` and
|
||||||
/// `stack_addr` instructions.
|
/// `stack_addr` instructions.
|
||||||
pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot {
|
pub fn create_stack_slot(&mut self, data: StackSlotData) -> StackSlot {
|
||||||
self.func.stack_slots.push(data)
|
self.func.create_stack_slot(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Adds a signature which can later be used to declare an external function import.
|
/// Adds a signature which can later be used to declare an external function import.
|
||||||
pub fn import_signature(&mut self, signature: Signature) -> SigRef {
|
pub fn import_signature(&mut self, signature: Signature) -> SigRef {
|
||||||
self.func.dfg.signatures.push(signature)
|
self.func.import_signature(signature)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Declare an external function import.
|
/// Declare an external function import.
|
||||||
pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef {
|
pub fn import_function(&mut self, data: ExtFuncData) -> FuncRef {
|
||||||
self.func.dfg.ext_funcs.push(data)
|
self.func.import_function(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declares a global variable accessible to the function.
|
||||||
|
pub fn create_global_var(&mut self, data: GlobalVarData) -> GlobalVar {
|
||||||
|
self.func.create_global_var(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Declares a heap accessible to the function.
|
||||||
|
pub fn create_heap(&mut self, data: HeapData) -> Heap {
|
||||||
|
self.func.create_heap(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an object with the [`InstBuilder`](../cretonne/ir/builder/trait.InstBuilder.html)
|
/// Returns an object with the [`InstBuilder`](../cretonne/ir/builder/trait.InstBuilder.html)
|
||||||
|
|||||||
@@ -1145,9 +1145,9 @@ mod tests {
|
|||||||
func.dfg.ins(cur).iconst(I32, 1)
|
func.dfg.ins(cur).iconst(I32, 1)
|
||||||
};
|
};
|
||||||
ssa.def_var(x_var, x1, block0);
|
ssa.def_var(x_var, x1, block0);
|
||||||
let mut jt_data = JumpTableData::new();
|
let mut data = JumpTableData::new();
|
||||||
jt_data.set_entry(0, ebb1);
|
data.push_entry(ebb1);
|
||||||
let jt = func.jump_tables.push(jt_data);
|
let jt = func.create_jump_table(data);
|
||||||
ssa.use_var(
|
ssa.use_var(
|
||||||
&mut func.dfg,
|
&mut func.dfg,
|
||||||
&mut func.layout,
|
&mut func.layout,
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ impl<'a> Context<'a> {
|
|||||||
fn add_ss(&mut self, number: u32, data: StackSlotData, loc: &Location) -> Result<()> {
|
fn add_ss(&mut self, number: u32, data: StackSlotData, loc: &Location) -> Result<()> {
|
||||||
self.map.def_ss(
|
self.map.def_ss(
|
||||||
number,
|
number,
|
||||||
self.function.stack_slots.push(data),
|
self.function.create_stack_slot(data),
|
||||||
loc,
|
loc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -137,7 +137,7 @@ impl<'a> Context<'a> {
|
|||||||
fn add_gv(&mut self, number: u32, data: GlobalVarData, loc: &Location) -> Result<()> {
|
fn add_gv(&mut self, number: u32, data: GlobalVarData, loc: &Location) -> Result<()> {
|
||||||
self.map.def_gv(
|
self.map.def_gv(
|
||||||
number,
|
number,
|
||||||
self.function.global_vars.push(data),
|
self.function.create_global_var(data),
|
||||||
loc,
|
loc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ impl<'a> Context<'a> {
|
|||||||
fn add_heap(&mut self, number: u32, data: HeapData, loc: &Location) -> Result<()> {
|
fn add_heap(&mut self, number: u32, data: HeapData, loc: &Location) -> Result<()> {
|
||||||
self.map.def_heap(
|
self.map.def_heap(
|
||||||
number,
|
number,
|
||||||
self.function.heaps.push(data),
|
self.function.create_heap(data),
|
||||||
loc,
|
loc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ impl<'a> Context<'a> {
|
|||||||
fn add_sig(&mut self, number: u32, data: Signature, loc: &Location) -> Result<()> {
|
fn add_sig(&mut self, number: u32, data: Signature, loc: &Location) -> Result<()> {
|
||||||
self.map.def_sig(
|
self.map.def_sig(
|
||||||
number,
|
number,
|
||||||
self.function.dfg.signatures.push(data),
|
self.function.import_signature(data),
|
||||||
loc,
|
loc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -188,7 +188,7 @@ impl<'a> Context<'a> {
|
|||||||
fn add_fn(&mut self, number: u32, data: ExtFuncData, loc: &Location) -> Result<()> {
|
fn add_fn(&mut self, number: u32, data: ExtFuncData, loc: &Location) -> Result<()> {
|
||||||
self.map.def_fn(
|
self.map.def_fn(
|
||||||
number,
|
number,
|
||||||
self.function.dfg.ext_funcs.push(data),
|
self.function.import_function(data),
|
||||||
loc,
|
loc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -205,7 +205,7 @@ impl<'a> Context<'a> {
|
|||||||
fn add_jt(&mut self, number: u32, data: JumpTableData, loc: &Location) -> Result<()> {
|
fn add_jt(&mut self, number: u32, data: JumpTableData, loc: &Location) -> Result<()> {
|
||||||
self.map.def_jt(
|
self.map.def_jt(
|
||||||
number,
|
number,
|
||||||
self.function.jump_tables.push(data),
|
self.function.create_jump_table(data),
|
||||||
loc,
|
loc,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -1275,7 +1275,7 @@ impl<'a> Parser<'a> {
|
|||||||
let data = match self.token() {
|
let data = match self.token() {
|
||||||
Some(Token::Identifier("function")) => {
|
Some(Token::Identifier("function")) => {
|
||||||
let (loc, name, sig) = self.parse_function_spec(ctx.unique_isa)?;
|
let (loc, name, sig) = self.parse_function_spec(ctx.unique_isa)?;
|
||||||
let sigref = ctx.function.dfg.signatures.push(sig);
|
let sigref = ctx.function.import_signature(sig);
|
||||||
ctx.map.def_entity(sigref.into(), &loc).expect(
|
ctx.map.def_entity(sigref.into(), &loc).expect(
|
||||||
"duplicate SigRef entities created",
|
"duplicate SigRef entities created",
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -21,7 +21,8 @@
|
|||||||
//!
|
//!
|
||||||
//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
|
//! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as
|
||||||
//! argument.
|
//! argument.
|
||||||
use cretonne::ir::{self, Function, Signature, Type, InstBuilder, FunctionName, Ebb, MemFlags};
|
use cretonne::ir::{self, Function, Signature, Type, InstBuilder, FunctionName, Ebb, MemFlags,
|
||||||
|
JumpTableData};
|
||||||
use cretonne::ir::types::*;
|
use cretonne::ir::types::*;
|
||||||
use cretonne::ir::immediates::{Ieee32, Ieee64};
|
use cretonne::ir::immediates::{Ieee32, Ieee64};
|
||||||
use cretonne::ir::condcodes::{IntCC, FloatCC};
|
use cretonne::ir::condcodes::{IntCC, FloatCC};
|
||||||
@@ -363,14 +364,15 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
if jump_args_count == 0 {
|
if jump_args_count == 0 {
|
||||||
// No jump arguments
|
// No jump arguments
|
||||||
let val = state.pop1();
|
let val = state.pop1();
|
||||||
let jt = builder.create_jump_table();
|
let mut data = JumpTableData::new();
|
||||||
for (index, depth) in depths.iter().enumerate() {
|
for depth in depths {
|
||||||
let i = state.control_stack.len() - 1 - (*depth as usize);
|
let i = state.control_stack.len() - 1 - (depth as usize);
|
||||||
let frame = &mut state.control_stack[i];
|
let frame = &mut state.control_stack[i];
|
||||||
let ebb = frame.br_destination();
|
let ebb = frame.br_destination();
|
||||||
builder.insert_jump_table_entry(jt, index, ebb);
|
data.push_entry(ebb);
|
||||||
frame.set_reachable();
|
frame.set_reachable();
|
||||||
}
|
}
|
||||||
|
let jt = builder.create_jump_table(data);
|
||||||
builder.ins().br_table(val, jt);
|
builder.ins().br_table(val, jt);
|
||||||
let i = state.control_stack.len() - 1 - (default as usize);
|
let i = state.control_stack.len() - 1 - (default as usize);
|
||||||
let frame = &mut state.control_stack[i];
|
let frame = &mut state.control_stack[i];
|
||||||
@@ -383,20 +385,20 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
|||||||
// We then proceed to split the edges going out of the br_table
|
// We then proceed to split the edges going out of the br_table
|
||||||
let val = state.pop1();
|
let val = state.pop1();
|
||||||
let cut_index = state.stack.len() - jump_args_count;
|
let cut_index = state.stack.len() - jump_args_count;
|
||||||
let jt = builder.create_jump_table();
|
let mut data = JumpTableData::new();
|
||||||
let dest_ebbs: HashMap<usize, Ebb> =
|
let dest_ebbs: HashMap<usize, Ebb> = depths.iter().fold(HashMap::new(), |mut acc,
|
||||||
depths.iter().enumerate().fold(HashMap::new(), |mut acc,
|
&depth| {
|
||||||
(index, &depth)| {
|
|
||||||
if acc.get(&(depth as usize)).is_none() {
|
if acc.get(&(depth as usize)).is_none() {
|
||||||
let branch_ebb = builder.create_ebb();
|
let branch_ebb = builder.create_ebb();
|
||||||
builder.insert_jump_table_entry(jt, index, branch_ebb);
|
data.push_entry(branch_ebb);
|
||||||
acc.insert(depth as usize, branch_ebb);
|
acc.insert(depth as usize, branch_ebb);
|
||||||
return acc;
|
return acc;
|
||||||
};
|
};
|
||||||
let branch_ebb = acc[&(depth as usize)];
|
let branch_ebb = acc[&(depth as usize)];
|
||||||
builder.insert_jump_table_entry(jt, index, branch_ebb);
|
data.push_entry(branch_ebb);
|
||||||
acc
|
acc
|
||||||
});
|
});
|
||||||
|
let jt = builder.create_jump_table(data);
|
||||||
builder.ins().br_table(val, jt);
|
builder.ins().br_table(val, jt);
|
||||||
let default_ebb = state.control_stack[state.control_stack.len() - 1 -
|
let default_ebb = state.control_stack[state.control_stack.len() - 1 -
|
||||||
(default as usize)]
|
(default as usize)]
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ impl FuncEnvironment for DummyRuntime {
|
|||||||
fn make_global(&self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
|
fn make_global(&self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue {
|
||||||
// Just create a dummy `vmctx` global.
|
// Just create a dummy `vmctx` global.
|
||||||
let offset = ((index * 8) as i32 + 8).into();
|
let offset = ((index * 8) as i32 + 8).into();
|
||||||
let gv = func.global_vars.push(ir::GlobalVarData::VmCtx { offset });
|
let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset });
|
||||||
GlobalValue::Memory {
|
GlobalValue::Memory {
|
||||||
gv,
|
gv,
|
||||||
ty: self.globals[index].ty,
|
ty: self.globals[index].ty,
|
||||||
@@ -48,7 +48,7 @@ impl FuncEnvironment for DummyRuntime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn make_heap(&self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
|
fn make_heap(&self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap {
|
||||||
func.heaps.push(ir::HeapData {
|
func.create_heap(ir::HeapData {
|
||||||
base: ir::HeapBase::ReservedReg,
|
base: ir::HeapBase::ReservedReg,
|
||||||
min_size: 0.into(),
|
min_size: 0.into(),
|
||||||
guard_size: 0x8000_0000.into(),
|
guard_size: 0x8000_0000.into(),
|
||||||
@@ -59,21 +59,21 @@ impl FuncEnvironment for DummyRuntime {
|
|||||||
fn make_indirect_sig(&self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
|
fn make_indirect_sig(&self, func: &mut ir::Function, index: SignatureIndex) -> ir::SigRef {
|
||||||
// A real implementation would probably change the calling convention and add `vmctx` and
|
// A real implementation would probably change the calling convention and add `vmctx` and
|
||||||
// signature index arguments.
|
// signature index arguments.
|
||||||
func.dfg.signatures.push(self.signatures[index].clone())
|
func.import_signature(self.signatures[index].clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_direct_func(&self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef {
|
fn make_direct_func(&self, func: &mut ir::Function, index: FunctionIndex) -> ir::FuncRef {
|
||||||
let sigidx = self.func_types[index];
|
let sigidx = self.func_types[index];
|
||||||
// A real implementation would probably add a `vmctx` argument.
|
// A real implementation would probably add a `vmctx` argument.
|
||||||
// And maybe attempt some signature de-duplication.
|
// And maybe attempt some signature de-duplication.
|
||||||
let signature = func.dfg.signatures.push(self.signatures[sigidx].clone());
|
let signature = func.import_signature(self.signatures[sigidx].clone());
|
||||||
|
|
||||||
let name = match self.imported_funcs.get(index) {
|
let name = match self.imported_funcs.get(index) {
|
||||||
Some(name) => name.clone(),
|
Some(name) => name.clone(),
|
||||||
None => ir::FunctionName::new(format!("localfunc{}", index)),
|
None => ir::FunctionName::new(format!("localfunc{}", index)),
|
||||||
};
|
};
|
||||||
|
|
||||||
func.dfg.ext_funcs.push(ir::ExtFuncData { name, signature })
|
func.import_function(ir::ExtFuncData { name, signature })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn translate_call_indirect(
|
fn translate_call_indirect(
|
||||||
|
|||||||
Reference in New Issue
Block a user