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-2013 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 
ppHRegClass(HRegClass hrc)47 void 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. */
ppHReg(HReg r)61 void 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 
RRegUniverse__init(RRegUniverse * univ)89 void 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 
RRegUniverse__check_is_sane(const RRegUniverse * univ)99 void 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 
ppHRegUsage(const RRegUniverse * univ,HRegUsage * tab)123 void 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 */
addHRegUse(HRegUsage * tab,HRegMode mode,HReg reg)164 void 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 
HRegUsage__contains(const HRegUsage * tab,HReg reg)213 Bool 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 
ppHRegRemap(HRegRemap * map)236 void 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 
addToHRegRemap(HRegRemap * map,HReg orig,HReg replacement)251 void 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 
lookupHRegRemap(HRegRemap * map,HReg orig)269 HReg 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 
newHInstrArray(void)285 HInstrArray* 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))
addHInstr_SLOW(HInstrArray * ha,HInstr * instr)296 void 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 
ppRetLoc(RetLoc ska)314 void 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