1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef ECMASCRIPT_COMPILER_ASSEMBLER_AARCH64_H
17#define ECMASCRIPT_COMPILER_ASSEMBLER_AARCH64_H
18
19#include "ecmascript/compiler/assembler/assembler.h"
20#include "ecmascript/compiler/assembler/aarch64/assembler_aarch64_constants.h"
21
22namespace panda::ecmascript::aarch64 {
23class Register {
24public:
25    Register(RegisterId reg, RegisterType type = RegisterType::X) : reg_(reg), type_(type) {};
26
27    Register W() const
28    {
29        return Register(reg_, RegisterType::W);
30    }
31
32    Register X() const
33    {
34        return Register(reg_, RegisterType::X);
35    }
36
37    RegisterType GetType() const
38    {
39        return type_;
40    }
41
42    inline bool IsSp() const
43    {
44        return reg_ == RegisterId::SP;
45    }
46
47    inline bool IsW() const
48    {
49        return type_ == RegisterType::W;
50    }
51
52    inline RegisterId GetId() const
53    {
54        return reg_;
55    }
56
57    inline bool IsValid() const
58    {
59        return reg_ != RegisterId::INVALID_REG;
60    }
61
62    inline bool operator !=(const Register &other)
63    {
64        return reg_ != other.GetId() || type_ != other.GetType();
65    }
66
67    inline bool operator ==(const Register &other)
68    {
69        return reg_ == other.GetId() && type_ == other.GetType();
70    }
71
72private:
73    RegisterId reg_;
74    RegisterType type_;
75};
76
77class VectorRegister {
78public:
79    explicit VectorRegister(VectorRegisterId reg, Scale scale = D) : reg_(reg), scale_(scale) {};
80
81    inline VectorRegisterId GetId() const
82    {
83        return reg_;
84    }
85
86    inline bool IsValid() const
87    {
88        return reg_ != VectorRegisterId::INVALID_VREG;
89    }
90
91    inline Scale GetScale() const
92    {
93        return scale_;
94    }
95
96    inline int GetRegSize() const
97    {
98        if (scale_ == B) {
99            return 8; // 8:Register size
100        } else if (scale_ == H) {
101            return 16; // 16:Register size
102        } else if (scale_ == S) {
103            return 32; // 32:Register size
104        } else if (scale_ == D) {
105            return 64; // 64:Register size
106        } else if (scale_ == Q) {
107            return 128; // 128:Register size
108        }
109        LOG_ECMA(FATAL) << "this branch is unreachable";
110        UNREACHABLE();
111    }
112private:
113    VectorRegisterId reg_;
114    Scale scale_;
115};
116
117class Immediate {
118public:
119    Immediate(int64_t value) : value_(value) {}
120    ~Immediate() = default;
121
122    int64_t Value() const
123    {
124        return value_;
125    }
126private:
127    int64_t value_;
128};
129
130class LogicalImmediate {
131public:
132    static LogicalImmediate Create(uint64_t imm, int width);
133    int Value() const
134    {
135        ASSERT(IsValid());
136        return imm_;
137    }
138
139    bool IsValid() const
140    {
141        return imm_ != InvalidLogicalImmediate;
142    }
143
144    bool Is64bit() const
145    {
146        return imm_ & BITWISE_OP_N_MASK;
147    }
148private:
149    explicit LogicalImmediate(int value)
150        : imm_(value)
151    {
152    }
153    static const int InvalidLogicalImmediate = -1;
154    int imm_;
155};
156
157class Operand {
158public:
159    Operand(Immediate imm)
160        : reg_(RegisterId::INVALID_REG), extend_(Extend::NO_EXTEND), shift_(Shift::NO_SHIFT),
161          shiftAmount_(0), immediate_(imm)
162    {
163    }
164    Operand(Register reg, Shift shift = Shift::LSL, uint8_t shift_amount = 0)
165        : reg_(reg), extend_(Extend::NO_EXTEND), shift_(shift), shiftAmount_(shift_amount), immediate_(0)
166    {
167    }
168    Operand(Register reg, Extend extend, uint8_t shiftAmount = 0)
169        : reg_(reg), extend_(extend), shift_(Shift::NO_SHIFT), shiftAmount_(shiftAmount), immediate_(0)
170    {
171    }
172    ~Operand() = default;
173
174    inline bool IsImmediate() const
175    {
176        return !reg_.IsValid();
177    }
178
179    inline bool IsShifted() const
180    {
181        return reg_.IsValid() && shift_ != Shift::NO_SHIFT;
182    }
183
184    inline bool IsExtended() const
185    {
186        return reg_.IsValid() && extend_ != Extend::NO_EXTEND;
187    }
188
189    inline Register Reg() const
190    {
191        return reg_;
192    }
193
194    inline Shift GetShiftOption() const
195    {
196        return shift_;
197    }
198
199    inline Extend GetExtendOption() const
200    {
201        return extend_;
202    }
203
204    inline uint8_t GetShiftAmount() const
205    {
206        return shiftAmount_;
207    }
208
209    inline int64_t ImmediateValue() const
210    {
211        return immediate_.Value();
212    }
213
214    inline Immediate GetImmediate() const
215    {
216        return immediate_;
217    }
218private:
219    Register reg_;
220    Extend  extend_;
221    Shift  shift_;
222    uint8_t  shiftAmount_;
223    Immediate immediate_;
224};
225
226class MemoryOperand {
227public:
228    MemoryOperand(Register base, Register offset, Extend extend, uint8_t  shiftAmount = 0)
229        : base_(base), offsetReg_(offset), offsetImm_(0), addrmod_(AddrMode::OFFSET),
230          extend_(extend), shift_(Shift::NO_SHIFT), shiftAmount_(shiftAmount)
231    {
232    }
233    MemoryOperand(Register base, Register offset, Shift shift = Shift::NO_SHIFT, uint8_t  shiftAmount = 0)
234        : base_(base), offsetReg_(offset), offsetImm_(0), addrmod_(AddrMode::OFFSET),
235          extend_(Extend::NO_EXTEND), shift_(shift), shiftAmount_(shiftAmount)
236    {
237    }
238    MemoryOperand(Register base, int64_t offset, AddrMode addrmod = AddrMode::OFFSET)
239        : base_(base), offsetReg_(RegisterId::INVALID_REG), offsetImm_(offset), addrmod_(addrmod),
240          extend_(Extend::NO_EXTEND), shift_(Shift::NO_SHIFT), shiftAmount_(0)
241    {
242    }
243    ~MemoryOperand() = default;
244
245    Register GetRegBase() const
246    {
247        return base_;
248    }
249
250    bool IsImmediateOffset() const
251    {
252        return !offsetReg_.IsValid();
253    }
254
255    Immediate GetImmediate() const
256    {
257        return offsetImm_;
258    }
259
260    AddrMode GetAddrMode() const
261    {
262        return addrmod_;
263    }
264
265    Extend GetExtendOption() const
266    {
267        return extend_;
268    }
269
270    Shift GetShiftOption() const
271    {
272        return shift_;
273    }
274
275    uint8_t GetShiftAmount() const
276    {
277        return shiftAmount_;
278    }
279
280    Register GetRegisterOffset() const
281    {
282        return offsetReg_;
283    }
284private:
285    Register base_;
286    Register offsetReg_;
287    Immediate offsetImm_;
288    AddrMode addrmod_;
289    Extend extend_;
290    Shift shift_;
291    uint8_t shiftAmount_;
292};
293
294class AssemblerAarch64 : public Assembler {
295public:
296    explicit AssemblerAarch64(Chunk *chunk)
297        : Assembler(chunk)
298    {
299    }
300    void Ldp(const Register &rt, const Register &rt2, const MemoryOperand &operand);
301    void Stp(const Register &rt, const Register &rt2, const MemoryOperand &operand);
302    void Ldp(const VectorRegister &vt, const VectorRegister &vt2, const MemoryOperand &operand);
303    void Stp(const VectorRegister &vt, const VectorRegister &vt2, const MemoryOperand &operand);
304    void Ldr(const Register &rt, const MemoryOperand &operand);
305    void Ldrh(const Register &rt, const MemoryOperand &operand);
306    void Ldrb(const Register &rt, const MemoryOperand &operand);
307    void Str(const Register &rt, const MemoryOperand &operand);
308    void Ldur(const Register &rt, const MemoryOperand &operand);
309    void Stur(const Register &rt, const MemoryOperand &operand);
310    void Mov(const Register &rd, const Immediate &imm);
311    void Mov(const Register &rd, const Register &rm);
312    void Movz(const Register &rd, uint64_t imm, int shift);
313    void Movk(const Register &rd, uint64_t imm, int shift);
314    void Movn(const Register &rd, uint64_t imm, int shift);
315    void Orr(const Register &rd, const Register &rn, const LogicalImmediate &imm);
316    void Orr(const Register &rd, const Register &rn, const Operand &operand);
317    void And(const Register &rd, const Register &rn, const Operand &operand);
318    void Ands(const Register &rd, const Register &rn, const Operand &operand);
319    void And(const Register &rd, const Register &rn, const LogicalImmediate &imm);
320    void Ands(const Register &rd, const Register &rn, const LogicalImmediate &imm);
321    void Lsr(const Register &rd, const Register &rn, unsigned shift);
322    void Lsl(const Register &rd, const Register &rn, const Register &rm);
323    void Lsr(const Register &rd, const Register &rn, const Register &rm);
324    void Ubfm(const Register &rd, const Register &rn, unsigned immr, unsigned imms);
325    void Bfm(const Register &rd, const Register &rn, unsigned immr, unsigned imms);
326
327    void Add(const Register &rd, const Register &rn, const Operand &operand);
328    void Adds(const Register &rd, const Register &rn, const Operand &operand);
329    void Sub(const Register &rd, const Register &rn, const Operand &operand);
330    void Subs(const Register &rd, const Register &rn, const Operand &operand);
331    void Cmp(const Register &rd, const Operand &operand);
332    void CMov(const Register &rd, const Register &rn, const Operand &operand, Condition cond);
333    void B(Label *label);
334    void B(int32_t imm);
335    void B(Condition cond, Label *label);
336    void B(Condition cond, int32_t imm);
337    void Br(const Register &rn);
338    void Blr(const Register &rn);
339    void Bl(Label *label);
340    void Bl(int32_t imm);
341    void Cbz(const Register &rt, int32_t imm);
342    void Cbz(const Register &rt, Label *label);
343    void Cbnz(const Register &rt, int32_t imm);
344    void Cbnz(const Register &rt, Label *label);
345    void Tbz(const Register &rt, int32_t bitPos, Label *label);
346    void Tbz(const Register &rt, int32_t bitPos, int32_t imm);
347    void Tbnz(const Register &rt, int32_t bitPos, Label *label);
348    void Tbnz(const Register &rt, int32_t bitPos, int32_t imm);
349    void Tst(const Register &rn, const Operand &operand);
350    void Tst(const Register &rn, const LogicalImmediate &imm);
351    void Ret();
352    void Ret(const Register &rn);
353    void Brk(const Immediate &imm);
354    void Bind(Label *target);
355private:
356    // common reg field defines
357    inline uint32_t Rd(uint32_t id)
358    {
359        return (id << COMMON_REG_Rd_LOWBITS) & COMMON_REG_Rd_MASK;
360    }
361
362    inline uint32_t Rn(uint32_t id)
363    {
364        return (id << COMMON_REG_Rn_LOWBITS) & COMMON_REG_Rn_MASK;
365    }
366
367    inline uint32_t Rm(uint32_t id)
368    {
369        return (id << COMMON_REG_Rm_LOWBITS) & COMMON_REG_Rm_MASK;
370    }
371
372    inline uint32_t Rt(uint32_t id)
373    {
374        return (id << COMMON_REG_Rt_LOWBITS) & COMMON_REG_Rt_MASK;
375    }
376
377    inline uint32_t Rt2(uint32_t id)
378    {
379        return (id << COMMON_REG_Rt2_LOWBITS) & COMMON_REG_Rt2_MASK;
380    }
381
382    inline uint32_t Sf(uint32_t id)
383    {
384        return (id << COMMON_REG_Sf_LOWBITS) & COMMON_REG_Sf_MASK;
385    }
386
387    inline uint32_t LoadAndStorePairImm(uint32_t imm)
388    {
389        return (((imm) << LDP_STP_Imm7_LOWBITS) & LDP_STP_Imm7_MASK);
390    }
391
392    inline uint32_t LoadAndStoreImm(uint32_t imm, bool isSigned)
393    {
394        if (isSigned) {
395            return (imm << LDR_STR_Imm9_LOWBITS) & LDR_STR_Imm9_MASK;
396        } else {
397            return (imm << LDR_STR_Imm12_LOWBITS) & LDR_STR_Imm12_MASK;
398        }
399    }
400
401    inline uint32_t BranchImm19(uint32_t imm)
402    {
403        return (imm << BRANCH_Imm19_LOWBITS) & BRANCH_Imm19_MASK;
404    }
405
406    uint32_t GetOpcFromScale(Scale scale, bool ispair);
407    bool IsAddSubImm(uint64_t imm);
408    void AddSubImm(AddSubOpCode op, const Register &rd, const Register &rn, bool setFlags, uint64_t imm);
409    void AddSubReg(AddSubOpCode op, const Register &rd, const Register &rn, bool setFlags, const Operand &operand);
410    void MovWide(uint32_t op, const Register &rd, uint64_t imm, int shift);
411    void BitWiseOpImm(BitwiseOpCode op, const Register &rd, const Register &rn, uint64_t imm);
412    void BitWiseOpShift(BitwiseOpCode op, const Register &rd, const Register &rn, const Operand &operand);
413    bool TrySequenceOfOnes(const Register &rd, uint64_t imm);
414    bool TryReplicateHWords(const Register &rd, uint64_t imm);
415    void EmitMovInstruct(const Register &rd, uint64_t imm,
416                         unsigned int allOneHWords, unsigned int allZeroHWords);
417    int32_t GetLinkOffsetFromBranchInst(int32_t pos);
418    int32_t LinkAndGetInstOffsetToLabel(Label *label);
419    int32_t ImmBranch(uint32_t branchCode);
420    void SetRealOffsetToBranchInst(uint32_t linkPos, int32_t disp);
421    void Ldr(const Register &rt, const MemoryOperand &operand, Scale scale);
422    uint64_t GetImmOfLdr(const MemoryOperand &operand, Scale scale, bool isRegX);
423    uint64_t GetOpcodeOfLdr(const MemoryOperand &operand, Scale scale);
424    uint32_t GetShiftOfLdr(const MemoryOperand &operand, Scale scale, bool isRegX);
425};
426}  // namespace panda::ecmascript::aarch64
427#endif
428