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