1
2 /*---------------------------------------------------------------*/
3 /*--- begin host_generic_regs.h ---*/
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 #ifndef __VEX_HOST_GENERIC_REGS_H
37 #define __VEX_HOST_GENERIC_REGS_H
38
39 #include "libvex_basictypes.h"
40
41
42 /*---------------------------------------------------------*/
43 /*--- Representing HOST REGISTERS ---*/
44 /*---------------------------------------------------------*/
45
46 /* Host registers. Stuff to represent:
47
48 - The register number
49 - The register class
50 - Whether or not the register is a virtual reg.
51
52 Registers are a 32-bit Int, thusly:
53
54 bits 31-28 are the register class.
55 bits 27-23 are 0000b for real register, 0001b for virtual register
56 bits 23-0 register number
57
58 Note (importantly) that by arranging that the class field is never
59 0000b, any valid register looks like an extremely large int -- at
60 least 2^28 -- and so there is little chance of confusing it with an
61 integer array index in the register allocator.
62
63 Note further that since the class field is never 1111b, no valid
64 register can have the value INVALID_HREG.
65
66 There are currently 6 register classes:
67
68 int32 int64 float32 float64 simd64 simd128
69 */
70
71 typedef
72 struct {
73 UInt reg;
74 }
75 HReg;
76
77 /* When extending this, do not use any value > 14 or < 0. */
78 /* HRegClass describes host register classes which the instruction
79 selectors can speak about. We would not expect all of them to be
80 available on any specific host. For example on x86, the available
81 classes are: Int32, Flt64, Vec128 only.
82
83 IMPORTANT NOTE: host_generic_reg_alloc2.c needs how much space is
84 needed to spill each class of register. It allocates the following
85 amount of space:
86
87 HRcInt32 64 bits
88 HRcInt64 64 bits
89 HRcFlt32 64 bits
90 HRcFlt64 128 bits (on x86 these are spilled by fstpt/fldt and
91 so won't fit in a 64-bit slot)
92 HRcVec64 64 bits
93 HRcVec128 128 bits
94
95 If you add another regclass, you must remember to update
96 host_generic_reg_alloc2.c accordingly.
97 */
98 typedef
99 enum {
100 HRcINVALID=1, /* NOT A VALID REGISTER CLASS */
101 HRcInt32=3, /* 32-bit int */
102 HRcInt64=4, /* 64-bit int */
103 HRcFlt32=5, /* 32-bit float */
104 HRcFlt64=6, /* 64-bit float */
105 HRcVec64=7, /* 64-bit SIMD */
106 HRcVec128=8 /* 128-bit SIMD */
107 }
108 HRegClass;
109
110 extern void ppHRegClass ( HRegClass );
111
112
113 /* Print an HReg in a generic (non-target-specific) way. */
114 extern void ppHReg ( HReg );
115
116 /* Construct/destruct. */
mkHReg(UInt regno,HRegClass rc,Bool virtual)117 static inline HReg mkHReg ( UInt regno, HRegClass rc, Bool virtual ) {
118 UInt r24 = regno & 0x00FFFFFF;
119 /* This is critical. The register number field may only
120 occupy 24 bits. */
121 if (r24 != regno)
122 vpanic("mkHReg: regno exceeds 2^24");
123 HReg r;
124 r.reg = regno | (((UInt)rc) << 28) | (virtual ? (1<<24) : 0);
125 return r;
126 }
127
hregClass(HReg r)128 static inline HRegClass hregClass ( HReg r ) {
129 UInt rc = r.reg;
130 rc = (rc >> 28) & 0x0F;
131 vassert(rc >= HRcInt32 && rc <= HRcVec128);
132 return (HRegClass)rc;
133 }
134
hregNumber(HReg r)135 static inline UInt hregNumber ( HReg r ) {
136 return r.reg & 0x00FFFFFF;
137 }
138
hregIsVirtual(HReg r)139 static inline Bool hregIsVirtual ( HReg r ) {
140 return toBool(r.reg & (1<<24));
141 }
142
sameHReg(HReg r1,HReg r2)143 static inline Bool sameHReg ( HReg r1, HReg r2 )
144 {
145 return toBool(r1.reg == r2.reg);
146 }
147
148 static const HReg INVALID_HREG = { 0xFFFFFFFF };
149
hregIsInvalid(HReg r)150 static inline Bool hregIsInvalid ( HReg r )
151 {
152 return sameHReg(r, INVALID_HREG);
153 }
154
155 /*---------------------------------------------------------*/
156 /*--- Recording register usage (for reg-alloc) ---*/
157 /*---------------------------------------------------------*/
158
159 typedef
160 enum { HRmRead, HRmWrite, HRmModify }
161 HRegMode;
162
163
164 /* A struct for recording the usage of registers in instructions.
165 This can get quite large, but we don't expect to allocate them
166 dynamically, so there's no problem.
167 */
168 #define N_HREG_USAGE 25
169
170 typedef
171 struct {
172 HReg hreg[N_HREG_USAGE];
173 HRegMode mode[N_HREG_USAGE];
174 Int n_used;
175 }
176 HRegUsage;
177
178 extern void ppHRegUsage ( HRegUsage* );
179
initHRegUsage(HRegUsage * tab)180 static inline void initHRegUsage ( HRegUsage* tab ) {
181 tab->n_used = 0;
182 }
183
184 /* Add a register to a usage table. Combine incoming read uses with
185 existing write uses into a modify use, and vice versa. Do not
186 create duplicate entries -- each reg should only be mentioned once.
187 */
188 extern void addHRegUse ( HRegUsage*, HRegMode, HReg );
189
190
191
192 /*---------------------------------------------------------*/
193 /*--- Indicating register remappings (for reg-alloc) ---*/
194 /*---------------------------------------------------------*/
195
196 /* Note that such maps can only map virtual regs to real regs.
197 addToHRegRenap will barf if given a pair not of that form. As a
198 result, no valid HRegRemap will bind a real reg to anything, and so
199 if lookupHRegMap is given a real reg, it returns it unchanged.
200 This is precisely the behaviour that the register allocator needs
201 to impose its decisions on the instructions it processes. */
202
203 #define N_HREG_REMAP 6
204
205 typedef
206 struct {
207 HReg orig [N_HREG_REMAP];
208 HReg replacement[N_HREG_REMAP];
209 Int n_used;
210 }
211 HRegRemap;
212
213 extern void ppHRegRemap ( HRegRemap* );
214 extern void initHRegRemap ( HRegRemap* );
215 extern void addToHRegRemap ( HRegRemap*, HReg, HReg );
216 extern HReg lookupHRegRemap ( HRegRemap*, HReg );
217
218
219 /*---------------------------------------------------------*/
220 /*--- Abstract instructions ---*/
221 /*---------------------------------------------------------*/
222
223 /* A type is needed to refer to pointers to instructions of any
224 target. Defining it like this means that HInstr* can stand in for
225 X86Instr*, ArmInstr*, etc. */
226
227 typedef void HInstr;
228
229
230 /* An expandable array of HInstr*'s. Handy for insn selection and
231 register allocation. n_vregs indicates the number of virtual
232 registers mentioned in the code, something that reg-alloc needs to
233 know. These are required to be numbered 0 .. n_vregs-1.
234 */
235 typedef
236 struct {
237 HInstr** arr;
238 Int arr_size;
239 Int arr_used;
240 Int n_vregs;
241 }
242 HInstrArray;
243
244 extern HInstrArray* newHInstrArray ( void );
245 extern void addHInstr ( HInstrArray*, HInstr* );
246
247
248 /*---------------------------------------------------------*/
249 /*--- C-Call return-location descriptions ---*/
250 /*---------------------------------------------------------*/
251
252 /* This is common to all back ends. It describes where the return
253 value from a C call is located. This is important in the case that
254 the call is conditional, since the return locations will need to be
255 set to 0x555..555 in the case that the call does not happen. */
256
257 typedef
258 enum {
259 RLPri_INVALID, /* INVALID */
260 RLPri_None, /* no return value (a.k.a C "void") */
261 RLPri_Int, /* in the primary int return reg */
262 RLPri_2Int, /* in both primary and secondary int ret regs */
263 RLPri_V128SpRel, /* 128-bit value, on the stack */
264 RLPri_V256SpRel /* 256-bit value, on the stack */
265 }
266 RetLocPrimary;
267
268 typedef
269 struct {
270 /* Primary description */
271 RetLocPrimary pri;
272 /* For .pri == RLPri_V128SpRel or RLPri_V256SpRel only, gives
273 the offset of the lowest addressed byte of the value,
274 relative to the stack pointer. For all other .how values,
275 has no meaning and should be zero. */
276 Int spOff;
277 }
278 RetLoc;
279
280 extern void ppRetLoc ( RetLoc rloc );
281
mk_RetLoc_simple(RetLocPrimary pri)282 static inline RetLoc mk_RetLoc_simple ( RetLocPrimary pri ) {
283 vassert(pri >= RLPri_INVALID && pri <= RLPri_2Int);
284 return (RetLoc){pri, 0};
285 }
286
mk_RetLoc_spRel(RetLocPrimary pri,Int off)287 static inline RetLoc mk_RetLoc_spRel ( RetLocPrimary pri, Int off ) {
288 vassert(pri >= RLPri_V128SpRel && pri <= RLPri_V256SpRel);
289 return (RetLoc){pri, off};
290 }
291
is_sane_RetLoc(RetLoc rloc)292 static inline Bool is_sane_RetLoc ( RetLoc rloc ) {
293 switch (rloc.pri) {
294 case RLPri_None: case RLPri_Int: case RLPri_2Int:
295 return rloc.spOff == 0;
296 case RLPri_V128SpRel: case RLPri_V256SpRel:
297 return True;
298 default:
299 return False;
300 }
301 }
302
mk_RetLoc_INVALID(void)303 static inline RetLoc mk_RetLoc_INVALID ( void ) {
304 return (RetLoc){RLPri_INVALID, 0};
305 }
306
is_RetLoc_INVALID(RetLoc rl)307 static inline Bool is_RetLoc_INVALID ( RetLoc rl ) {
308 return rl.pri == RLPri_INVALID && rl.spOff == 0;
309 }
310
311
312 /*---------------------------------------------------------*/
313 /*--- Reg alloc: TODO: move somewhere else ---*/
314 /*---------------------------------------------------------*/
315
316 extern
317 HInstrArray* doRegisterAllocation (
318
319 /* Incoming virtual-registerised code. */
320 HInstrArray* instrs_in,
321
322 /* An array listing all the real registers the allocator may use,
323 in no particular order. */
324 HReg* available_real_regs,
325 Int n_available_real_regs,
326
327 /* Return True iff the given insn is a reg-reg move, in which
328 case also return the src and dst regs. */
329 Bool (*isMove) (HInstr*, HReg*, HReg*),
330
331 /* Get info about register usage in this insn. */
332 void (*getRegUsage) (HRegUsage*, HInstr*, Bool),
333
334 /* Apply a reg-reg mapping to an insn. */
335 void (*mapRegs) (HRegRemap*, HInstr*, Bool),
336
337 /* Return insn(s) to spill/restore a real reg to a spill slot
338 offset. And optionally a function to do direct reloads. */
339 void (*genSpill) ( HInstr**, HInstr**, HReg, Int, Bool ),
340 void (*genReload) ( HInstr**, HInstr**, HReg, Int, Bool ),
341 HInstr* (*directReload) ( HInstr*, HReg, Short ),
342 Int guest_sizeB,
343
344 /* For debug printing only. */
345 void (*ppInstr) ( HInstr*, Bool ),
346 void (*ppReg) ( HReg ),
347
348 /* 32/64bit mode */
349 Bool mode64
350 );
351
352
353 #endif /* ndef __VEX_HOST_GENERIC_REGS_H */
354
355 /*---------------------------------------------------------------*/
356 /*--- host_generic_regs.h ---*/
357 /*---------------------------------------------------------------*/
358