| |
| /*---------------------------------------------------------------*/ |
| /*--- begin host_generic_regs.h ---*/ |
| /*---------------------------------------------------------------*/ |
| |
| /* |
| This file is part of Valgrind, a dynamic binary instrumentation |
| framework. |
| |
| Copyright (C) 2004-2012 OpenWorks LLP |
| info@open-works.net |
| |
| This program is free software; you can redistribute it and/or |
| modify it under the terms of the GNU General Public License as |
| published by the Free Software Foundation; either version 2 of the |
| License, or (at your option) any later version. |
| |
| This program is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with this program; if not, write to the Free Software |
| Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301, USA. |
| |
| The GNU General Public License is contained in the file COPYING. |
| |
| Neither the names of the U.S. Department of Energy nor the |
| University of California nor the names of its contributors may be |
| used to endorse or promote products derived from this software |
| without prior written permission. |
| */ |
| |
| #ifndef __VEX_HOST_GENERIC_REGS_H |
| #define __VEX_HOST_GENERIC_REGS_H |
| |
| #include "libvex_basictypes.h" |
| |
| |
| /*---------------------------------------------------------*/ |
| /*--- Representing HOST REGISTERS ---*/ |
| /*---------------------------------------------------------*/ |
| |
| /* Host registers. Stuff to represent: |
| |
| - The register number |
| - The register class |
| - Whether or not the register is a virtual reg. |
| |
| Registers are a 32-bit Int, thusly: |
| |
| bits 31-28 are the register class. |
| bits 27-23 are 0000b for real register, 0001b for virtual register |
| bits 23-0 register number |
| |
| Note (importantly) that by arranging that the class field is never |
| 0000b, any valid register looks like an extremely large int -- at |
| least 2^28 -- and so there is little chance of confusing it with an |
| integer array index in the register allocator. |
| |
| Note further that since the class field is never 1111b, no valid |
| register can have the value INVALID_HREG. |
| |
| There are currently 6 register classes: |
| |
| int32 int64 float32 float64 simd64 simd128 |
| */ |
| |
| typedef UInt HReg; |
| |
| /* When extending this, do not use any value > 14 or < 0. */ |
| /* HRegClass describes host register classes which the instruction |
| selectors can speak about. We would not expect all of them to be |
| available on any specific host. For example on x86, the available |
| classes are: Int32, Flt64, Vec128 only. |
| |
| IMPORTANT NOTE: host_generic_reg_alloc2.c needs how much space is |
| needed to spill each class of register. It allocates the following |
| amount of space: |
| |
| HRcInt32 64 bits |
| HRcInt64 64 bits |
| HRcFlt32 64 bits |
| HRcFlt64 128 bits (on x86 these are spilled by fstpt/fldt and |
| so won't fit in a 64-bit slot) |
| HRcVec64 64 bits |
| HRcVec128 128 bits |
| |
| If you add another regclass, you must remember to update |
| host_generic_reg_alloc2.c accordingly. |
| */ |
| typedef |
| enum { |
| HRcINVALID=1, /* NOT A VALID REGISTER CLASS */ |
| HRcInt32=3, /* 32-bit int */ |
| HRcInt64=4, /* 64-bit int */ |
| HRcFlt32=5, /* 32-bit float */ |
| HRcFlt64=6, /* 64-bit float */ |
| HRcVec64=7, /* 64-bit SIMD */ |
| HRcVec128=8 /* 128-bit SIMD */ |
| } |
| HRegClass; |
| |
| extern void ppHRegClass ( HRegClass ); |
| |
| |
| /* Print an HReg in a generic (non-target-specific) way. */ |
| extern void ppHReg ( HReg ); |
| |
| /* Construct/destruct. */ |
| static inline HReg mkHReg ( UInt regno, HRegClass rc, Bool virtual ) { |
| UInt r24 = regno & 0x00FFFFFF; |
| /* This is critical. The register number field may only |
| occupy 24 bits. */ |
| if (r24 != regno) |
| vpanic("mkHReg: regno exceeds 2^24"); |
| return regno | (((UInt)rc) << 28) | (virtual ? (1<<24) : 0); |
| } |
| |
| static inline HRegClass hregClass ( HReg r ) { |
| UInt rc = r; |
| rc = (rc >> 28) & 0x0F; |
| vassert(rc >= HRcInt32 && rc <= HRcVec128); |
| return (HRegClass)rc; |
| } |
| |
| static inline UInt hregNumber ( HReg r ) { |
| return ((UInt)r) & 0x00FFFFFF; |
| } |
| |
| static inline Bool hregIsVirtual ( HReg r ) { |
| return toBool(((UInt)r) & (1<<24)); |
| } |
| |
| |
| |
| |
| #define INVALID_HREG ((HReg)0xFFFFFFFF) |
| |
| |
| /*---------------------------------------------------------*/ |
| /*--- Recording register usage (for reg-alloc) ---*/ |
| /*---------------------------------------------------------*/ |
| |
| typedef |
| enum { HRmRead, HRmWrite, HRmModify } |
| HRegMode; |
| |
| |
| /* A struct for recording the usage of registers in instructions. |
| This can get quite large, but we don't expect to allocate them |
| dynamically, so there's no problem. |
| */ |
| #define N_HREG_USAGE 25 |
| |
| typedef |
| struct { |
| HReg hreg[N_HREG_USAGE]; |
| HRegMode mode[N_HREG_USAGE]; |
| Int n_used; |
| } |
| HRegUsage; |
| |
| extern void ppHRegUsage ( HRegUsage* ); |
| |
| static inline void initHRegUsage ( HRegUsage* tab ) { |
| tab->n_used = 0; |
| } |
| |
| /* Add a register to a usage table. Combine incoming read uses with |
| existing write uses into a modify use, and vice versa. Do not |
| create duplicate entries -- each reg should only be mentioned once. |
| */ |
| extern void addHRegUse ( HRegUsage*, HRegMode, HReg ); |
| |
| |
| |
| /*---------------------------------------------------------*/ |
| /*--- Indicating register remappings (for reg-alloc) ---*/ |
| /*---------------------------------------------------------*/ |
| |
| /* Note that such maps can only map virtual regs to real regs. |
| addToHRegRenap will barf if given a pair not of that form. As a |
| result, no valid HRegRemap will bind a real reg to anything, and so |
| if lookupHRegMap is given a real reg, it returns it unchanged. |
| This is precisely the behaviour that the register allocator needs |
| to impose its decisions on the instructions it processes. */ |
| |
| #define N_HREG_REMAP 6 |
| |
| typedef |
| struct { |
| HReg orig [N_HREG_REMAP]; |
| HReg replacement[N_HREG_REMAP]; |
| Int n_used; |
| } |
| HRegRemap; |
| |
| extern void ppHRegRemap ( HRegRemap* ); |
| extern void initHRegRemap ( HRegRemap* ); |
| extern void addToHRegRemap ( HRegRemap*, HReg, HReg ); |
| extern HReg lookupHRegRemap ( HRegRemap*, HReg ); |
| |
| |
| /*---------------------------------------------------------*/ |
| /*--- Abstract instructions ---*/ |
| /*---------------------------------------------------------*/ |
| |
| /* A type is needed to refer to pointers to instructions of any |
| target. Defining it like this means that HInstr* can stand in for |
| X86Instr*, ArmInstr*, etc. */ |
| |
| typedef void HInstr; |
| |
| |
| /* An expandable array of HInstr*'s. Handy for insn selection and |
| register allocation. n_vregs indicates the number of virtual |
| registers mentioned in the code, something that reg-alloc needs to |
| know. These are required to be numbered 0 .. n_vregs-1. |
| */ |
| typedef |
| struct { |
| HInstr** arr; |
| Int arr_size; |
| Int arr_used; |
| Int n_vregs; |
| } |
| HInstrArray; |
| |
| extern HInstrArray* newHInstrArray ( void ); |
| extern void addHInstr ( HInstrArray*, HInstr* ); |
| |
| |
| /*---------------------------------------------------------*/ |
| /*--- Reg alloc: TODO: move somewhere else ---*/ |
| /*---------------------------------------------------------*/ |
| |
| extern |
| HInstrArray* doRegisterAllocation ( |
| |
| /* Incoming virtual-registerised code. */ |
| HInstrArray* instrs_in, |
| |
| /* An array listing all the real registers the allocator may use, |
| in no particular order. */ |
| HReg* available_real_regs, |
| Int n_available_real_regs, |
| |
| /* Return True iff the given insn is a reg-reg move, in which |
| case also return the src and dst regs. */ |
| Bool (*isMove) (HInstr*, HReg*, HReg*), |
| |
| /* Get info about register usage in this insn. */ |
| void (*getRegUsage) (HRegUsage*, HInstr*, Bool), |
| |
| /* Apply a reg-reg mapping to an insn. */ |
| void (*mapRegs) (HRegRemap*, HInstr*, Bool), |
| |
| /* Return insn(s) to spill/restore a real reg to a spill slot |
| offset. And optionally a function to do direct reloads. */ |
| void (*genSpill) ( HInstr**, HInstr**, HReg, Int, Bool ), |
| void (*genReload) ( HInstr**, HInstr**, HReg, Int, Bool ), |
| HInstr* (*directReload) ( HInstr*, HReg, Short ), |
| Int guest_sizeB, |
| |
| /* For debug printing only. */ |
| void (*ppInstr) ( HInstr*, Bool ), |
| void (*ppReg) ( HReg ), |
| |
| /* 32/64bit mode */ |
| Bool mode64 |
| ); |
| |
| |
| #endif /* ndef __VEX_HOST_GENERIC_REGS_H */ |
| |
| /*---------------------------------------------------------------*/ |
| /*--- host_generic_regs.h ---*/ |
| /*---------------------------------------------------------------*/ |