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, write to the Free Software
25 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
28 The GNU General Public License is contained in the file COPYING.
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.
36 #include "libvex_basictypes.h"
39 #include "main_util.h"
40 #include "host_generic_regs.h"
43 /*---------------------------------------------------------*/
44 /*--- Representing HOST REGISTERS ---*/
45 /*---------------------------------------------------------*/
47 void ppHRegClass ( HRegClass 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");
60 /* Generic printing for registers. */
61 UInt
ppHReg ( HReg r
)
63 if (hregIsInvalid(r
)) {
64 return vex_printf("HReg_INVALID");
66 const Bool isV
= hregIsVirtual(r
);
67 const HChar
* maybe_v
= isV
? "v" : "";
68 const UInt regNN
= isV
? hregIndex(r
) : hregEncoding(r
);
69 /* For real registers, we show the encoding. But the encoding is
70 always zero for virtual registers, so that's pointless -- hence
71 show the index number instead. */
72 switch (hregClass(r
)) {
73 case HRcInt32
: return vex_printf("%%%sr%u", maybe_v
, regNN
);
74 case HRcInt64
: return vex_printf("%%%sR%u", maybe_v
, regNN
);
75 case HRcFlt32
: return vex_printf("%%%sF%u", maybe_v
, regNN
);
76 case HRcFlt64
: return vex_printf("%%%sD%u", maybe_v
, regNN
);
77 case HRcVec64
: return vex_printf("%%%sv%u", maybe_v
, regNN
);
78 case HRcVec128
: return vex_printf("%%%sV%u", maybe_v
, regNN
);
79 default: vpanic("ppHReg");
84 /*---------------------------------------------------------*/
85 /*--- Real register Universes. ---*/
86 /*---------------------------------------------------------*/
88 void RRegUniverse__init ( /*OUT*/RRegUniverse
* univ
)
90 *univ
= (RRegUniverse
){};
93 for (UInt i
= 0; i
< N_RREGUNIVERSE_REGS
; i
++) {
94 univ
->regs
[i
] = INVALID_HREG
;
97 for (UInt i
= 0; i
<= HrcLAST
; i
++) {
98 univ
->allocable_start
[i
] = N_RREGUNIVERSE_REGS
;
99 univ
->allocable_end
[i
] = N_RREGUNIVERSE_REGS
;
103 void RRegUniverse__check_is_sane ( const RRegUniverse
* univ
)
105 /* Check Real-Register-Universe invariants. All of these are
107 vassert(univ
->size
> 0);
108 vassert(univ
->size
<= N_RREGUNIVERSE_REGS
);
109 vassert(univ
->allocable
<= univ
->size
);
110 for (UInt i
= 0; i
< univ
->size
; i
++) {
111 HReg reg
= univ
->regs
[i
];
112 vassert(!hregIsInvalid(reg
));
113 vassert(!hregIsVirtual(reg
));
114 vassert(hregIndex(reg
) == i
);
116 for (UInt i
= univ
->size
; i
< N_RREGUNIVERSE_REGS
; i
++) {
117 HReg reg
= univ
->regs
[i
];
118 vassert(hregIsInvalid(reg
));
121 /* Determine register classes used and if they form contiguous range. */
122 Bool regclass_used
[HrcLAST
+ 1];
123 for (UInt i
= 0; i
<= HrcLAST
; i
++) {
124 regclass_used
[i
] = False
;
127 for (UInt i
= 0; i
< univ
->allocable
; i
++) {
128 HReg reg
= univ
->regs
[i
];
129 HRegClass regclass
= hregClass(reg
);
130 if (!regclass_used
[regclass
]) {
131 regclass_used
[regclass
] = True
;
135 UInt regs_visited
= 0;
136 for (UInt i
= 0; i
<= HrcLAST
; i
++) {
137 if (regclass_used
[i
]) {
138 for (UInt j
= univ
->allocable_start
[i
];
139 j
<= univ
->allocable_end
[i
]; j
++) {
140 vassert(hregClass(univ
->regs
[j
]) == i
);
146 vassert(regs_visited
== univ
->allocable
);
150 /*---------------------------------------------------------*/
151 /*--- Helpers for recording reg usage (for reg-alloc) ---*/
152 /*---------------------------------------------------------*/
154 void ppHRegUsage ( const RRegUniverse
* univ
, HRegUsage
* tab
)
156 /* This is going to fail miserably if N_RREGUNIVERSE_REGS exceeds
157 64. So let's cause it to fail in an obvious way. */
158 vassert(N_RREGUNIVERSE_REGS
== 64);
160 vex_printf("HRegUsage {\n");
161 /* First print the real regs */
162 for (UInt i
= 0; i
< N_RREGUNIVERSE_REGS
; i
++) {
163 Bool rRd
= (tab
->rRead
& (1ULL << i
)) != 0;
164 Bool rWr
= (tab
->rWritten
& (1ULL << i
)) != 0;
165 const HChar
* str
= "Modify ";
166 /**/ if (!rRd
&& !rWr
) { continue; }
167 else if ( rRd
&& !rWr
) { str
= "Read "; }
168 else if (!rRd
&& rWr
) { str
= "Write "; }
169 /* else "Modify" is correct */
170 vex_printf(" %s ", str
);
171 ppHReg(univ
->regs
[i
]);
174 /* and now the virtual registers */
175 for (UInt i
= 0; i
< tab
->n_vRegs
; i
++) {
176 const HChar
* str
= NULL
;
177 switch (tab
->vMode
[i
]) {
178 case HRmRead
: str
= "Read "; break;
179 case HRmWrite
: str
= "Write "; break;
180 case HRmModify
: str
= "Modify "; break;
181 default: vpanic("ppHRegUsage");
183 vex_printf(" %s ", str
);
184 ppHReg(tab
->vRegs
[i
]);
187 if (tab
->isRegRegMove
) {
188 vex_printf(" (is a reg-reg move)\n");
194 /* Add a register to a usage table. Combines incoming read uses with
195 existing write uses into a modify use, and vice versa. Does not
196 create duplicate entries -- each reg is only mentioned once.
198 void addHRegUse ( HRegUsage
* tab
, HRegMode mode
, HReg reg
)
200 /* Because real and virtual registers are represented differently,
201 they have completely different paths here. */
202 if (LIKELY(hregIsVirtual(reg
))) {
203 /* Virtual register */
206 for (i
= 0; i
< tab
->n_vRegs
; i
++)
207 if (sameHReg(tab
->vRegs
[i
], reg
))
209 if (i
== tab
->n_vRegs
) {
210 /* Not found, add new entry. */
211 vassert(tab
->n_vRegs
< N_HREGUSAGE_VREGS
);
212 tab
->vRegs
[tab
->n_vRegs
] = reg
;
213 tab
->vMode
[tab
->n_vRegs
] = mode
;
216 /* Found: combine or ignore. */
217 /* This is a greatest-lower-bound operation in the poset:
223 Need to do: tab->mode[i] = GLB(tab->mode, mode). In this
224 case very simple -- if tab->mode[i] != mode then result must
227 if (tab
->vMode
[i
] == mode
) {
228 /* duplicate, ignore */
230 tab
->vMode
[i
] = HRmModify
;
235 UInt ix
= hregIndex(reg
);
236 vassert(ix
< N_RREGUNIVERSE_REGS
);
237 ULong mask
= 1ULL << ix
;
239 case HRmRead
: tab
->rRead
|= mask
; break;
240 case HRmWrite
: tab
->rWritten
|= mask
; break;
241 case HRmModify
: tab
->rRead
|= mask
; tab
->rWritten
|= mask
; break;
247 Bool
HRegUsage__contains ( const HRegUsage
* tab
, HReg reg
)
249 vassert(!hregIsInvalid(reg
));
250 if (hregIsVirtual(reg
)) {
251 for (UInt i
= 0; i
< tab
->n_vRegs
; i
++) {
252 if (sameHReg(reg
, tab
->vRegs
[i
]))
257 UInt ix
= hregIndex(reg
);
258 vassert(ix
< N_RREGUNIVERSE_REGS
);
259 ULong mentioned
= tab
->rRead
| tab
->rWritten
;
260 return (mentioned
& (1ULL << ix
)) != 0;
266 /*---------------------------------------------------------*/
267 /*--- Indicating register remappings (for reg-alloc) ---*/
268 /*---------------------------------------------------------*/
270 void ppHRegRemap ( HRegRemap
* map
)
273 vex_printf("HRegRemap {\n");
274 for (i
= 0; i
< map
->n_used
; i
++) {
276 ppHReg(map
->orig
[i
]);
278 ppHReg(map
->replacement
[i
]);
285 void addToHRegRemap ( HRegRemap
* map
, HReg orig
, HReg replacement
)
288 for (i
= 0; i
< map
->n_used
; i
++)
289 if (sameHReg(map
->orig
[i
], orig
))
290 vpanic("addToHRegMap: duplicate entry");
291 if (!hregIsVirtual(orig
))
292 vpanic("addToHRegMap: orig is not a vreg");
293 if (hregIsVirtual(replacement
))
294 vpanic("addToHRegMap: replacement is a vreg");
296 vassert(map
->n_used
+1 < N_HREG_REMAP
);
297 map
->orig
[map
->n_used
] = orig
;
298 map
->replacement
[map
->n_used
] = replacement
;
303 HReg
lookupHRegRemap ( HRegRemap
* map
, HReg orig
)
306 if (!hregIsVirtual(orig
))
308 for (i
= 0; i
< map
->n_used
; i
++)
309 if (sameHReg(map
->orig
[i
], orig
))
310 return map
->replacement
[i
];
311 vpanic("lookupHRegRemap: not found");
315 /*---------------------------------------------------------*/
316 /*--- Abstract instructions ---*/
317 /*---------------------------------------------------------*/
319 HInstrArray
* newHInstrArray ( void )
321 HInstrArray
* ha
= LibVEX_Alloc_inline(sizeof(HInstrArray
));
324 ha
->arr
= LibVEX_Alloc_inline(ha
->arr_size
* sizeof(HInstr
*));
329 __attribute__((noinline
))
330 void addHInstr_SLOW ( HInstrArray
* ha
, HInstr
* instr
)
332 vassert(ha
->arr_used
== ha
->arr_size
);
334 HInstr
** arr2
= LibVEX_Alloc_inline(ha
->arr_size
* 2 * sizeof(HInstr
*));
335 for (i
= 0; i
< ha
->arr_size
; i
++) {
336 arr2
[i
] = ha
->arr
[i
];
340 addHInstr(ha
, instr
);
344 /*---------------------------------------------------------*/
345 /*--- C-Call return-location actions ---*/
346 /*---------------------------------------------------------*/
348 void ppRetLoc ( RetLoc ska
)
352 vex_printf("RLPri_INVALID"); return;
354 vex_printf("RLPri_None"); return;
356 vex_printf("RLPri_Int"); return;
358 vex_printf("RLPri_2Int"); return;
359 case RLPri_V128SpRel
:
360 vex_printf("RLPri_V128SpRel(%d)", ska
.spOff
); return;
361 case RLPri_V256SpRel
:
362 vex_printf("RLPri_V256SpRel(%d)", ska
.spOff
); return;
369 /*---------------------------------------------------------------*/
370 /*--- end host_generic_regs.c ---*/
371 /*---------------------------------------------------------------*/