odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

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