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 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; 100 } else if (scale_ == H) { 101 return 16; 102 } else if (scale_ == S) { 103 return 32; 104 } else if (scale_ == D) { 105 return 64; 106 } else if (scale_ == Q) { 107 return 128; 108 } 109 UNREACHABLE(); 110 } 111 private: 112 VectorRegisterId reg_; 113 Scale scale_; 114 }; 115 116 class Immediate { 117 public: Immediate(int64_t value)118 Immediate(int64_t value) : value_(value) {} 119 ~Immediate() = default; 120 Value()121 int64_t Value() const 122 { 123 return value_; 124 } 125 private: 126 int64_t value_; 127 }; 128 129 class LogicalImmediate { 130 public: 131 static LogicalImmediate Create(uint64_t imm, int width); Value()132 int Value() const 133 { 134 ASSERT(IsValid()); 135 return imm_; 136 } 137 IsValid()138 bool IsValid() const 139 { 140 return imm_ != InvalidLogicalImmediate; 141 } 142 Is64bit()143 bool Is64bit() const 144 { 145 return imm_ & BITWISE_OP_N_MASK; 146 } 147 private: LogicalImmediate(int value)148 explicit LogicalImmediate(int value) 149 : imm_(value) 150 { 151 } 152 static const int InvalidLogicalImmediate = -1; 153 int imm_; 154 }; 155 156 class Operand { 157 public: Operand(Immediate imm)158 Operand(Immediate imm) 159 : reg_(RegisterId::INVALID_REG), extend_(Extend::NO_EXTEND), shift_(Shift::NO_SHIFT), 160 shiftAmount_(0), immediate_(imm) 161 { 162 } 163 Operand(Register reg, Shift shift = Shift::LSL, uint8_t shift_amount = 0) reg_(reg)164 : reg_(reg), extend_(Extend::NO_EXTEND), shift_(shift), shiftAmount_(shift_amount), immediate_(0) 165 { 166 } 167 Operand(Register reg, Extend extend, uint8_t shiftAmount = 0) reg_(reg)168 : reg_(reg), extend_(extend), shift_(Shift::NO_SHIFT), shiftAmount_(shiftAmount), immediate_(0) 169 { 170 } 171 ~Operand() = default; 172 IsImmediate()173 inline bool IsImmediate() const 174 { 175 return !reg_.IsValid(); 176 } 177 IsShifted()178 inline bool IsShifted() const 179 { 180 return reg_.IsValid() && shift_ != Shift::NO_SHIFT; 181 } 182 IsExtended()183 inline bool IsExtended() const 184 { 185 return reg_.IsValid() && extend_ != Extend::NO_EXTEND; 186 } 187 Reg()188 inline Register Reg() const 189 { 190 return reg_; 191 } 192 GetShiftOption()193 inline Shift GetShiftOption() const 194 { 195 return shift_; 196 } 197 GetExtendOption()198 inline Extend GetExtendOption() const 199 { 200 return extend_; 201 } 202 GetShiftAmount()203 inline uint8_t GetShiftAmount() const 204 { 205 return shiftAmount_; 206 } 207 ImmediateValue()208 inline int64_t ImmediateValue() const 209 { 210 return immediate_.Value(); 211 } 212 GetImmediate()213 inline Immediate GetImmediate() const 214 { 215 return immediate_; 216 } 217 private: 218 Register reg_; 219 Extend extend_; 220 Shift shift_; 221 uint8_t shiftAmount_; 222 Immediate immediate_; 223 }; 224 225 class MemoryOperand { 226 public: 227 MemoryOperand(Register base, Register offset, Extend extend, uint8_t shiftAmount = 0) base_(base)228 : base_(base), offsetReg_(offset), offsetImm_(0), addrmod_(AddrMode::OFFSET), 229 extend_(extend), shift_(Shift::NO_SHIFT), shiftAmount_(shiftAmount) 230 { 231 } 232 MemoryOperand(Register base, Register offset, Shift shift = Shift::NO_SHIFT, uint8_t shiftAmount = 0) base_(base)233 : base_(base), offsetReg_(offset), offsetImm_(0), addrmod_(AddrMode::OFFSET), 234 extend_(Extend::NO_EXTEND), shift_(shift), shiftAmount_(shiftAmount) 235 { 236 } 237 MemoryOperand(Register base, int64_t offset, AddrMode addrmod = AddrMode::OFFSET) base_(base)238 : base_(base), offsetReg_(RegisterId::INVALID_REG), offsetImm_(offset), addrmod_(addrmod), 239 extend_(Extend::NO_EXTEND), shift_(Shift::NO_SHIFT), shiftAmount_(0) 240 { 241 } 242 ~MemoryOperand() = default; 243 GetRegBase()244 Register GetRegBase() const 245 { 246 return base_; 247 } 248 IsImmediateOffset()249 bool IsImmediateOffset() const 250 { 251 return !offsetReg_.IsValid(); 252 } 253 GetImmediate()254 Immediate GetImmediate() const 255 { 256 return offsetImm_; 257 } 258 GetAddrMode()259 AddrMode GetAddrMode() const 260 { 261 return addrmod_; 262 } 263 GetExtendOption()264 Extend GetExtendOption() const 265 { 266 return extend_; 267 } 268 GetShiftOption()269 Shift GetShiftOption() const 270 { 271 return shift_; 272 } 273 GetShiftAmount()274 uint8_t GetShiftAmount() const 275 { 276 return shiftAmount_; 277 } 278 GetRegisterOffset()279 Register GetRegisterOffset() const 280 { 281 return offsetReg_; 282 } 283 private: 284 Register base_; 285 Register offsetReg_; 286 Immediate offsetImm_; 287 AddrMode addrmod_; 288 Extend extend_; 289 Shift shift_; 290 uint8_t shiftAmount_; 291 }; 292 293 class AssemblerAarch64 : public Assembler { 294 public: AssemblerAarch64(Chunk * chunk)295 explicit AssemblerAarch64(Chunk *chunk) 296 : Assembler(chunk) 297 { 298 } 299 void Ldp(const Register &rt, const Register &rt2, const MemoryOperand &operand); 300 void Stp(const Register &rt, const Register &rt2, const MemoryOperand &operand); 301 void Ldp(const VectorRegister &vt, const VectorRegister &vt2, const MemoryOperand &operand); 302 void Stp(const VectorRegister &vt, const VectorRegister &vt2, const MemoryOperand &operand); 303 void Ldr(const Register &rt, const MemoryOperand &operand); 304 void Ldrh(const Register &rt, const MemoryOperand &operand); 305 void Ldrb(const Register &rt, const MemoryOperand &operand); 306 void Str(const Register &rt, const MemoryOperand &operand); 307 void Ldur(const Register &rt, const MemoryOperand &operand); 308 void Stur(const Register &rt, const MemoryOperand &operand); 309 void Mov(const Register &rd, const Immediate &imm); 310 void Mov(const Register &rd, const Register &rm); 311 void Movz(const Register &rd, uint64_t imm, int shift); 312 void Movk(const Register &rd, uint64_t imm, int shift); 313 void Movn(const Register &rd, uint64_t imm, int shift); 314 void Orr(const Register &rd, const Register &rn, const LogicalImmediate &imm); 315 void Orr(const Register &rd, const Register &rn, const Operand &operand); 316 void And(const Register &rd, const Register &rn, const Operand &operand); 317 void Ands(const Register &rd, const Register &rn, const Operand &operand); 318 void And(const Register &rd, const Register &rn, const LogicalImmediate &imm); 319 void Ands(const Register &rd, const Register &rn, const LogicalImmediate &imm); 320 void Lsr(const Register &rd, const Register &rn, unsigned shift); 321 void Lsl(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