this repo has no description
1// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
2// Copyright (c) 2013, the Dart project authors and Facebook, Inc. and its
3// affiliates. Please see the AUTHORS-Dart file for details. All rights
4// reserved. Use of this source code is governed by a BSD-style license that
5// can be found in the LICENSE-Dart file.
6
7#include "assembler-x64.h"
8
9#include <cstdarg>
10#include <cstdio>
11#include <cstring>
12
13#include "globals.h"
14
15namespace py {
16namespace x64 {
17
18void Assembler::initializeMemoryWithBreakpoints(uword data, word length) {
19 std::memset(reinterpret_cast<void*>(data), 0xcc, length);
20}
21
22void Assembler::call(Label* label) {
23 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
24 static const int size = 5;
25 emitUint8(0xe8);
26 emitLabel(label, size);
27}
28
29void Assembler::pushq(Register reg) {
30 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
31 emitRegisterREX(reg, REX_NONE);
32 emitUint8(0x50 | (reg & 7));
33}
34
35void Assembler::pushq(Immediate imm) {
36 if (imm.isInt8()) {
37 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
38 emitUint8(0x6a);
39 emitUint8(imm.value() & 0xff);
40 } else {
41 DCHECK(imm.isInt32(), "assert()");
42 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
43 emitUint8(0x68);
44 emitImmediate(imm);
45 }
46}
47
48void Assembler::popq(Register reg) {
49 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
50 emitRegisterREX(reg, REX_NONE);
51 emitUint8(0x58 | (reg & 7));
52}
53
54void Assembler::setcc(Condition condition, Register dst) {
55 DCHECK(dst != kNoRegister, "assert()");
56 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
57 if (dst >= 8) {
58 emitUint8(REX_PREFIX | (((dst & 0x08) != 0) ? REX_B : REX_NONE));
59 }
60 emitUint8(0x0f);
61 emitUint8(0x90 + condition);
62 emitUint8(0xc0 + (dst & 0x07));
63}
64
65void Assembler::emitQ(int reg, Address address, int opcode, int prefix2,
66 int prefix1) {
67 DCHECK(reg <= XMM15, "assert()");
68 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
69 if (prefix1 >= 0) {
70 emitUint8(prefix1);
71 }
72 emitOperandREX(reg, address, REX_W);
73 if (prefix2 >= 0) {
74 emitUint8(prefix2);
75 }
76 emitUint8(opcode);
77 emitOperand(reg & 7, address);
78}
79
80void Assembler::emitB(Register reg, Address address, int opcode, int prefix2,
81 int prefix1) {
82 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
83 if (prefix1 >= 0) {
84 emitUint8(prefix1);
85 }
86 emitOperandREX(reg, address, byteRegisterREX(reg));
87 if (prefix2 >= 0) {
88 emitUint8(prefix2);
89 }
90 emitUint8(opcode);
91 emitOperand(reg & 7, address);
92}
93
94void Assembler::emitL(int reg, Address address, int opcode, int prefix2,
95 int prefix1) {
96 DCHECK(reg <= XMM15, "assert()");
97 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
98 if (prefix1 >= 0) {
99 emitUint8(prefix1);
100 }
101 emitOperandREX(reg, address, REX_NONE);
102 if (prefix2 >= 0) {
103 emitUint8(prefix2);
104 }
105 emitUint8(opcode);
106 emitOperand(reg & 7, address);
107}
108
109void Assembler::emitW(Register reg, Address address, int opcode, int prefix2,
110 int prefix1) {
111 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
112 if (prefix1 >= 0) {
113 emitUint8(prefix1);
114 }
115 emitOperandSizeOverride();
116 emitOperandREX(reg, address, REX_NONE);
117 if (prefix2 >= 0) {
118 emitUint8(prefix2);
119 }
120 emitUint8(opcode);
121 emitOperand(reg & 7, address);
122}
123
124void Assembler::movl(Register dst, Immediate imm) {
125 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
126 Operand operand(dst);
127 emitOperandREX(0, operand, REX_NONE);
128 emitUint8(0xc7);
129 emitOperand(0, operand);
130 DCHECK(imm.isInt32(), "assert()");
131 emitImmediate(imm);
132}
133
134void Assembler::movl(Address dst, Immediate imm) {
135 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
136 Operand operand(dst);
137 emitOperandREX(0, dst, REX_NONE);
138 emitUint8(0xc7);
139 emitOperand(0, dst);
140 DCHECK(imm.isInt32(), "assert()");
141 emitImmediate(imm);
142}
143
144void Assembler::movb(Address dst, Immediate imm) {
145 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
146 emitOperandREX(0, dst, REX_NONE);
147 emitUint8(0xc6);
148 emitOperand(0, dst);
149 DCHECK(imm.isInt8(), "assert()");
150 emitUint8(imm.value() & 0xff);
151}
152
153void Assembler::movw(Register /*dst*/, Address /*src*/) {
154 UNIMPLEMENTED("Use movzxw or movsxw instead.");
155}
156
157void Assembler::movw(Address dst, Immediate imm) {
158 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
159 emitOperandSizeOverride();
160 emitOperandREX(0, dst, REX_NONE);
161 emitUint8(0xc7);
162 emitOperand(0, dst);
163 emitUint8(imm.value() & 0xff);
164 emitUint8((imm.value() >> 8) & 0xff);
165}
166
167void Assembler::leaq(Register dst, Label* label) {
168 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
169 // Emit RIP-relative lea
170 emitUint8(REX_PREFIX | REX_W | (dst > 7 ? REX_R : REX_NONE));
171 emitUint8(0x8d);
172 Address address(Address::addressRIPRelative(0xdeadbeef));
173 emitOperand(dst & 7, address);
174 // Overwrite the fake displacement with a label or label link
175 buffer_.remit<uint32_t>();
176 static const int size = 7;
177 emitLabel(label, size);
178}
179
180void Assembler::movq(Register dst, Immediate imm) {
181 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
182 if (imm.isUint32()) {
183 // Pick single byte B8 encoding if possible. If dst < 8 then we also omit
184 // the Rex byte.
185 emitRegisterREX(dst, REX_NONE);
186 emitUint8(0xb8 | (dst & 7));
187 emitUInt32(imm.value());
188 } else if (imm.isInt32()) {
189 // Sign extended C7 Cx encoding if we have a negative input.
190 Operand operand(dst);
191 emitOperandREX(0, operand, REX_W);
192 emitUint8(0xc7);
193 emitOperand(0, operand);
194 emitImmediate(imm);
195 } else {
196 // Full 64 bit immediate encoding.
197 emitRegisterREX(dst, REX_W);
198 emitUint8(0xb8 | (dst & 7));
199 emitImmediate(imm);
200 }
201}
202
203void Assembler::movq(Address dst, Immediate imm) {
204 CHECK(imm.isInt32(), "this instruction only exists for 32bit immediates");
205 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
206 emitOperandREX(0, dst, REX_W);
207 emitUint8(0xC7);
208 emitOperand(0, dst);
209 emitImmediate(imm);
210}
211
212void Assembler::movsb() {
213 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
214 emitUint8(0xa4);
215}
216
217void Assembler::movsw() {
218 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
219 emitOperandSizeOverride();
220 emitUint8(0xa5);
221}
222
223void Assembler::movsl() {
224 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
225 emitUint8(0xa5);
226}
227
228void Assembler::movsq() {
229 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
230 emitUint8(REX_PREFIX | REX_W);
231 emitUint8(0xa5);
232}
233
234void Assembler::repMovsb() {
235 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
236 emitUint8(REP);
237 emitUint8(0xa4);
238}
239
240void Assembler::repMovsw() {
241 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
242 emitUint8(REP);
243 emitOperandSizeOverride();
244 emitUint8(0xa5);
245}
246
247void Assembler::repMovsl() {
248 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
249 emitUint8(REP);
250 emitUint8(0xa5);
251}
252
253void Assembler::repMovsq() {
254 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
255 emitUint8(REP);
256 emitUint8(REX_PREFIX | REX_W);
257 emitUint8(0xa5);
258}
259
260void Assembler::repnzMovsb() {
261 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
262 emitUint8(REPNZ);
263 emitUint8(0xa4);
264}
265
266void Assembler::repnzMovsw() {
267 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
268 emitUint8(REPNZ);
269 emitOperandSizeOverride();
270 emitUint8(0xa5);
271}
272
273void Assembler::repnzMovsl() {
274 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
275 emitUint8(REPNZ);
276 emitUint8(0xa5);
277}
278
279void Assembler::repnzMovsq() {
280 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
281 emitUint8(REPNZ);
282 emitUint8(REX_PREFIX | REX_W);
283 emitUint8(0xa5);
284}
285
286void Assembler::emitSimple(int opcode, int opcode2) {
287 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
288 emitUint8(opcode);
289 if (opcode2 != -1) {
290 emitUint8(opcode2);
291 }
292}
293
294void Assembler::emitQ(int dst, int src, int opcode, int prefix2, int prefix1) {
295 DCHECK(src <= XMM15, "assert()");
296 DCHECK(dst <= XMM15, "assert()");
297 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
298 if (prefix1 >= 0) {
299 emitUint8(prefix1);
300 }
301 emitRegRegREX(dst, src, REX_W);
302 if (prefix2 >= 0) {
303 emitUint8(prefix2);
304 }
305 emitUint8(opcode);
306 emitRegisterOperand(dst & 7, src);
307}
308
309void Assembler::emitL(int dst, int src, int opcode, int prefix2, int prefix1) {
310 DCHECK(src <= XMM15, "assert()");
311 DCHECK(dst <= XMM15, "assert()");
312 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
313 if (prefix1 >= 0) {
314 emitUint8(prefix1);
315 }
316 emitRegRegREX(dst, src);
317 if (prefix2 >= 0) {
318 emitUint8(prefix2);
319 }
320 emitUint8(opcode);
321 emitRegisterOperand(dst & 7, src);
322}
323
324void Assembler::emitW(Register dst, Register src, int opcode, int prefix2,
325 int prefix1) {
326 DCHECK(src <= R15, "assert()");
327 DCHECK(dst <= R15, "assert()");
328 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
329 if (prefix1 >= 0) {
330 emitUint8(prefix1);
331 }
332 emitOperandSizeOverride();
333 emitRegRegREX(dst, src);
334 if (prefix2 >= 0) {
335 emitUint8(prefix2);
336 }
337 emitUint8(opcode);
338 emitRegisterOperand(dst & 7, src);
339}
340
341void Assembler::cmpPS(XmmRegister dst, XmmRegister src, int condition) {
342 emitL(dst, src, 0xc2, 0x0f);
343 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
344 emitUint8(condition);
345}
346
347void Assembler::set1ps(XmmRegister dst, Register tmp, Immediate imm) {
348 // load 32-bit immediate value into tmp1.
349 movl(tmp, imm);
350 // Move value from tmp1 into dst.
351 movd(dst, tmp);
352 // Broadcast low lane into other three lanes.
353 shufps(dst, dst, Immediate(0x0));
354}
355
356void Assembler::shufps(XmmRegister dst, XmmRegister src, Immediate mask) {
357 emitL(dst, src, 0xc6, 0x0f);
358 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
359 DCHECK(mask.isUint8(), "assert()");
360 emitUint8(mask.value());
361}
362
363void Assembler::shufpd(XmmRegister dst, XmmRegister src, Immediate mask) {
364 emitL(dst, src, 0xc6, 0x0f, 0x66);
365 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
366 DCHECK(mask.isUint8(), "assert()");
367 emitUint8(mask.value());
368}
369
370void Assembler::roundsd(XmmRegister dst, XmmRegister src, RoundingMode mode) {
371 DCHECK(src <= XMM15, "assert()");
372 DCHECK(dst <= XMM15, "assert()");
373 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
374 emitUint8(0x66);
375 emitRegRegREX(dst, src);
376 emitUint8(0x0f);
377 emitUint8(0x3a);
378 emitUint8(0x0b);
379 emitRegisterOperand(dst & 7, src);
380 // Mask precision exeption.
381 emitUint8(static_cast<uint8_t>(mode) | 0x8);
382}
383
384void Assembler::fldl(Address src) {
385 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
386 emitUint8(0xdd);
387 emitOperand(0, src);
388}
389
390void Assembler::fstpl(Address dst) {
391 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
392 emitUint8(0xdd);
393 emitOperand(3, dst);
394}
395
396void Assembler::ffree(word value) {
397 DCHECK(value < 7, "assert()");
398 emitSimple(0xdd, 0xc0 + value);
399}
400
401void Assembler::emitTestB(Operand operand, Immediate imm) {
402 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
403 if (operand.hasRegister(RAX)) {
404 emitUint8(0xa8);
405 } else {
406 emitOperandREX(0, operand, byteOperandREX(operand));
407 emitUint8(0xf6);
408 emitOperand(0, operand);
409 }
410 DCHECK(imm.isInt8(), "immediate too large");
411 emitUint8(imm.value());
412}
413
414void Assembler::testb(Register dst, Register src) {
415 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
416 emitRegRegREX(dst, src, byteRegisterREX(dst) | byteRegisterREX(src));
417 emitUint8(0x84);
418 emitRegisterOperand(dst & 7, src);
419}
420
421void Assembler::testb(Register reg, Immediate imm) {
422 emitTestB(Operand(reg), imm);
423}
424
425void Assembler::testb(Address address, Immediate imm) {
426 emitTestB(address, imm);
427}
428
429void Assembler::testb(Address address, Register reg) {
430 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
431 emitOperandREX(reg, address, byteRegisterREX(reg));
432 emitUint8(0x84);
433 emitOperand(reg & 7, address);
434}
435
436void Assembler::emitTestQ(Operand operand, Immediate imm) {
437 // Try to emit a small instruction if the value of the immediate lets us. For
438 // Address operands, this relies on the fact that x86 is little-endian.
439 if (imm.isUint8()) {
440 emitTestB(operand, Immediate(static_cast<int8_t>(imm.value())));
441 } else if (imm.isUint32()) {
442 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
443 if (operand.hasRegister(RAX)) {
444 emitUint8(0xa9);
445 } else {
446 emitOperandREX(0, operand, REX_NONE);
447 emitUint8(0xf7);
448 emitOperand(0, operand);
449 }
450 emitUInt32(imm.value());
451 } else {
452 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
453 // Sign extended version of 32 bit test.
454 DCHECK(imm.isInt32(), "assert()");
455 emitOperandREX(0, operand, REX_W);
456 if (operand.hasRegister(RAX)) {
457 emitUint8(0xa9);
458 } else {
459 emitUint8(0xf7);
460 emitOperand(0, operand);
461 }
462 emitInt32(imm.value());
463 }
464}
465
466void Assembler::testq(Register reg, Immediate imm) {
467 emitTestQ(Operand(reg), imm);
468}
469
470void Assembler::testq(Address address, Immediate imm) {
471 emitTestQ(address, imm);
472}
473
474void Assembler::aluB(uint8_t modrm_opcode, Register dst, Immediate imm) {
475 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
476 Operand dst_operand(dst);
477 emitOperandREX(modrm_opcode, dst_operand, byteRegisterREX(dst));
478 emitComplexB(modrm_opcode, dst_operand, imm);
479}
480
481void Assembler::aluL(uint8_t modrm_opcode, Register dst, Immediate imm) {
482 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
483 emitRegisterREX(dst, REX_NONE);
484 emitComplex(modrm_opcode, Operand(dst), imm);
485}
486
487void Assembler::aluB(uint8_t modrm_opcode, Address dst, Immediate imm) {
488 DCHECK(imm.isUint8() || imm.isInt8(), "assert()");
489 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
490 emitOperandREX(modrm_opcode, dst, REX_NONE);
491 emitUint8(0x80);
492 emitOperand(modrm_opcode, dst);
493 emitUint8(imm.value() & 0xff);
494}
495
496void Assembler::aluW(uint8_t modrm_opcode, Address dst, Immediate imm) {
497 DCHECK(imm.isInt16() || imm.isUint16(), "assert()");
498 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
499 emitOperandSizeOverride();
500 emitOperandREX(modrm_opcode, dst, REX_NONE);
501 if (imm.isInt8()) {
502 emitSignExtendedInt8(modrm_opcode, dst, imm);
503 } else {
504 emitUint8(0x81);
505 emitOperand(modrm_opcode, dst);
506 emitUint8(imm.value() & 0xff);
507 emitUint8((imm.value() >> 8) & 0xff);
508 }
509}
510
511void Assembler::aluL(uint8_t modrm_opcode, Address dst, Immediate imm) {
512 DCHECK(imm.isInt32(), "assert()");
513 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
514 emitOperandREX(modrm_opcode, dst, REX_NONE);
515 emitComplex(modrm_opcode, dst, imm);
516}
517
518void Assembler::aluQ(uint8_t modrm_opcode, uint8_t /*opcode*/, Register dst,
519 Immediate imm) {
520 Operand operand(dst);
521 if (modrm_opcode == 4 && imm.isUint32()) {
522 // We can use andl for andq.
523 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
524 emitRegisterREX(dst, REX_NONE);
525 // Would like to use emitComplex here, but it doesn't like uint32
526 // immediates.
527 if (imm.isInt8()) {
528 emitSignExtendedInt8(modrm_opcode, operand, imm);
529 } else {
530 if (dst == RAX) {
531 emitUint8(0x25);
532 } else {
533 emitUint8(0x81);
534 emitOperand(modrm_opcode, operand);
535 }
536 emitUInt32(imm.value());
537 }
538 } else {
539 DCHECK(imm.isInt32(), "assert()");
540 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
541 emitRegisterREX(dst, REX_W);
542 emitComplex(modrm_opcode, operand, imm);
543 }
544}
545
546void Assembler::aluQ(uint8_t modrm_opcode, uint8_t /*opcode*/, Address dst,
547 Immediate imm) {
548 DCHECK(imm.isInt32(), "assert()");
549 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
550 emitOperandREX(modrm_opcode, dst, REX_W);
551 emitComplex(modrm_opcode, dst, imm);
552}
553
554void Assembler::cqo() {
555 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
556 emitRegisterREX(RAX, REX_W);
557 emitUint8(0x99);
558}
559
560void Assembler::emitUnaryQ(Register reg, int opcode, int modrm_code) {
561 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
562 emitRegisterREX(reg, REX_W);
563 emitUint8(opcode);
564 emitOperand(modrm_code, Operand(reg));
565}
566
567void Assembler::emitUnaryL(Register reg, int opcode, int modrm_code) {
568 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
569 emitRegisterREX(reg, REX_NONE);
570 emitUint8(opcode);
571 emitOperand(modrm_code, Operand(reg));
572}
573
574void Assembler::emitUnaryQ(Address address, int opcode, int modrm_code) {
575 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
576 Operand operand(address);
577 emitOperandREX(modrm_code, operand, REX_W);
578 emitUint8(opcode);
579 emitOperand(modrm_code, operand);
580}
581
582void Assembler::emitUnaryL(Address address, int opcode, int modrm_code) {
583 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
584 Operand operand(address);
585 emitOperandREX(modrm_code, operand, REX_NONE);
586 emitUint8(opcode);
587 emitOperand(modrm_code, operand);
588}
589
590void Assembler::imull(Register reg, Immediate imm) {
591 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
592 Operand operand(reg);
593 emitOperandREX(reg, operand, REX_NONE);
594 emitUint8(0x69);
595 emitOperand(reg & 7, Operand(reg));
596 emitImmediate(imm);
597}
598
599void Assembler::shll(Register reg, Immediate imm) {
600 emitGenericShift(false, 4, reg, imm);
601}
602
603void Assembler::shll(Register operand, Register shifter) {
604 emitGenericShift(false, 4, operand, shifter);
605}
606
607void Assembler::shrl(Register reg, Immediate imm) {
608 emitGenericShift(false, 5, reg, imm);
609}
610
611void Assembler::shrl(Register operand, Register shifter) {
612 emitGenericShift(false, 5, operand, shifter);
613}
614
615void Assembler::sarl(Register reg, Immediate imm) {
616 emitGenericShift(false, 7, reg, imm);
617}
618
619void Assembler::sarl(Register operand, Register shifter) {
620 emitGenericShift(false, 7, operand, shifter);
621}
622
623void Assembler::shldl(Register dst, Register src, Immediate imm) {
624 emitL(src, dst, 0xa4, 0x0f);
625 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
626 DCHECK(imm.isInt8(), "assert()");
627 emitUint8(imm.value() & 0xff);
628}
629
630void Assembler::shlq(Register reg, Immediate imm) {
631 emitGenericShift(true, 4, reg, imm);
632}
633
634void Assembler::shlq(Register operand, Register shifter) {
635 emitGenericShift(true, 4, operand, shifter);
636}
637
638void Assembler::shrq(Register reg, Immediate imm) {
639 emitGenericShift(true, 5, reg, imm);
640}
641
642void Assembler::shrq(Register operand, Register shifter) {
643 emitGenericShift(true, 5, operand, shifter);
644}
645
646void Assembler::sarq(Register reg, Immediate imm) {
647 emitGenericShift(true, 7, reg, imm);
648}
649
650void Assembler::sarq(Register operand, Register shifter) {
651 emitGenericShift(true, 7, operand, shifter);
652}
653
654void Assembler::shldq(Register dst, Register src, Immediate imm) {
655 emitQ(src, dst, 0xa4, 0x0f);
656 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
657 DCHECK(imm.isInt8(), "assert()");
658 emitUint8(imm.value() & 0xff);
659}
660
661void Assembler::btq(Register base, int bit) {
662 DCHECK(bit >= 0 && bit < 64, "assert()");
663 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
664 Operand operand(base);
665 emitOperandREX(4, operand, bit >= 32 ? REX_W : REX_NONE);
666 emitUint8(0x0f);
667 emitUint8(0xba);
668 emitOperand(4, operand);
669 emitUint8(bit);
670}
671
672void Assembler::enter(Immediate imm) {
673 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
674 emitUint8(0xc8);
675 DCHECK(imm.isUint16(), "assert()");
676 emitUint8(imm.value() & 0xff);
677 emitUint8((imm.value() >> 8) & 0xff);
678 emitUint8(0x00);
679}
680
681void Assembler::nop(int size) {
682 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
683 // There are nops up to size 15, but for now just provide up to size 8.
684 DCHECK(0 < size && size <= kMaxNopSize, "assert()");
685 switch (size) {
686 case 1:
687 emitUint8(0x90);
688 break;
689 case 2:
690 emitUint8(0x66);
691 emitUint8(0x90);
692 break;
693 case 3:
694 emitUint8(0x0f);
695 emitUint8(0x1f);
696 emitUint8(0x00);
697 break;
698 case 4:
699 emitUint8(0x0f);
700 emitUint8(0x1f);
701 emitUint8(0x40);
702 emitUint8(0x00);
703 break;
704 case 5:
705 emitUint8(0x0f);
706 emitUint8(0x1f);
707 emitUint8(0x44);
708 emitUint8(0x00);
709 emitUint8(0x00);
710 break;
711 case 6:
712 emitUint8(0x66);
713 emitUint8(0x0f);
714 emitUint8(0x1f);
715 emitUint8(0x44);
716 emitUint8(0x00);
717 emitUint8(0x00);
718 break;
719 case 7:
720 emitUint8(0x0f);
721 emitUint8(0x1f);
722 emitUint8(0x80);
723 emitUint8(0x00);
724 emitUint8(0x00);
725 emitUint8(0x00);
726 emitUint8(0x00);
727 break;
728 case 8:
729 emitUint8(0x0f);
730 emitUint8(0x1f);
731 emitUint8(0x84);
732 emitUint8(0x00);
733 emitUint8(0x00);
734 emitUint8(0x00);
735 emitUint8(0x00);
736 emitUint8(0x00);
737 break;
738 default:
739 UNIMPLEMENTED("default");
740 }
741}
742
743void Assembler::nops(int size) {
744 DCHECK(size >= 0, "Can't emit negative nops");
745 if (size == 0) return;
746 while (size > kMaxNopSize) {
747 nop(kMaxNopSize);
748 size -= kMaxNopSize;
749 }
750 nop(size);
751}
752
753void Assembler::ud2() {
754 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
755 emitUint8(0x0f);
756 emitUint8(0x0b);
757}
758
759void Assembler::jcc(Condition condition, Label* label, bool near) {
760 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
761 if (label->isBound()) {
762 static const int short_size = 2;
763 static const int long_size = 6;
764 word offset = label->position() - buffer_.size();
765 DCHECK(offset <= 0, "assert()");
766 if (Utils::fits<int8_t>(offset - short_size)) {
767 emitUint8(0x70 + condition);
768 emitUint8((offset - short_size) & 0xff);
769 } else {
770 emitUint8(0x0f);
771 emitUint8(0x80 + condition);
772 emitInt32(offset - long_size);
773 }
774 } else if (near) {
775 emitUint8(0x70 + condition);
776 emitNearLabelLink(label);
777 } else {
778 emitUint8(0x0f);
779 emitUint8(0x80 + condition);
780 emitLabelLink(label);
781 }
782}
783
784void Assembler::jmp(Label* label, bool near) {
785 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
786 if (label->isBound()) {
787 static const int short_size = 2;
788 static const int long_size = 5;
789 word offset = label->position() - buffer_.size();
790 DCHECK(offset <= 0, "assert()");
791 if (Utils::fits<int8_t>(offset - short_size)) {
792 emitUint8(0xeb);
793 emitUint8((offset - short_size) & 0xff);
794 } else {
795 emitUint8(0xe9);
796 emitInt32(offset - long_size);
797 }
798 } else if (near) {
799 emitUint8(0xeb);
800 emitNearLabelLink(label);
801 } else {
802 emitUint8(0xe9);
803 emitLabelLink(label);
804 }
805}
806
807void Assembler::bind(Label* label) {
808 word bound = buffer_.size();
809 DCHECK(!label->isBound(), "assert()"); // Labels can only be bound once.
810 while (label->isLinked()) {
811 word position = label->linkPosition();
812 word next = buffer_.load<int32_t>(position);
813 buffer_.store<int32_t>(position, bound - (position + 4));
814 label->position_ = next;
815 }
816 while (label->hasNear()) {
817 word position = label->nearPosition();
818 word offset = bound - (position + 1);
819 DCHECK(Utils::fits<int8_t>(offset), "assert()");
820 buffer_.store<int8_t>(position, offset);
821 }
822 label->bindTo(bound);
823}
824
825void Assembler::comment(const char* format, ...) {
826 char comment_buffer[1024];
827 va_list args;
828 ::va_start(args, format);
829 std::vsnprintf(comment_buffer, sizeof comment_buffer, format, args);
830 ::va_end(args);
831 comments_.add(new CodeComment(buffer_.getPosition(), comment_buffer));
832}
833
834void Assembler::align(int alignment) {
835 DCHECK(Utils::isPowerOfTwo(alignment), "assert()");
836 word pos = buffer_.getPosition();
837 int mod = pos & (alignment - 1);
838 if (mod == 0) {
839 return;
840 }
841 word bytes_needed = alignment - mod;
842 while (bytes_needed > kMaxNopSize) {
843 nop(kMaxNopSize);
844 bytes_needed -= kMaxNopSize;
845 }
846 if (bytes_needed) {
847 nop(bytes_needed);
848 }
849 DCHECK((buffer_.getPosition() & (alignment - 1)) == 0, "assert()");
850}
851
852void Assembler::emitOperand(int rm, Operand operand) {
853 DCHECK(rm >= 0 && rm < 8, "assert()");
854 const word length = operand.length_;
855 DCHECK(length > 0, "assert()");
856 // emit the ModRM byte updated with the given RM value.
857 DCHECK((operand.encoding_[0] & 0x38) == 0, "assert()");
858 emitUint8(operand.encoding_[0] + (rm << 3));
859 // emit the rest of the encoded operand.
860 for (word i = 1; i < length; i++) {
861 emitUint8(operand.encoding_[i]);
862 }
863}
864
865void Assembler::emitRegisterOperand(int rm, int reg) {
866 Operand operand;
867 operand.setModRM(3, static_cast<Register>(reg));
868 emitOperand(rm, operand);
869}
870
871void Assembler::emitImmediate(Immediate imm) {
872 if (imm.isInt32()) {
873 emitInt32(static_cast<int32_t>(imm.value()));
874 } else {
875 emitInt64(imm.value());
876 }
877}
878
879void Assembler::emitSignExtendedInt8(int rm, Operand operand,
880 Immediate immediate) {
881 emitUint8(0x83);
882 emitOperand(rm, operand);
883 emitUint8(immediate.value() & 0xff);
884}
885
886void Assembler::emitComplexB(int rm, Operand operand, Immediate imm) {
887 DCHECK(rm >= 0 && rm < 8, "assert()");
888 DCHECK(imm.isUint8() || imm.isInt8(), "immediate too large");
889 if (operand.hasRegister(RAX)) {
890 // Use short form if the destination is al.
891 emitUint8(0x04 + (rm << 3));
892 } else {
893 emitUint8(0x80);
894 emitOperand(rm, operand);
895 }
896 emitUint8(imm.value());
897}
898
899void Assembler::emitComplex(int rm, Operand operand, Immediate immediate) {
900 DCHECK(rm >= 0 && rm < 8, "assert()");
901 DCHECK(immediate.isInt32(), "assert()");
902 if (immediate.isInt8()) {
903 emitSignExtendedInt8(rm, operand, immediate);
904 } else if (operand.hasRegister(RAX)) {
905 // Use short form if the destination is rax.
906 emitUint8(0x05 + (rm << 3));
907 emitImmediate(immediate);
908 } else {
909 emitUint8(0x81);
910 emitOperand(rm, operand);
911 emitImmediate(immediate);
912 }
913}
914
915void Assembler::emitLabel(Label* label, word instruction_size) {
916 if (label->isBound()) {
917 word offset = label->position() - buffer_.size();
918 DCHECK(offset <= 0, "assert()");
919 emitInt32(offset - instruction_size);
920 } else {
921 emitLabelLink(label);
922 }
923}
924
925void Assembler::emitLabelLink(Label* label) {
926 DCHECK(!label->isBound(), "assert()");
927 word position = buffer_.size();
928 emitInt32(label->position_);
929 label->linkTo(position);
930}
931
932void Assembler::emitNearLabelLink(Label* label) {
933 DCHECK(!label->isBound(), "assert()");
934 word position = buffer_.size();
935 emitUint8(0);
936 label->nearLinkTo(position);
937}
938
939void Assembler::emitGenericShift(bool wide, int rm, Register reg,
940 Immediate imm) {
941 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
942 DCHECK(imm.isInt8(), "assert()");
943 if (wide) {
944 emitRegisterREX(reg, REX_W);
945 } else {
946 emitRegisterREX(reg, REX_NONE);
947 }
948 if (imm.value() == 1) {
949 emitUint8(0xd1);
950 emitOperand(rm, Operand(reg));
951 } else {
952 emitUint8(0xc1);
953 emitOperand(rm, Operand(reg));
954 emitUint8(imm.value() & 0xff);
955 }
956}
957
958void Assembler::emitGenericShift(bool wide, int rm, Register operand,
959 Register shifter) {
960 AssemblerBuffer::EnsureCapacity ensured(&buffer_);
961 DCHECK(shifter == RCX, "assert()");
962 emitRegisterREX(operand, wide ? REX_W : REX_NONE);
963 emitUint8(0xd3);
964 emitOperand(rm, Operand(operand));
965}
966
967} // namespace x64
968} // namespace py