Home | History | Annotate | Line # | Download | only in common
      1 /*
      2  * Copyright  2019 Intel Corporation
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining a
      5  * copy of this software and associated documentation files (the "Software"),
      6  * to deal in the Software without restriction, including without limitation
      7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8  * and/or sell copies of the Software, and to permit persons to whom the
      9  * Software is furnished to do so, subject to the following conditions:
     10  *
     11  * The above copyright notice and this permission notice (including the next
     12  * paragraph) shall be included in all copies or substantial portions of the
     13  * Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     21  * IN THE SOFTWARE.
     22  */
     23 
     24 #ifndef GEN_MI_BUILDER_H
     25 #define GEN_MI_BUILDER_H
     26 
     27 #include "util/bitscan.h"
     28 #include "util/fast_idiv_by_const.h"
     29 #include "util/u_math.h"
     30 
     31 #ifndef GEN_MI_BUILDER_NUM_ALLOC_GPRS
     32 /** The number of GPRs the MI builder is allowed to allocate
     33  *
     34  * This may be set by a user of this API so that it can reserve some GPRs at
     35  * the top end for its own use.
     36  */
     37 #define GEN_MI_BUILDER_NUM_ALLOC_GPRS 16
     38 #endif
     39 
     40 /** These must be defined by the user of the builder
     41  *
     42  * void *__gen_get_batch_dwords(__gen_user_data *user_data,
     43  *                              unsigned num_dwords);
     44  *
     45  * __gen_address_type
     46  * __gen_address_offset(__gen_address_type addr, uint64_t offset);
     47  *
     48  */
     49 
     50 /*
     51  * Start of the actual MI builder
     52  */
     53 
     54 #define __genxml_cmd_length(cmd) cmd ## _length
     55 #define __genxml_cmd_header(cmd) cmd ## _header
     56 #define __genxml_cmd_pack(cmd) cmd ## _pack
     57 
     58 #define gen_mi_builder_pack(b, cmd, dst, name)                          \
     59    for (struct cmd name = { __genxml_cmd_header(cmd) },                 \
     60         *_dst = (struct cmd *)(dst); __builtin_expect(_dst != NULL, 1); \
     61         __genxml_cmd_pack(cmd)((b)->user_data, (void *)_dst, &name),    \
     62         _dst = NULL)
     63 
     64 #define gen_mi_builder_emit(b, cmd, name)                               \
     65    gen_mi_builder_pack((b), cmd, __gen_get_batch_dwords((b)->user_data, __genxml_cmd_length(cmd)), name)
     66 
     67 
     68 enum gen_mi_value_type {
     69    GEN_MI_VALUE_TYPE_IMM,
     70    GEN_MI_VALUE_TYPE_MEM32,
     71    GEN_MI_VALUE_TYPE_MEM64,
     72    GEN_MI_VALUE_TYPE_REG32,
     73    GEN_MI_VALUE_TYPE_REG64,
     74 };
     75 
     76 struct gen_mi_value {
     77    enum gen_mi_value_type type;
     78 
     79    union {
     80       uint64_t imm;
     81       __gen_address_type addr;
     82       uint32_t reg;
     83    };
     84 
     85 #if GEN_GEN >= 7 || GEN_IS_HASWELL
     86    bool invert;
     87 #endif
     88 };
     89 
     90 #if GEN_GEN >= 9
     91 #define GEN_MI_BUILDER_MAX_MATH_DWORDS 256
     92 #else
     93 #define GEN_MI_BUILDER_MAX_MATH_DWORDS 64
     94 #endif
     95 
     96 struct gen_mi_builder {
     97    __gen_user_data *user_data;
     98 
     99 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    100    uint32_t gprs;
    101    uint8_t gpr_refs[GEN_MI_BUILDER_NUM_ALLOC_GPRS];
    102 
    103    unsigned num_math_dwords;
    104    uint32_t math_dwords[GEN_MI_BUILDER_MAX_MATH_DWORDS];
    105 #endif
    106 };
    107 
    108 static inline void
    109 gen_mi_builder_init(struct gen_mi_builder *b, __gen_user_data *user_data)
    110 {
    111    memset(b, 0, sizeof(*b));
    112    b->user_data = user_data;
    113 
    114 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    115    b->gprs = 0;
    116    b->num_math_dwords = 0;
    117 #endif
    118 }
    119 
    120 static inline void
    121 gen_mi_builder_flush_math(struct gen_mi_builder *b)
    122 {
    123 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    124    if (b->num_math_dwords == 0)
    125       return;
    126 
    127    uint32_t *dw = (uint32_t *)__gen_get_batch_dwords(b->user_data,
    128                                                      1 + b->num_math_dwords);
    129    gen_mi_builder_pack(b, GENX(MI_MATH), dw, math) {
    130       math.DWordLength = 1 + b->num_math_dwords - GENX(MI_MATH_length_bias);
    131    }
    132    memcpy(dw + 1, b->math_dwords, b->num_math_dwords * sizeof(uint32_t));
    133    b->num_math_dwords = 0;
    134 #endif
    135 }
    136 
    137 #define _GEN_MI_BUILDER_GPR_BASE 0x2600
    138 /* The actual hardware limit on GPRs */
    139 #define _GEN_MI_BUILDER_NUM_HW_GPRS 16
    140 
    141 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    142 
    143 static inline bool
    144 gen_mi_value_is_gpr(struct gen_mi_value val)
    145 {
    146    return (val.type == GEN_MI_VALUE_TYPE_REG32 ||
    147            val.type == GEN_MI_VALUE_TYPE_REG64) &&
    148           val.reg >= _GEN_MI_BUILDER_GPR_BASE &&
    149           val.reg < _GEN_MI_BUILDER_GPR_BASE +
    150                     _GEN_MI_BUILDER_NUM_HW_GPRS * 8;
    151 }
    152 
    153 static inline bool
    154 _gen_mi_value_is_allocated_gpr(struct gen_mi_value val)
    155 {
    156    return (val.type == GEN_MI_VALUE_TYPE_REG32 ||
    157            val.type == GEN_MI_VALUE_TYPE_REG64) &&
    158           val.reg >= _GEN_MI_BUILDER_GPR_BASE &&
    159           val.reg < _GEN_MI_BUILDER_GPR_BASE +
    160                     GEN_MI_BUILDER_NUM_ALLOC_GPRS * 8;
    161 }
    162 
    163 static inline uint32_t
    164 _gen_mi_value_as_gpr(struct gen_mi_value val)
    165 {
    166    assert(gen_mi_value_is_gpr(val));
    167    assert(val.reg % 8 == 0);
    168    return (val.reg - _GEN_MI_BUILDER_GPR_BASE) / 8;
    169 }
    170 
    171 static inline struct gen_mi_value
    172 gen_mi_new_gpr(struct gen_mi_builder *b)
    173 {
    174    unsigned gpr = ffs(~b->gprs) - 1;
    175    assert(gpr < GEN_MI_BUILDER_NUM_ALLOC_GPRS);
    176    assert(b->gpr_refs[gpr] == 0);
    177    b->gprs |= (1u << gpr);
    178    b->gpr_refs[gpr] = 1;
    179 
    180    return (struct gen_mi_value) {
    181       .type = GEN_MI_VALUE_TYPE_REG64,
    182       .reg = _GEN_MI_BUILDER_GPR_BASE + gpr * 8,
    183    };
    184 }
    185 #endif /* GEN_GEN >= 8 || GEN_IS_HASWELL */
    186 
    187 /** Take a reference to a gen_mi_value
    188  *
    189  * The MI builder uses reference counting to automatically free ALU GPRs for
    190  * re-use in calculations.  All gen_mi_* math functions consume the reference
    191  * they are handed for each source and return a reference to a value which the
    192  * caller must consume.  In particular, if you pas the same value into a
    193  * single gen_mi_* math function twice (say to add a number to itself), you
    194  * are responsible for calling gen_mi_value_ref() to get a second reference
    195  * because the gen_mi_* math function will consume it twice.
    196  */
    197 static inline struct gen_mi_value
    198 gen_mi_value_ref(struct gen_mi_builder *b, struct gen_mi_value val)
    199 {
    200 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    201    if (_gen_mi_value_is_allocated_gpr(val)) {
    202       unsigned gpr = _gen_mi_value_as_gpr(val);
    203       assert(gpr < GEN_MI_BUILDER_NUM_ALLOC_GPRS);
    204       assert(b->gprs & (1u << gpr));
    205       assert(b->gpr_refs[gpr] < UINT8_MAX);
    206       b->gpr_refs[gpr]++;
    207    }
    208 #endif /* GEN_GEN >= 8 || GEN_IS_HASWELL */
    209 
    210    return val;
    211 }
    212 
    213 /** Drop a reference to a gen_mi_value
    214  *
    215  * See also gen_mi_value_ref.
    216  */
    217 static inline void
    218 gen_mi_value_unref(struct gen_mi_builder *b, struct gen_mi_value val)
    219 {
    220 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    221    if (_gen_mi_value_is_allocated_gpr(val)) {
    222       unsigned gpr = _gen_mi_value_as_gpr(val);
    223       assert(gpr < GEN_MI_BUILDER_NUM_ALLOC_GPRS);
    224       assert(b->gprs & (1u << gpr));
    225       assert(b->gpr_refs[gpr] > 0);
    226       if (--b->gpr_refs[gpr] == 0)
    227          b->gprs &= ~(1u << gpr);
    228    }
    229 #endif /* GEN_GEN >= 8 || GEN_IS_HASWELL */
    230 }
    231 
    232 static inline struct gen_mi_value
    233 gen_mi_imm(uint64_t imm)
    234 {
    235    return (struct gen_mi_value) {
    236       .type = GEN_MI_VALUE_TYPE_IMM,
    237       .imm = imm,
    238    };
    239 }
    240 
    241 static inline struct gen_mi_value
    242 gen_mi_reg32(uint32_t reg)
    243 {
    244    struct gen_mi_value val = {
    245       .type = GEN_MI_VALUE_TYPE_REG32,
    246       .reg = reg,
    247    };
    248 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    249    assert(!_gen_mi_value_is_allocated_gpr(val));
    250 #endif
    251    return val;
    252 }
    253 
    254 static inline struct gen_mi_value
    255 gen_mi_reg64(uint32_t reg)
    256 {
    257    struct gen_mi_value val = {
    258       .type = GEN_MI_VALUE_TYPE_REG64,
    259       .reg = reg,
    260    };
    261 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    262    assert(!_gen_mi_value_is_allocated_gpr(val));
    263 #endif
    264    return val;
    265 }
    266 
    267 static inline struct gen_mi_value
    268 gen_mi_mem32(__gen_address_type addr)
    269 {
    270    return (struct gen_mi_value) {
    271       .type = GEN_MI_VALUE_TYPE_MEM32,
    272       .addr = addr,
    273    };
    274 }
    275 
    276 static inline struct gen_mi_value
    277 gen_mi_mem64(__gen_address_type addr)
    278 {
    279    return (struct gen_mi_value) {
    280       .type = GEN_MI_VALUE_TYPE_MEM64,
    281       .addr = addr,
    282    };
    283 }
    284 
    285 static inline struct gen_mi_value
    286 gen_mi_value_half(struct gen_mi_value value, bool top_32_bits)
    287 {
    288    switch (value.type) {
    289    case GEN_MI_VALUE_TYPE_IMM:
    290       if (top_32_bits)
    291          value.imm >>= 32;
    292       else
    293          value.imm &= 0xffffffffu;
    294       return value;
    295 
    296    case GEN_MI_VALUE_TYPE_MEM32:
    297       assert(!top_32_bits);
    298       return value;
    299 
    300    case GEN_MI_VALUE_TYPE_MEM64:
    301       if (top_32_bits)
    302          value.addr = __gen_address_offset(value.addr, 4);
    303       value.type = GEN_MI_VALUE_TYPE_MEM32;
    304       return value;
    305 
    306    case GEN_MI_VALUE_TYPE_REG32:
    307       assert(!top_32_bits);
    308       return value;
    309 
    310    case GEN_MI_VALUE_TYPE_REG64:
    311       if (top_32_bits)
    312          value.reg += 4;
    313       value.type = GEN_MI_VALUE_TYPE_REG32;
    314       return value;
    315    }
    316 
    317    unreachable("Invalid gen_mi_value type");
    318 }
    319 
    320 static inline void
    321 _gen_mi_copy_no_unref(struct gen_mi_builder *b,
    322                       struct gen_mi_value dst, struct gen_mi_value src)
    323 {
    324 #if GEN_GEN >= 7 || GEN_IS_HASWELL
    325    /* TODO: We could handle src.invert by emitting a bit of math if we really
    326     * wanted to.
    327     */
    328    assert(!dst.invert && !src.invert);
    329 #endif
    330    gen_mi_builder_flush_math(b);
    331 
    332    switch (dst.type) {
    333    case GEN_MI_VALUE_TYPE_IMM:
    334       unreachable("Cannot copy to an immediate");
    335 
    336    case GEN_MI_VALUE_TYPE_MEM64:
    337    case GEN_MI_VALUE_TYPE_REG64:
    338       /* If the destination is 64 bits, we have to copy in two halves */
    339       _gen_mi_copy_no_unref(b, gen_mi_value_half(dst, false),
    340                                gen_mi_value_half(src, false));
    341       switch (src.type) {
    342       case GEN_MI_VALUE_TYPE_IMM:
    343       case GEN_MI_VALUE_TYPE_MEM64:
    344       case GEN_MI_VALUE_TYPE_REG64:
    345          /* TODO: Use MI_STORE_DATA_IMM::StoreQWord when we have it */
    346          _gen_mi_copy_no_unref(b, gen_mi_value_half(dst, true),
    347                                   gen_mi_value_half(src, true));
    348          break;
    349       default:
    350          _gen_mi_copy_no_unref(b, gen_mi_value_half(dst, true),
    351                                   gen_mi_imm(0));
    352          break;
    353       }
    354       break;
    355 
    356    case GEN_MI_VALUE_TYPE_MEM32:
    357       switch (src.type) {
    358       case GEN_MI_VALUE_TYPE_IMM:
    359          gen_mi_builder_emit(b, GENX(MI_STORE_DATA_IMM), sdi) {
    360             sdi.Address = dst.addr;
    361             sdi.ImmediateData = src.imm;
    362          }
    363          break;
    364 
    365       case GEN_MI_VALUE_TYPE_MEM32:
    366       case GEN_MI_VALUE_TYPE_MEM64:
    367 #if GEN_GEN >= 8
    368          gen_mi_builder_emit(b, GENX(MI_COPY_MEM_MEM), cmm) {
    369             cmm.DestinationMemoryAddress = dst.addr;
    370             cmm.SourceMemoryAddress = src.addr;
    371          }
    372 #elif GEN_IS_HASWELL
    373          {
    374             struct gen_mi_value tmp = gen_mi_new_gpr(b);
    375             _gen_mi_copy_no_unref(b, tmp, src);
    376             _gen_mi_copy_no_unref(b, dst, tmp);
    377             gen_mi_value_unref(b, tmp);
    378          }
    379 #else
    380          unreachable("Cannot do mem <-> mem copy on IVB and earlier");
    381 #endif
    382          break;
    383 
    384       case GEN_MI_VALUE_TYPE_REG32:
    385       case GEN_MI_VALUE_TYPE_REG64:
    386          gen_mi_builder_emit(b, GENX(MI_STORE_REGISTER_MEM), srm) {
    387             srm.RegisterAddress = src.reg;
    388             srm.MemoryAddress = dst.addr;
    389          }
    390          break;
    391 
    392       default:
    393          unreachable("Invalid gen_mi_value type");
    394       }
    395       break;
    396 
    397    case GEN_MI_VALUE_TYPE_REG32:
    398       switch (src.type) {
    399       case GEN_MI_VALUE_TYPE_IMM:
    400          gen_mi_builder_emit(b, GENX(MI_LOAD_REGISTER_IMM), lri) {
    401             lri.RegisterOffset = dst.reg;
    402             lri.DataDWord = src.imm;
    403          }
    404          break;
    405 
    406       case GEN_MI_VALUE_TYPE_MEM32:
    407       case GEN_MI_VALUE_TYPE_MEM64:
    408          gen_mi_builder_emit(b, GENX(MI_LOAD_REGISTER_MEM), lrm) {
    409             lrm.RegisterAddress = dst.reg;
    410             lrm.MemoryAddress = src.addr;
    411          }
    412          break;
    413 
    414       case GEN_MI_VALUE_TYPE_REG32:
    415       case GEN_MI_VALUE_TYPE_REG64:
    416 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    417          gen_mi_builder_emit(b, GENX(MI_LOAD_REGISTER_REG), lrr) {
    418             lrr.SourceRegisterAddress = src.reg;
    419             lrr.DestinationRegisterAddress = dst.reg;
    420          }
    421 #else
    422          unreachable("Cannot do reg <-> reg copy on IVB and earlier");
    423 #endif
    424          break;
    425 
    426       default:
    427          unreachable("Invalid gen_mi_value type");
    428       }
    429       break;
    430 
    431    default:
    432       unreachable("Invalid gen_mi_value type");
    433    }
    434 }
    435 
    436 /** Store the value in src to the value represented by dst
    437  *
    438  * If the bit size of src and dst mismatch, this function does an unsigned
    439  * integer cast.  If src has more bits than dst, it takes the bottom bits.  If
    440  * src has fewer bits then dst, it fills the top bits with zeros.
    441  *
    442  * This function consumes one reference for each of src and dst.
    443  */
    444 static inline void
    445 gen_mi_store(struct gen_mi_builder *b,
    446              struct gen_mi_value dst, struct gen_mi_value src)
    447 {
    448    _gen_mi_copy_no_unref(b, dst, src);
    449    gen_mi_value_unref(b, src);
    450    gen_mi_value_unref(b, dst);
    451 }
    452 
    453 static inline void
    454 gen_mi_memset(struct gen_mi_builder *b, __gen_address_type dst,
    455               uint32_t value, uint32_t size)
    456 {
    457 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    458    assert(b->num_math_dwords == 0);
    459 #endif
    460 
    461    /* This memset operates in units of dwords. */
    462    assert(size % 4 == 0);
    463 
    464    for (uint32_t i = 0; i < size; i += 4) {
    465       gen_mi_store(b, gen_mi_mem32(__gen_address_offset(dst, i)),
    466                       gen_mi_imm(value));
    467    }
    468 }
    469 
    470 /* NOTE: On IVB, this function stomps GEN7_3DPRIM_BASE_VERTEX */
    471 static inline void
    472 gen_mi_memcpy(struct gen_mi_builder *b, __gen_address_type dst,
    473               __gen_address_type src, uint32_t size)
    474 {
    475 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    476    assert(b->num_math_dwords == 0);
    477 #endif
    478 
    479    /* This memcpy operates in units of dwords. */
    480    assert(size % 4 == 0);
    481 
    482    for (uint32_t i = 0; i < size; i += 4) {
    483       struct gen_mi_value dst_val = gen_mi_mem32(__gen_address_offset(dst, i));
    484       struct gen_mi_value src_val = gen_mi_mem32(__gen_address_offset(src, i));
    485 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    486       gen_mi_store(b, dst_val, src_val);
    487 #else
    488       /* IVB does not have a general purpose register for command streamer
    489        * commands. Therefore, we use an alternate temporary register.
    490        */
    491       struct gen_mi_value tmp_reg = gen_mi_reg32(0x2440); /* GEN7_3DPRIM_BASE_VERTEX */
    492       gen_mi_store(b, tmp_reg, src_val);
    493       gen_mi_store(b, dst_val, tmp_reg);
    494 #endif
    495    }
    496 }
    497 
    498 /*
    499  * MI_MATH Section.  Only available on Haswell+
    500  */
    501 
    502 #if GEN_GEN >= 8 || GEN_IS_HASWELL
    503 
    504 static inline void
    505 _gen_mi_builder_push_math(struct gen_mi_builder *b,
    506                           const uint32_t *dwords,
    507                           unsigned num_dwords)
    508 {
    509    assert(num_dwords < GEN_MI_BUILDER_MAX_MATH_DWORDS);
    510    if (b->num_math_dwords + num_dwords > GEN_MI_BUILDER_MAX_MATH_DWORDS)
    511       gen_mi_builder_flush_math(b);
    512 
    513    memcpy(&b->math_dwords[b->num_math_dwords],
    514           dwords, num_dwords * sizeof(*dwords));
    515    b->num_math_dwords += num_dwords;
    516 }
    517 
    518 static inline uint32_t
    519 _gen_mi_pack_alu(uint32_t opcode, uint32_t operand1, uint32_t operand2)
    520 {
    521    struct GENX(MI_MATH_ALU_INSTRUCTION) instr = {
    522       .Operand2 = operand2,
    523       .Operand1 = operand1,
    524       .ALUOpcode = opcode,
    525    };
    526 
    527    uint32_t dw;
    528    GENX(MI_MATH_ALU_INSTRUCTION_pack)(NULL, &dw, &instr);
    529 
    530    return dw;
    531 }
    532 
    533 static inline struct gen_mi_value
    534 gen_mi_value_to_gpr(struct gen_mi_builder *b, struct gen_mi_value val)
    535 {
    536    if (gen_mi_value_is_gpr(val))
    537       return val;
    538 
    539    /* Save off the invert flag because it makes copy() grumpy */
    540    bool invert = val.invert;
    541    val.invert = false;
    542 
    543    struct gen_mi_value tmp = gen_mi_new_gpr(b);
    544    _gen_mi_copy_no_unref(b, tmp, val);
    545    tmp.invert = invert;
    546 
    547    return tmp;
    548 }
    549 
    550 static inline uint32_t
    551 _gen_mi_math_load_src(struct gen_mi_builder *b,
    552                       unsigned src, struct gen_mi_value *val)
    553 {
    554    if (val->type == GEN_MI_VALUE_TYPE_IMM &&
    555        (val->imm == 0 || val->imm == UINT64_MAX)) {
    556       uint64_t imm = val->invert ? ~val->imm : val->imm;
    557       return _gen_mi_pack_alu(imm ? MI_ALU_LOAD1 : MI_ALU_LOAD0, src, 0);
    558    } else {
    559       *val = gen_mi_value_to_gpr(b, *val);
    560       return _gen_mi_pack_alu(val->invert ? MI_ALU_LOADINV : MI_ALU_LOAD,
    561                               src, _gen_mi_value_as_gpr(*val));
    562    }
    563 }
    564 
    565 static inline struct gen_mi_value
    566 gen_mi_math_binop(struct gen_mi_builder *b, uint32_t opcode,
    567                   struct gen_mi_value src0, struct gen_mi_value src1,
    568                   uint32_t store_op, uint32_t store_src)
    569 {
    570    struct gen_mi_value dst = gen_mi_new_gpr(b);
    571 
    572    uint32_t dw[4];
    573    dw[0] = _gen_mi_math_load_src(b, MI_ALU_SRCA, &src0);
    574    dw[1] = _gen_mi_math_load_src(b, MI_ALU_SRCB, &src1);
    575    dw[2] = _gen_mi_pack_alu(opcode, 0, 0);
    576    dw[3] = _gen_mi_pack_alu(store_op, _gen_mi_value_as_gpr(dst), store_src);
    577    _gen_mi_builder_push_math(b, dw, 4);
    578 
    579    gen_mi_value_unref(b, src0);
    580    gen_mi_value_unref(b, src1);
    581 
    582    return dst;
    583 }
    584 
    585 static inline struct gen_mi_value
    586 gen_mi_inot(struct gen_mi_builder *b, struct gen_mi_value val)
    587 {
    588    /* TODO These currently can't be passed into gen_mi_copy */
    589    val.invert = !val.invert;
    590    return val;
    591 }
    592 
    593 static inline struct gen_mi_value
    594 gen_mi_iadd(struct gen_mi_builder *b,
    595             struct gen_mi_value src0, struct gen_mi_value src1)
    596 {
    597    return gen_mi_math_binop(b, MI_ALU_ADD, src0, src1,
    598                             MI_ALU_STORE, MI_ALU_ACCU);
    599 }
    600 
    601 static inline struct gen_mi_value
    602 gen_mi_iadd_imm(struct gen_mi_builder *b,
    603                 struct gen_mi_value src, uint64_t N)
    604 {
    605    if (N == 0)
    606       return src;
    607 
    608    return gen_mi_iadd(b, src, gen_mi_imm(N));
    609 }
    610 
    611 static inline struct gen_mi_value
    612 gen_mi_isub(struct gen_mi_builder *b,
    613             struct gen_mi_value src0, struct gen_mi_value src1)
    614 {
    615    return gen_mi_math_binop(b, MI_ALU_SUB, src0, src1,
    616                             MI_ALU_STORE, MI_ALU_ACCU);
    617 }
    618 
    619 static inline struct gen_mi_value
    620 gen_mi_ult(struct gen_mi_builder *b,
    621            struct gen_mi_value src0, struct gen_mi_value src1)
    622 {
    623    /* Compute "less than" by subtracting and storing the carry bit */
    624    return gen_mi_math_binop(b, MI_ALU_SUB, src0, src1,
    625                             MI_ALU_STORE, MI_ALU_CF);
    626 }
    627 
    628 static inline struct gen_mi_value
    629 gen_mi_uge(struct gen_mi_builder *b,
    630            struct gen_mi_value src0, struct gen_mi_value src1)
    631 {
    632    /* Compute "less than" by subtracting and storing the carry bit */
    633    return gen_mi_math_binop(b, MI_ALU_SUB, src0, src1,
    634                             MI_ALU_STOREINV, MI_ALU_CF);
    635 }
    636 
    637 static inline struct gen_mi_value
    638 gen_mi_iand(struct gen_mi_builder *b,
    639             struct gen_mi_value src0, struct gen_mi_value src1)
    640 {
    641    return gen_mi_math_binop(b, MI_ALU_AND, src0, src1,
    642                             MI_ALU_STORE, MI_ALU_ACCU);
    643 }
    644 
    645 static inline struct gen_mi_value
    646 gen_mi_imul_imm(struct gen_mi_builder *b,
    647                 struct gen_mi_value src, uint32_t N)
    648 {
    649    if (N == 0) {
    650       gen_mi_value_unref(b, src);
    651       return gen_mi_imm(0);
    652    }
    653 
    654    if (N == 1)
    655       return src;
    656 
    657    src = gen_mi_value_to_gpr(b, src);
    658 
    659    struct gen_mi_value res = gen_mi_value_ref(b, src);
    660 
    661    unsigned top_bit = 31 - __builtin_clz(N);
    662    for (int i = top_bit - 1; i >= 0; i--) {
    663       res = gen_mi_iadd(b, res, gen_mi_value_ref(b, res));
    664       if (N & (1 << i))
    665          res = gen_mi_iadd(b, res, gen_mi_value_ref(b, src));
    666    }
    667 
    668    gen_mi_value_unref(b, src);
    669 
    670    return res;
    671 }
    672 
    673 static inline struct gen_mi_value
    674 gen_mi_ishl_imm(struct gen_mi_builder *b,
    675                 struct gen_mi_value src, uint32_t shift)
    676 {
    677    struct gen_mi_value res = gen_mi_value_to_gpr(b, src);
    678 
    679    for (unsigned i = 0; i < shift; i++)
    680       res = gen_mi_iadd(b, res, gen_mi_value_ref(b, res));
    681 
    682    return res;
    683 }
    684 
    685 static inline struct gen_mi_value
    686 gen_mi_ushr32_imm(struct gen_mi_builder *b,
    687                   struct gen_mi_value src, uint32_t shift)
    688 {
    689    /* We right-shift by left-shifting by 32 - shift and taking the top 32 bits
    690     * of the result.  This assumes the top 32 bits are zero.
    691     */
    692    if (shift > 64)
    693       return gen_mi_imm(0);
    694 
    695    if (shift > 32) {
    696       struct gen_mi_value tmp = gen_mi_new_gpr(b);
    697       _gen_mi_copy_no_unref(b, gen_mi_value_half(tmp, false),
    698                                gen_mi_value_half(src, true));
    699       _gen_mi_copy_no_unref(b, gen_mi_value_half(tmp, true), gen_mi_imm(0));
    700       gen_mi_value_unref(b, src);
    701       src = tmp;
    702       shift -= 32;
    703    }
    704    assert(shift <= 32);
    705    struct gen_mi_value tmp = gen_mi_ishl_imm(b, src, 32 - shift);
    706    struct gen_mi_value dst = gen_mi_new_gpr(b);
    707    _gen_mi_copy_no_unref(b, gen_mi_value_half(dst, false),
    708                             gen_mi_value_half(tmp, true));
    709    _gen_mi_copy_no_unref(b, gen_mi_value_half(dst, true), gen_mi_imm(0));
    710    gen_mi_value_unref(b, tmp);
    711    return dst;
    712 }
    713 
    714 static inline struct gen_mi_value
    715 gen_mi_udiv32_imm(struct gen_mi_builder *b,
    716                   struct gen_mi_value N, uint32_t D)
    717 {
    718    /* We implicitly assume that N is only a 32-bit value */
    719    if (D == 0) {
    720       /* This is invalid but we should do something */
    721       return gen_mi_imm(0);
    722    } else if (util_is_power_of_two_or_zero(D)) {
    723       return gen_mi_ushr32_imm(b, N, util_logbase2(D));
    724    } else {
    725       struct util_fast_udiv_info m = util_compute_fast_udiv_info(D, 32, 32);
    726       assert(m.multiplier <= UINT32_MAX);
    727 
    728       if (m.pre_shift)
    729          N = gen_mi_ushr32_imm(b, N, m.pre_shift);
    730 
    731       /* Do the 32x32 multiply  into gpr0 */
    732       N = gen_mi_imul_imm(b, N, m.multiplier);
    733 
    734       if (m.increment)
    735          N = gen_mi_iadd(b, N, gen_mi_imm(m.multiplier));
    736 
    737       N = gen_mi_ushr32_imm(b, N, 32);
    738 
    739       if (m.post_shift)
    740          N = gen_mi_ushr32_imm(b, N, m.post_shift);
    741 
    742       return N;
    743    }
    744 }
    745 
    746 #endif /* MI_MATH section */
    747 
    748 #endif /* GEN_MI_BUILDER_H */
    749