///|
pub(all) struct Block {
id : Int
params : Array[VReg]
instructions : Array[Instruction]
successors : Array[Int]
mut terminator : Terminator?
} derive(Debug)
///|
pub fn Block::new(id : Int) -> Block {
{ id, params: [], instructions: [], successors: [], terminator: None }
}
///|
pub fn Block::append(self : Block, inst : Instruction) -> Unit {
self.instructions.push(inst)
}
///|
pub fn Block::add_successor(self : Block, block_id : Int) -> Unit {
self.successors.push(block_id)
}
///|
pub fn Block::add_param(self : Block, param : VReg) -> Unit {
self.params.push(param)
}
///|
fn terminator_successors(term : Terminator) -> Array[Int] {
match term {
TermJump(target, _) => [target]
TermBranch(_, true_target, _, false_target, _)
| TermBranchCmp(_, _, _, _, true_target, _, false_target, _)
| TermBranchZero(_, _, _, true_target, _, false_target, _)
| TermBranchCmpImm(_, _, _, _, true_target, _, false_target, _) =>
[true_target, false_target]
TermBrTable(_, targets, default_target) => {
let out : Array[Int] = []
for target in targets {
out.push(target)
}
out.push(default_target)
out
}
TermReturn(_) | TermTrap(_) => []
}
}
///|
pub fn Block::set_terminator(self : Block, term : Terminator) -> Unit {
self.terminator = Some(term)
self.successors.clear()
for target in terminator_successors(term) {
self.successors.push(target)
}
}
///|
pub(all) struct AbstractFunction {
name : String
params : Array[VReg]
results : Array[RegClass]
blocks : Array[Block]
stack_slots : Array[StackSlot]
mut num_spill_slots : Int
param_pregs : Array[PReg?]
param_locations : Array[AbiValueLocation]
result_locations : Array[AbiValueLocation]
mut return_area : AbiReturnArea?
mut int_stack_params : Int
mut max_outgoing_args_size : Int
mut next_block_id : Int
mut next_inst_id : Int
mut next_vreg_id : Int
mut next_stack_slot_id : Int
} derive(Debug)
///|
pub fn AbstractFunction::new(name : String) -> AbstractFunction {
{
name,
params: [],
results: [],
blocks: [],
stack_slots: [],
num_spill_slots: 0,
param_pregs: [],
param_locations: [],
result_locations: [],
return_area: None,
int_stack_params: 0,
max_outgoing_args_size: 0,
next_block_id: 0,
next_inst_id: 0,
next_vreg_id: 0,
next_stack_slot_id: 0,
}
}
///|
pub fn AbstractFunction::new_block(self : AbstractFunction) -> Block {
let block = Block::new(self.next_block_id)
self.next_block_id = self.next_block_id + 1
self.blocks.push(block)
block
}
///|
pub fn AbstractFunction::new_vreg(
self : AbstractFunction,
class : RegClass,
) -> VReg {
let reg = { id: self.next_vreg_id, class }
self.next_vreg_id = self.next_vreg_id + 1
reg
}
///|
pub fn AbstractFunction::add_param(
self : AbstractFunction,
class : RegClass,
) -> VReg {
let vreg = self.new_vreg(class)
self.params.push(vreg)
vreg
}
///|
pub fn AbstractFunction::push_param(
self : AbstractFunction,
vreg : VReg,
) -> Unit {
self.params.push(vreg)
}
///|
pub fn AbstractFunction::add_result(
self : AbstractFunction,
class : RegClass,
) -> Unit {
self.results.push(class)
}
///|
pub fn AbstractFunction::new_inst(
self : AbstractFunction,
opcode : Opcode,
) -> Instruction {
let inst = Instruction::new(self.next_inst_id, opcode)
self.next_inst_id = self.next_inst_id + 1
inst
}
///|
pub fn AbstractFunction::new_stack_slot(
self : AbstractFunction,
size : Int,
align : Int,
) -> StackSlot {
let slot = { id: self.next_stack_slot_id, size, align }
self.next_stack_slot_id = self.next_stack_slot_id + 1
self.stack_slots.push(slot)
slot
}
///|
pub fn AbstractFunction::set_num_spill_slots(
self : AbstractFunction,
n : Int,
) -> Unit {
self.num_spill_slots = n
}
///|
pub fn AbstractFunction::add_param_preg(
self : AbstractFunction,
preg : PReg?,
) -> Unit {
self.param_pregs.push(preg)
}
///|
pub fn AbstractFunction::add_param_location(
self : AbstractFunction,
location : AbiValueLocation,
) -> Unit {
self.param_locations.push(location)
}
///|
pub fn AbstractFunction::add_result_location(
self : AbstractFunction,
location : AbiValueLocation,
) -> Unit {
self.result_locations.push(location)
}
///|
pub fn AbstractFunction::set_return_area(
self : AbstractFunction,
area : AbiReturnArea,
) -> Unit {
self.return_area = Some(area)
}
///|
pub fn AbstractFunction::set_int_stack_params(
self : AbstractFunction,
n : Int,
) -> Unit {
self.int_stack_params = n
}
///|
pub fn AbstractFunction::update_max_outgoing_args_size(
self : AbstractFunction,
size : Int,
) -> Unit {
if size > self.max_outgoing_args_size {
self.max_outgoing_args_size = size
}
}
///|
pub fn AbstractFunction::get_max_outgoing_args_size(
self : AbstractFunction,
) -> Int {
self.max_outgoing_args_size
}
///|
pub fn AbstractFunction::get_num_spill_slots(self : AbstractFunction) -> Int {
self.num_spill_slots
}