diff options
author | Jason Ekstrand <[email protected]> | 2018-11-12 18:38:24 -0600 |
---|---|---|
committer | Jason Ekstrand <[email protected]> | 2018-11-15 19:59:28 -0600 |
commit | f16bd8a9feec026d2a11a203d860189be954896d (patch) | |
tree | 10e279728f3ffbfee74ad6d0e2add0b0d616116c /src/compiler/nir/nir_builder.h | |
parent | b77d68b78e2bf623bf9ba3f28945cf2080185a9d (diff) |
nir/builder: Add a nir_pack/unpack/bitcast helpers
The new helpers can generate any pack/unpack operation including those
for which we do not have specific opcodes and they express a bitcast in
terms of these pack/unpack operations. In particular, the new helpers
properly handle 8-bit types.
Reviewed-by: Samuel Iglesias Gonsálvez <[email protected]>
Diffstat (limited to 'src/compiler/nir/nir_builder.h')
-rw-r--r-- | src/compiler/nir/nir_builder.h | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/src/compiler/nir/nir_builder.h b/src/compiler/nir/nir_builder.h index cf096d41bf2..e37aba23dc2 100644 --- a/src/compiler/nir/nir_builder.h +++ b/src/compiler/nir/nir_builder.h @@ -565,6 +565,132 @@ nir_imul_imm(nir_builder *build, nir_ssa_def *x, uint64_t y) return nir_imul(build, x, nir_imm_intN_t(build, y, x->bit_size)); } +static inline nir_ssa_def * +nir_pack_bits(nir_builder *b, nir_ssa_def *src, unsigned dest_bit_size) +{ + assert(src->num_components * src->bit_size == dest_bit_size); + + switch (dest_bit_size) { + case 64: + switch (src->bit_size) { + case 32: return nir_pack_64_2x32(b, src); + case 16: return nir_pack_64_4x16(b, src); + default: break; + } + break; + + case 32: + if (src->bit_size == 16) + return nir_pack_32_2x16(b, src); + break; + + default: + break; + } + + /* If we got here, we have no dedicated unpack opcode. */ + nir_ssa_def *dest = nir_imm_intN_t(b, 0, dest_bit_size); + for (unsigned i = 0; i < src->num_components; i++) { + nir_ssa_def *val; + switch (dest_bit_size) { + case 64: val = nir_u2u64(b, nir_channel(b, src, i)); break; + case 32: val = nir_u2u32(b, nir_channel(b, src, i)); break; + case 16: val = nir_u2u16(b, nir_channel(b, src, i)); break; + default: unreachable("Invalid bit size"); + } + val = nir_ishl(b, val, nir_imm_int(b, i * src->bit_size)); + dest = nir_ior(b, dest, val); + } + return dest; +} + +static inline nir_ssa_def * +nir_unpack_bits(nir_builder *b, nir_ssa_def *src, unsigned dest_bit_size) +{ + assert(src->num_components == 1); + assert(src->bit_size > dest_bit_size); + const unsigned dest_num_components = src->bit_size / dest_bit_size; + assert(dest_num_components <= NIR_MAX_VEC_COMPONENTS); + + switch (src->bit_size) { + case 64: + switch (dest_bit_size) { + case 32: return nir_unpack_64_2x32(b, src); + case 16: return nir_unpack_64_4x16(b, src); + default: break; + } + break; + + case 32: + if (dest_bit_size == 16) + return nir_unpack_32_2x16(b, src); + break; + + default: + break; + } + + /* If we got here, we have no dedicated unpack opcode. */ + nir_ssa_def *dest_comps[NIR_MAX_VEC_COMPONENTS]; + for (unsigned i = 0; i < dest_num_components; i++) { + nir_ssa_def *val = nir_ushr(b, src, nir_imm_int(b, i * dest_bit_size)); + switch (dest_bit_size) { + case 32: dest_comps[i] = nir_u2u32(b, val); break; + case 16: dest_comps[i] = nir_u2u16(b, val); break; + case 8: dest_comps[i] = nir_u2u8(b, val); break; + default: unreachable("Invalid bit size"); + } + } + return nir_vec(b, dest_comps, dest_num_components); +} + +static inline nir_ssa_def * +nir_bitcast_vector(nir_builder *b, nir_ssa_def *src, unsigned dest_bit_size) +{ + assert((src->bit_size * src->num_components) % dest_bit_size == 0); + const unsigned dest_num_components = + (src->bit_size * src->num_components) / dest_bit_size; + assert(dest_num_components <= NIR_MAX_VEC_COMPONENTS); + + if (src->bit_size > dest_bit_size) { + assert(src->bit_size % dest_bit_size == 0); + if (src->num_components == 1) { + return nir_unpack_bits(b, src, dest_bit_size); + } else { + const unsigned divisor = src->bit_size / dest_bit_size; + assert(src->num_components * divisor == dest_num_components); + nir_ssa_def *dest[NIR_MAX_VEC_COMPONENTS]; + for (unsigned i = 0; i < src->num_components; i++) { + nir_ssa_def *unpacked = + nir_unpack_bits(b, nir_channel(b, src, i), dest_bit_size); + assert(unpacked->num_components == divisor); + for (unsigned j = 0; j < divisor; j++) + dest[i * divisor + j] = nir_channel(b, unpacked, j); + } + return nir_vec(b, dest, dest_num_components); + } + } else if (src->bit_size < dest_bit_size) { + assert(dest_bit_size % src->bit_size == 0); + if (dest_num_components == 1) { + return nir_pack_bits(b, src, dest_bit_size); + } else { + const unsigned divisor = dest_bit_size / src->bit_size; + assert(src->num_components == dest_num_components * divisor); + nir_ssa_def *dest[NIR_MAX_VEC_COMPONENTS]; + for (unsigned i = 0; i < dest_num_components; i++) { + nir_component_mask_t src_mask = + ((1 << divisor) - 1) << (i * divisor); + dest[i] = nir_pack_bits(b, nir_channels(b, src, src_mask), + dest_bit_size); + } + return nir_vec(b, dest, dest_num_components); + } + } else { + assert(src->bit_size == dest_bit_size); + return src; + } +} + /** * Turns a nir_src into a nir_ssa_def * so it can be passed to * nir_build_alu()-based builder calls. |