gallivm: Clamp indirect register indices to file_max.
authorJosé Fonseca <jfonseca@vmware.com>
Thu, 16 Sep 2010 10:45:16 +0000 (11:45 +0100)
committerJosé Fonseca <jfonseca@vmware.com>
Thu, 16 Sep 2010 19:20:49 +0000 (20:20 +0100)
Prevents crashes with bogus data, or bad shader translation.

src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c

index 0d8d49be2c73af56e0f222709259b4f9531eff2d..441aebae298e86bb6d86a2ed1f3a9db87dcde205 100644 (file)
@@ -49,6 +49,7 @@
 #include "lp_bld_type.h"
 #include "lp_bld_const.h"
 #include "lp_bld_arit.h"
+#include "lp_bld_bitarit.h"
 #include "lp_bld_gather.h"
 #include "lp_bld_logic.h"
 #include "lp_bld_swizzle.h"
@@ -119,7 +120,7 @@ struct lp_build_tgsi_soa_context
    struct lp_build_context base;
 
    /* Builder for integer masks and indices */
-   struct lp_build_context int_bld;
+   struct lp_build_context uint_bld;
 
    LLVMValueRef consts_ptr;
    const LLVMValueRef *pos;
@@ -139,6 +140,7 @@ struct lp_build_tgsi_soa_context
     */
    LLVMValueRef temps_array;
 
+   const struct tgsi_shader_info *info;
    /** bitmask indicating which register files are accessed indirectly */
    unsigned indirect_files;
 
@@ -472,27 +474,41 @@ build_gather(struct lp_build_tgsi_soa_context *bld,
  * temporary register file.
  */
 static LLVMValueRef
-get_indirect_offsets(struct lp_build_tgsi_soa_context *bld,
-                     const struct tgsi_src_register *indirect_reg)
+get_indirect_index(struct lp_build_tgsi_soa_context *bld,
+                   unsigned reg_file, unsigned reg_index,
+                   const struct tgsi_src_register *indirect_reg)
 {
+   struct lp_build_context *uint_bld = &bld->uint_bld;
    /* always use X component of address register */
    unsigned swizzle = indirect_reg->SwizzleX;
-   LLVMTypeRef int_vec_type = lp_build_int_vec_type(bld->base.type);
-   LLVMValueRef vec4 = lp_build_const_int_vec(bld->int_bld.type, 4); 
-   LLVMValueRef addr_vec;
+   LLVMValueRef base;
+   LLVMValueRef rel;
+   LLVMValueRef max_index;
+   LLVMValueRef index;
 
-   addr_vec = LLVMBuildLoad(bld->base.builder,
-                            bld->addr[indirect_reg->Index][swizzle],
-                            "load addr reg");
+   assert(bld->indirect_files & (1 << reg_file));
+
+   base = lp_build_const_int_vec(uint_bld->type, reg_index);
+
+   assert(swizzle < 4);
+   rel = LLVMBuildLoad(bld->base.builder,
+                        bld->addr[indirect_reg->Index][swizzle],
+                        "load addr reg");
 
    /* for indexing we want integers */
-   addr_vec = LLVMBuildFPToSI(bld->base.builder, addr_vec,
-                              int_vec_type, "");
+   rel = LLVMBuildFPToSI(bld->base.builder,
+                         rel,
+                         uint_bld->vec_type, "");
+
+   index = lp_build_add(uint_bld, base, rel);
 
-   /* addr_vec = addr_vec * 4 */
-   addr_vec = lp_build_mul(&bld->int_bld, addr_vec, vec4);
+   max_index = lp_build_const_int_vec(uint_bld->type,
+                                      bld->info->file_max[reg_file]);
 
-   return addr_vec;
+   assert(!uint_bld->type.sign);
+   index = lp_build_min(uint_bld, index, max_index);
+
+   return index;
 }
 
 
@@ -506,11 +522,12 @@ emit_fetch(
    unsigned src_op,
    const unsigned chan_index )
 {
+   struct lp_build_context *uint_bld = &bld->uint_bld;
    const struct tgsi_full_src_register *reg = &inst->Src[src_op];
    const unsigned swizzle =
       tgsi_util_get_full_src_register_swizzle(reg, chan_index);
    LLVMValueRef res;
-   LLVMValueRef addr_vec = NULL;
+   LLVMValueRef indirect_index = NULL;
 
    if (swizzle > 3) {
       assert(0 && "invalid swizzle in emit_fetch()");
@@ -518,23 +535,24 @@ emit_fetch(
    }
 
    if (reg->Register.Indirect) {
-      assert(bld->indirect_files);
-      addr_vec = get_indirect_offsets(bld, &reg->Indirect);
+      indirect_index = get_indirect_index(bld,
+                                          reg->Register.File,
+                                          reg->Register.Index,
+                                          &reg->Indirect);
+   } else {
+      assert(reg->Register.Index <= bld->info->file_max[reg->Register.File]);
    }
 
    switch (reg->Register.File) {
    case TGSI_FILE_CONSTANT:
       if (reg->Register.Indirect) {
+         LLVMValueRef swizzle_vec =
+            lp_build_const_int_vec(uint_bld->type, swizzle);
          LLVMValueRef index_vec;  /* index into the const buffer */
 
-         assert(bld->indirect_files & (1 << TGSI_FILE_CONSTANT));
-
-         /* index_vec = broadcast(reg->Register.Index * 4 + swizzle) */
-         index_vec = lp_build_const_int_vec(bld->int_bld.type,
-                                            reg->Register.Index * 4 + swizzle);
-
-         /* index_vec = index_vec + addr_vec */
-         index_vec = lp_build_add(&bld->int_bld, index_vec, addr_vec);
+         /* index_vec = indirect_index * 4 + swizzle */
+         index_vec = lp_build_shl_imm(uint_bld, indirect_index, 2);
+         index_vec = lp_build_add(uint_bld, index_vec, swizzle_vec);
 
          /* Gather values from the constant buffer */
          res = build_gather(bld, bld->consts_ptr, index_vec);
@@ -565,27 +583,22 @@ emit_fetch(
 
    case TGSI_FILE_TEMPORARY:
       if (reg->Register.Indirect) {
-         LLVMValueRef vec_len =
-            lp_build_const_int_vec(bld->int_bld.type, bld->base.type.length);
+         LLVMValueRef swizzle_vec =
+            lp_build_const_int_vec(uint_bld->type, swizzle);
+         LLVMValueRef length_vec =
+            lp_build_const_int_vec(uint_bld->type, bld->base.type.length);
          LLVMValueRef index_vec;  /* index into the const buffer */
          LLVMValueRef temps_array;
          LLVMTypeRef float4_ptr_type;
 
-         assert(bld->indirect_files & (1 << TGSI_FILE_TEMPORARY));
-
-         /* index_vec = broadcast(reg->Register.Index * 4 + swizzle) */
-         index_vec = lp_build_const_int_vec(bld->int_bld.type,
-                                            reg->Register.Index * 4 + swizzle);
-
-         /* index_vec += addr_vec */
-         index_vec = lp_build_add(&bld->int_bld, index_vec, addr_vec);
-
-         /* index_vec *= vector_length */
-         index_vec = lp_build_mul(&bld->int_bld, index_vec, vec_len);
+         /* index_vec = (indirect_index * 4 + swizzle) * length */
+         index_vec = lp_build_shl_imm(uint_bld, indirect_index, 2);
+         index_vec = lp_build_add(uint_bld, index_vec, swizzle_vec);
+         index_vec = lp_build_mul(uint_bld, index_vec, length_vec);
 
          /* cast temps_array pointer to float* */
          float4_ptr_type = LLVMPointerType(LLVMFloatType(), 0);
-         temps_array = LLVMBuildBitCast(bld->int_bld.builder, bld->temps_array,
+         temps_array = LLVMBuildBitCast(uint_bld->builder, bld->temps_array,
                                         float4_ptr_type, "");
 
          /* Gather values from the temporary register array */
@@ -735,7 +748,7 @@ emit_store(
    LLVMValueRef value)
 {
    const struct tgsi_full_dst_register *reg = &inst->Dst[index];
-   LLVMValueRef addr = NULL;
+   LLVMValueRef indirect_index = NULL;
 
    switch( inst->Instruction.Saturate ) {
    case TGSI_SAT_NONE:
@@ -756,24 +769,12 @@ emit_store(
    }
 
    if (reg->Register.Indirect) {
-      /* XXX use get_indirect_offsets() here eventually */
-      LLVMTypeRef int_vec_type = lp_build_int_vec_type(bld->base.type);
-      unsigned swizzle = tgsi_util_get_src_register_swizzle( &reg->Indirect, chan_index );
-
-      assert(bld->indirect_files);
-
-      addr = LLVMBuildLoad(bld->base.builder,
-                           bld->addr[reg->Indirect.Index][swizzle],
-                           "");
-      /* for indexing we want integers */
-      addr = LLVMBuildFPToSI(bld->base.builder, addr,
-                             int_vec_type, "");
-      addr = LLVMBuildExtractElement(bld->base.builder,
-                                     addr, LLVMConstInt(LLVMInt32Type(), 0, 0),
-                                     "");
-      addr = LLVMBuildMul(bld->base.builder,
-                          addr, LLVMConstInt(LLVMInt32Type(), 4, 0),
-                          "");
+      indirect_index = get_indirect_index(bld,
+                                          reg->Register.File,
+                                          reg->Register.Index,
+                                          &reg->Indirect);
+   } else {
+      assert(reg->Register.Index <= bld->info->file_max[reg->Register.File]);
    }
 
    switch( reg->Register.File ) {
@@ -993,13 +994,14 @@ emit_declaration(
    struct lp_build_tgsi_soa_context *bld,
    const struct tgsi_full_declaration *decl)
 {
-   LLVMTypeRef vec_type = lp_build_vec_type(bld->base.type);
+   LLVMTypeRef vec_type = bld->base.vec_type;
 
    unsigned first = decl->Range.First;
    unsigned last = decl->Range.Last;
    unsigned idx, i;
 
    for (idx = first; idx <= last; ++idx) {
+      assert(last <= bld->info->file_max[decl->Declaration.File]);
       switch (decl->Declaration.File) {
       case TGSI_FILE_TEMPORARY:
          assert(idx < LP_MAX_TGSI_TEMPS);
@@ -2017,16 +2019,25 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
    unsigned i;
    int pc = 0;
 
+   struct lp_type res_type;
+
+   assert(type.length <= LP_MAX_VECTOR_LENGTH);
+   memset(&res_type, 0, sizeof res_type);
+   res_type.width = type.width;
+   res_type.length = type.length;
+   res_type.sign = 1;
+
    /* Setup build context */
    memset(&bld, 0, sizeof bld);
    lp_build_context_init(&bld.base, builder, type);
-   lp_build_context_init(&bld.int_bld, builder, lp_int_type(type));
+   lp_build_context_init(&bld.uint_bld, builder, lp_uint_type(type));
    bld.mask = mask;
    bld.pos = pos;
    bld.inputs = inputs;
    bld.outputs = outputs;
    bld.consts_ptr = consts_ptr;
    bld.sampler = sampler;
+   bld.info = info;
    bld.indirect_files = info->indirect_files;
    bld.instructions = (struct tgsi_full_instruction *)
                       MALLOC( LP_MAX_INSTRUCTIONS * sizeof(struct tgsi_full_instruction) );