1 /** 2 Copyright: Copyright (c) 2017-2019 Andrey Penechko. 3 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 4 Authors: Andrey Penechko. 5 */ 6 module vox.be.lir_amd64; 7 8 import std.bitmanip : bitfields; 9 import std.stdio; 10 import std.format; 11 12 import vox.all; 13 import vox.be.amd64asm; 14 15 // usage reg_names[physRegClass][physRegSize][physRegIndex] 16 immutable string[][][] reg_names = [[ 17 ["al", "cl", "dl", "bl", "spl","bpl","sil","dil","r8b","r9b","r10b","r11b","r12b","r13b","r14b","r15b"], 18 ["ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w","r9w","r10w","r11w","r12w","r13w","r14w","r15w"], 19 ["eax","ecx","edx","ebx","esp","ebp","esi","edi","r8d","r9d","r10d","r11d","r12d","r13d","r14d","r15d"], 20 ["rax","rcx","rdx","rbx","rsp","rbp","rsi","rdi","r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" ], 21 ], 22 [ 23 ["xmm0b","xmm1b","xmm2b","xmm3b","xmm4b","xmm5b","xmm6b","xmm7b","xmm8b","xmm9b","xmm10b","xmm11b","xmm12b","xmm13b","xmm14b","xmm15b"], // 8 24 ["xmm0w","xmm1w","xmm2w","xmm3w","xmm4w","xmm5w","xmm6w","xmm7w","xmm8w","xmm9w","xmm10w","xmm11w","xmm12w","xmm13w","xmm14w","xmm15w"], // 16 25 ["xmm0d","xmm1d","xmm2d","xmm3d","xmm4d","xmm5d","xmm6d","xmm7d","xmm8d","xmm9d","xmm10d","xmm11d","xmm12d","xmm13d","xmm14d","xmm15d"], // 32 26 ["xmm0q","xmm1q","xmm2q","xmm3q","xmm4q","xmm5q","xmm6q","xmm7q","xmm8q","xmm9q","xmm10q","xmm11q","xmm12q","xmm13q","xmm14q","xmm15q"], // 64 27 ["xmm0","xmm1","xmm2","xmm3","xmm4","xmm5","xmm6","xmm7","xmm8","xmm9","xmm10","xmm11","xmm12","xmm13","xmm14","xmm15"], // 128 28 ["ymm0","ymm1","ymm2","ymm3","ymm4","ymm5","ymm6","ymm7","ymm8","ymm9","ymm10","ymm11","ymm12","ymm13","ymm14","ymm15"], // 256 29 ["zmm0","zmm1","zmm2","zmm3","zmm4","zmm5","zmm6","zmm7","zmm8","zmm9","zmm10","zmm11","zmm12","zmm13","zmm14","zmm15"], // 512 30 ], 31 ]; 32 33 /// Creates physicalRegister index 34 IrIndex amd64Reg(uint index, uint regSize) 35 { 36 IrIndex result; 37 result.storageUintIndex = regSize << 12 | (index & ((1 << 12) - 1)); 38 result.kind = IrValueKind.physicalRegister; 39 return result; 40 } 41 42 uint typeToRegSize(IrIndex type, CompilationContext* context) { 43 uint typeSize = context.types.typeSize(type); 44 switch (typeSize) { 45 case 1: return ArgType.BYTE; 46 case 2: return ArgType.WORD; 47 case 4: return ArgType.DWORD; 48 case 8: return ArgType.QWORD; 49 default: 50 context.internal_error("Type %s of size %s cannot be stored in a register", 51 IrTypeDump(type, *context), typeSize); 52 } 53 } 54 55 struct PhysReg { 56 this(ubyte _regClass, ubyte _regIndex) { 57 regClass = _regClass; 58 regIndex = _regIndex; 59 } 60 61 mixin(bitfields!( 62 uint, "regIndex", 5, 63 uint, "regClass", 3, 64 )); 65 66 void toString(scope void delegate(const(char)[]) sink) { 67 sink.formattedWrite("%s %s %s", regClass, regIndex, regClass*(1<<5) + regIndex); 68 } 69 } 70 71 enum NUM_REG_CLASSES = 2; 72 enum NUM_REGS_PER_CLASS = 32; 73 enum NUM_TOTAL_REGS = NUM_REG_CLASSES * NUM_REGS_PER_CLASS; 74 75 enum AMD64_REG_CLASS : ubyte { 76 GPR = 0, 77 XMM = 1, 78 } 79 80 // Register set of registers of all classes 81 struct FullRegSet { 82 ClassRegSet[NUM_REG_CLASSES] classes; 83 84 ubyte length() { 85 ubyte result; 86 foreach(i, cl; classes) 87 result += classes[i].length; 88 return result; 89 } 90 91 FullRegSet opUnary(string op)() 92 if (op == "~") 93 { 94 FullRegSet result = this; 95 result.classes = ~result.classes[]; 96 return result; 97 } 98 99 FullRegSet opBinary(string op)(FullRegSet rhs) 100 if (op == "|" || op == "^" || op == "&") 101 { 102 FullRegSet result; 103 foreach(i, cl; classes) 104 result.classes[i] = mixin("classes[i] "~op~" rhs.classes[i]"); 105 return result; 106 } 107 108 FullRegSet opBinary(string op)(PhysReg rhs) 109 if (op == "|" || op == "^" || op == "&") 110 { 111 FullRegSet result = this; 112 mixin("result.classes[rhs.regClass].bits "~op~"= 1 << rhs.regIndex;"); 113 return result; 114 } 115 116 void opOpAssign(string op)(FullRegSet rhs) 117 if (op == "|" || op == "^" || op == "&") 118 { 119 foreach(i, cl; classes) 120 classes[i] = mixin("classes[i] "~op~" rhs.classes[i]"); 121 } 122 123 void opOpAssign(string op)(PhysReg rhs) 124 if (op == "|" || op == "^" || op == "&") 125 { 126 mixin("classes[rhs.regClass].bits "~op~"= 1 << rhs.regIndex;"); 127 } 128 129 void disable(PhysReg rhs) 130 { 131 classes[rhs.regClass].bits &= ~(1 << rhs.regIndex); 132 } 133 134 FullRegSet lowest(int n) { 135 FullRegSet result; 136 foreach(i, cl; classes) 137 result.classes[i] = classes[i].lowest(n); 138 return result; 139 } 140 141 int opApply(scope int delegate(PhysReg) dg) 142 { 143 foreach(ubyte regClass; 0..NUM_REG_CLASSES) { 144 uint[1] bits = classes[regClass].bits; 145 foreach(regIndex; bitsSet(bits[])) 146 if (int res = dg(PhysReg(regClass, cast(ubyte)regIndex))) return res; 147 } 148 return 0; 149 } 150 151 int opApply(scope int delegate(uint index, PhysReg) dg) 152 { 153 uint index; 154 foreach(ubyte regClass; 0..NUM_REG_CLASSES) { 155 uint[1] bits = classes[regClass].bits; 156 foreach(regIndex; bitsSet(bits[])) { 157 if (int res = dg(index, PhysReg(regClass, cast(ubyte)regIndex))) return res; 158 ++index; 159 } 160 } 161 return 0; 162 } 163 } 164 165 /// Register set of a single register class 166 struct ClassRegSet { 167 // Assume at most 32 registers per register class 168 uint bits; 169 170 ubyte length() { return cast(ubyte)popcnt(bits); } 171 172 ClassRegSet opBinary(string op)(ClassRegSet rhs) 173 if (op == "|" || op == "^" || op == "&") 174 { 175 return ClassRegSet(mixin("bits "~op~" rhs.bits")); 176 } 177 178 // returns set with lowest n registers 179 ClassRegSet lowest(int n) { 180 uint slotBits = bits; 181 uint result; 182 while (slotBits != 0 && n) { 183 // Extract lowest set isolated bit 184 // 111000 -> 001000; 0 -> 0 185 uint lowestSetBit = slotBits & -slotBits; 186 result |= lowestSetBit; 187 188 // Disable lowest set isolated bit 189 // 111000 -> 110000 190 slotBits ^= lowestSetBit; 191 --n; 192 } 193 return ClassRegSet(result); 194 } 195 196 int opApply(scope int delegate(ubyte) dg) 197 { 198 uint[1] bitsCopy = bits; 199 foreach(regIndex; bitsSet(bitsCopy[])) 200 if (int res = dg(cast(ubyte)regIndex)) return res; 201 return 0; 202 } 203 } 204 205 struct MachineInfo 206 { 207 // total number of registers 208 ubyte numRegisters; 209 // index is register class. Each entry specifies number of registers in this class 210 ubyte[NUM_REG_CLASSES] numRegsPerClass; 211 // first index is register class 212 // second index is register size 213 // third index is register index 214 // Sizes of name arrays must match corresponding regsPerClass 215 immutable string[][][] reg_names; 216 //PhysicalRegister[] registers; 217 InstrInfo[] instrInfo; 218 219 string regName(IrIndex reg) { 220 return reg_names[reg.physRegClass][reg.physRegSize][reg.physRegIndex]; 221 } 222 } 223 224 __gshared MachineInfo mach_info_amd64 = MachineInfo( 225 32, 226 [16, 16], 227 reg_names, 228 amd64InstrInfos.dup 229 ); 230 231 enum amd64_reg : PhysReg { 232 ax = PhysReg(0, 0), 233 cx = PhysReg(0, 1), 234 dx = PhysReg(0, 2), 235 bx = PhysReg(0, 3), 236 sp = PhysReg(0, 4), 237 bp = PhysReg(0, 5), 238 si = PhysReg(0, 6), 239 di = PhysReg(0, 7), 240 r8 = PhysReg(0, 8), 241 r9 = PhysReg(0, 9), 242 r10 = PhysReg(0, 10), 243 r11 = PhysReg(0, 11), 244 r12 = PhysReg(0, 12), 245 r13 = PhysReg(0, 13), 246 r14 = PhysReg(0, 14), 247 r15 = PhysReg(0, 15), 248 249 xmm0 = PhysReg(1, 0), 250 xmm1 = PhysReg(1, 1), 251 xmm2 = PhysReg(1, 2), 252 xmm3 = PhysReg(1, 3), 253 xmm4 = PhysReg(1, 4), 254 xmm5 = PhysReg(1, 5), 255 xmm6 = PhysReg(1, 6), 256 xmm7 = PhysReg(1, 7), 257 xmm8 = PhysReg(1, 8), 258 xmm9 = PhysReg(1, 9), 259 xmm10 = PhysReg(1, 10), 260 xmm11 = PhysReg(1, 11), 261 xmm12 = PhysReg(1, 12), 262 xmm13 = PhysReg(1, 13), 263 xmm14 = PhysReg(1, 14), 264 xmm15 = PhysReg(1, 15), 265 } 266 267 struct CallConv 268 { 269 PhysReg[] gprParamRegs; 270 PhysReg[] sseParamRegs; 271 FullRegSet volatileRegs; 272 FullRegSet calleeSaved; 273 // Size of the register preserved by the callee 274 IrArgSize[] calleeSavedSizePerClass; 275 /// Included into calleeSaved 276 /// Can be used as frame pointer when 277 /// frame pointer is enabled for the function, or 278 /// can be used as allocatable register if not (in which case it is considered as callee saved) 279 PhysReg framePointer; 280 PhysReg stackPointer; 281 282 ubyte minStackAlignmentPower; 283 284 uint flags; 285 286 bool hasShadowSpace() { return cast(bool)(flags & CallConvFlags.hasShadowSpace); } 287 bool hasRedZone() { return cast(bool)(flags & CallConvFlags.hasRedZone); } 288 bool hasReverseStackOrder() { return cast(bool)(flags & CallConvFlags.hasReverseStackOrder); } 289 } 290 291 enum CallConvention : ubyte { 292 win64, 293 sysv64, 294 sysv64_syscall, 295 } 296 297 enum CallConvFlags : uint { 298 hasShadowSpace = 1 << 0, 299 hasRedZone = 1 << 1, 300 /// By default parameters that are passed via stack are passed in left-to-right order 301 /// This means that leftmost parameter has the smallest memory address, and rightmost parameter has biggest address 302 /// If set, parameters are passed right-to-left on the stack 303 hasReverseStackOrder = 1 << 2, 304 } 305 306 __gshared CallConv*[] callConventions = [ 307 &win64_call_conv, 308 &sysv64_call_conv, 309 &sysv64_syscall_call_conv, 310 ]; 311 312 __gshared CallConv win64_call_conv = CallConv 313 ( 314 // parameters in registers 315 [amd64_reg.cx, amd64_reg.dx, amd64_reg.r8, amd64_reg.r9], 316 [amd64_reg.xmm0, amd64_reg.xmm1, amd64_reg.xmm2, amd64_reg.xmm3], 317 318 // volatile regs, zero cost allocation 319 // ax cx dx r8 r9 r10 r11 320 // xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 321 FullRegSet([ 322 // 1111 11 323 // 5432 1098 7654 3210 324 ClassRegSet(0b0000_1111_0000_0111), 325 ClassRegSet(0b0000_0000_0011_1111)]), 326 327 // callee saved regs, need to save/restore to use 328 // bp bx si di r12 r13 r14 r15 329 FullRegSet([ 330 // 1111 11 331 // 5432 1098 7654 3210 332 ClassRegSet(0b1111_0000_1110_1000), 333 ClassRegSet(0b1111_1111_1100_0000)]), 334 335 [IrArgSize.size64, IrArgSize.size128], 336 337 amd64_reg.bp, // frame pointer 338 amd64_reg.sp, // stack pointer 339 340 4, 341 342 CallConvFlags.hasShadowSpace, 343 ); 344 345 __gshared CallConv sysv64_call_conv = CallConv 346 ( 347 // parameters in registers 348 [amd64_reg.di, amd64_reg.si, amd64_reg.dx, amd64_reg.cx, amd64_reg.r8, amd64_reg.r9], 349 [amd64_reg.xmm0, amd64_reg.xmm1, amd64_reg.xmm2, amd64_reg.xmm3, amd64_reg.xmm4, amd64_reg.xmm5, amd64_reg.xmm6, amd64_reg.xmm7], 350 351 // volatile regs, zero cost allocation 352 // ax cx dx si di r8 r9 r10 r11 353 // xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 354 FullRegSet([ 355 // 1111 11 356 // 5432 1098 7654 3210 357 ClassRegSet(0b0000_1111_1100_0111), 358 ClassRegSet(0b1111_1111_1111_1111)]), 359 360 // callee saved regs, need to save/restore to use 361 // bp bx r12 r13 r14 r15 362 FullRegSet([ 363 // 1111 11 364 // 5432 1098 7654 3210 365 ClassRegSet(0b1111_0000_0010_1000), 366 ClassRegSet(0b0000_0000_0000_0000)]), 367 368 [IrArgSize.size64, IrArgSize.size128], 369 370 amd64_reg.bp, // frame pointer 371 amd64_reg.sp, // stack pointer 372 373 4, 374 CallConvFlags.hasRedZone, 375 ); 376 377 __gshared CallConv sysv64_syscall_call_conv = CallConv 378 ( 379 // parameters in registers 380 [amd64_reg.di, amd64_reg.si, amd64_reg.dx, amd64_reg.r10, amd64_reg.r8, amd64_reg.r9], 381 [amd64_reg.xmm0, amd64_reg.xmm1, amd64_reg.xmm2, amd64_reg.xmm3, amd64_reg.xmm4, amd64_reg.xmm5, amd64_reg.xmm6, amd64_reg.xmm7], 382 383 // volatile regs, zero cost allocation 384 // cx and r11 are clobbered by syscall 385 // ax cx dx si di r8 r9 r10 r11 386 // xmm0 xmm1 xmm2 xmm3 xmm4 xmm5 xmm6 xmm7 387 FullRegSet([ 388 // 1111 11 389 // 5432 1098 7654 3210 390 ClassRegSet(0b0000_1111_1100_0111), 391 ClassRegSet(0b1111_1111_1111_1111)]), 392 393 // callee saved regs, need to save/restore to use 394 // bp bx r12 r13 r14 r15 395 FullRegSet([ 396 // 1111 11 397 // 5432 1098 7654 3210 398 ClassRegSet(0b1111_0000_0010_1000), 399 ClassRegSet(0b0000_0000_0000_0000)]), 400 401 [IrArgSize.size64, IrArgSize.size128], 402 403 amd64_reg.bp, // frame pointer 404 amd64_reg.sp, // stack pointer 405 406 4, 407 0, 408 ); 409 410 immutable InstrInfo[] amd64InstrInfos = gatherInstrInfos!Amd64Opcode; 411 412 private alias _ii = InstrInfo; 413 /// 414 enum Amd64Opcode : ushort { 415 @_ii() invalid, 416 @_ii(2,IFLG.hasResult|IFLG.isResultInDst|IFLG.isCommutative) add, // arg0 = arg0 + arg1 417 @_ii(2,IFLG.hasResult|IFLG.isResultInDst) sub, // arg0 = arg0 - arg1 418 @_ii(2,IFLG.hasResult|IFLG.isResultInDst) mul, 419 @_ii(2,IFLG.hasResult|IFLG.isResultInDst|IFLG.isCommutative) imul, 420 @_ii(3,IFLG.hasResult) div, // (dx, ax) = div (dx, ax) / v2 421 @_ii(3,IFLG.hasResult) idiv, // (dx, ax) = div (dx, ax) / v2 422 @_ii(0,IFLG.hasResult) divsx, // CWD/CDQ/CQO 423 @_ii(2,IFLG.hasResult|IFLG.isResultInDst|IFLG.isCommutative) and, 424 @_ii(2,IFLG.hasResult|IFLG.isResultInDst|IFLG.isCommutative) or, 425 @_ii(2,IFLG.hasResult|IFLG.isResultInDst|IFLG.isCommutative) xor, 426 @_ii(2,IFLG.hasResult|IFLG.isResultInDst) shl, 427 @_ii(2,IFLG.hasResult|IFLG.isResultInDst) shr, 428 @_ii(2,IFLG.hasResult|IFLG.isResultInDst) sar, 429 @_ii(2,IFLG.hasResult|IFLG.isResultInDst) lea, 430 431 @_ii(2,IFLG.hasResult|IFLG.isResultInDst|IFLG.isCommutative) fadd, // arg0 = arg0 + arg1 432 @_ii(2,IFLG.hasResult|IFLG.isResultInDst) fsub, // arg0 = arg0 - arg1 433 @_ii(2,IFLG.hasResult|IFLG.isResultInDst|IFLG.isCommutative) fmul, // arg0 = arg0 * arg1 434 @_ii(2,IFLG.hasResult|IFLG.isResultInDst) fdiv, // arg0 = arg0 / arg1 435 436 @_ii(1,IFLG.hasResult|IFLG.isMov) mov, // mov rr/ri 437 @_ii(1,IFLG.hasResult|IFLG.isLoad) load, // mov rm 438 @_ii(2,IFLG.isStore) store, // mov mr/mi 439 440 @_ii(1,IFLG.hasResult) movzx_btow, 441 @_ii(1,IFLG.hasResult) movzx_btod, 442 @_ii(1,IFLG.hasResult) movzx_btoq, 443 @_ii(1,IFLG.hasResult) movzx_wtod, 444 @_ii(1,IFLG.hasResult) movzx_wtoq, 445 446 @_ii(1,IFLG.hasResult) movsx_btow, 447 @_ii(1,IFLG.hasResult) movsx_btod, 448 @_ii(1,IFLG.hasResult) movsx_btoq, 449 @_ii(1,IFLG.hasResult) movsx_wtod, 450 @_ii(1,IFLG.hasResult) movsx_wtoq, 451 @_ii(1,IFLG.hasResult) movsx_dtoq, 452 453 @_ii(1,IFLG.hasResult) f32_to_f64, 454 @_ii(1,IFLG.hasResult) f64_to_f32, 455 456 @_ii(1,IFLG.hasResult) i32_to_f32, 457 @_ii(1,IFLG.hasResult) i64_to_f32, 458 @_ii(1,IFLG.hasResult) i32_to_f64, 459 @_ii(1,IFLG.hasResult) i64_to_f64, 460 @_ii(1,IFLG.hasResult) f32_to_i32_trunc, 461 @_ii(1,IFLG.hasResult) f32_to_i64_trunc, 462 @_ii(1,IFLG.hasResult) f64_to_i32_trunc, 463 @_ii(1,IFLG.hasResult) f64_to_i64_trunc, 464 465 @_ii(1,IFLG.hasResult) f32_to_i32_round, 466 @_ii(1,IFLG.hasResult) f32_to_i64_round, 467 @_ii(1,IFLG.hasResult) f64_to_i32_round, 468 @_ii(1,IFLG.hasResult) f64_to_i64_round, 469 470 @_ii(2) xchg, // xchg mr/mr 471 472 @_ii(1,IFLG.hasResult|IFLG.isResultInDst) not, 473 @_ii(1,IFLG.hasResult|IFLG.isResultInDst) neg, 474 475 @_ii(1,IFLG.hasResult|IFLG.isResultInDst) fneg, 476 477 @_ii(2) cmp, 478 @_ii(1) test, 479 480 // machine specific branches 481 @_ii(0,IFLG.isJump | IFLG.isBlockExit) jmp, 482 @_ii(1,IFLG.isBlockExit) jcc, 483 // high-level branches 484 @_ii(2,IFLG.hasCondition | IFLG.isBranch | IFLG.isBlockExit) bin_branch, 485 @_ii(1,IFLG.hasCondition | IFLG.isBranch | IFLG.isBlockExit) un_branch, 486 @_ii(1,IFLG.hasResult | IFLG.hasCondition) set_unary_cond, 487 @_ii(2,IFLG.hasResult | IFLG.hasCondition) set_binary_cond, 488 489 @_ii(1,IFLG.hasCondition) setcc, 490 491 @_ii(1,IFLG.hasVariadicArgs | IFLG.hasVariadicResult | IFLG.isCall) call, 492 @_ii(1,IFLG.hasVariadicArgs | IFLG.hasVariadicResult | IFLG.isCall) syscall, 493 @_ii(0,IFLG.isBlockExit) ret, 494 495 @_ii(0,IFLG.hasResult) pop, 496 @_ii(1) push, 497 498 @_ii(3) rep_stos, 499 500 @_ii(0,IFLG.isBlockExit) ud2, 501 } 502 503 Condition[] IrBinCondToAmd64Condition = [ 504 Condition.E, // eq 505 Condition.NE, // ne 506 Condition.A, // ugt 507 Condition.AE, // uge 508 Condition.B, // ult 509 Condition.BE, // ule 510 Condition.G, // sgt 511 Condition.GE, // sge 512 Condition.L, // slt 513 Condition.LE, // sle 514 Condition.A, // fgt 515 Condition.AE, // fge 516 Condition.B, // flt 517 Condition.BE, // fle 518 ]; 519 520 Condition[] IrUnCondToAmd64Condition = [ 521 Condition.Z, // zero 522 Condition.NZ, // not_zero 523 ]; 524 525 void dumpAmd64Instr(ref InstrPrintInfo p) 526 { 527 switch(p.instrHeader.op) 528 { 529 case Amd64Opcode.bin_branch: 530 dumpBinBranch(p); 531 break; 532 case Amd64Opcode.un_branch: 533 dumpUnBranch(p); 534 break; 535 case Amd64Opcode.jmp: dumpJmp(p); break; 536 case Amd64Opcode.jcc: 537 p.sink.putf(" j%s %s", 538 cast(Condition)p.instrHeader.cond, 539 IrIndexDump(p.instrHeader.arg(p.ir, 0), p)); 540 break; 541 default: 542 dumpOptionalResult(p); 543 p.sink.putf("%s", cast(Amd64Opcode)p.instrHeader.op); 544 dumpArgs(p); 545 break; 546 } 547 } 548 549 void dumpLirAmd64Index(scope void delegate(const(char)[]) sink, ref CompilationContext context, IrIndex i) 550 { 551 if (!i.isDefined) { 552 sink("<null>"); 553 return; 554 } 555 556 final switch(i.kind) with(IrValueKind) { 557 case none: sink.formattedWrite("0x%X", i.asUint); break; 558 case array: sink.formattedWrite("arr%s", i.storageUintIndex); break; 559 case instruction: sink.formattedWrite("i%s", i.storageUintIndex); break; 560 case basicBlock: sink.formattedWrite("@%s", i.storageUintIndex); break; 561 case constant: 562 final switch(i.constantKind) with(IrConstantKind) { 563 case smallZx: sink.formattedWrite("%s", i.constantIndex); break; 564 case smallSx: sink.formattedWrite("%s", (cast(int)i.constantIndex << 8) >> 8); break; 565 case big: sink.formattedWrite("%s", context.constants.get(i).i64); break; 566 } 567 break; 568 case constantAggregate: sink.formattedWrite("cagg%s", i.storageUintIndex); break; 569 case constantZero: 570 if (i.typeKind == IrTypeKind.basic) 571 sink("0"); 572 else 573 sink("zeroinit"); 574 break; 575 case global: sink.formattedWrite("g%s", i.storageUintIndex); break; 576 case phi: sink.formattedWrite("phi%s", i.storageUintIndex); break; 577 case stackSlot: sink.formattedWrite("s%s", i.storageUintIndex); break; 578 case virtualRegister: sink.formattedWrite("v%s", i.storageUintIndex); break; 579 case physicalRegister: sink(reg_names[i.physRegClass][i.physRegSize][i.physRegIndex]); break; 580 case type: dumpIrType(sink, context, i); break; 581 case variable: assert(false); 582 case func: sink.formattedWrite("f%s", i.storageUintIndex); break; 583 } 584 }