• 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     explicit 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; // 8 : RegSize
100         } else if (scale_ == H) {
101             return 16; // 16 : RegSize
102         } else if (scale_ == S) {
103             return 32; // 32 : RegSize
104         } else if (scale_ == D) {
105             return 64; // 64 : RegSize
106         } else if (scale_ == Q) {
107             return 128; // 128 : RegSize
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()122     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()133     int Value() const
134     {
135         ASSERT(IsValid());
136         return imm_;
137     }
138 
IsValid()139     bool IsValid() const
140     {
141         return imm_ != InvalidLogicalImmediate;
142     }
143 
Is64bit()144     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     }
164     Operand(Register reg, Shift shift = Shift::LSL, uint8_t shift_amount = 0)
reg_(reg)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)
reg_(reg)169         : reg_(reg), extend_(extend), shift_(Shift::NO_SHIFT), shiftAmount_(shiftAmount), immediate_(0)
170     {
171     }
172     ~Operand() = default;
173 
IsImmediate()174     inline bool IsImmediate() const
175     {
176         return !reg_.IsValid();
177     }
178 
IsShifted()179     inline bool IsShifted() const
180     {
181         return reg_.IsValid() && shift_ != Shift::NO_SHIFT;
182     }
183 
IsExtended()184     inline bool IsExtended() const
185     {
186         return reg_.IsValid() && extend_ != Extend::NO_EXTEND;
187     }
188 
Reg()189     inline Register Reg() const
190     {
191         return reg_;
192     }
193 
GetShiftOption()194     inline Shift GetShiftOption() const
195     {
196         return shift_;
197     }
198 
GetExtendOption()199     inline Extend GetExtendOption() const
200     {
201         return extend_;
202     }
203 
GetShiftAmount()204     inline uint8_t GetShiftAmount() const
205     {
206         return shiftAmount_;
207     }
208 
ImmediateValue()209     inline int64_t ImmediateValue() const
210     {
211         return immediate_.Value();
212     }
213 
GetImmediate()214     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:
228     MemoryOperand(Register base, Register offset, Extend extend, uint8_t  shiftAmount = 0)
base_(base)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)
base_(base)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)
base_(base)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()245     Register GetRegBase() const
246     {
247         return base_;
248     }
249 
IsImmediateOffset()250     bool IsImmediateOffset() const
251     {
252         return !offsetReg_.IsValid();
253     }
254 
GetImmediate()255     Immediate GetImmediate() const
256     {
257         return offsetImm_;
258     }
259 
GetAddrMode()260     AddrMode GetAddrMode() const
261     {
262         return addrmod_;
263     }
264 
GetExtendOption()265     Extend GetExtendOption() const
266     {
267         return extend_;
268     }
269 
GetShiftOption()270     Shift GetShiftOption() const
271     {
272         return shift_;
273     }
274 
GetShiftAmount()275     uint8_t GetShiftAmount() const
276     {
277         return shiftAmount_;
278     }
279 
GetRegisterOffset()280     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 
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
427