• 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_AARCH32_TARGET_H_
17 #define COMPILER_OPTIMIZER_CODEGEN_TARGET_AARCH32_TARGET_H_
18 
19 #include "operands.h"
20 #include "encode.h"
21 #include "callconv.h"
22 #include "target_info.h"
23 
24 #ifdef USE_VIXL_ARM32
25 #include "aarch32/constants-aarch32.h"
26 #include "aarch32/instructions-aarch32.h"
27 #include "aarch32/macro-assembler-aarch32.h"
28 #else
29 #error "Wrong build type, please add VIXL in build"
30 #endif  // USE_VIXL_ARM32
31 
32 namespace panda::compiler::aarch32 {
33 constexpr uint32_t AVAILABLE_DOUBLE_WORD_REGISTERS = 4;
34 
35 static inline constexpr const uint8_t UNDEF_REG = std::numeric_limits<uint8_t>::max();
36 
37 const size_t AARCH32_COUNT_REG = 3;
38 const size_t AARCH32_COUNT_VREG = 2;
39 
40 const size_t MAX_SCALAR_PARAM_ID = 3;          // r0-r3
41 const size_t MAX_VECTOR_SINGLE_PARAM_ID = 15;  // s0-s15
42 const size_t MAX_VECTOR_DOUBLE_PARAM_ID = 7;   // d0-d7
43 
44 // Temporary registers used (r12 already used by vixl)
45 // r11 is used as FP register for frames
46 const std::array<unsigned, AARCH32_COUNT_REG> AARCH32_TMP_REG = {
47     vixl::aarch32::r8.GetCode(), vixl::aarch32::r9.GetCode(), vixl::aarch32::r12.GetCode()};
48 
49 // Temporary vector registers used
50 const std::array<unsigned, AARCH32_COUNT_VREG> AARCH32_TMP_VREG = {vixl::aarch32::s14.GetCode(),
51                                                                    vixl::aarch32::s15.GetCode()};
52 
IsConditionSigned(Condition cc)53 static inline bool IsConditionSigned(Condition cc)
54 {
55     switch (cc) {
56         case Condition::LT:
57         case Condition::LE:
58         case Condition::GT:
59         case Condition::GE:
60             return true;
61 
62         default:
63             return false;
64     }
65 }
66 
67 /**
68  * Converters
69  */
Convert(const Condition CC)70 static inline vixl::aarch32::Condition Convert(const Condition CC)
71 {
72     switch (CC) {
73         case Condition::EQ:
74             return vixl::aarch32::eq;
75         case Condition::NE:
76             return vixl::aarch32::ne;
77         case Condition::LT:
78             return vixl::aarch32::lt;
79         case Condition::GT:
80             return vixl::aarch32::gt;
81         case Condition::LE:
82             return vixl::aarch32::le;
83         case Condition::GE:
84             return vixl::aarch32::ge;
85         case Condition::LO:
86             return vixl::aarch32::lo;
87         case Condition::LS:
88             return vixl::aarch32::ls;
89         case Condition::HI:
90             return vixl::aarch32::hi;
91         case Condition::HS:
92             return vixl::aarch32::hs;
93         // TODO(igorban) : Remove them
94         case Condition::MI:
95             return vixl::aarch32::mi;
96         case Condition::PL:
97             return vixl::aarch32::pl;
98         case Condition::VS:
99             return vixl::aarch32::vs;
100         case Condition::VC:
101             return vixl::aarch32::vc;
102         case Condition::AL:
103             return vixl::aarch32::al;
104         default:
105             UNREACHABLE();
106             return vixl::aarch32::eq;
107     }
108 }
109 
110 /**
111  * Converters
112  */
ConvertTest(const Condition CC)113 static inline vixl::aarch32::Condition ConvertTest(const Condition CC)
114 {
115     ASSERT(CC == Condition::TST_EQ || CC == Condition::TST_NE);
116     return CC == Condition::TST_EQ ? vixl::aarch32::eq : vixl::aarch32::ne;
117 }
118 
VixlReg(Reg reg)119 static inline vixl::aarch32::Register VixlReg(Reg reg)
120 {
121     ASSERT(reg.IsValid());
122     if (reg.IsScalar()) {
123         auto vixl_reg = vixl::aarch32::Register(reg.GetId());
124         ASSERT(vixl_reg.IsValid());
125         return vixl_reg;
126     }
127     // Unsupported register type
128     UNREACHABLE();
129     return vixl::aarch32::Register();
130 }
131 
132 // Upper half-part for register
VixlRegU(Reg reg)133 static inline vixl::aarch32::Register VixlRegU(Reg reg)
134 {
135     ASSERT(reg.IsValid());
136     if (reg.IsScalar()) {
137         auto vixl_reg = vixl::aarch32::Register(reg.GetId() + 1);
138         ASSERT(reg.GetId() <= AVAILABLE_DOUBLE_WORD_REGISTERS * 2U);
139         ASSERT(vixl_reg.IsValid());
140         return vixl_reg;
141     }
142     // Unsupported register type
143     UNREACHABLE();
144     return vixl::aarch32::Register();
145 }
146 
VixlVReg(Reg reg)147 static inline vixl::aarch32::VRegister VixlVReg(Reg reg)
148 {
149     ASSERT(reg.IsValid());
150     ASSERT(reg.IsFloat());
151     if (reg.GetSize() == WORD_SIZE) {
152         // Aarch32 Vreg map double regs for 2 single-word registers
153         auto vixl_vreg = vixl::aarch32::SRegister(reg.GetId());
154         ASSERT(vixl_vreg.IsValid());
155         return vixl_vreg;
156     }
157     ASSERT(reg.GetSize() == DOUBLE_WORD_SIZE);
158     ASSERT(reg.GetId() % 2U == 0);
159     auto vixl_vreg = vixl::aarch32::DRegister(reg.GetId() / 2U);
160     ASSERT(vixl_vreg.IsValid());
161     return vixl_vreg;
162 }
163 
VixlImm(const int32_t IMM)164 static inline vixl::aarch32::Operand VixlImm(const int32_t IMM)
165 {
166     return vixl::aarch32::Operand(IMM);
167 }
168 
VixlNeonImm(const float IMM)169 static inline vixl::aarch32::NeonImmediate VixlNeonImm(const float IMM)
170 {
171     return vixl::aarch32::NeonImmediate(IMM);
172 }
173 
VixlNeonImm(const double IMM)174 static inline vixl::aarch32::NeonImmediate VixlNeonImm(const double IMM)
175 {
176     return vixl::aarch32::NeonImmediate(IMM);
177 }
178 
179 static inline vixl::aarch32::DataType Convert(const TypeInfo INFO, const bool IS_SIGNED = false)
180 {
181     if (!IS_SIGNED) {
182         if (INFO.IsFloat()) {
183             if (INFO.GetSize() == WORD_SIZE) {
184                 return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::F32);
185             }
186             ASSERT(INFO.GetSize() == DOUBLE_WORD_SIZE);
187             return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::F64);
188         }
189         switch (INFO.GetSize()) {
190             case BYTE_SIZE:
191                 return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::I8);
192             case HALF_SIZE:
193                 return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::I16);
194             case WORD_SIZE:
195                 return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::I32);
196             case DOUBLE_WORD_SIZE:
197                 return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::I64);
198             default:
199                 break;
200         }
201     }
202     ASSERT(!INFO.IsFloat());
203 
204     switch (INFO.GetSize()) {
205         case BYTE_SIZE:
206             return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::S8);
207         case HALF_SIZE:
208             return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::S16);
209         case WORD_SIZE:
210             return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::S32);
211         case DOUBLE_WORD_SIZE:
212             return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::S64);
213         default:
214             break;
215     }
216     return vixl::aarch32::DataType(vixl::aarch32::DataTypeValue::kDataTypeValueInvalid);
217 }
218 
VixlImm(Imm imm)219 static inline vixl::aarch32::Operand VixlImm(Imm imm)
220 {
221     ASSERT(imm.IsValid());
222     // Unsupported 64-bit values - force cast
223     if (imm.GetType() == INT64_TYPE) {
224         auto data = static_cast<int32_t>(imm.GetValue<int64_t>());
225         return vixl::aarch32::Operand(data);
226     }
227     if (imm.GetType() == INT32_TYPE) {
228         return vixl::aarch32::Operand(imm.GetValue<int32_t>());
229     }
230     if (imm.GetType() == INT16_TYPE) {
231         return vixl::aarch32::Operand(imm.GetValue<int16_t>());
232     }
233     if (imm.GetType() == INT8_TYPE) {
234         return vixl::aarch32::Operand(imm.GetValue<int8_t>());
235     }
236     if (imm.GetType() == FLOAT32_TYPE) {
237         auto data = bit_cast<int32_t>(imm.GetValue<float>());
238         return vixl::aarch32::Operand(data);
239     }
240     if (imm.GetType() == FLOAT64_TYPE) {
241         auto data = static_cast<int32_t>(bit_cast<int64_t>(imm.GetValue<double>()));
242         return vixl::aarch32::Operand(data);
243     }
244     // Invalid converted register
245     UNREACHABLE();
246     return vixl::aarch32::Operand(imm.GetValue<int8_t>());
247 }
248 
249 // Upper half for immediate
VixlImmU(Imm imm)250 static inline vixl::aarch32::Operand VixlImmU(Imm imm)
251 {
252     ASSERT(imm.IsValid());
253     // Unsupported 64-bit values - force cast
254     if (imm.GetType() == INT64_TYPE) {
255         // NOLINTNEXTLINE(hicpp-signed-bitwise)
256         auto data = static_cast<int32_t>(imm.GetValue<int64_t>() >> WORD_SIZE);
257         return vixl::aarch32::Operand(data);
258     }
259     if (imm.GetType() == FLOAT64_TYPE) {
260         auto val = bit_cast<int64_t>(imm.GetValue<double>());
261         // NOLINTNEXTLINE(hicpp-signed-bitwise)
262         auto data = static_cast<int32_t>(val >> WORD_SIZE);
263         return vixl::aarch32::Operand(data);
264     }
265 
266     return vixl::aarch32::Operand(0x0);
267 }
268 
VixlDImm(Imm imm)269 static inline vixl::aarch32::DOperand VixlDImm(Imm imm)
270 {
271     ASSERT(imm.IsValid());
272     if (imm.GetType() == INT64_TYPE) {
273         auto data = imm.GetValue<int64_t>();
274         return vixl::aarch32::DOperand(data);
275     }
276     if (imm.GetType() == INT32_TYPE) {
277         return vixl::aarch32::DOperand(imm.GetValue<int32_t>());
278     }
279     if (imm.GetType() == INT16_TYPE) {
280         return vixl::aarch32::DOperand(imm.GetValue<int16_t>());
281     }
282     if (imm.GetType() == INT8_TYPE) {
283         return vixl::aarch32::DOperand(imm.GetValue<int8_t>());
284     }
285     // Invalid converted register
286     UNREACHABLE();
287     return vixl::aarch32::DOperand(imm.GetValue<int8_t>());
288 }
289 
290 class Aarch32RegisterDescription final : public RegistersDescription {
291     //                 r4-r10 - "0000011111110000"
292     const RegMask CALLEE_SAVED = RegMask(GetCalleeRegsMask(Arch::AARCH32, false));
293     //                 s16-s31 - "11111111111111110000000000000000"
294     const VRegMask CALLEE_SAVEDV = VRegMask(GetCalleeRegsMask(Arch::AARCH32, true));
295     //                 r0-r3 -  "0000000000001111"
296     const RegMask CALLER_SAVED = RegMask(GetCallerRegsMask(Arch::AARCH32, false));
297     //                 s0-s15 - "00000000000000001111111111111111"
298     const VRegMask CALLER_SAVEDV = VRegMask(GetCallerRegsMask(Arch::AARCH32, true));
299 
300 public:
301     explicit Aarch32RegisterDescription(ArenaAllocator *allocator);
302     NO_MOVE_SEMANTIC(Aarch32RegisterDescription);
303     NO_COPY_SEMANTIC(Aarch32RegisterDescription);
304     ~Aarch32RegisterDescription() override = default;
305 
306     ArenaVector<Reg> GetCalleeSaved() override;
307     void SetCalleeSaved(const ArenaVector<Reg> &regs) override;
308 
309     // Set used regs - change GetCallee
310     void SetUsedRegs(const ArenaVector<Reg> &regs) override;
311 
GetCallerSavedRegMask()312     RegMask GetCallerSavedRegMask() const override
313     {
314         return caller_saved_;
315     }
316 
GetCallerSavedVRegMask()317     VRegMask GetCallerSavedVRegMask() const override
318     {
319         return caller_savedv_;
320     }
321 
IsCalleeRegister(Reg reg)322     bool IsCalleeRegister(Reg reg) override
323     {
324         bool is_fp = reg.IsFloat();
325         return reg.GetId() >= GetFirstCalleeReg(Arch::AARCH32, is_fp) &&
326                reg.GetId() <= GetLastCalleeReg(Arch::AARCH32, is_fp);
327     }
328 
GetZeroReg()329     Reg GetZeroReg() const override
330     {
331         return INVALID_REGISTER;
332     }
333 
IsZeroReg(Reg reg)334     bool IsZeroReg([[maybe_unused]] Reg reg) const override
335     {
336         return false;
337     }
338 
GetTempReg()339     Reg::RegIDType GetTempReg() override
340     {
341         return INVALID_REG_ID;
342     }
343 
GetTempVReg()344     Reg::RegIDType GetTempVReg() override
345     {
346         return INVALID_REG_ID;
347     }
348 
349     // Reg Mask
350     // r0,r1,r2,r3,r4,r5,r6,r7,r8,r9,r10,r11,r12,r13,r14,r15
351     // -dwr0,-dwr1,-dwr2,-dwr3,-dwr4,---dwr8,---dwr6,---dwr7 <- double word
352     // r0,r1,r2,r3,r4,r5,r6,r7,r8,r9, fp+tmp,  sp+ip, lr+pc
353     // |----------------------------| <- available for regalloc
354     // r0,   r2,   r4,   r6    r8    - market to be available
GetDefaultRegMask()355     RegMask GetDefaultRegMask() const override
356     {
357         // Set all to 1
358         RegMask reg_mask;
359         reg_mask.set();
360         for (size_t i = 0; i < AVAILABLE_DOUBLE_WORD_REGISTERS; ++i) {
361             reg_mask.reset(i * 2U);
362         }
363         reg_mask.set(GetThreadReg(Arch::AARCH32));
364         return reg_mask;
365     }
366 
GetVRegMask()367     VRegMask GetVRegMask() override
368     {
369         VRegMask vreg_mask;
370         for (auto vreg_code : AARCH32_TMP_VREG) {
371             vreg_mask.set(vreg_code);
372         }
373         // Only d0-d15 available for alloc
374         // They mapped on s0-s31 same, like scalar:
375         for (size_t i = 0; i < vreg_mask.size() / 2U; ++i) {
376             vreg_mask.set(i * 2U + 1);
377         }
378         return vreg_mask;
379     }
380 
SupportMapping(uint32_t type)381     bool SupportMapping(uint32_t type) override
382     {
383         // Current implementation does not support vreg-vreg mapping
384         if ((type & (RegMapping::VECTOR_VECTOR | RegMapping::FLOAT_FLOAT)) != 0U) {
385             return false;
386         }
387         // Scalar and float registers lay in different registers
388         if ((type & (RegMapping::SCALAR_VECTOR | RegMapping::SCALAR_FLOAT)) != 0U) {
389             return false;
390         }
391         // Supported mapping for upper half register-parts:
392         // (type & RegMapping::SCALAR_SCALAR != 0)
393         return true;
394     };
395 
396     bool IsValid() const override;
397 
398     bool IsRegUsed(ArenaVector<Reg> vec_reg, Reg reg) override;
399 
400     // TODO(igorban): implement as virtual
401     static bool IsTmp(Reg reg);
402 
403 public:
404     // Special implementation-specific getters
GetCalleeSavedR()405     RegMask GetCalleeSavedR()
406     {
407         return callee_saved_;
408     }
GetCalleeSavedV()409     VRegMask GetCalleeSavedV()
410     {
411         return callee_savedv_;
412     }
GetCallerSavedR()413     RegMask GetCallerSavedR()
414     {
415         return caller_saved_;
416     }
GetCallerSavedV()417     VRegMask GetCallerSavedV()
418     {
419         return caller_savedv_;
420     }
421 
GetAligmentReg(bool is_callee)422     uint8_t GetAligmentReg(bool is_callee)
423     {
424         auto allignment_reg = is_callee ? allignment_reg_callee_ : allignment_reg_caller_;
425         ASSERT(allignment_reg != UNDEF_REG);
426         return allignment_reg;
427     }
428 
429 private:
430     // Full list of arm64 General-purpose registers (with vector registers)
431     ArenaVector<Reg> aarch32_reg_list_;
432     //
433     ArenaVector<Reg> used_regs_;
434     Reg tmp_reg1_;
435     Reg tmp_reg2_;
436 
437     RegMask callee_saved_ {CALLEE_SAVED};
438     RegMask caller_saved_ {CALLER_SAVED};
439 
440     VRegMask callee_savedv_ {CALLEE_SAVEDV};
441     VRegMask caller_savedv_ {CALLER_SAVEDV};
442 
443     uint8_t allignment_reg_callee_ {UNDEF_REG};
444     uint8_t allignment_reg_caller_ {UNDEF_REG};
445 };  // Aarch32RegisterDescription
446 
447 class Aarch32Encoder;
448 
449 class Aarch32LabelHolder final : public LabelHolder {
450 public:
451     using LabelType = vixl::aarch32::Label;
Aarch32LabelHolder(Encoder * enc)452     explicit Aarch32LabelHolder(Encoder *enc) : LabelHolder(enc), labels_(enc->GetAllocator()->Adapter()) {};
453 
CreateLabel()454     LabelId CreateLabel() override
455     {
456         ++id_;
457         auto allocator = GetEncoder()->GetAllocator();
458         auto *label = allocator->New<LabelType>(allocator);
459         labels_.push_back(label);
460         ASSERT(labels_.size() == id_);
461         return id_ - 1;
462     };
463 
CreateLabels(LabelId size)464     void CreateLabels(LabelId size) override
465     {
466         for (LabelId i = 0; i <= size; ++i) {
467             CreateLabel();
468         }
469     };
470 
471     void BindLabel(LabelId id) override;
472 
GetLabel(LabelId id)473     LabelType *GetLabel(LabelId id)
474     {
475         ASSERT(labels_.size() > id);
476         return labels_[id];
477     }
478 
Size()479     LabelId Size() override
480     {
481         return labels_.size();
482     };
483 
484     NO_MOVE_SEMANTIC(Aarch32LabelHolder);
485     NO_COPY_SEMANTIC(Aarch32LabelHolder);
486     ~Aarch32LabelHolder() override = default;
487 
488 private:
489     ArenaVector<LabelType *> labels_;
490     LabelId id_ {0};
491     friend Aarch32Encoder;
492 };  // Aarch32LabelHolder
493 
494 class Aarch32Encoder final : public Encoder {
495 public:
496     explicit Aarch32Encoder(ArenaAllocator *allocator);
497 
GetLabels()498     LabelHolder *GetLabels() const override
499     {
500         return labels_;
501     };
502 
503     ~Aarch32Encoder() override;
504 
505     NO_COPY_SEMANTIC(Aarch32Encoder);
506     NO_MOVE_SEMANTIC(Aarch32Encoder);
507 
IsValid()508     bool IsValid() const override
509     {
510         return true;
511     }
512 
GetTarget()513     static constexpr auto GetTarget()
514     {
515         return panda::compiler::Target(Arch::AARCH32);
516     }
517 
SetMaxAllocatedBytes(size_t size)518     void SetMaxAllocatedBytes(size_t size) override
519     {
520         GetMasm()->GetBuffer()->SetMmapMaxBytes(size);
521     }
522 
523 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
524 #define UnaryOperation(opc) void Encode##opc(Reg dst, Reg src0) override;
525 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
526 #define BinaryOperationRegRegReg(opc) void Encode##opc(Reg dst, Reg src0, Reg src1) override;
527 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
528 #define BinaryOperationRegRegImm(opc) void Encode##opc(Reg dst, Reg src0, Imm src1) override;
529 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
530 #define BinaryOperation(opc) BinaryOperationRegRegReg(opc) BinaryOperationRegRegImm(opc)
531 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
532 #define INST_DEF(OPCODE, TYPE) TYPE(OPCODE)
533 
534     ENCODE_MATH_LIST(INST_DEF)
535 
536 #undef UnaryOperation
537 #undef BinaryOperation
538 #undef INST_DEF
539 
540     void EncodeNop() override;
541 
542     // Additional special instructions
543     void EncodeCastToBool(Reg dst, Reg src) override;
544     void EncodeCast(Reg dst, bool dst_signed, Reg src, bool src_signed) override;
545     void EncodeMin(Reg dst, bool dst_signed, Reg src0, Reg src1) override;
546     void EncodeDiv(Reg dst, bool dst_signed, Reg src0, Reg src1) override;
547     void EncodeMod(Reg dst, bool dst_signed, Reg src0, Reg src1) override;
548     void EncodeMax(Reg dst, bool dst_signed, Reg src0, Reg src1) override;
549 
550     void EncodeLdr(Reg dst, bool dst_signed, MemRef mem) override;
551     void EncodeLdr(Reg dst, bool dst_signed, const vixl::aarch32::MemOperand &vixl_mem);
552     void EncodeLdrAcquire(Reg dst, bool dst_signed, MemRef mem) override;
553 
554     void EncodeMemoryBarrier(MemoryOrder::Order order) override;
555 
556     void EncodeMov(Reg dst, Imm src) override;
557     void EncodeStr(Reg src, const vixl::aarch32::MemOperand &vixl_mem);
558     void EncodeStr(Reg src, MemRef mem) override;
559     void EncodeStrRelease(Reg src, MemRef mem) override;
560     void EncodeStp(Reg src0, Reg src1, MemRef mem) override;
561 
562     /* builtins-related encoders */
563     void EncodeIsInf(Reg dst, Reg src) override;
564     void EncodeBitCount(Reg dst, Reg src) override;
565     void EncodeCountLeadingZeroBits(Reg dst, Reg src) override;
566     void EncodeCeil([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) override;
567     void EncodeFloor([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) override;
568     void EncodeRint([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) override;
569     void EncodeRound([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src) override;
570     void EncodeReverseBytes(Reg dst, Reg src) override;
571     void EncodeReverseBits(Reg dst, Reg src) override;
572     void EncodeFpToBits(Reg dst, Reg src) override;
573     void EncodeMoveBitsRaw(Reg dst, Reg src) override;
574 
575     void EncodeLdrExclusive(Reg dst, Reg addr, bool acquire) override;
576     void EncodeStrExclusive(Reg dst, Reg src, Reg addr, bool release) override;
577 
578     // zerod high part: [reg.size, 64)
579     void EncodeStrz(Reg src, MemRef mem) override;
580     void EncodeSti(Imm src, MemRef mem) override;
581     // size must be 8, 16,32 or 64
582     void EncodeMemCopy(MemRef mem_from, MemRef mem_to, size_t size) override;
583     // size must be 8, 16,32 or 64
584     // zerod high part: [reg.size, 64)
585     void EncodeMemCopyz(MemRef mem_from, MemRef mem_to, size_t size) override;
586 
587     void EncodeCmp(Reg dst, Reg src0, Reg src1, Condition cc) override;
588 
589     void EncodeCompare(Reg dst, Reg src0, Reg src1, Condition cc) override;
590     void EncodeCompareTest(Reg dst, Reg src0, Reg src1, Condition cc) override;
591 
592     void EncodeSelect(Reg dst, Reg src0, Reg src1, Reg src2, Reg src3, Condition cc) override;
593     void EncodeSelect(Reg dst, Reg src0, Reg src1, Reg src2, Imm imm, Condition cc) override;
594     void EncodeSelectTest(Reg dst, Reg src0, Reg src1, Reg src2, Reg src3, Condition cc) override;
595     void EncodeSelectTest(Reg dst, Reg src0, Reg src1, Reg src2, Imm imm, Condition cc) override;
596 
597     bool CanEncodeImmAddSubCmp(int64_t imm, uint32_t size, bool signed_compare) override;
598     bool CanEncodeImmLogical(uint64_t imm, uint32_t size) override;
599 
GetCursorOffset()600     size_t GetCursorOffset() const override
601     {
602         return GetMasm()->GetBuffer()->GetCursorOffset();
603     }
604 
SetCursorOffset(size_t offset)605     void SetCursorOffset(size_t offset) override
606     {
607         GetMasm()->GetBuffer()->Rewind(offset);
608     }
609 
AcquireScratchRegister(TypeInfo type)610     Reg AcquireScratchRegister(TypeInfo type) override
611     {
612         ASSERT(GetMasm()->GetCurrentScratchRegisterScope() == nullptr);
613         if (type.IsFloat()) {
614             if (type == FLOAT32_TYPE) {
615                 auto reg = GetMasm()->GetScratchVRegisterList()->GetFirstAvailableSRegister();
616                 ASSERT(reg.IsValid());
617                 GetMasm()->GetScratchVRegisterList()->Remove(reg);
618                 return Reg(reg.GetCode(), type);
619             }
620             // Get 2 float registers instead one double - to save agreement about hi-regs in VixlVReg
621             auto reg1 = GetMasm()->GetScratchVRegisterList()->GetFirstAvailableSRegister();
622             auto reg2 = GetMasm()->GetScratchVRegisterList()->GetFirstAvailableSRegister();
623             ASSERT(reg1.IsValid());
624             ASSERT(reg2.IsValid());
625             GetMasm()->GetScratchVRegisterList()->Remove(reg1);
626             GetMasm()->GetScratchVRegisterList()->Remove(reg2);
627             return Reg(reg1.GetCode(), type);
628         }
629         auto reg = GetMasm()->GetScratchRegisterList()->GetFirstAvailableRegister();
630         ASSERT(reg.IsValid());
631         GetMasm()->GetScratchRegisterList()->Remove(reg);
632         return Reg(reg.GetCode(), type);
633     }
634 
AcquireScratchRegister(Reg reg)635     void AcquireScratchRegister(Reg reg) override
636     {
637         if (reg == GetTarget().GetLinkReg()) {
638             ASSERT_PRINT(!lr_acquired_, "Trying to acquire LR, which hasn't been released before");
639             lr_acquired_ = true;
640         } else if (reg.IsFloat()) {
641             ASSERT(GetMasm()->GetScratchVRegisterList()->IncludesAliasOf(vixl::aarch32::SRegister(reg.GetId())));
642             GetMasm()->GetScratchVRegisterList()->Remove(vixl::aarch32::SRegister(reg.GetId()));
643         } else {
644             ASSERT(GetMasm()->GetScratchRegisterList()->Includes(vixl::aarch32::Register(reg.GetId())));
645             GetMasm()->GetScratchRegisterList()->Remove(vixl::aarch32::Register(reg.GetId()));
646         }
647     }
648 
ReleaseScratchRegister(Reg reg)649     void ReleaseScratchRegister(Reg reg) override
650     {
651         if (reg == GetTarget().GetLinkReg()) {
652             ASSERT_PRINT(lr_acquired_, "Trying to release LR, which hasn't been acquired before");
653             lr_acquired_ = false;
654         } else if (reg.IsFloat()) {
655             GetMasm()->GetScratchVRegisterList()->Combine(vixl::aarch32::SRegister(reg.GetId()));
656         } else {
657             GetMasm()->GetScratchRegisterList()->Combine(vixl::aarch32::Register(reg.GetId()));
658         }
659     }
660 
IsScratchRegisterReleased(Reg reg)661     bool IsScratchRegisterReleased(Reg reg) override
662     {
663         if (reg == GetTarget().GetLinkReg()) {
664             return !lr_acquired_;
665         }
666         if (reg.IsFloat()) {
667             return GetMasm()->GetScratchVRegisterList()->IncludesAliasOf(vixl::aarch32::SRegister(reg.GetId()));
668         }
669         return GetMasm()->GetScratchRegisterList()->Includes(vixl::aarch32::Register(reg.GetId()));
670     }
671 
GetScratchRegistersMask()672     RegMask GetScratchRegistersMask() const override
673     {
674         return RegMask(GetMasm()->GetScratchRegisterList()->GetList());
675     }
676 
GetScratchFpRegistersMask()677     RegMask GetScratchFpRegistersMask() const override
678     {
679         return RegMask(GetMasm()->GetScratchVRegisterList()->GetList());
680     }
681 
GetAvailableScratchRegisters()682     RegMask GetAvailableScratchRegisters() const override
683     {
684         return RegMask(GetMasm()->GetScratchRegisterList()->GetList());
685     }
686 
GetAvailableScratchFpRegisters()687     VRegMask GetAvailableScratchFpRegisters() const override
688     {
689         return VRegMask(GetMasm()->GetScratchVRegisterList()->GetList());
690     }
691 
SetRegister(RegMask * mask,VRegMask * vmask,Reg reg,bool val)692     void SetRegister(RegMask *mask, VRegMask *vmask, Reg reg, bool val) const override
693     {
694         if (!reg.IsValid()) {
695             return;
696         }
697         if (reg.IsScalar()) {
698             ASSERT(mask != nullptr);
699             mask->set(reg.GetId(), val);
700             if (reg.GetSize() > WORD_SIZE) {
701                 mask->set(reg.GetId() + 1, val);
702             }
703         } else {
704             ASSERT(vmask != nullptr);
705             ASSERT(reg.IsFloat());
706             vmask->set(reg.GetId(), val);
707             if (reg.GetSize() > WORD_SIZE) {
708                 vmask->set(reg.GetId() + 1, val);
709             }
710         }
711     }
712 
GetRefType()713     TypeInfo GetRefType() override
714     {
715         return INT32_TYPE;
716     };
717 
718     size_t DisasmInstr(std::ostream &stream, size_t pc, ssize_t code_offset) const override;
719 
BufferData()720     void *BufferData() const override
721     {
722         return GetMasm()->GetBuffer()->GetStartAddress<void *>();
723     };
724 
BufferSize()725     size_t BufferSize() const override
726     {
727         return GetMasm()->GetBuffer()->GetSizeInBytes();
728     };
729 
730     bool InitMasm() override;
731 
732     void Finalize() override;
733 
734     void MakeCall(compiler::RelocationInfo *relocation) override;
735     void MakeCall(const void *entry_point) override;
736     void MakeCall(MemRef entry_point) override;
737     void MakeCall(Reg reg) override;
738 
739     void MakeCallAot(intptr_t offset) override;
740     void MakeCallByOffset(intptr_t offset) override;
741     void MakeLoadAotTable(intptr_t offset, Reg reg) override;
742     void MakeLoadAotTableAddr(intptr_t offset, Reg addr, Reg val) override;
743 
744     // Encode unconditional branch
745     void EncodeJump(LabelHolder::LabelId id) override;
746 
747     // Encode jump with compare to zero
748     void EncodeJump(LabelHolder::LabelId id, Reg src, Condition cc) override;
749 
750     // Compare reg and immediate and branch
751     void EncodeJump(LabelHolder::LabelId id, Reg src, Imm imm, Condition cc) override;
752 
753     // Compare two regs and branch
754     void EncodeJump(LabelHolder::LabelId id, Reg src0, Reg src1, Condition cc) override;
755 
756     // Compare reg and immediate and branch
757     void EncodeJumpTest(LabelHolder::LabelId id, Reg src, Imm imm, Condition cc) override;
758 
759     // Compare two regs and branch
760     void EncodeJumpTest(LabelHolder::LabelId id, Reg src0, Reg src1, Condition cc) override;
761 
762     // Encode jump by register value
763     void EncodeJump(Reg dst) override;
764 
765     void EncodeJump(RelocationInfo *relocation) override;
766 
767     void EncodeBitTestAndBranch(LabelHolder::LabelId id, compiler::Reg reg, uint32_t bit_pos, bool bit_value) override;
768 
769     void EncodeAbort() override;
770 
771     void EncodeReturn() override;
772 
773     void EncodeStackOverflowCheck(ssize_t offset) override;
774 
SaveRegisters(RegMask registers,ssize_t slot,size_t start_reg,bool is_fp)775     void SaveRegisters(RegMask registers, ssize_t slot, size_t start_reg, bool is_fp) override
776     {
777         LoadStoreRegisters<true>(registers, slot, start_reg, is_fp);
778     }
LoadRegisters(RegMask registers,ssize_t slot,size_t start_reg,bool is_fp)779     void LoadRegisters(RegMask registers, ssize_t slot, size_t start_reg, bool is_fp) override
780     {
781         LoadStoreRegisters<false>(registers, slot, start_reg, is_fp);
782     }
783 
SaveRegisters(RegMask registers,bool is_fp,ssize_t slot,Reg base,RegMask mask)784     void SaveRegisters(RegMask registers, bool is_fp, ssize_t slot, Reg base, RegMask mask) override
785     {
786         LoadStoreRegisters<true>(registers, is_fp, slot, base, mask);
787     }
LoadRegisters(RegMask registers,bool is_fp,ssize_t slot,Reg base,RegMask mask)788     void LoadRegisters(RegMask registers, bool is_fp, ssize_t slot, Reg base, RegMask mask) override
789     {
790         LoadStoreRegisters<false>(registers, is_fp, slot, base, mask);
791     }
792 
793     void PushRegisters(RegMask registers, bool is_fp, bool align) override;
794     void PopRegisters(RegMask registers, bool is_fp, bool align) override;
795 
ConvertMem(MemRef mem)796     static inline vixl::aarch32::MemOperand ConvertMem(MemRef mem)
797     {
798         bool has_index = mem.HasIndex();
799         bool has_shift = mem.HasScale();
800         bool has_offset = mem.HasDisp();
801         auto base_reg = VixlReg(mem.GetBase());
802         if (has_index) {
803             // MemRef with index and offser isn't supported
804             ASSERT(!has_offset);
805             auto index_reg = mem.GetIndex();
806             if (has_shift) {
807                 auto shift = mem.GetScale();
808                 return vixl::aarch32::MemOperand(base_reg, VixlReg(index_reg), vixl::aarch32::LSL, shift);
809             }
810             return vixl::aarch32::MemOperand(base_reg, VixlReg(index_reg));
811         }
812         if (has_offset) {
813             auto offset = mem.GetDisp();
814             return vixl::aarch32::MemOperand(base_reg, offset);
815         }
816         return vixl::aarch32::MemOperand(base_reg);
817     }
818 
819     /**
820      * The function construct additional instruction for encode memory instructions and returns MemOperand for ldr/str
821      * LDR/STR with immediate offset(for A32)
822      * |  mem type  | offset size |
823      * | ---------- | ----------- |
824      * |word or byte|-4095 to 4095|
825      * |   others   | -255 to 255 |
826      *
827      * LDR/STR with register offset(for A32)
828      * |  mem type  |    shift    |
829      * | ---------- | ----------- |
830      * |word or byte|    0 to 31  |
831      * |   others   |      --     |
832      *
833      * VLDR and VSTR has base and offset. The offset must be a multiple of 4, and lie in the range -1020 to +1020.
834      */
835     static bool IsNeedToPrepareMemLdS(MemRef mem, const TypeInfo &mem_type, bool is_signed);
836     vixl::aarch32::MemOperand PrepareMemLdS(MemRef mem, const TypeInfo &mem_type, vixl::aarch32::Register tmp,
837                                             bool is_signed, bool copy_sp = false);
838 
839     void MakeLibCall(Reg dst, Reg src0, Reg src1, void *entry_point, bool second_value = false);
840 
841     void MakeLibCall(Reg dst, Reg src, void *entry_point);
842 
GetMasm()843     vixl::aarch32::MacroAssembler *GetMasm() const
844     {
845         ASSERT(masm_ != nullptr);
846         return masm_;
847     }
848 
GetLabelAddress(LabelHolder::LabelId label)849     size_t GetLabelAddress(LabelHolder::LabelId label) override
850     {
851         auto plabel = labels_->GetLabel(label);
852         ASSERT(plabel->IsBound());
853         return GetMasm()->GetBuffer()->GetOffsetAddress<size_t>(plabel->GetLocation());
854     }
855 
LabelHasLinks(LabelHolder::LabelId label)856     bool LabelHasLinks(LabelHolder::LabelId label) override
857     {
858         auto plabel = labels_->GetLabel(label);
859         return plabel->IsReferenced();
860     }
861 
862 private:
863     template <bool is_store>
864     void LoadStoreRegisters(RegMask registers, ssize_t slot, size_t start_reg, bool is_fp);
865 
866     template <bool is_store>
867     void LoadStoreRegisters(RegMask registers, bool is_fp, int32_t slot, Reg base, RegMask mask);
868 
869 private:
870     vixl::aarch32::MemOperand PrepareMemLdSForFloat(MemRef mem, vixl::aarch32::Register tmp);
871     void EncodeCastFloatToFloat(Reg dst, Reg src);
872     void EncodeCastFloatToInt64(Reg dst, Reg src);
873     void EncodeCastDoubleToInt64(Reg dst, Reg src);
874     void EncodeCastScalarToFloat(Reg dst, Reg src, bool src_signed);
875     void EncodeCastFloatToScalar(Reg dst, bool dst_signed, Reg src);
876     void EncodeCastFloatToScalarWithSmallDst(Reg dst, bool dst_signed, Reg src);
877 
878     void EncoderCastExtendFromInt32(Reg dst, bool dst_signed);
879     void EncodeCastScalar(Reg dst, bool dst_signed, Reg src, bool src_signed);
880     void EncodeCastScalarFromSignedScalar(Reg dst, Reg src);
881     void EncodeCastScalarFromUnsignedScalar(Reg dst, Reg src);
882     template <bool is_max>
883     void EncodeMinMaxFp(Reg dst, Reg src0, Reg src1);
884     void EncodeVorr(Reg dst, Reg src0, Reg src1);
885     void EncodeVand(Reg dst, Reg src0, Reg src1);
886     void MakeLibCallWithFloatResult(Reg dst, Reg src0, Reg src1, void *entry_point, bool second_value);
887     void MakeLibCallWithDoubleResult(Reg dst, Reg src0, Reg src1, void *entry_point, bool second_value);
888     void MakeLibCallWithInt64Result(Reg dst, Reg src0, Reg src1, void *entry_point, bool second_value);
889     void CompareHelper(Reg src0, Reg src1, Condition *cc);
890     void TestHelper(Reg src0, Reg src1, Condition cc);
891     bool CompareImmHelper(Reg src, Imm imm, Condition *cc);
892     void TestImmHelper(Reg src, Imm imm, Condition cc);
893     bool CompareNegImmHelper(Reg src, int64_t value, const Condition *cc);
894     bool ComparePosImmHelper(Reg src, int64_t value, Condition *cc);
895     void CompareZeroHelper(Reg src, Condition *cc);
896     void EncodeFloatSti(Imm src, MemRef mem);
897     static inline constexpr int32_t MEM_BIG_OFFSET = 4095;
898     static inline constexpr int32_t MEM_SMALL_OFFSET = 255;
899     static inline constexpr int32_t VMEM_OFFSET = 1020;
900     Aarch32LabelHolder *labels_ {nullptr};
901     vixl::aarch32::MacroAssembler *masm_ {nullptr};
902     bool lr_acquired_ {false};
903 };  // Aarch32Encoder
904 
905 class Aarch32ParameterInfo final : public ParameterInfo {
906 public:
907     std::variant<Reg, uint8_t> GetNativeParam(const TypeInfo &type) override;
908     Location GetNextLocation(DataType::Type type) override;
909 };
910 
911 class Aarch32CallingConvention : public CallingConvention {
912 public:
913     Aarch32CallingConvention(ArenaAllocator *allocator, Encoder *enc, RegistersDescription *descr, CallConvMode mode);
914 
GetTarget()915     static constexpr auto GetTarget()
916     {
917         return panda::compiler::Target(Arch::AARCH32);
918     }
919 
IsValid()920     bool IsValid() const override
921     {
922         return true;
923     }
924 
925     void GeneratePrologue(const FrameInfo &frame_info) override;
926     void GenerateEpilogue(const FrameInfo &frame_info, std::function<void()> post_job) override;
GenerateNativePrologue(const FrameInfo & frame_info)927     void GenerateNativePrologue(const FrameInfo &frame_info) override
928     {
929         GeneratePrologue(frame_info);
930     }
GenerateNativeEpilogue(const FrameInfo & frame_info,std::function<void ()> post_job)931     void GenerateNativeEpilogue(const FrameInfo &frame_info, std::function<void()> post_job) override
932     {
933         GenerateEpilogue(frame_info, post_job);
934     }
935 
936     void *GetCodeEntry() override;
937     uint32_t GetCodeSize() override;
938 
GetMasm()939     vixl::aarch32::MacroAssembler *GetMasm()
940     {
941         return (static_cast<Aarch32Encoder *>(GetEncoder()))->GetMasm();
942     }
943 
944     // Calculating information about parameters and save regs_offset registers for special needs
945     ParameterInfo *GetParameterInfo(uint8_t regs_offset) override;
946 
947     NO_MOVE_SEMANTIC(Aarch32CallingConvention);
948     NO_COPY_SEMANTIC(Aarch32CallingConvention);
949     ~Aarch32CallingConvention() override = default;
950 
951 private:
952     uint8_t PushPopVRegs(VRegMask vregs, bool is_push);
953     uint8_t PushRegs(RegMask regs, VRegMask vregs, bool is_callee);
954     uint8_t PopRegs(RegMask regs, VRegMask vregs, bool is_callee);
955 };  // Aarch32CallingConvention
956 }  // namespace panda::compiler::aarch32
957 
958 #endif  // COMPILER_OPTIMIZER_CODEGEN_TARGET_AARCH32_TARGET_H_
959