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), ¬Equal);
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(¬Equal);
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