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