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