github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/backend/isa/amd64/instr.go (about) 1 package amd64 2 3 import ( 4 "fmt" 5 6 "github.com/tetratelabs/wazero/internal/engine/wazevo/backend" 7 "github.com/tetratelabs/wazero/internal/engine/wazevo/backend/regalloc" 8 "github.com/tetratelabs/wazero/internal/engine/wazevo/ssa" 9 ) 10 11 type instruction struct { 12 prev, next *instruction 13 op1, op2 operand 14 u1, u2 uint64 15 b1 bool 16 addedBeforeRegAlloc bool 17 kind instructionKind 18 } 19 20 // Next implements regalloc.Instr. 21 func (i *instruction) Next() regalloc.Instr { 22 return i.next 23 } 24 25 // Prev implements regalloc.Instr. 26 func (i *instruction) Prev() regalloc.Instr { 27 return i.prev 28 } 29 30 // IsCall implements regalloc.Instr. 31 func (i *instruction) IsCall() bool { return i.kind == call } 32 33 // IsIndirectCall implements regalloc.Instr. 34 func (i *instruction) IsIndirectCall() bool { return i.kind == callIndirect } 35 36 // IsReturn implements regalloc.Instr. 37 func (i *instruction) IsReturn() bool { return i.kind == ret } 38 39 // AddedBeforeRegAlloc implements regalloc.Instr. 40 func (i *instruction) AddedBeforeRegAlloc() bool { return i.addedBeforeRegAlloc } 41 42 // String implements regalloc.Instr. 43 func (i *instruction) String() string { 44 switch i.kind { 45 case nop0: 46 return "nop" 47 case sourceOffsetInfo: 48 return fmt.Sprintf("source_offset_info %d", i.u1) 49 case ret: 50 return "ret" 51 case imm: 52 if i.b1 { 53 return fmt.Sprintf("movabsq $%d, %s", int64(i.u1), i.op2.format(true)) 54 } else { 55 return fmt.Sprintf("movl $%d, %s", int32(i.u1), i.op2.format(false)) 56 } 57 case aluRmiR: 58 return fmt.Sprintf("%s %s, %s", aluRmiROpcode(i.u1), i.op1.format(i.b1), i.op2.format(i.b1)) 59 case movRR: 60 if i.b1 { 61 return fmt.Sprintf("movq %s, %s", i.op1.format(true), i.op2.format(true)) 62 } else { 63 return fmt.Sprintf("movl %s, %s", i.op1.format(false), i.op2.format(false)) 64 } 65 case xmmRmR: 66 return fmt.Sprintf("%s %s, %s", sseOpcode(i.u1), i.op1.format(false), i.op2.format(false)) 67 case gprToXmm: 68 return fmt.Sprintf("%s %s, %s", sseOpcode(i.u1), i.op1.format(i.b1), i.op2.format(i.b1)) 69 case xmmUnaryRmR: 70 return fmt.Sprintf("%s %s, %s", sseOpcode(i.u1), i.op1.format(false), i.op2.format(false)) 71 case xmmUnaryRmRImm: 72 return fmt.Sprintf("%s $%d, %s, %s", sseOpcode(i.u1), roundingMode(i.u2), i.op1.format(false), i.op2.format(false)) 73 case unaryRmR: 74 var suffix string 75 if i.b1 { 76 suffix = "q" 77 } else { 78 suffix = "l" 79 } 80 return fmt.Sprintf("%s%s %s, %s", unaryRmROpcode(i.u1), suffix, i.op1.format(i.b1), i.op2.format(i.b1)) 81 case not: 82 var op string 83 if i.b1 { 84 op = "notq" 85 } else { 86 op = "notl" 87 } 88 return fmt.Sprintf("%s %s", op, i.op1.format(i.b1)) 89 case neg: 90 var op string 91 if i.b1 { 92 op = "negq" 93 } else { 94 op = "negl" 95 } 96 return fmt.Sprintf("%s %s", op, i.op1.format(i.b1)) 97 case div: 98 var prefix string 99 var op string 100 if i.b1 { 101 op = "divq" 102 } else { 103 op = "divl" 104 } 105 if i.u1 != 0 { 106 prefix = "i" 107 } 108 return fmt.Sprintf("%s%s %s", prefix, op, i.op1.format(i.b1)) 109 case mulHi: 110 signed, _64 := i.u1 != 0, i.b1 111 var op string 112 switch { 113 case signed && _64: 114 op = "imulq" 115 case !signed && _64: 116 op = "mulq" 117 case signed && !_64: 118 op = "imull" 119 case !signed && !_64: 120 op = "mull" 121 } 122 return fmt.Sprintf("%s %s", op, i.op1.format(i.b1)) 123 case signExtendData: 124 var op string 125 if i.b1 { 126 op = "cqo" 127 } else { 128 op = "cdq" 129 } 130 return op 131 case movzxRmR: 132 return fmt.Sprintf("movzx.%s %s, %s", extMode(i.u1), i.op1.format(true), i.op2.format(true)) 133 case mov64MR: 134 return fmt.Sprintf("movq %s, %s", i.op1.format(true), i.op2.format(true)) 135 case lea: 136 return fmt.Sprintf("lea %s, %s", i.op1.format(true), i.op2.format(true)) 137 case movsxRmR: 138 return fmt.Sprintf("movsx.%s %s, %s", extMode(i.u1), i.op1.format(true), i.op2.format(true)) 139 case movRM: 140 var suffix string 141 switch i.u1 { 142 case 1: 143 suffix = "b" 144 case 2: 145 suffix = "w" 146 case 4: 147 suffix = "l" 148 case 8: 149 suffix = "q" 150 } 151 return fmt.Sprintf("mov.%s %s, %s", suffix, i.op1.format(true), i.op2.format(true)) 152 case shiftR: 153 var suffix string 154 if i.b1 { 155 suffix = "q" 156 } else { 157 suffix = "l" 158 } 159 return fmt.Sprintf("%s%s %s, %s", shiftROp(i.u1), suffix, i.op1.format(false), i.op2.format(i.b1)) 160 case xmmRmiReg: 161 return fmt.Sprintf("%s %s, %s", sseOpcode(i.u1), i.op1.format(true), i.op2.format(true)) 162 case cmpRmiR: 163 var op, suffix string 164 if i.u1 != 0 { 165 op = "cmp" 166 } else { 167 op = "test" 168 } 169 if i.b1 { 170 suffix = "q" 171 } else { 172 suffix = "l" 173 } 174 if op == "test" && i.op1.kind == operandKindMem { 175 // Print consistently with AT&T syntax. 176 return fmt.Sprintf("%s%s %s, %s", op, suffix, i.op2.format(i.b1), i.op1.format(i.b1)) 177 } 178 return fmt.Sprintf("%s%s %s, %s", op, suffix, i.op1.format(i.b1), i.op2.format(i.b1)) 179 case setcc: 180 return fmt.Sprintf("set%s %s", cond(i.u1), i.op2.format(true)) 181 case cmove: 182 var suffix string 183 if i.b1 { 184 suffix = "q" 185 } else { 186 suffix = "l" 187 } 188 return fmt.Sprintf("cmov%s%s %s, %s", cond(i.u1), suffix, i.op1.format(i.b1), i.op2.format(i.b1)) 189 case push64: 190 return fmt.Sprintf("pushq %s", i.op1.format(true)) 191 case pop64: 192 return fmt.Sprintf("popq %s", i.op1.format(true)) 193 case xmmMovRM: 194 return fmt.Sprintf("%s %s, %s", sseOpcode(i.u1), i.op1.format(true), i.op2.format(true)) 195 case xmmLoadConst: 196 panic("TODO") 197 case xmmToGpr: 198 return fmt.Sprintf("%s %s, %s", sseOpcode(i.u1), i.op1.format(i.b1), i.op2.format(i.b1)) 199 case cvtUint64ToFloatSeq: 200 panic("TODO") 201 case cvtFloatToSintSeq: 202 panic("TODO") 203 case cvtFloatToUintSeq: 204 panic("TODO") 205 case xmmMinMaxSeq: 206 panic("TODO") 207 case xmmCmpRmR: 208 return fmt.Sprintf("%s %s, %s", sseOpcode(i.u1), i.op1.format(false), i.op2.format(false)) 209 case xmmRmRImm: 210 op := sseOpcode(i.u1) 211 r1, r2 := i.op1.format(op == sseOpcodePextrq || op == sseOpcodePinsrq), 212 i.op2.format(op == sseOpcodePextrq || op == sseOpcodePinsrq) 213 return fmt.Sprintf("%s $%d, %s, %s", op, i.u2, r1, r2) 214 case jmp: 215 return fmt.Sprintf("jmp %s", i.op1.format(true)) 216 case jmpIf: 217 return fmt.Sprintf("j%s %s", cond(i.u1), i.op1.format(true)) 218 case jmpTableIsland: 219 return fmt.Sprintf("jump_table_island: jmp_table_index=%d", i.u1) 220 case exitSequence: 221 return fmt.Sprintf("exit_sequence %s", i.op1.format(true)) 222 case ud2: 223 return "ud2" 224 case call: 225 return fmt.Sprintf("call %s", ssa.FuncRef(i.u1)) 226 case callIndirect: 227 return fmt.Sprintf("callq *%s", i.op1.format(true)) 228 case xchg: 229 var suffix string 230 switch i.u1 { 231 case 1: 232 suffix = "b" 233 case 2: 234 suffix = "w" 235 case 4: 236 suffix = "l" 237 case 8: 238 suffix = "q" 239 } 240 return fmt.Sprintf("xchg.%s %s, %s", suffix, i.op1.format(true), i.op2.format(true)) 241 case zeros: 242 return fmt.Sprintf("xor %s, %s", i.op2.format(true), i.op2.format(true)) 243 case fcvtToSintSequence: 244 execCtx, src, tmpGp, tmpGp2, tmpXmm, src64, dst64, sat := i.fcvtToSintSequenceData() 245 return fmt.Sprintf( 246 "fcvtToSintSequence execCtx=%s, src=%s, tmpGp=%s, tmpGp2=%s, tmpXmm=%s, src64=%v, dst64=%v, sat=%v", 247 formatVRegSized(execCtx, true), 248 formatVRegSized(src, true), 249 formatVRegSized(tmpGp, true), 250 formatVRegSized(tmpGp2, true), 251 formatVRegSized(tmpXmm, true), src64, dst64, sat) 252 case fcvtToUintSequence: 253 execCtx, src, tmpGp, tmpGp2, tmpXmm, tmpXmm2, src64, dst64, sat := i.fcvtToUintSequenceData() 254 return fmt.Sprintf( 255 "fcvtToUintSequence execCtx=%s, src=%s, tmpGp=%s, tmpGp2=%s, tmpXmm=%s, tmpXmm2=%s, src64=%v, dst64=%v, sat=%v", 256 formatVRegSized(execCtx, true), 257 formatVRegSized(src, true), 258 formatVRegSized(tmpGp, true), 259 formatVRegSized(tmpGp2, true), 260 formatVRegSized(tmpXmm, true), 261 formatVRegSized(tmpXmm2, true), src64, dst64, sat) 262 case idivRemSequence: 263 execCtx, divisor, tmpGp, isDiv, signed, _64 := i.idivRemSequenceData() 264 return fmt.Sprintf("idivRemSequence execCtx=%s, divisor=%s, tmpGp=%s, isDiv=%v, signed=%v, _64=%v", 265 formatVRegSized(execCtx, true), formatVRegSized(divisor, _64), formatVRegSized(tmpGp, _64), isDiv, signed, _64) 266 case defineUninitializedReg: 267 return fmt.Sprintf("defineUninitializedReg %s", i.op2.format(true)) 268 case xmmCMov: 269 return fmt.Sprintf("xmmcmov%s %s, %s", cond(i.u1), i.op1.format(true), i.op2.format(true)) 270 case blendvpd: 271 return fmt.Sprintf("blendvpd %s, %s, %%xmm0", i.op1.format(false), i.op2.format(false)) 272 case mfence: 273 return "mfence" 274 case lockcmpxchg: 275 var suffix string 276 switch i.u1 { 277 case 1: 278 suffix = "b" 279 case 2: 280 suffix = "w" 281 case 4: 282 suffix = "l" 283 case 8: 284 suffix = "q" 285 } 286 return fmt.Sprintf("lock cmpxchg.%s %s, %s", suffix, i.op1.format(true), i.op2.format(true)) 287 case lockxadd: 288 var suffix string 289 switch i.u1 { 290 case 1: 291 suffix = "b" 292 case 2: 293 suffix = "w" 294 case 4: 295 suffix = "l" 296 case 8: 297 suffix = "q" 298 } 299 return fmt.Sprintf("lock xadd.%s %s, %s", suffix, i.op1.format(true), i.op2.format(true)) 300 301 case nopUseReg: 302 return fmt.Sprintf("nop_use_reg %s", i.op1.format(true)) 303 304 default: 305 panic(fmt.Sprintf("BUG: %d", int(i.kind))) 306 } 307 } 308 309 // Defs implements regalloc.Instr. 310 func (i *instruction) Defs(regs *[]regalloc.VReg) []regalloc.VReg { 311 *regs = (*regs)[:0] 312 switch dk := defKinds[i.kind]; dk { 313 case defKindNone: 314 case defKindOp2: 315 *regs = append(*regs, i.op2.reg()) 316 case defKindCall: 317 _, _, retIntRealRegs, retFloatRealRegs, _ := backend.ABIInfoFromUint64(i.u2) 318 for i := byte(0); i < retIntRealRegs; i++ { 319 *regs = append(*regs, regInfo.RealRegToVReg[intArgResultRegs[i]]) 320 } 321 for i := byte(0); i < retFloatRealRegs; i++ { 322 *regs = append(*regs, regInfo.RealRegToVReg[floatArgResultRegs[i]]) 323 } 324 case defKindDivRem: 325 _, _, _, isDiv, _, _ := i.idivRemSequenceData() 326 if isDiv { 327 *regs = append(*regs, raxVReg) 328 } else { 329 *regs = append(*regs, rdxVReg) 330 } 331 default: 332 panic(fmt.Sprintf("BUG: invalid defKind \"%s\" for %s", dk, i)) 333 } 334 return *regs 335 } 336 337 // Uses implements regalloc.Instr. 338 func (i *instruction) Uses(regs *[]regalloc.VReg) []regalloc.VReg { 339 *regs = (*regs)[:0] 340 switch uk := useKinds[i.kind]; uk { 341 case useKindNone: 342 case useKindOp1Op2Reg, useKindOp1RegOp2: 343 opAny, opReg := &i.op1, &i.op2 344 if uk == useKindOp1RegOp2 { 345 opAny, opReg = opReg, opAny 346 } 347 // The destination operand (op2) can be only reg, 348 // the source operand (op1) can be imm32, reg or mem. 349 switch opAny.kind { 350 case operandKindReg: 351 *regs = append(*regs, opAny.reg()) 352 case operandKindMem: 353 opAny.addressMode().uses(regs) 354 case operandKindImm32: 355 default: 356 panic(fmt.Sprintf("BUG: invalid operand: %s", i)) 357 } 358 if opReg.kind != operandKindReg { 359 panic(fmt.Sprintf("BUG: invalid operand: %s", i)) 360 } 361 *regs = append(*regs, opReg.reg()) 362 case useKindOp1: 363 op := i.op1 364 switch op.kind { 365 case operandKindReg: 366 *regs = append(*regs, op.reg()) 367 case operandKindMem: 368 op.addressMode().uses(regs) 369 case operandKindImm32, operandKindLabel: 370 default: 371 panic(fmt.Sprintf("BUG: invalid operand: %s", i)) 372 } 373 case useKindCallInd: 374 op := i.op1 375 switch op.kind { 376 case operandKindReg: 377 *regs = append(*regs, op.reg()) 378 case operandKindMem: 379 op.addressMode().uses(regs) 380 default: 381 panic(fmt.Sprintf("BUG: invalid operand: %s", i)) 382 } 383 fallthrough 384 case useKindCall: 385 argIntRealRegs, argFloatRealRegs, _, _, _ := backend.ABIInfoFromUint64(i.u2) 386 for i := byte(0); i < argIntRealRegs; i++ { 387 *regs = append(*regs, regInfo.RealRegToVReg[intArgResultRegs[i]]) 388 } 389 for i := byte(0); i < argFloatRealRegs; i++ { 390 *regs = append(*regs, regInfo.RealRegToVReg[floatArgResultRegs[i]]) 391 } 392 case useKindFcvtToSintSequence: 393 execCtx, src, tmpGp, tmpGp2, tmpXmm, _, _, _ := i.fcvtToSintSequenceData() 394 *regs = append(*regs, execCtx, src, tmpGp, tmpGp2, tmpXmm) 395 case useKindFcvtToUintSequence: 396 execCtx, src, tmpGp, tmpGp2, tmpXmm, tmpXmm2, _, _, _ := i.fcvtToUintSequenceData() 397 *regs = append(*regs, execCtx, src, tmpGp, tmpGp2, tmpXmm, tmpXmm2) 398 case useKindDivRem: 399 execCtx, divisor, tmpGp, _, _, _ := i.idivRemSequenceData() 400 // idiv uses rax and rdx as implicit operands. 401 *regs = append(*regs, raxVReg, rdxVReg, execCtx, divisor, tmpGp) 402 case useKindBlendvpd: 403 *regs = append(*regs, xmm0VReg) 404 405 opAny, opReg := &i.op1, &i.op2 406 switch opAny.kind { 407 case operandKindReg: 408 *regs = append(*regs, opAny.reg()) 409 case operandKindMem: 410 opAny.addressMode().uses(regs) 411 default: 412 panic(fmt.Sprintf("BUG: invalid operand: %s", i)) 413 } 414 if opReg.kind != operandKindReg { 415 panic(fmt.Sprintf("BUG: invalid operand: %s", i)) 416 } 417 *regs = append(*regs, opReg.reg()) 418 419 case useKindRaxOp1RegOp2: 420 opReg, opAny := &i.op1, &i.op2 421 *regs = append(*regs, raxVReg, opReg.reg()) 422 switch opAny.kind { 423 case operandKindReg: 424 *regs = append(*regs, opAny.reg()) 425 case operandKindMem: 426 opAny.addressMode().uses(regs) 427 default: 428 panic(fmt.Sprintf("BUG: invalid operand: %s", i)) 429 } 430 if opReg.kind != operandKindReg { 431 panic(fmt.Sprintf("BUG: invalid operand: %s", i)) 432 } 433 434 default: 435 panic(fmt.Sprintf("BUG: invalid useKind %s for %s", uk, i)) 436 } 437 return *regs 438 } 439 440 // AssignUse implements regalloc.Instr. 441 func (i *instruction) AssignUse(index int, v regalloc.VReg) { 442 switch uk := useKinds[i.kind]; uk { 443 case useKindNone: 444 case useKindCallInd: 445 if index != 0 { 446 panic("BUG") 447 } 448 op := &i.op1 449 switch op.kind { 450 case operandKindReg: 451 op.setReg(v) 452 case operandKindMem: 453 op.addressMode().assignUses(index, v) 454 default: 455 panic("BUG") 456 } 457 case useKindOp1Op2Reg, useKindOp1RegOp2: 458 op, opMustBeReg := &i.op1, &i.op2 459 if uk == useKindOp1RegOp2 { 460 op, opMustBeReg = opMustBeReg, op 461 } 462 switch op.kind { 463 case operandKindReg: 464 if index == 0 { 465 op.setReg(v) 466 } else if index == 1 { 467 opMustBeReg.setReg(v) 468 } else { 469 panic("BUG") 470 } 471 case operandKindMem: 472 nregs := op.addressMode().nregs() 473 if index < nregs { 474 op.addressMode().assignUses(index, v) 475 } else if index == nregs { 476 opMustBeReg.setReg(v) 477 } else { 478 panic("BUG") 479 } 480 case operandKindImm32: 481 if index == 0 { 482 opMustBeReg.setReg(v) 483 } else { 484 panic("BUG") 485 } 486 default: 487 panic(fmt.Sprintf("BUG: invalid operand pair: %s", i)) 488 } 489 case useKindOp1: 490 op := &i.op1 491 switch op.kind { 492 case operandKindReg: 493 if index != 0 { 494 panic("BUG") 495 } 496 op.setReg(v) 497 case operandKindMem: 498 op.addressMode().assignUses(index, v) 499 default: 500 panic(fmt.Sprintf("BUG: invalid operand: %s", i)) 501 } 502 case useKindFcvtToSintSequence: 503 switch index { 504 case 0: 505 i.op1.addressMode().base = v 506 case 1: 507 i.op1.addressMode().index = v 508 case 2: 509 i.op2.addressMode().base = v 510 case 3: 511 i.op2.addressMode().index = v 512 case 4: 513 i.u1 = uint64(v) 514 default: 515 panic("BUG") 516 } 517 case useKindFcvtToUintSequence: 518 switch index { 519 case 0: 520 i.op1.addressMode().base = v 521 case 1: 522 i.op1.addressMode().index = v 523 case 2: 524 i.op2.addressMode().base = v 525 case 3: 526 i.op2.addressMode().index = v 527 case 4: 528 i.u1 = uint64(v) 529 case 5: 530 i.u2 = uint64(v) 531 default: 532 panic("BUG") 533 } 534 case useKindDivRem: 535 switch index { 536 case 0: 537 if v != raxVReg { 538 panic("BUG") 539 } 540 case 1: 541 if v != rdxVReg { 542 panic("BUG") 543 } 544 case 2: 545 i.op1.setReg(v) 546 case 3: 547 i.op2.setReg(v) 548 case 4: 549 i.u1 = uint64(v) 550 default: 551 panic("BUG") 552 } 553 case useKindBlendvpd: 554 op, opMustBeReg := &i.op1, &i.op2 555 if index == 0 { 556 if v.RealReg() != xmm0 { 557 panic("BUG") 558 } 559 } else { 560 switch op.kind { 561 case operandKindReg: 562 switch index { 563 case 1: 564 op.setReg(v) 565 case 2: 566 opMustBeReg.setReg(v) 567 default: 568 panic("BUG") 569 } 570 case operandKindMem: 571 nregs := op.addressMode().nregs() 572 index-- 573 if index < nregs { 574 op.addressMode().assignUses(index, v) 575 } else if index == nregs { 576 opMustBeReg.setReg(v) 577 } else { 578 panic("BUG") 579 } 580 default: 581 panic(fmt.Sprintf("BUG: invalid operand pair: %s", i)) 582 } 583 } 584 585 case useKindRaxOp1RegOp2: 586 switch index { 587 case 0: 588 if v.RealReg() != rax { 589 panic("BUG") 590 } 591 case 1: 592 i.op1.setReg(v) 593 default: 594 op := &i.op2 595 switch op.kind { 596 case operandKindReg: 597 switch index { 598 case 1: 599 op.setReg(v) 600 case 2: 601 op.setReg(v) 602 default: 603 panic("BUG") 604 } 605 case operandKindMem: 606 nregs := op.addressMode().nregs() 607 index -= 2 608 if index < nregs { 609 op.addressMode().assignUses(index, v) 610 } else if index == nregs { 611 op.setReg(v) 612 } else { 613 panic("BUG") 614 } 615 default: 616 panic(fmt.Sprintf("BUG: invalid operand pair: %s", i)) 617 } 618 } 619 default: 620 panic(fmt.Sprintf("BUG: invalid useKind %s for %s", uk, i)) 621 } 622 } 623 624 // AssignDef implements regalloc.Instr. 625 func (i *instruction) AssignDef(reg regalloc.VReg) { 626 switch dk := defKinds[i.kind]; dk { 627 case defKindNone: 628 case defKindOp2: 629 i.op2.setReg(reg) 630 default: 631 panic(fmt.Sprintf("BUG: invalid defKind \"%s\" for %s", dk, i)) 632 } 633 } 634 635 // IsCopy implements regalloc.Instr. 636 func (i *instruction) IsCopy() bool { 637 k := i.kind 638 if k == movRR { 639 return true 640 } 641 if k == xmmUnaryRmR { 642 if i.op1.kind == operandKindReg { 643 sse := sseOpcode(i.u1) 644 return sse == sseOpcodeMovss || sse == sseOpcodeMovsd || sse == sseOpcodeMovdqu 645 } 646 } 647 return false 648 } 649 650 func resetInstruction(i *instruction) { 651 *i = instruction{} 652 } 653 654 func setNext(i *instruction, next *instruction) { 655 i.next = next 656 } 657 658 func setPrev(i *instruction, prev *instruction) { 659 i.prev = prev 660 } 661 662 func asNop(i *instruction) { 663 i.kind = nop0 664 } 665 666 func (i *instruction) asNop0WithLabel(label backend.Label) *instruction { //nolint 667 i.kind = nop0 668 i.u1 = uint64(label) 669 return i 670 } 671 672 func (i *instruction) nop0Label() backend.Label { 673 return backend.Label(i.u1) 674 } 675 676 type instructionKind byte 677 678 const ( 679 nop0 instructionKind = iota + 1 680 681 // Integer arithmetic/bit-twiddling: (add sub and or xor mul, etc.) (32 64) (reg addr imm) reg 682 aluRmiR 683 684 // Instructions on GPR that only read src and defines dst (dst is not modified): bsr, etc. 685 unaryRmR 686 687 // Bitwise not 688 not 689 690 // Integer negation 691 neg 692 693 // Integer quotient and remainder: (div idiv) $rax $rdx (reg addr) 694 div 695 696 // The high bits (RDX) of a (un)signed multiply: RDX:RAX := RAX * rhs. 697 mulHi 698 699 // Do a sign-extend based on the sign of the value in rax into rdx: (cwd cdq cqo) 700 // or al into ah: (cbw) 701 signExtendData 702 703 // Constant materialization: (imm32 imm64) reg. 704 // Either: movl $imm32, %reg32 or movabsq $imm64, %reg64. 705 imm 706 707 // GPR to GPR move: mov (64 32) reg reg. 708 movRR 709 710 // movzxRmR is zero-extended loads or move (R to R), except for 64 bits: movz (bl bq wl wq lq) addr reg. 711 // Note that the lq variant doesn't really exist since the default zero-extend rule makes it 712 // unnecessary. For that case we emit the equivalent "movl AM, reg32". 713 movzxRmR 714 715 // mov64MR is a plain 64-bit integer load, since movzxRmR can't represent that. 716 mov64MR 717 718 // Loads the memory address of addr into dst. 719 lea 720 721 // Sign-extended loads and moves: movs (bl bq wl wq lq) addr reg. 722 movsxRmR 723 724 // Integer stores: mov (b w l q) reg addr. 725 movRM 726 727 // Arithmetic shifts: (shl shr sar) (b w l q) imm reg. 728 shiftR 729 730 // Arithmetic SIMD shifts. 731 xmmRmiReg 732 733 // Integer comparisons/tests: cmp or test (b w l q) (reg addr imm) reg. 734 cmpRmiR 735 736 // Materializes the requested condition code in the destination reg. 737 setcc 738 739 // Integer conditional move. 740 // Overwrites the destination register. 741 cmove 742 743 // pushq (reg addr imm) 744 push64 745 746 // popq reg 747 pop64 748 749 // XMM (scalar or vector) binary op: (add sub and or xor mul adc? sbb?) (32 64) (reg addr) reg 750 xmmRmR 751 752 // XMM (scalar or vector) unary op: mov between XMM registers (32 64) (reg addr) reg. 753 // 754 // This differs from xmmRmR in that the dst register of xmmUnaryRmR is not used in the 755 // computation of the instruction dst value and so does not have to be a previously valid 756 // value. This is characteristic of mov instructions. 757 xmmUnaryRmR 758 759 // XMM (scalar or vector) unary op with immediate: roundss, roundsd, etc. 760 // 761 // This differs from XMM_RM_R_IMM in that the dst register of 762 // XmmUnaryRmRImm is not used in the computation of the instruction dst 763 // value and so does not have to be a previously valid value. 764 xmmUnaryRmRImm 765 766 // XMM (scalar or vector) unary op (from xmm to mem): stores, movd, movq 767 xmmMovRM 768 769 // XMM (vector) unary op (to move a constant value into an xmm register): movups 770 xmmLoadConst 771 772 // XMM (scalar) unary op (from xmm to integer reg): movd, movq, cvtts{s,d}2si 773 xmmToGpr 774 775 // XMM (scalar) unary op (from integer to float reg): movd, movq, cvtsi2s{s,d} 776 gprToXmm 777 778 // Converts an unsigned int64 to a float32/float64. 779 cvtUint64ToFloatSeq 780 781 // Converts a scalar xmm to a signed int32/int64. 782 cvtFloatToSintSeq 783 784 // Converts a scalar xmm to an unsigned int32/int64. 785 cvtFloatToUintSeq 786 787 // A sequence to compute min/max with the proper NaN semantics for xmm registers. 788 xmmMinMaxSeq 789 790 // Float comparisons/tests: cmp (b w l q) (reg addr imm) reg. 791 xmmCmpRmR 792 793 // A binary XMM instruction with an 8-bit immediate: e.g. cmp (ps pd) imm (reg addr) reg 794 xmmRmRImm 795 796 // Direct call: call simm32. 797 // Note that the offset is the relative to the *current RIP*, which points to the first byte of the next instruction. 798 call 799 800 // Indirect call: callq (reg mem). 801 callIndirect 802 803 // Return. 804 ret 805 806 // Jump: jmp (reg, mem, imm32 or label) 807 jmp 808 809 // Jump conditionally: jcond cond label. 810 jmpIf 811 812 // jmpTableIsland is to emit the jump table. 813 jmpTableIsland 814 815 // exitSequence exits the execution and go back to the Go world. 816 exitSequence 817 818 // An instruction that will always trigger the illegal instruction exception. 819 ud2 820 821 // xchg is described in https://www.felixcloutier.com/x86/xchg. 822 // This instruction uses two operands, where one of them can be a memory address, and swaps their values. 823 // If the dst is a memory address, the execution is atomic. 824 xchg 825 826 // lockcmpxchg is the cmpxchg instruction https://www.felixcloutier.com/x86/cmpxchg with a lock prefix. 827 lockcmpxchg 828 829 // zeros puts zeros into the destination register. This is implemented as xor reg, reg for 830 // either integer or XMM registers. The reason why we have this instruction instead of using aluRmiR 831 // is that it requires the already-defined registers. From reg alloc's perspective, this defines 832 // the destination register and takes no inputs. 833 zeros 834 835 // sourceOffsetInfo is a dummy instruction to emit source offset info. 836 // The existence of this instruction does not affect the execution. 837 sourceOffsetInfo 838 839 // defineUninitializedReg is a no-op instruction that defines a register without a defining instruction. 840 defineUninitializedReg 841 842 // fcvtToSintSequence is a sequence of instructions to convert a float to a signed integer. 843 fcvtToSintSequence 844 845 // fcvtToUintSequence is a sequence of instructions to convert a float to an unsigned integer. 846 fcvtToUintSequence 847 848 // xmmCMov is a conditional move instruction for XMM registers. Lowered after register allocation. 849 xmmCMov 850 851 // idivRemSequence is a sequence of instructions to compute both the quotient and remainder of a division. 852 idivRemSequence 853 854 // blendvpd is https://www.felixcloutier.com/x86/blendvpd. 855 blendvpd 856 857 // mfence is https://www.felixcloutier.com/x86/mfence 858 mfence 859 860 // lockxadd is xadd https://www.felixcloutier.com/x86/xadd with a lock prefix. 861 lockxadd 862 863 // nopUseReg is a meta instruction that uses one register and does nothing. 864 nopUseReg 865 866 instrMax 867 ) 868 869 func (i *instruction) asMFence() *instruction { 870 i.kind = mfence 871 return i 872 } 873 874 func (i *instruction) asNopUseReg(r regalloc.VReg) *instruction { 875 i.kind = nopUseReg 876 i.op1 = newOperandReg(r) 877 return i 878 } 879 880 func (i *instruction) asIdivRemSequence(execCtx, divisor, tmpGp regalloc.VReg, isDiv, signed, _64 bool) *instruction { 881 i.kind = idivRemSequence 882 i.op1 = newOperandReg(execCtx) 883 i.op2 = newOperandReg(divisor) 884 i.u1 = uint64(tmpGp) 885 if isDiv { 886 i.u2 |= 1 887 } 888 if signed { 889 i.u2 |= 2 890 } 891 if _64 { 892 i.u2 |= 4 893 } 894 return i 895 } 896 897 func (i *instruction) idivRemSequenceData() ( 898 execCtx, divisor, tmpGp regalloc.VReg, isDiv, signed, _64 bool, 899 ) { 900 if i.kind != idivRemSequence { 901 panic("BUG") 902 } 903 return i.op1.reg(), i.op2.reg(), regalloc.VReg(i.u1), i.u2&1 != 0, i.u2&2 != 0, i.u2&4 != 0 904 } 905 906 func (i *instruction) asXmmCMov(cc cond, x operand, rd regalloc.VReg, size byte) *instruction { 907 i.kind = xmmCMov 908 i.op1 = x 909 i.op2 = newOperandReg(rd) 910 i.u1 = uint64(cc) 911 i.u2 = uint64(size) 912 return i 913 } 914 915 func (i *instruction) asDefineUninitializedReg(r regalloc.VReg) *instruction { 916 i.kind = defineUninitializedReg 917 i.op2 = newOperandReg(r) 918 return i 919 } 920 921 func (m *machine) allocateFcvtToUintSequence( 922 execCtx, src, tmpGp, tmpGp2, tmpXmm, tmpXmm2 regalloc.VReg, 923 src64, dst64, sat bool, 924 ) *instruction { 925 i := m.allocateInstr() 926 i.kind = fcvtToUintSequence 927 op1a := m.amodePool.Allocate() 928 op2a := m.amodePool.Allocate() 929 i.op1 = newOperandMem(op1a) 930 i.op2 = newOperandMem(op2a) 931 if src64 { 932 op1a.imm32 = 1 933 } else { 934 op1a.imm32 = 0 935 } 936 if dst64 { 937 op1a.imm32 |= 2 938 } 939 if sat { 940 op1a.imm32 |= 4 941 } 942 943 op1a.base = execCtx 944 op1a.index = src 945 op2a.base = tmpGp 946 op2a.index = tmpGp2 947 i.u1 = uint64(tmpXmm) 948 i.u2 = uint64(tmpXmm2) 949 return i 950 } 951 952 func (i *instruction) fcvtToUintSequenceData() ( 953 execCtx, src, tmpGp, tmpGp2, tmpXmm, tmpXmm2 regalloc.VReg, src64, dst64, sat bool, 954 ) { 955 if i.kind != fcvtToUintSequence { 956 panic("BUG") 957 } 958 op1a := i.op1.addressMode() 959 op2a := i.op2.addressMode() 960 return op1a.base, op1a.index, op2a.base, op2a.index, regalloc.VReg(i.u1), regalloc.VReg(i.u2), 961 op1a.imm32&1 != 0, op1a.imm32&2 != 0, op1a.imm32&4 != 0 962 } 963 964 func (m *machine) allocateFcvtToSintSequence( 965 execCtx, src, tmpGp, tmpGp2, tmpXmm regalloc.VReg, 966 src64, dst64, sat bool, 967 ) *instruction { 968 i := m.allocateInstr() 969 i.kind = fcvtToSintSequence 970 op1a := m.amodePool.Allocate() 971 op2a := m.amodePool.Allocate() 972 i.op1 = newOperandMem(op1a) 973 i.op2 = newOperandMem(op2a) 974 op1a.base = execCtx 975 op1a.index = src 976 op2a.base = tmpGp 977 op2a.index = tmpGp2 978 i.u1 = uint64(tmpXmm) 979 if src64 { 980 i.u2 = 1 981 } else { 982 i.u2 = 0 983 } 984 if dst64 { 985 i.u2 |= 2 986 } 987 if sat { 988 i.u2 |= 4 989 } 990 return i 991 } 992 993 func (i *instruction) fcvtToSintSequenceData() ( 994 execCtx, src, tmpGp, tmpGp2, tmpXmm regalloc.VReg, src64, dst64, sat bool, 995 ) { 996 if i.kind != fcvtToSintSequence { 997 panic("BUG") 998 } 999 op1a := i.op1.addressMode() 1000 op2a := i.op2.addressMode() 1001 return op1a.base, op1a.index, op2a.base, op2a.index, regalloc.VReg(i.u1), 1002 i.u2&1 != 0, i.u2&2 != 0, i.u2&4 != 0 1003 } 1004 1005 func (k instructionKind) String() string { 1006 switch k { 1007 case nop0: 1008 return "nop" 1009 case ret: 1010 return "ret" 1011 case imm: 1012 return "imm" 1013 case aluRmiR: 1014 return "aluRmiR" 1015 case movRR: 1016 return "movRR" 1017 case xmmRmR: 1018 return "xmmRmR" 1019 case gprToXmm: 1020 return "gprToXmm" 1021 case xmmUnaryRmR: 1022 return "xmmUnaryRmR" 1023 case xmmUnaryRmRImm: 1024 return "xmmUnaryRmRImm" 1025 case unaryRmR: 1026 return "unaryRmR" 1027 case not: 1028 return "not" 1029 case neg: 1030 return "neg" 1031 case div: 1032 return "div" 1033 case mulHi: 1034 return "mulHi" 1035 case signExtendData: 1036 return "signExtendData" 1037 case movzxRmR: 1038 return "movzxRmR" 1039 case mov64MR: 1040 return "mov64MR" 1041 case lea: 1042 return "lea" 1043 case movsxRmR: 1044 return "movsxRmR" 1045 case movRM: 1046 return "movRM" 1047 case shiftR: 1048 return "shiftR" 1049 case xmmRmiReg: 1050 return "xmmRmiReg" 1051 case cmpRmiR: 1052 return "cmpRmiR" 1053 case setcc: 1054 return "setcc" 1055 case cmove: 1056 return "cmove" 1057 case push64: 1058 return "push64" 1059 case pop64: 1060 return "pop64" 1061 case xmmMovRM: 1062 return "xmmMovRM" 1063 case xmmLoadConst: 1064 return "xmmLoadConst" 1065 case xmmToGpr: 1066 return "xmmToGpr" 1067 case cvtUint64ToFloatSeq: 1068 return "cvtUint64ToFloatSeq" 1069 case cvtFloatToSintSeq: 1070 return "cvtFloatToSintSeq" 1071 case cvtFloatToUintSeq: 1072 return "cvtFloatToUintSeq" 1073 case xmmMinMaxSeq: 1074 return "xmmMinMaxSeq" 1075 case xmmCmpRmR: 1076 return "xmmCmpRmR" 1077 case xmmRmRImm: 1078 return "xmmRmRImm" 1079 case jmpIf: 1080 return "jmpIf" 1081 case jmp: 1082 return "jmp" 1083 case jmpTableIsland: 1084 return "jmpTableIsland" 1085 case exitSequence: 1086 return "exit_sequence" 1087 case ud2: 1088 return "ud2" 1089 case xchg: 1090 return "xchg" 1091 case zeros: 1092 return "zeros" 1093 case fcvtToSintSequence: 1094 return "fcvtToSintSequence" 1095 case fcvtToUintSequence: 1096 return "fcvtToUintSequence" 1097 case xmmCMov: 1098 return "xmmCMov" 1099 case idivRemSequence: 1100 return "idivRemSequence" 1101 case mfence: 1102 return "mfence" 1103 case lockcmpxchg: 1104 return "lockcmpxchg" 1105 case lockxadd: 1106 return "lockxadd" 1107 default: 1108 panic("BUG") 1109 } 1110 } 1111 1112 type aluRmiROpcode byte 1113 1114 const ( 1115 aluRmiROpcodeAdd aluRmiROpcode = iota + 1 1116 aluRmiROpcodeSub 1117 aluRmiROpcodeAnd 1118 aluRmiROpcodeOr 1119 aluRmiROpcodeXor 1120 aluRmiROpcodeMul 1121 ) 1122 1123 func (a aluRmiROpcode) String() string { 1124 switch a { 1125 case aluRmiROpcodeAdd: 1126 return "add" 1127 case aluRmiROpcodeSub: 1128 return "sub" 1129 case aluRmiROpcodeAnd: 1130 return "and" 1131 case aluRmiROpcodeOr: 1132 return "or" 1133 case aluRmiROpcodeXor: 1134 return "xor" 1135 case aluRmiROpcodeMul: 1136 return "imul" 1137 default: 1138 panic("BUG") 1139 } 1140 } 1141 1142 func (i *instruction) asJmpIf(cond cond, target operand) *instruction { 1143 i.kind = jmpIf 1144 i.u1 = uint64(cond) 1145 i.op1 = target 1146 return i 1147 } 1148 1149 // asJmpTableSequence is used to emit the jump table. 1150 // targetSliceIndex is the index of the target slice in machine.jmpTableTargets. 1151 func (i *instruction) asJmpTableSequence(targetSliceIndex int, targetCount int) *instruction { 1152 i.kind = jmpTableIsland 1153 i.u1 = uint64(targetSliceIndex) 1154 i.u2 = uint64(targetCount) 1155 return i 1156 } 1157 1158 func (i *instruction) asJmp(target operand) *instruction { 1159 i.kind = jmp 1160 i.op1 = target 1161 return i 1162 } 1163 1164 func (i *instruction) jmpLabel() backend.Label { 1165 switch i.kind { 1166 case jmp, jmpIf, lea, xmmUnaryRmR: 1167 return i.op1.label() 1168 default: 1169 panic("BUG") 1170 } 1171 } 1172 1173 func (i *instruction) asLEA(target operand, rd regalloc.VReg) *instruction { 1174 i.kind = lea 1175 i.op1 = target 1176 i.op2 = newOperandReg(rd) 1177 return i 1178 } 1179 1180 func (i *instruction) asCall(ref ssa.FuncRef, abi *backend.FunctionABI) *instruction { 1181 i.kind = call 1182 i.u1 = uint64(ref) 1183 if abi != nil { 1184 i.u2 = abi.ABIInfoAsUint64() 1185 } 1186 return i 1187 } 1188 1189 func (i *instruction) asCallIndirect(ptr operand, abi *backend.FunctionABI) *instruction { 1190 if ptr.kind != operandKindReg && ptr.kind != operandKindMem { 1191 panic("BUG") 1192 } 1193 i.kind = callIndirect 1194 i.op1 = ptr 1195 if abi != nil { 1196 i.u2 = abi.ABIInfoAsUint64() 1197 } 1198 return i 1199 } 1200 1201 func (i *instruction) asRet() *instruction { 1202 i.kind = ret 1203 return i 1204 } 1205 1206 func (i *instruction) asImm(dst regalloc.VReg, value uint64, _64 bool) *instruction { 1207 i.kind = imm 1208 i.op2 = newOperandReg(dst) 1209 i.u1 = value 1210 i.b1 = _64 1211 return i 1212 } 1213 1214 func (i *instruction) asAluRmiR(op aluRmiROpcode, rm operand, rd regalloc.VReg, _64 bool) *instruction { 1215 if rm.kind != operandKindReg && rm.kind != operandKindMem && rm.kind != operandKindImm32 { 1216 panic("BUG") 1217 } 1218 i.kind = aluRmiR 1219 i.op1 = rm 1220 i.op2 = newOperandReg(rd) 1221 i.u1 = uint64(op) 1222 i.b1 = _64 1223 return i 1224 } 1225 1226 func (i *instruction) asZeros(dst regalloc.VReg) *instruction { 1227 i.kind = zeros 1228 i.op2 = newOperandReg(dst) 1229 return i 1230 } 1231 1232 func (i *instruction) asBlendvpd(rm operand, rd regalloc.VReg) *instruction { 1233 if rm.kind != operandKindReg && rm.kind != operandKindMem { 1234 panic("BUG") 1235 } 1236 i.kind = blendvpd 1237 i.op1 = rm 1238 i.op2 = newOperandReg(rd) 1239 return i 1240 } 1241 1242 func (i *instruction) asXmmRmR(op sseOpcode, rm operand, rd regalloc.VReg) *instruction { 1243 if rm.kind != operandKindReg && rm.kind != operandKindMem { 1244 panic("BUG") 1245 } 1246 i.kind = xmmRmR 1247 i.op1 = rm 1248 i.op2 = newOperandReg(rd) 1249 i.u1 = uint64(op) 1250 return i 1251 } 1252 1253 func (i *instruction) asXmmRmRImm(op sseOpcode, imm uint8, rm operand, rd regalloc.VReg) *instruction { 1254 if rm.kind != operandKindReg && rm.kind != operandKindMem { 1255 panic("BUG") 1256 } 1257 i.kind = xmmRmRImm 1258 i.op1 = rm 1259 i.op2 = newOperandReg(rd) 1260 i.u1 = uint64(op) 1261 i.u2 = uint64(imm) 1262 return i 1263 } 1264 1265 func (i *instruction) asGprToXmm(op sseOpcode, rm operand, rd regalloc.VReg, _64 bool) *instruction { 1266 if rm.kind != operandKindReg && rm.kind != operandKindMem { 1267 panic("BUG") 1268 } 1269 i.kind = gprToXmm 1270 i.op1 = rm 1271 i.op2 = newOperandReg(rd) 1272 i.u1 = uint64(op) 1273 i.b1 = _64 1274 return i 1275 } 1276 1277 func (i *instruction) asEmitSourceOffsetInfo(l ssa.SourceOffset) *instruction { 1278 i.kind = sourceOffsetInfo 1279 i.u1 = uint64(l) 1280 return i 1281 } 1282 1283 func (i *instruction) sourceOffsetInfo() ssa.SourceOffset { 1284 return ssa.SourceOffset(i.u1) 1285 } 1286 1287 func (i *instruction) asXmmToGpr(op sseOpcode, rm, rd regalloc.VReg, _64 bool) *instruction { 1288 i.kind = xmmToGpr 1289 i.op1 = newOperandReg(rm) 1290 i.op2 = newOperandReg(rd) 1291 i.u1 = uint64(op) 1292 i.b1 = _64 1293 return i 1294 } 1295 1296 func (i *instruction) asMovRM(rm regalloc.VReg, rd operand, size byte) *instruction { 1297 if rd.kind != operandKindMem { 1298 panic("BUG") 1299 } 1300 i.kind = movRM 1301 i.op1 = newOperandReg(rm) 1302 i.op2 = rd 1303 i.u1 = uint64(size) 1304 return i 1305 } 1306 1307 func (i *instruction) asMovsxRmR(ext extMode, src operand, rd regalloc.VReg) *instruction { 1308 if src.kind != operandKindReg && src.kind != operandKindMem { 1309 panic("BUG") 1310 } 1311 i.kind = movsxRmR 1312 i.op1 = src 1313 i.op2 = newOperandReg(rd) 1314 i.u1 = uint64(ext) 1315 return i 1316 } 1317 1318 func (i *instruction) asMovzxRmR(ext extMode, src operand, rd regalloc.VReg) *instruction { 1319 if src.kind != operandKindReg && src.kind != operandKindMem { 1320 panic("BUG") 1321 } 1322 i.kind = movzxRmR 1323 i.op1 = src 1324 i.op2 = newOperandReg(rd) 1325 i.u1 = uint64(ext) 1326 return i 1327 } 1328 1329 func (i *instruction) asSignExtendData(_64 bool) *instruction { 1330 i.kind = signExtendData 1331 i.b1 = _64 1332 return i 1333 } 1334 1335 func (i *instruction) asUD2() *instruction { 1336 i.kind = ud2 1337 return i 1338 } 1339 1340 func (i *instruction) asDiv(rn operand, signed bool, _64 bool) *instruction { 1341 i.kind = div 1342 i.op1 = rn 1343 i.b1 = _64 1344 if signed { 1345 i.u1 = 1 1346 } 1347 return i 1348 } 1349 1350 func (i *instruction) asMov64MR(rm operand, rd regalloc.VReg) *instruction { 1351 if rm.kind != operandKindMem { 1352 panic("BUG") 1353 } 1354 i.kind = mov64MR 1355 i.op1 = rm 1356 i.op2 = newOperandReg(rd) 1357 return i 1358 } 1359 1360 func (i *instruction) asMovRR(rm, rd regalloc.VReg, _64 bool) *instruction { 1361 i.kind = movRR 1362 i.op1 = newOperandReg(rm) 1363 i.op2 = newOperandReg(rd) 1364 i.b1 = _64 1365 return i 1366 } 1367 1368 func (i *instruction) asNot(rm operand, _64 bool) *instruction { 1369 if rm.kind != operandKindReg && rm.kind != operandKindMem { 1370 panic("BUG") 1371 } 1372 i.kind = not 1373 i.op1 = rm 1374 i.b1 = _64 1375 return i 1376 } 1377 1378 func (i *instruction) asNeg(rm operand, _64 bool) *instruction { 1379 if rm.kind != operandKindReg && rm.kind != operandKindMem { 1380 panic("BUG") 1381 } 1382 i.kind = neg 1383 i.op1 = rm 1384 i.b1 = _64 1385 return i 1386 } 1387 1388 func (i *instruction) asMulHi(rm operand, signed, _64 bool) *instruction { 1389 if rm.kind != operandKindReg && (rm.kind != operandKindMem) { 1390 panic("BUG") 1391 } 1392 i.kind = mulHi 1393 i.op1 = rm 1394 i.b1 = _64 1395 if signed { 1396 i.u1 = 1 1397 } 1398 return i 1399 } 1400 1401 func (i *instruction) asUnaryRmR(op unaryRmROpcode, rm operand, rd regalloc.VReg, _64 bool) *instruction { 1402 if rm.kind != operandKindReg && rm.kind != operandKindMem { 1403 panic("BUG") 1404 } 1405 i.kind = unaryRmR 1406 i.op1 = rm 1407 i.op2 = newOperandReg(rd) 1408 i.u1 = uint64(op) 1409 i.b1 = _64 1410 return i 1411 } 1412 1413 func (i *instruction) asShiftR(op shiftROp, amount operand, rd regalloc.VReg, _64 bool) *instruction { 1414 if amount.kind != operandKindReg && amount.kind != operandKindImm32 { 1415 panic("BUG") 1416 } 1417 i.kind = shiftR 1418 i.op1 = amount 1419 i.op2 = newOperandReg(rd) 1420 i.u1 = uint64(op) 1421 i.b1 = _64 1422 return i 1423 } 1424 1425 func (i *instruction) asXmmRmiReg(op sseOpcode, rm operand, rd regalloc.VReg) *instruction { 1426 if rm.kind != operandKindReg && rm.kind != operandKindImm32 && rm.kind != operandKindMem { 1427 panic("BUG") 1428 } 1429 i.kind = xmmRmiReg 1430 i.op1 = rm 1431 i.op2 = newOperandReg(rd) 1432 i.u1 = uint64(op) 1433 return i 1434 } 1435 1436 func (i *instruction) asCmpRmiR(cmp bool, rm operand, rn regalloc.VReg, _64 bool) *instruction { 1437 if rm.kind != operandKindReg && rm.kind != operandKindImm32 && rm.kind != operandKindMem { 1438 panic("BUG") 1439 } 1440 i.kind = cmpRmiR 1441 i.op1 = rm 1442 i.op2 = newOperandReg(rn) 1443 if cmp { 1444 i.u1 = 1 1445 } 1446 i.b1 = _64 1447 return i 1448 } 1449 1450 func (i *instruction) asSetcc(c cond, rd regalloc.VReg) *instruction { 1451 i.kind = setcc 1452 i.op2 = newOperandReg(rd) 1453 i.u1 = uint64(c) 1454 return i 1455 } 1456 1457 func (i *instruction) asCmove(c cond, rm operand, rd regalloc.VReg, _64 bool) *instruction { 1458 i.kind = cmove 1459 i.op1 = rm 1460 i.op2 = newOperandReg(rd) 1461 i.u1 = uint64(c) 1462 i.b1 = _64 1463 return i 1464 } 1465 1466 func (m *machine) allocateExitSeq(execCtx regalloc.VReg) *instruction { 1467 i := m.allocateInstr() 1468 i.kind = exitSequence 1469 i.op1 = newOperandReg(execCtx) 1470 // Allocate the address mode that will be used in encoding the exit sequence. 1471 i.op2 = newOperandMem(m.amodePool.Allocate()) 1472 return i 1473 } 1474 1475 func (i *instruction) asXmmUnaryRmR(op sseOpcode, rm operand, rd regalloc.VReg) *instruction { 1476 if rm.kind != operandKindReg && rm.kind != operandKindMem { 1477 panic("BUG") 1478 } 1479 i.kind = xmmUnaryRmR 1480 i.op1 = rm 1481 i.op2 = newOperandReg(rd) 1482 i.u1 = uint64(op) 1483 return i 1484 } 1485 1486 func (i *instruction) asXmmUnaryRmRImm(op sseOpcode, imm byte, rm operand, rd regalloc.VReg) *instruction { 1487 if rm.kind != operandKindReg && rm.kind != operandKindMem { 1488 panic("BUG") 1489 } 1490 i.kind = xmmUnaryRmRImm 1491 i.op1 = rm 1492 i.op2 = newOperandReg(rd) 1493 i.u1 = uint64(op) 1494 i.u2 = uint64(imm) 1495 return i 1496 } 1497 1498 func (i *instruction) asXmmCmpRmR(op sseOpcode, rm operand, rd regalloc.VReg) *instruction { 1499 if rm.kind != operandKindReg && rm.kind != operandKindMem { 1500 panic("BUG") 1501 } 1502 i.kind = xmmCmpRmR 1503 i.op1 = rm 1504 i.op2 = newOperandReg(rd) 1505 i.u1 = uint64(op) 1506 return i 1507 } 1508 1509 func (i *instruction) asXmmMovRM(op sseOpcode, rm regalloc.VReg, rd operand) *instruction { 1510 if rd.kind != operandKindMem { 1511 panic("BUG") 1512 } 1513 i.kind = xmmMovRM 1514 i.op1 = newOperandReg(rm) 1515 i.op2 = rd 1516 i.u1 = uint64(op) 1517 return i 1518 } 1519 1520 func (i *instruction) asPop64(rm regalloc.VReg) *instruction { 1521 i.kind = pop64 1522 i.op1 = newOperandReg(rm) 1523 return i 1524 } 1525 1526 func (i *instruction) asPush64(op operand) *instruction { 1527 if op.kind != operandKindReg && op.kind != operandKindMem && op.kind != operandKindImm32 { 1528 panic("BUG") 1529 } 1530 i.kind = push64 1531 i.op1 = op 1532 return i 1533 } 1534 1535 func (i *instruction) asXCHG(rm regalloc.VReg, rd operand, size byte) *instruction { 1536 i.kind = xchg 1537 i.op1 = newOperandReg(rm) 1538 i.op2 = rd 1539 i.u1 = uint64(size) 1540 return i 1541 } 1542 1543 func (i *instruction) asLockCmpXCHG(rm regalloc.VReg, rd *amode, size byte) *instruction { 1544 i.kind = lockcmpxchg 1545 i.op1 = newOperandReg(rm) 1546 i.op2 = newOperandMem(rd) 1547 i.u1 = uint64(size) 1548 return i 1549 } 1550 1551 func (i *instruction) asLockXAdd(rm regalloc.VReg, rd *amode, size byte) *instruction { 1552 i.kind = lockxadd 1553 i.op1 = newOperandReg(rm) 1554 i.op2 = newOperandMem(rd) 1555 i.u1 = uint64(size) 1556 return i 1557 } 1558 1559 type unaryRmROpcode byte 1560 1561 const ( 1562 unaryRmROpcodeBsr unaryRmROpcode = iota 1563 unaryRmROpcodeBsf 1564 unaryRmROpcodeLzcnt 1565 unaryRmROpcodeTzcnt 1566 unaryRmROpcodePopcnt 1567 ) 1568 1569 func (u unaryRmROpcode) String() string { 1570 switch u { 1571 case unaryRmROpcodeBsr: 1572 return "bsr" 1573 case unaryRmROpcodeBsf: 1574 return "bsf" 1575 case unaryRmROpcodeLzcnt: 1576 return "lzcnt" 1577 case unaryRmROpcodeTzcnt: 1578 return "tzcnt" 1579 case unaryRmROpcodePopcnt: 1580 return "popcnt" 1581 default: 1582 panic("BUG") 1583 } 1584 } 1585 1586 type shiftROp byte 1587 1588 const ( 1589 shiftROpRotateLeft shiftROp = 0 1590 shiftROpRotateRight shiftROp = 1 1591 shiftROpShiftLeft shiftROp = 4 1592 shiftROpShiftRightLogical shiftROp = 5 1593 shiftROpShiftRightArithmetic shiftROp = 7 1594 ) 1595 1596 func (s shiftROp) String() string { 1597 switch s { 1598 case shiftROpRotateLeft: 1599 return "rol" 1600 case shiftROpRotateRight: 1601 return "ror" 1602 case shiftROpShiftLeft: 1603 return "shl" 1604 case shiftROpShiftRightLogical: 1605 return "shr" 1606 case shiftROpShiftRightArithmetic: 1607 return "sar" 1608 default: 1609 panic("BUG") 1610 } 1611 } 1612 1613 type sseOpcode byte 1614 1615 const ( 1616 sseOpcodeInvalid sseOpcode = iota 1617 sseOpcodeAddps 1618 sseOpcodeAddpd 1619 sseOpcodeAddss 1620 sseOpcodeAddsd 1621 sseOpcodeAndps 1622 sseOpcodeAndpd 1623 sseOpcodeAndnps 1624 sseOpcodeAndnpd 1625 sseOpcodeBlendvps 1626 sseOpcodeBlendvpd 1627 sseOpcodeComiss 1628 sseOpcodeComisd 1629 sseOpcodeCmpps 1630 sseOpcodeCmppd 1631 sseOpcodeCmpss 1632 sseOpcodeCmpsd 1633 sseOpcodeCvtdq2ps 1634 sseOpcodeCvtdq2pd 1635 sseOpcodeCvtsd2ss 1636 sseOpcodeCvtsd2si 1637 sseOpcodeCvtsi2ss 1638 sseOpcodeCvtsi2sd 1639 sseOpcodeCvtss2si 1640 sseOpcodeCvtss2sd 1641 sseOpcodeCvttps2dq 1642 sseOpcodeCvttss2si 1643 sseOpcodeCvttsd2si 1644 sseOpcodeDivps 1645 sseOpcodeDivpd 1646 sseOpcodeDivss 1647 sseOpcodeDivsd 1648 sseOpcodeInsertps 1649 sseOpcodeMaxps 1650 sseOpcodeMaxpd 1651 sseOpcodeMaxss 1652 sseOpcodeMaxsd 1653 sseOpcodeMinps 1654 sseOpcodeMinpd 1655 sseOpcodeMinss 1656 sseOpcodeMinsd 1657 sseOpcodeMovaps 1658 sseOpcodeMovapd 1659 sseOpcodeMovd 1660 sseOpcodeMovdqa 1661 sseOpcodeMovdqu 1662 sseOpcodeMovlhps 1663 sseOpcodeMovmskps 1664 sseOpcodeMovmskpd 1665 sseOpcodeMovq 1666 sseOpcodeMovss 1667 sseOpcodeMovsd 1668 sseOpcodeMovups 1669 sseOpcodeMovupd 1670 sseOpcodeMulps 1671 sseOpcodeMulpd 1672 sseOpcodeMulss 1673 sseOpcodeMulsd 1674 sseOpcodeOrps 1675 sseOpcodeOrpd 1676 sseOpcodePabsb 1677 sseOpcodePabsw 1678 sseOpcodePabsd 1679 sseOpcodePackssdw 1680 sseOpcodePacksswb 1681 sseOpcodePackusdw 1682 sseOpcodePackuswb 1683 sseOpcodePaddb 1684 sseOpcodePaddd 1685 sseOpcodePaddq 1686 sseOpcodePaddw 1687 sseOpcodePaddsb 1688 sseOpcodePaddsw 1689 sseOpcodePaddusb 1690 sseOpcodePaddusw 1691 sseOpcodePalignr 1692 sseOpcodePand 1693 sseOpcodePandn 1694 sseOpcodePavgb 1695 sseOpcodePavgw 1696 sseOpcodePcmpeqb 1697 sseOpcodePcmpeqw 1698 sseOpcodePcmpeqd 1699 sseOpcodePcmpeqq 1700 sseOpcodePcmpgtb 1701 sseOpcodePcmpgtw 1702 sseOpcodePcmpgtd 1703 sseOpcodePcmpgtq 1704 sseOpcodePextrb 1705 sseOpcodePextrw 1706 sseOpcodePextrd 1707 sseOpcodePextrq 1708 sseOpcodePinsrb 1709 sseOpcodePinsrw 1710 sseOpcodePinsrd 1711 sseOpcodePinsrq 1712 sseOpcodePmaddwd 1713 sseOpcodePmaxsb 1714 sseOpcodePmaxsw 1715 sseOpcodePmaxsd 1716 sseOpcodePmaxub 1717 sseOpcodePmaxuw 1718 sseOpcodePmaxud 1719 sseOpcodePminsb 1720 sseOpcodePminsw 1721 sseOpcodePminsd 1722 sseOpcodePminub 1723 sseOpcodePminuw 1724 sseOpcodePminud 1725 sseOpcodePmovmskb 1726 sseOpcodePmovsxbd 1727 sseOpcodePmovsxbw 1728 sseOpcodePmovsxbq 1729 sseOpcodePmovsxwd 1730 sseOpcodePmovsxwq 1731 sseOpcodePmovsxdq 1732 sseOpcodePmovzxbd 1733 sseOpcodePmovzxbw 1734 sseOpcodePmovzxbq 1735 sseOpcodePmovzxwd 1736 sseOpcodePmovzxwq 1737 sseOpcodePmovzxdq 1738 sseOpcodePmulld 1739 sseOpcodePmullw 1740 sseOpcodePmuludq 1741 sseOpcodePor 1742 sseOpcodePshufb 1743 sseOpcodePshufd 1744 sseOpcodePsllw 1745 sseOpcodePslld 1746 sseOpcodePsllq 1747 sseOpcodePsraw 1748 sseOpcodePsrad 1749 sseOpcodePsrlw 1750 sseOpcodePsrld 1751 sseOpcodePsrlq 1752 sseOpcodePsubb 1753 sseOpcodePsubd 1754 sseOpcodePsubq 1755 sseOpcodePsubw 1756 sseOpcodePsubsb 1757 sseOpcodePsubsw 1758 sseOpcodePsubusb 1759 sseOpcodePsubusw 1760 sseOpcodePtest 1761 sseOpcodePunpckhbw 1762 sseOpcodePunpcklbw 1763 sseOpcodePxor 1764 sseOpcodeRcpss 1765 sseOpcodeRoundps 1766 sseOpcodeRoundpd 1767 sseOpcodeRoundss 1768 sseOpcodeRoundsd 1769 sseOpcodeRsqrtss 1770 sseOpcodeSqrtps 1771 sseOpcodeSqrtpd 1772 sseOpcodeSqrtss 1773 sseOpcodeSqrtsd 1774 sseOpcodeSubps 1775 sseOpcodeSubpd 1776 sseOpcodeSubss 1777 sseOpcodeSubsd 1778 sseOpcodeUcomiss 1779 sseOpcodeUcomisd 1780 sseOpcodeXorps 1781 sseOpcodeXorpd 1782 sseOpcodePmulhrsw 1783 sseOpcodeUnpcklps 1784 sseOpcodeCvtps2pd 1785 sseOpcodeCvtpd2ps 1786 sseOpcodeCvttpd2dq 1787 sseOpcodeShufps 1788 sseOpcodePmaddubsw 1789 ) 1790 1791 func (s sseOpcode) String() string { 1792 switch s { 1793 case sseOpcodeInvalid: 1794 return "invalid" 1795 case sseOpcodeAddps: 1796 return "addps" 1797 case sseOpcodeAddpd: 1798 return "addpd" 1799 case sseOpcodeAddss: 1800 return "addss" 1801 case sseOpcodeAddsd: 1802 return "addsd" 1803 case sseOpcodeAndps: 1804 return "andps" 1805 case sseOpcodeAndpd: 1806 return "andpd" 1807 case sseOpcodeAndnps: 1808 return "andnps" 1809 case sseOpcodeAndnpd: 1810 return "andnpd" 1811 case sseOpcodeBlendvps: 1812 return "blendvps" 1813 case sseOpcodeBlendvpd: 1814 return "blendvpd" 1815 case sseOpcodeComiss: 1816 return "comiss" 1817 case sseOpcodeComisd: 1818 return "comisd" 1819 case sseOpcodeCmpps: 1820 return "cmpps" 1821 case sseOpcodeCmppd: 1822 return "cmppd" 1823 case sseOpcodeCmpss: 1824 return "cmpss" 1825 case sseOpcodeCmpsd: 1826 return "cmpsd" 1827 case sseOpcodeCvtdq2ps: 1828 return "cvtdq2ps" 1829 case sseOpcodeCvtdq2pd: 1830 return "cvtdq2pd" 1831 case sseOpcodeCvtsd2ss: 1832 return "cvtsd2ss" 1833 case sseOpcodeCvtsd2si: 1834 return "cvtsd2si" 1835 case sseOpcodeCvtsi2ss: 1836 return "cvtsi2ss" 1837 case sseOpcodeCvtsi2sd: 1838 return "cvtsi2sd" 1839 case sseOpcodeCvtss2si: 1840 return "cvtss2si" 1841 case sseOpcodeCvtss2sd: 1842 return "cvtss2sd" 1843 case sseOpcodeCvttps2dq: 1844 return "cvttps2dq" 1845 case sseOpcodeCvttss2si: 1846 return "cvttss2si" 1847 case sseOpcodeCvttsd2si: 1848 return "cvttsd2si" 1849 case sseOpcodeDivps: 1850 return "divps" 1851 case sseOpcodeDivpd: 1852 return "divpd" 1853 case sseOpcodeDivss: 1854 return "divss" 1855 case sseOpcodeDivsd: 1856 return "divsd" 1857 case sseOpcodeInsertps: 1858 return "insertps" 1859 case sseOpcodeMaxps: 1860 return "maxps" 1861 case sseOpcodeMaxpd: 1862 return "maxpd" 1863 case sseOpcodeMaxss: 1864 return "maxss" 1865 case sseOpcodeMaxsd: 1866 return "maxsd" 1867 case sseOpcodeMinps: 1868 return "minps" 1869 case sseOpcodeMinpd: 1870 return "minpd" 1871 case sseOpcodeMinss: 1872 return "minss" 1873 case sseOpcodeMinsd: 1874 return "minsd" 1875 case sseOpcodeMovaps: 1876 return "movaps" 1877 case sseOpcodeMovapd: 1878 return "movapd" 1879 case sseOpcodeMovd: 1880 return "movd" 1881 case sseOpcodeMovdqa: 1882 return "movdqa" 1883 case sseOpcodeMovdqu: 1884 return "movdqu" 1885 case sseOpcodeMovlhps: 1886 return "movlhps" 1887 case sseOpcodeMovmskps: 1888 return "movmskps" 1889 case sseOpcodeMovmskpd: 1890 return "movmskpd" 1891 case sseOpcodeMovq: 1892 return "movq" 1893 case sseOpcodeMovss: 1894 return "movss" 1895 case sseOpcodeMovsd: 1896 return "movsd" 1897 case sseOpcodeMovups: 1898 return "movups" 1899 case sseOpcodeMovupd: 1900 return "movupd" 1901 case sseOpcodeMulps: 1902 return "mulps" 1903 case sseOpcodeMulpd: 1904 return "mulpd" 1905 case sseOpcodeMulss: 1906 return "mulss" 1907 case sseOpcodeMulsd: 1908 return "mulsd" 1909 case sseOpcodeOrps: 1910 return "orps" 1911 case sseOpcodeOrpd: 1912 return "orpd" 1913 case sseOpcodePabsb: 1914 return "pabsb" 1915 case sseOpcodePabsw: 1916 return "pabsw" 1917 case sseOpcodePabsd: 1918 return "pabsd" 1919 case sseOpcodePackssdw: 1920 return "packssdw" 1921 case sseOpcodePacksswb: 1922 return "packsswb" 1923 case sseOpcodePackusdw: 1924 return "packusdw" 1925 case sseOpcodePackuswb: 1926 return "packuswb" 1927 case sseOpcodePaddb: 1928 return "paddb" 1929 case sseOpcodePaddd: 1930 return "paddd" 1931 case sseOpcodePaddq: 1932 return "paddq" 1933 case sseOpcodePaddw: 1934 return "paddw" 1935 case sseOpcodePaddsb: 1936 return "paddsb" 1937 case sseOpcodePaddsw: 1938 return "paddsw" 1939 case sseOpcodePaddusb: 1940 return "paddusb" 1941 case sseOpcodePaddusw: 1942 return "paddusw" 1943 case sseOpcodePalignr: 1944 return "palignr" 1945 case sseOpcodePand: 1946 return "pand" 1947 case sseOpcodePandn: 1948 return "pandn" 1949 case sseOpcodePavgb: 1950 return "pavgb" 1951 case sseOpcodePavgw: 1952 return "pavgw" 1953 case sseOpcodePcmpeqb: 1954 return "pcmpeqb" 1955 case sseOpcodePcmpeqw: 1956 return "pcmpeqw" 1957 case sseOpcodePcmpeqd: 1958 return "pcmpeqd" 1959 case sseOpcodePcmpeqq: 1960 return "pcmpeqq" 1961 case sseOpcodePcmpgtb: 1962 return "pcmpgtb" 1963 case sseOpcodePcmpgtw: 1964 return "pcmpgtw" 1965 case sseOpcodePcmpgtd: 1966 return "pcmpgtd" 1967 case sseOpcodePcmpgtq: 1968 return "pcmpgtq" 1969 case sseOpcodePextrb: 1970 return "pextrb" 1971 case sseOpcodePextrw: 1972 return "pextrw" 1973 case sseOpcodePextrd: 1974 return "pextrd" 1975 case sseOpcodePextrq: 1976 return "pextrq" 1977 case sseOpcodePinsrb: 1978 return "pinsrb" 1979 case sseOpcodePinsrw: 1980 return "pinsrw" 1981 case sseOpcodePinsrd: 1982 return "pinsrd" 1983 case sseOpcodePinsrq: 1984 return "pinsrq" 1985 case sseOpcodePmaddwd: 1986 return "pmaddwd" 1987 case sseOpcodePmaxsb: 1988 return "pmaxsb" 1989 case sseOpcodePmaxsw: 1990 return "pmaxsw" 1991 case sseOpcodePmaxsd: 1992 return "pmaxsd" 1993 case sseOpcodePmaxub: 1994 return "pmaxub" 1995 case sseOpcodePmaxuw: 1996 return "pmaxuw" 1997 case sseOpcodePmaxud: 1998 return "pmaxud" 1999 case sseOpcodePminsb: 2000 return "pminsb" 2001 case sseOpcodePminsw: 2002 return "pminsw" 2003 case sseOpcodePminsd: 2004 return "pminsd" 2005 case sseOpcodePminub: 2006 return "pminub" 2007 case sseOpcodePminuw: 2008 return "pminuw" 2009 case sseOpcodePminud: 2010 return "pminud" 2011 case sseOpcodePmovmskb: 2012 return "pmovmskb" 2013 case sseOpcodePmovsxbd: 2014 return "pmovsxbd" 2015 case sseOpcodePmovsxbw: 2016 return "pmovsxbw" 2017 case sseOpcodePmovsxbq: 2018 return "pmovsxbq" 2019 case sseOpcodePmovsxwd: 2020 return "pmovsxwd" 2021 case sseOpcodePmovsxwq: 2022 return "pmovsxwq" 2023 case sseOpcodePmovsxdq: 2024 return "pmovsxdq" 2025 case sseOpcodePmovzxbd: 2026 return "pmovzxbd" 2027 case sseOpcodePmovzxbw: 2028 return "pmovzxbw" 2029 case sseOpcodePmovzxbq: 2030 return "pmovzxbq" 2031 case sseOpcodePmovzxwd: 2032 return "pmovzxwd" 2033 case sseOpcodePmovzxwq: 2034 return "pmovzxwq" 2035 case sseOpcodePmovzxdq: 2036 return "pmovzxdq" 2037 case sseOpcodePmulld: 2038 return "pmulld" 2039 case sseOpcodePmullw: 2040 return "pmullw" 2041 case sseOpcodePmuludq: 2042 return "pmuludq" 2043 case sseOpcodePor: 2044 return "por" 2045 case sseOpcodePshufb: 2046 return "pshufb" 2047 case sseOpcodePshufd: 2048 return "pshufd" 2049 case sseOpcodePsllw: 2050 return "psllw" 2051 case sseOpcodePslld: 2052 return "pslld" 2053 case sseOpcodePsllq: 2054 return "psllq" 2055 case sseOpcodePsraw: 2056 return "psraw" 2057 case sseOpcodePsrad: 2058 return "psrad" 2059 case sseOpcodePsrlw: 2060 return "psrlw" 2061 case sseOpcodePsrld: 2062 return "psrld" 2063 case sseOpcodePsrlq: 2064 return "psrlq" 2065 case sseOpcodePsubb: 2066 return "psubb" 2067 case sseOpcodePsubd: 2068 return "psubd" 2069 case sseOpcodePsubq: 2070 return "psubq" 2071 case sseOpcodePsubw: 2072 return "psubw" 2073 case sseOpcodePsubsb: 2074 return "psubsb" 2075 case sseOpcodePsubsw: 2076 return "psubsw" 2077 case sseOpcodePsubusb: 2078 return "psubusb" 2079 case sseOpcodePsubusw: 2080 return "psubusw" 2081 case sseOpcodePtest: 2082 return "ptest" 2083 case sseOpcodePunpckhbw: 2084 return "punpckhbw" 2085 case sseOpcodePunpcklbw: 2086 return "punpcklbw" 2087 case sseOpcodePxor: 2088 return "pxor" 2089 case sseOpcodeRcpss: 2090 return "rcpss" 2091 case sseOpcodeRoundps: 2092 return "roundps" 2093 case sseOpcodeRoundpd: 2094 return "roundpd" 2095 case sseOpcodeRoundss: 2096 return "roundss" 2097 case sseOpcodeRoundsd: 2098 return "roundsd" 2099 case sseOpcodeRsqrtss: 2100 return "rsqrtss" 2101 case sseOpcodeSqrtps: 2102 return "sqrtps" 2103 case sseOpcodeSqrtpd: 2104 return "sqrtpd" 2105 case sseOpcodeSqrtss: 2106 return "sqrtss" 2107 case sseOpcodeSqrtsd: 2108 return "sqrtsd" 2109 case sseOpcodeSubps: 2110 return "subps" 2111 case sseOpcodeSubpd: 2112 return "subpd" 2113 case sseOpcodeSubss: 2114 return "subss" 2115 case sseOpcodeSubsd: 2116 return "subsd" 2117 case sseOpcodeUcomiss: 2118 return "ucomiss" 2119 case sseOpcodeUcomisd: 2120 return "ucomisd" 2121 case sseOpcodeXorps: 2122 return "xorps" 2123 case sseOpcodeXorpd: 2124 return "xorpd" 2125 case sseOpcodePmulhrsw: 2126 return "pmulhrsw" 2127 case sseOpcodeUnpcklps: 2128 return "unpcklps" 2129 case sseOpcodeCvtps2pd: 2130 return "cvtps2pd" 2131 case sseOpcodeCvtpd2ps: 2132 return "cvtpd2ps" 2133 case sseOpcodeCvttpd2dq: 2134 return "cvttpd2dq" 2135 case sseOpcodeShufps: 2136 return "shufps" 2137 case sseOpcodePmaddubsw: 2138 return "pmaddubsw" 2139 default: 2140 panic("BUG") 2141 } 2142 } 2143 2144 type roundingMode uint8 2145 2146 const ( 2147 roundingModeNearest roundingMode = iota 2148 roundingModeDown 2149 roundingModeUp 2150 roundingModeZero 2151 ) 2152 2153 func (r roundingMode) String() string { 2154 switch r { 2155 case roundingModeNearest: 2156 return "nearest" 2157 case roundingModeDown: 2158 return "down" 2159 case roundingModeUp: 2160 return "up" 2161 case roundingModeZero: 2162 return "zero" 2163 default: 2164 panic("BUG") 2165 } 2166 } 2167 2168 // cmpPred is the immediate value for a comparison operation in xmmRmRImm. 2169 type cmpPred uint8 2170 2171 const ( 2172 // cmpPredEQ_OQ is Equal (ordered, non-signaling) 2173 cmpPredEQ_OQ cmpPred = iota 2174 // cmpPredLT_OS is Less-than (ordered, signaling) 2175 cmpPredLT_OS 2176 // cmpPredLE_OS is Less-than-or-equal (ordered, signaling) 2177 cmpPredLE_OS 2178 // cmpPredUNORD_Q is Unordered (non-signaling) 2179 cmpPredUNORD_Q 2180 // cmpPredNEQ_UQ is Not-equal (unordered, non-signaling) 2181 cmpPredNEQ_UQ 2182 // cmpPredNLT_US is Not-less-than (unordered, signaling) 2183 cmpPredNLT_US 2184 // cmpPredNLE_US is Not-less-than-or-equal (unordered, signaling) 2185 cmpPredNLE_US 2186 // cmpPredORD_Q is Ordered (non-signaling) 2187 cmpPredORD_Q 2188 // cmpPredEQ_UQ is Equal (unordered, non-signaling) 2189 cmpPredEQ_UQ 2190 // cmpPredNGE_US is Not-greater-than-or-equal (unordered, signaling) 2191 cmpPredNGE_US 2192 // cmpPredNGT_US is Not-greater-than (unordered, signaling) 2193 cmpPredNGT_US 2194 // cmpPredFALSE_OQ is False (ordered, non-signaling) 2195 cmpPredFALSE_OQ 2196 // cmpPredNEQ_OQ is Not-equal (ordered, non-signaling) 2197 cmpPredNEQ_OQ 2198 // cmpPredGE_OS is Greater-than-or-equal (ordered, signaling) 2199 cmpPredGE_OS 2200 // cmpPredGT_OS is Greater-than (ordered, signaling) 2201 cmpPredGT_OS 2202 // cmpPredTRUE_UQ is True (unordered, non-signaling) 2203 cmpPredTRUE_UQ 2204 // Equal (ordered, signaling) 2205 cmpPredEQ_OS 2206 // Less-than (ordered, nonsignaling) 2207 cmpPredLT_OQ 2208 // Less-than-or-equal (ordered, nonsignaling) 2209 cmpPredLE_OQ 2210 // Unordered (signaling) 2211 cmpPredUNORD_S 2212 // Not-equal (unordered, signaling) 2213 cmpPredNEQ_US 2214 // Not-less-than (unordered, nonsignaling) 2215 cmpPredNLT_UQ 2216 // Not-less-than-or-equal (unordered, nonsignaling) 2217 cmpPredNLE_UQ 2218 // Ordered (signaling) 2219 cmpPredORD_S 2220 // Equal (unordered, signaling) 2221 cmpPredEQ_US 2222 // Not-greater-than-or-equal (unordered, non-signaling) 2223 cmpPredNGE_UQ 2224 // Not-greater-than (unordered, nonsignaling) 2225 cmpPredNGT_UQ 2226 // False (ordered, signaling) 2227 cmpPredFALSE_OS 2228 // Not-equal (ordered, signaling) 2229 cmpPredNEQ_OS 2230 // Greater-than-or-equal (ordered, nonsignaling) 2231 cmpPredGE_OQ 2232 // Greater-than (ordered, nonsignaling) 2233 cmpPredGT_OQ 2234 // True (unordered, signaling) 2235 cmpPredTRUE_US 2236 ) 2237 2238 func (r cmpPred) String() string { 2239 switch r { 2240 case cmpPredEQ_OQ: 2241 return "eq_oq" 2242 case cmpPredLT_OS: 2243 return "lt_os" 2244 case cmpPredLE_OS: 2245 return "le_os" 2246 case cmpPredUNORD_Q: 2247 return "unord_q" 2248 case cmpPredNEQ_UQ: 2249 return "neq_uq" 2250 case cmpPredNLT_US: 2251 return "nlt_us" 2252 case cmpPredNLE_US: 2253 return "nle_us" 2254 case cmpPredORD_Q: 2255 return "ord_q" 2256 case cmpPredEQ_UQ: 2257 return "eq_uq" 2258 case cmpPredNGE_US: 2259 return "nge_us" 2260 case cmpPredNGT_US: 2261 return "ngt_us" 2262 case cmpPredFALSE_OQ: 2263 return "false_oq" 2264 case cmpPredNEQ_OQ: 2265 return "neq_oq" 2266 case cmpPredGE_OS: 2267 return "ge_os" 2268 case cmpPredGT_OS: 2269 return "gt_os" 2270 case cmpPredTRUE_UQ: 2271 return "true_uq" 2272 case cmpPredEQ_OS: 2273 return "eq_os" 2274 case cmpPredLT_OQ: 2275 return "lt_oq" 2276 case cmpPredLE_OQ: 2277 return "le_oq" 2278 case cmpPredUNORD_S: 2279 return "unord_s" 2280 case cmpPredNEQ_US: 2281 return "neq_us" 2282 case cmpPredNLT_UQ: 2283 return "nlt_uq" 2284 case cmpPredNLE_UQ: 2285 return "nle_uq" 2286 case cmpPredORD_S: 2287 return "ord_s" 2288 case cmpPredEQ_US: 2289 return "eq_us" 2290 case cmpPredNGE_UQ: 2291 return "nge_uq" 2292 case cmpPredNGT_UQ: 2293 return "ngt_uq" 2294 case cmpPredFALSE_OS: 2295 return "false_os" 2296 case cmpPredNEQ_OS: 2297 return "neq_os" 2298 case cmpPredGE_OQ: 2299 return "ge_oq" 2300 case cmpPredGT_OQ: 2301 return "gt_oq" 2302 case cmpPredTRUE_US: 2303 return "true_us" 2304 default: 2305 panic("BUG") 2306 } 2307 } 2308 2309 func linkInstr(prev, next *instruction) *instruction { 2310 prev.next = next 2311 next.prev = prev 2312 return next 2313 } 2314 2315 type defKind byte 2316 2317 const ( 2318 defKindNone defKind = iota + 1 2319 defKindOp2 2320 defKindCall 2321 defKindDivRem 2322 ) 2323 2324 var defKinds = [instrMax]defKind{ 2325 nop0: defKindNone, 2326 ret: defKindNone, 2327 movRR: defKindOp2, 2328 movRM: defKindNone, 2329 xmmMovRM: defKindNone, 2330 aluRmiR: defKindNone, 2331 shiftR: defKindNone, 2332 imm: defKindOp2, 2333 unaryRmR: defKindOp2, 2334 xmmRmiReg: defKindNone, 2335 xmmUnaryRmR: defKindOp2, 2336 xmmUnaryRmRImm: defKindOp2, 2337 xmmCmpRmR: defKindNone, 2338 xmmRmR: defKindNone, 2339 xmmRmRImm: defKindNone, 2340 mov64MR: defKindOp2, 2341 movsxRmR: defKindOp2, 2342 movzxRmR: defKindOp2, 2343 gprToXmm: defKindOp2, 2344 xmmToGpr: defKindOp2, 2345 cmove: defKindNone, 2346 call: defKindCall, 2347 callIndirect: defKindCall, 2348 ud2: defKindNone, 2349 jmp: defKindNone, 2350 jmpIf: defKindNone, 2351 jmpTableIsland: defKindNone, 2352 cmpRmiR: defKindNone, 2353 exitSequence: defKindNone, 2354 lea: defKindOp2, 2355 setcc: defKindOp2, 2356 zeros: defKindOp2, 2357 sourceOffsetInfo: defKindNone, 2358 fcvtToSintSequence: defKindNone, 2359 defineUninitializedReg: defKindOp2, 2360 fcvtToUintSequence: defKindNone, 2361 xmmCMov: defKindOp2, 2362 idivRemSequence: defKindDivRem, 2363 blendvpd: defKindNone, 2364 mfence: defKindNone, 2365 xchg: defKindNone, 2366 lockcmpxchg: defKindNone, 2367 lockxadd: defKindNone, 2368 neg: defKindNone, 2369 nopUseReg: defKindNone, 2370 } 2371 2372 // String implements fmt.Stringer. 2373 func (d defKind) String() string { 2374 switch d { 2375 case defKindNone: 2376 return "none" 2377 case defKindOp2: 2378 return "op2" 2379 case defKindCall: 2380 return "call" 2381 case defKindDivRem: 2382 return "divrem" 2383 default: 2384 return "invalid" 2385 } 2386 } 2387 2388 type useKind byte 2389 2390 const ( 2391 useKindNone useKind = iota + 1 2392 useKindOp1 2393 // useKindOp1Op2Reg is Op1 can be any operand, Op2 must be a register. 2394 useKindOp1Op2Reg 2395 // useKindOp1RegOp2 is Op1 must be a register, Op2 can be any operand. 2396 useKindOp1RegOp2 2397 // useKindRaxOp1RegOp2 is Op1 must be a register, Op2 can be any operand, and RAX is used. 2398 useKindRaxOp1RegOp2 2399 useKindDivRem 2400 useKindBlendvpd 2401 useKindCall 2402 useKindCallInd 2403 useKindFcvtToSintSequence 2404 useKindFcvtToUintSequence 2405 ) 2406 2407 var useKinds = [instrMax]useKind{ 2408 nop0: useKindNone, 2409 ret: useKindNone, 2410 movRR: useKindOp1, 2411 movRM: useKindOp1RegOp2, 2412 xmmMovRM: useKindOp1RegOp2, 2413 cmove: useKindOp1Op2Reg, 2414 aluRmiR: useKindOp1Op2Reg, 2415 shiftR: useKindOp1Op2Reg, 2416 imm: useKindNone, 2417 unaryRmR: useKindOp1, 2418 xmmRmiReg: useKindOp1Op2Reg, 2419 xmmUnaryRmR: useKindOp1, 2420 xmmUnaryRmRImm: useKindOp1, 2421 xmmCmpRmR: useKindOp1Op2Reg, 2422 xmmRmR: useKindOp1Op2Reg, 2423 xmmRmRImm: useKindOp1Op2Reg, 2424 mov64MR: useKindOp1, 2425 movzxRmR: useKindOp1, 2426 movsxRmR: useKindOp1, 2427 gprToXmm: useKindOp1, 2428 xmmToGpr: useKindOp1, 2429 call: useKindCall, 2430 callIndirect: useKindCallInd, 2431 ud2: useKindNone, 2432 jmpIf: useKindOp1, 2433 jmp: useKindOp1, 2434 cmpRmiR: useKindOp1Op2Reg, 2435 exitSequence: useKindOp1, 2436 lea: useKindOp1, 2437 jmpTableIsland: useKindNone, 2438 setcc: useKindNone, 2439 zeros: useKindNone, 2440 sourceOffsetInfo: useKindNone, 2441 fcvtToSintSequence: useKindFcvtToSintSequence, 2442 defineUninitializedReg: useKindNone, 2443 fcvtToUintSequence: useKindFcvtToUintSequence, 2444 xmmCMov: useKindOp1, 2445 idivRemSequence: useKindDivRem, 2446 blendvpd: useKindBlendvpd, 2447 mfence: useKindNone, 2448 xchg: useKindOp1RegOp2, 2449 lockcmpxchg: useKindRaxOp1RegOp2, 2450 lockxadd: useKindOp1RegOp2, 2451 neg: useKindOp1, 2452 nopUseReg: useKindOp1, 2453 } 2454 2455 func (u useKind) String() string { 2456 switch u { 2457 case useKindNone: 2458 return "none" 2459 case useKindOp1: 2460 return "op1" 2461 case useKindOp1Op2Reg: 2462 return "op1op2Reg" 2463 case useKindOp1RegOp2: 2464 return "op1RegOp2" 2465 case useKindCall: 2466 return "call" 2467 case useKindCallInd: 2468 return "callInd" 2469 default: 2470 return "invalid" 2471 } 2472 }