mirror of
https://github.com/ioacademy-jikim/debugging
synced 2025-06-09 17:06:24 +00:00
338 lines
10 KiB
C
338 lines
10 KiB
C
|
|
/*---------------------------------------------------------------*/
|
|
/*--- begin host_generic_regs.c ---*/
|
|
/*---------------------------------------------------------------*/
|
|
|
|
/*
|
|
This file is part of Valgrind, a dynamic binary instrumentation
|
|
framework.
|
|
|
|
Copyright (C) 2004-2015 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.
|
|
*/
|
|
|
|
#include "libvex_basictypes.h"
|
|
#include "libvex.h"
|
|
|
|
#include "main_util.h"
|
|
#include "host_generic_regs.h"
|
|
|
|
|
|
/*---------------------------------------------------------*/
|
|
/*--- Representing HOST REGISTERS ---*/
|
|
/*---------------------------------------------------------*/
|
|
|
|
void ppHRegClass ( HRegClass hrc )
|
|
{
|
|
switch (hrc) {
|
|
case HRcInt32: vex_printf("HRcInt32"); break;
|
|
case HRcInt64: vex_printf("HRcInt64"); break;
|
|
case HRcFlt32: vex_printf("HRcFlt32"); break;
|
|
case HRcFlt64: vex_printf("HRcFlt64"); break;
|
|
case HRcVec64: vex_printf("HRcVec64"); break;
|
|
case HRcVec128: vex_printf("HRcVec128"); break;
|
|
default: vpanic("ppHRegClass");
|
|
}
|
|
}
|
|
|
|
/* Generic printing for registers. */
|
|
void ppHReg ( HReg r )
|
|
{
|
|
if (hregIsInvalid(r)) {
|
|
vex_printf("HReg_INVALID");
|
|
return;
|
|
}
|
|
const Bool isV = hregIsVirtual(r);
|
|
const HChar* maybe_v = isV ? "v" : "";
|
|
const UInt regNN = isV ? hregIndex(r) : hregEncoding(r);
|
|
/* For real registers, we show the encoding. But the encoding is
|
|
always zero for virtual registers, so that's pointless -- hence
|
|
show the index number instead. */
|
|
switch (hregClass(r)) {
|
|
case HRcInt32: vex_printf("%%%sr%u", maybe_v, regNN); return;
|
|
case HRcInt64: vex_printf("%%%sR%u", maybe_v, regNN); return;
|
|
case HRcFlt32: vex_printf("%%%sF%u", maybe_v, regNN); return;
|
|
case HRcFlt64: vex_printf("%%%sD%u", maybe_v, regNN); return;
|
|
case HRcVec64: vex_printf("%%%sv%u", maybe_v, regNN); return;
|
|
case HRcVec128: vex_printf("%%%sV%u", maybe_v, regNN); return;
|
|
default: vpanic("ppHReg");
|
|
}
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------*/
|
|
/*--- Real register Universes. ---*/
|
|
/*---------------------------------------------------------*/
|
|
|
|
void RRegUniverse__init ( /*OUT*/RRegUniverse* univ )
|
|
{
|
|
*univ = (RRegUniverse){};
|
|
univ->size = 0;
|
|
univ->allocable = 0;
|
|
for (UInt i = 0; i < N_RREGUNIVERSE_REGS; i++) {
|
|
univ->regs[i] = INVALID_HREG;
|
|
}
|
|
}
|
|
|
|
void RRegUniverse__check_is_sane ( const RRegUniverse* univ )
|
|
{
|
|
/* Check Real-Register-Universe invariants. All of these are
|
|
important. */
|
|
vassert(univ->size > 0);
|
|
vassert(univ->size <= N_RREGUNIVERSE_REGS);
|
|
vassert(univ->allocable <= univ->size);
|
|
for (UInt i = 0; i < univ->size; i++) {
|
|
HReg reg = univ->regs[i];
|
|
vassert(!hregIsInvalid(reg));
|
|
vassert(!hregIsVirtual(reg));
|
|
vassert(hregIndex(reg) == i);
|
|
}
|
|
for (UInt i = univ->size; i < N_RREGUNIVERSE_REGS; i++) {
|
|
HReg reg = univ->regs[i];
|
|
vassert(hregIsInvalid(reg));
|
|
}
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------*/
|
|
/*--- Helpers for recording reg usage (for reg-alloc) ---*/
|
|
/*---------------------------------------------------------*/
|
|
|
|
void ppHRegUsage ( const RRegUniverse* univ, HRegUsage* tab )
|
|
{
|
|
/* This is going to fail miserably if N_RREGUNIVERSE_REGS exceeds
|
|
64. So let's cause it to fail in an obvious way. */
|
|
vassert(N_RREGUNIVERSE_REGS == 64);
|
|
|
|
vex_printf("HRegUsage {\n");
|
|
/* First print the real regs */
|
|
for (UInt i = 0; i < N_RREGUNIVERSE_REGS; i++) {
|
|
Bool rRd = (tab->rRead & (1ULL << i)) != 0;
|
|
Bool rWr = (tab->rWritten & (1ULL << i)) != 0;
|
|
const HChar* str = "Modify ";
|
|
/**/ if (!rRd && !rWr) { continue; }
|
|
else if ( rRd && !rWr) { str = "Read "; }
|
|
else if (!rRd && rWr) { str = "Write "; }
|
|
/* else "Modify" is correct */
|
|
vex_printf(" %s ", str);
|
|
ppHReg(univ->regs[i]);
|
|
vex_printf("\n");
|
|
}
|
|
/* and now the virtual registers */
|
|
for (UInt i = 0; i < tab->n_vRegs; i++) {
|
|
const HChar* str = NULL;
|
|
switch (tab->vMode[i]) {
|
|
case HRmRead: str = "Read "; break;
|
|
case HRmWrite: str = "Write "; break;
|
|
case HRmModify: str = "Modify "; break;
|
|
default: vpanic("ppHRegUsage");
|
|
}
|
|
vex_printf(" %s ", str);
|
|
ppHReg(tab->vRegs[i]);
|
|
vex_printf("\n");
|
|
}
|
|
vex_printf("}\n");
|
|
}
|
|
|
|
|
|
/* Add a register to a usage table. Combines incoming read uses with
|
|
existing write uses into a modify use, and vice versa. Does not
|
|
create duplicate entries -- each reg is only mentioned once.
|
|
*/
|
|
void addHRegUse ( HRegUsage* tab, HRegMode mode, HReg reg )
|
|
{
|
|
/* Because real and virtual registers are represented differently,
|
|
they have completely different paths here. */
|
|
if (LIKELY(hregIsVirtual(reg))) {
|
|
/* Virtual register */
|
|
UInt i;
|
|
/* Find it ... */
|
|
for (i = 0; i < tab->n_vRegs; i++)
|
|
if (sameHReg(tab->vRegs[i], reg))
|
|
break;
|
|
if (i == tab->n_vRegs) {
|
|
/* Not found, add new entry. */
|
|
vassert(tab->n_vRegs < N_HREGUSAGE_VREGS);
|
|
tab->vRegs[tab->n_vRegs] = reg;
|
|
tab->vMode[tab->n_vRegs] = mode;
|
|
tab->n_vRegs++;
|
|
} else {
|
|
/* Found: combine or ignore. */
|
|
/* This is a greatest-lower-bound operation in the poset:
|
|
|
|
R W
|
|
\ /
|
|
M
|
|
|
|
Need to do: tab->mode[i] = GLB(tab->mode, mode). In this
|
|
case very simple -- if tab->mode[i] != mode then result must
|
|
be M.
|
|
*/
|
|
if (tab->vMode[i] == mode) {
|
|
/* duplicate, ignore */
|
|
} else {
|
|
tab->vMode[i] = HRmModify;
|
|
}
|
|
}
|
|
} else {
|
|
/* Real register */
|
|
UInt ix = hregIndex(reg);
|
|
vassert(ix < N_RREGUNIVERSE_REGS);
|
|
ULong mask = 1ULL << ix;
|
|
switch (mode) {
|
|
case HRmRead: tab->rRead |= mask; break;
|
|
case HRmWrite: tab->rWritten |= mask; break;
|
|
case HRmModify: tab->rRead |= mask; tab->rWritten |= mask; break;
|
|
default: vassert(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
Bool HRegUsage__contains ( const HRegUsage* tab, HReg reg )
|
|
{
|
|
vassert(!hregIsInvalid(reg));
|
|
if (hregIsVirtual(reg)) {
|
|
for (UInt i = 0; i < tab->n_vRegs; i++) {
|
|
if (sameHReg(reg, tab->vRegs[i]))
|
|
return True;
|
|
}
|
|
return False;
|
|
} else {
|
|
UInt ix = hregIndex(reg);
|
|
vassert(ix < N_RREGUNIVERSE_REGS);
|
|
ULong mentioned = tab->rRead | tab->rWritten;
|
|
return (mentioned & (1ULL << ix)) != 0;
|
|
}
|
|
/*NOTREACHED*/
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------*/
|
|
/*--- Indicating register remappings (for reg-alloc) ---*/
|
|
/*---------------------------------------------------------*/
|
|
|
|
void ppHRegRemap ( HRegRemap* map )
|
|
{
|
|
Int i;
|
|
vex_printf("HRegRemap {\n");
|
|
for (i = 0; i < map->n_used; i++) {
|
|
vex_printf(" ");
|
|
ppHReg(map->orig[i]);
|
|
vex_printf(" --> ");
|
|
ppHReg(map->replacement[i]);
|
|
vex_printf("\n");
|
|
}
|
|
vex_printf("}\n");
|
|
}
|
|
|
|
|
|
void addToHRegRemap ( HRegRemap* map, HReg orig, HReg replacement )
|
|
{
|
|
Int i;
|
|
for (i = 0; i < map->n_used; i++)
|
|
if (sameHReg(map->orig[i], orig))
|
|
vpanic("addToHRegMap: duplicate entry");
|
|
if (!hregIsVirtual(orig))
|
|
vpanic("addToHRegMap: orig is not a vreg");
|
|
if (hregIsVirtual(replacement))
|
|
vpanic("addToHRegMap: replacement is a vreg");
|
|
|
|
vassert(map->n_used+1 < N_HREG_REMAP);
|
|
map->orig[map->n_used] = orig;
|
|
map->replacement[map->n_used] = replacement;
|
|
map->n_used++;
|
|
}
|
|
|
|
|
|
HReg lookupHRegRemap ( HRegRemap* map, HReg orig )
|
|
{
|
|
Int i;
|
|
if (!hregIsVirtual(orig))
|
|
return orig;
|
|
for (i = 0; i < map->n_used; i++)
|
|
if (sameHReg(map->orig[i], orig))
|
|
return map->replacement[i];
|
|
vpanic("lookupHRegRemap: not found");
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------*/
|
|
/*--- Abstract instructions ---*/
|
|
/*---------------------------------------------------------*/
|
|
|
|
HInstrArray* newHInstrArray ( void )
|
|
{
|
|
HInstrArray* ha = LibVEX_Alloc_inline(sizeof(HInstrArray));
|
|
ha->arr_size = 4;
|
|
ha->arr_used = 0;
|
|
ha->arr = LibVEX_Alloc_inline(ha->arr_size * sizeof(HInstr*));
|
|
ha->n_vregs = 0;
|
|
return ha;
|
|
}
|
|
|
|
__attribute__((noinline))
|
|
void addHInstr_SLOW ( HInstrArray* ha, HInstr* instr )
|
|
{
|
|
vassert(ha->arr_used == ha->arr_size);
|
|
Int i;
|
|
HInstr** arr2 = LibVEX_Alloc_inline(ha->arr_size * 2 * sizeof(HInstr*));
|
|
for (i = 0; i < ha->arr_size; i++) {
|
|
arr2[i] = ha->arr[i];
|
|
}
|
|
ha->arr_size *= 2;
|
|
ha->arr = arr2;
|
|
addHInstr(ha, instr);
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------*/
|
|
/*--- C-Call return-location actions ---*/
|
|
/*---------------------------------------------------------*/
|
|
|
|
void ppRetLoc ( RetLoc ska )
|
|
{
|
|
switch (ska.pri) {
|
|
case RLPri_INVALID:
|
|
vex_printf("RLPri_INVALID"); return;
|
|
case RLPri_None:
|
|
vex_printf("RLPri_None"); return;
|
|
case RLPri_Int:
|
|
vex_printf("RLPri_Int"); return;
|
|
case RLPri_2Int:
|
|
vex_printf("RLPri_2Int"); return;
|
|
case RLPri_V128SpRel:
|
|
vex_printf("RLPri_V128SpRel(%d)", ska.spOff); return;
|
|
case RLPri_V256SpRel:
|
|
vex_printf("RLPri_V256SpRel(%d)", ska.spOff); return;
|
|
default:
|
|
vpanic("ppRetLoc");
|
|
}
|
|
}
|
|
|
|
|
|
/*---------------------------------------------------------------*/
|
|
/*--- end host_generic_regs.c ---*/
|
|
/*---------------------------------------------------------------*/
|