• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-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 #ifndef COMPILER_OPTIMIZER_CODEGEN_TARGET_AMD64_TARGET_H_
17 #define COMPILER_OPTIMIZER_CODEGEN_TARGET_AMD64_TARGET_H_
18 
19 #include "compiler/optimizer/code_generator/callconv.h"
20 
21 #include "asmjit/x86.h"
22 #include "target_info.h"
23 
24 namespace panda::compiler::amd64 {
25 const size_t MAX_SCALAR_PARAM_ID = 5;  // %rdi, %rsi, %rdx, %rcx, %r8, %r9
26 const size_t MAX_VECTOR_PARAM_ID = 7;  // %xmm0-%xmm7
27 
IsConditionSigned(Condition cc)28 static inline bool IsConditionSigned(Condition cc)
29 {
30     switch (cc) {
31         case Condition::LT:
32         case Condition::LE:
33         case Condition::GT:
34         case Condition::GE:
35             return true;
36 
37         default:
38             return false;
39     }
40 }
41 
42 /**
43  * Converters
44  */
45 static inline asmjit::x86::Condition::Code ArchCc(Condition cc, bool is_float = false)
46 {
47     switch (cc) {
48         case Condition::EQ:
49             return asmjit::x86::Condition::Code::kEqual;
50         case Condition::NE:
51             return asmjit::x86::Condition::Code::kNotEqual;
52         case Condition::LT:
53             return is_float ? asmjit::x86::Condition::Code::kUnsignedLT : asmjit::x86::Condition::Code::kSignedLT;
54         case Condition::GT:
55             return is_float ? asmjit::x86::Condition::Code::kUnsignedGT : asmjit::x86::Condition::Code::kSignedGT;
56         case Condition::LE:
57             return is_float ? asmjit::x86::Condition::Code::kUnsignedLE : asmjit::x86::Condition::Code::kSignedLE;
58         case Condition::GE:
59             return is_float ? asmjit::x86::Condition::Code::kUnsignedGE : asmjit::x86::Condition::Code::kSignedGE;
60         case Condition::LO:
61             return asmjit::x86::Condition::Code::kUnsignedLT;
62         case Condition::LS:
63             return asmjit::x86::Condition::Code::kUnsignedLE;
64         case Condition::HI:
65             return asmjit::x86::Condition::Code::kUnsignedGT;
66         case Condition::HS:
67             return asmjit::x86::Condition::Code::kUnsignedGE;
68         // TODO(igorban) : Remove them
69         case Condition::MI:
70             return asmjit::x86::Condition::Code::kNegative;
71         case Condition::PL:
72             return asmjit::x86::Condition::Code::kPositive;
73         case Condition::VS:
74             return asmjit::x86::Condition::Code::kOverflow;
75         case Condition::VC:
76             return asmjit::x86::Condition::Code::kNotOverflow;
77         case Condition::AL:
78         case Condition::NV:
79         default:
80             UNREACHABLE();
81             return asmjit::x86::Condition::Code::kEqual;
82     }
83 }
84 
ArchCcTest(Condition cc)85 static inline asmjit::x86::Condition::Code ArchCcTest(Condition cc)
86 {
87     ASSERT(cc == Condition::TST_EQ || cc == Condition::TST_NE);
88     return cc == Condition::TST_EQ ? asmjit::x86::Condition::Code::kEqual : asmjit::x86::Condition::Code::kNotEqual;
89 }
90 
CcMatchesNan(Condition cc)91 static inline bool CcMatchesNan(Condition cc)
92 {
93     switch (cc) {
94         case Condition::NE:
95         case Condition::LT:
96         case Condition::LE:
97         case Condition::HI:
98         case Condition::HS:
99             return true;
100 
101         default:
102             return false;
103     }
104 }
105 
106 class AsmJitErrorHandler : public asmjit::ErrorHandler {
107 public:
AsmJitErrorHandler(Encoder * encoder)108     explicit AsmJitErrorHandler(Encoder *encoder) : encoder_(encoder)
109     {
110         ASSERT(encoder != nullptr);
111     }
112 
handleError(asmjit::Error err,const char * message,asmjit::BaseEmitter * origin)113     void handleError([[maybe_unused]] asmjit::Error err, [[maybe_unused]] const char *message,
114                      [[maybe_unused]] asmjit::BaseEmitter *origin) override
115     {
116         encoder_->SetFalseResult();
117     }
118 
119     NO_MOVE_SEMANTIC(AsmJitErrorHandler);
120     NO_COPY_SEMANTIC(AsmJitErrorHandler);
121     ~AsmJitErrorHandler() override = default;
122 
123 private:
124     Encoder *encoder_ {nullptr};
125 };
126 
127 class RegList {
128 public:
RegList(size_t mask)129     explicit RegList(size_t mask) : mask_(mask)
130     {
131         for (size_t i = 0; i < sizeof(size_t) * BITS_PER_BYTE; ++i) {
132             if (Has(i)) {
133                 ++count_;
134             }
135         }
136     }
137 
138     DEFAULT_MOVE_SEMANTIC(RegList);
139     DEFAULT_COPY_SEMANTIC(RegList);
140     ~RegList() = default;
141 
size_t()142     explicit operator size_t() const
143     {
144         return mask_;
145     }
146 
IsEmpty()147     bool IsEmpty() const
148     {
149         return count_ == size_t(0);
150     }
151 
GetCount()152     size_t GetCount() const
153     {
154         return count_;
155     }
156 
Has(size_t i)157     bool Has(size_t i) const
158     {
159         return (mask_ & (size_t(1) << i)) != 0;
160     }
161 
Add(size_t i)162     void Add(size_t i)
163     {
164         if (Has(i)) {
165             return;
166         }
167         mask_ |= size_t(1) << i;
168         ++count_;
169     }
170 
Remove(size_t i)171     void Remove(size_t i)
172     {
173         if (!Has(i)) {
174             return;
175         }
176         mask_ &= ~(size_t(1) << i);
177         --count_;
178     }
179 
Pop()180     size_t Pop()
181     {
182         ASSERT(!IsEmpty());
183         size_t i = __builtin_ctzll(mask_);
184         Remove(i);
185         return i;
186     }
187 
GetMask()188     size_t GetMask() const
189     {
190         return mask_;
191     }
192 
193 private:
194     size_t mask_ {0};
195     size_t count_ {0};
196 };
197 
198 /**
199  * Converters
200  */
201 static inline asmjit::x86::Gp ArchReg(Reg reg, uint8_t size = 0)
202 {
203     ASSERT(reg.IsValid());
204     if (reg.IsScalar()) {
205         size_t reg_size = size == 0 ? reg.GetSize() : size;
206         auto arch_id = ConvertRegNumber(reg.GetId());
207 
208         asmjit::x86::Gp arch_reg;
209         switch (reg_size) {
210             case DOUBLE_WORD_SIZE:
211                 arch_reg = asmjit::x86::Gp(asmjit::x86::Gpq::kSignature, arch_id);
212                 break;
213             case WORD_SIZE:
214                 arch_reg = asmjit::x86::Gp(asmjit::x86::Gpd::kSignature, arch_id);
215                 break;
216             case HALF_SIZE:
217                 arch_reg = asmjit::x86::Gp(asmjit::x86::Gpw::kSignature, arch_id);
218                 break;
219             case BYTE_SIZE:
220                 arch_reg = asmjit::x86::Gp(asmjit::x86::GpbLo::kSignature, arch_id);
221                 break;
222 
223             default:
224                 UNREACHABLE();
225         }
226 
227         ASSERT(arch_reg.isValid());
228         return arch_reg;
229     }
230     if (reg.GetId() == ConvertRegNumber(asmjit::x86::rsp.id())) {
231         return asmjit::x86::rsp;
232     }
233 
234     // Invalid register type
235     UNREACHABLE();
236     return asmjit::x86::rax;
237 }
238 
ArchVReg(Reg reg)239 static inline asmjit::x86::Xmm ArchVReg(Reg reg)
240 {
241     ASSERT(reg.IsValid() && reg.IsFloat());
242     auto arch_vreg = asmjit::x86::xmm(reg.GetId());
243     return arch_vreg;
244 }
245 
ArchImm(Imm imm)246 static inline asmjit::Imm ArchImm(Imm imm)
247 {
248     ASSERT(imm.IsValid());
249     if (imm.GetType() == INT64_TYPE) {
250         return asmjit::imm(imm.GetValue<int64_t>());
251     }
252     if (imm.GetType() == INT32_TYPE) {
253         return asmjit::imm(imm.GetValue<int32_t>());
254     }
255     if (imm.GetType() == INT16_TYPE) {
256         return asmjit::imm(imm.GetValue<int16_t>());
257     }
258     if (imm.GetType() == INT8_TYPE) {
259         return asmjit::imm(imm.GetValue<int8_t>());
260     }
261     // Invalid converted register
262     UNREACHABLE();
263     return asmjit::imm(0);
264 }
265 
ImmToSignedInt(Imm imm)266 static inline int64_t ImmToSignedInt(Imm imm)
267 {
268     ASSERT(imm.IsValid());
269     if (imm.GetType() == INT64_TYPE) {
270         return imm.GetValue<int64_t>();
271     }
272     if (imm.GetType() == INT32_TYPE) {
273         return imm.GetValue<int32_t>();
274     }
275     if (imm.GetType() == INT16_TYPE) {
276         return imm.GetValue<int16_t>();
277     }
278     if (imm.GetType() == INT8_TYPE) {
279         return imm.GetValue<int8_t>();
280     }
281     // Invalid converted register
282     UNREACHABLE();
283     return 0;
284 }
285 
ImmToUnsignedInt(Imm imm)286 static inline uint64_t ImmToUnsignedInt(Imm imm)
287 {
288     ASSERT(imm.IsValid());
289     if (imm.GetType() == INT64_TYPE) {
290         return uint64_t(imm.GetValue<int64_t>());
291     }
292     if (imm.GetType() == INT32_TYPE) {
293         return uint32_t(imm.GetValue<int32_t>());
294     }
295     if (imm.GetType() == INT16_TYPE) {
296         return uint16_t(imm.GetValue<int16_t>());
297     }
298     if (imm.GetType() == INT8_TYPE) {
299         return uint8_t(imm.GetValue<int8_t>());
300     }
301     // Invalid converted register
302     UNREACHABLE();
303     return 0;
304 }
305 
ImmFitsSize(int64_t imm,uint8_t size)306 static inline bool ImmFitsSize(int64_t imm, uint8_t size)
307 {
308     if (size == DOUBLE_WORD_SIZE) {
309         size = WORD_SIZE;
310     }
311 
312     // NOLINTNEXTLINE(clang-analyzer-core.UndefinedBinaryOperatorResult)
313     int64_t max = (uint64_t(1) << (size - 1U)) - 1U;  // SUPPRESS_CSA(core.UndefinedBinaryOperatorResult)
314     int64_t min = ~uint64_t(max);
315     ASSERT(min < 0);
316     ASSERT(max > 0);
317 
318     return imm >= min && imm <= max;
319 }
320 
321 class ArchMem {
322 public:
ArchMem(MemRef mem)323     explicit ArchMem(MemRef mem)
324     {
325         bool base = mem.HasBase();
326         bool regoffset = mem.HasIndex();
327         bool shift = mem.HasScale();
328         bool offset = mem.HasDisp();
329 
330         if (base && !regoffset && !shift) {
331             // Default memory - base + offset
332             mem_ = asmjit::x86::ptr(ArchReg(mem.GetBase()), mem.GetDisp());
333         } else if (base && regoffset && !offset) {
334             auto base_size = mem.GetBase().GetSize();
335             auto index_size = mem.GetIndex().GetSize();
336 
337             ASSERT(base_size >= index_size);
338             ASSERT(index_size >= WORD_SIZE);
339 
340             if (base_size > index_size) {
341                 need_extend_index_ = true;
342             }
343 
344             if (mem.GetScale() == 0) {
345                 mem_ = asmjit::x86::ptr(ArchReg(mem.GetBase()), ArchReg(mem.GetIndex(), base_size));
346             } else {
347                 auto scale = mem.GetScale();
348 
349                 if (scale <= 3U) {
350                     mem_ = asmjit::x86::ptr(ArchReg(mem.GetBase()), ArchReg(mem.GetIndex(), base_size), scale);
351                 } else {
352                     mem_ = asmjit::x86::ptr(ArchReg(mem.GetBase()), ArchReg(mem.GetIndex(), base_size));
353                     big_shift_ = scale;
354                 }
355             }
356         } else {
357             // Wrong memRef
358             UNREACHABLE();
359         }
360     }
361 
362     DEFAULT_MOVE_SEMANTIC(ArchMem);
363     DEFAULT_COPY_SEMANTIC(ArchMem);
364     ~ArchMem() = default;
365 
Prepare(asmjit::x86::Assembler * masm)366     asmjit::x86::Mem Prepare(asmjit::x86::Assembler *masm)
367     {
368         if (is_prepared_) {
369             return mem_;
370         }
371 
372         if (big_shift_ != 0) {
373             ASSERT(!mem_.hasOffset() && mem_.hasIndex() && big_shift_ > 3U);
374             masm->shl(mem_.indexReg().as<asmjit::x86::Gp>(), asmjit::imm(big_shift_));
375         }
376 
377         if (need_extend_index_) {
378             ASSERT(mem_.hasIndex());
379             auto q_index = mem_.indexReg().as<asmjit::x86::Gp>();
380             auto d_index {q_index};
381             d_index.setSignature(asmjit::x86::Gpd::kSignature);
382             masm->movsxd(q_index, d_index);
383         }
384 
385         is_prepared_ = true;
386         return mem_;
387     }
388 
389 private:
390     int64_t big_shift_ {0};
391     asmjit::x86::Mem mem_;
392     bool need_extend_index_ {false};
393     bool is_prepared_ {false};
394 };
395 
396 /*
397  * Scalar registers mapping:
398  * +-----------+---------------------+
399  * | AMD64 Reg |      Panda Reg      |
400  * +-----------+---------------------+
401  * | rax       | r0                  |
402  * | rcx       | r1                  |
403  * | rdx       | r2                  |
404  * | rbx       | r3 (renamed to r11) |
405  * | rsp       | r4 (renamed to r10) |
406  * | rbp       | r5 (renamed to r9)  |
407  * | rsi       | r6                  |
408  * | rdi       | r7                  |
409  * | r8        | r8                  |
410  * | r9        | r9 (renamed to r5)  |
411  * | r10       | r10 (renamed to r4) |
412  * | r11       | r11 (renamed to r3) |
413  * | r12       | r12                 |
414  * | r13       | r13                 |
415  * | r14       | r14                 |
416  * | r15       | r15                 |
417  * | <no reg>  | r16-r31             |
418  * +-----------+---------------------+
419  *
420  * Vector registers mapping:
421  * xmm[i] <-> vreg[i], 0 <= i <= 15
422  */
423 class Amd64RegisterDescription final : public RegistersDescription {
424 public:
425     explicit Amd64RegisterDescription(ArenaAllocator *allocator);
426     NO_MOVE_SEMANTIC(Amd64RegisterDescription);
427     NO_COPY_SEMANTIC(Amd64RegisterDescription);
428     ~Amd64RegisterDescription() override = default;
429 
430     ArenaVector<Reg> GetCalleeSaved() override;
431     void SetCalleeSaved(const ArenaVector<Reg> &regs) override;
432     // Set used regs - change GetCallee
433     void SetUsedRegs(const ArenaVector<Reg> &regs) override;
434 
GetCallerSavedRegMask()435     RegMask GetCallerSavedRegMask() const override
436     {
437         return RegMask(caller_saved_.GetMask());
438     }
439 
GetCallerSavedVRegMask()440     VRegMask GetCallerSavedVRegMask() const override
441     {
442         return VRegMask(caller_savedv_.GetMask());
443     }
444 
IsCalleeRegister(Reg reg)445     bool IsCalleeRegister(Reg reg) override
446     {
447         bool is_fp = reg.IsFloat();
448         return reg.GetId() >= GetFirstCalleeReg(Arch::X86_64, is_fp) &&
449                reg.GetId() <= GetLastCalleeReg(Arch::X86_64, is_fp);
450     }
451 
GetZeroReg()452     Reg GetZeroReg() const override
453     {
454         return INVALID_REGISTER;  // there is no one
455     }
456 
IsZeroReg(Reg reg)457     bool IsZeroReg([[maybe_unused]] Reg reg) const override
458     {
459         return false;
460     }
461 
GetTempReg()462     Reg::RegIDType GetTempReg() override
463     {
464         return compiler::arch_info::x86_64::TEMP_REGS.GetMaxRegister();
465     }
466 
GetTempVReg()467     Reg::RegIDType GetTempVReg() override
468     {
469         return compiler::arch_info::x86_64::TEMP_FP_REGS.GetMaxRegister();
470     }
471 
GetDefaultRegMask()472     RegMask GetDefaultRegMask() const override
473     {
474         static constexpr size_t HIGH_MASK {0xFFFF0000};
475 
476         RegMask reg_mask(HIGH_MASK);
477         reg_mask |= compiler::arch_info::x86_64::TEMP_REGS;
478         reg_mask.set(ConvertRegNumber(asmjit::x86::rbp.id()));
479         reg_mask.set(ConvertRegNumber(asmjit::x86::rsp.id()));
480         reg_mask.set(GetThreadReg(Arch::X86_64));
481         return reg_mask;
482     }
483 
GetVRegMask()484     VRegMask GetVRegMask() override
485     {
486         static constexpr size_t HIGH_MASK {0xFFFF0000};
487 
488         VRegMask vreg_mask(HIGH_MASK);
489         vreg_mask |= compiler::arch_info::x86_64::TEMP_FP_REGS;
490         return vreg_mask;
491     }
492 
493     // Check register mapping
SupportMapping(uint32_t type)494     bool SupportMapping(uint32_t type) override
495     {
496         // Current implementation does not support reg-reg mapping
497         if ((type & (RegMapping::VECTOR_VECTOR | RegMapping::FLOAT_FLOAT)) != 0U) {
498             return false;
499         }
500         // Scalar and float registers lay in different registers
501         if ((type & (RegMapping::SCALAR_VECTOR | RegMapping::SCALAR_FLOAT)) != 0U) {
502             return false;
503         }
504         return true;
505     };
506 
IsValid()507     bool IsValid() const override
508     {
509         return true;
510     }
511 
512     bool IsRegUsed(ArenaVector<Reg> vec_reg, Reg reg) override;
513 
514 public:
515     // Special implementation-specific getters
GetCalleeSavedR()516     size_t GetCalleeSavedR()
517     {
518         return static_cast<size_t>(callee_saved_);
519     }
GetCalleeSavedV()520     size_t GetCalleeSavedV()
521     {
522         return static_cast<size_t>(callee_savedv_);
523     }
GetCallerSavedR()524     size_t GetCallerSavedR()
525     {
526         return static_cast<size_t>(caller_saved_);
527     }
GetCallerSavedV()528     size_t GetCallerSavedV()
529     {
530         return static_cast<size_t>(caller_savedv_);
531     }
532 
AcquireScratchRegister(TypeInfo type)533     Reg AcquireScratchRegister(TypeInfo type)
534     {
535         if (type.IsFloat()) {
536             return Reg(scratchv_.Pop(), type);
537         }
538         return Reg(scratch_.Pop(), type);
539     }
540 
AcquireScratchRegister(Reg reg)541     void AcquireScratchRegister(Reg reg)
542     {
543         if (reg.GetType().IsFloat()) {
544             ASSERT(scratchv_.Has(reg.GetId()));
545             scratchv_.Remove(reg.GetId());
546         } else {
547             ASSERT(scratch_.Has(reg.GetId()));
548             scratch_.Remove(reg.GetId());
549         }
550     }
551 
ReleaseScratchRegister(Reg reg)552     void ReleaseScratchRegister(Reg reg)
553     {
554         if (reg.IsFloat()) {
555             scratchv_.Add(reg.GetId());
556         } else {
557             scratch_.Add(reg.GetId());
558         }
559     }
560 
IsScratchRegisterReleased(Reg reg)561     bool IsScratchRegisterReleased(Reg reg)
562     {
563         if (reg.GetType().IsFloat()) {
564             return scratchv_.Has(reg.GetId());
565         }
566         return scratch_.Has(reg.GetId());
567     }
568 
GetScratchRegisters()569     RegList GetScratchRegisters() const
570     {
571         return scratch_;
572     }
573 
GetScratchFPRegisters()574     RegList GetScratchFPRegisters() const
575     {
576         return scratchv_;
577     }
578 
GetScratchRegistersCount()579     size_t GetScratchRegistersCount() const
580     {
581         return scratch_.GetCount();
582     }
583 
GetScratchFPRegistersCount()584     size_t GetScratchFPRegistersCount() const
585     {
586         return scratchv_.GetCount();
587     }
588 
GetScratchRegistersMask()589     RegMask GetScratchRegistersMask() const
590     {
591         return RegMask(scratch_.GetMask());
592     }
593 
GetScratchFpRegistersMask()594     RegMask GetScratchFpRegistersMask() const
595     {
596         return RegMask(scratchv_.GetMask());
597     }
598 
599 private:
600     ArenaVector<Reg> used_regs_;
601 
602     RegList callee_saved_ {GetCalleeRegsMask(Arch::X86_64, false).GetValue()};
603     RegList caller_saved_ {GetCallerRegsMask(Arch::X86_64, false).GetValue()};
604 
605     RegList callee_savedv_ {GetCalleeRegsMask(Arch::X86_64, true).GetValue()};
606     RegList caller_savedv_ {GetCallerRegsMask(Arch::X86_64, true).GetValue()};
607 
608     RegList scratch_ {compiler::arch_info::x86_64::TEMP_REGS.to_ulong()};
609     RegList scratchv_ {compiler::arch_info::x86_64::TEMP_FP_REGS.to_ulong()};
610 };  // Amd64RegisterDescription
611 
612 class Amd64Encoder;
613 
614 class Amd64LabelHolder final : public LabelHolder {
615 public:
616     using LabelType = asmjit::Label;
617 
Amd64LabelHolder(Encoder * enc)618     explicit Amd64LabelHolder(Encoder *enc) : LabelHolder(enc), labels_(enc->GetAllocator()->Adapter()) {};
619     NO_MOVE_SEMANTIC(Amd64LabelHolder);
620     NO_COPY_SEMANTIC(Amd64LabelHolder);
621     ~Amd64LabelHolder() override = default;
622 
623     LabelId CreateLabel() override;
624 
CreateLabels(LabelId max)625     void CreateLabels(LabelId max) override
626     {
627         for (LabelId i = 0; i < max; ++i) {
628             CreateLabel();
629         }
630     };
631 
632     void BindLabel(LabelId id) override;
633 
GetLabel(LabelId id)634     LabelType *GetLabel(LabelId id)
635     {
636         ASSERT(labels_.size() > id);
637         return labels_[id];
638     }
639 
Size()640     LabelId Size() override
641     {
642         return labels_.size();
643     };
644 
645 private:
646     ArenaVector<LabelType *> labels_;
647     LabelId id_ {0};
648     friend Amd64Encoder;
649 };  // Amd64LabelHolder
650 
651 class Amd64Encoder final : public Encoder {
652 public:
653     using Encoder::Encoder;
654     explicit Amd64Encoder(ArenaAllocator *allocator);
655 
GetLabels()656     LabelHolder *GetLabels() const override
657     {
658         ASSERT(labels_ != nullptr);
659         return labels_;
660     };
661 
662     ~Amd64Encoder() override;
663 
664     NO_COPY_SEMANTIC(Amd64Encoder);
665     NO_MOVE_SEMANTIC(Amd64Encoder);
666 
IsValid()667     bool IsValid() const override
668     {
669         return true;
670     }
671 
GetTarget()672     static constexpr auto GetTarget()
673     {
674         return panda::compiler::Target(Arch::X86_64);
675     }
676 
677 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
678 #define UnaryOperation(opc) void Encode##opc(Reg dst, Reg src0) override;
679 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
680 #define BinaryOperation(opc)                                \
681     void Encode##opc(Reg dst, Reg src0, Reg src1) override; \
682     void Encode##opc(Reg dst, Reg src0, Imm src1) override;
683 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
684 #define INST_DEF(OPCODE, TYPE) TYPE(OPCODE)
685 
686     ENCODE_MATH_LIST(INST_DEF)
687 
688 #undef UnaryOperation
689 #undef BinaryOperation
690 #undef INST_DEF
691 
692     void EncodeNop() override;
693 
694     // Additional special instructions
695     void EncodeAdd(Reg dst, Reg src0, Shift src1) override;
696 
697     void EncodeCastToBool(Reg dst, Reg src) override;
698     void EncodeCast(Reg dst, bool dst_signed, Reg src, bool src_signed) override;
699     void EncodeMin(Reg dst, bool dst_signed, Reg src0, Reg src1) override;
700     void EncodeDiv(Reg dst, bool dst_signed, Reg src0, Reg src1) override;
701     void EncodeMod(Reg dst, bool dst_signed, Reg src0, Reg src1) override;
702     void EncodeMax(Reg dst, bool dst_signed, Reg src0, Reg src1) override;
703 
704     void EncodeAddOverflow(compiler::LabelHolder::LabelId id, Reg dst, Reg src0, Reg src1, Condition cc) override;
705     void EncodeSubOverflow(compiler::LabelHolder::LabelId id, Reg dst, Reg src0, Reg src1, Condition cc) override;
706 
707     void EncodeLdr(Reg dst, bool dst_signed, MemRef mem) override;
708     void EncodeLdrAcquire(Reg dst, bool dst_signed, MemRef mem) override;
709 
710     void EncodeMov(Reg dst, Imm src) override;
711     void EncodeStr(Reg src, MemRef mem) override;
712     void EncodeStrRelease(Reg src, MemRef mem) override;
713     // zerod high part: [reg.size, 64)
714     void EncodeStrz(Reg src, MemRef mem) override;
715     void EncodeSti(Imm src, MemRef mem) override;
716     // size must be 8, 16,32 or 64
717     void EncodeMemCopy(MemRef mem_from, MemRef mem_to, size_t size) override;
718     // size must be 8, 16,32 or 64
719     // zerod high part: [reg.size, 64)
720     void EncodeMemCopyz(MemRef mem_from, MemRef mem_to, size_t size) override;
721 
722     void EncodeCmp(Reg dst, Reg src0, Reg src1, Condition cc) override;
723 
724     void EncodeCompare(Reg dst, Reg src0, Reg src1, Condition cc) override;
725     void EncodeCompareTest(Reg dst, Reg src0, Reg src1, Condition cc) override;
726 
727     void EncodeSelect(Reg dst, Reg src0, Reg src1, Reg src2, Reg src3, Condition cc) override;
728     void EncodeSelect(Reg dst, Reg src0, Reg src1, Reg src2, Imm imm, Condition cc) override;
729     void EncodeSelectTest(Reg dst, Reg src0, Reg src1, Reg src2, Reg src3, Condition cc) override;
730     void EncodeSelectTest(Reg dst, Reg src0, Reg src1, Reg src2, Imm imm, Condition cc) override;
731 
732     void EncodeLdp(Reg dst0, Reg dst1, bool dst_signed, MemRef mem) override;
733 
734     void EncodeStp(Reg src0, Reg src1, MemRef mem) override;
735 
736     /* builtins-related encoders */
737     void EncodeIsInf(Reg dst, Reg src) override;
738     void EncodeBitCount(Reg dst, Reg src) override;
739     void EncodeCountLeadingZeroBits(Reg dst, Reg src) override;
740     void EncodeCountTrailingZeroBits(Reg dst, Reg src) override;
741     void EncodeCeil([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) override;
742     void EncodeFloor([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) override;
743     void EncodeRint([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) override;
744     void EncodeRound([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) override;
745     void EncodeReverseBytes(Reg dst, Reg src) override;
746     void EncodeReverseBits(Reg dst, Reg src) override;
747     void EncodeFpToBits(Reg dst, Reg src) override;
748     void EncodeMoveBitsRaw(Reg dst, Reg src) override;
749 
750     bool CanEncodeImmAddSubCmp(int64_t imm, uint32_t size, bool signed_compare) override;
751     bool CanEncodeImmLogical(uint64_t imm, uint32_t size) override;
752     bool CanEncodeScale(uint64_t imm, uint32_t size) override;
753     bool CanEncodeBitCount() override;
754 
EncodeCompareAndSwap(Reg dst,Reg obj,Reg offset,Reg val,Reg newval)755     void EncodeCompareAndSwap(Reg dst, Reg obj, Reg offset, Reg val, Reg newval) override
756     {
757         EncodeCompareAndSwap(dst, obj, &offset, val, newval);
758     }
759 
EncodeCompareAndSwap(Reg dst,Reg addr,Reg val,Reg newval)760     void EncodeCompareAndSwap(Reg dst, Reg addr, Reg val, Reg newval) override
761     {
762         EncodeCompareAndSwap(dst, addr, nullptr, val, newval);
763     }
764 
765     void EncodeUnsafeGetAndSet(Reg dst, Reg obj, Reg offset, Reg val) override;
766     void EncodeUnsafeGetAndAdd(Reg dst, Reg obj, Reg offset, Reg val, Reg tmp) override;
767     void EncodeMemoryBarrier(MemoryOrder::Order order) override;
768 
769     void EncodeStackOverflowCheck(ssize_t offset) override;
770 
GetCursorOffset()771     size_t GetCursorOffset() const override
772     {
773         return GetMasm()->offset();
774     }
775 
SetCursorOffset(size_t offset)776     void SetCursorOffset(size_t offset) override
777     {
778         GetMasm()->setOffset(offset);
779     }
780 
AcquireScratchRegister(TypeInfo type)781     Reg AcquireScratchRegister(TypeInfo type) override
782     {
783         return (static_cast<Amd64RegisterDescription *>(GetRegfile()))->AcquireScratchRegister(type);
784     }
785 
AcquireScratchRegister(Reg reg)786     void AcquireScratchRegister(Reg reg) override
787     {
788         (static_cast<Amd64RegisterDescription *>(GetRegfile()))->AcquireScratchRegister(reg);
789     }
790 
ReleaseScratchRegister(Reg reg)791     void ReleaseScratchRegister(Reg reg) override
792     {
793         (static_cast<Amd64RegisterDescription *>(GetRegfile()))->ReleaseScratchRegister(reg);
794     }
795 
IsScratchRegisterReleased(Reg reg)796     bool IsScratchRegisterReleased(Reg reg) override
797     {
798         return (static_cast<Amd64RegisterDescription *>(GetRegfile()))->IsScratchRegisterReleased(reg);
799     }
800 
GetScratchRegistersMask()801     RegMask GetScratchRegistersMask() const override
802     {
803         return (static_cast<const Amd64RegisterDescription *>(GetRegfile()))->GetScratchRegistersMask();
804     }
805 
GetScratchFpRegistersMask()806     RegMask GetScratchFpRegistersMask() const override
807     {
808         return (static_cast<const Amd64RegisterDescription *>(GetRegfile()))->GetScratchFpRegistersMask();
809     }
810 
GetAvailableScratchRegisters()811     RegMask GetAvailableScratchRegisters() const override
812     {
813         auto regfile = static_cast<const Amd64RegisterDescription *>(GetRegfile());
814         return RegMask(regfile->GetScratchRegisters().GetMask());
815     }
816 
GetAvailableScratchFpRegisters()817     VRegMask GetAvailableScratchFpRegisters() const override
818     {
819         auto regfile = static_cast<const Amd64RegisterDescription *>(GetRegfile());
820         return VRegMask(regfile->GetScratchFPRegisters().GetMask());
821     }
822 
GetRefType()823     TypeInfo GetRefType() override
824     {
825         return INT64_TYPE;
826     };
827 
828     size_t DisasmInstr(std::ostream &stream, size_t pc, ssize_t code_offset) const override;
829 
BufferData()830     void *BufferData() const override
831     {
832         return GetMasm()->bufferData();
833     };
834 
BufferSize()835     size_t BufferSize() const override
836     {
837         return GetMasm()->offset();
838     };
839 
840     bool InitMasm() override;
841 
842     void Finalize() override;
843 
844     void MakeCall(compiler::RelocationInfo *relocation) override;
845     void MakeCall(LabelHolder::LabelId id) override;
846     void MakeCall(const void *entry_point) override;
847     void MakeCall(Reg reg) override;
848     void MakeCall(MemRef entry_point) override;
849 
850     void MakeCallAot(intptr_t offset) override;
851     void MakeCallByOffset(intptr_t offset) override;
852     void MakeLoadAotTable(intptr_t offset, Reg reg) override;
853     void MakeLoadAotTableAddr(intptr_t offset, Reg addr, Reg val) override;
854     bool CanMakeCallByOffset(intptr_t offset) override;
855 
856     // Encode unconditional branch
857     void EncodeJump(LabelHolder::LabelId id) override;
858 
859     // Encode jump with compare to zero
860     void EncodeJump(LabelHolder::LabelId id, Reg src, Condition cc) override;
861 
862     // Compare reg and immediate and branch
863     void EncodeJump(LabelHolder::LabelId id, Reg src, Imm imm, Condition cc) override;
864 
865     // Compare two regs and branch
866     void EncodeJump(LabelHolder::LabelId id, Reg src0, Reg src1, Condition cc) override;
867 
868     // Compare reg and immediate and branch
869     void EncodeJumpTest(LabelHolder::LabelId id, Reg src, Imm imm, Condition cc) override;
870 
871     // Compare two regs and branch
872     void EncodeJumpTest(LabelHolder::LabelId id, Reg src0, Reg src1, Condition cc) override;
873 
874     // Encode jump by register value
875     void EncodeJump(Reg dst) override;
876 
877     void EncodeJump(RelocationInfo *relocation) override;
878 
879     void EncodeBitTestAndBranch(LabelHolder::LabelId id, compiler::Reg reg, uint32_t bit_pos, bool bit_value) override;
880 
881     void EncodeAbort() override;
882 
883     void EncodeReturn() override;
884 
885     void MakeLibCall(Reg dst, Reg src0, Reg src1, void *entry_point);
886 
SaveRegisters(RegMask registers,ssize_t slot,size_t start_reg,bool is_fp)887     void SaveRegisters(RegMask registers, ssize_t slot, size_t start_reg, bool is_fp) override
888     {
889         LoadStoreRegisters<true>(registers, slot, start_reg, is_fp);
890     }
LoadRegisters(RegMask registers,ssize_t slot,size_t start_reg,bool is_fp)891     void LoadRegisters(RegMask registers, ssize_t slot, size_t start_reg, bool is_fp) override
892     {
893         LoadStoreRegisters<false>(registers, slot, start_reg, is_fp);
894     }
SaveRegisters(RegMask registers,bool is_fp,ssize_t slot,Reg base,RegMask mask)895     void SaveRegisters(RegMask registers, bool is_fp, ssize_t slot, Reg base, RegMask mask) override
896     {
897         LoadStoreRegisters<true>(registers, is_fp, slot, base, mask);
898     }
LoadRegisters(RegMask registers,bool is_fp,ssize_t slot,Reg base,RegMask mask)899     void LoadRegisters(RegMask registers, bool is_fp, ssize_t slot, Reg base, RegMask mask) override
900     {
901         LoadStoreRegisters<false>(registers, is_fp, slot, base, mask);
902     }
903 
904     void PushRegisters(RegMask registers, bool is_fp, bool align) override;
905     void PopRegisters(RegMask registers, bool is_fp, bool align) override;
906 
907     template <typename Func>
908     void EncodeRelativePcMov(Reg reg, intptr_t offset, Func encode_instruction);
909 
GetMasm()910     asmjit::x86::Assembler *GetMasm() const
911     {
912         ASSERT(masm_ != nullptr);
913         return masm_;
914     }
915 
GetLabelAddress(LabelHolder::LabelId label)916     size_t GetLabelAddress(LabelHolder::LabelId label) override
917     {
918         auto code = GetMasm()->code();
919         ASSERT(code->isLabelBound(label));
920         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
921         return code->baseAddress() + code->labelOffset(label);
922     }
923 
LabelHasLinks(LabelHolder::LabelId label)924     bool LabelHasLinks(LabelHolder::LabelId label) override
925     {
926         auto code = GetMasm()->code();
927         auto entry = code->labelEntry(label);
928         return entry->links() != nullptr;
929     }
930 
931 private:
932     template <bool is_store>
933     void LoadStoreRegisters(RegMask registers, ssize_t slot, size_t start_reg, bool is_fp);
934 
935     template <bool is_store>
936     void LoadStoreRegisters(RegMask registers, bool is_fp, int32_t slot, Reg base, RegMask mask);
937 
938     inline Reg MakeShift(Shift shift);
939 
940     template <typename T>
941     void EncodeReverseBitsImpl(Reg dst0, Reg src0);
942 
943     void EncodeCastFloatToScalar(Reg dst, bool dst_signed, Reg src);
944     inline void EncodeCastFloatSignCheckRange(Reg dst, Reg src, const asmjit::Label &end);
945     inline void EncodeCastFloatUnsignCheckRange(Reg dst, Reg src, const asmjit::Label &end);
946     void EncodeCastFloatCheckNan(Reg dst, Reg src, const asmjit::Label &end);
947     void EncodeCastFloatCheckRange(Reg dst, Reg src, const asmjit::Label &end, int64_t min_value, uint64_t max_value);
948     void EncodeCastFloat32ToUint64(Reg dst, Reg src);
949     void EncodeCastFloat64ToUint64(Reg dst, Reg src);
950 
951     void EncodeCastScalarToFloat(Reg dst, Reg src, bool src_signed);
952     void EncodeCastScalarToFloatUnsignDouble(Reg dst, Reg src);
953     void EncodeCastScalar(Reg dst, bool dst_signed, Reg src, bool src_signed);
954 
955     void EncodeDivFloat(Reg dst, Reg src0, Reg src1);
956     void EncodeModFloat(Reg dst, Reg src0, Reg src1);
957     template <bool is_max>
958     void EncodeMinMaxFp(Reg dst, Reg src0, Reg src1);
959 
960     template <typename T, size_t n>
961     void CopyArrayToXmm(Reg xmm, const std::array<T, n> &arr);
962 
963     template <typename T>
964     void CopyImmToXmm(Reg xmm, T imm);
965 
966     void EncodeCompareAndSwap(Reg dst, Reg obj, const Reg *offset, Reg val, Reg newval);
967 
968 private:
969     Amd64LabelHolder *labels_ {nullptr};
970     asmjit::ErrorHandler *error_handler_ {nullptr};
971     asmjit::CodeHolder *code_holder_ {nullptr};
972     asmjit::x86::Assembler *masm_ {nullptr};
973 };  // Amd64Encoder
974 
975 class Amd64ParameterInfo : public ParameterInfo {
976 public:
977     std::variant<Reg, uint8_t> GetNativeParam(const TypeInfo &type) override;
978     Location GetNextLocation(DataType::Type type) override;
979 };
980 
981 class Amd64CallingConvention : public CallingConvention {
982 public:
983     Amd64CallingConvention(ArenaAllocator *allocator, Encoder *enc, RegistersDescription *descr, CallConvMode mode);
984     NO_MOVE_SEMANTIC(Amd64CallingConvention);
985     NO_COPY_SEMANTIC(Amd64CallingConvention);
986     ~Amd64CallingConvention() override = default;
987 
GetTarget()988     static constexpr auto GetTarget()
989     {
990         return panda::compiler::Target(Arch::X86_64);
991     }
992 
IsValid()993     bool IsValid() const override
994     {
995         return true;
996     }
997 
998     void GeneratePrologue(const FrameInfo &frame_info) override;
999     void GenerateEpilogue(const FrameInfo &frame_info, std::function<void()> post_job) override;
GenerateNativePrologue(const FrameInfo & frame_info)1000     void GenerateNativePrologue(const FrameInfo &frame_info) override
1001     {
1002         GeneratePrologue(frame_info);
1003     }
GenerateNativeEpilogue(const FrameInfo & frame_info,std::function<void ()> post_job)1004     void GenerateNativeEpilogue(const FrameInfo &frame_info, std::function<void()> post_job) override
1005     {
1006         GenerateEpilogue(frame_info, post_job);
1007     }
1008 
1009     void *GetCodeEntry() override;
1010     uint32_t GetCodeSize() override;
1011 
1012     // Pushes regs and returns number of regs(from boths vectors)
1013     size_t PushRegs(RegList regs, RegList vregs);
1014     // Pops regs and returns number of regs(from boths vectors)
1015     size_t PopRegs(RegList regs, RegList vregs);
1016 
1017     // Calculating information about parameters and save regs_offset registers for special needs
1018     ParameterInfo *GetParameterInfo(uint8_t regs_offset) override;
1019 
GetMasm()1020     asmjit::x86::Assembler *GetMasm()
1021     {
1022         return (static_cast<Amd64Encoder *>(GetEncoder()))->GetMasm();
1023     }
1024 
1025 private:
1026 };  // Amd64CallingConvention
1027 }  // namespace panda::compiler::amd64
1028 
1029 #endif  // COMPILER_OPTIMIZER_CODEGEN_TARGET_AMD64_TARGET_H_
1030