• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 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 Encoder (implementation of math and mem Low-level emitters)
17 */
18 
19 #include <aarch32/disasm-aarch32.h>
20 #include "compiler/optimizer/code_generator/relocations.h"
21 #include "encode.h"
22 #include "operands.h"
23 #include "target/aarch32/target.h"
24 #include "lib_helpers.inl"
25 
26 #ifndef PANDA_TARGET_MACOS
27 #include "elf.h"
28 #endif  // PANDA_TARGET_MACOS
29 
30 #include <iomanip>
31 
32 namespace panda::compiler::aarch32 {
BindLabel(LabelId id)33 void Aarch32LabelHolder::BindLabel(LabelId id)
34 {
35     static_cast<Aarch32Encoder *>(GetEncoder())->GetMasm()->Bind(labels_[id]);
36 }
37 
Aarch32Encoder(ArenaAllocator * allocator)38 Aarch32Encoder::Aarch32Encoder(ArenaAllocator *allocator) : Encoder(allocator, Arch::AARCH32)
39 {
40     labels_ = allocator->New<Aarch32LabelHolder>(this);
41     if (labels_ == nullptr) {
42         SetFalseResult();
43     }
44     EnableLrAsTempReg(true);
45 }
46 
~Aarch32Encoder()47 Aarch32Encoder::~Aarch32Encoder()
48 {
49     auto labels = static_cast<Aarch32LabelHolder *>(GetLabels())->labels_;
50     for (auto label : labels) {
51         label->~Label();
52     }
53     if (masm_ != nullptr) {
54         masm_->~MacroAssembler();
55         masm_ = nullptr;
56     }
57 }
58 
InitMasm()59 bool Aarch32Encoder::InitMasm()
60 {
61     if (masm_ == nullptr) {
62         auto allocator = GetAllocator();
63 
64         // Initialize Masm
65         masm_ = allocator->New<vixl::aarch32::MacroAssembler>(allocator);
66         if (masm_ == nullptr || !masm_->IsValid()) {
67             SetFalseResult();
68             return false;
69         }
70 
71         ASSERT(masm_);
72         for (auto regCode : AARCH32_TMP_REG) {
73             masm_->GetScratchRegisterList()->Combine(vixl::aarch32::Register(regCode));
74         }
75         for (auto vregCode : AARCH32_TMP_VREG) {
76             masm_->GetScratchVRegisterList()->Combine(vixl::aarch32::SRegister(vregCode));
77         }
78 
79         // Make sure that the compiler uses the same scratch registers as the assembler
80         CHECK_EQ(RegMask(masm_->GetScratchRegisterList()->GetList()), GetTarget().GetTempRegsMask());
81         CHECK_EQ(RegMask(masm_->GetScratchVRegisterList()->GetList()), GetTarget().GetTempVRegsMask());
82     }
83     return true;
84 }
85 
Finalize()86 void Aarch32Encoder::Finalize()
87 {
88     GetMasm()->FinalizeCode();
89 }
90 
EncodeJump(LabelHolder::LabelId id)91 void Aarch32Encoder::EncodeJump(LabelHolder::LabelId id)
92 {
93     auto label = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(id);
94     GetMasm()->B(label);
95 }
96 
EncodeJump(LabelHolder::LabelId id,Reg src0,Reg src1,Condition cc)97 void Aarch32Encoder::EncodeJump(LabelHolder::LabelId id, Reg src0, Reg src1, Condition cc)
98 {
99     auto label = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(id);
100     CompareHelper(src0, src1, &cc);
101     GetMasm()->B(Convert(cc), label);
102 }
103 
EncodeJumpTest(LabelHolder::LabelId id,Reg src0,Reg src1,Condition cc)104 void Aarch32Encoder::EncodeJumpTest(LabelHolder::LabelId id, Reg src0, Reg src1, Condition cc)
105 {
106     auto label = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(id);
107     TestHelper(src0, src1, cc);
108     GetMasm()->B(ConvertTest(cc), label);
109 }
110 
EncodeBitTestAndBranch(LabelHolder::LabelId id,Reg reg,uint32_t bitPos,bool bitValue)111 void Aarch32Encoder::EncodeBitTestAndBranch(LabelHolder::LabelId id, Reg reg, uint32_t bitPos, bool bitValue)
112 {
113     ASSERT(reg.IsScalar() && reg.GetSize() > bitPos);
114     auto label = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(id);
115     if (reg.GetSize() == DOUBLE_WORD_SIZE) {
116         if (bitPos < WORD_SIZE) {
117             GetMasm()->tst(VixlReg(reg), VixlImm(1U << bitPos));
118         } else {
119             GetMasm()->tst(VixlRegU(reg), VixlImm(1U << (bitPos - WORD_SIZE)));
120         }
121     } else {
122         GetMasm()->tst(VixlReg(reg), VixlImm(1U << bitPos));
123     }
124     if (bitValue) {
125         GetMasm()->B(Convert(Condition::NE), label);
126     } else {
127         GetMasm()->B(Convert(Condition::EQ), label);
128     }
129 }
130 
CompareImmHelper(Reg src,int64_t imm,Condition * cc)131 bool Aarch32Encoder::CompareImmHelper(Reg src, int64_t imm, Condition *cc)
132 {
133     ASSERT(src.IsScalar());
134     ASSERT(imm != 0);
135     ASSERT(-static_cast<int64_t>(UINT32_MAX) <= imm && imm <= UINT32_MAX);
136     ASSERT(CanEncodeImmAddSubCmp(imm, src.GetSize(), IsConditionSigned(*cc)));
137 
138     return imm < 0 ? CompareNegImmHelper(src, imm, cc) : ComparePosImmHelper(src, imm, cc);
139 }
140 
TestImmHelper(Reg src,Imm imm,Condition cc)141 void Aarch32Encoder::TestImmHelper(Reg src, Imm imm, [[maybe_unused]] Condition cc)
142 {
143     auto value = imm.GetAsInt();
144     ASSERT(src.IsScalar());
145     ASSERT(cc == Condition::TST_EQ || cc == Condition::TST_NE);
146     ASSERT(CanEncodeImmLogical(value, src.GetSize()));
147 
148     if (src.GetSize() <= WORD_SIZE) {
149         GetMasm()->Tst(VixlReg(src), VixlImm(value));
150     } else {
151         GetMasm()->Tst(VixlRegU(src), VixlImm(0x0));
152         GetMasm()->Tst(Convert(Condition::EQ), VixlReg(src), VixlImm(value));
153     }
154 }
155 
CompareNegImmHelper(Reg src,int64_t value,const Condition * cc)156 bool Aarch32Encoder::CompareNegImmHelper(Reg src, int64_t value, const Condition *cc)
157 {
158     if (src.GetSize() <= WORD_SIZE) {
159         GetMasm()->Cmn(VixlReg(src), VixlImm(-value));
160     } else {
161         if (!IsConditionSigned(*cc)) {
162             GetMasm()->Cmn(VixlRegU(src), VixlImm(0x1));
163             GetMasm()->Cmn(Convert(Condition::EQ), VixlReg(src), VixlImm(-value));
164         } else {
165             // There are no effective implementation in this case
166             // Can't get here because of logic behind CanEncodeImmAddSubCmp
167             UNREACHABLE();
168             SetFalseResult();
169             return false;
170         }
171     }
172     return true;
173 }
174 
ComparePosImmHelper(Reg src,int64_t value,Condition * cc)175 bool Aarch32Encoder::ComparePosImmHelper(Reg src, int64_t value, Condition *cc)
176 {
177     if (src.GetSize() <= WORD_SIZE) {
178         GetMasm()->Cmp(VixlReg(src), VixlImm(value));
179     } else {
180         if (!IsConditionSigned(*cc)) {
181             GetMasm()->Cmp(VixlRegU(src), VixlImm(0x0));
182             GetMasm()->Cmp(Convert(Condition::EQ), VixlReg(src), VixlImm(value));
183         } else {
184             bool swap = false;
185             switch (*cc) {
186                 case Condition::GT:
187                     swap = true;
188                     *cc = Condition::LT;
189                     break;
190                 case Condition::LE:
191                     swap = true;
192                     *cc = Condition::GE;
193                     break;
194                 case Condition::GE:
195                 case Condition::LT:
196                     break;
197                 default:
198                     UNREACHABLE();
199             }
200 
201             ScopedTmpRegU32 tmpReg(this);
202             if (swap) {
203                 GetMasm()->Rsbs(VixlReg(tmpReg), VixlReg(src), VixlImm(value));
204                 GetMasm()->Rscs(VixlReg(tmpReg), VixlRegU(src), vixl::aarch32::Operand(0x0));
205             } else {
206                 GetMasm()->Cmp(VixlReg(src), VixlImm(value));
207                 GetMasm()->Sbcs(VixlReg(tmpReg), VixlRegU(src), vixl::aarch32::Operand(0x0));
208             }
209         }
210     }
211     return true;
212 }
213 
EncodeJump(LabelHolder::LabelId id,Reg src,Imm imm,Condition cc)214 void Aarch32Encoder::EncodeJump(LabelHolder::LabelId id, Reg src, Imm imm, Condition cc)
215 {
216     auto value = imm.GetAsInt();
217     if (value == 0) {
218         EncodeJump(id, src, cc);
219         return;
220     }
221 
222     if (!CompareImmHelper(src, value, &cc)) {
223         return;
224     }
225 
226     auto label = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(id);
227     GetMasm()->B(Convert(cc), label);
228 }
229 
EncodeJumpTest(LabelHolder::LabelId id,Reg src,Imm imm,Condition cc)230 void Aarch32Encoder::EncodeJumpTest(LabelHolder::LabelId id, Reg src, Imm imm, Condition cc)
231 {
232     ASSERT(src.IsScalar());
233 
234     TestImmHelper(src, imm, cc);
235     auto label = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(id);
236     GetMasm()->B(ConvertTest(cc), label);
237 }
238 
CompareZeroHelper(Reg src,Condition * cc)239 void Aarch32Encoder::CompareZeroHelper(Reg src, Condition *cc)
240 {
241     ASSERT(src.IsScalar());
242     if (src.GetSize() <= WORD_SIZE) {
243         GetMasm()->Cmp(VixlReg(src), vixl::aarch32::Operand(0x0));
244     } else {
245         ScopedTmpRegU32 tmpReg(this);
246         uint32_t imm = 0x0;
247 
248         switch (*cc) {
249             case Condition::EQ:
250             case Condition::NE:
251                 GetMasm()->Orrs(VixlReg(tmpReg), VixlReg(src), VixlRegU(src));
252                 break;
253             case Condition::LE:
254                 imm = 0x1;
255                 *cc = Condition::LT;
256                 /* fallthrough */
257                 [[fallthrough]];
258             case Condition::LT:
259                 GetMasm()->Cmp(VixlReg(src), vixl::aarch32::Operand(imm));
260                 GetMasm()->Sbcs(VixlReg(tmpReg), VixlRegU(src), vixl::aarch32::Operand(0x0));
261                 break;
262             case Condition::GT:
263                 imm = 0x1;
264                 *cc = Condition::GE;
265                 /* fallthrough */
266                 [[fallthrough]];
267             case Condition::GE:
268                 GetMasm()->Cmp(VixlReg(src), vixl::aarch32::Operand(imm));
269                 GetMasm()->Sbcs(VixlReg(tmpReg), VixlRegU(src), vixl::aarch32::Operand(0x0));
270                 break;
271             default:
272                 UNREACHABLE();
273         }
274     }
275 }
276 
EncodeJump(LabelHolder::LabelId id,Reg src,Condition cc)277 void Aarch32Encoder::EncodeJump(LabelHolder::LabelId id, Reg src, Condition cc)
278 {
279     auto label = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(id);
280     ASSERT(src.IsScalar());
281 
282     switch (cc) {
283         case Condition::LO:
284             // LO is always false
285             return;
286         case Condition::HS:
287             // HS is always true
288             GetMasm()->B(label);
289             return;
290         case Condition::LS:
291             // LS is same as EQ
292             cc = Condition::EQ;
293             break;
294         case Condition::HI:
295             // HI is same as NE
296             cc = Condition::NE;
297             break;
298         default:
299             break;
300     }
301 
302     CompareZeroHelper(src, &cc);
303 
304     GetMasm()->B(Convert(cc), label);
305 }
306 
EncodeJump(Reg dst)307 void Aarch32Encoder::EncodeJump(Reg dst)
308 {
309     GetMasm()->Bx(VixlReg(dst));
310 }
311 
EncodeJump(RelocationInfo * relocation)312 void Aarch32Encoder::EncodeJump([[maybe_unused]] RelocationInfo *relocation)
313 {
314 #ifdef PANDA_TARGET_MACOS
315     LOG(FATAL, COMPILER) << "Not supported in Macos build";
316 #else
317     auto buffer = GetMasm()->GetBuffer();
318     relocation->offset = GetCursorOffset();
319     relocation->addend = 0;
320     relocation->type = R_ARM_CALL;
321     static constexpr uint32_t CALL_WITH_ZERO_OFFSET = 0xeafffffe;
322     buffer->Emit32(CALL_WITH_ZERO_OFFSET);
323 #endif
324 }
325 
EncodeNop()326 void Aarch32Encoder::EncodeNop()
327 {
328     GetMasm()->Nop();
329 }
330 
MakeCall(compiler::RelocationInfo * relocation)331 void Aarch32Encoder::MakeCall([[maybe_unused]] compiler::RelocationInfo *relocation)
332 {
333 #ifdef PANDA_TARGET_MACOS
334     LOG(FATAL, COMPILER) << "Not supported in Macos build";
335 #else
336     auto buffer = GetMasm()->GetBuffer();
337     relocation->offset = GetCursorOffset();
338     relocation->addend = 0;
339     relocation->type = R_ARM_CALL;
340     static constexpr uint32_t CALL_WITH_ZERO_OFFSET = 0xebfffffe;
341     buffer->Emit32(CALL_WITH_ZERO_OFFSET);
342 #endif
343 }
344 
MakeCall(const void * entryPoint)345 void Aarch32Encoder::MakeCall(const void *entryPoint)
346 {
347     ScopedTmpRegU32 tmpReg(this);
348 
349     auto entry = static_cast<int32_t>(reinterpret_cast<int64_t>(entryPoint));
350     EncodeMov(tmpReg, Imm(entry));
351     GetMasm()->Blx(VixlReg(tmpReg));
352 }
353 
MakeCall(MemRef entryPoint)354 void Aarch32Encoder::MakeCall(MemRef entryPoint)
355 {
356     ScopedTmpRegU32 tmpReg(this);
357 
358     EncodeLdr(tmpReg, false, entryPoint);
359     GetMasm()->Blx(VixlReg(tmpReg));
360 }
361 
MakeCall(Reg reg)362 void Aarch32Encoder::MakeCall(Reg reg)
363 {
364     GetMasm()->Blx(VixlReg(reg));
365 }
366 
MakeCallAot(intptr_t offset)367 void Aarch32Encoder::MakeCallAot([[maybe_unused]] intptr_t offset)
368 {
369     // Unimplemented
370     SetFalseResult();
371 }
372 
MakeCallByOffset(intptr_t offset)373 void Aarch32Encoder::MakeCallByOffset([[maybe_unused]] intptr_t offset)
374 {
375     // Unimplemented
376     SetFalseResult();
377 }
378 
MakeLoadAotTable(intptr_t offset,Reg reg)379 void Aarch32Encoder::MakeLoadAotTable([[maybe_unused]] intptr_t offset, [[maybe_unused]] Reg reg)
380 {
381     // Unimplemented
382     SetFalseResult();
383 }
384 
MakeLoadAotTableAddr(intptr_t offset,Reg addr,Reg val)385 void Aarch32Encoder::MakeLoadAotTableAddr([[maybe_unused]] intptr_t offset, [[maybe_unused]] Reg addr,
386                                           [[maybe_unused]] Reg val)
387 {
388     // Unimplemented
389     SetFalseResult();
390 }
391 
EncodeReturn()392 void Aarch32Encoder::EncodeReturn()
393 {
394     GetMasm()->Bx(vixl::aarch32::lr);
395 }
396 
EncodeAbort()397 void Aarch32Encoder::EncodeAbort()
398 {
399     GetMasm()->Udf(0);
400 }
401 
EncodeMul(Reg dst,Reg src,Imm imm)402 void Aarch32Encoder::EncodeMul([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src, [[maybe_unused]] Imm imm)
403 {
404     SetFalseResult();
405 }
406 
407 /* static */
IsNeedToPrepareMemLdS(MemRef mem,const TypeInfo & memType,bool isSigned)408 bool Aarch32Encoder::IsNeedToPrepareMemLdS(MemRef mem, const TypeInfo &memType, bool isSigned)
409 {
410     bool hasIndex = mem.HasIndex();
411     bool hasShift = mem.HasScale();
412     bool hasOffset = mem.HasDisp();
413     ASSERT(mem.HasBase());
414     // VLDR and VSTR has base and offset. The offset must be a multiple of 4, and lie in the range -1020 to +1020.
415     if (memType.IsFloat()) {
416         if (hasIndex) {
417             return true;
418         }
419         if (hasOffset) {
420             auto offset = mem.GetDisp();
421             constexpr int32_t IMM_4 = 4;
422             if (!((offset >= -VMEM_OFFSET) && (offset <= VMEM_OFFSET) && ((offset % IMM_4) == 0))) {
423                 return true;
424             }
425         }
426         return false;
427     }
428     int32_t maxOffset = MEM_SMALL_OFFSET;
429     bool hasLsl = false;
430     if (!isSigned && (memType == INT32_TYPE || memType == INT8_TYPE)) {
431         hasLsl = true;
432         maxOffset = MEM_BIG_OFFSET;
433     }
434     // LDR/STR with register offset(for A32)
435     // |  mem type  |    shift    |
436     // | ---------- | ----------- |
437     // |word or byte|    0 to 31  |
438     // |   others   |      --     |
439     //
440     if (hasIndex) {
441         // MemRef with index and offser isn't supported
442         ASSERT(!hasOffset);
443         if (hasShift) {
444             ASSERT(mem.GetScale() != 0);
445             [[maybe_unused]] constexpr int32_t MAX_SHIFT = 3;
446             ASSERT(mem.GetScale() <= MAX_SHIFT);
447             if (!hasLsl) {
448                 return true;
449             }
450         }
451         return false;
452     }
453     // LDR/STR with immediate offset(for A32)
454     // |  mem type  | offset size |
455     // | ---------- | ----------- |
456     // |word or byte|-4095 to 4095|
457     // |   others   | -255 to 255 |
458     //
459     if (hasOffset) {
460         ASSERT(mem.GetDisp() != 0);
461         [[maybe_unused]] auto offset = mem.GetDisp();
462         if (!((offset >= -maxOffset) && (offset <= maxOffset))) {
463             return true;
464         }
465     }
466     return false;
467 }
468 
469 /**
470  * The function construct additional instruction for encode memory instructions and returns MemOperand for ldr/str
471  * LDR/STR with immediate offset(for A32)
472  * |  mem type  | offset size |
473  * | ---------- | ----------- |
474  * |word or byte|-4095 to 4095|
475  * |   others   | -255 to 255 |
476  *
477  * LDR/STR with register offset(for A32)
478  * |  mem type  |    shift    |
479  * | ---------- | ----------- |
480  * |word or byte|    0 to 31  |
481  * |   others   |      --     |
482  *
483  * VLDR and VSTR has base and offset. The offset must be a multiple of 4, and lie in the range -1020 to +1020.
484  */
PrepareMemLdS(MemRef mem,const TypeInfo & memType,vixl::aarch32::Register tmp,bool isSigned,bool copySp)485 vixl::aarch32::MemOperand Aarch32Encoder::PrepareMemLdS(MemRef mem, const TypeInfo &memType,
486                                                         vixl::aarch32::Register tmp, bool isSigned, bool copySp)
487 {
488     bool hasIndex = mem.HasIndex();
489     bool hasShift = mem.HasScale();
490     bool hasOffset = mem.HasDisp();
491     ASSERT(mem.HasBase());
492     auto baseReg = VixlReg(mem.GetBase());
493     if (copySp) {
494         if (baseReg.IsSP()) {
495             GetMasm()->Mov(tmp, baseReg);
496             baseReg = tmp;
497         }
498     }
499     // VLDR and VSTR has base and offset. The offset must be a multiple of 4, and lie in the range -1020 to +1020.
500     if (memType.IsFloat()) {
501         return PrepareMemLdSForFloat(mem, tmp);
502     }
503     int32_t maxOffset = MEM_SMALL_OFFSET;
504     bool hasLsl = false;
505     if (!isSigned && (memType == INT32_TYPE || memType == INT8_TYPE)) {
506         hasLsl = true;
507         maxOffset = MEM_BIG_OFFSET;
508     }
509     // LDR/STR with register offset(for A32)
510     // |  mem type  |    shift    |
511     // | ---------- | ----------- |
512     // |word or byte|    0 to 31  |
513     // |   others   |      --     |
514     //
515     if (hasIndex) {
516         // MemRef with index and offser isn't supported
517         ASSERT(!hasOffset);
518         auto indexReg = mem.GetIndex();
519         if (hasShift) {
520             ASSERT(mem.GetScale() != 0);
521             auto shift = mem.GetScale();
522             [[maybe_unused]] constexpr int32_t MAX_SHIFT = 3;
523             ASSERT(mem.GetScale() <= MAX_SHIFT);
524             if (hasLsl) {
525                 return vixl::aarch32::MemOperand(baseReg, VixlReg(indexReg), vixl::aarch32::LSL, shift);
526             }
527             // from:
528             //   mem: base, index, scale
529             // to:
530             //   add tmp, base, index, scale
531             //   mem tmp
532             GetMasm()->Add(tmp, baseReg, vixl::aarch32::Operand(VixlReg(indexReg), vixl::aarch32::LSL, shift));
533             return vixl::aarch32::MemOperand(tmp);
534         }
535         return vixl::aarch32::MemOperand(baseReg, VixlReg(indexReg));
536     }
537     // LDR/STR with immediate offset(for A32):
538     // |  mem type  | offset size |
539     // | ---------- | ----------- |
540     // |word or byte|-4095 to 4095|
541     // |   others   | -255 to 255 |
542     //
543     if (hasOffset) {
544         ASSERT(mem.GetDisp() != 0);
545         auto offset = mem.GetDisp();
546         if ((offset >= -maxOffset) && (offset <= maxOffset)) {
547             return vixl::aarch32::MemOperand(baseReg, offset);
548         }
549         // from:
550         //   mem: base, offset
551         // to:
552         //   add tmp, base, offset
553         //   mem tmp
554         GetMasm()->Add(tmp, baseReg, VixlImm(offset));
555         baseReg = tmp;
556     }
557     return vixl::aarch32::MemOperand(baseReg);
558 }
559 
PrepareMemLdSForFloat(MemRef mem,vixl::aarch32::Register tmp)560 vixl::aarch32::MemOperand Aarch32Encoder::PrepareMemLdSForFloat(MemRef mem, vixl::aarch32::Register tmp)
561 {
562     bool hasIndex = mem.HasIndex();
563     bool hasShift = mem.HasScale();
564     bool hasOffset = mem.HasDisp();
565     auto baseReg = VixlReg(mem.GetBase());
566     if (hasIndex) {
567         auto indexReg = mem.GetIndex();
568         auto scale = mem.GetScale();
569         // from:
570         //   vmem: base, index, scale, offset
571         // to:
572         //   add tmp, base, index, scale
573         //   vmem tmp, offset
574         if (hasShift) {
575             ASSERT(scale != 0);
576             [[maybe_unused]] constexpr int32_t MAX_SHIFT = 3;
577             ASSERT(scale > 0 && scale <= MAX_SHIFT);
578             GetMasm()->Add(tmp, baseReg, vixl::aarch32::Operand(VixlReg(indexReg), vixl::aarch32::LSL, scale));
579         } else {
580             ASSERT(scale == 0);
581             GetMasm()->Add(tmp, baseReg, VixlReg(indexReg));
582         }
583         baseReg = tmp;
584     }
585     if (hasOffset) {
586         ASSERT(mem.GetDisp() != 0);
587         auto offset = mem.GetDisp();
588         constexpr int32_t IMM_4 = 4;
589         if ((offset >= -VMEM_OFFSET) && (offset <= VMEM_OFFSET) && ((offset % IMM_4) == 0)) {
590             return vixl::aarch32::MemOperand(baseReg, offset);
591         }
592         // from:
593         //   vmem: base, offset
594         // to:
595         //   add tmp, base, offset
596         //   vmem tmp
597         GetMasm()->Add(tmp, baseReg, VixlImm(offset));
598         baseReg = tmp;
599     }
600     return vixl::aarch32::MemOperand(baseReg);
601 }
602 
EncodeFpToBits(Reg dst,Reg src)603 void Aarch32Encoder::EncodeFpToBits(Reg dst, Reg src)
604 {
605     ASSERT(dst.IsScalar() && src.IsFloat());
606     if (dst.GetSize() == WORD_SIZE) {
607         ASSERT(src.GetSize() == WORD_SIZE);
608 
609         constexpr uint32_t NANF = 0x7fc00000U;
610 
611         GetMasm()->Vcmp(VixlVReg(src), VixlVReg(src));
612         GetMasm()->Vmrs(vixl::aarch32::RegisterOrAPSR_nzcv(vixl::aarch32::kPcCode), vixl::aarch32::FPSCR);
613         GetMasm()->Vmov(VixlReg(dst), VixlVReg(src).S());
614         GetMasm()->Mov(Convert(Condition::NE), VixlReg(dst), VixlImm(NANF));
615     } else {
616         ASSERT(src.GetSize() == DOUBLE_WORD_SIZE);
617 
618         constexpr uint32_t NAND_HIGH = 0x7ff80000U;
619 
620         GetMasm()->Vcmp(VixlVReg(src), VixlVReg(src));
621         GetMasm()->Vmrs(vixl::aarch32::RegisterOrAPSR_nzcv(vixl::aarch32::kPcCode), vixl::aarch32::FPSCR);
622         GetMasm()->Vmov(VixlReg(dst), VixlRegU(dst), VixlVReg(src).D());
623         GetMasm()->Mov(Convert(Condition::NE), VixlReg(dst), VixlImm(0));
624         GetMasm()->Mov(Convert(Condition::NE), VixlRegU(dst), VixlImm(NAND_HIGH));
625     }
626 }
627 
EncodeMoveBitsRaw(Reg dst,Reg src)628 void Aarch32Encoder::EncodeMoveBitsRaw(Reg dst, Reg src)
629 {
630     ASSERT((dst.IsFloat() && src.IsScalar()) || (src.IsFloat() && dst.IsScalar()));
631     if (dst.IsScalar()) {
632         ASSERT(src.GetSize() == dst.GetSize());
633         if (dst.GetSize() == WORD_SIZE) {
634             GetMasm()->Vmov(VixlReg(dst), VixlVReg(src).S());
635         } else {
636             GetMasm()->Vmov(VixlReg(dst), VixlRegU(dst), VixlVReg(src).D());
637         }
638     } else {
639         ASSERT(dst.GetSize() == src.GetSize());
640         if (src.GetSize() == WORD_SIZE) {
641             GetMasm()->Vmov(VixlVReg(dst).S(), VixlReg(src));
642         } else {
643             GetMasm()->Vmov(VixlVReg(dst).D(), VixlReg(src), VixlRegU(src));
644         }
645     }
646 }
EncodeMov(Reg dst,Reg src)647 void Aarch32Encoder::EncodeMov(Reg dst, Reg src)
648 {
649     if (src.GetSize() <= WORD_SIZE && dst.GetSize() == DOUBLE_WORD_SIZE && !src.IsFloat() && !dst.IsFloat()) {
650         SetFalseResult();
651         return;
652     }
653     if (dst == src) {
654         return;
655     }
656     if (dst.IsFloat()) {
657         if (src.GetType().IsScalar()) {
658             if (src.GetSize() == DOUBLE_WORD_SIZE) {
659                 GetMasm()->Vmov(VixlVReg(dst).D(), VixlReg(src), VixlRegU(src));
660                 return;
661             }
662             GetMasm()->Vmov(VixlVReg(dst).S(), VixlReg(src));
663             return;
664         }
665         if (dst.GetSize() == WORD_SIZE) {
666             GetMasm()->Vmov(VixlVReg(dst).S(), VixlVReg(src));
667         } else {
668             GetMasm()->Vmov(VixlVReg(dst).D(), VixlVReg(src));
669         }
670         return;
671     }
672     ASSERT(dst.IsScalar());
673     if (src.IsFloat()) {
674         if (src.GetSize() == DOUBLE_WORD_SIZE) {
675             GetMasm()->Vmov(VixlReg(dst), VixlRegU(dst), VixlVReg(src).D());
676             return;
677         }
678         GetMasm()->Vmov(VixlReg(dst), VixlVReg(src).S());
679         return;
680     }
681     ASSERT(src.IsScalar());
682     GetMasm()->Mov(VixlReg(dst), VixlReg(src));
683     if (dst.GetSize() > WORD_SIZE) {
684         GetMasm()->Mov(VixlRegU(dst), VixlRegU(src));
685     }
686 }
687 
EncodeNeg(Reg dst,Reg src)688 void Aarch32Encoder::EncodeNeg(Reg dst, Reg src)
689 {
690     if (dst.IsFloat()) {
691         GetMasm()->Vneg(VixlVReg(dst), VixlVReg(src));
692         return;
693     }
694 
695     if (dst.GetSize() <= WORD_SIZE) {
696         GetMasm()->Rsb(VixlReg(dst), VixlReg(src), VixlImm(0x0));
697         return;
698     }
699 
700     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
701     GetMasm()->Rsbs(VixlReg(dst), VixlReg(src), VixlImm(0x0));
702     GetMasm()->Rsc(VixlRegU(dst), VixlRegU(src), VixlImm(0x0));
703 }
704 
EncodeAbs(Reg dst,Reg src)705 void Aarch32Encoder::EncodeAbs(Reg dst, Reg src)
706 {
707     if (dst.IsFloat()) {
708         GetMasm()->Vabs(VixlVReg(dst), VixlVReg(src));
709         return;
710     }
711 
712     if (dst.GetSize() <= WORD_SIZE) {
713         GetMasm()->Cmp(VixlReg(src), VixlImm(0x0));
714         GetMasm()->Rsb(Convert(Condition::MI), VixlReg(dst), VixlReg(src), VixlImm(0x0));
715         GetMasm()->Mov(Convert(Condition::PL), VixlReg(dst), VixlReg(src));
716         return;
717     }
718 
719     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
720     ScopedTmpRegU32 loReg(this);
721     ScopedTmpRegU32 hiReg(this);
722 
723     GetMasm()->Rsbs(VixlReg(loReg), VixlReg(src), VixlImm(0x0));
724     GetMasm()->Rsc(VixlReg(hiReg), VixlRegU(src), VixlImm(0x0));
725     GetMasm()->Cmp(VixlRegU(src), VixlImm(0x0));
726     GetMasm()->Mov(Convert(Condition::PL), VixlReg(loReg), VixlReg(src));
727     GetMasm()->Mov(Convert(Condition::PL), VixlReg(hiReg), VixlRegU(src));
728 
729     GetMasm()->Mov(VixlReg(dst), VixlReg(loReg));
730     GetMasm()->Mov(VixlRegU(dst), VixlReg(hiReg));
731 }
732 
EncodeSqrt(Reg dst,Reg src)733 void Aarch32Encoder::EncodeSqrt(Reg dst, Reg src)
734 {
735     ASSERT(dst.IsFloat());
736     GetMasm()->Vsqrt(VixlVReg(dst), VixlVReg(src));
737 }
738 
EncodeNot(Reg dst,Reg src)739 void Aarch32Encoder::EncodeNot([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
740 {
741     GetMasm()->Mvn(VixlReg(dst), VixlReg(src));
742     if (dst.GetSize() > WORD_SIZE) {
743         GetMasm()->Mvn(VixlRegU(dst), VixlRegU(src));
744     }
745 }
746 
EncodeIsInf(Reg dst,Reg src)747 void Aarch32Encoder::EncodeIsInf(Reg dst, Reg src)
748 {
749     ASSERT(dst.IsScalar() && src.IsFloat());
750 
751     if (src.GetSize() == WORD_SIZE) {
752         constexpr uint32_t INF_MASK = 0xff000000;
753 
754         ScopedTmpRegU32 tmp(this);
755 
756         GetMasm()->Vmov(VixlReg(tmp), VixlVReg(src).S());
757         GetMasm()->Lsl(VixlReg(tmp), VixlReg(tmp), 1); /* 0xff000000 if Infinity */
758         GetMasm()->Mov(VixlReg(dst), INF_MASK);
759         GetMasm()->Cmp(VixlReg(dst), VixlReg(tmp));
760     } else {
761         constexpr uint32_t INF_MASK = 0xffe00000;
762 
763         ScopedTmpRegU32 tmp(this);
764         ScopedTmpRegU32 tmp1(this);
765 
766         GetMasm()->Vmov(VixlReg(tmp), VixlReg(tmp1), VixlVReg(src).D());
767         GetMasm()->Lsl(VixlReg(tmp1), VixlReg(tmp1), 1); /* 0xffe00000 if Infinity */
768         GetMasm()->Mov(VixlReg(dst), INF_MASK);
769         GetMasm()->Cmp(VixlReg(dst), VixlReg(tmp1));
770     }
771 
772     GetMasm()->Mov(VixlReg(dst), VixlImm(0));
773     GetMasm()->Mov(Convert(Condition::EQ), VixlReg(dst), VixlImm(1));
774 }
775 
EncodeCmpFracWithDelta(Reg src)776 void Aarch32Encoder::EncodeCmpFracWithDelta(Reg src)
777 {
778     ASSERT(src.IsFloat());
779     ASSERT(src.GetSize() == WORD_SIZE || src.GetSize() == DOUBLE_WORD_SIZE);
780 
781     // Encode (fabs(src - trunc(src)) <= DELTA)
782     if (src.GetSize() == WORD_SIZE) {
783         ScopedTmpRegF32 tmp(this);
784         vixl::aarch32::SRegister tmp1(tmp.GetReg().GetId() + 1);
785         GetMasm()->Vrintz(VixlVReg(tmp).S(), VixlVReg(src).S());
786         EncodeSub(tmp, src, tmp);
787         EncodeAbs(tmp, tmp);
788         GetMasm()->Vmov(tmp1, std::numeric_limits<float>::epsilon());
789         GetMasm()->Vcmp(VixlVReg(tmp).S(), tmp1);
790     } else {
791         ScopedTmpRegF64 tmp(this);
792         vixl::aarch32::DRegister tmp1(tmp.GetReg().GetId() + 1);
793         GetMasm()->Vrintz(VixlVReg(tmp).D(), VixlVReg(src).D());
794         EncodeSub(tmp, src, tmp);
795         EncodeAbs(tmp, tmp);
796         GetMasm()->Vmov(tmp1, std::numeric_limits<double>::epsilon());
797         GetMasm()->Vcmp(VixlVReg(tmp).D(), tmp1);
798     }
799     GetMasm()->Vmrs(vixl::aarch32::RegisterOrAPSR_nzcv(vixl::aarch32::kPcCode), vixl::aarch32::FPSCR);
800 }
801 
EncodeIsInteger(Reg dst,Reg src)802 void Aarch32Encoder::EncodeIsInteger(Reg dst, Reg src)
803 {
804     ASSERT(dst.IsScalar() && src.IsFloat());
805     ASSERT(src.GetSize() == WORD_SIZE || src.GetSize() == DOUBLE_WORD_SIZE);
806 
807     auto labelExit = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(CreateLabel());
808     auto labelInfOrNan = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(CreateLabel());
809 
810     EncodeCmpFracWithDelta(src);
811     GetMasm()->B(vixl::aarch32::vs, labelInfOrNan);  // Inf or NaN
812     GetMasm()->Mov(vixl::aarch32::le, VixlReg(dst), 0x1);
813     GetMasm()->Mov(vixl::aarch32::gt, VixlReg(dst), 0x0);
814     GetMasm()->B(labelExit);
815 
816     // IsInteger returns false if src is Inf or NaN
817     GetMasm()->Bind(labelInfOrNan);
818     EncodeMov(dst, Imm(false));
819 
820     GetMasm()->Bind(labelExit);
821 }
822 
EncodeIsSafeInteger(Reg dst,Reg src)823 void Aarch32Encoder::EncodeIsSafeInteger(Reg dst, Reg src)
824 {
825     ASSERT(dst.IsScalar() && src.IsFloat());
826     ASSERT(src.GetSize() == WORD_SIZE || src.GetSize() == DOUBLE_WORD_SIZE);
827 
828     auto labelExit = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(CreateLabel());
829     auto labelFalse = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(CreateLabel());
830 
831     // Check if IsInteger
832     EncodeCmpFracWithDelta(src);
833     GetMasm()->B(vixl::aarch32::vs, labelFalse);  // Inf or NaN
834     GetMasm()->B(vixl::aarch32::gt, labelFalse);
835 
836     // Check if it is safe, i.e. src can be represented in float/double without losing precision
837     if (src.GetSize() == WORD_SIZE) {
838         ScopedTmpRegF32 tmp1(this);
839         vixl::aarch32::SRegister tmp2(tmp1.GetReg().GetId() + 1);
840         EncodeAbs(tmp1, src);
841         GetMasm()->Vmov(tmp2, MaxIntAsExactFloat());
842         GetMasm()->Vcmp(VixlVReg(tmp1).S(), tmp2);
843     } else {
844         ScopedTmpRegF64 tmp1(this);
845         vixl::aarch32::DRegister tmp2(tmp1.GetReg().GetId() + 1);
846         EncodeAbs(tmp1, src);
847         GetMasm()->Vmov(tmp2, MaxIntAsExactDouble());
848         GetMasm()->Vcmp(VixlVReg(tmp1).D(), tmp2);
849     }
850     GetMasm()->Vmrs(vixl::aarch32::RegisterOrAPSR_nzcv(vixl::aarch32::kPcCode), vixl::aarch32::FPSCR);
851     GetMasm()->Mov(vixl::aarch32::le, VixlReg(dst), 0x1);
852     GetMasm()->Mov(vixl::aarch32::gt, VixlReg(dst), 0x0);
853     GetMasm()->B(labelExit);
854 
855     // Return false if src !IsInteger
856     GetMasm()->Bind(labelFalse);
857     EncodeMov(dst, Imm(false));
858 
859     GetMasm()->Bind(labelExit);
860 }
861 
EncodeReverseBytes(Reg dst,Reg src)862 void Aarch32Encoder::EncodeReverseBytes(Reg dst, Reg src)
863 {
864     ASSERT(src.GetSize() > BYTE_SIZE);
865     ASSERT(src.GetSize() == dst.GetSize());
866 
867     if (src.GetSize() == HALF_SIZE) {
868         GetMasm()->Rev16(VixlReg(dst), VixlReg(src));
869         GetMasm()->Sxth(VixlReg(dst), VixlReg(dst));
870     } else if (src.GetSize() == WORD_SIZE) {
871         GetMasm()->Rev(VixlReg(dst), VixlReg(src));
872     } else {
873         if (src == dst) {
874             ScopedTmpRegU32 tmpReg(this);
875             GetMasm()->Mov(VixlReg(tmpReg), VixlReg(src));
876             GetMasm()->Rev(VixlReg(dst), VixlRegU(src));
877             GetMasm()->Rev(VixlRegU(dst), VixlReg(tmpReg));
878         } else {
879             GetMasm()->Rev(VixlRegU(dst), VixlReg(src));
880             GetMasm()->Rev(VixlReg(dst), VixlRegU(src));
881         }
882     }
883 }
884 
EncodeBitCount(Reg dst,Reg src)885 void Aarch32Encoder::EncodeBitCount([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
886 {
887     SetFalseResult();
888 }
889 
EncodeCountLeadingZeroBits(Reg dst,Reg src)890 void Aarch32Encoder::EncodeCountLeadingZeroBits(Reg dst, Reg src)
891 {
892     ASSERT(src.GetSize() == WORD_SIZE || src.GetSize() == DOUBLE_WORD_SIZE);
893     if (src.GetSize() == WORD_SIZE) {
894         GetMasm()->Clz(VixlReg(dst), VixlReg(src));
895         return;
896     }
897 
898     auto low = CreateLabel();
899     auto end = CreateLabel();
900     auto highBits = Reg(src.GetId() + 1, INT32_TYPE);
901     EncodeJump(low, highBits, Condition::EQ);
902     GetMasm()->Clz(VixlReg(dst), VixlReg(highBits));
903     EncodeJump(end);
904 
905     BindLabel(low);
906     GetMasm()->Clz(VixlReg(dst), VixlReg(src));
907     GetMasm()->Adds(VixlReg(dst), VixlReg(dst), VixlImm(WORD_SIZE));
908 
909     BindLabel(end);
910 }
911 
EncodeCeil(Reg dst,Reg src)912 void Aarch32Encoder::EncodeCeil(Reg dst, Reg src)
913 {
914     GetMasm()->Vrintp(VixlVReg(dst), VixlVReg(src));
915 }
916 
EncodeFloor(Reg dst,Reg src)917 void Aarch32Encoder::EncodeFloor(Reg dst, Reg src)
918 {
919     GetMasm()->Vrintm(VixlVReg(dst), VixlVReg(src));
920 }
921 
EncodeRint(Reg dst,Reg src)922 void Aarch32Encoder::EncodeRint(Reg dst, Reg src)
923 {
924     GetMasm()->Vrintn(VixlVReg(dst), VixlVReg(src));
925 }
926 
EncodeTrunc(Reg dst,Reg src)927 void Aarch32Encoder::EncodeTrunc(Reg dst, Reg src)
928 {
929     GetMasm()->Vrintz(VixlVReg(dst), VixlVReg(src));
930 }
931 
EncodeRoundAway(Reg dst,Reg src)932 void Aarch32Encoder::EncodeRoundAway(Reg dst, Reg src)
933 {
934     GetMasm()->Vrinta(VixlVReg(dst), VixlVReg(src));
935 }
936 
EncodeRoundToPInf(Reg dst,Reg src)937 void Aarch32Encoder::EncodeRoundToPInf(Reg dst, Reg src)
938 {
939     ScopedTmpRegF64 temp(this);
940     vixl::aarch32::SRegister temp1(temp.GetReg().GetId());
941     vixl::aarch32::SRegister temp2(temp.GetReg().GetId() + 1);
942 
943     auto done = CreateLabel();
944     // round to nearest integer, ties away from zero
945     GetMasm()->Vcvta(vixl::aarch32::DataTypeValue::S32, vixl::aarch32::DataTypeValue::F32, temp1, VixlVReg(src).S());
946     GetMasm()->Vmov(VixlReg(dst), temp1);
947     // for positive, zero and NaN inputs, rounding is done
948     GetMasm()->Cmp(VixlReg(dst), 0);
949     GetMasm()->B(vixl::aarch32::ge, static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(done));
950     // if input is negative but not a tie, round to nearest is valid.
951     // if input is a negative tie, change rounding direction to positive infinity, dst += 1.
952     GetMasm()->Vrinta(vixl::aarch32::DataTypeValue::F32, temp1, VixlVReg(src).S());
953     // NOLINTNEXTLINE(readability-magic-numbers)
954     GetMasm()->Vmov(temp2, 0.5F);
955     GetMasm()->Vsub(vixl::aarch32::DataTypeValue::F32, temp1, VixlVReg(src).S(), temp1);
956     GetMasm()->Vcmp(vixl::aarch32::DataTypeValue::F32, temp1, temp2);
957     GetMasm()->Vmrs(vixl::aarch32::RegisterOrAPSR_nzcv(vixl::aarch32::kPcCode), vixl::aarch32::FPSCR);
958     GetMasm()->add(vixl::aarch32::eq, VixlReg(dst), VixlReg(dst), 1);
959 
960     BindLabel(done);
961 }
962 
EncodeReverseBits(Reg dst,Reg src)963 void Aarch32Encoder::EncodeReverseBits(Reg dst, Reg src)
964 {
965     ASSERT(src.GetSize() == WORD_SIZE || src.GetSize() == DOUBLE_WORD_SIZE);
966     ASSERT(src.GetSize() == dst.GetSize());
967 
968     if (src.GetSize() == WORD_SIZE) {
969         GetMasm()->Rbit(VixlReg(dst), VixlReg(src));
970         return;
971     }
972 
973     if (src == dst) {
974         ScopedTmpRegU32 tmpReg(this);
975         GetMasm()->Mov(VixlReg(tmpReg), VixlReg(src));
976         GetMasm()->Rbit(VixlReg(dst), VixlRegU(src));
977         GetMasm()->Rbit(VixlRegU(dst), VixlReg(tmpReg));
978         return;
979     }
980 
981     GetMasm()->Rbit(VixlRegU(dst), VixlReg(src));
982     GetMasm()->Rbit(VixlReg(dst), VixlRegU(src));
983 }
984 
EncodeCastToBool(Reg dst,Reg src)985 void Aarch32Encoder::EncodeCastToBool(Reg dst, Reg src)
986 {
987     // In ISA says that we only support casts:
988     // i32tou1, i64tou1, u32tou1, u64tou1
989     ASSERT(src.IsScalar());
990     ASSERT(dst.IsScalar());
991 
992     GetMasm()->Cmp(VixlReg(src), VixlImm(0x0));
993     GetMasm()->Mov(Convert(Condition::EQ), VixlReg(dst), VixlImm(0x0));
994     GetMasm()->Mov(Convert(Condition::NE), VixlReg(dst), VixlImm(0x1));
995     if (src.GetSize() == DOUBLE_WORD_SIZE) {
996         GetMasm()->Cmp(VixlRegU(src), VixlImm(0x0));
997         GetMasm()->Mov(Convert(Condition::NE), VixlReg(dst), VixlImm(0x1));
998     }
999 }
1000 
EncodeCast(Reg dst,bool dstSigned,Reg src,bool srcSigned)1001 void Aarch32Encoder::EncodeCast(Reg dst, bool dstSigned, Reg src, bool srcSigned)
1002 {
1003     // float/double -> float/double
1004     if (dst.IsFloat() && src.IsFloat()) {
1005         EncodeCastFloatToFloat(dst, src);
1006         return;
1007     }
1008 
1009     // uint/int -> float/double
1010     if (dst.IsFloat() && src.IsScalar()) {
1011         EncodeCastScalarToFloat(dst, src, srcSigned);
1012         return;
1013     }
1014 
1015     // float/double -> uint/int
1016     if (dst.IsScalar() && src.IsFloat()) {
1017         EncodeCastFloatToScalar(dst, dstSigned, src);
1018         return;
1019     }
1020 
1021     // uint/int -> uint/int
1022     ASSERT(dst.IsScalar() && src.IsScalar());
1023     EncodeCastScalar(dst, dstSigned, src, srcSigned);
1024 }
1025 
EncodeCastScalar(Reg dst,bool dstSigned,Reg src,bool srcSigned)1026 void Aarch32Encoder::EncodeCastScalar(Reg dst, bool dstSigned, Reg src, bool srcSigned)
1027 {
1028     size_t srcSize = src.GetSize();
1029     size_t dstSize = dst.GetSize();
1030     // In our ISA minimal type is 32-bit, so type less then 32-bit
1031     // we should extend to 32-bit. So we can have 2 cast
1032     // (For examble, i8->u16 will work as i8->u16 and u16->u32)
1033     if (dstSize < WORD_SIZE) {
1034         if (srcSize > dstSize) {
1035             if (dstSigned) {
1036                 EncodeCastScalarFromSignedScalar(dst, src);
1037             } else {
1038                 EncodeCastScalarFromUnsignedScalar(dst, src);
1039             }
1040             return;
1041         }
1042         if (srcSize == dstSize) {
1043             GetMasm()->Mov(VixlReg(dst), VixlReg(src));
1044             if (srcSigned == dstSigned) {
1045                 return;
1046             }
1047             if (dstSigned) {
1048                 EncodeCastScalarFromSignedScalar(Reg(dst.GetId(), INT32_TYPE), dst);
1049             } else {
1050                 EncodeCastScalarFromUnsignedScalar(Reg(dst.GetId(), INT32_TYPE), dst);
1051             }
1052             return;
1053         }
1054         if (srcSigned) {
1055             EncodeCastScalarFromSignedScalar(dst, src);
1056             if (!dstSigned) {
1057                 EncodeCastScalarFromUnsignedScalar(Reg(dst.GetId(), INT32_TYPE), dst);
1058             }
1059         } else {
1060             EncodeCastScalarFromUnsignedScalar(dst, src);
1061             if (dstSigned) {
1062                 EncodeCastScalarFromSignedScalar(Reg(dst.GetId(), INT32_TYPE), dst);
1063             }
1064         }
1065     } else {
1066         if (srcSize == dstSize) {
1067             GetMasm()->Mov(VixlReg(dst), VixlReg(src));
1068             if (srcSize == DOUBLE_WORD_SIZE) {
1069                 GetMasm()->Mov(VixlRegU(dst), VixlRegU(src));
1070             }
1071             return;
1072         }
1073 
1074         if (srcSigned) {
1075             EncodeCastScalarFromSignedScalar(dst, src);
1076         } else {
1077             EncodeCastScalarFromUnsignedScalar(dst, src);
1078         }
1079     }
1080 }
1081 
EncodeCastFloatToFloat(Reg dst,Reg src)1082 void Aarch32Encoder::EncodeCastFloatToFloat(Reg dst, Reg src)
1083 {
1084     // float/double -> float/double
1085     if (dst.GetSize() == src.GetSize()) {
1086         if (dst.GetSize() == WORD_SIZE) {
1087             GetMasm()->Vmov(VixlVReg(dst).S(), VixlVReg(src));
1088         } else {
1089             GetMasm()->Vmov(VixlVReg(dst).D(), VixlVReg(src));
1090         }
1091         return;
1092     }
1093 
1094     // double -> float
1095     if (dst.GetSize() == WORD_SIZE) {
1096         GetMasm()->Vcvt(vixl::aarch32::DataTypeValue::F32, vixl::aarch32::DataTypeValue::F64, VixlVReg(dst).S(),
1097                         VixlVReg(src).D());
1098     } else {
1099         // float -> double
1100         GetMasm()->Vcvt(vixl::aarch32::DataTypeValue::F64, vixl::aarch32::DataTypeValue::F32, VixlVReg(dst).D(),
1101                         VixlVReg(src).S());
1102     }
1103 }
1104 
EncodeCastScalarToFloat(Reg dst,Reg src,bool srcSigned)1105 void Aarch32Encoder::EncodeCastScalarToFloat(Reg dst, Reg src, bool srcSigned)
1106 {
1107     // uint/int -> float/double
1108     switch (src.GetSize()) {
1109         case BYTE_SIZE:
1110         case HALF_SIZE:
1111         case WORD_SIZE: {
1112             ScopedTmpRegF32 tmpReg(this);
1113 
1114             GetMasm()->Vmov(VixlVReg(tmpReg).S(), VixlReg(src));
1115             auto dataType = srcSigned ? vixl::aarch32::DataTypeValue::S32 : vixl::aarch32::DataTypeValue::U32;
1116             if (dst.GetSize() == WORD_SIZE) {
1117                 GetMasm()->Vcvt(vixl::aarch32::DataTypeValue::F32, dataType, VixlVReg(dst).S(), VixlVReg(tmpReg).S());
1118             } else {
1119                 GetMasm()->Vcvt(vixl::aarch32::DataTypeValue::F64, dataType, VixlVReg(dst).D(), VixlVReg(tmpReg).S());
1120             }
1121             break;
1122         }
1123         case DOUBLE_WORD_SIZE: {
1124             if (dst.GetSize() == WORD_SIZE) {
1125                 if (srcSigned) {
1126                     // int64 -> float
1127                     MakeLibCall(dst, src, reinterpret_cast<void *>(__aeabi_l2f));
1128                 } else {
1129                     // uint64 -> float
1130                     MakeLibCall(dst, src, reinterpret_cast<void *>(__aeabi_ul2f));
1131                 }
1132             } else {
1133                 if (srcSigned) {
1134                     // int64 -> double
1135                     MakeLibCall(dst, src, reinterpret_cast<void *>(__aeabi_l2d));
1136                 } else {
1137                     // uint64 -> double
1138                     MakeLibCall(dst, src, reinterpret_cast<void *>(__aeabi_ul2d));
1139                 }
1140             }
1141             break;
1142         }
1143         default:
1144             SetFalseResult();
1145             break;
1146     }
1147 }
1148 
EncodeCastFloatToScalar(Reg dst,bool dstSigned,Reg src)1149 void Aarch32Encoder::EncodeCastFloatToScalar(Reg dst, bool dstSigned, Reg src)
1150 {
1151     // We DON'T support casts from float32/64 to int8/16 and bool, because this caste is not declared anywhere
1152     // in other languages and architecture, we do not know what the behavior should be.
1153     // But there is one implementation in other function: "EncodeCastFloatToScalarWithSmallDst". Call it in the
1154     // "EncodeCast" function instead of "EncodeCastFloat". It works as follows: cast from float32/64 to int32, moving
1155     // sign bit from int32 to dst type, then extend number from dst type to int32 (a necessary condition for an isa).
1156     // All work in dst register.
1157     ASSERT(dst.GetSize() >= WORD_SIZE);
1158 
1159     switch (dst.GetSize()) {
1160         case WORD_SIZE: {
1161             ScopedTmpRegF32 tmpReg(this);
1162 
1163             auto dataType = dstSigned ? vixl::aarch32::DataTypeValue::S32 : vixl::aarch32::DataTypeValue::U32;
1164             if (src.GetSize() == WORD_SIZE) {
1165                 GetMasm()->Vcvt(dataType, vixl::aarch32::DataTypeValue::F32, VixlVReg(tmpReg).S(), VixlVReg(src).S());
1166             } else {
1167                 GetMasm()->Vcvt(dataType, vixl::aarch32::DataTypeValue::F64, VixlVReg(tmpReg).S(), VixlVReg(src).D());
1168             }
1169 
1170             GetMasm()->Vmov(VixlReg(dst), VixlVReg(tmpReg).S());
1171             break;
1172         }
1173         case DOUBLE_WORD_SIZE: {
1174             if (src.GetSize() == WORD_SIZE) {
1175                 if (dstSigned) {
1176                     // float -> int64
1177                     EncodeCastFloatToInt64(dst, src);
1178                 } else {
1179                     // float -> uint64
1180                     MakeLibCall(dst, src, reinterpret_cast<void *>(__aeabi_f2ulz));
1181                 }
1182             } else {
1183                 if (dstSigned) {
1184                     // double -> int64
1185                     EncodeCastDoubleToInt64(dst, src);
1186                 } else {
1187                     // double -> uint64
1188                     MakeLibCall(dst, src, reinterpret_cast<void *>(__aeabi_d2ulz));
1189                 }
1190             }
1191             break;
1192         }
1193         default:
1194             SetFalseResult();
1195             break;
1196     }
1197 }
1198 
EncodeCastFloatToScalarWithSmallDst(Reg dst,bool dstSigned,Reg src)1199 void Aarch32Encoder::EncodeCastFloatToScalarWithSmallDst(Reg dst, bool dstSigned, Reg src)
1200 {
1201     switch (dst.GetSize()) {
1202         case BYTE_SIZE:
1203         case HALF_SIZE:
1204         case WORD_SIZE: {
1205             ScopedTmpRegF32 tmpReg(this);
1206 
1207             auto dataType = dstSigned ? vixl::aarch32::DataTypeValue::S32 : vixl::aarch32::DataTypeValue::U32;
1208             if (src.GetSize() == WORD_SIZE) {
1209                 GetMasm()->Vcvt(dataType, vixl::aarch32::DataTypeValue::F32, VixlVReg(tmpReg).S(), VixlVReg(src).S());
1210             } else {
1211                 GetMasm()->Vcvt(dataType, vixl::aarch32::DataTypeValue::F64, VixlVReg(tmpReg).S(), VixlVReg(src).D());
1212             }
1213 
1214             GetMasm()->Vmov(VixlReg(dst), VixlVReg(tmpReg).S());
1215             if (dst.GetSize() < WORD_SIZE) {
1216                 EncoderCastExtendFromInt32(dst, dstSigned);
1217             }
1218             break;
1219         }
1220         case DOUBLE_WORD_SIZE: {
1221             if (src.GetSize() == WORD_SIZE) {
1222                 if (dstSigned) {
1223                     // float -> int64
1224                     EncodeCastFloatToInt64(dst, src);
1225                 } else {
1226                     // float -> uint64
1227                     MakeLibCall(dst, src, reinterpret_cast<void *>(__aeabi_f2ulz));
1228                 }
1229             } else {
1230                 if (dstSigned) {
1231                     // double -> int64
1232                     EncodeCastDoubleToInt64(dst, src);
1233                 } else {
1234                     // double -> uint64
1235                     MakeLibCall(dst, src, reinterpret_cast<void *>(__aeabi_d2ulz));
1236                 }
1237             }
1238             break;
1239         }
1240         default:
1241             SetFalseResult();
1242             break;
1243     }
1244 }
1245 
EncoderCastExtendFromInt32(Reg dst,bool dstSigned)1246 void Aarch32Encoder::EncoderCastExtendFromInt32(Reg dst, bool dstSigned)
1247 {
1248     if (dstSigned) {
1249         constexpr uint32_t TEST_BIT = (1U << (static_cast<uint32_t>(WORD_SIZE) - 1));
1250         ScopedTmpReg tmpReg(this, dst.GetType());
1251 
1252         uint32_t setBit = (dst.GetSize() == BYTE_SIZE) ? (1U << static_cast<uint32_t>(BYTE_SIZE - 1))
1253                                                        : (1U << static_cast<uint32_t>(HALF_SIZE - 1));
1254         uint32_t remBit = setBit - 1;
1255         GetMasm()->And(VixlReg(tmpReg), VixlReg(dst), TEST_BIT);
1256         auto labelSkip = CreateLabel();
1257         auto labelEndIf = CreateLabel();
1258         EncodeJump(labelSkip, tmpReg, Condition::EQ);
1259         // Set signed bit in dst reg (accordingly destination type)
1260         // If signed bit == 1
1261         GetMasm()->Orr(VixlReg(dst), VixlReg(dst), setBit);
1262         EncodeJump(labelEndIf);
1263         BindLabel(labelSkip);
1264         // If signed bit == 0
1265         GetMasm()->And(VixlReg(dst), VixlReg(dst), remBit);
1266         BindLabel(labelEndIf);
1267     }
1268     EncodeCastScalar(Reg(dst.GetId(), INT32_TYPE), dstSigned, dst, dstSigned);
1269 }
1270 
EncodeCastDoubleToInt64(Reg dst,Reg src)1271 void Aarch32Encoder::EncodeCastDoubleToInt64(Reg dst, Reg src)
1272 {
1273     auto labelCheckNan = CreateLabel();
1274     auto labelNotNan = CreateLabel();
1275     auto labelExit = CreateLabel();
1276     ScopedTmpReg tmpReg1(this, INT32_TYPE);
1277 
1278     // Mov double to 2x reg to storage double in hex format and work with them
1279     EncodeMov(dst, src);
1280     // See the exponent of number
1281     GetMasm()->Ubfx(VixlReg(tmpReg1), VixlRegU(dst), START_EXP_DOUBLE, SIZE_EXP_DOUBLE);
1282     // Max exponent that we can load in int64
1283     // Check that x > MIN_INT64 & x < MAX_INT64, else jump
1284     GetMasm()->Cmp(VixlReg(tmpReg1), VixlImm(POSSIBLE_EXP_DOUBLE));
1285     // If greater than or equal, branch to "label_not_nan"
1286     GetMasm()->B(vixl::aarch32::hs, static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(labelCheckNan));
1287     MakeLibCall(dst, src, reinterpret_cast<void *>(__aeabi_d2lz));
1288     EncodeJump(labelExit);
1289 
1290     BindLabel(labelCheckNan);
1291     // Form of nan number
1292     GetMasm()->Cmp(VixlReg(tmpReg1), VixlImm(UP_BITS_NAN_DOUBLE));
1293     // If not equal, branch to "label_not_nan"
1294     GetMasm()->B(vixl::aarch32::ne, static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(labelNotNan));
1295 
1296     GetMasm()->Orrs(VixlReg(tmpReg1), VixlReg(dst),
1297                     vixl::aarch32::Operand(VixlRegU(dst), vixl::aarch32::LSL, SHIFT_BITS_DOUBLE));
1298     auto addrLabel = static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(labelNotNan);
1299     GetMasm()->B(vixl::aarch32::eq, addrLabel);
1300     GetMasm()->Mov(VixlReg(dst), VixlImm(0));
1301     GetMasm()->Mov(VixlRegU(dst), VixlImm(0));
1302     EncodeJump(labelExit);
1303 
1304     BindLabel(labelNotNan);
1305     GetMasm()->Adds(VixlRegU(dst), VixlRegU(dst), VixlRegU(dst));
1306     GetMasm()->Mov(VixlReg(dst), VixlImm(UINT32_MAX));
1307     GetMasm()->Mov(VixlRegU(dst), VixlImm(INT32_MAX));
1308     GetMasm()->Adc(VixlReg(dst), VixlReg(dst), VixlImm(0));
1309     // If exponent negative, transform maxint64 to minint64
1310     GetMasm()->Adc(VixlRegU(dst), VixlRegU(dst), VixlImm(0));
1311 
1312     BindLabel(labelExit);
1313 }
1314 
EncodeCastFloatToInt64(Reg dst,Reg src)1315 void Aarch32Encoder::EncodeCastFloatToInt64(Reg dst, Reg src)
1316 {
1317     auto labelCheckNan = CreateLabel();
1318     auto labelNotNan = CreateLabel();
1319     auto labelExit = CreateLabel();
1320 
1321     ScopedTmpReg tmpReg(this, INT32_TYPE);
1322     ScopedTmpReg movedSrc(this, INT32_TYPE);
1323     EncodeMov(movedSrc, src);
1324     // See the exponent of number
1325     GetMasm()->Ubfx(VixlReg(tmpReg), VixlReg(movedSrc), START_EXP_FLOAT, SIZE_EXP_FLOAT);
1326     // Max exponent that we can load in int64
1327     // Check that x > MIN_INT64 & x < MAX_INT64, else jump
1328     GetMasm()->Cmp(VixlReg(tmpReg), VixlImm(POSSIBLE_EXP_FLOAT));
1329     // If greater than or equal, branch to "label_not_nan"
1330     GetMasm()->B(vixl::aarch32::hs, static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(labelCheckNan));
1331     MakeLibCall(dst, src, reinterpret_cast<void *>(__aeabi_f2lz));
1332     EncodeJump(labelExit);
1333 
1334     BindLabel(labelCheckNan);
1335     // Form of nan number
1336     GetMasm()->Cmp(VixlReg(tmpReg), VixlImm(UP_BITS_NAN_FLOAT));
1337     // If not equal, branch to "label_not_nan"
1338     GetMasm()->B(vixl::aarch32::ne, static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(labelNotNan));
1339 
1340     GetMasm()->Lsls(VixlReg(tmpReg), VixlReg(movedSrc), vixl::aarch32::Operand(SHIFT_BITS_FLOAT));
1341     // If equal, branch to "label_not_nan"
1342     GetMasm()->B(vixl::aarch32::eq, static_cast<Aarch32LabelHolder *>(GetLabels())->GetLabel(labelNotNan));
1343     GetMasm()->Mov(VixlReg(dst), VixlImm(0));
1344     GetMasm()->Mov(VixlRegU(dst), VixlImm(0));
1345     EncodeJump(labelExit);
1346 
1347     BindLabel(labelNotNan);
1348     GetMasm()->Adds(VixlReg(movedSrc), VixlReg(movedSrc), VixlReg(movedSrc));
1349     GetMasm()->Mov(VixlReg(dst), VixlImm(UINT32_MAX));
1350     GetMasm()->Mov(VixlRegU(dst), VixlImm(INT32_MAX));
1351     GetMasm()->Adc(VixlReg(dst), VixlReg(dst), VixlImm(0));
1352     // If exponent negative, transform maxint64 to minint64
1353     GetMasm()->Adc(VixlRegU(dst), VixlRegU(dst), VixlImm(0));
1354 
1355     BindLabel(labelExit);
1356 }
1357 
EncodeCastScalarFromSignedScalar(Reg dst,Reg src)1358 void Aarch32Encoder::EncodeCastScalarFromSignedScalar(Reg dst, Reg src)
1359 {
1360     size_t srcSize = src.GetSize();
1361     size_t dstSize = dst.GetSize();
1362     if (srcSize > dstSize) {
1363         srcSize = dstSize;
1364     }
1365     switch (srcSize) {
1366         case BYTE_SIZE:
1367             GetMasm()->Sxtb(VixlReg(dst), VixlReg(src));
1368             break;
1369         case HALF_SIZE:
1370             GetMasm()->Sxth(VixlReg(dst), VixlReg(src));
1371             break;
1372         case WORD_SIZE:
1373             GetMasm()->Mov(VixlReg(dst), VixlReg(src));
1374             break;
1375         case DOUBLE_WORD_SIZE:
1376             GetMasm()->Mov(VixlReg(dst), VixlReg(src));
1377             if (dstSize == DOUBLE_WORD_SIZE) {
1378                 GetMasm()->Mov(VixlReg(dst), VixlReg(src));
1379                 return;
1380             }
1381             break;
1382         default:
1383             SetFalseResult();
1384             break;
1385     }
1386     if (dstSize == DOUBLE_WORD_SIZE) {
1387         GetMasm()->Asr(VixlRegU(dst), VixlReg(dst), VixlImm(WORD_SIZE - 1));
1388     }
1389 }
1390 
EncodeCastScalarFromUnsignedScalar(Reg dst,Reg src)1391 void Aarch32Encoder::EncodeCastScalarFromUnsignedScalar(Reg dst, Reg src)
1392 {
1393     size_t srcSize = src.GetSize();
1394     size_t dstSize = dst.GetSize();
1395     if (srcSize > dstSize && dstSize < WORD_SIZE) {
1396         // We need to cut the number, if it is less, than 32-bit. It is by ISA agreement.
1397         int64_t cutValue = (1ULL << dstSize) - 1;
1398         GetMasm()->And(VixlReg(dst), VixlReg(src), VixlImm(cutValue));
1399         return;
1400     }
1401     // Else unsigned extend
1402     switch (srcSize) {
1403         case BYTE_SIZE:
1404             GetMasm()->Uxtb(VixlReg(dst), VixlReg(src));
1405             break;
1406         case HALF_SIZE:
1407             GetMasm()->Uxth(VixlReg(dst), VixlReg(src));
1408             break;
1409         case WORD_SIZE:
1410             GetMasm()->Mov(VixlReg(dst), VixlReg(src));
1411             break;
1412         case DOUBLE_WORD_SIZE:
1413             GetMasm()->Mov(VixlReg(dst), VixlReg(src));
1414             if (dstSize == DOUBLE_WORD_SIZE) {
1415                 GetMasm()->Mov(VixlReg(dst), VixlReg(src));
1416                 return;
1417             }
1418             break;
1419         default:
1420             SetFalseResult();
1421             break;
1422     }
1423     if (dstSize == DOUBLE_WORD_SIZE) {
1424         GetMasm()->Mov(VixlRegU(dst), VixlImm(0x0));
1425     }
1426 }
1427 
EncodeAdd(Reg dst,Reg src0,Reg src1)1428 void Aarch32Encoder::EncodeAdd(Reg dst, Reg src0, Reg src1)
1429 {
1430     if (dst.IsFloat()) {
1431         ASSERT(src0.IsFloat() && src1.IsFloat());
1432         GetMasm()->Vadd(VixlVReg(dst), VixlVReg(src0), VixlVReg(src1));
1433         return;
1434     }
1435 
1436     if (dst.GetSize() <= WORD_SIZE) {
1437         GetMasm()->Add(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1438         return;
1439     }
1440 
1441     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
1442     GetMasm()->Adds(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1443     GetMasm()->Adc(VixlRegU(dst), VixlRegU(src0), VixlRegU(src1));
1444 }
1445 
EncodeSub(Reg dst,Reg src0,Reg src1)1446 void Aarch32Encoder::EncodeSub(Reg dst, Reg src0, Reg src1)
1447 {
1448     if (dst.IsFloat()) {
1449         GetMasm()->Vsub(VixlVReg(dst), VixlVReg(src0), VixlVReg(src1));
1450         return;
1451     }
1452 
1453     if (dst.GetSize() <= WORD_SIZE) {
1454         GetMasm()->Sub(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1455         return;
1456     }
1457 
1458     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
1459     GetMasm()->Subs(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1460     GetMasm()->Sbc(VixlRegU(dst), VixlRegU(src0), VixlRegU(src1));
1461 }
1462 
EncodeMul(Reg dst,Reg src0,Reg src1)1463 void Aarch32Encoder::EncodeMul(Reg dst, Reg src0, Reg src1)
1464 {
1465     if (dst.IsFloat()) {
1466         GetMasm()->Vmul(VixlVReg(dst), VixlVReg(src0), VixlVReg(src1));
1467         return;
1468     }
1469 
1470     if (dst.GetSize() <= WORD_SIZE) {
1471         GetMasm()->Mul(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1472         return;
1473     }
1474 
1475     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
1476     ScopedTmpRegU32 loReg(this);
1477     ScopedTmpRegU32 hiReg(this);
1478 
1479     GetMasm()->Umull(VixlReg(loReg), VixlReg(hiReg), VixlReg(src0), VixlReg(src1));
1480     GetMasm()->Mla(VixlReg(hiReg), VixlRegU(src0), VixlReg(src1), VixlReg(hiReg));
1481     GetMasm()->Mla(VixlReg(hiReg), VixlReg(src0), VixlRegU(src1), VixlReg(hiReg));
1482 
1483     GetMasm()->Mov(VixlReg(dst), VixlReg(loReg));
1484     GetMasm()->Mov(VixlRegU(dst), VixlReg(hiReg));
1485 }
1486 
MakeLibCall(Reg dst,Reg src0,Reg src1,void * entryPoint,bool secondValue)1487 void Aarch32Encoder::MakeLibCall(Reg dst, Reg src0, Reg src1, void *entryPoint, bool secondValue)
1488 {
1489     if (dst.GetType() == FLOAT32_TYPE) {
1490         MakeLibCallWithFloatResult(dst, src0, src1, entryPoint, secondValue);
1491         return;
1492     }
1493 
1494     if (dst.GetType() == FLOAT64_TYPE) {
1495         MakeLibCallWithDoubleResult(dst, src0, src1, entryPoint, secondValue);
1496         return;
1497     }
1498 
1499     if (dst.GetType() == INT64_TYPE) {
1500         MakeLibCallWithInt64Result(dst, src0, src1, entryPoint, secondValue);
1501         return;
1502     }
1503 
1504     ASSERT(dst.GetSize() < DOUBLE_WORD_SIZE);
1505 
1506     if (src1.GetId() == vixl::aarch32::r0.GetCode() || src0 == src1) {
1507         ScopedTmpRegU32 tmp(this);
1508         GetMasm()->Mov(VixlReg(tmp), VixlReg(src1));
1509         GetMasm()->Mov(vixl::aarch32::r0, VixlReg(src0));
1510         GetMasm()->Mov(vixl::aarch32::r1, VixlReg(tmp));
1511     } else {
1512         GetMasm()->Mov(vixl::aarch32::r0, VixlReg(src0));
1513         GetMasm()->Mov(vixl::aarch32::r1, VixlReg(src1));
1514     };
1515 
1516     // Call lib-method
1517     MakeCall(entryPoint);
1518 
1519     auto dstRegister = secondValue ? vixl::aarch32::r1 : vixl::aarch32::r0;
1520 
1521     if (dst.GetId() <= vixl::aarch32::r3.GetCode()) {
1522         ScopedTmpRegU32 tmp(this);
1523         GetMasm()->Mov(VixlReg(tmp), dstRegister);
1524         GetMasm()->Mov(VixlReg(dst), VixlReg(tmp));
1525     } else {
1526         GetMasm()->Mov(VixlReg(dst), dstRegister);
1527     }
1528 }
1529 
MakeLibCallWithFloatResult(Reg dst,Reg src0,Reg src1,void * entryPoint,bool secondValue)1530 void Aarch32Encoder::MakeLibCallWithFloatResult(Reg dst, Reg src0, Reg src1, void *entryPoint, bool secondValue)
1531 {
1532 #if (PANDA_TARGET_ARM32_ABI_HARD)
1533     // gnueabihf
1534     // use double parameters
1535     if (src1.GetId() == vixl::aarch32::s0.GetCode() || src0 == src1) {
1536         ScopedTmpRegF32 tmp(this);
1537         GetMasm()->Vmov(VixlVReg(tmp), VixlVReg(src1));
1538         GetMasm()->Vmov(vixl::aarch32::s0, VixlVReg(src0));
1539         GetMasm()->Vmov(vixl::aarch32::s1, VixlVReg(tmp));
1540     } else {
1541         GetMasm()->Vmov(vixl::aarch32::s0, VixlVReg(src0));
1542         GetMasm()->Vmov(vixl::aarch32::s1, VixlVReg(src1));
1543     };
1544 
1545     MakeCall(entryPoint);
1546 
1547     auto dstRegister = secondValue ? vixl::aarch32::s1 : vixl::aarch32::s0;
1548     if (dst.GetId() <= vixl::aarch32::s1.GetCode()) {
1549         ScopedTmpRegF32 tmp(this);
1550         GetMasm()->Vmov(VixlVReg(tmp).S(), dstRegister);
1551         GetMasm()->Vmov(VixlVReg(dst).S(), VixlVReg(tmp).S());
1552     } else {
1553         GetMasm()->Vmov(VixlVReg(dst).S(), dstRegister);
1554     }
1555 #else
1556     // gnueabi
1557     // use scalar parameters
1558     GetMasm()->Vmov(vixl::aarch32::r0, VixlVReg(src0).S());
1559     GetMasm()->Vmov(vixl::aarch32::r1, VixlVReg(src1).S());
1560 
1561     MakeCall(entryPoint);
1562 
1563     auto dstRegister = secondValue ? vixl::aarch32::r1 : vixl::aarch32::r0;
1564     GetMasm()->Vmov(VixlVReg(dst).S(), dstRegister);
1565 #endif  // PANDA_TARGET_ARM32_ABI_HARD
1566 }
1567 
MakeLibCallWithDoubleResult(Reg dst,Reg src0,Reg src1,void * entryPoint,bool secondValue)1568 void Aarch32Encoder::MakeLibCallWithDoubleResult(Reg dst, Reg src0, Reg src1, void *entryPoint, bool secondValue)
1569 {
1570 #if (PANDA_TARGET_ARM32_ABI_HARD)
1571     // Scope for temp
1572     if (src1.GetId() == vixl::aarch32::d0.GetCode() || src0 == src1) {
1573         ScopedTmpRegF64 tmp(this);
1574         GetMasm()->Vmov(VixlVReg(tmp), VixlVReg(src1));
1575         GetMasm()->Vmov(vixl::aarch32::d0, VixlVReg(src0));
1576         GetMasm()->Vmov(vixl::aarch32::d1, VixlVReg(tmp));
1577     } else {
1578         GetMasm()->Vmov(vixl::aarch32::d0, VixlVReg(src0));
1579         GetMasm()->Vmov(vixl::aarch32::d1, VixlVReg(src1));
1580     };
1581     MakeCall(entryPoint);
1582     auto dstRegister = secondValue ? vixl::aarch32::d1 : vixl::aarch32::d0;
1583 
1584     if (dst.GetId() <= vixl::aarch32::d1.GetCode()) {
1585         ScopedTmpRegF64 tmp(this);
1586         GetMasm()->Vmov(VixlVReg(tmp), dstRegister);
1587         GetMasm()->Vmov(VixlVReg(dst), VixlVReg(tmp));
1588     } else {
1589         GetMasm()->Vmov(VixlVReg(dst), dstRegister);
1590     }
1591 
1592     // use double parameters
1593 #else
1594     // use scalar parameters
1595     GetMasm()->Vmov(vixl::aarch32::r0, vixl::aarch32::r1, VixlVReg(src0).D());
1596     GetMasm()->Vmov(vixl::aarch32::r2, vixl::aarch32::r3, VixlVReg(src1).D());
1597 
1598     MakeCall(entryPoint);
1599 
1600     auto dstRegister1 = secondValue ? vixl::aarch32::r2 : vixl::aarch32::r0;
1601     auto dstRegister2 = secondValue ? vixl::aarch32::r3 : vixl::aarch32::r1;
1602 
1603     GetMasm()->Vmov(VixlVReg(dst).D(), dstRegister1, dstRegister2);
1604 #endif  // PANDA_TARGET_ARM32_ABI_HARD
1605 }
1606 
MakeLibCallWithInt64Result(Reg dst,Reg src0,Reg src1,void * entryPoint,bool secondValue)1607 void Aarch32Encoder::MakeLibCallWithInt64Result(Reg dst, Reg src0, Reg src1, void *entryPoint, bool secondValue)
1608 {
1609     // Here I look only for this case, because src - is mapped on two regs.
1610     // (INT64_TYPE), and src0 can't be rewrited
1611     // NOTE(igorban) If src0==src1 - the result will be 1 or UB(if src0 = 0)
1612     // It is better to check them in optimizations
1613     // ASSERT(src0 != src1); - do not enable for tests
1614 
1615     if (src1.GetId() == vixl::aarch32::r0.GetCode() || src0 == src1) {
1616         ScopedTmpRegU32 tmp1(this);
1617         ScopedTmpRegU32 tmp2(this);
1618         GetMasm()->Mov(VixlReg(tmp1), VixlReg(src1));
1619         GetMasm()->Mov(VixlReg(tmp2), VixlRegU(src1));
1620         GetMasm()->Mov(vixl::aarch32::r0, VixlReg(src0));
1621         GetMasm()->Mov(vixl::aarch32::r1, VixlRegU(src0));
1622         GetMasm()->Mov(vixl::aarch32::r2, VixlReg(tmp1));
1623         GetMasm()->Mov(vixl::aarch32::r3, VixlReg(tmp2));
1624     } else {
1625         GetMasm()->Mov(vixl::aarch32::r0, VixlReg(src0));
1626         GetMasm()->Mov(vixl::aarch32::r1, VixlRegU(src0));
1627         GetMasm()->Mov(vixl::aarch32::r2, VixlReg(src1));
1628         GetMasm()->Mov(vixl::aarch32::r3, VixlRegU(src1));
1629     };
1630 
1631     // Call lib-method
1632     MakeCall(entryPoint);
1633 
1634     auto dstRegister1 = secondValue ? vixl::aarch32::r2 : vixl::aarch32::r0;
1635     auto dstRegister2 = secondValue ? vixl::aarch32::r3 : vixl::aarch32::r1;
1636 
1637     if (dst.GetId() <= vixl::aarch32::r3.GetCode()) {
1638         ScopedTmpRegU32 tmp1(this);
1639         ScopedTmpRegU32 tmp2(this);
1640         GetMasm()->Mov(VixlReg(tmp1), dstRegister1);
1641         GetMasm()->Mov(VixlReg(tmp2), dstRegister2);
1642         GetMasm()->Mov(VixlReg(dst), VixlReg(tmp1));
1643         GetMasm()->Mov(VixlRegU(dst), VixlReg(tmp2));
1644     } else {
1645         GetMasm()->Mov(VixlReg(dst), dstRegister1);
1646         GetMasm()->Mov(VixlRegU(dst), dstRegister2);
1647     }
1648 }
1649 
MakeLibCall(Reg dst,Reg src,void * entryPoint)1650 void Aarch32Encoder::MakeLibCall(Reg dst, Reg src, void *entryPoint)
1651 {
1652     if (dst.IsFloat() && src.IsScalar()) {
1653         if (src.GetSize() != DOUBLE_WORD_SIZE) {
1654             SetFalseResult();
1655             return;
1656         }
1657 
1658         bool saveR1 {src.GetId() != vixl::aarch32::r0.GetCode() || dst.GetType() == FLOAT64_TYPE};
1659 
1660         GetMasm()->Push(vixl::aarch32::r0);
1661         if (saveR1) {
1662             GetMasm()->Push(vixl::aarch32::r1);
1663         }
1664 
1665         if (src.GetId() != vixl::aarch32::r0.GetCode()) {
1666             GetMasm()->Mov(vixl::aarch32::r0, VixlReg(src));
1667             GetMasm()->Mov(vixl::aarch32::r1, VixlRegU(src));
1668         }
1669 
1670         MakeCall(entryPoint);
1671 
1672         if (dst.GetType() == FLOAT64_TYPE) {
1673             GetMasm()->Vmov(VixlVReg(dst).D(), vixl::aarch32::r0, vixl::aarch32::r1);
1674         } else {
1675             GetMasm()->Vmov(VixlVReg(dst).S(), vixl::aarch32::r0);
1676         }
1677 
1678         if (saveR1) {
1679             GetMasm()->Pop(vixl::aarch32::r1);
1680         }
1681         GetMasm()->Pop(vixl::aarch32::r0);
1682     } else if (dst.IsScalar() && src.IsFloat()) {
1683         if (dst.GetSize() != DOUBLE_WORD_SIZE) {
1684             SetFalseResult();
1685             return;
1686         }
1687 
1688         bool saveR0R1 {dst.GetId() != vixl::aarch32::r0.GetCode()};
1689 
1690         if (saveR0R1) {
1691             GetMasm()->Push(vixl::aarch32::r0);
1692             GetMasm()->Push(vixl::aarch32::r1);
1693         }
1694 
1695         if (src.GetType() == FLOAT64_TYPE) {
1696             GetMasm()->Vmov(vixl::aarch32::r0, vixl::aarch32::r1, VixlVReg(src).D());
1697         } else {
1698             GetMasm()->Vmov(vixl::aarch32::r0, VixlVReg(src).S());
1699         }
1700 
1701         MakeCall(entryPoint);
1702 
1703         if (saveR0R1) {
1704             GetMasm()->Mov(VixlReg(dst), vixl::aarch32::r0);
1705             GetMasm()->Mov(VixlRegU(dst), vixl::aarch32::r1);
1706 
1707             GetMasm()->Pop(vixl::aarch32::r1);
1708             GetMasm()->Pop(vixl::aarch32::r0);
1709         }
1710     } else {
1711         SetFalseResult();
1712         return;
1713     }
1714 }
1715 
EncodeDiv(Reg dst,bool dstSigned,Reg src0,Reg src1)1716 void Aarch32Encoder::EncodeDiv(Reg dst, bool dstSigned, Reg src0, Reg src1)
1717 {
1718     if (dst.IsFloat()) {
1719         GetMasm()->Vdiv(VixlVReg(dst), VixlVReg(src0), VixlVReg(src1));
1720         return;
1721     }
1722 
1723     if (dst.GetSize() <= WORD_SIZE) {
1724         if (!dstSigned) {
1725             GetMasm()->Udiv(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1726             return;
1727         }
1728 
1729         GetMasm()->Sdiv(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1730         return;
1731     }
1732     if (dstSigned) {
1733         MakeLibCall(dst, src0, src1, reinterpret_cast<void *>(__aeabi_ldivmod));
1734     } else {
1735         MakeLibCall(dst, src0, src1, reinterpret_cast<void *>(__aeabi_uldivmod));
1736     }
1737 }
1738 
EncodeMod(Reg dst,bool dstSigned,Reg src0,Reg src1)1739 void Aarch32Encoder::EncodeMod(Reg dst, bool dstSigned, Reg src0, Reg src1)
1740 {
1741     if (dst.GetType() == FLOAT32_TYPE) {
1742         using Fp = float (*)(float, float);
1743         MakeLibCall(dst, src0, src1, reinterpret_cast<void *>(static_cast<Fp>(fmodf)));
1744         return;
1745     }
1746     if (dst.GetType() == FLOAT64_TYPE) {
1747         using Fp = double (*)(double, double);
1748         MakeLibCall(dst, src0, src1, reinterpret_cast<void *>(static_cast<Fp>(fmod)));
1749         return;
1750     }
1751 
1752     if (dst.GetSize() <= WORD_SIZE) {
1753         if (dstSigned) {
1754             MakeLibCall(dst, src0, src1, reinterpret_cast<void *>(__aeabi_idivmod), true);
1755         } else {
1756             MakeLibCall(dst, src0, src1, reinterpret_cast<void *>(__aeabi_uidivmod), true);
1757         }
1758 
1759         // dst = -(tmp * src0) + src1
1760         if ((dst.GetSize() == BYTE_SIZE) && dstSigned) {
1761             GetMasm()->Sxtb(VixlReg(dst), VixlReg(dst));
1762         }
1763         if ((dst.GetSize() == HALF_SIZE) && dstSigned) {
1764             GetMasm()->Sxth(VixlReg(dst), VixlReg(dst));
1765         }
1766         return;
1767     }
1768 
1769     // Call lib-method
1770     if (dstSigned) {
1771         MakeLibCall(dst, src0, src1, reinterpret_cast<void *>(__aeabi_ldivmod), true);
1772     } else {
1773         MakeLibCall(dst, src0, src1, reinterpret_cast<void *>(__aeabi_uldivmod), true);
1774     }
1775 }
1776 
EncodeMin(Reg dst,bool dstSigned,Reg src0,Reg src1)1777 void Aarch32Encoder::EncodeMin(Reg dst, bool dstSigned, Reg src0, Reg src1)
1778 {
1779     if (dst.IsFloat()) {
1780         EncodeMinMaxFp<false>(dst, src0, src1);
1781         return;
1782     }
1783 
1784     if (dst.GetSize() <= WORD_SIZE) {
1785         if (dstSigned) {
1786             GetMasm()->Cmp(VixlReg(src0), VixlReg(src1));
1787             GetMasm()->Mov(Convert(Condition::LE), VixlReg(dst), VixlReg(src0));
1788             GetMasm()->Mov(Convert(Condition::GT), VixlReg(dst), VixlReg(src1));
1789             return;
1790         }
1791         GetMasm()->Cmp(VixlReg(src0), VixlReg(src1));
1792         GetMasm()->Mov(Convert(Condition::LS), VixlReg(dst), VixlReg(src0));
1793         GetMasm()->Mov(Convert(Condition::HI), VixlReg(dst), VixlReg(src1));
1794         return;
1795     }
1796 
1797     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
1798     ScopedTmpRegU32 tmpReg(this);
1799 
1800     GetMasm()->Subs(VixlReg(tmpReg), VixlReg(src0), VixlReg(src1));
1801     GetMasm()->Sbcs(VixlReg(tmpReg), VixlRegU(src0), VixlRegU(src1));
1802 
1803     auto cc = Convert(dstSigned ? Condition::LT : Condition::LO);
1804     GetMasm()->Mov(cc, VixlReg(dst), VixlReg(src0));
1805     GetMasm()->Mov(cc, VixlRegU(dst), VixlRegU(src0));
1806     GetMasm()->Mov(cc.Negate(), VixlReg(dst), VixlReg(src1));
1807     GetMasm()->Mov(cc.Negate(), VixlRegU(dst), VixlRegU(src1));
1808 }
1809 
EncodeMax(Reg dst,bool dstSigned,Reg src0,Reg src1)1810 void Aarch32Encoder::EncodeMax(Reg dst, bool dstSigned, Reg src0, Reg src1)
1811 {
1812     if (dst.IsFloat()) {
1813         EncodeMinMaxFp<true>(dst, src0, src1);
1814         return;
1815     }
1816 
1817     if (dst.GetSize() <= WORD_SIZE) {
1818         if (dstSigned) {
1819             GetMasm()->Cmp(VixlReg(src0), VixlReg(src1));
1820             GetMasm()->Mov(Convert(Condition::GT), VixlReg(dst), VixlReg(src0));
1821             GetMasm()->Mov(Convert(Condition::LE), VixlReg(dst), VixlReg(src1));
1822             return;
1823         }
1824         GetMasm()->Cmp(VixlReg(src0), VixlReg(src1));
1825         GetMasm()->Mov(Convert(Condition::HI), VixlReg(dst), VixlReg(src0));
1826         GetMasm()->Mov(Convert(Condition::LS), VixlReg(dst), VixlReg(src1));
1827         return;
1828     }
1829 
1830     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
1831     ScopedTmpRegU32 tmpReg(this);
1832 
1833     GetMasm()->Subs(VixlReg(tmpReg), VixlReg(src0), VixlReg(src1));
1834     GetMasm()->Sbcs(VixlReg(tmpReg), VixlRegU(src0), VixlRegU(src1));
1835 
1836     auto cc = Convert(dstSigned ? Condition::LT : Condition::LO);
1837     GetMasm()->Mov(cc, VixlReg(dst), VixlReg(src1));
1838     GetMasm()->Mov(cc, VixlRegU(dst), VixlRegU(src1));
1839     GetMasm()->Mov(cc.Negate(), VixlReg(dst), VixlReg(src0));
1840     GetMasm()->Mov(cc.Negate(), VixlRegU(dst), VixlRegU(src0));
1841 }
1842 
1843 template <bool IS_MAX>
EncodeMinMaxFp(Reg dst,Reg src0,Reg src1)1844 void Aarch32Encoder::EncodeMinMaxFp(Reg dst, Reg src0, Reg src1)
1845 {
1846     Aarch32LabelHolder::LabelType notEqual(GetAllocator());
1847     Aarch32LabelHolder::LabelType gotNan(GetAllocator());
1848     Aarch32LabelHolder::LabelType end(GetAllocator());
1849     auto &srcA = dst.GetId() != src1.GetId() ? src0 : src1;
1850     auto &srcB = srcA.GetId() == src0.GetId() ? src1 : src0;
1851     GetMasm()->Vmov(VixlVReg(dst), VixlVReg(srcA));
1852     // Vcmp change flags:
1853     // NZCV
1854     // 0011 <- if any operand is NaN
1855     // 0110 <- operands are equals
1856     // 1000 <- operand0 < operand1
1857     // 0010 <- operand0 > operand1
1858     GetMasm()->Vcmp(VixlVReg(srcB), VixlVReg(srcA));
1859     GetMasm()->Vmrs(vixl::aarch32::RegisterOrAPSR_nzcv(vixl::aarch32::kPcCode), vixl::aarch32::FPSCR);
1860     GetMasm()->B(Convert(Condition::VS), &gotNan);
1861     GetMasm()->B(Convert(Condition::NE), &notEqual);
1862 
1863     // calculate result for positive/negative zero operands
1864     if (IS_MAX) {
1865         EncodeVand(dst, srcA, srcB);
1866     } else {
1867         EncodeVorr(dst, srcA, srcB);
1868     }
1869     GetMasm()->B(&end);
1870     GetMasm()->Bind(&gotNan);
1871     // if any operand is NaN result is NaN
1872     EncodeVorr(dst, srcA, srcB);
1873     GetMasm()->B(&end);
1874     GetMasm()->bind(&notEqual);
1875     // calculate min/max for other cases
1876     if (IS_MAX) {
1877         GetMasm()->B(Convert(Condition::MI), &end);
1878     } else {
1879         GetMasm()->B(Convert(Condition::HI), &end);
1880     }
1881     GetMasm()->Vmov(VixlVReg(dst), VixlVReg(srcB));
1882     GetMasm()->bind(&end);
1883 }
1884 
EncodeVorr(Reg dst,Reg src0,Reg src1)1885 void Aarch32Encoder::EncodeVorr(Reg dst, Reg src0, Reg src1)
1886 {
1887     if (dst.GetType() == FLOAT32_TYPE) {
1888         ScopedTmpRegF64 tmpReg(this);
1889         GetMasm()->Vmov(vixl::aarch32::SRegister(tmpReg.GetReg().GetId() + (src0.GetId() & 1U)), VixlVReg(src1).S());
1890         GetMasm()->Vorr(vixl::aarch32::DRegister(tmpReg.GetReg().GetId() / 2U),
1891                         vixl::aarch32::DRegister(src0.GetId() / 2U),
1892                         vixl::aarch32::DRegister(tmpReg.GetReg().GetId() / 2U));
1893         GetMasm()->Vmov(VixlVReg(dst).S(), vixl::aarch32::SRegister(tmpReg.GetReg().GetId() + (src0.GetId() & 1U)));
1894     } else {
1895         GetMasm()->Vorr(VixlVReg(dst).D(), VixlVReg(src0).D(), VixlVReg(src1).D());
1896     }
1897 }
1898 
EncodeVand(Reg dst,Reg src0,Reg src1)1899 void Aarch32Encoder::EncodeVand(Reg dst, Reg src0, Reg src1)
1900 {
1901     if (dst.GetType() == FLOAT32_TYPE) {
1902         ScopedTmpRegF64 tmpReg(this);
1903         GetMasm()->Vmov(vixl::aarch32::SRegister(tmpReg.GetReg().GetId() + (src0.GetId() & 1U)), VixlVReg(src1).S());
1904         GetMasm()->Vand(vixl::aarch32::kDataTypeValueNone, vixl::aarch32::DRegister(tmpReg.GetReg().GetId() / 2U),
1905                         vixl::aarch32::DRegister(src0.GetId() / 2U),
1906                         vixl::aarch32::DRegister(tmpReg.GetReg().GetId() / 2U));
1907         GetMasm()->Vmov(VixlVReg(dst).S(), vixl::aarch32::SRegister(tmpReg.GetReg().GetId() + (src0.GetId() & 1U)));
1908     } else {
1909         GetMasm()->Vand(vixl::aarch32::kDataTypeValueNone, VixlVReg(dst).D(), VixlVReg(src0).D(), VixlVReg(src1).D());
1910     }
1911 }
1912 
EncodeShl(Reg dst,Reg src0,Reg src1)1913 void Aarch32Encoder::EncodeShl(Reg dst, Reg src0, Reg src1)
1914 {
1915     if (dst.GetSize() < WORD_SIZE) {
1916         GetMasm()->And(VixlReg(src1), VixlReg(src1), VixlImm(dst.GetSize() - 1));
1917     }
1918 
1919     if (dst.GetSize() <= WORD_SIZE) {
1920         GetMasm()->Lsl(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1921         return;
1922     }
1923 
1924     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
1925     ScopedTmpRegU32 hiReg(this);
1926     ScopedTmpRegU32 tmpReg(this);
1927 
1928     GetMasm()->Rsb(VixlReg(tmpReg), VixlReg(src1), VixlImm(WORD_SIZE));
1929     GetMasm()->Lsr(VixlReg(tmpReg), VixlReg(src0), VixlReg(tmpReg));
1930     GetMasm()->Orr(VixlReg(hiReg), VixlReg(tmpReg),
1931                    vixl::aarch32::Operand(VixlRegU(src0), vixl::aarch32::LSL, VixlReg(src1)));
1932     GetMasm()->Subs(VixlReg(tmpReg), VixlReg(src1), VixlImm(WORD_SIZE));
1933     GetMasm()->Lsl(Convert(Condition::PL), VixlReg(hiReg), VixlReg(src0), VixlReg(tmpReg));
1934     GetMasm()->Mov(Convert(Condition::PL), VixlReg(dst), VixlImm(0x0));
1935     GetMasm()->Lsl(Convert(Condition::MI), VixlReg(dst), VixlReg(src0), VixlReg(src1));
1936     GetMasm()->Mov(VixlRegU(dst), VixlReg(hiReg));
1937 }
1938 
EncodeShr(Reg dst,Reg src0,Reg src1)1939 void Aarch32Encoder::EncodeShr(Reg dst, Reg src0, Reg src1)
1940 {
1941     if (dst.GetSize() < WORD_SIZE) {
1942         GetMasm()->And(VixlReg(src1), VixlReg(src1), VixlImm(dst.GetSize() - 1));
1943     }
1944 
1945     if (dst.GetSize() <= WORD_SIZE) {
1946         GetMasm()->Lsr(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1947         return;
1948     }
1949 
1950     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
1951     ScopedTmpRegU32 loReg(this);
1952     ScopedTmpRegU32 tmpReg(this);
1953 
1954     GetMasm()->Rsb(VixlReg(tmpReg), VixlReg(src1), VixlImm(WORD_SIZE));
1955     GetMasm()->Lsr(VixlReg(loReg), VixlReg(src0), VixlReg(src1));
1956     GetMasm()->Orr(VixlReg(loReg), VixlReg(loReg),
1957                    vixl::aarch32::Operand(VixlRegU(src0), vixl::aarch32::LSL, VixlReg(tmpReg)));
1958     GetMasm()->Subs(VixlReg(tmpReg), VixlReg(src1), VixlImm(WORD_SIZE));
1959     GetMasm()->Lsr(Convert(Condition::PL), VixlReg(loReg), VixlRegU(src0), VixlReg(tmpReg));
1960     GetMasm()->Mov(Convert(Condition::PL), VixlRegU(dst), VixlImm(0x0));
1961     GetMasm()->Lsr(Convert(Condition::MI), VixlRegU(dst), VixlRegU(src0), VixlReg(src1));
1962     GetMasm()->Mov(VixlReg(dst), VixlReg(loReg));
1963 }
1964 
EncodeAShr(Reg dst,Reg src0,Reg src1)1965 void Aarch32Encoder::EncodeAShr(Reg dst, Reg src0, Reg src1)
1966 {
1967     if (dst.GetSize() < WORD_SIZE) {
1968         GetMasm()->And(VixlReg(src1), VixlReg(src1), VixlImm(dst.GetSize() - 1));
1969     }
1970 
1971     if (dst.GetSize() <= WORD_SIZE) {
1972         GetMasm()->Asr(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1973         return;
1974     }
1975 
1976     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
1977     ScopedTmpRegU32 loReg(this);
1978     ScopedTmpRegU32 tmpReg(this);
1979 
1980     GetMasm()->Subs(VixlReg(tmpReg), VixlReg(src1), VixlImm(WORD_SIZE));
1981     GetMasm()->Lsr(VixlReg(loReg), VixlReg(src0), VixlReg(src1));
1982     GetMasm()->Rsb(VixlReg(tmpReg), VixlReg(src1), VixlImm(WORD_SIZE));
1983     GetMasm()->Orr(VixlReg(loReg), VixlReg(loReg),
1984                    vixl::aarch32::Operand(VixlRegU(src0), vixl::aarch32::LSL, VixlReg(tmpReg)));
1985     GetMasm()->Rsb(Convert(Condition::PL), VixlReg(tmpReg), VixlReg(tmpReg), VixlImm(0x0));
1986     GetMasm()->Asr(Convert(Condition::PL), VixlReg(loReg), VixlRegU(src0), VixlReg(tmpReg));
1987     GetMasm()->Asr(Convert(Condition::PL), VixlRegU(dst), VixlRegU(src0), VixlImm(WORD_SIZE - 1));
1988     GetMasm()->Asr(Convert(Condition::MI), VixlRegU(dst), VixlRegU(src0), VixlReg(src1));
1989     GetMasm()->Mov(VixlReg(dst), VixlReg(loReg));
1990 }
1991 
EncodeAnd(Reg dst,Reg src0,Reg src1)1992 void Aarch32Encoder::EncodeAnd(Reg dst, Reg src0, Reg src1)
1993 {
1994     GetMasm()->And(VixlReg(dst), VixlReg(src0), VixlReg(src1));
1995     if (dst.GetSize() > WORD_SIZE) {
1996         GetMasm()->And(VixlRegU(dst), VixlRegU(src0), VixlRegU(src1));
1997     }
1998 }
1999 
EncodeOr(Reg dst,Reg src0,Reg src1)2000 void Aarch32Encoder::EncodeOr(Reg dst, Reg src0, Reg src1)
2001 {
2002     GetMasm()->Orr(VixlReg(dst), VixlReg(src0), VixlReg(src1));
2003     if (dst.GetSize() > WORD_SIZE) {
2004         GetMasm()->Orr(VixlRegU(dst), VixlRegU(src0), VixlRegU(src1));
2005     }
2006 }
2007 
EncodeXor(Reg dst,Reg src0,Reg src1)2008 void Aarch32Encoder::EncodeXor(Reg dst, Reg src0, Reg src1)
2009 {
2010     GetMasm()->Eor(VixlReg(dst), VixlReg(src0), VixlReg(src1));
2011     if (dst.GetSize() > WORD_SIZE) {
2012         GetMasm()->Eor(VixlRegU(dst), VixlRegU(src0), VixlRegU(src1));
2013     }
2014 }
2015 
EncodeAdd(Reg dst,Reg src,Imm imm)2016 void Aarch32Encoder::EncodeAdd(Reg dst, Reg src, Imm imm)
2017 {
2018     ASSERT(dst.IsScalar() && "UNIMPLEMENTED");
2019     if (dst.GetSize() <= WORD_SIZE) {
2020         GetMasm()->Add(VixlReg(dst), VixlReg(src), VixlImm(imm));
2021         return;
2022     }
2023 
2024     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
2025     GetMasm()->Adds(VixlReg(dst), VixlReg(src), VixlImm(imm));
2026     GetMasm()->Adc(VixlRegU(dst), VixlRegU(src), VixlImmU(imm));
2027 }
2028 
EncodeSub(Reg dst,Reg src,Imm imm)2029 void Aarch32Encoder::EncodeSub(Reg dst, Reg src, Imm imm)
2030 {
2031     ASSERT(dst.IsScalar() && "UNIMPLEMENTED");
2032     if (dst.GetSize() <= WORD_SIZE) {
2033         GetMasm()->Sub(VixlReg(dst), VixlReg(src), VixlImm(imm));
2034         return;
2035     }
2036 
2037     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
2038     GetMasm()->Subs(VixlReg(dst), VixlReg(src), VixlImm(imm));
2039     GetMasm()->Sbc(VixlRegU(dst), VixlRegU(src), VixlImmU(imm));
2040 }
2041 
EncodeShl(Reg dst,Reg src,Imm imm)2042 void Aarch32Encoder::EncodeShl(Reg dst, Reg src, Imm imm)
2043 {
2044     auto value = static_cast<uint32_t>(imm.GetAsInt());
2045     int32_t immValue = value & (dst.GetSize() - 1);
2046 
2047     ASSERT(dst.IsScalar() && "Invalid operand type");
2048     if (dst.GetSize() <= WORD_SIZE) {
2049         GetMasm()->Lsl(VixlReg(dst), VixlReg(src), VixlImm(immValue));
2050         return;
2051     }
2052 
2053     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
2054     ScopedTmpRegU32 hiReg(this);
2055     ScopedTmpRegU32 tmpReg(this);
2056 
2057     GetMasm()->Lsr(VixlReg(tmpReg), VixlReg(src), VixlImm(WORD_SIZE - immValue));
2058     GetMasm()->Mov(VixlReg(hiReg), VixlImm(immValue));
2059     GetMasm()->Orr(VixlReg(hiReg), VixlReg(tmpReg),
2060                    vixl::aarch32::Operand(VixlRegU(src), vixl::aarch32::LSL, VixlReg(hiReg)));
2061     GetMasm()->Movs(VixlReg(tmpReg), VixlImm(immValue - WORD_SIZE));
2062     GetMasm()->Lsl(Convert(Condition::PL), VixlReg(hiReg), VixlReg(src), VixlReg(tmpReg));
2063     GetMasm()->Mov(Convert(Condition::PL), VixlReg(dst), VixlImm(0x0));
2064     GetMasm()->Lsl(Convert(Condition::MI), VixlReg(dst), VixlReg(src), VixlImm(immValue));
2065     GetMasm()->Mov(VixlRegU(dst), VixlReg(hiReg));
2066 }
2067 
EncodeShr(Reg dst,Reg src,Imm imm)2068 void Aarch32Encoder::EncodeShr(Reg dst, Reg src, Imm imm)
2069 {
2070     auto value = static_cast<uint32_t>(imm.GetAsInt());
2071     int32_t immValue = value & (dst.GetSize() - 1);
2072 
2073     ASSERT(dst.IsScalar() && "Invalid operand type");
2074     if (dst.GetSize() <= WORD_SIZE) {
2075         GetMasm()->Lsr(VixlReg(dst), VixlReg(src), immValue);
2076         return;
2077     }
2078 
2079     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
2080     ScopedTmpRegU32 loReg(this);
2081     ScopedTmpRegU32 tmpReg(this);
2082 
2083     GetMasm()->Mov(VixlReg(tmpReg), VixlImm(WORD_SIZE - immValue));
2084     GetMasm()->Lsr(VixlReg(loReg), VixlReg(src), VixlImm(immValue));
2085     GetMasm()->Orr(VixlReg(loReg), VixlReg(loReg),
2086                    vixl::aarch32::Operand(VixlRegU(src), vixl::aarch32::LSL, VixlReg(tmpReg)));
2087     GetMasm()->Movs(VixlReg(tmpReg), VixlImm(immValue - WORD_SIZE));
2088     GetMasm()->Lsr(Convert(Condition::PL), VixlReg(loReg), VixlRegU(src), VixlReg(tmpReg));
2089     GetMasm()->Mov(Convert(Condition::PL), VixlRegU(dst), VixlImm(0x0));
2090     GetMasm()->Lsr(Convert(Condition::MI), VixlRegU(dst), VixlRegU(src), VixlImm(immValue));
2091     GetMasm()->Mov(VixlReg(dst), VixlReg(loReg));
2092 }
2093 
EncodeAShr(Reg dst,Reg src,Imm imm)2094 void Aarch32Encoder::EncodeAShr(Reg dst, Reg src, Imm imm)
2095 {
2096     ASSERT(dst.IsScalar() && "Invalid operand type");
2097 
2098     auto value = static_cast<uint32_t>(imm.GetAsInt());
2099     int32_t immValue = value & (dst.GetSize() - 1);
2100 
2101     if (dst.GetSize() <= WORD_SIZE) {
2102         GetMasm()->Asr(VixlReg(dst), VixlReg(src), immValue);
2103         return;
2104     }
2105 
2106     ScopedTmpRegU32 loReg(this);
2107     ScopedTmpRegU32 tmpReg(this);
2108     GetMasm()->Movs(VixlReg(tmpReg), VixlImm(immValue - WORD_SIZE));
2109     GetMasm()->Lsr(VixlReg(loReg), VixlReg(src), VixlImm(immValue));
2110     GetMasm()->Mov(VixlReg(tmpReg), VixlImm(WORD_SIZE - immValue));
2111     GetMasm()->Orr(VixlReg(loReg), VixlReg(loReg),
2112                    vixl::aarch32::Operand(VixlRegU(src), vixl::aarch32::LSL, VixlReg(tmpReg)));
2113     GetMasm()->Rsb(Convert(Condition::PL), VixlReg(tmpReg), VixlReg(tmpReg), VixlImm(0x0));
2114     GetMasm()->Asr(Convert(Condition::PL), VixlReg(loReg), VixlRegU(src), VixlReg(tmpReg));
2115     GetMasm()->Asr(Convert(Condition::PL), VixlRegU(dst), VixlRegU(src), VixlImm(WORD_SIZE - 1));
2116     GetMasm()->Asr(Convert(Condition::MI), VixlRegU(dst), VixlRegU(src), VixlImm(immValue));
2117     GetMasm()->Mov(VixlReg(dst), VixlReg(loReg));
2118 }
2119 
EncodeAnd(Reg dst,Reg src,Imm imm)2120 void Aarch32Encoder::EncodeAnd(Reg dst, Reg src, Imm imm)
2121 {
2122     ASSERT(dst.IsScalar() && "Invalid operand type");
2123     GetMasm()->And(VixlReg(dst), VixlReg(src), VixlImm(imm));
2124     if (dst.GetSize() > WORD_SIZE) {
2125         GetMasm()->And(VixlRegU(dst), VixlRegU(src), VixlImmU(imm));
2126     }
2127 }
2128 
EncodeOr(Reg dst,Reg src,Imm imm)2129 void Aarch32Encoder::EncodeOr(Reg dst, Reg src, Imm imm)
2130 {
2131     ASSERT(dst.IsScalar() && "Invalid operand type");
2132     GetMasm()->Orr(VixlReg(dst), VixlReg(src), VixlImm(imm));
2133     if (dst.GetSize() > WORD_SIZE) {
2134         GetMasm()->Orr(VixlRegU(dst), VixlRegU(src), VixlImmU(imm));
2135     }
2136 }
2137 
EncodeXor(Reg dst,Reg src,Imm imm)2138 void Aarch32Encoder::EncodeXor(Reg dst, Reg src, Imm imm)
2139 {
2140     ASSERT(dst.IsScalar() && "Invalid operand type");
2141     GetMasm()->Eor(VixlReg(dst), VixlReg(src), VixlImm(imm));
2142     if (dst.GetSize() > WORD_SIZE) {
2143         GetMasm()->Eor(VixlRegU(dst), VixlRegU(src), VixlImmU(imm));
2144     }
2145 }
2146 
EncodeMov(Reg dst,Imm src)2147 void Aarch32Encoder::EncodeMov(Reg dst, Imm src)
2148 {
2149     if (dst.IsFloat()) {
2150         if (dst.GetSize() == WORD_SIZE) {
2151             GetMasm()->Vmov(Convert(dst.GetType()), VixlVReg(dst).S(), VixlNeonImm(src.GetAsFloat()));
2152         } else {
2153             GetMasm()->Vmov(Convert(dst.GetType()), VixlVReg(dst).D(), VixlNeonImm(src.GetAsDouble()));
2154         }
2155         return;
2156     }
2157 
2158     GetMasm()->Mov(VixlReg(dst), VixlImm(src));
2159     if (dst.GetSize() > WORD_SIZE) {
2160         GetMasm()->Mov(VixlRegU(dst), VixlImmU(src));
2161     }
2162 }
2163 
EncodeLdr(Reg dst,bool dstSigned,const vixl::aarch32::MemOperand & vixlMem)2164 void Aarch32Encoder::EncodeLdr(Reg dst, bool dstSigned, const vixl::aarch32::MemOperand &vixlMem)
2165 {
2166     if (dst.IsFloat()) {
2167         if (dst.GetSize() == WORD_SIZE) {
2168             GetMasm()->Vldr(VixlVReg(dst).S(), vixlMem);
2169         } else {
2170             GetMasm()->Vldr(VixlVReg(dst).D(), vixlMem);
2171         }
2172         return;
2173     }
2174     if (dstSigned) {
2175         if (dst.GetSize() == BYTE_SIZE) {
2176             GetMasm()->Ldrsb(VixlReg(dst), vixlMem);
2177             return;
2178         }
2179         if (dst.GetSize() == HALF_SIZE) {
2180             GetMasm()->Ldrsh(VixlReg(dst), vixlMem);
2181             return;
2182         }
2183     } else {
2184         if (dst.GetSize() == BYTE_SIZE) {
2185             GetMasm()->Ldrb(VixlReg(dst), vixlMem);
2186             return;
2187         }
2188         if (dst.GetSize() == HALF_SIZE) {
2189             GetMasm()->Ldrh(VixlReg(dst), vixlMem);
2190             return;
2191         }
2192     }
2193     if (dst.GetSize() == WORD_SIZE) {
2194         GetMasm()->Ldr(VixlReg(dst), vixlMem);
2195         return;
2196     }
2197     ASSERT(dst.GetSize() == DOUBLE_WORD_SIZE);
2198     GetMasm()->Ldrd(VixlReg(dst), VixlRegU(dst), vixlMem);
2199 }
2200 
EncodeLdr(Reg dst,bool dstSigned,MemRef mem)2201 void Aarch32Encoder::EncodeLdr(Reg dst, bool dstSigned, MemRef mem)
2202 {
2203     auto type = dst.GetType();
2204     if (IsNeedToPrepareMemLdS(mem, type, dstSigned)) {
2205         ScopedTmpRegU32 tmpReg(this);
2206         auto tmp = VixlReg(tmpReg);
2207         auto vixlMem = PrepareMemLdS(mem, type, tmp, dstSigned);
2208         EncodeLdr(dst, dstSigned, vixlMem);
2209     } else {
2210         auto vixlMem = ConvertMem(mem);
2211         EncodeLdr(dst, dstSigned, vixlMem);
2212     }
2213 }
2214 
EncodeLdrAcquire(Reg dst,bool dstSigned,MemRef mem)2215 void Aarch32Encoder::EncodeLdrAcquire(Reg dst, bool dstSigned, MemRef mem)
2216 {
2217     EncodeLdr(dst, dstSigned, mem);
2218     GetMasm()->Dmb(vixl::aarch32::MemoryBarrierType::ISH);
2219 }
2220 
EncodeMemoryBarrier(memory_order::Order order)2221 void Aarch32Encoder::EncodeMemoryBarrier(memory_order::Order order)
2222 {
2223     switch (order) {
2224         case memory_order::ACQUIRE:
2225         case memory_order::RELEASE: {
2226             GetMasm()->Dmb(vixl::aarch32::MemoryBarrierType::ISH);
2227             break;
2228         }
2229         case memory_order::FULL: {
2230             GetMasm()->Dmb(vixl::aarch32::MemoryBarrierType::ISHST);
2231             break;
2232         }
2233         default:
2234             break;
2235     }
2236 }
2237 
EncodeStr(Reg src,const vixl::aarch32::MemOperand & vixlMem)2238 void Aarch32Encoder::EncodeStr(Reg src, const vixl::aarch32::MemOperand &vixlMem)
2239 {
2240     if (src.IsFloat()) {
2241         if (src.GetSize() == WORD_SIZE) {
2242             GetMasm()->Vstr(VixlVReg(src).S(), vixlMem);
2243         } else {
2244             GetMasm()->Vstr(VixlVReg(src).D(), vixlMem);
2245         }
2246     } else if (src.GetSize() == BYTE_SIZE) {
2247         GetMasm()->Strb(VixlReg(src), vixlMem);
2248     } else if (src.GetSize() == HALF_SIZE) {
2249         GetMasm()->Strh(VixlReg(src), vixlMem);
2250     } else if (src.GetSize() == WORD_SIZE) {
2251         GetMasm()->Str(VixlReg(src), vixlMem);
2252     } else {
2253         ASSERT(src.GetSize() == DOUBLE_WORD_SIZE);
2254         GetMasm()->Strd(VixlReg(src), VixlRegU(src), vixlMem);
2255     }
2256 }
2257 
EncodeStr(Reg src,MemRef mem)2258 void Aarch32Encoder::EncodeStr(Reg src, MemRef mem)
2259 {
2260     auto type = src.GetType();
2261     if (IsNeedToPrepareMemLdS(mem, type, false)) {
2262         ScopedTmpRegU32 tmpReg(this);
2263         auto tmp = VixlReg(tmpReg);
2264         auto vixlMem = PrepareMemLdS(mem, type, tmp, false);
2265         EncodeStr(src, vixlMem);
2266     } else {
2267         auto vixlMem = ConvertMem(mem);
2268         EncodeStr(src, vixlMem);
2269     }
2270 }
2271 
EncodeStrRelease(Reg src,MemRef mem)2272 void Aarch32Encoder::EncodeStrRelease(Reg src, MemRef mem)
2273 {
2274     GetMasm()->Dmb(vixl::aarch32::MemoryBarrierType::ISH);
2275     EncodeStr(src, mem);
2276     GetMasm()->Dmb(vixl::aarch32::MemoryBarrierType::ISH);
2277 }
2278 
EncodeStrz(Reg src,MemRef mem)2279 void Aarch32Encoder::EncodeStrz(Reg src, MemRef mem)
2280 {
2281     if (src.GetSize() <= WORD_SIZE) {
2282         EncodeSti(0, DOUBLE_WORD_SIZE_BYTES, mem);
2283     }
2284     EncodeStr(src, mem);
2285 }
2286 
EncodeStp(Reg src0,Reg src1,MemRef mem)2287 void Aarch32Encoder::EncodeStp(Reg src0, Reg src1, MemRef mem)
2288 {
2289     ASSERT(src0.IsFloat() == src1.IsFloat());
2290     ASSERT(src0.GetSize() == src1.GetSize());
2291     EncodeStr(src0, mem);
2292     EncodeStr(src1, MemRef(mem.GetBase(), mem.GetIndex(), mem.GetScale(), mem.GetDisp() + WORD_SIZE_BYTES));
2293 }
2294 
EncodeLdrExclusive(Reg dst,Reg addr,bool acquire)2295 void Aarch32Encoder::EncodeLdrExclusive(Reg dst, Reg addr, bool acquire)
2296 {
2297     ASSERT(dst.IsScalar());
2298     auto dstReg = VixlReg(dst);
2299     auto memCvt = ConvertMem(MemRef(addr));
2300     if (dst.GetSize() == BYTE_SIZE) {
2301         if (acquire) {
2302             GetMasm()->Ldaexb(dstReg, memCvt);
2303             return;
2304         }
2305         GetMasm()->Ldrexb(dstReg, memCvt);
2306         return;
2307     }
2308     if (dst.GetSize() == HALF_SIZE) {
2309         if (acquire) {
2310             GetMasm()->Ldaexh(dstReg, memCvt);
2311             return;
2312         }
2313         GetMasm()->Ldrexh(dstReg, memCvt);
2314         return;
2315     }
2316     if (dst.GetSize() == DOUBLE_WORD_SIZE) {
2317         auto dstRegU = VixlRegU(dst);
2318         if (acquire) {
2319             GetMasm()->Ldaexd(dstReg, dstRegU, memCvt);
2320             return;
2321         }
2322         GetMasm()->Ldrexd(dstReg, dstRegU, memCvt);
2323         return;
2324     }
2325     if (acquire) {
2326         GetMasm()->Ldaex(dstReg, memCvt);
2327         return;
2328     }
2329     GetMasm()->Ldrex(dstReg, memCvt);
2330 }
2331 
EncodeStrExclusive(Reg dst,Reg src,Reg addr,bool release)2332 void Aarch32Encoder::EncodeStrExclusive(Reg dst, Reg src, Reg addr, bool release)
2333 {
2334     ASSERT(dst.IsScalar() && src.IsScalar());
2335     ASSERT(dst.GetSize() != DOUBLE_WORD_SIZE);
2336 
2337     bool copyDst = dst.GetId() == src.GetId() || dst.GetId() == addr.GetId();
2338     ScopedTmpReg tmp(this);
2339     auto dstReg = copyDst ? VixlReg(tmp) : VixlReg(dst);
2340     auto srcReg = VixlReg(src);
2341     auto memCvt = ConvertMem(MemRef(addr));
2342 
2343     if (src.GetSize() == BYTE_SIZE) {
2344         if (release) {
2345             GetMasm()->Stlexb(dstReg, srcReg, memCvt);
2346         } else {
2347             GetMasm()->Strexb(dstReg, srcReg, memCvt);
2348         }
2349     } else if (src.GetSize() == HALF_SIZE) {
2350         if (release) {
2351             GetMasm()->Stlexh(dstReg, srcReg, memCvt);
2352         } else {
2353             GetMasm()->Strexh(dstReg, srcReg, memCvt);
2354         }
2355     } else if (src.GetSize() == DOUBLE_WORD_SIZE) {
2356         auto srcRegU = VixlRegU(src);
2357         if (release) {
2358             GetMasm()->Stlexd(dstReg, srcReg, srcRegU, memCvt);
2359         } else {
2360             GetMasm()->Strexd(dstReg, srcReg, srcRegU, memCvt);
2361         }
2362     } else {
2363         if (release) {
2364             GetMasm()->Stlex(dstReg, srcReg, memCvt);
2365         } else {
2366             GetMasm()->Strex(dstReg, srcReg, memCvt);
2367         }
2368     }
2369 
2370     if (copyDst) {
2371         EncodeMov(dst, tmp);
2372     }
2373 }
2374 
FindRegForMem(vixl::aarch32::MemOperand mem)2375 inline static int32_t FindRegForMem(vixl::aarch32::MemOperand mem)
2376 {
2377     int32_t baseRegId = mem.GetBaseRegister().GetCode();
2378     int32_t indexRegId = -1;
2379     if (mem.IsShiftedRegister()) {
2380         indexRegId = mem.GetOffsetRegister().GetCode();
2381     }
2382     // find regs for mem
2383     constexpr int32_t STEP = 2;
2384     for (int32_t i = 0; i < static_cast<int32_t>(BYTE_SIZE); i += STEP) {
2385         if (baseRegId == i || baseRegId == i + 1 || indexRegId == i || indexRegId == i + 1) {
2386             continue;
2387         }
2388         return i;
2389     }
2390     UNREACHABLE();
2391     return -1;
2392 }
2393 
EncodeSti(int64_t src,uint8_t srcSizeBytes,MemRef mem)2394 void Aarch32Encoder::EncodeSti(int64_t src, uint8_t srcSizeBytes, MemRef mem)
2395 {
2396     ScopedTmpRegU32 tmpReg(this);
2397     auto tmp = VixlReg(tmpReg);
2398     auto type = TypeInfo::GetScalarTypeBySize(srcSizeBytes * BITS_PER_BYTE);
2399     if (srcSizeBytes <= WORD_SIZE_BYTES) {
2400         auto vixlMem = PrepareMemLdS(mem, type, tmp, false);
2401         if (vixlMem.GetBaseRegister().GetCode() == tmp.GetCode()) {
2402             ScopedTmpRegU32 tmp1Reg(this);
2403             tmp = VixlReg(tmp1Reg);
2404         }
2405         GetMasm()->Mov(tmp, VixlImm(src));
2406         if (srcSizeBytes == 1) {
2407             GetMasm()->Strb(tmp, vixlMem);
2408             return;
2409         }
2410         if (srcSizeBytes == HALF_WORD_SIZE_BYTES) {
2411             GetMasm()->Strh(tmp, vixlMem);
2412             return;
2413         }
2414         GetMasm()->Str(tmp, vixlMem);
2415         return;
2416     }
2417 
2418     auto vixlMem = PrepareMemLdS(mem, type, tmp, false, true);
2419     ASSERT(srcSizeBytes == DOUBLE_WORD_SIZE_BYTES);
2420     vixl::aarch32::Register tmpImm1;
2421     vixl::aarch32::Register tmpImm2;
2422     // if tmp isn't base reg and tmp is even and tmp+1 isn't SP we can use tmp and tmp + 1
2423     if (vixlMem.GetBaseRegister().GetCode() != tmp.GetCode() && (tmp.GetCode() % 2U == 0) &&
2424         tmp.GetCode() + 1 != vixl::aarch32::sp.GetCode()) {
2425         tmpImm1 = tmp;
2426         tmpImm2 = vixl::aarch32::Register(tmp.GetCode() + 1);
2427     } else {
2428         auto regId = FindRegForMem(vixlMem);
2429         ASSERT(regId != -1);
2430         tmpImm1 = vixl::aarch32::Register(regId);
2431         tmpImm2 = vixl::aarch32::Register(regId + 1);
2432         GetMasm()->Push(tmpImm1);
2433     }
2434 
2435     ASSERT(tmpImm1.IsValid() && tmpImm2.IsValid());
2436     GetMasm()->Push(tmpImm2);
2437     GetMasm()->Mov(tmpImm1, VixlImm(Imm(src)));
2438     GetMasm()->Mov(tmpImm2, VixlImmU(Imm(src)));
2439     GetMasm()->Strd(tmpImm1, tmpImm2, vixlMem);
2440     GetMasm()->Pop(tmpImm2);
2441     if (tmpImm1.GetCode() != tmp.GetCode()) {
2442         GetMasm()->Pop(tmpImm1);
2443     }
2444 }
2445 
EncodeSti(float src,MemRef mem)2446 void Aarch32Encoder::EncodeSti(float src, MemRef mem)
2447 {
2448     ScopedTmpRegF32 tmpReg(this);
2449     GetMasm()->Vmov(VixlVReg(tmpReg).S(), src);
2450     EncodeStr(tmpReg, mem);
2451 }
2452 
EncodeSti(double src,MemRef mem)2453 void Aarch32Encoder::EncodeSti(double src, MemRef mem)
2454 {
2455     ScopedTmpRegF64 tmpReg(this);
2456     GetMasm()->Vmov(VixlVReg(tmpReg).D(), src);
2457     EncodeStr(tmpReg, mem);
2458 }
2459 
EncodeMemCopy(MemRef memFrom,MemRef memTo,size_t size)2460 void Aarch32Encoder::EncodeMemCopy(MemRef memFrom, MemRef memTo, size_t size)
2461 {
2462     if (size == DOUBLE_WORD_SIZE && memFrom.IsOffsetMem() && memTo.IsOffsetMem()) {
2463         EncodeMemCopy(memFrom, memTo, WORD_SIZE);
2464         constexpr int32_t STEP = 4;
2465         auto offsetFrom = memFrom.GetDisp() + STEP;
2466         auto offsetTo = memTo.GetDisp() + STEP;
2467         EncodeMemCopy(MemRef(memFrom.GetBase(), offsetFrom), MemRef(memTo.GetBase(), offsetTo), WORD_SIZE);
2468 
2469         return;
2470     }
2471     ScopedTmpRegU32 tmpReg(this);
2472     auto tmp = VixlReg(tmpReg);
2473     ScopedTmpRegU32 tmpReg1(this);
2474     auto tmp1 = VixlReg(tmpReg1);
2475     if (size == BYTE_SIZE) {
2476         GetMasm()->Ldrb(tmp, PrepareMemLdS(memFrom, INT8_TYPE, tmp, false));
2477         GetMasm()->Strb(tmp, PrepareMemLdS(memTo, INT8_TYPE, tmp1, false));
2478     } else if (size == HALF_SIZE) {
2479         GetMasm()->Ldrh(tmp, PrepareMemLdS(memFrom, INT16_TYPE, tmp, false));
2480         GetMasm()->Strh(tmp, PrepareMemLdS(memTo, INT16_TYPE, tmp1, false));
2481     } else if (size == WORD_SIZE) {
2482         GetMasm()->Ldr(tmp, PrepareMemLdS(memFrom, INT32_TYPE, tmp, false));
2483         GetMasm()->Str(tmp, PrepareMemLdS(memTo, INT32_TYPE, tmp1, false));
2484     } else {
2485         ASSERT(size == DOUBLE_WORD_SIZE);
2486 
2487         auto vixlMemFrom = PrepareMemLdS(memFrom, INT64_TYPE, tmp, false, true);
2488         auto vixlMemTo = PrepareMemLdS(memTo, INT64_TYPE, tmp1, false, true);
2489         auto regId = FindRegForMem(vixlMemTo);
2490         ASSERT(regId != -1);
2491         [[maybe_unused]] constexpr auto IMM_2 = 2;
2492         ASSERT(regId % IMM_2 == 0);
2493         vixl::aarch32::Register tmpCopy1(regId);
2494         vixl::aarch32::Register tmpCopy2(regId + 1);
2495 
2496         GetMasm()->Push(tmpCopy1);
2497         GetMasm()->Push(tmpCopy2);
2498         GetMasm()->Ldrd(tmpCopy1, tmpCopy2, vixlMemFrom);
2499         GetMasm()->Strd(tmpCopy1, tmpCopy2, vixlMemTo);
2500         GetMasm()->Pop(tmpCopy2);
2501         GetMasm()->Pop(tmpCopy1);
2502     }
2503 }
2504 
EncodeMemCopyz(MemRef memFrom,MemRef memTo,size_t size)2505 void Aarch32Encoder::EncodeMemCopyz(MemRef memFrom, MemRef memTo, size_t size)
2506 {
2507     ScopedTmpRegU32 tmpReg(this);
2508     auto tmp = VixlReg(tmpReg);
2509     ScopedTmpRegU32 tmpReg1(this);
2510     auto tmp1 = VixlReg(tmpReg1);
2511 
2512     auto type = TypeInfo::GetScalarTypeBySize(size);
2513 
2514     auto vixlMemFrom = PrepareMemLdS(memFrom, type, tmp, false, true);
2515     auto vixlMemTo = PrepareMemLdS(memTo, INT64_TYPE, tmp1, false, true);
2516     auto regId = FindRegForMem(vixlMemTo);
2517     ASSERT(regId != -1);
2518     [[maybe_unused]] constexpr auto IMM_2 = 2;
2519     ASSERT(regId % IMM_2 == 0);
2520     vixl::aarch32::Register tmpCopy1(regId);
2521     vixl::aarch32::Register tmpCopy2(regId + 1);
2522 
2523     GetMasm()->Push(tmpCopy1);
2524     GetMasm()->Push(tmpCopy2);
2525     if (size == BYTE_SIZE) {
2526         GetMasm()->Ldrb(tmpCopy1, vixlMemFrom);
2527         GetMasm()->Mov(tmpCopy2, VixlImm(0));
2528         GetMasm()->Strd(tmpCopy1, tmpCopy2, vixlMemTo);
2529     } else if (size == HALF_SIZE) {
2530         GetMasm()->Ldrh(tmpCopy1, vixlMemFrom);
2531         GetMasm()->Mov(tmpCopy2, VixlImm(0));
2532         GetMasm()->Strd(tmpCopy1, tmpCopy2, vixlMemTo);
2533     } else if (size == WORD_SIZE) {
2534         GetMasm()->Ldr(tmpCopy1, vixlMemFrom);
2535         GetMasm()->Mov(tmpCopy2, VixlImm(0));
2536         GetMasm()->Strd(tmpCopy1, tmpCopy2, vixlMemTo);
2537     } else {
2538         ASSERT(size == DOUBLE_WORD_SIZE);
2539         GetMasm()->Ldrd(tmpCopy1, tmpCopy2, vixlMemFrom);
2540         GetMasm()->Strd(tmpCopy1, tmpCopy2, vixlMemTo);
2541     }
2542     GetMasm()->Pop(tmpCopy2);
2543     GetMasm()->Pop(tmpCopy1);
2544 }
2545 
CompareHelper(Reg src0,Reg src1,Condition * cc)2546 void Aarch32Encoder::CompareHelper(Reg src0, Reg src1, Condition *cc)
2547 {
2548     if (src0.IsFloat() && src1.IsFloat()) {
2549         GetMasm()->Vcmp(VixlVReg(src0), VixlVReg(src1));
2550         GetMasm()->Vmrs(vixl::aarch32::RegisterOrAPSR_nzcv(vixl::aarch32::kPcCode), vixl::aarch32::FPSCR);
2551     } else if (src0.GetSize() <= WORD_SIZE && src1.GetSize() <= WORD_SIZE) {
2552         GetMasm()->Cmp(VixlReg(src0), VixlReg(src1));
2553     } else {
2554         if (!IsConditionSigned(*cc)) {
2555             GetMasm()->Cmp(VixlRegU(src0), VixlRegU(src1));
2556             GetMasm()->Cmp(Convert(Condition::EQ), VixlReg(src0), VixlReg(src1));
2557         } else {
2558             bool swap = false;
2559             switch (*cc) {
2560                 case Condition::GT:
2561                     swap = true;
2562                     *cc = Condition::LT;
2563                     break;
2564                 case Condition::LE:
2565                     swap = true;
2566                     *cc = Condition::GE;
2567                     break;
2568                 case Condition::GE:
2569                 case Condition::LT:
2570                     break;
2571                 default:
2572                     UNREACHABLE();
2573             }
2574 
2575             Reg op0 = swap ? src1 : src0;
2576             Reg op1 = swap ? src0 : src1;
2577             ScopedTmpRegU32 tmpReg(this);
2578             GetMasm()->Cmp(VixlReg(op0), VixlReg(op1));
2579             GetMasm()->Sbcs(VixlReg(tmpReg), VixlRegU(op0), VixlRegU(op1));
2580         }
2581     }
2582 }
2583 
TestHelper(Reg src0,Reg src1,Condition cc)2584 void Aarch32Encoder::TestHelper(Reg src0, Reg src1, [[maybe_unused]] Condition cc)
2585 {
2586     ASSERT(!src0.IsFloat() && !src1.IsFloat());
2587     ASSERT(cc == Condition::TST_EQ || cc == Condition::TST_NE);
2588 
2589     if (src0.GetSize() <= WORD_SIZE && src1.GetSize() <= WORD_SIZE) {
2590         GetMasm()->Tst(VixlReg(src0), VixlReg(src1));
2591     } else {
2592         GetMasm()->Tst(VixlRegU(src0), VixlRegU(src1));
2593         GetMasm()->Tst(Convert(Condition::EQ), VixlReg(src0), VixlReg(src1));
2594     }
2595 }
2596 
EncodeCompare(Reg dst,Reg src0,Reg src1,Condition cc)2597 void Aarch32Encoder::EncodeCompare(Reg dst, Reg src0, Reg src1, Condition cc)
2598 {
2599     CompareHelper(src0, src1, &cc);
2600     GetMasm()->Mov(Convert(cc), VixlReg(dst), 0x1);
2601     GetMasm()->Mov(Convert(cc).Negate(), VixlReg(dst), 0x0);
2602 }
2603 
EncodeCompareTest(Reg dst,Reg src0,Reg src1,Condition cc)2604 void Aarch32Encoder::EncodeCompareTest(Reg dst, Reg src0, Reg src1, Condition cc)
2605 {
2606     TestHelper(src0, src1, cc);
2607     GetMasm()->Mov(ConvertTest(cc), VixlReg(dst), 0x1);
2608     GetMasm()->Mov(ConvertTest(cc).Negate(), VixlReg(dst), 0x0);
2609 }
2610 
EncodeCmp(Reg dst,Reg src0,Reg src1,Condition cc)2611 void Aarch32Encoder::EncodeCmp(Reg dst, Reg src0, Reg src1, Condition cc)
2612 {
2613     if (src0.IsFloat()) {
2614         ASSERT(src1.IsFloat());
2615         ASSERT(cc == Condition::MI || cc == Condition::LT);
2616         GetMasm()->Vcmp(VixlVReg(src0), VixlVReg(src1));
2617         GetMasm()->Vmrs(vixl::aarch32::RegisterOrAPSR_nzcv(vixl::aarch32::kPcCode), vixl::aarch32::FPSCR);
2618     } else {
2619         ASSERT(src0.IsScalar() && src1.IsScalar());
2620         ASSERT(cc == Condition::LO || cc == Condition::LT);
2621         if (src0.GetSize() <= WORD_SIZE && src1.GetSize() <= WORD_SIZE) {
2622             GetMasm()->Cmp(VixlReg(src0), VixlReg(src1));
2623         } else {
2624             if (cc == Condition::LO) {
2625                 GetMasm()->Cmp(VixlRegU(src0), VixlRegU(src1));
2626                 GetMasm()->Cmp(Convert(Condition::EQ), VixlReg(src0), VixlReg(src1));
2627             } else if (cc == Condition::LT) {
2628                 auto labelHolder = static_cast<Aarch32LabelHolder *>(GetLabels());
2629                 auto endLabel = labelHolder->CreateLabel();
2630                 ScopedTmpRegU32 tmpReg(this);
2631 
2632                 GetMasm()->Cmp(VixlReg(src0), VixlReg(src1));
2633                 GetMasm()->Sbcs(VixlReg(tmpReg), VixlRegU(src0), VixlRegU(src1));
2634                 GetMasm()->Mov(Convert(Condition::LT), VixlReg(dst), VixlImm(-1));
2635                 GetMasm()->B(Convert(Condition::LT), labelHolder->GetLabel(endLabel));
2636 
2637                 GetMasm()->Cmp(VixlReg(src1), VixlReg(src0));
2638                 GetMasm()->Sbcs(VixlReg(tmpReg), VixlRegU(src1), VixlRegU(src0));
2639                 GetMasm()->Mov(Convert(Condition::LT), VixlReg(dst), VixlImm(1));
2640                 GetMasm()->Mov(Convert(Condition::EQ), VixlReg(dst), VixlImm(0));
2641 
2642                 labelHolder->BindLabel(endLabel);
2643                 return;
2644             } else {
2645                 UNREACHABLE();
2646             }
2647         }
2648     }
2649 
2650     GetMasm()->Mov(Convert(Condition::EQ), VixlReg(dst), VixlImm(0x0));
2651     GetMasm()->Mov(Convert(Condition::NE), VixlReg(dst), VixlImm(0x1));
2652 
2653     GetMasm()->Rsb(Convert(cc), VixlReg(dst), VixlReg(dst), VixlImm(0x0));
2654 }
2655 
EncodeStackOverflowCheck(ssize_t offset)2656 void Aarch32Encoder::EncodeStackOverflowCheck(ssize_t offset)
2657 {
2658     ScopedTmpReg tmp(this);
2659     EncodeAdd(tmp, GetTarget().GetStackReg(), Imm(offset));
2660     EncodeLdr(tmp, false, MemRef(tmp));
2661 }
2662 
EncodeSelect(Reg dst,Reg src0,Reg src1,Reg src2,Reg src3,Condition cc)2663 void Aarch32Encoder::EncodeSelect(Reg dst, Reg src0, Reg src1, Reg src2, Reg src3, Condition cc)
2664 {
2665     ASSERT(!src0.IsFloat() && !src1.IsFloat());
2666 
2667     CompareHelper(src2, src3, &cc);
2668 
2669     GetMasm()->Mov(Convert(cc), VixlReg(dst), VixlReg(src0));
2670     GetMasm()->Mov(Convert(cc).Negate(), VixlReg(dst), VixlReg(src1));
2671 
2672     if (src0.GetSize() > WORD_SIZE || src1.GetSize() > WORD_SIZE) {
2673         GetMasm()->Mov(Convert(cc), VixlRegU(dst), VixlRegU(src0));
2674         GetMasm()->Mov(Convert(cc).Negate(), VixlRegU(dst), VixlRegU(src1));
2675     }
2676 }
2677 
EncodeSelect(Reg dst,Reg src0,Reg src1,Reg src2,Imm imm,Condition cc)2678 void Aarch32Encoder::EncodeSelect(Reg dst, Reg src0, Reg src1, Reg src2, Imm imm, Condition cc)
2679 {
2680     ASSERT(!src0.IsFloat() && !src1.IsFloat() && !src2.IsFloat());
2681     auto value = imm.GetAsInt();
2682     if (value == 0) {
2683         switch (cc) {
2684             case Condition::LO:
2685                 // LO is always false, select src1
2686                 GetMasm()->Mov(VixlReg(dst), VixlReg(src1));
2687                 if (src0.GetSize() > WORD_SIZE || src1.GetSize() > WORD_SIZE) {
2688                     GetMasm()->Mov(VixlRegU(dst), VixlRegU(src1));
2689                 }
2690                 return;
2691             case Condition::HS:
2692                 // HS is always true, select src0
2693                 GetMasm()->Mov(VixlReg(dst), VixlReg(src0));
2694                 if (src0.GetSize() > WORD_SIZE || src1.GetSize() > WORD_SIZE) {
2695                     GetMasm()->Mov(VixlRegU(dst), VixlRegU(src0));
2696                 }
2697                 return;
2698             case Condition::LS:
2699                 // LS is same as EQ
2700                 cc = Condition::EQ;
2701                 break;
2702             case Condition::HI:
2703                 // HI is same as NE
2704                 cc = Condition::NE;
2705                 break;
2706             default:
2707                 break;
2708         }
2709         CompareZeroHelper(src2, &cc);
2710     } else {  // value != 0
2711         if (!CompareImmHelper(src2, value, &cc)) {
2712             return;
2713         }
2714     }
2715 
2716     GetMasm()->Mov(Convert(cc), VixlReg(dst), VixlReg(src0));
2717     GetMasm()->Mov(Convert(cc).Negate(), VixlReg(dst), VixlReg(src1));
2718 
2719     if (src0.GetSize() > WORD_SIZE || src1.GetSize() > WORD_SIZE) {
2720         GetMasm()->Mov(Convert(cc), VixlRegU(dst), VixlRegU(src0));
2721         GetMasm()->Mov(Convert(cc).Negate(), VixlRegU(dst), VixlRegU(src1));
2722     }
2723 }
2724 
EncodeSelectTest(Reg dst,Reg src0,Reg src1,Reg src2,Reg src3,Condition cc)2725 void Aarch32Encoder::EncodeSelectTest(Reg dst, Reg src0, Reg src1, Reg src2, Reg src3, Condition cc)
2726 {
2727     ASSERT(!src0.IsFloat() && !src1.IsFloat() && !src2.IsFloat());
2728 
2729     TestHelper(src2, src3, cc);
2730 
2731     GetMasm()->Mov(ConvertTest(cc), VixlReg(dst), VixlReg(src0));
2732     GetMasm()->Mov(ConvertTest(cc).Negate(), VixlReg(dst), VixlReg(src1));
2733 
2734     if (src0.GetSize() > WORD_SIZE || src1.GetSize() > WORD_SIZE) {
2735         GetMasm()->Mov(ConvertTest(cc), VixlRegU(dst), VixlRegU(src0));
2736         GetMasm()->Mov(ConvertTest(cc).Negate(), VixlRegU(dst), VixlRegU(src1));
2737     }
2738 }
2739 
EncodeSelectTest(Reg dst,Reg src0,Reg src1,Reg src2,Imm imm,Condition cc)2740 void Aarch32Encoder::EncodeSelectTest(Reg dst, Reg src0, Reg src1, Reg src2, Imm imm, Condition cc)
2741 {
2742     ASSERT(!src0.IsFloat() && !src1.IsFloat() && !src2.IsFloat());
2743 
2744     TestImmHelper(src2, imm, cc);
2745     GetMasm()->Mov(ConvertTest(cc), VixlReg(dst), VixlReg(src0));
2746     GetMasm()->Mov(ConvertTest(cc).Negate(), VixlReg(dst), VixlReg(src1));
2747 
2748     if (src0.GetSize() > WORD_SIZE || src1.GetSize() > WORD_SIZE) {
2749         GetMasm()->Mov(ConvertTest(cc), VixlRegU(dst), VixlRegU(src0));
2750         GetMasm()->Mov(ConvertTest(cc).Negate(), VixlRegU(dst), VixlRegU(src1));
2751     }
2752 }
2753 
CanEncodeImmAddSubCmp(int64_t imm,uint32_t size,bool signedCompare)2754 bool Aarch32Encoder::CanEncodeImmAddSubCmp(int64_t imm, uint32_t size, bool signedCompare)
2755 {
2756     if (imm == INT64_MIN) {
2757         return false;
2758     }
2759     if (imm < 0) {
2760         imm = -imm;
2761         if (size > WORD_SIZE && signedCompare) {
2762             return false;
2763         }
2764     }
2765     // We don't support 64-bit immediate, even when both higher and lower parts are legal immediates
2766     if (imm > UINT32_MAX) {
2767         return false;
2768     }
2769     return vixl::aarch32::ImmediateA32::IsImmediateA32(imm);
2770 }
2771 
CanEncodeImmLogical(uint64_t imm,uint32_t size)2772 bool Aarch32Encoder::CanEncodeImmLogical(uint64_t imm, uint32_t size)
2773 {
2774     // NOLINTNEXTLINE(hicpp-signed-bitwise)
2775     uint64_t high = imm >> WORD_SIZE;
2776     if (size == DOUBLE_WORD_SIZE) {
2777         if (high != 0U && high != UINT32_MAX) {
2778             return false;
2779         }
2780     }
2781 #ifndef NDEBUG
2782     if (size < DOUBLE_WORD_SIZE) {
2783         // Test if the highest part is consistent:
2784         ASSERT(((imm >> size) == 0) || (((~imm) >> size) == 0));
2785     }
2786 #endif  // NDEBUG
2787     return vixl::aarch32::ImmediateA32::IsImmediateA32(imm);
2788 }
2789 
2790 using vixl::aarch32::MemOperand;
2791 
2792 template <bool IS_STORE>
LoadStoreRegistersMainLoop(RegMask registers,bool isFp,int32_t slot,Reg base,RegMask mask)2793 void Aarch32Encoder::LoadStoreRegistersMainLoop(RegMask registers, bool isFp, int32_t slot, Reg base, RegMask mask)
2794 {
2795     bool hasMask = mask.any();
2796     int32_t index = hasMask ? static_cast<int32_t>(mask.GetMinRegister()) : 0;
2797     slot -= index;
2798     vixl::aarch32::Register baseReg = VixlReg(base);
2799     for (size_t i = index; i < registers.size(); i++) {
2800         if (hasMask) {
2801             if (!mask.test(i)) {
2802                 continue;
2803             }
2804             index++;
2805         }
2806         if (!registers.test(i)) {
2807             continue;
2808         }
2809 
2810         if (!hasMask) {
2811             index++;
2812         }
2813         auto mem = MemOperand(baseReg, (slot + index - 1) * WORD_SIZE_BYTES);
2814         if (isFp) {
2815             auto reg = vixl::aarch32::SRegister(i);
2816             if constexpr (IS_STORE) {  // NOLINT
2817                 GetMasm()->Vstr(reg, mem);
2818             } else {  // NOLINT
2819                 GetMasm()->Vldr(reg, mem);
2820             }
2821         } else {
2822             auto reg = vixl::aarch32::Register(i);
2823             if constexpr (IS_STORE) {  // NOLINT
2824                 GetMasm()->Str(reg, mem);
2825             } else {  // NOLINT
2826                 GetMasm()->Ldr(reg, mem);
2827             }
2828         }
2829     }
2830 }
2831 
2832 template <bool IS_STORE>
LoadStoreRegisters(RegMask registers,bool isFp,int32_t slot,Reg base,RegMask mask)2833 void Aarch32Encoder::LoadStoreRegisters(RegMask registers, bool isFp, int32_t slot, Reg base, RegMask mask)
2834 {
2835     if (registers.none()) {
2836         return;
2837     }
2838 
2839     vixl::aarch32::Register baseReg = VixlReg(base);
2840     int32_t maxOffset = (slot + helpers::ToSigned(registers.GetMaxRegister())) * WORD_SIZE_BYTES;
2841 
2842     ScopedTmpRegU32 tmpReg(this);
2843     auto tmp = VixlReg(tmpReg);
2844     // Construct single add for big offset
2845     if (isFp) {
2846         if ((maxOffset < -VMEM_OFFSET) || (maxOffset > VMEM_OFFSET)) {
2847             GetMasm()->Add(tmp, baseReg, VixlImm(slot * WORD_SIZE_BYTES));
2848             slot = 0;
2849             baseReg = tmp;
2850         }
2851     } else {
2852         if ((maxOffset < -MEM_BIG_OFFSET) || (maxOffset > MEM_BIG_OFFSET)) {
2853             GetMasm()->Add(tmp, baseReg, VixlImm(slot * WORD_SIZE_BYTES));
2854             slot = 0;
2855             baseReg = tmp;
2856         }
2857     }
2858     LoadStoreRegistersMainLoop<IS_STORE>(registers, isFp, slot, base, mask);
2859 }
2860 
2861 template <bool IS_STORE>
LoadStoreRegisters(RegMask registers,ssize_t slot,size_t startReg,bool isFp)2862 void Aarch32Encoder::LoadStoreRegisters(RegMask registers, ssize_t slot, size_t startReg, bool isFp)
2863 {
2864     if (registers.none()) {
2865         return;
2866     }
2867     int32_t lastReg = registers.size() - 1;
2868     for (; lastReg >= 0; --lastReg) {
2869         if (registers.test(lastReg)) {
2870             break;
2871         }
2872     }
2873     vixl::aarch32::Register baseReg = vixl::aarch32::sp;
2874     auto maxOffset = (slot + lastReg) * WORD_SIZE_BYTES;
2875     ScopedTmpRegU32 tmpReg(this);
2876     auto tmp = VixlReg(tmpReg);
2877     // Construct single add for big offset
2878     if (isFp) {
2879         if ((maxOffset < -VMEM_OFFSET) || (maxOffset > VMEM_OFFSET)) {
2880             GetMasm()->Add(tmp, baseReg, VixlImm(slot * WORD_SIZE_BYTES));
2881             slot = 0;
2882             baseReg = tmp;
2883         }
2884     } else {
2885         if ((maxOffset < -MEM_BIG_OFFSET) || (maxOffset > MEM_BIG_OFFSET)) {
2886             GetMasm()->Add(tmp, baseReg, VixlImm(slot * WORD_SIZE_BYTES));
2887             slot = 0;
2888             baseReg = tmp;
2889         }
2890     }
2891     for (auto i = startReg; i < registers.size(); i++) {
2892         if (!registers.test(i)) {
2893             continue;
2894         }
2895         auto mem = MemOperand(baseReg, (slot + i - startReg) * WORD_SIZE_BYTES);
2896         if (isFp) {
2897             auto reg = vixl::aarch32::SRegister(i);
2898             if constexpr (IS_STORE) {  // NOLINT
2899                 GetMasm()->Vstr(reg, mem);
2900             } else {  // NOLINT
2901                 GetMasm()->Vldr(reg, mem);
2902             }
2903         } else {
2904             auto reg = vixl::aarch32::Register(i);
2905             if constexpr (IS_STORE) {  // NOLINT
2906                 GetMasm()->Str(reg, mem);
2907             } else {  // NOLINT
2908                 GetMasm()->Ldr(reg, mem);
2909             }
2910         }
2911     }
2912 }
2913 
PushRegisters(RegMask registers,bool isFp)2914 void Aarch32Encoder::PushRegisters(RegMask registers, bool isFp)
2915 {
2916     (void)registers;
2917     (void)isFp;
2918     // NOTE(msherstennikov): Implement
2919 }
2920 
PopRegisters(RegMask registers,bool isFp)2921 void Aarch32Encoder::PopRegisters(RegMask registers, bool isFp)
2922 {
2923     (void)registers;
2924     (void)isFp;
2925     // NOTE(msherstennikov): Implement
2926 }
2927 
DisasmInstr(std::ostream & stream,size_t pc,ssize_t codeOffset) const2928 size_t Aarch32Encoder::DisasmInstr(std::ostream &stream, size_t pc, ssize_t codeOffset) const
2929 {
2930     auto addr = GetMasm()->GetBuffer()->GetOffsetAddress<const uint32_t *>(pc);
2931     // Display pc is seted, because disassembler use pc
2932     // for upper bits (e.g. 0x40000000), when print one instruction.
2933     if (codeOffset < 0) {
2934         vixl::aarch32::PrintDisassembler disasm(GetAllocator(), stream);
2935         disasm.DisassembleA32Buffer(addr, vixl::aarch32::k32BitT32InstructionSizeInBytes);
2936     } else {
2937         const uint64_t displayPc = 0x10000000;
2938         vixl::aarch32::PrintDisassembler disasm(GetAllocator(), stream, displayPc + pc + codeOffset);
2939         disasm.DisassembleA32Buffer(addr, vixl::aarch32::k32BitT32InstructionSizeInBytes);
2940 
2941         stream << std::setfill(' ');
2942     }
2943     return pc + vixl::aarch32::k32BitT32InstructionSizeInBytes;
2944 }
2945 }  // namespace panda::compiler::aarch32
2946