Optional Two-phase heap tracing
[hiphop-php.git] / hphp / util / asm-x64.cpp
bloba81755d3c615b4450baba074ba4ed2378b9b4c76
1 /*
2 +----------------------------------------------------------------------+
3 | HipHop for PHP |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
16 #include "hphp/util/asm-x64.h"
18 #include <folly/Format.h>
20 #include "hphp/util/safe-cast.h"
22 namespace HPHP { namespace jit {
24 // These are in order according to the binary encoding of the X64
25 // condition codes.
26 const char* cc_names[] = {
27 "O", "NO", "B", "AE", "E", "NE", "BE", "A",
28 "S", "NS", "P", "NP", "L", "GE", "LE", "G"
31 const char* show(RoundDirection rd) {
32 switch (rd) {
33 case RoundDirection::nearest: return "nearest";
34 case RoundDirection::floor: return "floor";
35 case RoundDirection::ceil: return "ceil";
36 case RoundDirection::truncate: return "truncate";
38 not_reached();
41 namespace x64 {
43 void DecodedInstruction::decode(uint8_t* ip) {
44 m_ip = ip;
45 m_flagsVal = 0;
46 m_map_select = 0;
47 m_xtra_op = 0;
48 m_immSz = sz::nosize;
49 m_offSz = sz::nosize;
51 while (decodePrefix(ip)) {
52 ++ip;
54 while (int sz = decodeRexVexXop(ip)) {
55 ip += sz;
58 ip += decodeOpcode(ip);
59 ip += decodeModRm(ip);
60 ip += m_offSz + m_immSz;
61 m_size = ip - m_ip;
64 bool DecodedInstruction::decodePrefix(uint8_t* ip) {
65 switch (*ip) {
66 case 0xf0: m_flags.lock = 1; return true;
67 case 0xf2: m_flags.repNE = 1; return true;
68 case 0xf3: m_flags.rep = 1; return true;
70 case 0x26: m_flags.es = 1; return true;
71 case 0x2e: m_flags.bTaken = 1; return true;
72 case 0x36: m_flags.ss = 1; return true;
73 case 0x3e: m_flags.bNotTaken = 1; return true;
74 case 0x64: m_flags.fs = 1; return true;
75 case 0x65: m_flags.gs = 1; return true;
77 case 0x66: m_flags.opndSzOvr = 1; return true;
78 case 0x67: m_flags.addrSzOvr = 1; return true;
80 return false;
83 int DecodedInstruction::decodeRexVexXop(uint8_t* ip) {
84 if ((*ip & 0xf0) == 0x40) {
85 m_flags.rex = 1;
86 m_flags.w = *ip & 8 ? 1 : 0;
87 m_flags.r = *ip & 4 ? 1 : 0;
88 m_flags.x = *ip & 2 ? 1 : 0;
89 m_flags.b = *ip & 1 ? 1 : 0;
90 return 1;
93 int sz = 0;
94 switch (*ip) {
95 case 0xc4:
96 case 0x8f:
97 if (*ip == 0xc4) {
98 m_flags.vex = 1;
99 } else {
100 // 0x8f is both a valid one-byte opcode and the first byte of the
101 // 3-byte XOP prefix. Figure out which one we have here by inspecting
102 // the next byte.
103 if (ip[1] & 0x18) {
104 m_flags.xop = 1;
105 } else {
106 return 0;
110 sz = 3;
111 m_flags.r = ip[1] & 0x80 ? 0 : 1;
112 m_flags.x = ip[1] & 0x40 ? 0 : 1;
113 m_flags.b = ip[1] & 0x20 ? 0 : 1;
114 m_map_select = ip[1] & 0x1f;
115 assert(m_map_select >= 1 && (m_flags.xop || m_map_select <= 3));
116 m_flags.w = ip[2] & 0x80 ? 1 : 0;
117 ip += 2;
118 break;
119 case 0xc5:
120 sz = 2;
121 m_flags.vex = 1;
122 m_flags.r = ip[1] & 0x80 ? 0 : 1;
123 m_map_select = 1;
124 ip++;
125 break;
126 default:
127 return 0;
130 // The final 7 bits of all VEX/XOP prefixes are the same:
131 m_xtra_op = (~ip[0] >> 3) & 0x0f;
132 m_flags.l = ip[0] & 0x04 ? 1 : 0;
133 switch (ip[0] & 3) {
134 case 0: break;
135 case 1: m_flags.opndSzOvr = 1; break;
136 case 2: m_flags.rep = 1; break;
137 case 3: m_flags.repNE = 1; break;
139 return sz;
142 int DecodedInstruction::decodeOpcode(uint8_t* ip) {
143 int sz = 1;
144 if (*ip == 0x0f) {
145 ++ip;
146 ++sz;
147 m_map_select = 1;
148 if (*ip == 0x38) {
149 ++ip;
150 ++sz;
151 m_map_select = 2;
152 } else if (*ip == 0x3a) {
153 ++ip;
154 ++sz;
155 m_map_select = 3;
159 m_opcode = *ip;
160 switch (m_map_select) {
161 case 0: determineOperandsMap0(ip); break;
162 case 1: determineOperandsMap1(ip); break;
163 case 2: determineOperandsMap2(ip); break;
164 case 3: determineOperandsMap3(ip); break;
165 default: assert(false);
167 return sz;
170 void DecodedInstruction::determineOperandsMap0(uint8_t* ip) {
171 switch (m_opcode >> 4) {
172 case 0x00:
173 case 0x01:
174 case 0x02:
175 case 0x03:
176 if ((m_opcode & 0x04) == 0) {
177 m_flags.hasModRm = true;
178 } else if ((m_opcode & 0x07) == 4) {
179 m_immSz = sz::byte;
180 } else if ((m_opcode & 0x07) == 5) {
181 m_immSz = m_flags.opndSzOvr ? sz::word : sz::dword;
183 break;
184 case 0x04: break; // REX
185 case 0x05:
186 m_flags.def64 = 1;
187 break;
188 case 0x06:
189 if ((m_opcode & 0x0c) == 0x08) {
190 m_immSz = m_opcode & 0x02 ? sz::byte :
191 m_flags.opndSzOvr ? sz::word : sz::dword;
193 break;
194 case 0x07:
195 m_flags.picOff = true;
196 m_offSz = sz::byte;
197 break;
198 case 0x08:
199 m_flags.hasModRm = true;
200 if ((m_opcode & 0x0c) == 0) {
201 m_immSz = (m_opcode & 0x0f) != 1 ? sz::byte :
202 m_flags.opndSzOvr ? sz::word : sz::dword;
204 break;
205 case 0x09:
206 break;
207 case 0x0a:
208 if ((m_opcode & 0x0c) == 0) {
209 m_offSz = m_flags.addrSzOvr ? sz::dword : sz::qword;
210 } else if ((m_opcode & 0x0e) == 8) {
211 m_immSz = !(m_opcode & 1) ? sz::byte :
212 m_flags.opndSzOvr ? sz::word : sz::dword;
214 break;
215 case 0x0b:
216 m_immSz = ((m_opcode & 8) == 0 ? sz::byte :
217 m_flags.w ? sz::qword :
218 m_flags.opndSzOvr ? sz::word : sz::dword);
219 break;
220 case 0x0c:
221 m_flags.hasModRm = !(m_opcode & 8) && (m_opcode & 6) != 2;
222 switch (m_opcode & 0x0f) {
223 case 0: case 1: case 6: case 13:
224 m_immSz = sz::byte;
225 break;
226 case 2: case 10:
227 m_immSz = sz::word;
228 break;
229 case 7:
230 m_immSz = m_flags.opndSzOvr ? sz::word : sz::dword;
231 break;
232 case 8:
233 m_offSz = sz::word;
234 m_immSz = sz::byte;
235 break;
237 break;
238 case 0x0d:
239 m_flags.hasModRm = (m_opcode & 0x0c) == 0;
240 m_immSz = (m_opcode & 0x0e) == 4 ? sz::byte : sz::nosize;
241 break;
242 case 0x0e: {
243 uint8_t siz = sz::nosize;
244 if ((m_opcode & 0x08) == 0 || (m_opcode & 0x0f) == 0xb) {
245 siz = sz::byte;
246 } else if ((m_opcode & 0x0e) == 0x8) {
247 siz = sz::dword;
249 if (siz != sz::nosize) {
250 if (!(m_opcode & 0x04)) {
251 m_offSz = siz;
252 m_flags.picOff = true;
253 } else {
254 m_immSz = siz;
257 break;
259 case 0x0f:
260 if ((m_opcode & 0x06) == 0x06) {
261 m_flags.hasModRm = true;
262 if (!(m_opcode & 0x08) && !((ip[1] >> 3) & 7)) {
263 m_immSz = !(m_opcode & 1) ? sz::byte :
264 m_flags.opndSzOvr ? sz::word : sz::dword;
267 break;
271 void DecodedInstruction::determineOperandsMap1(uint8_t* /*ip*/) {
272 switch (m_opcode >> 4) {
273 case 0:
274 if ((m_opcode & 15) < 4 || (m_opcode & 15) == 13) {
275 m_flags.hasModRm = true;
277 break;
278 case 0x01: case 0x02: case 0x04: case 0x05: case 0x06:
279 m_flags.hasModRm = true;
280 break;
281 case 0x03:
282 break;
283 case 0x07:
284 m_flags.hasModRm = (m_opcode & 15) != 7;
285 m_immSz = (m_opcode & 15) < 4 ? sz::byte : sz::nosize;
286 break;
287 case 0x08:
288 m_offSz = sz::dword;
289 m_flags.picOff = true;
290 break;
291 case 0x09:
292 m_flags.hasModRm = true;
293 break;
294 case 0x0a:
295 m_flags.hasModRm = (m_opcode & 7) >= 3;
296 if ((m_opcode & 7) == 4) m_immSz = sz::byte;
297 break;
298 case 0x0b:
299 m_flags.hasModRm = true;
300 if ((m_opcode & 15) == 0x0a) m_immSz = sz::byte;
301 break;
302 case 0x0c:
303 if (!(m_opcode & 8)) {
304 m_flags.hasModRm = true;
305 switch (m_opcode & 7) {
306 case 0x02:
307 case 0x04:
308 case 0x05:
309 case 0x06:
310 m_immSz = sz::byte;
311 break;
314 break;
315 case 0x0d:
316 case 0x0e:
317 case 0x0f:
318 m_flags.hasModRm = true;
319 break;
323 void DecodedInstruction::determineOperandsMap2(uint8_t* /*ip*/) {
324 m_flags.hasModRm = true;
325 if (m_opcode == 0x13) m_immSz = sz::byte;
328 void DecodedInstruction::determineOperandsMap3(uint8_t* /*ip*/) {
329 m_flags.hasModRm = true;
330 m_immSz = sz::byte;
333 int DecodedInstruction::decodeModRm(uint8_t* ip) {
334 if (!m_flags.hasModRm) return 0;
335 int size = 1;
336 if ((*ip & 0xc7) == 0x05) {
337 m_flags.picOff = true;
338 m_offSz = sz::dword;
339 } else {
340 if ((*ip & 0xc0) != 0xc0 &&
341 (*ip & 0x07) == 0x04) {
342 m_flags.hasSib = true;
343 size++;
345 if ((*ip & 0xc0) == 0x00) {
346 if (m_flags.hasSib && (ip[1] & 7) == 0x05) {
347 m_offSz = sz::dword;
349 } else if ((*ip & 0xc0) == 0x40) {
350 m_offSz = sz::byte;
351 } else if ((*ip & 0xc0) == 0x80) {
352 m_offSz = sz::dword;
355 return size;
359 * Read the numeric value stored at `ip`. It's widened to 64 bits (if smaller
360 * than 8 serialized bytes) but the MSB's sign is preserved.
362 static int64_t readValue(uint8_t* ip, int size) {
363 int64_t value = 0;
364 // This is the most-significant byte, so keep its sign.
365 value = (signed char)ip[--size];
366 while (size--) {
367 // Shift left 8 bits. (UBSAN doesn't like `<<` with signed values.)
368 value *= 256;
369 value += (uint64_t) ip[size];
371 return value;
374 static bool writeValue(uint8_t* ip, int size, int64_t v) {
375 auto value = uint64_t(v);
376 if (size * CHAR_BIT < 64) {
377 auto topBit = uint64_t(1) << (size * CHAR_BIT - 1);
378 if (value + topBit >= topBit * 2) return false;
381 while (size--) {
382 *ip++ = (uint8_t)value;
383 value >>= CHAR_BIT;
385 return true;
389 std::string DecodedInstruction::toString() {
390 auto str = folly::format("{:08x} {:02x}",
391 (uint64_t)m_ip,
392 m_opcode).str();
393 if (m_flags.hasModRm) {
394 auto modRm = getModRm();
395 str += folly::format(" ModRM({:02b} {} {})",
396 modRm >> 6,
397 (modRm >> 3) & 7,
398 modRm & 7).str();
399 if (m_flags.hasSib) {
400 auto sib = m_ip[m_size - m_immSz - m_offSz - 1];
401 str += folly::format(" SIB({:02b} {} {})",
402 sib >> 6,
403 (sib >> 3) & 7,
404 sib & 7).str();
408 auto ip = m_ip + m_size - m_immSz - m_offSz;
409 if (m_offSz) {
410 int64_t value = readValue(ip, m_offSz);
411 ip += m_offSz;
412 str += folly::format(" {}{:+x}",
413 m_flags.picOff ? "rip" : "",
414 value).str();
415 if (m_flags.picOff) {
416 str += folly::format("({:08x})", uintptr_t(m_ip + m_size + value)).str();
420 if (m_immSz) {
421 int64_t value = readValue(ip, m_immSz);
422 ip += m_immSz;
423 str += folly::format(" #{}", value).str();
425 return str;
428 int32_t DecodedInstruction::offset() const {
429 assert(hasOffset());
430 auto const addr = m_ip + m_size;
431 return safe_cast<int32_t>(readValue(addr - m_offSz, m_offSz));
434 uint8_t* DecodedInstruction::picAddress() const {
435 assert(hasPicOffset());
436 uint8_t* addr = m_ip + m_size;
437 uint8_t* rel = m_base + m_size;
438 return rel + readValue(addr - m_immSz - m_offSz, m_offSz);
441 bool DecodedInstruction::setPicAddress(uint8_t* target) {
442 assert(hasPicOffset());
443 uint8_t* addr = m_ip + m_size;
444 uint8_t* rel = m_base + m_size;
445 ptrdiff_t diff = target - rel;
447 return writeValue(addr - m_offSz - m_immSz, m_offSz, diff);
450 int64_t DecodedInstruction::immediate() const {
451 assert(hasImmediate());
452 return readValue(m_ip + m_size - m_immSz, m_immSz);
455 bool DecodedInstruction::setImmediate(int64_t value) {
456 assert(hasImmediate());
457 return writeValue(m_ip + m_size - m_immSz, m_immSz, value);
460 bool DecodedInstruction::isNop() const {
461 if (m_opcode == 0x90) {
462 return m_size == 1 || (m_size == 2 && m_flags.opndSzOvr);
464 return m_opcode == 0x1f && m_map_select == 1;
467 bool DecodedInstruction::isBranch(BranchType branchType
468 /* = Conditional |
469 Unconditional */) const {
470 if (!m_flags.picOff) return false;
471 if (m_map_select == 0) {
472 // The one-byte opcode map
473 return
474 ((m_opcode & 0xf0) == 0x70 /* 8-bit conditional branch */ &&
475 (branchType & Conditional)) ||
476 ((m_opcode == 0xe9 /* 32-bit unconditional branch */ ||
477 m_opcode == 0xeb /* 8-bit unconditional branch */) &&
478 (branchType & Unconditional));
480 if (m_map_select == 1 && (branchType & Conditional)) {
481 // The two-byte opcode map (first byte is 0x0f)
482 return (m_opcode & 0xf0) == 0x80 /* 32-bit conditional branch */;
484 return false;
487 bool DecodedInstruction::isCall() const {
488 if (m_map_select != 0) return false;
489 if (m_opcode == 0xe8) return true;
490 if (m_opcode != 0xff) return false;
491 return ((getModRm() >> 3) & 0x6) == 2;
494 bool DecodedInstruction::isJmp() const {
495 if (m_map_select != 0) return false;
496 return m_opcode == 0xe9;
499 bool DecodedInstruction::isLea() const {
500 if (m_map_select != 0) return false;
501 return m_opcode == 0x8d;
504 ConditionCode DecodedInstruction::jccCondCode() const {
505 if (m_map_select == 0) {
506 assert((m_opcode & 0xf0) == 0x70); // 8-bit jcc
507 } else {
508 assert(m_map_select == 1);
509 assert((m_opcode & 0xf0) == 0x80); // 32-bit jcc
511 return static_cast<ConditionCode>(m_opcode & 0x0f);
514 bool DecodedInstruction::shrinkBranch() {
515 assert(isBranch());
516 if (m_offSz != sz::dword) return false;
517 auto addr = m_ip + m_size - m_offSz;
518 auto delta = readValue(addr, m_offSz);
519 if (m_map_select == 1) {
520 if (m_flags.vex) return false;
521 assert((m_opcode & 0xf0) == 0x80); // must be a 32-bit conditional branch
523 The pc-relative offset is from the end of the instruction, and the
524 instruction is shrinking by 4 bytes (opcode goes from 2 bytes to 1,
525 and offset goes from 4 to 1), so we need to adjust delta by 4.
527 delta += 4;
528 if (-128 > delta || delta > 127) return false;
529 addr[-2] = 0x70 | (m_opcode & 0x0f); // make it an 8 bit conditional branch
530 addr[-1] = delta;
531 } else {
532 assert(m_opcode == 0xe9); // must be a 32-bit unconditional branch
534 As above, but opcode was already 1 byte, so the reduction is only 3
535 bytes this time.
537 delta += 3;
538 if (-128 > delta || delta > 127) return false;
539 addr[-1] = 0xeb;
540 addr[0] = delta;
542 decode(m_ip);
543 assert(isBranch() && m_offSz == 1);
544 return true;
547 void DecodedInstruction::widenBranch() {
548 assert(m_offSz == 1 && isBranch());
549 auto addr = m_ip + m_size - m_offSz;
550 auto delta = readValue(addr, 1);
551 if (m_opcode == 0xeb) {
552 addr[-1] = 0xe9;
553 writeValue(addr, 4, delta + 3);
554 } else {
555 addr[-1] = 0x0f;
556 addr[0] = 0x80 | (m_opcode & 0xf);
557 writeValue(addr + 1, 4, delta + 4);
559 decode(m_ip);
560 assert(isBranch() && m_offSz == 4);
563 uint8_t DecodedInstruction::getModRm() const {
564 assert(m_flags.hasModRm);
565 return m_ip[m_size - m_immSz - m_offSz - m_flags.hasSib - 1];
568 #define FUSEABLE_INSTRUCTIONS \
569 TEST(0x84, 0xFF) \
570 TEST(0x85, 0xFF) \
571 TEST(0xA8, 0xFF) \
572 TEST(0xA9, 0xFF) \
573 TEST(0xF6, 0) \
574 TEST(0xF6, 1) \
575 TEST(0xF7, 0) \
576 TEST(0xF7, 1) \
577 AND(0x20, 0xFF, true) \
578 AND(0x21, 0xFF, true) \
579 AND(0x22, 0xFF, false) \
580 AND(0x23, 0xFF, false) \
581 AND(0x24, 0xFF, false) \
582 AND(0x25, 0xFF, false) \
583 AND(0x80, 4, true) \
584 AND(0x81, 4, true) \
585 AND(0x83, 4, true) \
586 CMP(0x38, 0xFF) \
587 CMP(0x39, 0xFF) \
588 CMP(0x3A, 0xFF) \
589 CMP(0x3B, 0xFF) \
590 CMP(0x3C, 0xFF) \
591 CMP(0x3D, 0xFF) \
592 CMP(0x80, 7) \
593 CMP(0x81, 7) \
594 CMP(0x83, 7) \
595 ADD(0x00, 0xFF, true) \
596 ADD(0x01, 0xFF, true) \
597 ADD(0x02, 0xFF, false) \
598 ADD(0x03, 0xFF, false) \
599 ADD(0x04, 0xFF, false) \
600 ADD(0x05, 0xFF, false) \
601 ADD(0x80, 0, true) \
602 ADD(0x81, 0, true) \
603 ADD(0x83, 0, true) \
604 SUB(0x28, 0xFF, true) \
605 SUB(0x29, 0xFF, true) \
606 SUB(0x2A, 0xFF, false) \
607 SUB(0x2B, 0xFF, false) \
608 SUB(0x2C, 0xFF, false) \
609 SUB(0x2D, 0xFF, false) \
610 SUB(0x80, 5, true) \
611 SUB(0x81, 5, true) \
612 SUB(0x83, 5, true) \
613 INC(0xFE, 0) \
614 INC(0xFF, 0) \
615 DEC(0xFE, 1) \
616 DEC(0xFF, 1)
618 #define TEST(i, j) \
619 X(i, j, false, CC_O, CC_NO, CC_B, CC_NAE, CC_AE, CC_NB, CC_NC, CC_E, CC_Z, \
620 CC_NE, CC_NZ, CC_BE, CC_NA, CC_A, CC_NBE, CC_S, CC_NS, CC_P, CC_NP, CC_L, \
621 CC_NGE, CC_GE, CC_NL, CC_LE, CC_NG, CC_G, CC_NLE)
622 #define AND(i, j, k) \
623 X(i, j, k, CC_O, CC_NO, CC_B, CC_NAE, CC_AE, CC_NB, CC_NC, CC_E, CC_Z, \
624 CC_NE, CC_NZ, CC_BE, CC_NA, CC_A, CC_NBE, CC_S, CC_NS, CC_P, CC_NP, CC_L, \
625 CC_NGE, CC_GE, CC_NL, CC_LE, CC_NG, CC_G, CC_NLE)
626 #define CMP(i, j) \
627 X(i, j, false, CC_B, CC_NAE, CC_AE, CC_NB, CC_NC, CC_E, CC_Z, CC_NE, CC_NZ, \
628 CC_BE, CC_NA, CC_A, CC_NBE, CC_L, CC_NGE, CC_GE, CC_NL, CC_LE, CC_NG, \
629 CC_G, CC_NLE)
630 #define ADD(i, j, k) \
631 X(i, j, k, CC_B, CC_NAE, CC_AE, CC_NB, CC_NC, CC_E, CC_Z, CC_NE, CC_NZ, \
632 CC_BE, CC_NA, CC_A, CC_NBE, CC_L, CC_NGE, CC_GE, CC_NL, CC_LE, CC_NG, \
633 CC_G, CC_NLE)
634 #define SUB(i, j, k) \
635 X(i, j, k, CC_B, CC_NAE, CC_AE, CC_NB, CC_NC, CC_E, CC_Z, CC_NE, CC_NZ, \
636 CC_BE, CC_NA, CC_A, CC_NBE, CC_L, CC_NGE, CC_GE, CC_NL, CC_LE, CC_NG, \
637 CC_G, CC_NLE)
638 #define INC(i, j) \
639 X(i, j, true, CC_E, CC_Z, CC_NE, CC_NZ, CC_L, CC_NGE, CC_GE, CC_NL, CC_LE, \
640 CC_NG, CC_G, CC_NLE)
641 #define DEC(i, j) \
642 X(i, j, true, CC_E, CC_Z, CC_NE, CC_NZ, CC_L, CC_NGE, CC_GE, CC_NL, CC_LE, \
643 CC_NG, CC_G, CC_NLE)
645 bool DecodedInstruction::isFuseable(const DecodedInstruction& next) const {
646 // Assumes no invalid instructions.
647 if (m_map_select != 0 || // No multibyte instructions are fuseable.
648 hasPicOffset() || // No rip relative addressing
649 !next.isBranch(Conditional)) {
650 return false;
653 // Find extra 3 bits of opcode in the modrm byte if this opcode has it.
654 uint32_t e = 0xFF;
655 switch (m_opcode) {
656 case 0xF6: case 0xF7: case 0x80: case 0x81: case 0x83: case 0xFE: case 0xFF:
657 e = m_flags.hasModRm ? (getModRm() & 0x38) >> 3 : -1;
658 break;
659 default:
660 break;
663 switch (e << 16 | m_opcode) {
664 #define X(opcode, opExt, operand1IsDest, ...) \
665 case (opExt << 16 | opcode): { \
666 if ((operand1IsDest || hasImmediate()) && \
667 m_flags.hasModRm && (getModRm() & 0xC0) != 0xC0) { \
668 /* No fusing instruction with immediate and memory operands. */ \
669 /* Also cannot fuse instructions with destination memory operand. */ \
670 return false; \
672 const ConditionCode ccs[] = { __VA_ARGS__ }; \
673 for (size_t i = 0; i < sizeof(ccs) / sizeof(ConditionCode); ++i) { \
674 if (next.jccCondCode() == ccs[i]) { \
675 return true; \
678 break; \
680 FUSEABLE_INSTRUCTIONS
681 #undef X
682 default:
683 break;
685 return false;
688 #undef TEST
689 #undef AND
690 #undef CMP
691 #undef ADD
692 #undef SUB
693 #undef INC
694 #undef DEC
696 #undef FUSEABLE_INSTRUCTIONS