gallivm: implement indirect addressing over inputs
authorZack Rusin <zackr@vmware.com>
Tue, 9 Nov 2010 21:48:33 +0000 (16:48 -0500)
committerZack Rusin <zackr@vmware.com>
Wed, 10 Nov 2010 18:00:35 +0000 (13:00 -0500)
Instead of messing with the callers simply copy our inputs into a
alloca array at the beginning of the function and then use it.

Reviewed-by: José Fonseca <jfonseca@vmware.com>
src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c

index 5321a25452eabdeafeae5e349f88870915fe8949..7f0f058c2225d75dd53fca86bec148f486f690e6 100644 (file)
@@ -150,6 +150,12 @@ struct lp_build_tgsi_soa_context
     */
    LLVMValueRef outputs_array;
 
+   /* We allocate/use this array of inputs if (1 << TGSI_FILE_INPUT) is
+    * set in the indirect_files field.
+    * The inputs[] array above is unused then.
+    */
+   LLVMValueRef inputs_array;
+
    const struct tgsi_shader_info *info;
    /** bitmask indicating which register files are accessed indirectly */
    unsigned indirect_files;
@@ -466,8 +472,6 @@ get_output_ptr(struct lp_build_tgsi_soa_context *bld,
    }
 }
 
-
-
 /**
  * Gather vector.
  * XXX the lp_build_gather() function should be capable of doing this
@@ -661,7 +665,38 @@ emit_fetch(
       break;
 
    case TGSI_FILE_INPUT:
-      res = bld->inputs[reg->Register.Index][swizzle];
+      if (reg->Register.Indirect) {
+         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 inputs_array;
+         LLVMTypeRef float4_ptr_type;
+
+         /* 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 inputs_array pointer to float* */
+         float4_ptr_type = LLVMPointerType(LLVMFloatType(), 0);
+         inputs_array = LLVMBuildBitCast(uint_bld->builder, bld->inputs_array,
+                                        float4_ptr_type, "");
+
+         /* Gather values from the temporary register array */
+         res = build_gather(bld, inputs_array, index_vec);
+      } else {
+         if (bld->indirect_files & (1 << TGSI_FILE_INPUT)) {
+            LLVMValueRef lindex = lp_build_const_int32(reg->Register.Index * 4 + swizzle);
+            LLVMValueRef input_ptr =  LLVMBuildGEP(bld->base.builder,
+                                                   bld->inputs_array, &lindex, 1, "");
+            res = LLVMBuildLoad(bld->base.builder, input_ptr, "");
+         }
+         else {
+            res = bld->inputs[reg->Register.Index][swizzle];
+         }
+      }
       assert(res);
       break;
 
@@ -2314,6 +2349,32 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
                                                 "output_array");
    }
 
+   /* If we have indirect addressing in inputs we need to copy them into
+    * our alloca array to be able to iterate over them */
+   if (bld.indirect_files & (1 << TGSI_FILE_INPUT)) {
+      unsigned index, chan;
+      LLVMTypeRef vec_type = bld.base.vec_type;
+      LLVMValueRef array_size = LLVMConstInt(LLVMInt32Type(),
+                                             info->file_max[TGSI_FILE_INPUT]*4 + 4, 0);
+      bld.inputs_array = lp_build_array_alloca(bld.base.builder,
+                                               vec_type, array_size,
+                                               "input_array");
+
+      assert(info->num_inputs <= info->file_max[TGSI_FILE_INPUT] + 1);
+
+      for (index = 0; index < info->num_inputs; ++index) {
+         for (chan = 0; chan < NUM_CHANNELS; ++chan) {
+            LLVMValueRef lindex = lp_build_const_int32(index * 4 + chan);
+            LLVMValueRef input_ptr =
+               LLVMBuildGEP(bld.base.builder, bld.inputs_array,
+                            &lindex, 1, "");
+            LLVMValueRef value = bld.inputs[index][chan];
+            if (value)
+               LLVMBuildStore(bld.base.builder, value, input_ptr);
+         }
+      }
+   }
+
    tgsi_parse_init( &parse, tokens );
 
    while( !tgsi_parse_end_of_tokens( &parse ) ) {