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 22namespace panda::ecmascript::aarch64 { 23class Register { 24public: 25 Register(RegisterId reg, RegisterType type = RegisterType::X) : reg_(reg), type_(type) {}; 26 27 Register W() const 28 { 29 return Register(reg_, RegisterType::W); 30 } 31 32 Register X() const 33 { 34 return Register(reg_, RegisterType::X); 35 } 36 37 RegisterType GetType() const 38 { 39 return type_; 40 } 41 42 inline bool IsSp() const 43 { 44 return reg_ == RegisterId::SP; 45 } 46 47 inline bool IsW() const 48 { 49 return type_ == RegisterType::W; 50 } 51 52 inline RegisterId GetId() const 53 { 54 return reg_; 55 } 56 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 72private: 73 RegisterId reg_; 74 RegisterType type_; 75}; 76 77class VectorRegister { 78public: 79 explicit VectorRegister(VectorRegisterId reg, Scale scale = D) : reg_(reg), scale_(scale) {}; 80 81 inline VectorRegisterId GetId() const 82 { 83 return reg_; 84 } 85 86 inline bool IsValid() const 87 { 88 return reg_ != VectorRegisterId::INVALID_VREG; 89 } 90 91 inline Scale GetScale() const 92 { 93 return scale_; 94 } 95 96 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 } 112private: 113 VectorRegisterId reg_; 114 Scale scale_; 115}; 116 117class Immediate { 118public: 119 Immediate(int64_t value) : value_(value) {} 120 ~Immediate() = default; 121 122 int64_t Value() const 123 { 124 return value_; 125 } 126private: 127 int64_t value_; 128}; 129 130class LogicalImmediate { 131public: 132 static LogicalImmediate Create(uint64_t imm, int width); 133 int Value() const 134 { 135 ASSERT(IsValid()); 136 return imm_; 137 } 138 139 bool IsValid() const 140 { 141 return imm_ != InvalidLogicalImmediate; 142 } 143 144 bool Is64bit() const 145 { 146 return imm_ & BITWISE_OP_N_MASK; 147 } 148private: 149 explicit LogicalImmediate(int value) 150 : imm_(value) 151 { 152 } 153 static const int InvalidLogicalImmediate = -1; 154 int imm_; 155}; 156 157class Operand { 158public: 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) 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) 169 : reg_(reg), extend_(extend), shift_(Shift::NO_SHIFT), shiftAmount_(shiftAmount), immediate_(0) 170 { 171 } 172 ~Operand() = default; 173 174 inline bool IsImmediate() const 175 { 176 return !reg_.IsValid(); 177 } 178 179 inline bool IsShifted() const 180 { 181 return reg_.IsValid() && shift_ != Shift::NO_SHIFT; 182 } 183 184 inline bool IsExtended() const 185 { 186 return reg_.IsValid() && extend_ != Extend::NO_EXTEND; 187 } 188 189 inline Register Reg() const 190 { 191 return reg_; 192 } 193 194 inline Shift GetShiftOption() const 195 { 196 return shift_; 197 } 198 199 inline Extend GetExtendOption() const 200 { 201 return extend_; 202 } 203 204 inline uint8_t GetShiftAmount() const 205 { 206 return shiftAmount_; 207 } 208 209 inline int64_t ImmediateValue() const 210 { 211 return immediate_.Value(); 212 } 213 214 inline Immediate GetImmediate() const 215 { 216 return immediate_; 217 } 218private: 219 Register reg_; 220 Extend extend_; 221 Shift shift_; 222 uint8_t shiftAmount_; 223 Immediate immediate_; 224}; 225 226class MemoryOperand { 227public: 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 } 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 } 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 245 Register GetRegBase() const 246 { 247 return base_; 248 } 249 250 bool IsImmediateOffset() const 251 { 252 return !offsetReg_.IsValid(); 253 } 254 255 Immediate GetImmediate() const 256 { 257 return offsetImm_; 258 } 259 260 AddrMode GetAddrMode() const 261 { 262 return addrmod_; 263 } 264 265 Extend GetExtendOption() const 266 { 267 return extend_; 268 } 269 270 Shift GetShiftOption() const 271 { 272 return shift_; 273 } 274 275 uint8_t GetShiftAmount() const 276 { 277 return shiftAmount_; 278 } 279 280 Register GetRegisterOffset() const 281 { 282 return offsetReg_; 283 } 284private: 285 Register base_; 286 Register offsetReg_; 287 Immediate offsetImm_; 288 AddrMode addrmod_; 289 Extend extend_; 290 Shift shift_; 291 uint8_t shiftAmount_; 292}; 293 294class AssemblerAarch64 : public Assembler { 295public: 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); 355private: 356 // common reg field defines 357 inline uint32_t Rd(uint32_t id) 358 { 359 return (id << COMMON_REG_Rd_LOWBITS) & COMMON_REG_Rd_MASK; 360 } 361 362 inline uint32_t Rn(uint32_t id) 363 { 364 return (id << COMMON_REG_Rn_LOWBITS) & COMMON_REG_Rn_MASK; 365 } 366 367 inline uint32_t Rm(uint32_t id) 368 { 369 return (id << COMMON_REG_Rm_LOWBITS) & COMMON_REG_Rm_MASK; 370 } 371 372 inline uint32_t Rt(uint32_t id) 373 { 374 return (id << COMMON_REG_Rt_LOWBITS) & COMMON_REG_Rt_MASK; 375 } 376 377 inline uint32_t Rt2(uint32_t id) 378 { 379 return (id << COMMON_REG_Rt2_LOWBITS) & COMMON_REG_Rt2_MASK; 380 } 381 382 inline uint32_t Sf(uint32_t id) 383 { 384 return (id << COMMON_REG_Sf_LOWBITS) & COMMON_REG_Sf_MASK; 385 } 386 387 inline uint32_t LoadAndStorePairImm(uint32_t imm) 388 { 389 return (((imm) << LDP_STP_Imm7_LOWBITS) & LDP_STP_Imm7_MASK); 390 } 391 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 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