TPDE
Loading...
Searching...
No Matches
tpde::CompilerBase< Adaptor, Derived, Config >::ScratchReg Struct Reference

Owned unspillable and unevictable temporary register with RAII semantics. More...

#include <ScratchReg.hpp>

Public Member Functions

 ScratchReg (CompilerBase *compiler)
 Constructor, no register.
 
bool has_reg () const noexcept
 Whether a register is currently allocated.
 
AsmReg cur_reg () const noexcept
 The allocated register.
 
AsmReg alloc_specific (AsmReg reg) noexcept
 Allocate a specific register.
 
AsmReg alloc_gp () noexcept
 Allocate a general-purpose register.
 
AsmReg alloc (RegBank bank) noexcept
 Allocate register in the specified bank.
 
AsmReg release () noexcept
 Release register, marking it as unused; returns the register.
 
void reset () noexcept
 Deallocate register.
 
 CompilerBase (Adaptor *adaptor)
 Initialize a CompilerBase, should be called by the derived classes.
 
Derived * derived ()
 shortcut for casting to the Derived class so that overloading works
 
bool compile ()
 Compile the functions returned by Adaptor::funcs.
 
void reset ()
 Reset any leftover data from the previous compilation such that it will not affect the next compilation.
 
CCAssigner * cur_cc_assigner () noexcept
 Get CCAssigner for current function.
 
void release_assignment (ValLocalIdx local_idx, ValueAssignment *) noexcept
 Release an assignment when reference count drops to zero, either frees the assignment immediately or delays free to the end of the live range.
 
void init_variable_ref (ValLocalIdx local_idx, u32 var_ref_data) noexcept
 Init a variable-ref assignment.
 
void init_variable_ref (IRValueRef value, u32 var_ref_data) noexcept
 Init a variable-ref assignment.
 
void prologue_assign_arg (CCAssigner *cc_assigner, u32 arg_idx, IRValueRef arg, u32 align=1, bool allow_split=false) noexcept
 Assign function argument in prologue.
 
AsmReg gval_as_reg (GenericValuePart &gv) noexcept
 Get generic value part into a single register, evaluating expressions and materializing immediates as required.
 
AsmReg gval_as_reg_reuse (GenericValuePart &gv, ScratchReg &dst) noexcept
 Like gval_as_reg; if the GenericValuePart owns a reusable register (either a ScratchReg, possibly due to materialization, or a reusable ValuePartRef), store it in dst.
 
void label_place (Label label) noexcept
 Convenience function to place a label at the current position.
 
Stack Slots
i32 allocate_stack_slot (u32 size) noexcept
 Allocate a static stack slot.
 
void free_stack_slot (u32 slot, u32 size) noexcept
 Free a static stack slot.
 
Value References
ValueRef val_ref (IRValueRef value) noexcept
 Get a using reference to a value.
 
std::pair< ValueRef, ValuePartRef > val_ref_single (IRValueRef value) noexcept
 Get a using reference to a single-part value and provide direct access to the only part.
 
ValueRef result_ref (IRValueRef value) noexcept
 Get a defining reference to a value.
 
std::pair< ValueRef, ValuePartRef > result_ref_single (IRValueRef value) noexcept
 Get a defining reference to a single-part value and provide direct access to the only part.
 
ValueRef result_ref_alias (IRValueRef dst, ValueRef &&src) noexcept
 Make dst an alias for src, which must be a non-constant value with an identical part configuration.
 
ValueRef result_ref_stack_slot (IRValueRef value, AssignmentPartRef base, i32 off) noexcept
 Initialize value as a pointer into a stack variable (i.e., a value allocated from cur_static_allocas() or similar) with an offset.
 
Low-Level Assignment Register Handling
Reg select_reg (RegBank bank, u64 exclusion_mask) noexcept
 Select an available register, evicting loaded values if needed.
 
void reload_to_reg (AsmReg dst, AssignmentPartRef ap) noexcept
 Reload a value part from memory or recompute variable address.
 
void allocate_spill_slot (AssignmentPartRef ap) noexcept
 Allocate a stack slot for an assignment.
 
void spill (AssignmentPartRef ap) noexcept
 Ensure the value is spilled in its stack slot (except variable refs).
 
void evict (AssignmentPartRef ap) noexcept
 Evict the value from its register, spilling if needed, and free register.
 
void evict_reg (Reg reg) noexcept
 Evict the value from the register, spilling if needed, and free register.
 
void free_reg (Reg reg) noexcept
 Free the register. Requires that the contained value is already spilled.
 
High-Level Branch Generation
void generate_uncond_branch (IRBlockRef target) noexcept
 Generate an unconditional branch at the end of a basic block.
 
void generate_cond_branch (Jump jmp, IRBlockRef true_target, IRBlockRef false_target) noexcept
 Generate an conditional branch at the end of a basic block.
 
void generate_switch (ScratchReg &&cond, u32 width, IRBlockRef default_block, std::span< const std::pair< u64, IRBlockRef > > cases) noexcept
 Generate a switch at the end of a basic block.
 
Low-Level Branch Primitives

The general flow of using these low-level primitive is:

  1. spill_before_branch()
  2. begin_branch_region()
  3. One or more calls to generate_branch_to_block()
  4. end_branch_region()
  5. release_spilled_regs()
RegisterFile::RegBitSet spill_before_branch (bool force_spill=false) noexcept
 Spill values that need to be spilled for later blocks.
 
void release_spilled_regs (typename RegisterFile::RegBitSet) noexcept
 Free registers marked by spill_before_branch().
 
void release_regs_after_return () noexcept
 When reaching a point in the function where no other blocks will be reached anymore, use this function to release register assignments after the end of that block so the compiler does not accidentally use registers which don't contain any values.
 
void begin_branch_region () noexcept
 Indicate beginning of region where value-state must not change.
 
void end_branch_region () noexcept
 Indicate end of region where value-state must not change.
 
void generate_branch_to_block (Jump jmp, IRBlockRef target, bool needs_split, bool last_inst) noexcept
 Generate a branch to a basic block; execution continues afterwards.
 
bool branch_needs_split (IRBlockRef target) noexcept
 Whether branch to a block requires additional instructions and therefore a direct jump to the block is not possible.
 

Public Attributes

u32 frame_size
 The current size of the stack frame.
 
bool has_dynamic_alloca
 Whether the stack frame might have dynamic alloca.
 
bool is_leaf_function
 Whether the function is guaranteed to be a leaf function.
 
bool generated_call
 Whether the function actually includes a call.
 
bool frame_used
 Whether the stack frame is used.
 
util::SmallVector< i32, 16 > fixed_free_lists [5]
 Free-Lists for 1/2/4/8/16 sized allocations.
 
std::unordered_map< u32, std::vector< i32 > > dynamic_free_lists
 Free-Lists for all other sizes.
 
bool generating_branch
 Whether we are currently in the middle of generating branch-related code and therefore must not change any value-related state.
 

Detailed Description

template<IRAdaptor Adaptor, typename Derived, CompilerConfig Config = CompilerConfigDefault>
struct tpde::CompilerBase< Adaptor, Derived, Config >::ScratchReg

Owned unspillable and unevictable temporary register with RAII semantics.

Definition at line 10 of file ScratchReg.hpp.

Member Function Documentation

◆ alloc()

template<IRAdaptor Adaptor, typename Derived, CompilerConfig Config>
CompilerBase< Adaptor, Derived, Config >::AsmReg tpde::CompilerBase< Adaptor, Derived, Config >::ScratchReg::alloc ( RegBank bank)
noexcept

Allocate register in the specified bank.

Does nothing if it holds a register in the specified bank. Evicts a register if required.

Definition at line 106 of file ScratchReg.hpp.

◆ compile()

bool tpde::CompilerBase< Adaptor, Derived, Config >::compile ( )

Compile the functions returned by Adaptor::funcs.

Warning
If you intend to call this multiple times, you must call reset in-between the calls.
Returns
Whether the compilation was successful

Definition at line 335 of file CompilerBase.hpp.

◆ generate_branch_to_block()

void tpde::CompilerBase< Adaptor, Derived, Config >::generate_branch_to_block ( Jump jmp,
IRBlockRef target,
bool needs_split,
bool last_inst )
noexcept

Generate a branch to a basic block; execution continues afterwards.

Multiple calls to this function can be used to build conditional branches.

Template Parameters
JumpTarget-defined Jump type (e.g., CompilerX64::Jump).
Parameters
needs_splitResult of branch_needs_split(); pass false for an unconditional branch.
last_instWhether fall-through to target is possible.

Definition at line 544 of file CompilerBase.hpp.

◆ generate_switch()

void tpde::CompilerBase< Adaptor, Derived, Config >::generate_switch ( ScratchReg && cond,
u32 width,
IRBlockRef default_block,
std::span< const std::pair< u64, IRBlockRef > > cases )
noexcept

Generate a switch at the end of a basic block.

Only the lowest bits of the condition are considered. The condition must be a general-purpose register. The cases must be sorted and every case value must appear at most once.

Definition at line 489 of file CompilerBase.hpp.

◆ generate_uncond_branch()

void tpde::CompilerBase< Adaptor, Derived, Config >::generate_uncond_branch ( IRBlockRef target)
noexcept

Generate an unconditional branch at the end of a basic block.

No further instructions must follow. If target is the next block in the block order, the branch is omitted.

Definition at line 477 of file CompilerBase.hpp.

◆ prologue_assign_arg()

void tpde::CompilerBase< Adaptor, Derived, Config >::prologue_assign_arg ( CCAssigner * cc_assigner,
u32 arg_idx,
IRValueRef arg,
u32 align = 1,
bool allow_split = false )
noexcept

Assign function argument in prologue.

align can be used to increase the minimal stack alignment of the first part of the argument. If allow_split is set, the argument can be passed partially in registers, otherwise (default) it must be either passed completely in registers or completely on the stack.

Definition at line 377 of file CompilerBase.hpp.

◆ result_ref_alias()

CompilerBase< Adaptor, Derived, Config >::ValueRef tpde::CompilerBase< Adaptor, Derived, Config >::result_ref_alias ( IRValueRef dst,
ValueRef && src )
noexcept

Make dst an alias for src, which must be a non-constant value with an identical part configuration.

src must be in its last use (is_owned()), and the assignment will be repurposed for dst, keeping all assigned registers and stack slots.

Definition at line 407 of file CompilerBase.hpp.

◆ result_ref_single()

std::pair< typename CompilerBase< Adaptor, Derived, Config >::ValueRef, typename CompilerBase< Adaptor, Derived, Config >::ValuePartRef > tpde::CompilerBase< Adaptor, Derived, Config >::result_ref_single ( IRValueRef value)
noexcept

Get a defining reference to a single-part value and provide direct access to the only part.

Similar to val_ref_single().

Definition at line 401 of file CompilerBase.hpp.

◆ result_ref_stack_slot()

CompilerBase< Adaptor, Derived, Config >::ValueRef tpde::CompilerBase< Adaptor, Derived, Config >::result_ref_stack_slot ( IRValueRef value,
AssignmentPartRef base,
i32 off )
noexcept

Initialize value as a pointer into a stack variable (i.e., a value allocated from cur_static_allocas() or similar) with an offset.

The result value will be a stack variable itself.

Definition at line 412 of file CompilerBase.hpp.

◆ spill_before_branch()

CompilerBase< Adaptor, Derived, Config >::RegisterFile::RegBitSet tpde::CompilerBase< Adaptor, Derived, Config >::spill_before_branch ( bool force_spill = false)
noexcept

Spill values that need to be spilled for later blocks.

Returns the set of registers that will be free'd at the end of the block; pass this to release_spilled_regs().

Definition at line 511 of file CompilerBase.hpp.

◆ val_ref_single()

std::pair< typename CompilerBase< Adaptor, Derived, Config >::ValueRef, typename CompilerBase< Adaptor, Derived, Config >::ValuePartRef > tpde::CompilerBase< Adaptor, Derived, Config >::val_ref_single ( IRValueRef value)
noexcept

Get a using reference to a single-part value and provide direct access to the only part.

This is a convenience function; note that the ValueRef must outlive the ValuePartRef (i.e. auto p = val_ref().part(0); won't work, as the value will possibly be deallocated when the ValueRef is destroyed).

Definition at line 393 of file CompilerBase.hpp.

Member Data Documentation

◆ frame_used

bool tpde::CompilerBase< Adaptor, Derived, Config >::frame_used

Whether the stack frame is used.

If the stack frame is never used, the frame setup can in some cases be omitted entirely.

Definition at line 144 of file CompilerBase.hpp.

◆ generated_call

bool tpde::CompilerBase< Adaptor, Derived, Config >::generated_call

Whether the function actually includes a call.

There are cases, where it is not clear from the beginning whether a function has function calls. If a function has no calls, this will allow using the red zone guaranteed by some ABIs.

Definition at line 141 of file CompilerBase.hpp.

◆ has_dynamic_alloca

bool tpde::CompilerBase< Adaptor, Derived, Config >::has_dynamic_alloca

Whether the stack frame might have dynamic alloca.

Dynamic allocas may require a different and less efficient frame setup.

Definition at line 133 of file CompilerBase.hpp.

◆ is_leaf_function

bool tpde::CompilerBase< Adaptor, Derived, Config >::is_leaf_function

Whether the function is guaranteed to be a leaf function.

Throughout the entire function, the compiler may assume the absence of function calls.

Definition at line 136 of file CompilerBase.hpp.


The documentation for this struct was generated from the following files: