2 /*---------------------------------------------------------------*/
3 /*--- begin host_generic_regs.c ---*/
4 /*---------------------------------------------------------------*/
7 This file is part of Valgrind, a dynamic binary instrumentation
10 Copyright (C) 2004-2017 OpenWorks LLP
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.
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.
23 You should have received a copy of the GNU General Public License
24 along with this program; if not, see <http://www.gnu.org/licenses/>.
26 The GNU General Public License is contained in the file COPYING.
28 Neither the names of the U.S. Department of Energy nor the
29 University of California nor the names of its contributors may be
30 used to endorse or promote products derived from this software
31 without prior written permission.
34 #include "libvex_basictypes.h"
37 #include "main_util.h"
38 #include "host_generic_regs.h"
41 /*---------------------------------------------------------*/
42 /*--- Representing HOST REGISTERS ---*/
43 /*---------------------------------------------------------*/
45 void ppHRegClass ( HRegClass hrc
)
48 case HRcInt32
: vex_printf("HRcInt32"); break;
49 case HRcInt64
: vex_printf("HRcInt64"); break;
50 case HRcFlt32
: vex_printf("HRcFlt32"); break;
51 case HRcFlt64
: vex_printf("HRcFlt64"); break;
52 case HRcVec64
: vex_printf("HRcVec64"); break;
53 case HRcVec128
: vex_printf("HRcVec128"); break;
54 default: vpanic("ppHRegClass");
58 /* Generic printing for registers. */
59 UInt
ppHReg ( HReg r
)
61 if (hregIsInvalid(r
)) {
62 return vex_printf("HReg_INVALID");
64 const Bool isV
= hregIsVirtual(r
);
65 const HChar
* maybe_v
= isV
? "v" : "";
66 const UInt regNN
= isV
? hregIndex(r
) : hregEncoding(r
);
67 /* For real registers, we show the encoding. But the encoding is
68 always zero for virtual registers, so that's pointless -- hence
69 show the index number instead. */
70 switch (hregClass(r
)) {
71 case HRcInt32
: return vex_printf("%%%sr%u", maybe_v
, regNN
);
72 case HRcInt64
: return vex_printf("%%%sR%u", maybe_v
, regNN
);
73 case HRcFlt32
: return vex_printf("%%%sF%u", maybe_v
, regNN
);
74 case HRcFlt64
: return vex_printf("%%%sD%u", maybe_v
, regNN
);
75 case HRcVec64
: return vex_printf("%%%sv%u", maybe_v
, regNN
);
76 case HRcVec128
: return vex_printf("%%%sV%u", maybe_v
, regNN
);
77 default: vpanic("ppHReg");
82 /*---------------------------------------------------------*/
83 /*--- Real register Universes. ---*/
84 /*---------------------------------------------------------*/
86 void RRegUniverse__init ( /*OUT*/RRegUniverse
* univ
)
88 *univ
= (RRegUniverse
){};
91 for (UInt i
= 0; i
< N_RREGUNIVERSE_REGS
; i
++) {
92 univ
->regs
[i
] = INVALID_HREG
;
95 for (UInt i
= 0; i
<= HrcLAST
; i
++) {
96 univ
->allocable_start
[i
] = N_RREGUNIVERSE_REGS
;
97 univ
->allocable_end
[i
] = N_RREGUNIVERSE_REGS
;
101 void RRegUniverse__check_is_sane ( const RRegUniverse
* univ
)
103 /* Check Real-Register-Universe invariants. All of these are
105 vassert(univ
->size
> 0);
106 vassert(univ
->size
<= N_RREGUNIVERSE_REGS
);
107 vassert(univ
->allocable
<= univ
->size
);
108 for (UInt i
= 0; i
< univ
->size
; i
++) {
109 HReg reg
= univ
->regs
[i
];
110 vassert(!hregIsInvalid(reg
));
111 vassert(!hregIsVirtual(reg
));
112 vassert(hregIndex(reg
) == i
);
114 for (UInt i
= univ
->size
; i
< N_RREGUNIVERSE_REGS
; i
++) {
115 HReg reg
= univ
->regs
[i
];
116 vassert(hregIsInvalid(reg
));
119 /* Determine register classes used and if they form contiguous range. */
120 Bool regclass_used
[HrcLAST
+ 1];
121 for (UInt i
= 0; i
<= HrcLAST
; i
++) {
122 regclass_used
[i
] = False
;
125 for (UInt i
= 0; i
< univ
->allocable
; i
++) {
126 HReg reg
= univ
->regs
[i
];
127 HRegClass regclass
= hregClass(reg
);
128 if (!regclass_used
[regclass
]) {
129 regclass_used
[regclass
] = True
;
133 UInt regs_visited
= 0;
134 for (UInt i
= 0; i
<= HrcLAST
; i
++) {
135 if (regclass_used
[i
]) {
136 for (UInt j
= univ
->allocable_start
[i
];
137 j
<= univ
->allocable_end
[i
]; j
++) {
138 vassert(hregClass(univ
->regs
[j
]) == i
);
144 vassert(regs_visited
== univ
->allocable
);
148 /*---------------------------------------------------------*/
149 /*--- Helpers for recording reg usage (for reg-alloc) ---*/
150 /*---------------------------------------------------------*/
152 void ppHRegUsage ( const RRegUniverse
* univ
, HRegUsage
* tab
)
154 /* This is going to fail miserably if N_RREGUNIVERSE_REGS exceeds
155 64. So let's cause it to fail in an obvious way. */
156 vassert(N_RREGUNIVERSE_REGS
== 64);
158 vex_printf("HRegUsage {\n");
159 /* First print the real regs */
160 for (UInt i
= 0; i
< N_RREGUNIVERSE_REGS
; i
++) {
161 Bool rRd
= (tab
->rRead
& (1ULL << i
)) != 0;
162 Bool rWr
= (tab
->rWritten
& (1ULL << i
)) != 0;
163 const HChar
* str
= "Modify ";
164 /**/ if (!rRd
&& !rWr
) { continue; }
165 else if ( rRd
&& !rWr
) { str
= "Read "; }
166 else if (!rRd
&& rWr
) { str
= "Write "; }
167 /* else "Modify" is correct */
168 vex_printf(" %s ", str
);
169 ppHReg(univ
->regs
[i
]);
172 /* and now the virtual registers */
173 for (UInt i
= 0; i
< tab
->n_vRegs
; i
++) {
174 const HChar
* str
= NULL
;
175 switch (tab
->vMode
[i
]) {
176 case HRmRead
: str
= "Read "; break;
177 case HRmWrite
: str
= "Write "; break;
178 case HRmModify
: str
= "Modify "; break;
179 default: vpanic("ppHRegUsage");
181 vex_printf(" %s ", str
);
182 ppHReg(tab
->vRegs
[i
]);
185 if (tab
->isRegRegMove
) {
186 vex_printf(" (is a reg-reg move)\n");
192 /* Add a register to a usage table. Combines incoming read uses with
193 existing write uses into a modify use, and vice versa. Does not
194 create duplicate entries -- each reg is only mentioned once.
196 void addHRegUse ( HRegUsage
* tab
, HRegMode mode
, HReg reg
)
198 /* Because real and virtual registers are represented differently,
199 they have completely different paths here. */
200 if (LIKELY(hregIsVirtual(reg
))) {
201 /* Virtual register */
204 for (i
= 0; i
< tab
->n_vRegs
; i
++)
205 if (sameHReg(tab
->vRegs
[i
], reg
))
207 if (i
== tab
->n_vRegs
) {
208 /* Not found, add new entry. */
209 vassert(tab
->n_vRegs
< N_HREGUSAGE_VREGS
);
210 tab
->vRegs
[tab
->n_vRegs
] = reg
;
211 tab
->vMode
[tab
->n_vRegs
] = mode
;
214 /* Found: combine or ignore. */
215 /* This is a greatest-lower-bound operation in the poset:
221 Need to do: tab->mode[i] = GLB(tab->mode, mode). In this
222 case very simple -- if tab->mode[i] != mode then result must
225 if (tab
->vMode
[i
] == mode
) {
226 /* duplicate, ignore */
228 tab
->vMode
[i
] = HRmModify
;
233 UInt ix
= hregIndex(reg
);
234 vassert(ix
< N_RREGUNIVERSE_REGS
);
235 ULong mask
= 1ULL << ix
;
237 case HRmRead
: tab
->rRead
|= mask
; break;
238 case HRmWrite
: tab
->rWritten
|= mask
; break;
239 case HRmModify
: tab
->rRead
|= mask
; tab
->rWritten
|= mask
; break;
245 Bool
HRegUsage__contains ( const HRegUsage
* tab
, HReg reg
)
247 vassert(!hregIsInvalid(reg
));
248 if (hregIsVirtual(reg
)) {
249 for (UInt i
= 0; i
< tab
->n_vRegs
; i
++) {
250 if (sameHReg(reg
, tab
->vRegs
[i
]))
255 UInt ix
= hregIndex(reg
);
256 vassert(ix
< N_RREGUNIVERSE_REGS
);
257 ULong mentioned
= tab
->rRead
| tab
->rWritten
;
258 return (mentioned
& (1ULL << ix
)) != 0;
264 /*---------------------------------------------------------*/
265 /*--- Indicating register remappings (for reg-alloc) ---*/
266 /*---------------------------------------------------------*/
268 void ppHRegRemap ( HRegRemap
* map
)
271 vex_printf("HRegRemap {\n");
272 for (i
= 0; i
< map
->n_used
; i
++) {
274 ppHReg(map
->orig
[i
]);
276 ppHReg(map
->replacement
[i
]);
283 void addToHRegRemap ( HRegRemap
* map
, HReg orig
, HReg replacement
)
286 for (i
= 0; i
< map
->n_used
; i
++)
287 if (sameHReg(map
->orig
[i
], orig
))
288 vpanic("addToHRegMap: duplicate entry");
289 if (!hregIsVirtual(orig
))
290 vpanic("addToHRegMap: orig is not a vreg");
291 if (hregIsVirtual(replacement
))
292 vpanic("addToHRegMap: replacement is a vreg");
294 vassert(map
->n_used
+1 < N_HREG_REMAP
);
295 map
->orig
[map
->n_used
] = orig
;
296 map
->replacement
[map
->n_used
] = replacement
;
301 HReg
lookupHRegRemap ( HRegRemap
* map
, HReg orig
)
304 if (!hregIsVirtual(orig
))
306 for (i
= 0; i
< map
->n_used
; i
++)
307 if (sameHReg(map
->orig
[i
], orig
))
308 return map
->replacement
[i
];
309 vpanic("lookupHRegRemap: not found");
313 /*---------------------------------------------------------*/
314 /*--- Abstract instructions ---*/
315 /*---------------------------------------------------------*/
317 HInstrArray
* newHInstrArray ( void )
319 HInstrArray
* ha
= LibVEX_Alloc_inline(sizeof(HInstrArray
));
322 ha
->arr
= LibVEX_Alloc_inline(ha
->arr_size
* sizeof(HInstr
*));
327 __attribute__((noinline
))
328 void addHInstr_SLOW ( HInstrArray
* ha
, HInstr
* instr
)
330 vassert(ha
->arr_used
== ha
->arr_size
);
332 HInstr
** arr2
= LibVEX_Alloc_inline(ha
->arr_size
* 2 * sizeof(HInstr
*));
333 for (i
= 0; i
< ha
->arr_size
; i
++) {
334 arr2
[i
] = ha
->arr
[i
];
338 addHInstr(ha
, instr
);
342 /*---------------------------------------------------------*/
343 /*--- C-Call return-location actions ---*/
344 /*---------------------------------------------------------*/
346 void ppRetLoc ( RetLoc ska
)
350 vex_printf("RLPri_INVALID"); return;
352 vex_printf("RLPri_None"); return;
354 vex_printf("RLPri_Int"); return;
356 vex_printf("RLPri_2Int"); return;
357 case RLPri_V128SpRel
:
358 vex_printf("RLPri_V128SpRel(%d)", ska
.spOff
); return;
359 case RLPri_V256SpRel
:
360 vex_printf("RLPri_V256SpRel(%d)", ska
.spOff
); return;
367 /*---------------------------------------------------------------*/
368 /*--- end host_generic_regs.c ---*/
369 /*---------------------------------------------------------------*/