sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 1 | |
| 2 | /*---------------------------------------------------------------*/ |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 3 | /*--- begin host_generic_regs.c ---*/ |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 4 | /*---------------------------------------------------------------*/ |
| 5 | |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 6 | /* |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 7 | This file is part of Valgrind, a dynamic binary instrumentation |
| 8 | framework. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 9 | |
Elliott Hughes | ed39800 | 2017-06-21 14:41:24 -0700 | [diff] [blame^] | 10 | Copyright (C) 2004-2017 OpenWorks LLP |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 11 | info@open-works.net |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 12 | |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 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. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 17 | |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 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 |
sewardj | 7bd6ffe | 2005-08-03 16:07:36 +0000 | [diff] [blame] | 26 | 02110-1301, USA. |
| 27 | |
sewardj | 752f906 | 2010-05-03 21:38:49 +0000 | [diff] [blame] | 28 | The GNU General Public License is contained in the file COPYING. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 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. |
sewardj | f8ed9d8 | 2004-11-12 17:40:23 +0000 | [diff] [blame] | 34 | */ |
| 35 | |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 36 | #include "libvex_basictypes.h" |
| 37 | #include "libvex.h" |
| 38 | |
sewardj | cef7d3e | 2009-07-02 12:21:59 +0000 | [diff] [blame] | 39 | #include "main_util.h" |
| 40 | #include "host_generic_regs.h" |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 41 | |
| 42 | |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 43 | /*---------------------------------------------------------*/ |
| 44 | /*--- Representing HOST REGISTERS ---*/ |
| 45 | /*---------------------------------------------------------*/ |
| 46 | |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 47 | void ppHRegClass ( HRegClass hrc ) |
| 48 | { |
| 49 | switch (hrc) { |
sewardj | 4a31b26 | 2004-12-01 02:24:44 +0000 | [diff] [blame] | 50 | case HRcInt32: vex_printf("HRcInt32"); break; |
| 51 | case HRcInt64: vex_printf("HRcInt64"); break; |
sewardj | 6c299f3 | 2009-12-31 18:00:12 +0000 | [diff] [blame] | 52 | case HRcFlt32: vex_printf("HRcFlt32"); break; |
sewardj | 4a31b26 | 2004-12-01 02:24:44 +0000 | [diff] [blame] | 53 | case HRcFlt64: vex_printf("HRcFlt64"); break; |
| 54 | case HRcVec64: vex_printf("HRcVec64"); break; |
| 55 | case HRcVec128: vex_printf("HRcVec128"); break; |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 56 | default: vpanic("ppHRegClass"); |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | /* Generic printing for registers. */ |
| 61 | void ppHReg ( HReg r ) |
| 62 | { |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 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. */ |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 73 | switch (hregClass(r)) { |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 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; |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 80 | default: vpanic("ppHReg"); |
| 81 | } |
| 82 | } |
| 83 | |
| 84 | |
| 85 | /*---------------------------------------------------------*/ |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 86 | /*--- Real register Universes. ---*/ |
| 87 | /*---------------------------------------------------------*/ |
| 88 | |
| 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 | |
| 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 | /*---------------------------------------------------------*/ |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 120 | /*--- Helpers for recording reg usage (for reg-alloc) ---*/ |
| 121 | /*---------------------------------------------------------*/ |
| 122 | |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 123 | void ppHRegUsage ( const RRegUniverse* univ, HRegUsage* tab ) |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 124 | { |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 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 | |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 129 | vex_printf("HRegUsage {\n"); |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 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]) { |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 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); |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 153 | ppHReg(tab->vRegs[i]); |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 154 | vex_printf("\n"); |
| 155 | } |
| 156 | vex_printf("}\n"); |
| 157 | } |
| 158 | |
| 159 | |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 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. |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 163 | */ |
| 164 | void addHRegUse ( HRegUsage* tab, HRegMode mode, HReg reg ) |
| 165 | { |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 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++; |
sewardj | 3f21fd3 | 2005-10-22 12:46:06 +0000 | [diff] [blame] | 181 | } else { |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 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); |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 209 | } |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 210 | } |
| 211 | } |
| 212 | |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 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 | |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 231 | |
| 232 | /*---------------------------------------------------------*/ |
| 233 | /*--- Indicating register remappings (for reg-alloc) ---*/ |
| 234 | /*---------------------------------------------------------*/ |
| 235 | |
| 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 | |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 251 | void addToHRegRemap ( HRegRemap* map, HReg orig, HReg replacement ) |
| 252 | { |
| 253 | Int i; |
| 254 | for (i = 0; i < map->n_used; i++) |
florian | 79efdc6 | 2013-02-11 00:47:35 +0000 | [diff] [blame] | 255 | if (sameHReg(map->orig[i], orig)) |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 256 | vpanic("addToHRegMap: duplicate entry"); |
| 257 | if (!hregIsVirtual(orig)) |
| 258 | vpanic("addToHRegMap: orig is not a vreg"); |
| 259 | if (hregIsVirtual(replacement)) |
florian | 81c22f0 | 2011-08-19 02:58:51 +0000 | [diff] [blame] | 260 | vpanic("addToHRegMap: replacement is a vreg"); |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 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 | |
| 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++) |
florian | 79efdc6 | 2013-02-11 00:47:35 +0000 | [diff] [blame] | 275 | if (sameHReg(map->orig[i], orig)) |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 276 | return map->replacement[i]; |
| 277 | vpanic("lookupHRegRemap: not found"); |
| 278 | } |
| 279 | |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 280 | |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 281 | /*---------------------------------------------------------*/ |
| 282 | /*--- Abstract instructions ---*/ |
| 283 | /*---------------------------------------------------------*/ |
| 284 | |
| 285 | HInstrArray* newHInstrArray ( void ) |
| 286 | { |
florian | d8e3eca | 2015-03-13 12:46:49 +0000 | [diff] [blame] | 287 | HInstrArray* ha = LibVEX_Alloc_inline(sizeof(HInstrArray)); |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 288 | ha->arr_size = 4; |
| 289 | ha->arr_used = 0; |
florian | d8e3eca | 2015-03-13 12:46:49 +0000 | [diff] [blame] | 290 | ha->arr = LibVEX_Alloc_inline(ha->arr_size * sizeof(HInstr*)); |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 291 | ha->n_vregs = 0; |
| 292 | return ha; |
| 293 | } |
| 294 | |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 295 | __attribute__((noinline)) |
| 296 | void addHInstr_SLOW ( HInstrArray* ha, HInstr* instr ) |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 297 | { |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 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]; |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 303 | } |
sewardj | a5b5022 | 2015-03-26 07:18:32 +0000 | [diff] [blame] | 304 | ha->arr_size *= 2; |
| 305 | ha->arr = arr2; |
| 306 | addHInstr(ha, instr); |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 307 | } |
| 308 | |
| 309 | |
sewardj | cfe046e | 2013-01-17 14:23:53 +0000 | [diff] [blame] | 310 | /*---------------------------------------------------------*/ |
| 311 | /*--- C-Call return-location actions ---*/ |
| 312 | /*---------------------------------------------------------*/ |
| 313 | |
| 314 | void ppRetLoc ( RetLoc ska ) |
| 315 | { |
sewardj | 74142b8 | 2013-08-08 10:28:59 +0000 | [diff] [blame] | 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"); |
sewardj | cfe046e | 2013-01-17 14:23:53 +0000 | [diff] [blame] | 331 | } |
| 332 | } |
| 333 | |
| 334 | |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 335 | /*---------------------------------------------------------------*/ |
sewardj | cef7d3e | 2009-07-02 12:21:59 +0000 | [diff] [blame] | 336 | /*--- end host_generic_regs.c ---*/ |
sewardj | a704d35 | 2004-07-10 12:22:40 +0000 | [diff] [blame] | 337 | /*---------------------------------------------------------------*/ |