a64emithelper.cpp (14154B)
1 // This file is part of AsmJit project <https://asmjit.com> 2 // 3 // See <asmjit/core.h> or LICENSE.md for license and copyright information 4 // SPDX-License-Identifier: Zlib 5 6 #include "../core/api-build_p.h" 7 #if !defined(ASMJIT_NO_AARCH64) 8 9 #include "../core/formatter.h" 10 #include "../core/funcargscontext_p.h" 11 #include "../core/string.h" 12 #include "../core/support.h" 13 #include "../core/type.h" 14 #include "../arm/a64emithelper_p.h" 15 #include "../arm/a64formatter_p.h" 16 #include "../arm/a64instapi_p.h" 17 #include "../arm/a64operand.h" 18 19 ASMJIT_BEGIN_SUB_NAMESPACE(a64) 20 21 // a64::EmitHelper - Emit Operations 22 // ================================= 23 24 ASMJIT_FAVOR_SIZE Error EmitHelper::emit_reg_move( 25 const Operand_& dst_, 26 const Operand_& src_, TypeId type_id, const char* comment) { 27 28 Emitter* emitter = _emitter->as<Emitter>(); 29 30 // Invalid or abstract TypeIds are not allowed. 31 ASMJIT_ASSERT(TypeUtils::is_valid(type_id) && !TypeUtils::is_abstract(type_id)); 32 33 emitter->set_inline_comment(comment); 34 35 if (dst_.is_reg() && src_.is_mem()) { 36 Reg dst(dst_.as<Reg>()); 37 Mem src(src_.as<Mem>()); 38 39 switch (type_id) { 40 case TypeId::kInt8: 41 case TypeId::kUInt8: 42 return emitter->ldrb(dst.as<Gp>(), src); 43 44 case TypeId::kInt16: 45 case TypeId::kUInt16: 46 return emitter->ldrh(dst.as<Gp>(), src); 47 48 case TypeId::kInt32: 49 case TypeId::kUInt32: 50 return emitter->ldr(dst.as<Gp>().w(), src); 51 52 case TypeId::kInt64: 53 case TypeId::kUInt64: 54 return emitter->ldr(dst.as<Gp>().x(), src); 55 56 default: { 57 if (TypeUtils::is_float32(type_id) || TypeUtils::is_vec32(type_id)) { 58 return emitter->ldr(dst.as<Vec>().s(), src); 59 } 60 61 if (TypeUtils::is_float64(type_id) || TypeUtils::is_vec64(type_id)) { 62 return emitter->ldr(dst.as<Vec>().d(), src); 63 } 64 65 if (TypeUtils::is_vec128(type_id)) { 66 return emitter->ldr(dst.as<Vec>().q(), src); 67 } 68 69 break; 70 } 71 } 72 } 73 74 if (dst_.is_mem() && src_.is_reg()) { 75 Mem dst(dst_.as<Mem>()); 76 Reg src(src_.as<Reg>()); 77 78 switch (type_id) { 79 case TypeId::kInt8: 80 case TypeId::kUInt8: 81 return emitter->strb(src.as<Gp>(), dst); 82 83 case TypeId::kInt16: 84 case TypeId::kUInt16: 85 return emitter->strh(src.as<Gp>(), dst); 86 87 case TypeId::kInt32: 88 case TypeId::kUInt32: 89 return emitter->str(src.as<Gp>().w(), dst); 90 91 case TypeId::kInt64: 92 case TypeId::kUInt64: 93 return emitter->str(src.as<Gp>().x(), dst); 94 95 default: { 96 if (TypeUtils::is_float32(type_id) || TypeUtils::is_vec32(type_id)) { 97 return emitter->str(src.as<Vec>().s(), dst); 98 } 99 100 if (TypeUtils::is_float64(type_id) || TypeUtils::is_vec64(type_id)) { 101 return emitter->str(src.as<Vec>().d(), dst); 102 } 103 104 if (TypeUtils::is_vec128(type_id)) { 105 return emitter->str(src.as<Vec>().q(), dst); 106 } 107 108 break; 109 } 110 } 111 } 112 113 if (dst_.is_reg() && src_.is_reg()) { 114 Reg dst(dst_.as<Reg>()); 115 Reg src(src_.as<Reg>()); 116 117 switch (type_id) { 118 case TypeId::kInt8: 119 case TypeId::kUInt8: 120 case TypeId::kInt16: 121 case TypeId::kUInt16: 122 case TypeId::kInt32: 123 case TypeId::kUInt32: 124 case TypeId::kInt64: 125 case TypeId::kUInt64: 126 return emitter->mov(dst.as<Gp>().x(), src.as<Gp>().x()); 127 128 default: { 129 if (TypeUtils::is_float32(type_id) || TypeUtils::is_vec32(type_id)) { 130 return emitter->fmov(dst.as<Vec>().s(), src.as<Vec>().s()); 131 } 132 133 if (TypeUtils::is_float64(type_id) || TypeUtils::is_vec64(type_id)) { 134 return emitter->mov(dst.as<Vec>().b8(), src.as<Vec>().b8()); 135 } 136 137 if (TypeUtils::is_vec128(type_id)) { 138 return emitter->mov(dst.as<Vec>().b16(), src.as<Vec>().b16()); 139 } 140 141 break; 142 } 143 } 144 } 145 146 emitter->set_inline_comment(nullptr); 147 return make_error(Error::kInvalidState); 148 } 149 150 Error EmitHelper::emit_reg_swap( 151 const Reg& a, 152 const Reg& b, const char* comment) { 153 154 Support::maybe_unused(a, b, comment); 155 return make_error(Error::kInvalidState); 156 } 157 158 // TODO: [ARM] EmitArgMove is unfinished. 159 Error EmitHelper::emit_arg_move( 160 const Reg& dst_, TypeId dst_type_id, 161 const Operand_& src_, TypeId src_type_id, const char* comment) { 162 163 // Deduce optional `dst_type_id`, which may be `TypeId::kVoid` in some cases. 164 if (dst_type_id == TypeId::kVoid) { 165 dst_type_id = RegUtils::type_id_of(dst_.reg_type()); 166 } 167 168 // Invalid or abstract TypeIds are not allowed. 169 ASMJIT_ASSERT(TypeUtils::is_valid(dst_type_id) && !TypeUtils::is_abstract(dst_type_id)); 170 ASMJIT_ASSERT(TypeUtils::is_valid(src_type_id) && !TypeUtils::is_abstract(src_type_id)); 171 172 Reg dst(dst_.as<Reg>()); 173 Operand src(src_); 174 175 uint32_t dst_size = TypeUtils::size_of(dst_type_id); 176 uint32_t src_size = TypeUtils::size_of(src_type_id); 177 178 if (TypeUtils::is_int(dst_type_id)) { 179 if (TypeUtils::is_int(src_type_id)) { 180 uint32_t x = uint32_t(dst_size == 8); 181 182 dst.set_signature(OperandSignature{x ? RegTraits<RegType::kGp64>::kSignature : RegTraits<RegType::kGp32>::kSignature}); 183 _emitter->set_inline_comment(comment); 184 185 if (src.is_reg()) { 186 src.set_signature(dst.signature()); 187 return _emitter->emit(Inst::kIdMov, dst, src); 188 } 189 else if (src.is_mem()) { 190 InstId inst_id = Inst::kIdNone; 191 switch (src_type_id) { 192 case TypeId::kInt8: inst_id = Inst::kIdLdrsb; break; 193 case TypeId::kUInt8: inst_id = Inst::kIdLdrb; break; 194 case TypeId::kInt16: inst_id = Inst::kIdLdrsh; break; 195 case TypeId::kUInt16: inst_id = Inst::kIdLdrh; break; 196 case TypeId::kInt32: inst_id = x ? Inst::kIdLdrsw : Inst::kIdLdr; break; 197 case TypeId::kUInt32: inst_id = Inst::kIdLdr; break; 198 case TypeId::kInt64: inst_id = Inst::kIdLdr; break; 199 case TypeId::kUInt64: inst_id = Inst::kIdLdr; break; 200 default: 201 return make_error(Error::kInvalidState); 202 } 203 return _emitter->emit(inst_id, dst, src); 204 } 205 } 206 } 207 208 if (TypeUtils::is_float(dst_type_id) || TypeUtils::is_vec(dst_type_id)) { 209 if (TypeUtils::is_float(src_type_id) || TypeUtils::is_vec(src_type_id)) { 210 switch (src_size) { 211 case 2: dst.as<Vec>().set_signature(RegTraits<RegType::kVec16>::kSignature); break; 212 case 4: dst.as<Vec>().set_signature(RegTraits<RegType::kVec32>::kSignature); break; 213 case 8: dst.as<Vec>().set_signature(RegTraits<RegType::kVec64>::kSignature); break; 214 case 16: dst.as<Vec>().set_signature(RegTraits<RegType::kVec128>::kSignature); break; 215 default: 216 return make_error(Error::kInvalidState); 217 } 218 219 _emitter->set_inline_comment(comment); 220 221 if (src.is_reg()) { 222 InstId inst_id = src_size <= 4 ? Inst::kIdFmov_v : Inst::kIdMov_v; 223 src.set_signature(dst.signature()); 224 return _emitter->emit(inst_id, dst, src); 225 } 226 else if (src.is_mem()) { 227 return _emitter->emit(Inst::kIdLdr_v, dst, src); 228 } 229 } 230 } 231 232 return make_error(Error::kInvalidState); 233 } 234 235 // a64::EmitHelper - Emit Prolog & Epilog 236 // ====================================== 237 238 struct LoadStoreInstructions { 239 InstId single_inst_id; 240 InstId pair_inst_id; 241 }; 242 243 struct PrologEpilogInfo { 244 struct RegPair { 245 uint8_t ids[2]; 246 uint16_t offset; 247 }; 248 249 struct GroupData { 250 RegPair pairs[16]; 251 uint32_t pair_count; 252 }; 253 254 Support::Array<GroupData, 2> groups; 255 uint32_t size_total; 256 257 Error init(const FuncFrame& frame) noexcept { 258 uint32_t offset = 0; 259 260 for (RegGroup group : Support::enumerate(RegGroup::kGp, RegGroup::kVec)) { 261 GroupData& data = groups[group]; 262 263 uint32_t n = 0; 264 uint32_t pair_count = 0; 265 RegPair* pairs = data.pairs; 266 267 uint32_t slot_size = frame.save_restore_reg_size(group); 268 RegMask saved_regs = frame.saved_regs(group); 269 270 if (group == RegGroup::kGp && frame.has_preserved_fp()) { 271 // Must be at the beginning of the push/pop sequence. 272 ASMJIT_ASSERT(pair_count == 0); 273 274 pairs[0].offset = uint16_t(offset); 275 pairs[0].ids[0] = Gp::kIdFp; 276 pairs[0].ids[1] = Gp::kIdLr; 277 offset += slot_size * 2; 278 pair_count++; 279 280 saved_regs &= ~Support::bit_mask<RegMask>(Gp::kIdFp, Gp::kIdLr); 281 } 282 283 Support::BitWordIterator<uint32_t> it(saved_regs); 284 while (it.has_next()) { 285 pairs[pair_count].ids[n] = uint8_t(it.next()); 286 287 if (++n == 2) { 288 pairs[pair_count].offset = uint16_t(offset); 289 offset += slot_size * 2; 290 291 n = 0; 292 pair_count++; 293 } 294 } 295 296 if (n == 1) { 297 pairs[pair_count].ids[1] = uint8_t(Reg::kIdBad); 298 pairs[pair_count].offset = uint16_t(offset); 299 offset += slot_size * 2; 300 pair_count++; 301 } 302 303 data.pair_count = pair_count; 304 } 305 306 size_total = offset; 307 return Error::kOk; 308 } 309 }; 310 311 ASMJIT_FAVOR_SIZE Error EmitHelper::emit_prolog(const FuncFrame& frame) { 312 Emitter* emitter = _emitter->as<Emitter>(); 313 314 PrologEpilogInfo pei; 315 ASMJIT_PROPAGATE(pei.init(frame)); 316 317 static const Support::Array<Reg, 2> group_regs = {{ x0, d0 }}; 318 static const Support::Array<LoadStoreInstructions, 2> group_insts = {{ 319 { Inst::kIdStr , Inst::kIdStp }, 320 { Inst::kIdStr_v, Inst::kIdStp_v } 321 }}; 322 323 // Emit: 'bti {jc}' (indirect branch protection). 324 if (frame.has_indirect_branch_protection()) { 325 ASMJIT_PROPAGATE(emitter->bti(Predicate::BTI::kJC)); 326 } 327 328 uint32_t adjust_initial_offset = pei.size_total; 329 330 for (RegGroup group : Support::enumerate(RegGroup::kGp, RegGroup::kVec)) { 331 const PrologEpilogInfo::GroupData& data = pei.groups[group]; 332 uint32_t pair_count = data.pair_count; 333 334 Reg regs[2] = { group_regs[group], group_regs[group] }; 335 Mem mem = ptr(sp); 336 337 const LoadStoreInstructions& insts = group_insts[group]; 338 for (uint32_t i = 0; i < pair_count; i++) { 339 const PrologEpilogInfo::RegPair& pair = data.pairs[i]; 340 341 regs[0].set_id(pair.ids[0]); 342 regs[1].set_id(pair.ids[1]); 343 mem.set_offset_lo32(pair.offset); 344 345 if (pair.offset == 0 && adjust_initial_offset) { 346 mem.set_offset(-int(adjust_initial_offset)); 347 mem.make_pre_index(); 348 } 349 350 if (pair.ids[1] == Reg::kIdBad) { 351 ASMJIT_PROPAGATE(emitter->emit(insts.single_inst_id, regs[0], mem)); 352 } 353 else { 354 ASMJIT_PROPAGATE(emitter->emit(insts.pair_inst_id, regs[0], regs[1], mem)); 355 } 356 357 mem.reset_offset_mode(); 358 359 if (i == 0 && frame.has_preserved_fp()) { 360 ASMJIT_PROPAGATE(emitter->mov(x29, sp)); 361 } 362 } 363 } 364 365 if (frame.has_stack_adjustment()) { 366 uint32_t adj = frame.stack_adjustment(); 367 if (adj <= 0xFFFu) { 368 ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj)); 369 } 370 else if (adj <= 0xFFFFFFu) { 371 // TODO: [ARM] Prolog - we must touch the pages otherwise it's undefined. 372 ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj & 0x000FFFu)); 373 ASMJIT_PROPAGATE(emitter->sub(sp, sp, adj & 0xFFF000u)); 374 } 375 else { 376 return make_error(Error::kInvalidState); 377 } 378 } 379 380 return Error::kOk; 381 } 382 383 // TODO: [ARM] Emit epilog. 384 ASMJIT_FAVOR_SIZE Error EmitHelper::emit_epilog(const FuncFrame& frame) { 385 Emitter* emitter = _emitter->as<Emitter>(); 386 387 PrologEpilogInfo pei; 388 ASMJIT_PROPAGATE(pei.init(frame)); 389 390 static const Support::Array<Reg, 2> group_regs = {{ x0, d0 }}; 391 static const Support::Array<LoadStoreInstructions, 2> group_insts = {{ 392 { Inst::kIdLdr , Inst::kIdLdp }, 393 { Inst::kIdLdr_v, Inst::kIdLdp_v } 394 }}; 395 396 uint32_t adjust_initial_offset = pei.size_total; 397 398 if (frame.has_stack_adjustment()) { 399 uint32_t adj = frame.stack_adjustment(); 400 if (adj <= 0xFFFu) { 401 ASMJIT_PROPAGATE(emitter->add(sp, sp, adj)); 402 } 403 else if (adj <= 0xFFFFFFu) { 404 ASMJIT_PROPAGATE(emitter->add(sp, sp, adj & 0x000FFFu)); 405 ASMJIT_PROPAGATE(emitter->add(sp, sp, adj & 0xFFF000u)); 406 } 407 else { 408 return make_error(Error::kInvalidState); 409 } 410 } 411 412 for (int g = 1; g >= 0; g--) { 413 RegGroup group = RegGroup(g); 414 const PrologEpilogInfo::GroupData& data = pei.groups[group]; 415 uint32_t pair_count = data.pair_count; 416 417 Reg regs[2] = { group_regs[group], group_regs[group] }; 418 Mem mem = ptr(sp); 419 420 const LoadStoreInstructions& insts = group_insts[group]; 421 422 for (int i = int(pair_count) - 1; i >= 0; i--) { 423 const PrologEpilogInfo::RegPair& pair = data.pairs[i]; 424 425 regs[0].set_id(pair.ids[0]); 426 regs[1].set_id(pair.ids[1]); 427 mem.set_offset_lo32(pair.offset); 428 429 if (pair.offset == 0 && adjust_initial_offset) { 430 mem.set_offset(int(adjust_initial_offset)); 431 mem.make_post_index(); 432 } 433 434 if (pair.ids[1] == Reg::kIdBad) { 435 ASMJIT_PROPAGATE(emitter->emit(insts.single_inst_id, regs[0], mem)); 436 } 437 else { 438 ASMJIT_PROPAGATE(emitter->emit(insts.pair_inst_id, regs[0], regs[1], mem)); 439 } 440 441 mem.reset_offset_mode(); 442 } 443 } 444 445 ASMJIT_PROPAGATE(emitter->ret(x30)); 446 447 return Error::kOk; 448 } 449 450 static Error ASMJIT_CDECL Emitter_emitProlog(BaseEmitter* emitter, const FuncFrame& frame) { 451 EmitHelper emit_helper(emitter); 452 return emit_helper.emit_prolog(frame); 453 } 454 455 static Error ASMJIT_CDECL Emitter_emitEpilog(BaseEmitter* emitter, const FuncFrame& frame) { 456 EmitHelper emit_helper(emitter); 457 return emit_helper.emit_epilog(frame); 458 } 459 460 static Error ASMJIT_CDECL Emitter_emitArgsAssignment(BaseEmitter* emitter, const FuncFrame& frame, const FuncArgsAssignment& args) { 461 EmitHelper emit_helper(emitter); 462 return emit_helper.emit_args_assignment(frame, args); 463 } 464 465 void init_emitter_funcs(BaseEmitter* emitter) { 466 emitter->_funcs.emit_prolog = Emitter_emitProlog; 467 emitter->_funcs.emit_epilog = Emitter_emitEpilog; 468 emitter->_funcs.emit_args_assignment = Emitter_emitArgsAssignment; 469 470 #ifndef ASMJIT_NO_LOGGING 471 emitter->_funcs.format_instruction = FormatterInternal::format_instruction; 472 #endif 473 474 #ifndef ASMJIT_NO_VALIDATION 475 emitter->_funcs.validate = InstInternal::validate; 476 #endif 477 } 478 479 ASMJIT_END_SUB_NAMESPACE 480 481 #endif // !ASMJIT_NO_AARCH64