1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ecmascript/compiler/assembler/x64/assembler_x64.h"
17
18namespace panda::ecmascript::x64 {
19void AssemblerX64::Pushq(Register x)
20{
21    EmitRexPrefix(x);
22    // 0x50: Push r16
23    EmitU8(0x50 | LowBits(x));
24}
25
26void AssemblerX64::Pushq(Immediate x)
27{
28    if (InRange8(x.Value())) {
29        // 6A: Push imm8
30        EmitU8(0x6A);
31        EmitI8(static_cast<int8_t>(x.Value()));
32    } else {
33        // 68: Push imm32
34        EmitU8(0x68);
35        EmitI32(x.Value());
36    }
37}
38
39void AssemblerX64::Push(Register x)
40{
41    Pushq(x);
42}
43
44void AssemblerX64::Popq(Register x)
45{
46    EmitRexPrefix(x);
47    // 0x58: Pop r16
48    EmitU8(0x58 | LowBits(x));
49}
50
51void AssemblerX64::Pop(Register x)
52{
53    Popq(x);
54}
55
56
57void AssemblerX64::Addq(Immediate src, Register dst)
58{
59    EmitRexPrefixW(dst);
60    if (InRange8(src.Value())) {
61        // 83: Add r/m16, imm8
62        EmitU8(0x83);
63        // 0: 83 /0 ib
64        EmitModrm(0, dst);
65        EmitI8(static_cast<int8_t>(src.Value()));
66    } else if (dst == rax) {
67        // 0x5: Add rax, imm32
68        EmitU8(0x5);
69        EmitI32(src.Value());
70    } else {
71        // 81: Add r/m32, imm32
72        EmitU8(0x81);
73        // 0: 81 /0 id
74        EmitModrm(0, dst);
75        EmitI32(src.Value());
76    }
77}
78
79void AssemblerX64::Addq(Register src, Register dst)
80{
81    EmitRexPrefix(dst, src);
82    // 03 : add r64, r/m64
83    EmitU8(0x03);
84    EmitModrm(dst, src);
85}
86
87void AssemblerX64::Addl(Immediate src, Register dst)
88{
89    EmitRexPrefix(dst);
90    if (InRange8(src.Value())) {
91        // 83: Add r/m16, imm8
92        EmitU8(0x83);
93        // 0: 83 /0 ib
94        EmitModrm(0, dst);
95        EmitI8(static_cast<int8_t>(src.Value()));
96    } else if (dst == rax) {
97        // 0x5: Add rax, imm32
98        EmitU8(0x5);
99        EmitI32(src.Value());
100    } else {
101        // 81: Add r/m32, imm32
102        EmitU8(0x81);
103        // 0: 81 /0 id
104        EmitModrm(0, dst);
105        EmitI32(src.Value());
106    }
107}
108
109void AssemblerX64::Subq(Immediate src, Register dst)
110{
111    EmitRexPrefixW(dst);
112    if (InRange8(src.Value())) {
113        // 83: Sub r/m16, imm8
114        EmitU8(0x83);
115        // 5: 83 /5 ib
116        EmitModrm(5, dst);
117        EmitI8(static_cast<int8_t>(src.Value()));
118    } else if (dst == rax) {
119        // 0x2D: Sub rax, imm32
120        EmitU8(0x2D);
121        EmitI32(src.Value());
122    } else {
123        // 81: sub r/m32, imm32
124        EmitU8(0x81);
125        // 5: 81 /5 id
126        EmitModrm(5, dst);
127        EmitI32(src.Value());
128    }
129}
130
131void AssemblerX64::Subq(Register src, Register dst)
132{
133    EmitRexPrefix(src, dst);
134    // 29: sub r/m64, r64
135    EmitU8(0x29);
136    EmitModrm(src, dst);
137}
138
139void AssemblerX64::Subl(Immediate src, Register dst)
140{
141    EmitRexPrefix(dst);
142    if (InRange8(src.Value())) {
143        // 83: Sub r/m16, imm8
144        EmitU8(0x83);
145        // 5: 83 /5 ib
146        EmitModrm(5, dst);
147        EmitI8(static_cast<int8_t>(src.Value()));
148    } else if (dst == rax) {
149        // 0x2D: Sub eax, imm32
150        EmitU8(0x2D);
151        EmitI32(src.Value());
152    } else {
153        // 81: sub r/m32, imm32
154        EmitU8(0x81);
155        // 5: 81 /5 id
156        EmitModrm(5, dst);
157        EmitI32(src.Value());
158    }
159}
160
161void AssemblerX64::Cmpq(Immediate src, Register dst)
162{
163    EmitRexPrefixW(dst);
164    if (InRange8(src.Value())) {
165        // 83: cmp r/m64, imm8
166        EmitU8(0x83);
167        // 7: 83 /7 ib
168        EmitModrm(7, dst);
169        EmitI8(static_cast<int8_t>(src.Value()));
170    } else if (dst == rax) {
171        // 0x3D: cmp rax, imm32
172        EmitU8(0x3D);
173        EmitI32(src.Value());
174    } else {
175        // 81: cmp r/m32, imm32
176        EmitU8(0x81);
177        // 7: 81 /7 id
178        EmitModrm(7, dst);
179        EmitI32(src.Value());
180    }
181}
182
183void AssemblerX64::Cmpb(Immediate src, Register dst)
184{
185    EmitRexPrefix(dst);
186    if (InRange8(src.Value())) {
187        // 80: cmp r/m8, imm8
188        EmitU8(0x80);
189        // 7: /7 ib
190        EmitModrm(7, dst);
191        EmitI8(static_cast<int8_t>(src.Value()));
192    } else if (dst == rax) {
193        // 0x3C: cmp al, imm8
194        EmitU8(0x3C);
195        EmitI8(src.Value());
196    } else {
197        LOG_ECMA(FATAL) << "this branch is unreachable";
198        UNREACHABLE();
199    }
200}
201
202void AssemblerX64::Cmpq(Register src, Register dst)
203{
204    EmitRexPrefix(src, dst);
205    // 39: Cmp r/m64, r64
206    EmitU8(0x39);
207    EmitModrm(src, dst);
208}
209
210void AssemblerX64::Cmpl(Immediate src, Register dst)
211{
212    EmitRexPrefix(dst);
213    if (InRange8(src.Value())) {
214        // 83: cmp r/m32, imm8
215        EmitU8(0x83);
216        // 7: 83 /7 ib
217        EmitModrm(7, dst);
218        EmitI8(static_cast<int8_t>(src.Value()));
219    } else if (dst == rax) {
220        // 0x3D: cmp rax, imm32
221        EmitU8(0x3D);
222        EmitI32(src.Value());
223    } else {
224        // 81: cmp r/m32, imm32
225        EmitU8(0x81);
226        // 7: 81 /7 id
227        EmitModrm(7, dst);
228        EmitI32(src.Value());
229    }
230}
231
232void AssemblerX64::Cmp(Immediate src, Register dst)
233{
234    Cmpq(src, dst);
235}
236
237void AssemblerX64::Movq(Register src, Register dst)
238{
239    EmitRexPrefix(src, dst);
240    // 0x89: Move r16 to r/m16
241    EmitU8(0x89);
242    EmitModrm(src, dst);
243}
244
245void AssemblerX64::Mov(Register src, Register dst)
246{
247    EmitRexPrefixl(dst, src);
248    // 0x89: Move r16 to r/m16
249    EmitU8(0x8B);
250    EmitModrm(dst, src);
251}
252
253void AssemblerX64::Align16()
254{
255    auto pos = GetCurrentPosition();
256    // 16: align16
257    size_t x = 16;
258    size_t delta = static_cast<size_t>(x - (pos & (x - 1)));
259    for (size_t i = 0; i < delta; i++) {
260        // 0x90: NOP
261        EmitU8(0x90);
262    }
263}
264
265void AssemblerX64::Movq(const Operand &src, Register dst)
266{
267    EmitRexPrefix(dst, src);
268    // 0x8B: Move r/m64 to r64
269    EmitU8(0x8B);
270    EmitOperand(dst, src);
271}
272
273void AssemblerX64::Movq(Register src, const Operand &dst)
274{
275    EmitRexPrefix(src, dst);
276    // 0x89: Move r64 to r/m64
277    EmitU8(0x89);
278    EmitOperand(src, dst);
279}
280
281void AssemblerX64::Movq(Immediate src, Operand dst)
282{
283    EmitRexPrefix(dst);
284    // 0xC7: Move imm32 to r/m32
285    EmitU8(0xC7);
286    // 0: C7 /0 id
287    EmitOperand(0, dst);
288    EmitI32(src.Value());
289}
290
291void AssemblerX64::Movq(Immediate src, Register dst)
292{
293    EmitRexPrefix(dst);
294    // B8 : mov r32, imm32
295    EmitU8(0xB8 | LowBits(dst));
296    EmitI32(src.Value());
297}
298
299void AssemblerX64::Mov(const Operand &src, Register dst)
300{
301    Movq(src, dst);
302}
303
304void AssemblerX64::EmitJmp(int32_t offset)
305{
306    offset--;
307    if (InRange8(offset - SIZE_OF_INT8)) {
308        // EB: Jmp rel8
309        EmitU8(0xEB);
310        EmitI8(offset - SIZE_OF_INT8);
311    } else {
312        // E9: Jmp rel32
313        EmitU8(0xE9);
314        EmitI32(offset - SIZE_OF_INT32);
315    }
316}
317
318void AssemblerX64::EmitJa(int32_t offset)
319{
320    offset--;
321    if (InRange8(offset - SIZE_OF_INT8)) {
322        // 77 : Ja rel8
323        EmitU8(0x77);
324        EmitI8(offset - SIZE_OF_INT8);
325    } else {
326        offset--;
327        // 0F 87 : ja rel32
328        EmitU8(0x0F);
329        EmitU8(0x87);
330        EmitI32(offset - SIZE_OF_INT32);
331    }
332}
333
334void AssemblerX64::EmitJb(int32_t offset)
335{
336    offset--;
337    if (InRange8(offset - SIZE_OF_INT8)) {
338        // 72 : Jb rel8
339        EmitU8(0x72);
340        EmitI8(offset - SIZE_OF_INT8);
341    } else {
342        offset--;
343        // 0F 82 : Jb rel32
344        EmitU8(0x0F);
345        EmitU8(0x82);
346        EmitI32(offset - SIZE_OF_INT32);
347    }
348}
349
350void AssemblerX64::EmitJz(int32_t offset)
351{
352    offset--;
353    if (InRange8(offset - SIZE_OF_INT8)) {
354        // 74 : Jz rel8
355        EmitU8(0x74);
356        EmitI8(offset - SIZE_OF_INT8);
357    } else {
358        offset--;
359        // 0F 84 : Jz rel32
360        EmitU8(0x0F);
361        EmitU8(0x84);
362        EmitI32(offset - SIZE_OF_INT32);
363    }
364}
365
366void AssemblerX64::EmitJne(int32_t offset)
367{
368    offset--;
369    if (InRange8(offset - SIZE_OF_INT8)) {
370        // 75 : Jne rel8;
371        EmitU8(0x75);
372        EmitI8(offset - SIZE_OF_INT8);
373    } else {
374        offset--;
375        // 0F 85 : Jne rel32
376        EmitU8(0x0F);
377        EmitU8(0x85);
378        EmitI32(offset - SIZE_OF_INT32);
379    }
380}
381
382void AssemblerX64::EmitJbe(int32_t offset)
383{
384    offset--;
385    if (InRange8(offset - SIZE_OF_INT8)) {
386        // 76 : Jbe rel8;
387        EmitU8(0x76);
388        EmitI8(offset - SIZE_OF_INT8);
389    } else {
390        offset--;
391        // 0F 86 : Jne rel32
392        EmitU8(0x0F);
393        EmitU8(0x86);
394        EmitI32(offset - SIZE_OF_INT32);
395    }
396}
397
398void AssemblerX64::EmitJnz(int32_t offset)
399{
400    offset--;
401    if (InRange8(offset)) {
402        // 75 : Jnz rel8
403        EmitU8(0x75);
404        EmitI8(offset - SIZE_OF_INT8);
405    } else {
406        offset--;
407        // 0F 85: Jnz rel32
408        EmitU8(0x0F);
409        EmitU8(0x85);
410        EmitI32(offset - SIZE_OF_INT32);
411    }
412}
413
414void AssemblerX64::EmitJle(int32_t offset)
415{
416    offset--;
417    if (InRange8(offset)) {
418        // 7E : Jle rel8
419        EmitU8(0x7E);
420        EmitI8(offset - SIZE_OF_INT8);
421    } else {
422        offset--;
423        // 0F 8E: Jle rel32
424        EmitU8(0x0F);
425        EmitU8(0x8E);
426        EmitI32(offset - SIZE_OF_INT32);
427    }
428}
429
430void AssemblerX64::EmitJae(int32_t offset)
431{
432    offset--;
433    if (InRange8(offset)) {
434        // 73 : Jae rel8
435        EmitU8(0x73);
436        EmitI8(offset - SIZE_OF_INT8);
437    } else {
438        offset--;
439        // 0F 83: Jae rel32
440        EmitU8(0x0F);
441        EmitU8(0x83);
442        EmitI32(offset - SIZE_OF_INT32);
443    }
444}
445
446void AssemblerX64::EmitJg(int32_t offset)
447{
448    offset--;
449    if (InRange8(offset)) {
450        // 7F : Jg rel8
451        EmitU8(0x7F);
452        EmitI8(offset - SIZE_OF_INT8);
453    } else {
454        offset--;
455        // 0F 8F: Jg rel32
456        EmitU8(0x0F);
457        EmitU8(0x8F);
458        EmitI32(offset - SIZE_OF_INT32);
459    }
460}
461
462void AssemblerX64::EmitJge(int32_t offset)
463{
464    offset--;
465    if (InRange8(offset)) {
466        // 7D : Jg rel8
467        EmitU8(0x7D);
468        EmitI8(offset - SIZE_OF_INT8);
469    } else {
470        offset--;
471        // 0F 8F: Jg rel32
472        EmitU8(0x0F);
473        EmitU8(0x8D);
474        EmitI32(offset - SIZE_OF_INT32);
475    }
476}
477
478void AssemblerX64::EmitJe(int32_t offset)
479{
480    offset--;
481    if (InRange8(offset)) {
482        // 74 : Je rel8
483        EmitU8(0x74);
484        EmitI8(offset - SIZE_OF_INT8);
485    } else {
486        offset--;
487        // 0F 84: Je rel32
488        EmitU8(0x0F);
489        EmitU8(0x84);
490        EmitI32(offset - SIZE_OF_INT32);
491    }
492}
493
494void AssemblerX64::EmitCall(int32_t offset)
495{
496    offset--;
497    // E8: call rel32
498    EmitU8(0xE8);
499    EmitI32(offset - SIZE_OF_INT32);
500}
501
502void AssemblerX64::EmitJnb(int32_t offset)
503{
504    offset--;
505    if (InRange8(offset)) {
506        // 73 : Jnb rel8
507        EmitU8(0x73);
508        EmitI8(offset - SIZE_OF_INT8);
509    } else {
510        offset--;
511        // 0F 83: Jnb rel32
512        EmitU8(0x0F);
513        EmitU8(0x83);
514        EmitI32(offset - SIZE_OF_INT32);
515    }
516}
517
518void AssemblerX64::Callq(Register addr)
519{
520    // C3: RET Near return to calling procedure
521    EmitRexPrefix(addr);
522    // FF: Call r/m16
523    EmitU8(0xFF);
524    // 0x2: FF /2
525    EmitModrm(0x2, addr);
526}
527
528void AssemblerX64::Callq(Label *target)
529{
530    if (target->IsBound()) {
531        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
532        EmitCall(offset);
533        return;
534    }
535
536    auto pos = GetCurrentPosition();
537    int32_t emitPos = 0;
538    if (target->IsLinked()) {
539        emitPos = static_cast<int32_t>(target->GetLinkedPos());
540    }
541    // +1: skip opcode
542    target->LinkTo(pos + 1);
543    // E8: call rel32
544    EmitU8(0xE8);
545    EmitI32(emitPos);
546}
547
548void AssemblerX64::Ret()
549{
550    // C3: RET Near return to calling procedure
551    EmitU8(0xC3);
552}
553
554void AssemblerX64::Jmp(Label *target, Distance distance)
555{
556    if (target->IsBound()) {
557        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
558        EmitJmp(offset);
559        return;
560    }
561
562    auto pos = GetCurrentPosition();
563    int32_t emitPos = 0;
564    if (distance == Distance::Near) {
565        if (target->IsLinkedNear()) {
566            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
567        }
568        // +1: skip opcode
569        target->LinkNearPos(pos + 1);
570        ASSERT(InRange8(emitPos));
571        // EB: Jmp rel8
572        EmitU8(0xEB);
573        EmitI8(static_cast<int8_t>(emitPos));
574    } else {
575        if (target->IsLinked()) {
576            emitPos = static_cast<int32_t>(target->GetLinkedPos());
577        }
578        // +1: skip opcode
579        target->LinkTo(pos + 1);
580        // E9: Jmp rel32
581        EmitU8(0xE9);
582        EmitI32(emitPos);
583    }
584}
585
586void AssemblerX64::Jmp(Register dst)
587{
588    EmitRexPrefix(dst);
589    // opcode FF/4 : jmp r/m64
590    EmitU8(0xFF);
591    // 4 means register
592    EmitModrm(4, dst);
593}
594
595void AssemblerX64::Jmp(Immediate offset)
596{
597    if (InRange8(offset.Value())) {
598        // opcode EB : jmp rel8
599        EmitU8(0xEB);
600        EmitI8(static_cast<int8_t>(offset.Value()));
601    } else {
602        // opcode E9 : jmp rel32
603        EmitU8(0xE9);
604        EmitI32(offset.Value());
605    }
606}
607
608void AssemblerX64::Ja(Label *target, Distance distance)
609{
610    if (target->IsBound()) {
611        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
612        EmitJa(offset);
613        return;
614    }
615    auto pos = GetCurrentPosition();
616    int32_t emitPos = 0;
617    if (distance == Distance::Near) {
618        if (target->IsLinkedNear()) {
619            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
620        }
621        // +1: skip opcode
622        target->LinkNearPos(pos + 1);
623        ASSERT(InRange8(emitPos));
624        // 77: ja rel8
625        EmitU8(0x77);
626        EmitI8(static_cast<int8_t>(emitPos));
627    } else {
628        if (target->IsLinked()) {
629            emitPos = static_cast<int32_t>(target->GetLinkedPos());
630        }
631        // 2: skip opcode
632        target->LinkTo(pos + 2);
633        // 0F 87: ja rel32
634        EmitU8(0X0F);
635        EmitU8(0x87);
636        EmitI32(emitPos);
637    }
638}
639
640void AssemblerX64::Jb(Label *target, Distance distance)
641{
642    if (target->IsBound()) {
643        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
644        EmitJb(offset);
645        return;
646    }
647    auto pos = GetCurrentPosition();
648    int32_t emitPos = 0;
649    if (distance == Distance::Near) {
650        if (target->IsLinkedNear()) {
651            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
652        }
653        // +1: skip opcode
654        target->LinkNearPos(pos + 1);
655        ASSERT(InRange8(emitPos));
656        // 72 : Jb rel8
657        EmitU8(0x72);
658        EmitI8(static_cast<int8_t>(emitPos));
659    } else {
660        if (target->IsLinked()) {
661            emitPos = static_cast<int32_t>(target->GetLinkedPos());
662        }
663        // 2: skip opcode
664        target->LinkTo(pos + 2);
665        // 0F 82: jb rel32
666        EmitU8(0X0F);
667        EmitU8(0x82);
668        EmitI32(emitPos);
669    }
670}
671void AssemblerX64::Jz(Label *target, Distance distance)
672{
673    if (target->IsBound()) {
674        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
675        EmitJz(offset);
676        return;
677    }
678    auto pos = GetCurrentPosition();
679    int32_t emitPos = 0;
680    if (distance == Distance::Near) {
681        if (target->IsLinkedNear()) {
682            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
683        }
684        // +1: skip opcode
685        target->LinkNearPos(pos + 1);
686        ASSERT(InRange8(emitPos));
687        // 74 : Jz rel8
688        EmitU8(0x74);
689        EmitI8(static_cast<int8_t>(emitPos));
690    } else {
691        if (target->IsLinked()) {
692            emitPos = static_cast<int32_t>(target->GetLinkedPos());
693        }
694        // 2: skip opcode
695        target->LinkTo(pos + 2);
696        // 0F 84: Jz rel32
697        EmitU8(0X0F);
698        EmitU8(0x84);
699        EmitI32(emitPos);
700    }
701}
702
703void AssemblerX64::Je(Label *target, Distance distance)
704{
705    if (target->IsBound()) {
706        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
707        EmitJe(offset);
708        return;
709    }
710    auto pos = GetCurrentPosition();
711    int32_t emitPos = 0;
712    if (distance == Distance::Near) {
713        if (target->IsLinkedNear()) {
714            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
715        }
716        // +1: skip opcode
717        target->LinkNearPos(pos + 1);
718        ASSERT(InRange8(emitPos));
719        // 74 : Je rel8
720        EmitU8(0x74);
721        EmitI8(static_cast<int8_t>(emitPos));
722    } else {
723        if (target->IsLinked()) {
724            emitPos = static_cast<int32_t>(target->GetLinkedPos());
725        }
726        // 2: skip opcode
727        target->LinkTo(pos + 2);
728        // 0F 84: Je rel32
729        EmitU8(0X0F);
730        EmitU8(0x84);
731        EmitI32(emitPos);
732    }
733}
734
735void AssemblerX64::Bind(Label *target)
736{
737    size_t pos = GetCurrentPosition();
738    ASSERT(!target->IsBound());
739
740    if (target->IsLinked()) {
741        uint32_t linkPos = target->GetLinkedPos();
742        while (linkPos != 0) {
743            uint32_t preLinkPos = GetU32(linkPos);
744            int32_t disp = static_cast<int32_t>(pos - linkPos - sizeof(int32_t));
745            PutI32(linkPos, disp);
746            linkPos = preLinkPos;
747        }
748    }
749
750    if (target->IsLinkedNear()) {
751        uint32_t linkPos = target->GetLinkedNearPos();
752        while (linkPos != 0) {
753            int8_t offsetToNext = GetI8(static_cast<size_t>(linkPos));
754            int32_t disp = static_cast<int32_t>(pos - linkPos - sizeof(int8_t));
755            ASSERT(InRange8(disp));
756            PutI8(linkPos, static_cast<int8_t>(disp));
757            if (offsetToNext == 0) {
758                break;
759            }
760            linkPos += static_cast<uint32_t>(offsetToNext);
761        }
762        target->UnlinkNearPos();
763    }
764
765    target->BindTo(pos);
766}
767
768Operand::Operand(Register base, int32_t disp)
769{
770    if (base == rsp || base == r12) {
771        BuildSIB(Times1, rsp, base);
772    }
773    if (disp == 0 && base != rbp && base != r13) {
774        // 0: mode 00 [r/m]
775        BuildModerm(0, base);
776    } else if (AssemblerX64::InRange8(disp)) {
777        // 1: mode 01 [r/m + disp8]
778        BuildModerm(1, base);
779        BuildDisp8(disp);
780    } else {
781        // 2: mode 10 [r/m + disp32]
782        BuildModerm(2, base);
783        BuildDisp32(disp);
784    }
785}
786
787Operand::Operand(Register base, Register index, Scale scale, int32_t disp)
788{
789    BuildSIB(scale, index, base);
790    if (disp == 0 && base != rbp && base != r13) {
791        // 0: mode 00 [r/m]
792        BuildModerm(0, rsp);
793    } else if (AssemblerX64::InRange8(disp)) {
794        // 1: mode 01 [r/m + disp8]
795        BuildModerm(1, rsp);
796        BuildDisp8(disp);
797    } else {
798        // 2: mode 10 [r/m + disp32]
799        BuildModerm(2, rsp);
800        BuildDisp32(disp);
801    }
802}
803
804// [index * scale + disp]
805Operand::Operand(Register index, Scale scale, int32_t disp)
806{
807    ASSERT(index != rsp);
808    BuildModerm(0, rsp);
809    BuildSIB(scale, index, rbp);
810    BuildDisp32(disp);
811}
812
813void Operand::BuildSIB(Scale scale, Register index, Register base)
814{
815    sib_ = AssemblerX64::GetSIB(scale, index, base);
816    rex_ |= AssemblerX64::GetSIBRex(index, base);
817    hasSIB_ = true;
818}
819
820void Operand::BuildModerm(int32_t mode, Register rm)
821{
822    rex_ |= AssemblerX64::GetModrmRex(rm);
823    moderm_ = AssemblerX64::GetModrm(mode, rm);
824}
825
826void Operand::BuildDisp8(int32_t disp)
827{
828    disp_ = disp;
829    hasDisp8_ = true;
830}
831
832void Operand::BuildDisp32(int32_t disp)
833{
834    disp_ = disp;
835    hasDisp32_ = true;
836}
837
838void AssemblerX64::EmitOperand(int32_t reg, Operand rm)
839{
840    // moderm
841    EmitU8(rm.moderm_ | (static_cast<uint32_t>(reg) << LOW_BITS_SIZE));
842    if (rm.hasSIB_) {
843        EmitU8(rm.sib_);
844    }
845
846    if (rm.hasDisp8_) {
847        EmitI8(static_cast<int8_t>(rm.disp_));
848    } else if (rm.hasDisp32_) {
849        EmitI32(rm.disp_);
850    }
851}
852
853void AssemblerX64::Movl(Register src, Register dst)
854{
855    EmitRexPrefixl(src, dst);
856    // 0x89: Move r16 to r/m16
857    EmitU8(0x89);
858    EmitModrm(src, dst);
859}
860
861void AssemblerX64::Movl(const Operand &src, Register dst)
862{
863    EmitRexPrefixl(dst, src);
864    // 0x8B: Move r/m64 to r64
865    EmitU8(0x8B);
866    EmitOperand(dst, src);
867}
868
869void AssemblerX64::Movl(Register src, const Operand& dst)
870{
871    EmitRexPrefixl(src, dst);
872    // 0x89: Move r32 to r/m64
873    EmitU8(0x89);
874    EmitOperand(src, dst);
875}
876
877void AssemblerX64::Testq(Immediate src, Register dst)
878{
879    if (InRange8(src.Value())) {
880        Testb(src, dst);
881    } else if (dst == rax) {
882        // A9: Test rax, imm32
883        EmitU8(0xA9);
884        EmitI32(src.Value());
885    } else {
886        EmitRexPrefixW(dst);
887        // F7: Test r/m64, imm32
888        EmitU8(0xF7);
889        // 0: F7 0 id
890        EmitModrm(0, dst);
891        EmitI32(src.Value());
892    }
893}
894
895void AssemblerX64::Testb(Immediate src, Register dst)
896{
897    ASSERT(InRange8(src.Value()));
898    if (dst == rax) {
899        // A8: Test al, imm8
900        EmitU8(0xA8);
901    } else {
902        // AH BH CG DH can not be encoded to access if REX prefix used.
903        if (dst >= rsp) {
904            EmitRexPrefixL(dst);
905        }
906        // F6: Test r/m8, imm8
907        // REX F6: Test r/m8*, imm8
908        EmitU8(0xF6);
909        // 0: F6 /0 ib
910        EmitModrm(0, dst);
911    }
912    EmitI8(static_cast<int8_t>(src.Value()));
913}
914
915void AssemblerX64::Jne(Label *target, Distance distance)
916{
917    if (target->IsBound()) {
918        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
919        EmitJne(offset);
920        return;
921    }
922    auto pos = GetCurrentPosition();
923    int32_t emitPos = 0;
924    if (distance == Distance::Near) {
925        if (target->IsLinkedNear()) {
926            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
927        }
928        // +1: skip opcode
929        target->LinkNearPos(pos + 1);
930        ASSERT(InRange8(emitPos));
931        // 75 : Jne rel8;
932        EmitU8(0x75);
933        EmitI8(static_cast<int8_t>(emitPos));
934    } else {
935        if (target->IsLinked()) {
936            emitPos = static_cast<int32_t>(target->GetLinkedPos());
937        }
938        // 2: skip opcode
939        target->LinkTo(pos + 2);
940        // 0F 85 : Jne rel32
941        EmitU8(0x0F);
942        EmitU8(0x85);
943        EmitI32(emitPos);
944    }
945}
946
947void AssemblerX64::Cmpl(Register src, Register dst)
948{
949    EmitRexPrefixl(src, dst);
950    // 39: Cmp r16 to r/m16
951    EmitU8(0x39);
952    EmitModrm(src, dst);
953}
954
955void AssemblerX64::Jbe(Label *target, Distance distance)
956{
957    if (target->IsBound()) {
958        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
959        EmitJbe(offset);
960        return;
961    }
962    auto pos = GetCurrentPosition();
963    int32_t emitPos = 0;
964    if (distance == Distance::Near) {
965        if (target->IsLinkedNear()) {
966            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
967        }
968        // +1: skip opcode
969        target->LinkNearPos(pos + 1);
970        ASSERT(InRange8(emitPos));
971        // 76 : Jbe rel8;
972        EmitU8(0x76);
973        EmitI8(static_cast<int8_t>(emitPos));
974    } else {
975        if (target->IsLinked()) {
976            emitPos = static_cast<int32_t>(target->GetLinkedPos());
977        }
978        // 2: skip opcode
979        target->LinkTo(pos + 2);
980        // 0F 86 : Jbe rel32
981        EmitU8(0x0F);
982        EmitU8(0x86);
983        EmitI32(emitPos);
984    }
985}
986
987void AssemblerX64::CMovbe(Register src, Register dst)
988{
989    EmitRexPrefixl(dst, src);
990    // 0f 46: CMovbe r32, r/m32
991    EmitU8(0x0F);
992    EmitU8(0x46);
993    EmitModrm(dst, src);
994}
995
996void AssemblerX64::Leaq(const Operand &src, Register dst)
997{
998    EmitRexPrefix(dst, src);
999    // 8D : lea r64, m
1000    EmitU8(0x8D);
1001    EmitOperand(dst, src);
1002}
1003
1004void AssemblerX64::Leal(const Operand &src, Register dst)
1005{
1006    EmitRexPrefixl(dst, src);
1007    // 8D : lea r64, m
1008    EmitU8(0x8D);
1009    EmitOperand(dst, src);
1010}
1011
1012void AssemblerX64::Shrq(Immediate src, Register dst)
1013{
1014    EmitRexPrefixW(dst);
1015    // C1 : Shr r/m64, imm8;
1016    EmitU8(0xc1);
1017    // 5: C1 /5 id
1018    EmitModrm(5, dst);
1019    EmitI8(static_cast<int8_t>(src.Value()));
1020}
1021
1022void AssemblerX64::Shrl(Immediate src, Register dst)
1023{
1024    EmitRexPrefix(dst);
1025    // C1 : Shr r/m32, imm8;
1026    EmitU8(0xc1);
1027    // 5: C1 /5 id
1028    EmitModrm(5, dst);
1029    EmitI8(static_cast<int8_t>(src.Value()));
1030}
1031
1032void AssemblerX64::Shr(Immediate src, Register dst)
1033{
1034    Shrq(src, dst);
1035}
1036
1037void AssemblerX64::Andq(Immediate src, Register dst)
1038{
1039    EmitRexPrefixW(dst);
1040    if (InRange8(src.Value())) {
1041        // 83: and r/m64, imm8
1042        EmitU8(0x83);
1043        // 4: 83 /4 ib
1044        EmitModrm(4, dst);
1045        EmitI8(static_cast<int8_t>(src.Value()));
1046    } else if (dst == rax) {
1047        // 0x25: and rax, imm32
1048        EmitU8(0x25);
1049        EmitI32(src.Value());
1050    } else {
1051        // 81: and r/m64, imm32
1052        EmitU8(0x81);
1053        // 4: 81 /4 id
1054        EmitModrm(4, dst);
1055        EmitI32(src.Value());
1056    }
1057}
1058
1059void AssemblerX64::Andl(Immediate src, Register dst)
1060{
1061    EmitRexPrefix(dst);
1062    if (InRange8(src.Value())) {
1063        // 83: and r/m64, imm8
1064        EmitU8(0x83);
1065        // 4: 83 /4 ib
1066        EmitModrm(4, dst);
1067        EmitI8(static_cast<int8_t>(src.Value()));
1068    } else if (dst == rax) {
1069        // 0x25: and rax, imm32
1070        EmitU8(0x25);
1071        EmitI32(src.Value());
1072    } else {
1073        // 81: and r/m64, imm32
1074        EmitU8(0x81);
1075        // 4: 81 /4 id
1076        EmitModrm(4, dst);
1077        EmitI32(src.Value());
1078    }
1079}
1080
1081void AssemblerX64::And(Register src, Register dst)
1082{
1083    EmitRexPrefix(src, dst);
1084    // 21 : And r/m64, r64
1085    EmitU8(0x21);
1086    EmitModrm(src, dst);
1087}
1088
1089void AssemblerX64::Or(Immediate src, Register dst)
1090{
1091    EmitRexPrefixW(dst);
1092    if (InRange8(src.Value())) {
1093        // 83: or r/m64, imm8
1094        EmitU8(0x83);
1095        // 1: 83 /1 ib
1096        EmitModrm(1, dst);
1097        EmitI8(static_cast<int8_t>(src.Value()));
1098    } else if (dst == rax) {
1099        // 0x0D: or rax, imm32
1100        EmitU8(0x0D);
1101        EmitI32(src.Value());
1102    } else {
1103        // 81: or r/m64, imm32
1104        EmitU8(0x81);
1105        // 1: 81 /1 id
1106        EmitModrm(1, dst);
1107        EmitI32(src.Value());
1108    }
1109}
1110
1111void AssemblerX64::Orq(Register src, Register dst)
1112{
1113    EmitRexPrefix(src, dst);
1114    // 09 : Or r/m64, r64
1115    EmitU8(0x09);
1116    EmitModrm(src, dst);
1117}
1118
1119void AssemblerX64::Jnz(Label *target, Distance distance)
1120{
1121    if (target->IsBound()) {
1122        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1123        EmitJnz(offset);
1124        return;
1125    }
1126    auto pos = GetCurrentPosition();
1127    int32_t emitPos = 0;
1128    if (distance == Distance::Near) {
1129        if (target->IsLinkedNear()) {
1130            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1131        }
1132        // +1: skip opcode
1133        target->LinkNearPos(pos + 1);
1134        ASSERT(InRange8(emitPos));
1135        // 75 : Jnz rel8;
1136        EmitU8(0x75);
1137        EmitI8(static_cast<int8_t>(emitPos));
1138    } else {
1139        if (target->IsLinked()) {
1140            emitPos = static_cast<int32_t>(target->GetLinkedPos());
1141        }
1142        // 2: skip opcode
1143        target->LinkTo(pos + 2);
1144        // 0F 85 : Jnz rel32
1145        EmitU8(0x0F);
1146        EmitU8(0x85);
1147        EmitI32(emitPos);
1148    }
1149}
1150
1151void AssemblerX64::Jle(Label *target, Distance distance)
1152{
1153    if (target->IsBound()) {
1154        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1155        EmitJle(offset);
1156        return;
1157    }
1158    auto pos = GetCurrentPosition();
1159    int32_t emitPos = 0;
1160    if (distance == Distance::Near) {
1161        if (target->IsLinkedNear()) {
1162            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1163        }
1164        // +1: skip opcode
1165        target->LinkNearPos(pos + 1);
1166        ASSERT(InRange8(emitPos));
1167        // 7E : Jle rel8;
1168        EmitU8(0x7E);
1169        EmitI8(static_cast<int8_t>(emitPos));
1170    } else {
1171        if (target->IsLinked()) {
1172            emitPos = static_cast<int32_t>(target->GetLinkedPos());
1173        }
1174        // 2: skip opcode
1175        target->LinkTo(pos + 2);
1176        // 0F 8E: Jle rel32
1177        EmitU8(0x0F);
1178        EmitU8(0x8E);
1179        EmitI32(emitPos);
1180    }
1181}
1182
1183void AssemblerX64::Jae(Label *target, Distance distance)
1184{
1185    if (target->IsBound()) {
1186        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1187        EmitJae(offset);
1188        return;
1189    }
1190    auto pos = GetCurrentPosition();
1191    int32_t emitPos = 0;
1192    if (distance == Distance::Near) {
1193        if (target->IsLinkedNear()) {
1194            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1195        }
1196        // +1: skip opcode
1197        target->LinkNearPos(pos + 1);
1198        ASSERT(InRange8(emitPos));
1199        // 73 : Jae rel8
1200        EmitU8(0x73);
1201        EmitI8(static_cast<int8_t>(emitPos));
1202    } else {
1203        if (target->IsLinked()) {
1204            emitPos = static_cast<int32_t>(target->GetLinkedPos());
1205        }
1206        // 2: skip opcode
1207        target->LinkTo(pos + 2);
1208        // 0F 83: Jae rel32
1209        EmitU8(0x0F);
1210        EmitU8(0x83);
1211        EmitI32(emitPos);
1212    }
1213}
1214
1215void AssemblerX64::Jg(Label *target, Distance distance)
1216{
1217    if (target->IsBound()) {
1218        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1219        EmitJg(offset);
1220        return;
1221    }
1222    auto pos = GetCurrentPosition();
1223    int32_t emitPos = 0;
1224    if (distance == Distance::Near) {
1225        if (target->IsLinkedNear()) {
1226            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1227        }
1228        // +1: skip opcode
1229        target->LinkNearPos(pos + 1);
1230        ASSERT(InRange8(emitPos));
1231        // 7F : Jg rel8
1232        EmitU8(0x7F);
1233        EmitI8(static_cast<int8_t>(emitPos));
1234    } else {
1235        if (target->IsLinked()) {
1236            emitPos = static_cast<int32_t>(target->GetLinkedPos());
1237        }
1238        // 2: skip opcode
1239        target->LinkTo(pos + 2);
1240        // 0F 8F: Jae rel32
1241        EmitU8(0x0F);
1242        EmitU8(0x8F);
1243        EmitI32(emitPos);
1244    }
1245}
1246
1247void AssemblerX64::Jge(Label *target, Distance distance)
1248{
1249    if (target->IsBound()) {
1250        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1251        EmitJge(offset);
1252        return;
1253    }
1254    auto pos = GetCurrentPosition();
1255    int32_t emitPos = 0;
1256    if (distance == Distance::Near) {
1257        if (target->IsLinkedNear()) {
1258            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1259        }
1260        // +1: skip opcode
1261        target->LinkNearPos(pos + 1);
1262        ASSERT(InRange8(emitPos));
1263        // 7F : Jg rel8
1264        EmitU8(0x7D);
1265        EmitI8(static_cast<int8_t>(emitPos));
1266    } else {
1267        if (target->IsLinked()) {
1268            emitPos = static_cast<int32_t>(target->GetLinkedPos());
1269        }
1270        // 2: skip opcode
1271        target->LinkTo(pos + 2);
1272        // 0F 8F: Jae rel32
1273        EmitU8(0x0F);
1274        EmitU8(0x8D);
1275        EmitI32(emitPos);
1276    }
1277}
1278
1279void AssemblerX64::Movzbq(const Operand &src, Register dst)
1280{
1281    EmitRexPrefix(dst, src);
1282    // 0F B6 : Movzx r64, r/m16
1283    EmitU8(0x0F);
1284    EmitU8(0xB6);
1285    // 0F B6 /r: Movzx r64, r/m16
1286    EmitOperand(dst, src);
1287}
1288
1289void AssemblerX64::Movzbl(const Operand &src, Register dst)
1290{
1291    EmitRexPrefixl(dst, src);
1292    // 0F B6 : Movzx r64, r/m16
1293    EmitU8(0x0F);
1294    EmitU8(0xB6);
1295    // 0F B6 /r: Movzx r64, r/m16
1296    EmitOperand(dst, src);
1297}
1298
1299void AssemblerX64::Movzbl(Register src, Register dst)
1300{
1301    EmitRexPrefixl(dst, src);
1302    // 0F B6 : Movzx r64, r/m16
1303    EmitU8(0x0F);
1304    EmitU8(0xB6);
1305    // 0F B6 /r: Movzx r64, r/m16
1306    EmitModrm(dst, src);
1307}
1308
1309void AssemblerX64::Btq(Immediate src, Register dst)
1310{
1311    EmitRexPrefixW(dst);
1312    // 0F BA: bt r/m32, imm8;
1313    EmitU8(0x0F);
1314    EmitU8(0xBA);
1315    // /4: 0F BA bt r/m32, imm8
1316    EmitModrm(4, dst);
1317    EmitI8(static_cast<int8_t>(src.Value()));
1318}
1319void AssemblerX64::Btl(Immediate src, Register dst)
1320{
1321    EmitRexPrefix(dst);
1322    // 0F BA: bt r/m32, imm8;
1323    EmitU8(0x0F);
1324    EmitU8(0xBA);
1325    // /4: 0F BA bt r/m32, imm8
1326    EmitModrm(4, dst);
1327    EmitI8(static_cast<int8_t>(src.Value()));
1328}
1329
1330void AssemblerX64::Movabs(uint64_t src, Register dst)
1331{
1332    // REX.W + B8 + rd io : Mov r64, imm64
1333    EmitRexPrefixW(dst);
1334    EmitU8(0xB8 | LowBits(dst));
1335    EmitU64(src);
1336}
1337
1338void AssemblerX64::Shll(Immediate src, Register dst)
1339{
1340    EmitRexPrefix(dst);
1341    // C1 : shl r/m32, imm8
1342    EmitU8(0xC1);
1343    // C1 /4
1344    EmitModrm(4, dst);
1345    EmitI8(static_cast<int8_t>(src.Value()));
1346}
1347
1348void AssemblerX64::Shlq(Immediate src, Register dst)
1349{
1350    EmitRexPrefixW(dst);
1351    // C1 : shl r/m64, imm8
1352    EmitU8(0xC1);
1353    // C1 /4
1354    EmitModrm(4, dst);
1355    EmitI8(static_cast<int8_t>(src.Value()));
1356}
1357
1358void AssemblerX64::Btsl(Register src, Register dst)
1359{
1360    EmitRexPrefixl(src, dst);
1361    // 0F AB: bts r32, r32;
1362    EmitU8(0x0F);
1363    EmitU8(0xAB);
1364
1365    EmitModrm(src, dst);
1366}
1367
1368void AssemblerX64::Int3()
1369{
1370    // CC :: INT3
1371    EmitU8(0xCC);
1372}
1373
1374void AssemblerX64::Movzwq(const Operand &src, Register dst)
1375{
1376    EmitRexPrefix(dst, src);
1377    EmitU8(0x0F);
1378    EmitU8(0xB7);
1379    EmitOperand(dst, src);
1380}
1381
1382void AssemblerX64::Jnb(Label *target, Distance distance)
1383{
1384    if (target->IsBound()) {
1385        int32_t offset = static_cast<int32_t>(target->GetPos() - GetCurrentPosition());
1386        EmitJnb(offset);
1387        return;
1388    }
1389    auto pos = GetCurrentPosition();
1390    int32_t emitPos = 0;
1391    if (distance == Distance::Near) {
1392        if (target->IsLinkedNear()) {
1393            emitPos = static_cast<int32_t>(target->GetLinkedNearPos() - pos);
1394        }
1395        // +1: skip opcode
1396        target->LinkNearPos(pos + 1);
1397        ASSERT(InRange8(emitPos));
1398        // 73 : Jnb rel8
1399        EmitU8(0x73);
1400        EmitI8(static_cast<int8_t>(emitPos));
1401    } else {
1402        if (target->IsLinked()) {
1403            emitPos = static_cast<int32_t>(target->GetLinkedPos());
1404        }
1405        // 2: skip opcode
1406        target->LinkTo(pos + 2);
1407        // 0F 83: Jnb rel32
1408        EmitU8(0x0F);
1409        EmitU8(0x83);
1410        EmitI32(emitPos);
1411    }
1412}
1413}  // panda::ecmascript::x64
1414