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