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