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 
22 namespace panda::ecmascript::aarch64 {
23 class Register {
24 public:
Register(RegisterId reg, RegisterType type = RegisterType::X)25     Register(RegisterId reg, RegisterType type = RegisterType::X) : reg_(reg), type_(type) {};
26 
W() const27     Register W() const
28     {
29         return Register(reg_, RegisterType::W);
30     }
31 
X() const32     Register X() const
33     {
34         return Register(reg_, RegisterType::X);
35     }
36 
GetType() const37     RegisterType GetType() const
38     {
39         return type_;
40     }
41 
IsSp() const42     inline bool IsSp() const
43     {
44         return reg_ == RegisterId::SP;
45     }
46 
IsW() const47     inline bool IsW() const
48     {
49         return type_ == RegisterType::W;
50     }
51 
GetId() const52     inline RegisterId GetId() const
53     {
54         return reg_;
55     }
56 
IsValid() const57     inline bool IsValid() const
58     {
59         return reg_ != RegisterId::INVALID_REG;
60     }
61 
operator !=(const Register &other)62     inline bool operator !=(const Register &other)
63     {
64         return reg_ != other.GetId() || type_ != other.GetType();
65     }
66 
operator ==(const Register &other)67     inline bool operator ==(const Register &other)
68     {
69         return reg_ == other.GetId() && type_ == other.GetType();
70     }
71 
72 private:
73     RegisterId reg_;
74     RegisterType type_;
75 };
76 
77 class VectorRegister {
78 public:
VectorRegister(VectorRegisterId reg, Scale scale = D)79     explicit VectorRegister(VectorRegisterId reg, Scale scale = D) : reg_(reg), scale_(scale) {};
80 
GetId() const81     inline VectorRegisterId GetId() const
82     {
83         return reg_;
84     }
85 
IsValid() const86     inline bool IsValid() const
87     {
88         return reg_ != VectorRegisterId::INVALID_VREG;
89     }
90 
GetScale() const91     inline Scale GetScale() const
92     {
93         return scale_;
94     }
95 
GetRegSize() const96     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     }
112 private:
113     VectorRegisterId reg_;
114     Scale scale_;
115 };
116 
117 class Immediate {
118 public:
Immediate(int64_t value)119     Immediate(int64_t value) : value_(value) {}
120     ~Immediate() = default;
121 
Value() const122     int64_t Value() const
123     {
124         return value_;
125     }
126 private:
127     int64_t value_;
128 };
129 
130 class LogicalImmediate {
131 public:
132     static LogicalImmediate Create(uint64_t imm, int width);
Value() const133     int Value() const
134     {
135         ASSERT(IsValid());
136         return imm_;
137     }
138 
IsValid() const139     bool IsValid() const
140     {
141         return imm_ != InvalidLogicalImmediate;
142     }
143 
Is64bit() const144     bool Is64bit() const
145     {
146         return imm_ & BITWISE_OP_N_MASK;
147     }
148 private:
LogicalImmediate(int value)149     explicit LogicalImmediate(int value)
150         : imm_(value)
151     {
152     }
153     static const int InvalidLogicalImmediate = -1;
154     int imm_;
155 };
156 
157 class Operand {
158 public:
Operand(Immediate imm)159     Operand(Immediate imm)
160         : reg_(RegisterId::INVALID_REG), extend_(Extend::NO_EXTEND), shift_(Shift::NO_SHIFT),
161           shiftAmount_(0), immediate_(imm)
162     {
163     }
Operand(Register reg, Shift shift = Shift::LSL, uint8_t shift_amount = 0)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     }
Operand(Register reg, Extend extend, uint8_t shiftAmount = 0)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 
IsImmediate() const174     inline bool IsImmediate() const
175     {
176         return !reg_.IsValid();
177     }
178 
IsShifted() const179     inline bool IsShifted() const
180     {
181         return reg_.IsValid() && shift_ != Shift::NO_SHIFT;
182     }
183 
IsExtended() const184     inline bool IsExtended() const
185     {
186         return reg_.IsValid() && extend_ != Extend::NO_EXTEND;
187     }
188 
Reg() const189     inline Register Reg() const
190     {
191         return reg_;
192     }
193 
GetShiftOption() const194     inline Shift GetShiftOption() const
195     {
196         return shift_;
197     }
198 
GetExtendOption() const199     inline Extend GetExtendOption() const
200     {
201         return extend_;
202     }
203 
GetShiftAmount() const204     inline uint8_t GetShiftAmount() const
205     {
206         return shiftAmount_;
207     }
208 
ImmediateValue() const209     inline int64_t ImmediateValue() const
210     {
211         return immediate_.Value();
212     }
213 
GetImmediate() const214     inline Immediate GetImmediate() const
215     {
216         return immediate_;
217     }
218 private:
219     Register reg_;
220     Extend  extend_;
221     Shift  shift_;
222     uint8_t  shiftAmount_;
223     Immediate immediate_;
224 };
225 
226 class MemoryOperand {
227 public:
MemoryOperand(Register base, Register offset, Extend extend, uint8_t shiftAmount = 0)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     }
MemoryOperand(Register base, Register offset, Shift shift = Shift::NO_SHIFT, uint8_t shiftAmount = 0)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     }
MemoryOperand(Register base, int64_t offset, AddrMode addrmod = AddrMode::OFFSET)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 
GetRegBase() const245     Register GetRegBase() const
246     {
247         return base_;
248     }
249 
IsImmediateOffset() const250     bool IsImmediateOffset() const
251     {
252         return !offsetReg_.IsValid();
253     }
254 
GetImmediate() const255     Immediate GetImmediate() const
256     {
257         return offsetImm_;
258     }
259 
GetAddrMode() const260     AddrMode GetAddrMode() const
261     {
262         return addrmod_;
263     }
264 
GetExtendOption() const265     Extend GetExtendOption() const
266     {
267         return extend_;
268     }
269 
GetShiftOption() const270     Shift GetShiftOption() const
271     {
272         return shift_;
273     }
274 
GetShiftAmount() const275     uint8_t GetShiftAmount() const
276     {
277         return shiftAmount_;
278     }
279 
GetRegisterOffset() const280     Register GetRegisterOffset() const
281     {
282         return offsetReg_;
283     }
284 private:
285     Register base_;
286     Register offsetReg_;
287     Immediate offsetImm_;
288     AddrMode addrmod_;
289     Extend extend_;
290     Shift shift_;
291     uint8_t shiftAmount_;
292 };
293 
294 class AssemblerAarch64 : public Assembler {
295 public:
AssemblerAarch64(Chunk *chunk)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);
355 private:
356     // common reg field defines
Rd(uint32_t id)357     inline uint32_t Rd(uint32_t id)
358     {
359         return (id << COMMON_REG_Rd_LOWBITS) & COMMON_REG_Rd_MASK;
360     }
361 
Rn(uint32_t id)362     inline uint32_t Rn(uint32_t id)
363     {
364         return (id << COMMON_REG_Rn_LOWBITS) & COMMON_REG_Rn_MASK;
365     }
366 
Rm(uint32_t id)367     inline uint32_t Rm(uint32_t id)
368     {
369         return (id << COMMON_REG_Rm_LOWBITS) & COMMON_REG_Rm_MASK;
370     }
371 
Rt(uint32_t id)372     inline uint32_t Rt(uint32_t id)
373     {
374         return (id << COMMON_REG_Rt_LOWBITS) & COMMON_REG_Rt_MASK;
375     }
376 
Rt2(uint32_t id)377     inline uint32_t Rt2(uint32_t id)
378     {
379         return (id << COMMON_REG_Rt2_LOWBITS) & COMMON_REG_Rt2_MASK;
380     }
381 
Sf(uint32_t id)382     inline uint32_t Sf(uint32_t id)
383     {
384         return (id << COMMON_REG_Sf_LOWBITS) & COMMON_REG_Sf_MASK;
385     }
386 
LoadAndStorePairImm(uint32_t imm)387     inline uint32_t LoadAndStorePairImm(uint32_t imm)
388     {
389         return (((imm) << LDP_STP_Imm7_LOWBITS) & LDP_STP_Imm7_MASK);
390     }
391 
LoadAndStoreImm(uint32_t imm, bool isSigned)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 
BranchImm19(uint32_t imm)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