<div dir="ltr"><div class="gmail_quote"><div dir="ltr">On Mon, Oct 22, 2018 at 6:22 PM Ian Romanick <<a href="mailto:idr@freedesktop.org">idr@freedesktop.org</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">On 10/22/2018 03:13 PM, Jason Ekstrand wrote:<br>
> This commit adds support for 1-bit booleans and integers.  Booleans<br>
<br>
I've noticed this in some of the patches... Boolean is a proper name, so<br>
it should be capitalized everywhere.<br></blockquote><div><br></div><div>I did not know that.  Thanks for pointing it out!  I think I've fixed all the commit messages now.</div><div><br></div><div>--Jason<br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
> obviously take a value of true or false.  Because we have to define the<br>
> semantics of 1-bit signed and unsigned integers, we define uint1_t to<br>
> take values of 0 and 1 and int1_t to take values of 0 and -1.  1-bit<br>
> arithmetic is then well-defined in the usual way, just with fewer bits.<br>
> The definition of int1_t and uint1_t doesn't usually matter but we do<br>
> need something for purposes of constant folding.<br>
> ---<br>
>  src/compiler/nir/nir.c                        | 15 +++++------<br>
>  src/compiler/nir/nir.h                        | 21 +++++++++++-----<br>
>  src/compiler/nir/nir_builder.h                | 12 ++++++++-<br>
>  src/compiler/nir/nir_constant_expressions.py  | 25 ++++++++++++++++---<br>
>  src/compiler/nir/nir_instr_set.c              | 23 ++++++++++++++---<br>
>  .../nir/nir_lower_load_const_to_scalar.c      |  3 +++<br>
>  src/compiler/nir/nir_opt_constant_folding.c   |  3 +++<br>
>  src/compiler/nir/nir_opt_large_constants.c    |  5 ++++<br>
>  src/compiler/nir/nir_print.c                  |  3 +++<br>
>  src/compiler/nir/nir_search.c                 |  3 ++-<br>
>  src/compiler/nir/nir_validate.c               |  2 +-<br>
>  src/compiler/nir_types.cpp                    |  2 +-<br>
>  src/compiler/spirv/spirv_to_nir.c             |  9 +++++++<br>
>  13 files changed, 101 insertions(+), 25 deletions(-)<br>
> <br>
> diff --git a/src/compiler/nir/nir.c b/src/compiler/nir/nir.c<br>
> index 0be40d257f5..8e83edb3644 100644<br>
> --- a/src/compiler/nir/nir.c<br>
> +++ b/src/compiler/nir/nir.c<br>
> @@ -638,6 +638,7 @@ const_value_int(int64_t i, unsigned bit_size)<br>
>  {<br>
>     nir_const_value v;<br>
>     switch (bit_size) {<br>
> +   case 1:  v.b[0]   = i & 1;  break;<br>
>     case 8:  v.i8[0]  = i;  break;<br>
>     case 16: v.i16[0] = i;  break;<br>
>     case 32: v.i32[0] = i;  break;<br>
> @@ -1206,6 +1207,8 @@ nir_src_comp_as_int(nir_src src, unsigned comp)<br>
>  <br>
>     assert(comp < load->def.num_components);<br>
>     switch (load->def.bit_size) {<br>
> +   /* int1_t uses 0/-1 convention */<br>
> +   case 1:  return -(int)load->value.b[comp];<br>
>     case 8:  return load->value.i8[comp];<br>
>     case 16: return load->value.i16[comp];<br>
>     case 32: return load->value.i32[comp];<br>
> @@ -1223,6 +1226,7 @@ nir_src_comp_as_uint(nir_src src, unsigned comp)<br>
>  <br>
>     assert(comp < load->def.num_components);<br>
>     switch (load->def.bit_size) {<br>
> +   case 1:  return load->value.b[comp];<br>
>     case 8:  return load->value.u8[comp];<br>
>     case 16: return load->value.u16[comp];<br>
>     case 32: return load->value.u32[comp];<br>
> @@ -1235,15 +1239,12 @@ nir_src_comp_as_uint(nir_src src, unsigned comp)<br>
>  bool<br>
>  nir_src_comp_as_bool(nir_src src, unsigned comp)<br>
>  {<br>
> -   assert(nir_src_is_const(src));<br>
> -   nir_load_const_instr *load = nir_instr_as_load_const(src.ssa->parent_instr);<br>
> +   int64_t i = nir_src_comp_as_int(src, comp);<br>
>  <br>
> -   assert(comp < load->def.num_components);<br>
> -   assert(load->def.bit_size == 32);<br>
> -   assert(load->value.u32[comp] == NIR_TRUE ||<br>
> -          load->value.u32[comp] == NIR_FALSE);<br>
> +   /* Booleans of any size use 0/-1 convention */<br>
> +   assert(i == 0 || i == -1);<br>
>  <br>
> -   return load->value.u32[comp];<br>
> +   return i;<br>
>  }<br>
>  <br>
>  double<br>
> diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h<br>
> index 47c7f400b2d..b19138f9e61 100644<br>
> --- a/src/compiler/nir/nir.h<br>
> +++ b/src/compiler/nir/nir.h<br>
> @@ -117,6 +117,7 @@ typedef enum {<br>
>  } nir_rounding_mode;<br>
>  <br>
>  typedef union {<br>
> +   bool b[NIR_MAX_VEC_COMPONENTS];<br>
>     float f32[NIR_MAX_VEC_COMPONENTS];<br>
>     double f64[NIR_MAX_VEC_COMPONENTS];<br>
>     int8_t i8[NIR_MAX_VEC_COMPONENTS];<br>
> @@ -778,17 +779,25 @@ typedef struct {<br>
>     unsigned write_mask : NIR_MAX_VEC_COMPONENTS; /* ignored if dest.is_ssa is true */<br>
>  } nir_alu_dest;<br>
>  <br>
> +/** NIR sized and unsized types<br>
> + *<br>
> + * The values in this enum are carefully chosen so that the sized type is<br>
> + * just the unsized type OR the number of bits.<br>
> + */<br>
>  typedef enum {<br>
>     nir_type_invalid = 0, /* Not a valid type */<br>
> -   nir_type_float,<br>
> -   nir_type_int,<br>
> -   nir_type_uint,<br>
> -   nir_type_bool,<br>
> +   nir_type_int =       2,<br>
> +   nir_type_uint =      4,<br>
> +   nir_type_bool =      6,<br>
> +   nir_type_float =     128,<br>
> +   nir_type_bool1 =     1  | nir_type_bool,<br>
>     nir_type_bool32 =    32 | nir_type_bool,<br>
> +   nir_type_int1 =      1  | nir_type_int,<br>
>     nir_type_int8 =      8  | nir_type_int,<br>
>     nir_type_int16 =     16 | nir_type_int,<br>
>     nir_type_int32 =     32 | nir_type_int,<br>
>     nir_type_int64 =     64 | nir_type_int,<br>
> +   nir_type_uint1 =     1  | nir_type_uint,<br>
>     nir_type_uint8 =     8  | nir_type_uint,<br>
>     nir_type_uint16 =    16 | nir_type_uint,<br>
>     nir_type_uint32 =    32 | nir_type_uint,<br>
> @@ -798,8 +807,8 @@ typedef enum {<br>
>     nir_type_float64 =   64 | nir_type_float,<br>
>  } nir_alu_type;<br>
>  <br>
> -#define NIR_ALU_TYPE_SIZE_MASK 0xfffffff8<br>
> -#define NIR_ALU_TYPE_BASE_TYPE_MASK 0x00000007<br>
> +#define NIR_ALU_TYPE_SIZE_MASK 0x79<br>
> +#define NIR_ALU_TYPE_BASE_TYPE_MASK 0x86<br>
>  <br>
>  static inline unsigned<br>
>  nir_alu_type_get_type_size(nir_alu_type type)<br>
> diff --git a/src/compiler/nir/nir_builder.h b/src/compiler/nir/nir_builder.h<br>
> index 3271a480520..eaba5cfe448 100644<br>
> --- a/src/compiler/nir/nir_builder.h<br>
> +++ b/src/compiler/nir/nir_builder.h<br>
> @@ -332,7 +332,10 @@ nir_imm_intN_t(nir_builder *build, uint64_t x, unsigned bit_size)<br>
>  <br>
>     memset(&v, 0, sizeof(v));<br>
>     assert(bit_size <= 64);<br>
> -   v.i64[0] = x & (~0ull >> (64 - bit_size));<br>
> +   if (bit_size == 1)<br>
> +      v.b[0] = x & 1;<br>
> +   else<br>
> +      v.i64[0] = x & (~0ull >> (64 - bit_size));<br>
>  <br>
>     return nir_build_imm(build, 1, bit_size, v);<br>
>  }<br>
> @@ -351,6 +354,13 @@ nir_imm_ivec4(nir_builder *build, int x, int y, int z, int w)<br>
>     return nir_build_imm(build, 4, 32, v);<br>
>  }<br>
>  <br>
> +static inline nir_ssa_def *<br>
> +nir_imm_boolN_t(nir_builder *build, bool x, unsigned bit_size)<br>
> +{<br>
> +   /* We use a 0/-1 convention for all booleans regardless of size */<br>
> +   return nir_imm_intN_t(build, -(int)x, bit_size);<br>
> +}<br>
> +<br>
>  static inline nir_ssa_def *<br>
>  nir_build_alu(nir_builder *build, nir_op op, nir_ssa_def *src0,<br>
>                nir_ssa_def *src1, nir_ssa_def *src2, nir_ssa_def *src3)<br>
> diff --git a/src/compiler/nir/nir_constant_expressions.py b/src/compiler/nir/nir_constant_expressions.py<br>
> index 8f28571ee4d..1fe21e96b6d 100644<br>
> --- a/src/compiler/nir/nir_constant_expressions.py<br>
> +++ b/src/compiler/nir/nir_constant_expressions.py<br>
> @@ -17,7 +17,7 @@ def type_sizes(type_):<br>
>      elif type_ == 'float':<br>
>          return [16, 32, 64]<br>
>      else:<br>
> -        return [8, 16, 32, 64]<br>
> +        return [1, 8, 16, 32, 64]<br>
>  <br>
>  def type_add_size(type_, size):<br>
>      if type_has_size(type_):<br>
> @@ -45,6 +45,8 @@ def get_const_field(type_):<br>
>          m = type_split_re.match(type_)<br>
>          if not m:<br>
>              raise Exception(str(type_))<br>
> +        if int(m.group('bits')) == 1:<br>
> +            return 'b'<br>
>          if m.group('type') == 'bool':<br>
>              return 'i' + m.group('bits')<br>
>          return m.group('type')[0] + m.group('bits')<br>
> @@ -254,9 +256,12 @@ unpack_half_1x16(uint16_t u)<br>
>  }<br>
>  <br>
>  /* Some typed vector structures to make things like src0.y work */<br>
> +typedef int8_t int1_t;<br>
> +typedef uint8_t uint1_t;<br>
>  typedef float float16_t;<br>
>  typedef float float32_t;<br>
>  typedef double float64_t;<br>
> +typedef bool bool1_t;<br>
>  typedef bool bool8_t;<br>
>  typedef bool bool16_t;<br>
>  typedef bool bool32_t;<br>
> @@ -291,7 +296,10 @@ struct ${type}${width}_vec {<br>
>  <br>
>        const struct ${input_types[j]}_vec src${j} = {<br>
>        % for k in range(op.input_sizes[j]):<br>
> -         % if input_types[j] == "float16":<br>
> +         % if input_types[j] == "int1":<br>
> +             /* 1-bit integers use a 0/-1 convention */<br>
> +             -(int1_t)_src[${j}].b[${k}],<br>
> +         % elif input_types[j] == "float16":<br>
>              _mesa_half_to_float(_src[${j}].u16[${k}]),<br>
>           % else:<br>
>              _src[${j}].${get_const_field(input_types[j])}[${k}],<br>
> @@ -316,6 +324,9 @@ struct ${type}${width}_vec {<br>
>              % elif "src" + str(j) not in op.const_expr:<br>
>                 ## Avoid unused variable warnings<br>
>                 <% continue %><br>
> +            % elif input_types[j] == "int1":<br>
> +               /* 1-bit integers use a 0/-1 convention */<br>
> +               const int1_t src${j} = -(int1_t)_src[${j}].b[_i];<br>
>              % elif input_types[j] == "float16":<br>
>                 const float src${j} =<br>
>                    _mesa_half_to_float(_src[${j}].u16[_i]);<br>
> @@ -338,7 +349,10 @@ struct ${type}${width}_vec {<br>
>  <br>
>           ## Store the current component of the actual destination to the<br>
>           ## value of dst.<br>
> -         % if output_type.startswith("bool"):<br>
> +         % if output_type == "int1" or output_type == "uint1":<br>
> +            /* 1-bit integers get truncated */<br>
> +            _dst_val.b[_i] = dst & 1;<br>
> +         % elif output_type.startswith("bool"):<br>
>              ## Sanitize the C value to a proper NIR 0/-1 bool<br>
>              _dst_val.${get_const_field(output_type)}[_i] = -(int)dst;<br>
>           % elif output_type == "float16":<br>
> @@ -367,7 +381,10 @@ struct ${type}${width}_vec {<br>
>        ## For each component in the destination, copy the value of dst to<br>
>        ## the actual destination.<br>
>        % for k in range(op.output_size):<br>
> -         % if output_type == "bool32":<br>
> +         % if output_type == "int1" or output_type == "uint1":<br>
> +            /* 1-bit integers get truncated */<br>
> +            _dst_val.b[${k}] = dst.${"xyzw"[k]} & 1;<br>
> +         % elif output_type.startswith("bool"):<br>
>              ## Sanitize the C value to a proper NIR 0/-1 bool<br>
>              _dst_val.${get_const_field(output_type)}[${k}] = -(int)dst.${"xyzw"[k]};<br>
>           % elif output_type == "float16":<br>
> diff --git a/src/compiler/nir/nir_instr_set.c b/src/compiler/nir/nir_instr_set.c<br>
> index 19771fcd9dd..3b535b9009a 100644<br>
> --- a/src/compiler/nir/nir_instr_set.c<br>
> +++ b/src/compiler/nir/nir_instr_set.c<br>
> @@ -117,8 +117,15 @@ hash_load_const(uint32_t hash, const nir_load_const_instr *instr)<br>
>  {<br>
>     hash = HASH(hash, instr->def.num_components);<br>
>  <br>
> -   unsigned size = instr->def.num_components * (instr->def.bit_size / 8);<br>
> -   hash = _mesa_fnv32_1a_accumulate_block(hash, instr->value.f32, size);<br>
> +   if (instr->def.bit_size == 1) {<br>
> +      for (unsigned i = 0; i < instr->def.num_components; i++) {<br>
> +         uint8_t b = instr->value.b[i];<br>
> +         hash = HASH(hash, b);<br>
> +      }<br>
> +   } else {<br>
> +      unsigned size = instr->def.num_components * (instr->def.bit_size / 8);<br>
> +      hash = _mesa_fnv32_1a_accumulate_block(hash, instr->value.f32, size);<br>
> +   }<br>
>  <br>
>     return hash;<br>
>  }<br>
> @@ -399,8 +406,16 @@ nir_instrs_equal(const nir_instr *instr1, const nir_instr *instr2)<br>
>        if (load1->def.bit_size != load2->def.bit_size)<br>
>           return false;<br>
>  <br>
> -      return memcmp(load1->value.f32, load2->value.f32,<br>
> -                    load1->def.num_components * (load1->def.bit_size / 8u)) == 0;<br>
> +      if (load1->def.bit_size == 1) {<br>
> +         for (unsigned i = 0; i < load1->def.num_components; i++) {<br>
> +            if (load1->value.b[i] != load2->value.b[i])<br>
> +               return false;<br>
> +         }<br>
> +         return true;<br>
> +      } else {<br>
> +         unsigned size = load1->def.num_components * (load1->def.bit_size / 8);<br>
> +         return memcmp(load1->value.f32, load2->value.f32, size) == 0;<br>
> +      }<br>
>     }<br>
>     case nir_instr_type_phi: {<br>
>        nir_phi_instr *phi1 = nir_instr_as_phi(instr1);<br>
> diff --git a/src/compiler/nir/nir_lower_load_const_to_scalar.c b/src/compiler/nir/nir_lower_load_const_to_scalar.c<br>
> index b2e055f7dea..b62d32e483e 100644<br>
> --- a/src/compiler/nir/nir_lower_load_const_to_scalar.c<br>
> +++ b/src/compiler/nir/nir_lower_load_const_to_scalar.c<br>
> @@ -63,6 +63,9 @@ lower_load_const_instr_scalar(nir_load_const_instr *lower)<br>
>        case 8:<br>
>           load_comp->value.u8[0] = lower->value.u8[i];<br>
>           break;<br>
> +      case 1:<br>
> +         load_comp->value.b[0] = lower->value.b[i];<br>
> +         break;<br>
>        default:<br>
>           assert(!"invalid bit size");<br>
>        }<br>
> diff --git a/src/compiler/nir/nir_opt_constant_folding.c b/src/compiler/nir/nir_opt_constant_folding.c<br>
> index 5929a60aee8..e5ec5e9583f 100644<br>
> --- a/src/compiler/nir/nir_opt_constant_folding.c<br>
> +++ b/src/compiler/nir/nir_opt_constant_folding.c<br>
> @@ -89,6 +89,9 @@ constant_fold_alu_instr(nir_alu_instr *instr, void *mem_ctx)<br>
>           case 8:<br>
>              src[i].u8[j] = load_const->value.u8[instr->src[i].swizzle[j]];<br>
>              break;<br>
> +         case 1:<br>
> +            src[i].b[j] = load_const->value.b[instr->src[i].swizzle[j]];<br>
> +            break;<br>
>           default:<br>
>              unreachable("Invalid bit size");<br>
>           }<br>
> diff --git a/src/compiler/nir/nir_opt_large_constants.c b/src/compiler/nir/nir_opt_large_constants.c<br>
> index 634913aa9e5..4ca2646f331 100644<br>
> --- a/src/compiler/nir/nir_opt_large_constants.c<br>
> +++ b/src/compiler/nir/nir_opt_large_constants.c<br>
> @@ -74,6 +74,11 @@ handle_constant_store(nir_builder *b, nir_intrinsic_instr *store,<br>
>  <br>
>     nir_const_value *val = nir_src_as_const_value(store->src[1]);<br>
>     switch (bit_size) {<br>
> +   case 1:<br>
> +      for (unsigned i = 0; i < num_components; i++)<br>
> +         ((uint8_t *)dst)[i] = val->b[i];<br>
> +      break;<br>
> +<br>
>     case 8:<br>
>        for (unsigned i = 0; i < num_components; i++)<br>
>           ((uint8_t *)dst)[i] = val->u8[i];<br>
> diff --git a/src/compiler/nir/nir_print.c b/src/compiler/nir/nir_print.c<br>
> index 19f26f46405..1e3157d5c77 100644<br>
> --- a/src/compiler/nir/nir_print.c<br>
> +++ b/src/compiler/nir/nir_print.c<br>
> @@ -944,6 +944,9 @@ print_load_const_instr(nir_load_const_instr *instr, print_state *state)<br>
>        case 8:<br>
>           fprintf(fp, "0x%02x", instr->value.u8[i]);<br>
>           break;<br>
> +      case 1:<br>
> +         fprintf(fp, "%s", instr->value.b[i] ? "true" : "false");<br>
> +         break;<br>
>        }<br>
>     }<br>
>  <br>
> diff --git a/src/compiler/nir/nir_search.c b/src/compiler/nir/nir_search.c<br>
> index 0270302fd3d..c43b6007dd0 100644<br>
> --- a/src/compiler/nir/nir_search.c<br>
> +++ b/src/compiler/nir/nir_search.c<br>
> @@ -485,8 +485,9 @@ construct_value(nir_builder *build,<br>
>           break;<br>
>  <br>
>        case nir_type_bool:<br>
> -         cval = nir_imm_bool(build, c->data.u);<br>
> +         cval = nir_imm_boolN_t(build, c->data.u, bitsize->dest_size);<br>
>           break;<br>
> +<br>
>        default:<br>
>           unreachable("Invalid alu source type");<br>
>        }<br>
> diff --git a/src/compiler/nir/nir_validate.c b/src/compiler/nir/nir_validate.c<br>
> index 60d64f9c7a1..1eb55a28fa8 100644<br>
> --- a/src/compiler/nir/nir_validate.c<br>
> +++ b/src/compiler/nir/nir_validate.c<br>
> @@ -819,7 +819,7 @@ validate_if(nir_if *if_stmt, validate_state *state)<br>
>     nir_cf_node *next_node = nir_cf_node_next(&if_stmt->cf_node);<br>
>     validate_assert(state, next_node->type == nir_cf_node_block);<br>
>  <br>
> -   validate_src(&if_stmt->condition, state, 32, 1);<br>
> +   validate_src(&if_stmt->condition, state, 0, 1);<br>
>  <br>
>     validate_assert(state, !exec_list_is_empty(&if_stmt->then_list));<br>
>     validate_assert(state, !exec_list_is_empty(&if_stmt->else_list));<br>
> diff --git a/src/compiler/nir_types.cpp b/src/compiler/nir_types.cpp<br>
> index d24f0941519..5628fe14ab8 100644<br>
> --- a/src/compiler/nir_types.cpp<br>
> +++ b/src/compiler/nir_types.cpp<br>
> @@ -535,7 +535,7 @@ glsl_get_natural_size_align_bytes(const struct glsl_type *type,<br>
>     case GLSL_TYPE_DOUBLE:<br>
>     case GLSL_TYPE_UINT64:<br>
>     case GLSL_TYPE_INT64: {<br>
> -      unsigned N = glsl_get_bit_size(type) / 8;<br>
> +      unsigned N = DIV_ROUND_UP(glsl_get_bit_size(type), 8);<br>
>        *size = N * type->components();<br>
>        *align = N;<br>
>        break;<br>
> diff --git a/src/compiler/spirv/spirv_to_nir.c b/src/compiler/spirv/spirv_to_nir.c<br>
> index 96ff09c3659..d0df9ea4718 100644<br>
> --- a/src/compiler/spirv/spirv_to_nir.c<br>
> +++ b/src/compiler/spirv/spirv_to_nir.c<br>
> @@ -1560,6 +1560,9 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,<br>
>              case 8:<br>
>                 val->constant->values[0].u8[i] = elems[i]->values[0].u8[0];<br>
>                 break;<br>
> +            case 1:<br>
> +               val->constant->values[0].b[i] = elems[i]->values[0].b[0];<br>
> +               break;<br>
>              default:<br>
>                 vtn_fail("Invalid SpvOpConstantComposite bit size");<br>
>              }<br>
> @@ -1733,6 +1736,9 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,<br>
>                    case 8:<br>
>                       val->constant->values[0].u8[i] = (*c)->values[col].u8[elem + i];<br>
>                       break;<br>
> +                  case 1:<br>
> +                     val->constant->values[0].b[i] = (*c)->values[col].b[elem + i];<br>
> +                     break;<br>
>                    default:<br>
>                       vtn_fail("Invalid SpvOpCompositeExtract bit size");<br>
>                    }<br>
> @@ -1760,6 +1766,9 @@ vtn_handle_constant(struct vtn_builder *b, SpvOp opcode,<br>
>                    case 8:<br>
>                       (*c)->values[col].u8[elem + i] = insert->constant->values[0].u8[i];<br>
>                       break;<br>
> +                  case 1:<br>
> +                     (*c)->values[col].b[elem + i] = insert->constant->values[0].b[i];<br>
> +                     break;<br>
>                    default:<br>
>                       vtn_fail("Invalid SpvOpCompositeInsert bit size");<br>
>                    }<br>
> <br>
<br>
</blockquote></div></div>