odin-blend2d

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

pipecompiler.cpp (5243B)


      1 // This file is part of Blend2D project <https://blend2d.com>
      2 //
      3 // See blend2d.h or LICENSE.md for license and copyright information
      4 // SPDX-License-Identifier: Zlib
      5 
      6 #include "../../api-build_p.h"
      7 #if !defined(BL_BUILD_NO_JIT)
      8 
      9 #include "../../pipeline/jit/pipecompiler_p.h"
     10 #include "../../pipeline/jit/pipepart_p.h"
     11 #include "../../support/intops_p.h"
     12 
     13 namespace bl::Pipeline::JIT {
     14 
     15 // bl::Pipeline::PipeCompiler - Construction & Destruction
     16 // =======================================================
     17 
     18 PipeCompiler::PipeCompiler(BackendCompiler* cc, const CpuFeatures& cpu_features, CpuHints cpu_hints) noexcept
     19   : UniCompiler(cc, cpu_features, cpu_hints, VecConstTableRef{common_table, sizeof(common_table)}) {}
     20 
     21 PipeCompiler::~PipeCompiler() noexcept {}
     22 
     23 // bl::Pipeline::PipeCompiler - Predicate Helpers
     24 // ==============================================
     25 
     26 #if defined(BL_JIT_ARCH_X86)
     27 static KReg PipeCompiler_make_mask_predicate(PipeCompiler* pc, PixelPredicate& predicate, size_t last_n, const Gp& adjusted_count) noexcept {
     28   BL_ASSERT(last_n <= 64);
     29   BL_ASSERT(IntOps::is_power_of_2(last_n));
     30 
     31   KReg k_pred;
     32   if (!pc->has_avx512())
     33     return k_pred;
     34 
     35   uint32_t materialized_count = predicate._materialized_count;
     36   for (uint32_t i = 0; i < materialized_count; i++) {
     37     const PixelPredicate::MaterializedMask& p = predicate._materialized_masks[i];
     38     if (p.last_n == last_n && p.element_size == 0u) {
     39       // If the record was created it has to provide a mask register, not any other register type.
     40       BL_ASSERT(p.mask.is_kreg());
     41       return p.mask.as<KReg>();
     42     }
     43   }
     44 
     45   if (materialized_count >= PixelPredicate::kMaterializedMaskCapacity)
     46     return k_pred;
     47 
     48   BackendCompiler* cc = pc->cc;
     49   bool use_bzhi = last_n <= 32 || pc->is_64bit();
     50 
     51   if (last_n <= 32)
     52     k_pred = cc->new_kd("@k_pred");
     53   else
     54     k_pred = cc->new_kq("@k_pred");
     55 
     56   PixelPredicate::MaterializedMask& p = predicate._materialized_masks[materialized_count];
     57   p.last_n = uint8_t(last_n);
     58   p.element_size = 0;
     59   p.mask = k_pred;
     60 
     61   Gp gp_count = predicate.count();
     62 
     63   if (adjusted_count.is_valid()) {
     64     gp_count = adjusted_count;
     65   }
     66   else if (last_n < predicate.size()) {
     67     gp_count = pc->new_gpz("@gp_count");
     68     pc->and_(gp_count.clone_as(predicate.count()), predicate.count(), last_n - 1);
     69   }
     70 
     71   if (use_bzhi) {
     72     Gp gp_pred = pc->new_gpz("@gp_pred");
     73 
     74     if (last_n <= 32)
     75       gp_pred = gp_pred.r32();
     76 
     77     cc->mov(gp_pred, -1);
     78     cc->bzhi(gp_pred, gp_pred, gp_count.clone_as(gp_pred));
     79 
     80     if (last_n <= 32)
     81       cc->kmovd(k_pred, gp_pred);
     82     else
     83       cc->kmovq(k_pred, gp_pred);
     84   }
     85   else {
     86     x86::Mem mem = pc->_get_mem_const(common_table.k_msk64_data);
     87     mem.set_index(cc->gpz(gp_count.id()));
     88     mem.set_shift(3);
     89 
     90     if (last_n <= 8)
     91       cc->kmovb(k_pred, mem);
     92     else if (last_n <= 16)
     93       cc->kmovw(k_pred, mem);
     94     else if (last_n <= 32)
     95       cc->kmovd(k_pred, mem);
     96     else
     97       cc->kmovq(k_pred, mem);
     98   }
     99 
    100   predicate._materialized_count++;
    101   return k_pred;
    102 }
    103 
    104 KReg PipeCompiler::make_mask_predicate(PixelPredicate& predicate, size_t last_n) noexcept {
    105   Gp no_adjusted_count;
    106   return PipeCompiler_make_mask_predicate(this, predicate, last_n, no_adjusted_count);
    107 }
    108 
    109 KReg PipeCompiler::make_mask_predicate(PixelPredicate& predicate, size_t last_n, const Gp& adjusted_count) noexcept {
    110   return PipeCompiler_make_mask_predicate(this, predicate, last_n, adjusted_count);
    111 }
    112 
    113 Vec PipeCompiler::make_vec_predicate32(PixelPredicate& predicate, size_t last_n) noexcept {
    114   Gp no_adjusted_count;
    115   return make_vec_predicate32(predicate, last_n, no_adjusted_count);
    116 }
    117 
    118 Vec PipeCompiler::make_vec_predicate32(PixelPredicate& predicate, size_t last_n, const Gp& adjusted_count) noexcept {
    119   BL_ASSERT(last_n <= 8);
    120   BL_ASSERT(IntOps::is_power_of_2(last_n));
    121 
    122   Vec v_pred;
    123   if (!has_avx())
    124     return v_pred;
    125 
    126   uint32_t materialized_count = predicate._materialized_count;
    127   for (uint32_t i = 0; i < materialized_count; i++) {
    128     const PixelPredicate::MaterializedMask& p = predicate._materialized_masks[i];
    129     if (p.last_n == last_n && p.element_size == 4u) {
    130       // If the record was created it has to provide a mask register, not any other register type.
    131       BL_ASSERT(p.mask.is_vec());
    132       return p.mask.as<Vec>();
    133     }
    134   }
    135 
    136   if (materialized_count >= PixelPredicate::kMaterializedMaskCapacity)
    137     return v_pred;
    138 
    139   if (last_n <= 4)
    140     v_pred = new_vec128("@vPred128");
    141   else if (last_n <= 8)
    142     v_pred = new_vec256("@vPred256");
    143   else
    144     BL_NOT_REACHED();
    145 
    146   PixelPredicate::MaterializedMask& p = predicate._materialized_masks[materialized_count];
    147   p.last_n = uint8_t(last_n);
    148   p.element_size = uint8_t(4);
    149   p.mask = v_pred;
    150 
    151   Gp gp_count = predicate.count();
    152 
    153   if (adjusted_count.is_valid()) {
    154     gp_count = adjusted_count;
    155   }
    156   else if (last_n < predicate.size()) {
    157     gp_count = new_gpz("@gp_count");
    158     and_(gp_count.clone_as(predicate.count()), predicate.count(), last_n - 1);
    159   }
    160 
    161   x86::Mem mem = _get_mem_const(common_table.loadstore16_lo8_msk8());
    162   mem.set_index(cc->gpz(gp_count.id()));
    163   mem.set_shift(3);
    164   cc->vpmovsxbd(v_pred, mem);
    165 
    166   predicate._materialized_count++;
    167   return v_pred;
    168 }
    169 #endif // !BL_BUILD_NO_JIT
    170 
    171 } // {bl::Pipeline::JIT}
    172 
    173 #endif