• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef COMPILER_OPTIMIZER_CODEGEN_ENCODE_H
17 #define COMPILER_OPTIMIZER_CODEGEN_ENCODE_H
18 
19 /*
20     Hi-level interface for encoding
21     Wrapper for specialize concrete used encoding
22 
23     Responsible for
24         Primitive (not-branch) instruction encoding
25         Memory-instructions encoding
26         Immediate and Memory operands
27 */
28 
29 #include <variant>
30 
31 #include "operands.h"
32 #include "registers_description.h"
33 #include "utils/cframe_layout.h"
34 #include "target_info.h"
35 
36 namespace panda::compiler {
37 class Encoder;
38 class CompilerOptions;
39 class RelocationInfo;
40 
41 namespace memory_order {
42 enum Order { ACQUIRE, RELEASE, FULL };
43 }  // namespace memory_order
44 
45 class LabelHolder {
46 public:
47     using LabelId = uintptr_t;
48     static constexpr LabelId INVALID_LABEL = static_cast<uintptr_t>(-1);
49 
LabelHolder(Encoder * enc)50     explicit LabelHolder(Encoder *enc) : enc_ {enc} {};
51     virtual ~LabelHolder() = default;
52 
53     // NOTE (igorban) : hide all this methods in CallConv
54     virtual void CreateLabels(LabelId size) = 0;
55     virtual LabelId CreateLabel() = 0;
56     virtual LabelId Size() = 0;
57 
GetEncoder()58     Encoder *GetEncoder() const
59     {
60         return enc_;
61     }
62 
63     NO_COPY_SEMANTIC(LabelHolder);
64     NO_MOVE_SEMANTIC(LabelHolder);
65 
66 protected:
67     virtual void BindLabel(LabelId) = 0;
68 
69 private:
70     Encoder *enc_ {nullptr};
71     friend Encoder;
72 };
73 
74 class Encoder {
75 public:
76     // Main constructor
Encoder(ArenaAllocator * aa,Arch arch)77     explicit Encoder(ArenaAllocator *aa, Arch arch) : Encoder(aa, arch, false) {}
Encoder(ArenaAllocator * aa,Arch arch,bool jsNumberCast)78     Encoder(ArenaAllocator *aa, Arch arch, bool jsNumberCast)
79         : allocator_(aa), frameLayout_(arch, 0), target_(arch), jsNumberCast_(jsNumberCast)
80     {
81     }
82     virtual ~Encoder() = default;
83 
GetAllocator()84     ArenaAllocator *GetAllocator() const
85     {
86         return allocator_;
87     }
88 
IsLabelValid(LabelHolder::LabelId label)89     bool IsLabelValid(LabelHolder::LabelId label)
90     {
91         return label != LabelHolder::INVALID_LABEL;
92     }
93 
GetTarget()94     Target GetTarget() const
95     {
96         return target_;
97     }
98 
GetArch()99     Arch GetArch() const
100     {
101         return GetTarget().GetArch();
102     }
103 
IsJsNumberCast()104     bool IsJsNumberCast() const
105     {
106         return jsNumberCast_;
107     }
108 
SetIsJsNumberCast(bool v)109     void SetIsJsNumberCast(bool v)
110     {
111         jsNumberCast_ = v;
112     }
113 
114     /// Print instruction and return next pc
DisasmInstr(std::ostream & stream,size_t pc,ssize_t codeOffset)115     virtual size_t DisasmInstr([[maybe_unused]] std::ostream &stream, [[maybe_unused]] size_t pc,
116                                [[maybe_unused]] ssize_t codeOffset) const
117     {
118         return 0;
119     }
120 
BufferData()121     virtual void *BufferData() const
122     {
123         return nullptr;
124     }
125 
126     /// Size of used buffer
BufferSize()127     virtual size_t BufferSize() const
128     {
129         return 0;
130     }
131 
132     // Default behaviour - do nothing
InitMasm()133     virtual bool InitMasm()
134     {
135         return true;
136     }
137 
SetMaxAllocatedBytes(size_t size)138     virtual void SetMaxAllocatedBytes([[maybe_unused]] size_t size) {};
139 
140 // Define default math operations
141 // Encode (dst, src)
142 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
143 #define UNARY_OPERATION(opc)           \
144     virtual void Encode##opc(Reg, Reg) \
145     {                                  \
146         SetFalseResult();              \
147     }
148 
149 // Encode (dst, src0, src1)
150 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
151 #define BINARY_OPERATION(opc)               \
152     virtual void Encode##opc(Reg, Reg, Reg) \
153     {                                       \
154         SetFalseResult();                   \
155     }                                       \
156     virtual void Encode##opc(Reg, Reg, Imm) \
157     {                                       \
158         SetFalseResult();                   \
159     }
160 
161 // Encode (dst, src0, src1)
162 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
163 #define BINARY_SHIFTED_REGISTER_OPERATION(opc) \
164     virtual void Encode##opc(Reg, Reg, Shift)  \
165     {                                          \
166         SetFalseResult();                      \
167     }
168 
169 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
170 #define INST_DEF(OPCODE, TYPE) TYPE(OPCODE)
171 
172     ENCODE_MATH_LIST(INST_DEF)
173 
ENCODE_INST_WITH_SHIFTED_OPERAND(INST_DEF)174     ENCODE_INST_WITH_SHIFTED_OPERAND(INST_DEF)
175 
176 #undef UNARY_OPERATION
177 #undef BINARY_OPERATION
178 #undef BINARY_SHIFTED_REGISTER_OPERATION
179 #undef INST_DEF
180 
181     virtual void EncodeNop()
182     {
183         SetFalseResult();
184     }
185 
EncodeAddOverflow(compiler::LabelHolder::LabelId id,Reg dst,Reg src0,Reg src1,Condition cc)186     virtual void EncodeAddOverflow([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] Reg dst,
187                                    [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, [[maybe_unused]] Condition cc)
188     {
189         SetFalseResult();
190     }
191 
EncodeSubOverflow(compiler::LabelHolder::LabelId id,Reg dst,Reg src0,Reg src1,Condition cc)192     virtual void EncodeSubOverflow([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] Reg dst,
193                                    [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, [[maybe_unused]] Condition cc)
194     {
195         SetFalseResult();
196     }
197 
EncodeMulOverflow(compiler::LabelHolder::LabelId id,Reg dst,Reg src0,Reg src1,Condition cc)198     virtual void EncodeMulOverflow([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] Reg dst,
199                                    [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, [[maybe_unused]] Condition cc)
200     {
201         SetFalseResult();
202     }
203 
EncodeNegOverflowAndZero(compiler::LabelHolder::LabelId id,Reg dst,Reg src)204     virtual void EncodeNegOverflowAndZero([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] Reg dst,
205                                           [[maybe_unused]] Reg src)
206     {
207         SetFalseResult();
208     }
209 
EncodeFastPathDynamicCast(Reg dst,Reg src,LabelHolder::LabelId slow)210     virtual void EncodeFastPathDynamicCast([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src,
211                                            [[maybe_unused]] LabelHolder::LabelId slow)
212     {
213         SetFalseResult();
214     }
215 
EncodeCast(Reg dst,bool dstSigned,Reg src,bool srcSigned)216     virtual void EncodeCast([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] Reg src,
217                             [[maybe_unused]] bool srcSigned)
218     {
219         SetFalseResult();
220     }
EncodeCastToBool(Reg dst,Reg src)221     virtual void EncodeCastToBool([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
222     {
223         SetFalseResult();
224     }
EncodeMin(Reg dst,bool dstSigned,Reg src0,Reg src1)225     virtual void EncodeMin([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] Reg src0,
226                            [[maybe_unused]] Reg src1)
227     {
228         SetFalseResult();
229     }
EncodeDiv(Reg dst,bool dstSigned,Reg src0,Reg src1)230     virtual void EncodeDiv([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] Reg src0,
231                            [[maybe_unused]] Reg src1)
232     {
233         SetFalseResult();
234     }
EncodeMod(Reg dst,bool dstSigned,Reg src0,Reg src1)235     virtual void EncodeMod([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] Reg src0,
236                            [[maybe_unused]] Reg src1)
237     {
238         SetFalseResult();
239     }
EncodeMax(Reg dst,bool dstSigned,Reg src0,Reg src1)240     virtual void EncodeMax([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] Reg src0,
241                            [[maybe_unused]] Reg src1)
242     {
243         SetFalseResult();
244     }
EncodeMov(Reg dst,Imm src)245     virtual void EncodeMov([[maybe_unused]] Reg dst, [[maybe_unused]] Imm src)
246     {
247         SetFalseResult();
248     }
249 
EncodeLdr(Reg dst,bool dstSigned,MemRef mem)250     virtual void EncodeLdr([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned, [[maybe_unused]] MemRef mem)
251     {
252         SetFalseResult();
253     }
EncodeLdrAcquire(Reg dst,bool dstSigned,MemRef mem)254     virtual void EncodeLdrAcquire([[maybe_unused]] Reg dst, [[maybe_unused]] bool dstSigned,
255                                   [[maybe_unused]] MemRef mem)
256     {
257         SetFalseResult();
258     }
EncodeStr(Reg src,MemRef mem)259     virtual void EncodeStr([[maybe_unused]] Reg src, [[maybe_unused]] MemRef mem)
260     {
261         SetFalseResult();
262     }
EncodeStrRelease(Reg src,MemRef mem)263     virtual void EncodeStrRelease([[maybe_unused]] Reg src, [[maybe_unused]] MemRef mem)
264     {
265         SetFalseResult();
266     }
EncodeLdrExclusive(Reg dst,Reg addr,bool acquire)267     virtual void EncodeLdrExclusive([[maybe_unused]] Reg dst, [[maybe_unused]] Reg addr, [[maybe_unused]] bool acquire)
268     {
269         SetFalseResult();
270     }
EncodeStrExclusive(Reg dst,Reg src,Reg addr,bool release)271     virtual void EncodeStrExclusive([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src, [[maybe_unused]] Reg addr,
272                                     [[maybe_unused]] bool release)
273     {
274         SetFalseResult();
275     }
276 
277     // zerod high part: [reg.size, 64)
EncodeStrz(Reg src,MemRef mem)278     virtual void EncodeStrz([[maybe_unused]] Reg src, [[maybe_unused]] MemRef mem)
279     {
280         SetFalseResult();
281     }
Push(Reg src,MemRef mem)282     virtual void Push([[maybe_unused]] Reg src, [[maybe_unused]] MemRef mem)
283     {
284         SetFalseResult();
285     }
EncodeSti(int64_t src,uint8_t srcSizeBytes,MemRef mem)286     virtual void EncodeSti([[maybe_unused]] int64_t src, [[maybe_unused]] uint8_t srcSizeBytes,
287                            [[maybe_unused]] MemRef mem)
288     {
289         SetFalseResult();
290     }
EncodeSti(double src,MemRef mem)291     virtual void EncodeSti([[maybe_unused]] double src, [[maybe_unused]] MemRef mem)
292     {
293         SetFalseResult();
294     }
EncodeSti(float src,MemRef mem)295     virtual void EncodeSti([[maybe_unused]] float src, [[maybe_unused]] MemRef mem)
296     {
297         SetFalseResult();
298     }
299     // size must be 8, 16,32 or 64
EncodeMemCopy(MemRef memFrom,MemRef memTo,size_t size)300     virtual void EncodeMemCopy([[maybe_unused]] MemRef memFrom, [[maybe_unused]] MemRef memTo,
301                                [[maybe_unused]] size_t size)
302     {
303         SetFalseResult();
304     }
305     // size must be 8, 16,32 or 64
306     // zerod high part: [size, 64)
EncodeMemCopyz(MemRef memFrom,MemRef memTo,size_t size)307     virtual void EncodeMemCopyz([[maybe_unused]] MemRef memFrom, [[maybe_unused]] MemRef memTo,
308                                 [[maybe_unused]] size_t size)
309     {
310         SetFalseResult();
311     }
312 
EncodeCmp(Reg dst,Reg src0,Reg src1,Condition cc)313     virtual void EncodeCmp([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1,
314                            [[maybe_unused]] Condition cc)
315     {
316         SetFalseResult();
317     }
318 
319     // Additional check for isnan-comparison
EncodeCompare(Reg dst,Reg src0,Reg src1,Condition cc)320     virtual void EncodeCompare([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1,
321                                [[maybe_unused]] Condition cc)
322     {
323         SetFalseResult();
324     }
325 
EncodeCompareTest(Reg dst,Reg src0,Reg src1,Condition cc)326     virtual void EncodeCompareTest([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1,
327                                    [[maybe_unused]] Condition cc)
328     {
329         SetFalseResult();
330     }
331 
EncodeCompressedStringCharAt(Reg dst,Reg str,Reg idx,Reg length,Reg tmp,size_t dataOffset,uint32_t shift)332     virtual void EncodeCompressedStringCharAt([[maybe_unused]] Reg dst, [[maybe_unused]] Reg str,
333                                               [[maybe_unused]] Reg idx, [[maybe_unused]] Reg length,
334                                               [[maybe_unused]] Reg tmp, [[maybe_unused]] size_t dataOffset,
335                                               [[maybe_unused]] uint32_t shift)
336     {
337         SetFalseResult();
338     }
339 
EncodeCompressedStringCharAtI(Reg dst,Reg str,Reg length,size_t dataOffset,uint32_t index,uint32_t shift)340     virtual void EncodeCompressedStringCharAtI([[maybe_unused]] Reg dst, [[maybe_unused]] Reg str,
341                                                [[maybe_unused]] Reg length, [[maybe_unused]] size_t dataOffset,
342                                                [[maybe_unused]] uint32_t index, [[maybe_unused]] uint32_t shift)
343     {
344         SetFalseResult();
345     }
346 
EncodeSelect(Reg dst,Reg src0,Reg src1,Reg src2,Reg src3,Condition cc)347     virtual void EncodeSelect([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1,
348                               [[maybe_unused]] Reg src2, [[maybe_unused]] Reg src3, [[maybe_unused]] Condition cc)
349     {
350         SetFalseResult();
351     }
352 
EncodeSelectTest(Reg dst,Reg src0,Reg src1,Reg src2,Reg src3,Condition cc)353     virtual void EncodeSelectTest([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1,
354                                   [[maybe_unused]] Reg src2, [[maybe_unused]] Reg src3, [[maybe_unused]] Condition cc)
355     {
356         SetFalseResult();
357     }
358 
EncodeIsInf(Reg dst,Reg src0)359     virtual void EncodeIsInf([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0)
360     {
361         SetFalseResult();
362     }
363 
EncodeIsInteger(Reg dst,Reg src0)364     virtual void EncodeIsInteger([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0)
365     {
366         SetFalseResult();
367     }
368 
EncodeIsSafeInteger(Reg dst,Reg src0)369     virtual void EncodeIsSafeInteger([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0)
370     {
371         SetFalseResult();
372     }
373 
EncodeReverseBytes(Reg dst,Reg src)374     virtual void EncodeReverseBytes([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
375     {
376         SetFalseResult();
377     }
378 
EncodeReverseBits(Reg dst,Reg src)379     virtual void EncodeReverseBits([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
380     {
381         SetFalseResult();
382     }
383 
EncodeBitCount(Reg dst,Reg src)384     virtual void EncodeBitCount([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
385     {
386         SetFalseResult();
387     }
388 
EncodeRotate(Reg dst,Reg src1,Reg src2,bool isRor)389     virtual void EncodeRotate([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src1, [[maybe_unused]] Reg src2,
390                               [[maybe_unused]] bool isRor)
391     {
392         SetFalseResult();
393     }
394 
EncodeSignum(Reg dst,Reg src)395     virtual void EncodeSignum([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
396     {
397         SetFalseResult();
398     }
399 
EncodeCountLeadingZeroBits(Reg dst,Reg src)400     virtual void EncodeCountLeadingZeroBits([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
401     {
402         SetFalseResult();
403     }
404 
EncodeCountTrailingZeroBits(Reg dst,Reg src)405     virtual void EncodeCountTrailingZeroBits([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
406     {
407         SetFalseResult();
408     }
409 
EncodeCeil(Reg dst,Reg src)410     virtual void EncodeCeil([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
411     {
412         SetFalseResult();
413     }
414 
EncodeFloor(Reg dst,Reg src)415     virtual void EncodeFloor([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
416     {
417         SetFalseResult();
418     }
419 
EncodeRint(Reg dst,Reg src)420     virtual void EncodeRint([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
421     {
422         SetFalseResult();
423     }
424 
EncodeTrunc(Reg dst,Reg src)425     virtual void EncodeTrunc([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
426     {
427         SetFalseResult();
428     }
429 
EncodeRoundAway(Reg dst,Reg src)430     virtual void EncodeRoundAway([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
431     {
432         SetFalseResult();
433     }
434 
EncodeRoundToPInf(Reg dst,Reg src)435     virtual void EncodeRoundToPInf([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
436     {
437         SetFalseResult();
438     }
439 
EncodeSelect(Reg dst,Reg src0,Reg src1,Reg src2,Imm imm,Condition cc)440     virtual void EncodeSelect([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1,
441                               [[maybe_unused]] Reg src2, [[maybe_unused]] Imm imm, [[maybe_unused]] Condition cc)
442     {
443         SetFalseResult();
444     }
445 
EncodeSelectTest(Reg dst,Reg src0,Reg src1,Reg src2,Imm imm,Condition cc)446     virtual void EncodeSelectTest([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1,
447                                   [[maybe_unused]] Reg src2, [[maybe_unused]] Imm imm, [[maybe_unused]] Condition cc)
448     {
449         SetFalseResult();
450     }
451 
EncodeGetTypeSize(Reg size,Reg type)452     virtual void EncodeGetTypeSize([[maybe_unused]] Reg size, [[maybe_unused]] Reg type)
453     {
454         SetFalseResult();
455     }
456 
EncodeLdp(Reg dst0,Reg dst1,bool dstSigned,MemRef mem)457     virtual void EncodeLdp([[maybe_unused]] Reg dst0, [[maybe_unused]] Reg dst1, [[maybe_unused]] bool dstSigned,
458                            [[maybe_unused]] MemRef mem)
459     {
460         SetFalseResult();
461     }
462 
EncodeStp(Reg src0,Reg src1,MemRef mem)463     virtual void EncodeStp([[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1, [[maybe_unused]] MemRef mem)
464     {
465         SetFalseResult();
466     }
467 
EncodeMAdd(Reg dst,Reg src0,Reg src1,Reg src2)468     virtual void EncodeMAdd([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1,
469                             [[maybe_unused]] Reg src2)
470     {
471         SetFalseResult();
472     }
473 
EncodeMSub(Reg dst,Reg src0,Reg src1,Reg src2)474     virtual void EncodeMSub([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1,
475                             [[maybe_unused]] Reg src2)
476     {
477         SetFalseResult();
478     }
479 
EncodeMNeg(Reg dst,Reg src0,Reg src1)480     virtual void EncodeMNeg([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1)
481     {
482         SetFalseResult();
483     }
484 
EncodeOrNot(Reg dst,Reg src0,Reg src1)485     virtual void EncodeOrNot([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1)
486     {
487         SetFalseResult();
488     }
489 
EncodeAndNot(Reg dst,Reg src0,Reg src1)490     virtual void EncodeAndNot([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1)
491     {
492         SetFalseResult();
493     }
494 
EncodeXorNot(Reg dst,Reg src0,Reg src1)495     virtual void EncodeXorNot([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src0, [[maybe_unused]] Reg src1)
496     {
497         SetFalseResult();
498     }
499 
EncodeNeg(Reg dst,Shift src)500     virtual void EncodeNeg([[maybe_unused]] Reg dst, [[maybe_unused]] Shift src)
501     {
502         SetFalseResult();
503     }
504 
EncodeFpToBits(Reg dst,Reg src)505     virtual void EncodeFpToBits([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
506     {
507         SetFalseResult();
508     }
509 
EncodeMoveBitsRaw(Reg dst,Reg src)510     virtual void EncodeMoveBitsRaw([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src)
511     {
512         SetFalseResult();
513     }
514 
EncodeExtractBits(Reg dst,Reg src,Imm imm1,Imm imm2)515     virtual void EncodeExtractBits([[maybe_unused]] Reg dst, [[maybe_unused]] Reg src, [[maybe_unused]] Imm imm1,
516                                    [[maybe_unused]] Imm imm2)
517     {
518         success_ = false;
519     }
520 
EncodeCrc32Update(Reg dst,Reg crcReg,Reg valReg)521     virtual void EncodeCrc32Update([[maybe_unused]] Reg dst, [[maybe_unused]] Reg crcReg, [[maybe_unused]] Reg valReg)
522     {
523         SetFalseResult();
524     }
525 
526     /**
527      * Encode dummy load from the address [sp + offset].
528      * @param offset offset from the stack pointer register
529      */
EncodeStackOverflowCheck(ssize_t offset)530     virtual void EncodeStackOverflowCheck([[maybe_unused]] ssize_t offset)
531     {
532         SetFalseResult();
533     }
534 
IsValid()535     virtual bool IsValid() const
536     {
537         return false;
538     }
539 
GetResult()540     virtual bool GetResult() const
541     {
542         return success_;
543     }
544 
SetFalseResult()545     void SetFalseResult()
546     {
547         success_ = false;
548     }
549 
550     // Encoder builder - implement in target.cpp
551     static Encoder *Create(ArenaAllocator *arenaAllocator, Arch arch, bool printAsm, bool jsNumberCast = false);
552 
553     // For now it is one function for Add/Sub and Cmp, it suits all considered targets (x86, amd64, arm32, arm64).
554     // We probably should revisit this if we add new targets, like Thumb-2 or others.
CanEncodeImmAddSubCmp(int64_t imm,uint32_t size,bool signedCompare)555     virtual bool CanEncodeImmAddSubCmp([[maybe_unused]] int64_t imm, [[maybe_unused]] uint32_t size,
556                                        [[maybe_unused]] bool signedCompare)
557     {
558         return false;
559     }
560 
CanEncodeImmMulDivMod(uint64_t imm,uint32_t size)561     virtual bool CanEncodeImmMulDivMod([[maybe_unused]] uint64_t imm, [[maybe_unused]] uint32_t size)
562     {
563         return false;
564     }
565 
CanEncodeImmLogical(uint64_t imm,uint32_t size)566     virtual bool CanEncodeImmLogical([[maybe_unused]] uint64_t imm, [[maybe_unused]] uint32_t size)
567     {
568         return false;
569     }
570 
CanEncodeScale(uint64_t imm,uint32_t size)571     virtual bool CanEncodeScale([[maybe_unused]] uint64_t imm, [[maybe_unused]] uint32_t size)
572     {
573         return false;
574     }
575 
CanEncodeShift(uint32_t size)576     virtual bool CanEncodeShift([[maybe_unused]] uint32_t size)
577     {
578         return true;
579     }
580 
CanEncodeBitCount()581     virtual bool CanEncodeBitCount()
582     {
583         return false;
584     }
585 
CanEncodeMAdd()586     virtual bool CanEncodeMAdd()
587     {
588         return false;
589     }
590 
CanEncodeMSub()591     virtual bool CanEncodeMSub()
592     {
593         return false;
594     }
595 
CanEncodeMNeg()596     virtual bool CanEncodeMNeg()
597     {
598         return false;
599     }
600 
CanEncodeOrNot()601     virtual bool CanEncodeOrNot()
602     {
603         return false;
604     }
605 
CanEncodeAndNot()606     virtual bool CanEncodeAndNot()
607     {
608         return false;
609     }
610 
CanEncodeXorNot()611     virtual bool CanEncodeXorNot()
612     {
613         return false;
614     }
615 
616     // Check if encoder is capable of encoding operations where an operand is a register with
617     // a value shifted by shift operation with specified type by some immediate value.
CanEncodeShiftedOperand(ShiftOpcode opcode,ShiftType shiftType)618     virtual bool CanEncodeShiftedOperand([[maybe_unused]] ShiftOpcode opcode, [[maybe_unused]] ShiftType shiftType)
619     {
620         return false;
621     }
622 
CanEncodeCompressedStringCharAt()623     virtual bool CanEncodeCompressedStringCharAt()
624     {
625         return false;
626     }
627 
CanEncodeCompressedStringCharAtI()628     virtual bool CanEncodeCompressedStringCharAtI()
629     {
630         return false;
631     }
632 
CanEncodeFloatSelect()633     virtual bool CanEncodeFloatSelect()
634     {
635         return false;
636     }
637 
EncodeCompareAndSwap(Reg dst,Reg obj,Reg offset,Reg val,Reg newval)638     virtual void EncodeCompareAndSwap([[maybe_unused]] Reg dst, [[maybe_unused]] Reg obj, [[maybe_unused]] Reg offset,
639                                       [[maybe_unused]] Reg val, [[maybe_unused]] Reg newval)
640     {
641         SetFalseResult();
642     }
643 
EncodeCompareAndSwap(Reg dst,Reg addr,Reg val,Reg newval)644     virtual void EncodeCompareAndSwap([[maybe_unused]] Reg dst, [[maybe_unused]] Reg addr, [[maybe_unused]] Reg val,
645                                       [[maybe_unused]] Reg newval)
646     {
647         SetFalseResult();
648     }
649 
EncodeUnsafeGetAndSet(Reg dst,Reg obj,Reg offset,Reg val)650     virtual void EncodeUnsafeGetAndSet([[maybe_unused]] Reg dst, [[maybe_unused]] Reg obj, [[maybe_unused]] Reg offset,
651                                        [[maybe_unused]] Reg val)
652     {
653         SetFalseResult();
654     }
655 
EncodeUnsafeGetAndAdd(Reg dst,Reg obj,Reg offset,Reg val,Reg tmp)656     virtual void EncodeUnsafeGetAndAdd([[maybe_unused]] Reg dst, [[maybe_unused]] Reg obj, [[maybe_unused]] Reg offset,
657                                        [[maybe_unused]] Reg val, [[maybe_unused]] Reg tmp)
658     {
659         SetFalseResult();
660     }
661 
EncodeMemoryBarrier(memory_order::Order order)662     virtual void EncodeMemoryBarrier([[maybe_unused]] memory_order::Order order)
663     {
664         SetFalseResult();
665     }
666 
GetCursorOffset()667     virtual size_t GetCursorOffset() const
668     {
669         return 0;
670     }
671 
EncodeCompressEightUtf16ToUtf8CharsUsingSimd(Reg srcAddr,Reg dstAddr)672     virtual void EncodeCompressEightUtf16ToUtf8CharsUsingSimd([[maybe_unused]] Reg srcAddr,
673                                                               [[maybe_unused]] Reg dstAddr)
674     {
675         SetFalseResult();
676     }
677 
EncodeCompressSixteenUtf16ToUtf8CharsUsingSimd(Reg srcAddr,Reg dstAddr)678     virtual void EncodeCompressSixteenUtf16ToUtf8CharsUsingSimd([[maybe_unused]] Reg srcAddr,
679                                                                 [[maybe_unused]] Reg dstAddr)
680     {
681         SetFalseResult();
682     }
683 
SetCursorOffset(size_t offset)684     virtual void SetCursorOffset([[maybe_unused]] size_t offset) {}
685 
SaveRegisters(RegMask registers,ssize_t slot,size_t startReg,bool isFp)686     virtual void SaveRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] ssize_t slot,
687                                [[maybe_unused]] size_t startReg, [[maybe_unused]] bool isFp)
688     {
689         SetFalseResult();
690     }
LoadRegisters(RegMask registers,ssize_t slot,size_t startReg,bool isFp)691     virtual void LoadRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] ssize_t slot,
692                                [[maybe_unused]] size_t startReg, [[maybe_unused]] bool isFp)
693     {
694         SetFalseResult();
695     }
696 
697     /**
698      * Save/load registers to/from the memory.
699      *
700      * If `mask` is empty (all bits are zero), then registers will be saved densely, otherwise place for each register
701      * will be determined according to this mask.
702      * Example: registers' bits = [1, 3, 10], mask's bits = [0, 1, 2, 3, 8, 9, 10, 11]
703      * We can see that mask has the gap in 4-7 bits. So, registers will be saved in the following slots:
704      *      slots: 0   1   2   3   4   5   6   7
705      *      regs :     1       3          10
706      * If the mask would be zero, then the following layout will be used:
707      *      slots: 0   1   2
708      *      regs : 1   3  10
709      *
710      * @param registers mask of registers to be saved
711      * @param is_fp if true, registers are floating point registers
712      * @param slot offset from the `base` register to the destination address (in words)
713      * @param base base register
714      * @param mask determine memory layout for the registers
715      */
SaveRegisters(RegMask registers,bool isFp,ssize_t slot,Reg base,RegMask mask)716     virtual void SaveRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] bool isFp,
717                                [[maybe_unused]] ssize_t slot, [[maybe_unused]] Reg base, [[maybe_unused]] RegMask mask)
718     {
719         SetFalseResult();
720     }
LoadRegisters(RegMask registers,bool isFp,ssize_t slot,Reg base,RegMask mask)721     virtual void LoadRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] bool isFp,
722                                [[maybe_unused]] ssize_t slot, [[maybe_unused]] Reg base, [[maybe_unused]] RegMask mask)
723     {
724         SetFalseResult();
725     }
726 
727     void PushRegisters(RegMask regs, VRegMask fpRegs, bool isAligned = true)
728     {
729         ASSERT(GetArch() != Arch::AARCH64 || isAligned);
730         PushRegisters(regs, false);
731         PushRegisters(fpRegs, true);
732 
733         bool isEven {(regs.Count() + fpRegs.Count()) % 2U == 0U};
734         if (GetArch() != Arch::AARCH64 && isEven != isAligned) {
735             EncodeSub(GetTarget().GetStackReg(), GetTarget().GetStackReg(), Imm(GetTarget().WordSize()));
736         }
737     }
738 
739     void PopRegisters(RegMask regs, VRegMask fpRegs, bool isAligned = true)
740     {
741         bool isEven {(regs.Count() + fpRegs.Count()) % 2U == 0U};
742         if (GetArch() != Arch::AARCH64 && isEven != isAligned) {
743             EncodeAdd(GetTarget().GetStackReg(), GetTarget().GetStackReg(), Imm(GetTarget().WordSize()));
744         }
745 
746         PopRegisters(fpRegs, true);
747         PopRegisters(regs, false);
748     }
749 
PushRegisters(RegMask registers,bool isFp)750     virtual void PushRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] bool isFp)
751     {
752         SetFalseResult();
753     }
754 
PopRegisters(RegMask registers,bool isFp)755     virtual void PopRegisters([[maybe_unused]] RegMask registers, [[maybe_unused]] bool isFp)
756     {
757         SetFalseResult();
758     }
759 
GetRegfile()760     RegistersDescription *GetRegfile() const
761     {
762         ASSERT(regfile_ != nullptr);
763         return regfile_;
764     }
765 
SetRegfile(RegistersDescription * regfile)766     void SetRegfile(RegistersDescription *regfile)
767     {
768         regfile_ = regfile;
769     }
770 
AcquireScratchRegister(compiler::TypeInfo type)771     virtual compiler::Reg AcquireScratchRegister([[maybe_unused]] compiler::TypeInfo type)
772     {
773         return compiler::Reg();
774     }
775 
AcquireScratchRegister(compiler::Reg reg)776     virtual void AcquireScratchRegister([[maybe_unused]] compiler::Reg reg)
777     {
778         SetFalseResult();
779     }
780 
ReleaseScratchRegister(compiler::Reg reg)781     virtual void ReleaseScratchRegister([[maybe_unused]] compiler::Reg reg)
782     {
783         SetFalseResult();
784     }
785 
IsScratchRegisterReleased(compiler::Reg reg)786     virtual bool IsScratchRegisterReleased([[maybe_unused]] compiler::Reg reg)
787     {
788         return false;
789     }
790 
GetScratchRegistersCount()791     size_t GetScratchRegistersCount() const
792     {
793         return GetScratchRegistersMask().Count();
794     }
795 
GetScratchRegistersMask()796     virtual RegMask GetScratchRegistersMask() const
797     {
798         return 0;
799     }
800 
GetScratchFPRegistersCount()801     size_t GetScratchFPRegistersCount() const
802     {
803         return GetScratchFpRegistersMask().Count();
804     }
805 
GetScratchFpRegistersMask()806     virtual RegMask GetScratchFpRegistersMask() const
807     {
808         return 0;
809     }
810 
811     // Get Scratch registers, that currently are not allocated
GetAvailableScratchRegisters()812     virtual RegMask GetAvailableScratchRegisters() const
813     {
814         return 0;
815     }
816 
817     // Get Floating Point Scratch registers, that currently are not allocated
GetAvailableScratchFpRegisters()818     virtual VRegMask GetAvailableScratchFpRegisters() const
819     {
820         return 0;
821     }
822 
MaxArchInstPerEncoded()823     virtual size_t MaxArchInstPerEncoded()
824     {
825         static constexpr size_t MAX_ARCH_INST_PER_ENCODE = 32;
826         return MAX_ARCH_INST_PER_ENCODE;
827     }
828 
SetRegister(RegMask * mask,VRegMask * vmask,Reg reg)829     virtual void SetRegister(RegMask *mask, VRegMask *vmask, Reg reg)
830     {
831         SetRegister(mask, vmask, reg, true);
832     }
833 
SetRegister(RegMask * mask,VRegMask * vmask,Reg reg,bool val)834     virtual void SetRegister(RegMask *mask, VRegMask *vmask, Reg reg, bool val) const
835     {
836         if (!reg.IsValid()) {
837             return;
838         }
839         if (reg.IsScalar()) {
840             ASSERT(mask != nullptr);
841             mask->set(reg.GetId(), val);
842         } else {
843             ASSERT(vmask != nullptr);
844             ASSERT(reg.IsFloat());
845             if (vmask != nullptr) {
846                 vmask->set(reg.GetId(), val);
847             }
848         }
849     }
850 
GetRefType()851     virtual compiler::TypeInfo GetRefType()
852     {
853         return compiler::TypeInfo();
854     }
855 
856     virtual void Finalize() = 0;
857 
858 public:
859     /// Label-holder interfaces
CreateLabel()860     LabelHolder::LabelId CreateLabel()
861     {
862         auto labels = GetLabels();
863         ASSERT(labels != nullptr);
864         return labels->CreateLabel();
865     }
866 
BindLabel(LabelHolder::LabelId id)867     void BindLabel(LabelHolder::LabelId id)
868     {
869         auto labels = GetLabels();
870         ASSERT(labels != nullptr);
871         ASSERT(labels->Size() > id);
872         labels->BindLabel(id);
873     }
874 
GetLabels()875     virtual LabelHolder *GetLabels() const
876     {
877         return nullptr;
878     }
879     virtual size_t GetLabelAddress(LabelHolder::LabelId label) = 0;
880 
881     virtual bool LabelHasLinks(LabelHolder::LabelId label) = 0;
882 
883 public:
MakeCall(compiler::RelocationInfo * relocation)884     virtual void MakeCall([[maybe_unused]] compiler::RelocationInfo *relocation)
885     {
886         SetFalseResult();
887     }
888 
MakeCall(compiler::LabelHolder::LabelId id)889     virtual void MakeCall([[maybe_unused]] compiler::LabelHolder::LabelId id)
890     {
891         SetFalseResult();
892     }
893 
MakeCall(const void * entryPoint)894     virtual void MakeCall([[maybe_unused]] const void *entryPoint)
895     {
896         SetFalseResult();
897     }
898 
MakeCall(Reg reg)899     virtual void MakeCall([[maybe_unused]] Reg reg)
900     {
901         SetFalseResult();
902     }
903 
MakeCall(compiler::MemRef entryPoint)904     virtual void MakeCall([[maybe_unused]] compiler::MemRef entryPoint)
905     {
906         SetFalseResult();
907     }
908 
MakeCallAot(intptr_t offset)909     virtual void MakeCallAot([[maybe_unused]] intptr_t offset)
910     {
911         SetFalseResult();
912     }
913 
CanMakeCallByOffset(intptr_t offset)914     virtual bool CanMakeCallByOffset([[maybe_unused]] intptr_t offset)
915     {
916         return false;
917     }
918 
MakeCallByOffset(intptr_t offset)919     virtual void MakeCallByOffset([[maybe_unused]] intptr_t offset)
920     {
921         SetFalseResult();
922     }
923 
MakeLoadAotTable(intptr_t offset,compiler::Reg reg)924     virtual void MakeLoadAotTable([[maybe_unused]] intptr_t offset, [[maybe_unused]] compiler::Reg reg)
925     {
926         SetFalseResult();
927     }
928 
MakeLoadAotTableAddr(intptr_t offset,compiler::Reg addr,compiler::Reg val)929     virtual void MakeLoadAotTableAddr([[maybe_unused]] intptr_t offset, [[maybe_unused]] compiler::Reg addr,
930                                       [[maybe_unused]] compiler::Reg val)
931     {
932         SetFalseResult();
933     }
934 
935     // Encode unconditional branch
EncodeJump(compiler::LabelHolder::LabelId id)936     virtual void EncodeJump([[maybe_unused]] compiler::LabelHolder::LabelId id)
937     {
938         SetFalseResult();
939     }
940 
941     // Encode jump with compare to zero
EncodeJump(compiler::LabelHolder::LabelId id,compiler::Reg reg,compiler::Condition cond)942     virtual void EncodeJump([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] compiler::Reg reg,
943                             [[maybe_unused]] compiler::Condition cond)
944     {
945         SetFalseResult();
946     }
947 
948     // Compare reg and immediate and branch
EncodeJump(compiler::LabelHolder::LabelId id,compiler::Reg reg,compiler::Imm imm,compiler::Condition c)949     virtual void EncodeJump([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] compiler::Reg reg,
950                             [[maybe_unused]] compiler::Imm imm, [[maybe_unused]] compiler::Condition c)
951     {
952         SetFalseResult();
953     }
954 
955     // Compare two regs and branch
EncodeJump(compiler::LabelHolder::LabelId id,compiler::Reg r,compiler::Reg reg,compiler::Condition c)956     virtual void EncodeJump([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] compiler::Reg r,
957                             [[maybe_unused]] compiler::Reg reg, [[maybe_unused]] compiler::Condition c)
958     {
959         SetFalseResult();
960     }
961 
962     // Compare reg and immediate and branch
EncodeJumpTest(compiler::LabelHolder::LabelId id,compiler::Reg reg,compiler::Imm imm,compiler::Condition c)963     virtual void EncodeJumpTest([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] compiler::Reg reg,
964                                 [[maybe_unused]] compiler::Imm imm, [[maybe_unused]] compiler::Condition c)
965     {
966         SetFalseResult();
967     }
968 
969     // Compare two regs and branch
EncodeJumpTest(compiler::LabelHolder::LabelId id,compiler::Reg r,compiler::Reg reg,compiler::Condition c)970     virtual void EncodeJumpTest([[maybe_unused]] compiler::LabelHolder::LabelId id, [[maybe_unused]] compiler::Reg r,
971                                 [[maybe_unused]] compiler::Reg reg, [[maybe_unused]] compiler::Condition c)
972     {
973         SetFalseResult();
974     }
975 
976     // Encode jump by register value
EncodeJump(compiler::Reg reg)977     virtual void EncodeJump([[maybe_unused]] compiler::Reg reg)
978     {
979         SetFalseResult();
980     }
981 
EncodeJump(RelocationInfo * relocation)982     virtual void EncodeJump([[maybe_unused]] RelocationInfo *relocation)
983     {
984         SetFalseResult();
985     }
986 
EncodeBitTestAndBranch(compiler::LabelHolder::LabelId id,compiler::Reg reg,uint32_t bitPos,bool bitValue)987     virtual void EncodeBitTestAndBranch([[maybe_unused]] compiler::LabelHolder::LabelId id,
988                                         [[maybe_unused]] compiler::Reg reg, [[maybe_unused]] uint32_t bitPos,
989                                         [[maybe_unused]] bool bitValue)
990     {
991         SetFalseResult();
992     }
993 
EncodeAbort()994     virtual void EncodeAbort()
995     {
996         SetFalseResult();
997     }
998 
EncodeReturn()999     virtual void EncodeReturn()
1000     {
1001         SetFalseResult();
1002     }
1003 
SetFrameLayout(CFrameLayout fl)1004     void SetFrameLayout(CFrameLayout fl)
1005     {
1006         frameLayout_ = fl;
1007     }
1008 
GetFrameLayout()1009     const CFrameLayout &GetFrameLayout() const
1010     {
1011         return frameLayout_;
1012     }
1013 
GetLiveTmpRegMask()1014     RegMask GetLiveTmpRegMask()
1015     {
1016         return liveTmpRegs_;
1017     }
1018 
GetLiveTmpFpRegMask()1019     VRegMask GetLiveTmpFpRegMask()
1020     {
1021         return liveTmpFpRegs_;
1022     }
1023 
AddRegInLiveMask(Reg reg)1024     void AddRegInLiveMask(Reg reg)
1025     {
1026         if (!reg.IsValid()) {
1027             return;
1028         }
1029         if (reg.IsScalar()) {
1030             liveTmpRegs_.set(reg.GetId(), true);
1031         } else {
1032             ASSERT(reg.IsFloat());
1033             liveTmpFpRegs_.set(reg.GetId(), true);
1034         }
1035     }
1036 
RemoveRegFromLiveMask(Reg reg)1037     void RemoveRegFromLiveMask(Reg reg)
1038     {
1039         if (!reg.IsValid()) {
1040             return;
1041         }
1042         if (reg.IsScalar()) {
1043             liveTmpRegs_.set(reg.GetId(), false);
1044         } else {
1045             ASSERT(reg.IsFloat());
1046             liveTmpFpRegs_.set(reg.GetId(), false);
1047         }
1048     }
1049 
SetCodeOffset(size_t offset)1050     void SetCodeOffset(size_t offset)
1051     {
1052         codeOffset_ = offset;
1053     }
1054 
GetCodeOffset()1055     size_t GetCodeOffset() const
1056     {
1057         return codeOffset_;
1058     }
1059 
EnableLrAsTempReg(bool value)1060     void EnableLrAsTempReg(bool value)
1061     {
1062         enableLrAsTempReg_ = value;
1063     }
1064 
IsLrAsTempRegEnabled()1065     bool IsLrAsTempRegEnabled() const
1066     {
1067         return enableLrAsTempReg_;
1068     }
1069 
IsLrAsTempRegEnabledAndReleased()1070     bool IsLrAsTempRegEnabledAndReleased()
1071     {
1072         return IsLrAsTempRegEnabled() && IsScratchRegisterReleased(GetTarget().GetLinkReg());
1073     }
1074 
1075     NO_COPY_SEMANTIC(Encoder);
1076     NO_MOVE_SEMANTIC(Encoder);
1077 
1078 protected:
SetFrameSize(size_t size)1079     void SetFrameSize(size_t size)
1080     {
1081         frameSize_ = size;
1082     }
1083 
GetFrameSize()1084     size_t GetFrameSize() const
1085     {
1086         return frameSize_;
1087     }
1088 
1089     static constexpr size_t INVALID_OFFSET = std::numeric_limits<size_t>::max();
1090 
1091     // Max integer that can be represented in float/double without losing precision
MaxIntAsExactFloat()1092     constexpr float MaxIntAsExactFloat() const
1093     {
1094         return static_cast<float>((1U << static_cast<unsigned>(std::numeric_limits<float>::digits)) - 1);
1095     }
1096 
MaxIntAsExactDouble()1097     constexpr double MaxIntAsExactDouble() const
1098     {
1099         return static_cast<double>((1ULL << static_cast<unsigned>(std::numeric_limits<double>::digits)) - 1);
1100     }
1101 
1102 private:
1103     ArenaAllocator *allocator_;
1104     RegistersDescription *regfile_ {nullptr};
1105     size_t frameSize_ {0};
1106 
1107     CFrameLayout frameLayout_;
1108 
1109     RegMask liveTmpRegs_;
1110     VRegMask liveTmpFpRegs_;
1111 
1112     // In case of AOT compilation, this variable specifies offset from the start of the AOT file.
1113     // It is needed for accessing to the entrypoints table and AOT table, that lie right before code.
1114     size_t codeOffset_ {INVALID_OFFSET};
1115 
1116     Target target_ {Arch::NONE};
1117 
1118     bool success_ {true};
1119     bool jsNumberCast_ {false};
1120     // If true, then ScopedTmpReg can use LR as a temp register.
1121     bool enableLrAsTempReg_ {false};
1122 };  // Encoder
1123 
1124 /**
1125  * This class is using to acquire/release temp register using RAII technique.
1126  *
1127  * @tparam lazy if true, temp register will be acquired in the constructor, otherwise user should acquire it explicitly.
1128  */
1129 template <bool LAZY>
1130 class ScopedTmpRegImpl {
1131 public:
ScopedTmpRegImpl(Encoder * encoder)1132     explicit ScopedTmpRegImpl(Encoder *encoder) : ScopedTmpRegImpl(encoder, false) {}
ScopedTmpRegImpl(Encoder * encoder,bool withLr)1133     ScopedTmpRegImpl(Encoder *encoder, bool withLr) : encoder_(encoder)
1134     {
1135         if constexpr (!LAZY) {  // NOLINT
1136             auto linkReg = encoder->GetTarget().GetLinkReg();
1137             withLr &= encoder->IsLrAsTempRegEnabled();
1138             if (withLr && encoder->IsScratchRegisterReleased(linkReg)) {
1139                 reg_ = linkReg;
1140                 encoder->AcquireScratchRegister(linkReg);
1141             } else {
1142                 reg_ = encoder->AcquireScratchRegister(Is64BitsArch(encoder->GetArch()) ? INT64_TYPE : INT32_TYPE);
1143             }
1144         }
1145     }
1146 
ScopedTmpRegImpl(Encoder * encoder,TypeInfo type)1147     ScopedTmpRegImpl(Encoder *encoder, TypeInfo type) : encoder_(encoder), reg_(encoder->AcquireScratchRegister(type))
1148     {
1149         static_assert(!LAZY);
1150     }
1151 
ScopedTmpRegImpl(Encoder * encoder,Reg reg)1152     ScopedTmpRegImpl(Encoder *encoder, Reg reg) : encoder_(encoder), reg_(reg)
1153     {
1154         static_assert(!LAZY);
1155         encoder->AcquireScratchRegister(reg);
1156     }
1157 
ScopedTmpRegImpl(ScopedTmpRegImpl && other)1158     ScopedTmpRegImpl(ScopedTmpRegImpl &&other) noexcept
1159     {
1160         encoder_ = other.encoder_;
1161         reg_ = other.reg_;
1162         other.reg_ = Reg();
1163         ASSERT(!other.reg_.IsValid());
1164     }
1165 
~ScopedTmpRegImpl()1166     virtual ~ScopedTmpRegImpl()
1167     {
1168         if (reg_.IsValid()) {
1169             encoder_->ReleaseScratchRegister(reg_);
1170         }
1171     }
1172 
1173     NO_COPY_SEMANTIC(ScopedTmpRegImpl);
1174     NO_MOVE_OPERATOR(ScopedTmpRegImpl);
1175 
GetReg()1176     Reg GetReg() const
1177     {
1178         return reg_;
1179     }
1180 
GetType()1181     TypeInfo GetType() const
1182     {
1183         return reg_.GetType();
1184     }
1185 
1186     // NOLINTNEXTLINE(google-explicit-constructor)
Reg()1187     operator Reg() const
1188     {
1189         return reg_;
1190     }
1191 
ChangeType(TypeInfo tp)1192     void ChangeType(TypeInfo tp)
1193     {
1194         ASSERT(tp.IsScalar() == reg_.IsScalar());
1195         reg_ = Reg(reg_.GetId(), tp);
1196     }
1197 
Release()1198     virtual void Release()
1199     {
1200         if (reg_.IsValid()) {
1201             encoder_->ReleaseScratchRegister(reg_);
1202             reg_ = INVALID_REGISTER;
1203         }
1204     }
1205 
Acquire()1206     void Acquire()
1207     {
1208         ASSERT(!reg_.IsValid());
1209         reg_ = encoder_->AcquireScratchRegister(Is64BitsArch(encoder_->GetArch()) ? INT64_TYPE : INT32_TYPE);
1210         ASSERT(reg_.IsValid());
1211     }
1212 
AcquireWithLr()1213     void AcquireWithLr()
1214     {
1215         ASSERT(!reg_.IsValid());
1216         auto linkReg = encoder_->GetTarget().GetLinkReg();
1217         if (encoder_->IsLrAsTempRegEnabled() && encoder_->IsScratchRegisterReleased(linkReg)) {
1218             reg_ = linkReg;
1219             encoder_->AcquireScratchRegister(linkReg);
1220         } else {
1221             reg_ = encoder_->AcquireScratchRegister(Is64BitsArch(encoder_->GetArch()) ? INT64_TYPE : INT32_TYPE);
1222         }
1223         ASSERT(reg_.IsValid());
1224     }
1225 
AcquireIfInvalid()1226     void AcquireIfInvalid()
1227     {
1228         if (!reg_.IsValid()) {
1229             reg_ = encoder_->AcquireScratchRegister(Is64BitsArch(encoder_->GetArch()) ? INT64_TYPE : INT32_TYPE);
1230             ASSERT(reg_.IsValid());
1231         }
1232     }
1233 
1234 protected:
GetEncoder()1235     Encoder *GetEncoder()
1236     {
1237         return encoder_;
1238     }
1239 
1240 private:
1241     Encoder *encoder_ {nullptr};
1242     Reg reg_;
1243 };
1244 
1245 struct ScopedTmpReg : public ScopedTmpRegImpl<false> {
1246     using ScopedTmpRegImpl<false>::ScopedTmpRegImpl;
1247 };
1248 
1249 struct ScopedTmpRegLazy : public ScopedTmpRegImpl<true> {
1250     using ScopedTmpRegImpl<true>::ScopedTmpRegImpl;
1251 };
1252 
1253 struct ScopedTmpRegU16 : public ScopedTmpReg {
ScopedTmpRegU16ScopedTmpRegU161254     explicit ScopedTmpRegU16(Encoder *encoder) : ScopedTmpReg(encoder, INT16_TYPE) {}
1255 };
1256 
1257 struct ScopedTmpRegU32 : public ScopedTmpReg {
ScopedTmpRegU32ScopedTmpRegU321258     explicit ScopedTmpRegU32(Encoder *encoder) : ScopedTmpReg(encoder, INT32_TYPE) {}
1259 };
1260 
1261 struct ScopedTmpRegU64 : public ScopedTmpReg {
ScopedTmpRegU64ScopedTmpRegU641262     explicit ScopedTmpRegU64(Encoder *encoder) : ScopedTmpReg(encoder, INT64_TYPE) {}
1263 };
1264 
1265 struct ScopedTmpRegF32 : public ScopedTmpReg {
ScopedTmpRegF32ScopedTmpRegF321266     explicit ScopedTmpRegF32(Encoder *encoder) : ScopedTmpReg(encoder, FLOAT32_TYPE) {}
1267 };
1268 
1269 struct ScopedTmpRegF64 : public ScopedTmpReg {
ScopedTmpRegF64ScopedTmpRegF641270     explicit ScopedTmpRegF64(Encoder *encoder) : ScopedTmpReg(encoder, FLOAT64_TYPE) {}
1271 };
1272 
1273 struct ScopedTmpRegRef : public ScopedTmpReg {
ScopedTmpRegRefScopedTmpRegRef1274     explicit ScopedTmpRegRef(Encoder *encoder) : ScopedTmpReg(encoder, encoder->GetRefType()) {}
1275 };
1276 
1277 class ScopedLiveTmpReg : public ScopedTmpReg {
1278 public:
ScopedLiveTmpReg(Encoder * encoder)1279     explicit ScopedLiveTmpReg(Encoder *encoder) : ScopedTmpReg(encoder)
1280     {
1281         encoder->AddRegInLiveMask(GetReg());
1282     }
ScopedLiveTmpReg(Encoder * encoder,TypeInfo type)1283     ScopedLiveTmpReg(Encoder *encoder, TypeInfo type) : ScopedTmpReg(encoder, type)
1284     {
1285         encoder->AddRegInLiveMask(GetReg());
1286     }
1287 
Release()1288     void Release() final
1289     {
1290         ASSERT(GetReg().IsValid());
1291         GetEncoder()->RemoveRegFromLiveMask(GetReg());
1292         ScopedTmpReg::Release();
1293     }
1294 
~ScopedLiveTmpReg()1295     ~ScopedLiveTmpReg() override
1296     {
1297         if (GetReg().IsValid()) {
1298             GetEncoder()->RemoveRegFromLiveMask(GetReg());
1299         }
1300     }
1301 
1302     NO_COPY_SEMANTIC(ScopedLiveTmpReg);
1303     NO_MOVE_SEMANTIC(ScopedLiveTmpReg);
1304 };
1305 
1306 }  // namespace panda::compiler
1307 
1308 #endif  // COMPILER_OPTIMIZER_CODEGEN_ENCODE_H
1309