1
2/*---------------------------------------------------------------*/
3/*--- begin                               host_generic_regs.c ---*/
4/*---------------------------------------------------------------*/
5
6/*
7   This file is part of Valgrind, a dynamic binary instrumentation
8   framework.
9
10   Copyright (C) 2004-2015 OpenWorks LLP
11      info@open-works.net
12
13   This program is free software; you can redistribute it and/or
14   modify it under the terms of the GNU General Public License as
15   published by the Free Software Foundation; either version 2 of the
16   License, or (at your option) any later version.
17
18   This program is distributed in the hope that it will be useful, but
19   WITHOUT ANY WARRANTY; without even the implied warranty of
20   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21   General Public License for more details.
22
23   You should have received a copy of the GNU General Public License
24   along with this program; if not, write to the Free Software
25   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
26   02110-1301, USA.
27
28   The GNU General Public License is contained in the file COPYING.
29
30   Neither the names of the U.S. Department of Energy nor the
31   University of California nor the names of its contributors may be
32   used to endorse or promote products derived from this software
33   without prior written permission.
34*/
35
36#include "libvex_basictypes.h"
37#include "libvex.h"
38
39#include "main_util.h"
40#include "host_generic_regs.h"
41
42
43/*---------------------------------------------------------*/
44/*--- Representing HOST REGISTERS                       ---*/
45/*---------------------------------------------------------*/
46
47void ppHRegClass ( HRegClass hrc )
48{
49   switch (hrc) {
50      case HRcInt32:   vex_printf("HRcInt32"); break;
51      case HRcInt64:   vex_printf("HRcInt64"); break;
52      case HRcFlt32:   vex_printf("HRcFlt32"); break;
53      case HRcFlt64:   vex_printf("HRcFlt64"); break;
54      case HRcVec64:   vex_printf("HRcVec64"); break;
55      case HRcVec128:  vex_printf("HRcVec128"); break;
56      default: vpanic("ppHRegClass");
57   }
58}
59
60/* Generic printing for registers. */
61void ppHReg ( HReg r )
62{
63   if (hregIsInvalid(r)) {
64      vex_printf("HReg_INVALID");
65      return;
66   }
67   const Bool   isV     = hregIsVirtual(r);
68   const HChar* maybe_v = isV ? "v" : "";
69   const UInt   regNN   = isV ? hregIndex(r) : hregEncoding(r);
70   /* For real registers, we show the encoding.  But the encoding is
71      always zero for virtual registers, so that's pointless -- hence
72      show the index number instead. */
73   switch (hregClass(r)) {
74      case HRcInt32:   vex_printf("%%%sr%u", maybe_v, regNN); return;
75      case HRcInt64:   vex_printf("%%%sR%u", maybe_v, regNN); return;
76      case HRcFlt32:   vex_printf("%%%sF%u", maybe_v, regNN); return;
77      case HRcFlt64:   vex_printf("%%%sD%u", maybe_v, regNN); return;
78      case HRcVec64:   vex_printf("%%%sv%u", maybe_v, regNN); return;
79      case HRcVec128:  vex_printf("%%%sV%u", maybe_v, regNN); return;
80      default: vpanic("ppHReg");
81   }
82}
83
84
85/*---------------------------------------------------------*/
86/*--- Real register Universes.                          ---*/
87/*---------------------------------------------------------*/
88
89void RRegUniverse__init ( /*OUT*/RRegUniverse* univ )
90{
91   *univ = (RRegUniverse){};
92   univ->size      = 0;
93   univ->allocable = 0;
94   for (UInt i = 0; i < N_RREGUNIVERSE_REGS; i++) {
95      univ->regs[i] = INVALID_HREG;
96   }
97}
98
99void RRegUniverse__check_is_sane ( const RRegUniverse* univ )
100{
101   /* Check Real-Register-Universe invariants.  All of these are
102      important. */
103   vassert(univ->size > 0);
104   vassert(univ->size <= N_RREGUNIVERSE_REGS);
105   vassert(univ->allocable <= univ->size);
106   for (UInt i = 0; i < univ->size; i++) {
107      HReg reg = univ->regs[i];
108      vassert(!hregIsInvalid(reg));
109      vassert(!hregIsVirtual(reg));
110      vassert(hregIndex(reg) == i);
111   }
112   for (UInt i = univ->size; i < N_RREGUNIVERSE_REGS; i++) {
113      HReg reg = univ->regs[i];
114      vassert(hregIsInvalid(reg));
115   }
116}
117
118
119/*---------------------------------------------------------*/
120/*--- Helpers for recording reg usage (for reg-alloc)   ---*/
121/*---------------------------------------------------------*/
122
123void ppHRegUsage ( const RRegUniverse* univ, HRegUsage* tab )
124{
125   /* This is going to fail miserably if N_RREGUNIVERSE_REGS exceeds
126      64.  So let's cause it to fail in an obvious way. */
127   vassert(N_RREGUNIVERSE_REGS == 64);
128
129   vex_printf("HRegUsage {\n");
130   /* First print the real regs */
131   for (UInt i = 0; i < N_RREGUNIVERSE_REGS; i++) {
132      Bool rRd = (tab->rRead    & (1ULL << i)) != 0;
133      Bool rWr = (tab->rWritten & (1ULL << i)) != 0;
134      const HChar* str = "Modify ";
135      /**/ if (!rRd && !rWr) { continue; }
136      else if ( rRd && !rWr) { str = "Read   "; }
137      else if (!rRd &&  rWr) { str = "Write  "; }
138      /* else "Modify" is correct */
139      vex_printf("   %s ", str);
140      ppHReg(univ->regs[i]);
141      vex_printf("\n");
142   }
143   /* and now the virtual registers */
144   for (UInt i = 0; i < tab->n_vRegs; i++) {
145      const HChar* str = NULL;
146      switch (tab->vMode[i]) {
147         case HRmRead:   str = "Read   "; break;
148         case HRmWrite:  str = "Write  "; break;
149         case HRmModify: str = "Modify "; break;
150         default: vpanic("ppHRegUsage");
151      }
152      vex_printf("   %s ", str);
153      ppHReg(tab->vRegs[i]);
154      vex_printf("\n");
155   }
156   vex_printf("}\n");
157}
158
159
160/* Add a register to a usage table.  Combines incoming read uses with
161   existing write uses into a modify use, and vice versa.  Does not
162   create duplicate entries -- each reg is only mentioned once.
163*/
164void addHRegUse ( HRegUsage* tab, HRegMode mode, HReg reg )
165{
166   /* Because real and virtual registers are represented differently,
167      they have completely different paths here. */
168   if (LIKELY(hregIsVirtual(reg))) {
169      /* Virtual register */
170      UInt i;
171      /* Find it ... */
172      for (i = 0; i < tab->n_vRegs; i++)
173         if (sameHReg(tab->vRegs[i], reg))
174            break;
175      if (i == tab->n_vRegs) {
176         /* Not found, add new entry. */
177         vassert(tab->n_vRegs < N_HREGUSAGE_VREGS);
178         tab->vRegs[tab->n_vRegs] = reg;
179         tab->vMode[tab->n_vRegs] = mode;
180         tab->n_vRegs++;
181      } else {
182         /* Found: combine or ignore. */
183         /* This is a greatest-lower-bound operation in the poset:
184
185               R   W
186                \ /
187                 M
188
189            Need to do: tab->mode[i] = GLB(tab->mode, mode).  In this
190            case very simple -- if tab->mode[i] != mode then result must
191            be M.
192         */
193         if (tab->vMode[i] == mode) {
194            /* duplicate, ignore */
195         } else {
196            tab->vMode[i] = HRmModify;
197         }
198      }
199   } else {
200      /* Real register */
201      UInt ix = hregIndex(reg);
202      vassert(ix < N_RREGUNIVERSE_REGS);
203      ULong mask = 1ULL << ix;
204      switch (mode) {
205         case HRmRead:   tab->rRead |= mask; break;
206         case HRmWrite:  tab->rWritten |= mask; break;
207         case HRmModify: tab->rRead |= mask; tab->rWritten |= mask; break;
208         default: vassert(0);
209      }
210   }
211}
212
213Bool HRegUsage__contains ( const HRegUsage* tab, HReg reg )
214{
215   vassert(!hregIsInvalid(reg));
216   if (hregIsVirtual(reg)) {
217      for (UInt i = 0; i < tab->n_vRegs; i++) {
218         if (sameHReg(reg, tab->vRegs[i]))
219            return True;
220      }
221      return False;
222   } else {
223      UInt ix = hregIndex(reg);
224      vassert(ix < N_RREGUNIVERSE_REGS);
225      ULong mentioned = tab->rRead | tab->rWritten;
226      return (mentioned & (1ULL << ix)) != 0;
227   }
228   /*NOTREACHED*/
229}
230
231
232/*---------------------------------------------------------*/
233/*--- Indicating register remappings (for reg-alloc)    ---*/
234/*---------------------------------------------------------*/
235
236void ppHRegRemap ( HRegRemap* map )
237{
238   Int   i;
239   vex_printf("HRegRemap {\n");
240   for (i = 0; i < map->n_used; i++) {
241      vex_printf("   ");
242      ppHReg(map->orig[i]);
243      vex_printf("  -->  ");
244      ppHReg(map->replacement[i]);
245      vex_printf("\n");
246   }
247   vex_printf("}\n");
248}
249
250
251void addToHRegRemap ( HRegRemap* map, HReg orig, HReg replacement )
252{
253   Int i;
254   for (i = 0; i < map->n_used; i++)
255      if (sameHReg(map->orig[i], orig))
256         vpanic("addToHRegMap: duplicate entry");
257   if (!hregIsVirtual(orig))
258      vpanic("addToHRegMap: orig is not a vreg");
259   if (hregIsVirtual(replacement))
260      vpanic("addToHRegMap: replacement is a vreg");
261
262   vassert(map->n_used+1 < N_HREG_REMAP);
263   map->orig[map->n_used]        = orig;
264   map->replacement[map->n_used] = replacement;
265   map->n_used++;
266}
267
268
269HReg lookupHRegRemap ( HRegRemap* map, HReg orig )
270{
271   Int i;
272   if (!hregIsVirtual(orig))
273      return orig;
274   for (i = 0; i < map->n_used; i++)
275      if (sameHReg(map->orig[i], orig))
276         return map->replacement[i];
277   vpanic("lookupHRegRemap: not found");
278}
279
280
281/*---------------------------------------------------------*/
282/*--- Abstract instructions                             ---*/
283/*---------------------------------------------------------*/
284
285HInstrArray* newHInstrArray ( void )
286{
287   HInstrArray* ha = LibVEX_Alloc_inline(sizeof(HInstrArray));
288   ha->arr_size = 4;
289   ha->arr_used = 0;
290   ha->arr      = LibVEX_Alloc_inline(ha->arr_size * sizeof(HInstr*));
291   ha->n_vregs  = 0;
292   return ha;
293}
294
295__attribute__((noinline))
296void addHInstr_SLOW ( HInstrArray* ha, HInstr* instr )
297{
298   vassert(ha->arr_used == ha->arr_size);
299   Int      i;
300   HInstr** arr2 = LibVEX_Alloc_inline(ha->arr_size * 2 * sizeof(HInstr*));
301   for (i = 0; i < ha->arr_size; i++) {
302      arr2[i] = ha->arr[i];
303   }
304   ha->arr_size *= 2;
305   ha->arr = arr2;
306   addHInstr(ha, instr);
307}
308
309
310/*---------------------------------------------------------*/
311/*--- C-Call return-location actions                    ---*/
312/*---------------------------------------------------------*/
313
314void ppRetLoc ( RetLoc ska )
315{
316   switch (ska.pri) {
317      case RLPri_INVALID:
318         vex_printf("RLPri_INVALID"); return;
319      case RLPri_None:
320         vex_printf("RLPri_None");    return;
321      case RLPri_Int:
322         vex_printf("RLPri_Int");     return;
323      case RLPri_2Int:
324         vex_printf("RLPri_2Int");    return;
325      case RLPri_V128SpRel:
326         vex_printf("RLPri_V128SpRel(%d)", ska.spOff); return;
327      case RLPri_V256SpRel:
328         vex_printf("RLPri_V256SpRel(%d)", ska.spOff); return;
329      default:
330         vpanic("ppRetLoc");
331   }
332}
333
334
335/*---------------------------------------------------------------*/
336/*--- end                                 host_generic_regs.c ---*/
337/*---------------------------------------------------------------*/
338