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