/* * libbinrec: a recompiling translator for machine code * Copyright (c) 2016 Andrew Church * * This software may be copied and redistributed under certain conditions; * see the file "COPYING" in the source code distribution for details. * NO WARRANTY is provided with this software. */ #ifndef SRC_RTL_INTERNAL_H #define SRC_RTL_INTERNAL_H #ifndef SRC_RTL_H #include "src/rtl.h" #endif /*************************************************************************/ /************************* Configuration options *************************/ /*************************************************************************/ /** * INSNS_EXPAND_SIZE: Specifies the number of instructions by which to * expand a block's instruction array when the array is full. This value * is also used for the initial size of the array. */ #define INSNS_EXPAND_SIZE 1000 /** * BLOCKS_EXPAND_SIZE: Specifies the number of blocks by which to expand a * block's basic block array when the array is full. This value is also * used for the initial size of the array. */ #define BLOCKS_EXPAND_SIZE 100 /** * REGS_EXPAND_SIZE: Specifies the number of register entries by which to * expand a block's register array when the array is full. This value is * also used for the initial size of the array. */ #define REGS_EXPAND_SIZE 1000 /** * REGS_LIMIT: Specifies the maximum number of registers allowed for a * single block. Must be no greater than 65535 (because this value must * fit into a uint16_t). The actual number of available registers is one * less than this value, since register 0 is never used. */ #define REGS_LIMIT 65535 /** * ALIASES_EXPAND_SIZE: Specifies the number of entries by which to expand * a block's alias register array when the array is full. This value is * also used for the initial size of the array. */ #define ALIASES_EXPAND_SIZE 100 /** * ALIASES_LIMIT: Specifies the maximum number of alias registers allowed * for a single block. Must be no greater than 65535 (because this value * must fit into a uint16_t). The actual number of available alias * registers is one less than this value, since register 0 is never used. */ #define ALIASES_LIMIT 65535 /** * LABELS_EXPAND_SIZE: Specifies the number of entries by which to expand * a block's label-to-block mapping array when the array is full. This * value is also used for the initial size of the array. */ #define LABELS_EXPAND_SIZE 100 /** * LABELS_LIMIT: Specifies the maximum number of labels allowed for a * single block. Must be no greater than 65535 (because this value must * fit into a uint16_t). The actual number of available labels is one less * than this value, since label 0 is never used. */ #define LABELS_LIMIT 65535 /** * NATIVE_EXPAND_SIZE: Specifies the block size (in bytes) by which to * expand the native code buffer as necessary when translating. */ #define NATIVE_EXPAND_SIZE 8192 /** * RTL_DEBUG_OPTIMIZE: If defined, optimization functions will output * debugging information via log_info(). Normally defined (if desired) * by the Makefile. */ // #define RTL_DEBUG_OPTIMIZE /*************************************************************************/ /*************************** Type declarations ***************************/ /*************************************************************************/ /** * RTLInsn: A single platform-neutral (more or less) operation. Guest * instructions are translated into sequences of RTLInsns, which are then * optimized and retranslated into host instructions. */ typedef struct RTLInsn { uint16_t opcode; // Operation code (RTLOpcode) uint16_t dest; // Destination register uint16_t src1, src2; // Source registers union { struct { union { uint16_t src3; // Third source register struct { uint8_t start; // First (lowest) bit number for a bitfield uint8_t count; // Number of bits for a bitfield } bitfield; uint8_t fcmp; // Floating-point comparison type int16_t offset; // Byte offset for load/store instructions uint16_t alias; // Alias index for SET/GET_ALIAS uint8_t arg_index; // Argument index for LOAD_ARG uint8_t elem; // Vector element uint16_t label; // GOTO target label }; uint16_t host_data_16; // For use by host translators uint32_t host_data_32; // For use by host translators }; uint64_t src_imm; // Source immediate value }; } RTLInsn; STATIC_ASSERT(sizeof(RTLInsn) == 16, "RTLInsn should be 16 bytes long for best performance"); /*----------------------------------*/ /** * RTLRegType: The type (source information) of a register used in an RTL * unit. */ typedef enum RTLRegType_ { RTLREG_UNDEFINED = 0, // Not yet defined to anything RTLREG_CONSTANT, // Constant value RTLREG_CONSTANT_NOFOLD, // Constant value (folding disallowed) RTLREG_FUNC_ARG, // Function argument RTLREG_MEMORY, // Memory reference RTLREG_ALIAS, // Loaded from an alias register RTLREG_RESULT, // Result of an operation on other registers RTLREG_RESULT_NOFOLD, // Result of operation (not constant foldable) } RTLRegType; /** * RTLRegister: Data about a virtual register used in an RTL unit. */ typedef struct RTLRegister RTLRegister; struct RTLRegister { /* Basic register information. */ uint8_t type; // Register data type (RTLDataType) uint8_t source; // Register source (RTLRegType) /* Unique pointer information. The "unique_pointer" field has the * property that all registers with the same nonzero value for * "unique_pointer" are native addresses which point to the same region * of memory, and that region of memory will only be accessed through * a register with the same "unique_pointer" value. The field is set * initially by a call to rtl_make_unique_pointer(), and that value is * carried forward to other registers via data flow analysis. */ uint16_t unique_pointer; /* True if this register should never be spilled. */ bool unspillable; /* Liveness information. */ bool live; // True if this register has been referenced // (never cleared once set, except if the // register is killed during optimization) int32_t birth; // First RTL insn index when register is live // (= insn where it's assigned, because SSA) int32_t death; // Last RTL insn index when register is live /* Register value information. */ union { union { // Value of register for RTLREG_CONSTANT uint64_t i64; float f32; double f64; } value; uint8_t arg_index; // Function argument index for RTLREG_FUNC_ARG struct { uint16_t base; // Register holding address for RTLREG_MEMORY int16_t offset; // Access offset bool byterev; // True if a byte-reversed access uint8_t size; // Access size in bytes (1 or 2) if this is a // narrow integer load, else 0 bool is_signed; // True if a signed narrow integer load } memory; struct { uint16_t src; // Source alias register } alias; struct { uint16_t opcode : 15, // Operation code for RTLREG_RESULT{,_NOFOLD} is_imm : 1; // True if the second operand is src_imm uint16_t src1; // Operand 1 union { int32_t src_imm; // Immediate operand struct { uint16_t src2; // Operand 2 union { uint16_t src3; // Operand 3 struct { uint8_t start; // Start bit for bitfields uint8_t count; // Bit count for bitfields }; uint8_t elem; // Vector element uint8_t fcmp; // Floating-point comparison type }; }; }; } result; }; }; /*----------------------------------*/ /** * RTLAlias: Data about an alias register */ typedef struct RTLAlias_ { RTLDataType type; // Data type (RTLTYPE_*) uint16_t base; // Base register for loads and stores, or zero to // allocate transient storage for the alias int16_t offset; // Access offset for loads/stores (ignored if base==0) } RTLAlias; /*----------------------------------*/ /** * RTLBlock: Information about an basic block of code (a sequence of * instructions with one entry point and one exit point). Note that a block * can be empty, denoted by last_insn < first_insn, and that last_insn can * be negative, if first_insn is 0 and the block is empty. */ typedef struct RTLBlock { /* unit->insns[] index of the first instruction in the block. */ int32_t first_insn; /* unit->insns[] index of the last instruction in the block. * last_insn < first_insn indicates an empty block. */ int32_t last_insn; /* If there are any entering control flow edges from blocks located * after this block in the code stream, this field gives the * unit->insns[] index of the last instruction in the latest of those * blocks, which is the minimum instruction through which any register * live on entry to this block must be live. Otherwise, this field is * set to zero. */ int32_t min_death; /* Highest register index which is live during this block. */ uint16_t max_live_reg; /* unit->blocks[] index of the next block in the code stream (excluding * dropped blocks); -1 indicates the end of the code stream. */ int16_t next_block; /* unit->blocks[] index of the previous block in the code stream, or * -1 if this is the first block. */ int16_t prev_block; /* unit->blocks[] indices of predecessor blocks in the control flow * graph; -1 indicates an unused slot. Holes in the list are not * permitted. entries[0] is always the fall-through edge from the * previous block, if that edge exists. (rtl_block_*() functions take * care of all these details.) */ int16_t entries[7]; /* unit->blocks[] index of an extension block used to hold additional * entry edges that don't fit in entries[], or -1 if none. */ int16_t entry_overflow; /* unit->blocks[] indices of successor blocks. Note that a terminating * insstruction can go at most two places (conditional GOTO: branch * target and fall-through path). exits[0] is always the fall-through * edge if that edge exists. */ int16_t exits[2]; } RTLBlock; /*----------------------------------*/ /** * RTLUnit: State information used in translating a unit of code. The * RTLUnit type itself is defined in rtl.h. */ struct RTLUnit { binrec_t *handle; // Translation handle RTLInsn *insns; // Instruction array uint32_t insns_size; // Size of instruction array (entries) uint32_t num_insns; // Number of instructions actually in array RTLBlock *blocks; // Basic block array uint16_t blocks_size; // Size of block array (entries) uint16_t num_blocks; // Number of blocks actually in array bool have_block; // True if there is a currently active block uint16_t cur_block; // Current block index if have_block != 0 int16_t last_block; // Most recently added block (excluding dummy // blocks used for entry list extension), // or -1 if none int16_t *label_blockmap; // Label-to-block-index mapping (-1 = unset) uint16_t labels_size; // Size of label-to-block map array (entries) uint16_t next_label; // Next label number to allocate // (== number of allocated labels) RTLRegister *regs; // Register array uint16_t regs_size; // Size of register array (entries) uint16_t next_reg; // Next register number to allocate // (== number of allocated registers) uint16_t first_live_reg; // First register in live range list uint16_t last_live_reg; // Last register in live range list uint16_t membase_reg; // Register containing guest memory base // (for readonly-load optimizations) RTLAlias *aliases; // Alias register array uint16_t aliases_size; // Size of alias register array (entries) uint16_t next_alias; // Next alias register number to allocate // (== number of allocated alias registers) bool error; // True if an error has been detected bool finalized; // True if unit has been finalized char *disassembly; // Last disassembly result, or NULL if none // (saved so we can free it at destroy time) /* The following fields are used only by optimization routines: */ bool *block_seen; // Array of "seen" flags for all blocks // (used by rtlopt_drop_dead_blocks()) int block_seen_size; // Allocated size of block_seen array }; /*************************************************************************/ /**************** Library-internal function declarations *****************/ /*************************************************************************/ /*----------------------- Basic block processing ------------------------*/ /**** Basic block processing function declarations ****/ /** * rtl_block_add: Add a new, empty basic block to the given unit at the * end of the unit->blocks[] array. * * [Parameters] * unit: RTL unit. * [Return value] * True on success, false on error. */ #define rtl_block_add INTERNAL(rtl_block_add) extern bool rtl_block_add(RTLUnit *unit); /** * rtl_block_add_edge: Add a new control flow edge between two basic blocks. * * [Parameters] * unit: RTL unit. * from_index: Index of dominating basic block (in unit->blocks[]). * to_index: Index of dominated basic block (in unit->blocks[]). * [Return value] * True on success, false on error. */ #define rtl_block_add_edge INTERNAL(rtl_block_add_edge) extern bool rtl_block_add_edge(RTLUnit *unit, int from_index, int to_index); /** * rtl_block_remove_edge: Remove a control flow edge between two basic blocks. * * [Parameters] * unit: RTL unit. * from_index: Index of dominating basic block (in unit->blocks[]). * exit_index: Index of edge to remove in the dominating basic block's * exit list (blocks[from_index].exits[]). */ #define rtl_block_remove_edge INTERNAL(rtl_block_remove_edge) extern void rtl_block_remove_edge(RTLUnit *unit, int from_index, int exit_index); /*------------------------ Instruction encoding -------------------------*/ /* Internal table used by rtl_insn_make(). */ #define makefunc_table INTERNAL(makefunc_table) extern bool (* const makefunc_table[])(RTLUnit *, RTLInsn *, int, int, int, uint64_t); /** * rtl_insn_make: Fill in an RTLInsn structure based on the opcode stored * in the structure and the parameters passed to the function. * * [Parameters] * unit: RTLUnit containing instruction. * insn: RTLInsn structure to fill in (insn->opcode must be set by caller). * dest: Destination register for instruction. * src1: First source register for instruction. * src2: Second source register for instruction. * other: Extra register or immediate value for instruction. * [Return value] * True on success, false on error. */ static inline bool rtl_insn_make(RTLUnit *unit, RTLInsn *insn, int dest, int src1, int src2, uint64_t other) { ASSERT(unit != NULL); ASSERT(unit->insns != NULL); ASSERT(unit->blocks != NULL); ASSERT(unit->regs != NULL); ASSERT(unit->label_blockmap != NULL); ASSERT(insn->opcode >= RTLOP__FIRST && insn->opcode <= RTLOP__LAST); ASSERT(makefunc_table[insn->opcode]); return (*makefunc_table[insn->opcode])(unit, insn, dest, src1, src2, other); } /** * rtl_add_insn_copy: Add a copy of the given RTLInsn to the unit. * No operand checks are performed on the added instruction, and if a * destination operand is present, its register information is not * modified; however, register live ranges are updated appropriately. * * [Parameters] * unit: RTLUnit to append to. * insn: Instruction to append. * [Return value] * True on success, false if out of memory. */ extern bool rtl_add_insn_copy(RTLUnit *unit, const RTLInsn *insn); /** * rtl_opcode_has_src3: Return whether the given opcode takes a third * source register in the RTLInsn.src3 field. */ static inline CONST_FUNCTION bool rtl_opcode_has_src3(RTLOpcode opcode) { return opcode == RTLOP_SELECT || opcode == RTLOP_FMADD || opcode == RTLOP_FMSUB || opcode == RTLOP_FNMADD || opcode == RTLOP_FNMSUB || opcode == RTLOP_CMPXCHG || opcode == RTLOP_CALL || opcode == RTLOP_CALL_TRANSPARENT; } /** * rtl_opcode_has_alias: Return whether the given opcode takes an alias * index in the RTLInsn.alias field. */ static inline CONST_FUNCTION bool rtl_opcode_has_alias(RTLOpcode opcode) { return opcode == RTLOP_GET_ALIAS || opcode == RTLOP_SET_ALIAS; } /*-------------------------- Memory management --------------------------*/ /* * These functions wrap the similarly-named binrec_* memory management * functions declared in common.h; these allow us to pass an RTLUnit * directly without having to explicitly dereference it to get the * binrec handle. */ static inline void *rtl_malloc(const RTLUnit *unit, size_t size) { ASSERT(unit); return binrec_malloc(unit->handle, size); } static inline void *rtl_realloc(const RTLUnit *unit, void *ptr, size_t size) { ASSERT(unit); return binrec_realloc(unit->handle, ptr, size); } static inline void rtl_free(const RTLUnit *unit, void *ptr) { ASSERT(unit); binrec_free(unit->handle, ptr); } /*---------------------------- Optimization -----------------------------*/ /** * rtl_opt_prev_reg_use: Return the latest use of the given register prior * to the given instruction. If the register is not referenced by any * instructions between its birth and the given instruction, the index of * its birth instruction is returned. * * [Parameters] * unit: RTL unit. * reg_index: Index of register to check. * insn_index: Instruction index to use as endpoint of check. * [Return value] * Instruction index of the latest reference to reg_index before * insn_index. */ extern PURE_FUNCTION int rtl_opt_prev_reg_use( const RTLUnit *unit, int reg_index, int insn_index); /** * rtl_opt_kill_insn: Replace the given instruction with a NOP. If any * of the instruction's input operands died at that instruction, roll their * deaths back to the previous instruction at which they are referenced; if * such a register has no other references after the instruction that sets * it and if dse is true, recursively kill the instruction that sets it. * * Helper function for optimization routines. * * [Parameters] * unit: RTL unit. * insn_index: Index of instruction to kill. * ignore_fexc: True to kill the instruction even if it could raise a * floating-point exception; false to not kill such an instruction. * dse: True to recursively kill stores which become dead; false to * leave them alone. */ #define rtl_opt_kill_insn INTERNAL(rtl_opt_kill_insn) extern void rtl_opt_kill_insn(RTLUnit *unit, int insn_index, bool ignore_fexc, bool dse); /** * rtl_opt_alias_data_flow: Analyze data flow through aliases in the given * unit and eliminate SET_ALIAS instructions which are not visible to any * subsequent alias references. Aliases with bound storage (from * rtl_set_alias_storage()) are treated as being implicitly referenced * when the unit returns to its caller. * * This function's worst-case runtime is roughly quadratic in the number * of basic blocks in the unit (more precisely: O(ab^2+i), where a is the * number of aliases, b is the number of basic blocks, and i is the number * of instructions in the unit). * * [Parameters] * unit: RTL unit. */ #define rtl_opt_alias_data_flow INTERNAL(rtl_opt_alias_data_flow) extern void rtl_opt_alias_data_flow(RTLUnit *unit); /** * rtl_opt_decondition: Perform "deconditioning" of conditional branches * with constant conditions. For "GOTO_IF_Z (GOTO_IF_NZ) label, rN" where * rN is type RTLREG_CONSTANT, the instruction is changed to GOTO if the * value of rN is zero (nonzero) and NOP otherwise. As with constant * folding, if the condition register is not used anywhere else, the * register is eliminated and the instruction that loaded it is changed * to a NOP. * * [Parameters] * unit: RTL unit. */ #define rtl_opt_decondition INTERNAL(rtl_opt_decondition) extern void rtl_opt_decondition(RTLUnit *unit); /** * rtl_opt_drop_dead_blocks: Search an RTL unit for basic blocks which are * unreachable via any path from the initial block and remove them from the * code stream. All blocks dominated only by such dead blocks are * recursively removed as well. * * [Parameters] * unit: RTL unit. */ #define rtl_opt_drop_dead_blocks INTERNAL(rtl_opt_drop_dead_blocks) extern void rtl_opt_drop_dead_blocks(RTLUnit *unit); /** * rtl_opt_drop_dead_branches: Search an RTL unit for branch instructions * which branch to the next instruction in the code stream and replace them * with NOPs. Also replace any unused labels with NOPs. * * [Parameters] * unit: RTL unit. * ignore_fexc: Passed to rtl_opt_kill_insn() when eliminating dead stores. * dse: True to eliminate dead stores resulting from dropped branches, * false to leave dead stores alone. */ #define rtl_opt_drop_dead_branches INTERNAL(rtl_opt_drop_dead_branches) extern void rtl_opt_drop_dead_branches(RTLUnit *unit, bool ignore_fexc, bool dse); /** * rtl_opt_drop_dead_stores: Search an RTL unit for instructions that * write to a register which is never used elsewhere, and replace them * with NOPs. * * [Parameters] * unit: RTL unit. * ignore_fexc: True to eliminate instructions which could raise * floating-point exceptions; false to leave them alone. */ #define rtl_opt_drop_dead_stores INTERNAL(rtl_opt_drop_dead_stores) extern void rtl_opt_drop_dead_stores(RTLUnit *unit, bool ignore_fexc); /** * rtl_opt_fold_registers: Perform various categories of register folding * on the given RTL unit. * * If fold_constants is true, convert instructions that operate on constant * operands into load-immediate instructions that load the result of the * operation, and convert register-register instructions in which one of * the two registers is constant into register-immediate instructions when * possible. * * If both fold_constants and fold_fp_constants are true, floating-point * operations on constants will also be folded. Note that this can change * the behavior of the translated code, since constant folding does not * attempt to match the precise behavior of the guest architecture and any * exceptions generated by the operation are discarded. * * If fold_vectors is true, operations on scalar elements of vector * registers, such as VEXTRACT on a vector constructed with VBROADCAST, * will be converted to scalar operations on the original source values. * * [Parameters] * unit: RTL unit. * fold_constants: True to fold and propagate constants. * fold_fp_constants: True to fold floating-point constant operations * when fold_constants is true; false to leave them unfolded. * fold_vectors: True to fold vector operations. */ #define rtl_opt_fold_registers INTERNAL(rtl_opt_fold_registers) extern void rtl_opt_fold_registers(RTLUnit *unit, bool fold_constants, bool fold_fp_constants, bool fold_vectors); /** * rtl_opt_thread_branches: Search an RTL unit for branch instructions * which directly target other (unconditional or same-conditioned) branch * instructions, and rewrite their targets to point to the final branch * target. * * [Parameters] * unit: RTL unit. */ #define rtl_opt_thread_branches INTERNAL(rtl_opt_thread_branches) extern void rtl_opt_thread_branches(RTLUnit *unit); /*------------------------- Register management -------------------------*/ /** * rtl_type_is_int: Return whether the given data type is a scalar * integral type. */ static inline CONST_FUNCTION bool rtl_type_is_int(RTLDataType type) { return type <= RTLTYPE_ADDRESS; } /** * rtl_type_is_float: Return whether the given data type is a scalar * floating-point type. */ static inline CONST_FUNCTION bool rtl_type_is_float(RTLDataType type) { return type >= RTLTYPE_FLOAT32 && type <= RTLTYPE_FLOAT64; } /** * rtl_type_is_scalar: Return whether the given data type is a scalar type. */ static inline CONST_FUNCTION bool rtl_type_is_scalar(RTLDataType type) { return type <= RTLTYPE_FLOAT64; } /** * rtl_type_is_vector: Return whether the given data type is a vector type. */ static inline CONST_FUNCTION bool rtl_type_is_vector(RTLDataType type) { return type >= RTLTYPE_V2_FLOAT32 && type <= RTLTYPE_V2_FLOAT64; } /** * rtl_vector_length: Return the number of elements in the given vector type. */ static inline CONST_FUNCTION int rtl_vector_length(RTLDataType type) { return rtl_type_is_vector(type) ? 2 : 1; } /** * rtl_vector_element_type: Return the scalar element type for the given * vector type. */ static inline CONST_FUNCTION RTLDataType rtl_vector_element_type(RTLDataType type) { return (type == RTLTYPE_V2_FLOAT32 ? RTLTYPE_FLOAT32 : type == RTLTYPE_V2_FLOAT64 ? RTLTYPE_FLOAT64 : type); } /** * rtl_register_is_int: Return whether the given register has an integral * type. */ static inline PURE_FUNCTION bool rtl_register_is_int(const RTLRegister *reg) { return rtl_type_is_int(reg->type); } /** * rtl_register_is_float: Return whether the given register has a * floating-point type. */ static inline PURE_FUNCTION bool rtl_register_is_float(const RTLRegister *reg) { return rtl_type_is_float(reg->type); } /** * rtl_register_is_scalar: Return whether the given register has a scalar * type. */ static inline PURE_FUNCTION bool rtl_register_is_scalar(const RTLRegister *reg) { return rtl_type_is_scalar(reg->type); } /** * rtl_register_is_vector: Return whether the given register has a vector * type. */ static inline PURE_FUNCTION bool rtl_register_is_vector(const RTLRegister *reg) { return rtl_type_is_vector(reg->type); } /*------------------- Miscellaneous utility functions -------------------*/ /** * snprintf_assert: Wrapper for snprintf() which ASSERT()s that the * written string fits within the supplied buffer. */ #define snprintf_assert INTERNAL(snprintf_assert) FORMAT(3, 4) extern int snprintf_assert(char *buf, size_t size, const char *format, ...); /** * format_int: Write the given integer value to the given buffer as a * numeric string in an appropriate format for the type and value magnitude. * Non-address types in the range [-0x8000,+0xFFFF] are formatted as decimal * values; all other cases are formatted in hexadecimal. * * [Parameters] * buf: Buffer into which to store formatted value. * bufsize: Size of buffer, in bytes. Should be at least 19. * type: Type of value (RTLTYPE_*). * value: Value, as a 64-bit integer. * [Return value] * Number of bytes written, like snprintf(). */ #define format_int INTERNAL(format_int) extern int format_int(char *buf, int bufsize, RTLDataType type, uint64_t value); /** * format_float, format_double: Write the given floating-point value to * the given buffer as a numeric string. * * [Parameters] * buf: Buffer into which to store formatted value. * bufsize: Size of buffer, in bytes. Should be at least 14 for * format_float(), 24 for format_double(). * value: Value to format. * [Return value] * Number of bytes written, like snprintf(). */ #define format_float INTERNAL(format_float) extern int format_float(char *buf, int bufsize, float value); #define format_double INTERNAL(format_double) extern int format_double(char *buf, int bufsize, double value); /** * rtl_type_name: Return an appropriate name for the given data type. */ #define rtl_type_name INTERNAL(rtl_type_name) extern CONST_FUNCTION const char *rtl_type_name(RTLDataType type); /** * rtl_type_suffix: Return an appropriate suffix for the given data type. */ #define rtl_type_suffix INTERNAL(rtl_type_suffix) extern CONST_FUNCTION const char *rtl_type_suffix(RTLDataType type); /** * rtl_source_name: Return an appropriate name for the given register source. */ #define rtl_source_name INTERNAL(rtl_source_name) extern CONST_FUNCTION const char *rtl_source_name(RTLRegType source); /** * rtl_update_live_ranges: Update the live range of any register live at * the beginning of a block targeted by a backward branch so that the * register is live through all branches that target the block. * * Worst-case execution time is O(n*m) in the number of blocks (n) and the * number of registers (m). However, the register scan is only required * for blocks targeted by backward branches, and it terminates at the first * register born within or after the targeted block. * * [Parameters] * unit: RTL unit. */ #define rtl_update_live_ranges INTERNAL(rtl_update_live_ranges) extern void rtl_update_live_ranges(RTLUnit *unit); /*************************************************************************/ /*************************************************************************/ #endif // SRC_RTL_INTERNAL_H