llvmpipe: implement some control-flow
authorZack Rusin <zackr@vmware.com>
Tue, 2 Mar 2010 03:11:08 +0000 (22:11 -0500)
committerZack Rusin <zackr@vmware.com>
Tue, 2 Mar 2010 03:13:22 +0000 (22:13 -0500)
implements if/else/endif constructs and lays down the code for looping
and others. we create a conditional execution mask which decides which
of the four inputs are enabled for any store. it's used only if an
execution mask is present, otherwise we go through a direct store.

src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c

index 4cf28a9f934b8d91c398cfdd4ed7419d3e572c6e..81b0ab760eca77c14a10eb514343324dabb81a1d 100644 (file)
@@ -52,6 +52,7 @@
 #include "lp_bld_swizzle.h"
 #include "lp_bld_flow.h"
 #include "lp_bld_tgsi.h"
+#include "lp_bld_debug.h"
 
 
 #define LP_MAX_TEMPS 256
 #define QUAD_BOTTOM_LEFT  2
 #define QUAD_BOTTOM_RIGHT 3
 
+#define LP_TGSI_MAX_NESTING 16
+
+struct lp_exec_mask {
+   struct lp_build_context *bld;
+
+   boolean has_mask;
+
+   LLVMTypeRef int_vec_type;
+
+   LLVMValueRef cond_stack[LP_TGSI_MAX_NESTING];
+   int cond_stack_size;
+   LLVMValueRef cond_mask;
+
+   LLVMValueRef exec_mask;
+
+   LLVMValueRef inv_mask;
+};
 
 struct lp_build_tgsi_soa_context
 {
@@ -97,9 +115,9 @@ struct lp_build_tgsi_soa_context
    LLVMValueRef temps[LP_MAX_TEMPS][NUM_CHANNELS];
 
    struct lp_build_mask_context *mask;
+   struct lp_exec_mask exec_mask;
 };
 
-
 static const unsigned char
 swizzle_left[4] = {
    QUAD_TOP_LEFT,     QUAD_TOP_LEFT,
@@ -124,6 +142,70 @@ swizzle_bottom[4] = {
    QUAD_BOTTOM_LEFT,  QUAD_BOTTOM_RIGHT
 };
 
+static void lp_exec_mask_init(struct lp_exec_mask *mask, struct lp_build_context *bld)
+{
+   mask->bld = bld;
+   mask->has_mask = FALSE;
+   mask->cond_stack_size = 0;
+
+   mask->int_vec_type = lp_build_int_vec_type(mask->bld->type);
+   mask->inv_mask =
+      LLVMConstSub(LLVMConstNull(mask->int_vec_type),
+                   LLVMConstAllOnes(mask->int_vec_type));
+}
+
+static void lp_exec_mask_update(struct lp_exec_mask *mask)
+{
+   mask->exec_mask = mask->cond_mask;
+   if (mask->cond_stack_size > 0)
+      mask->has_mask = TRUE;
+}
+
+static void lp_exec_mask_cond_push(struct lp_exec_mask *mask,
+                                   LLVMValueRef val)
+{
+   mask->cond_stack[mask->cond_stack_size++] = mask->cond_mask;
+   mask->cond_mask = LLVMBuildBitCast(mask->bld->builder, val,
+                                      mask->int_vec_type, "");
+
+   lp_exec_mask_update(mask);
+}
+
+static void lp_exec_mask_cond_invert(struct lp_exec_mask *mask)
+{
+   LLVMValueRef prev_mask = mask->cond_stack[mask->cond_stack_size - 1];
+   LLVMValueRef inv_mask = LLVMBuildXor(mask->bld->builder,
+                                        mask->cond_mask,
+                                        mask->inv_mask, "");
+   mask->cond_mask = LLVMBuildAnd(mask->bld->builder,
+                                  inv_mask,
+                                  prev_mask, "");
+   lp_exec_mask_update(mask);
+}
+
+static void lp_exec_mask_cond_pop(struct lp_exec_mask *mask)
+{
+   mask->cond_mask = mask->cond_stack[--mask->cond_stack_size];
+   lp_exec_mask_update(mask);
+}
+
+static void lp_exec_mask_store(struct lp_exec_mask *mask,
+                               LLVMValueRef val,
+                               LLVMValueRef dst)
+{
+   if (mask->has_mask) {
+      LLVMValueRef real_val, dst_val;
+
+      dst_val = LLVMBuildLoad(mask->bld->builder, dst, "");
+      real_val = lp_build_select(mask->bld,
+                                 mask->exec_mask,
+                                 val, dst_val);
+
+      LLVMBuildStore(mask->bld->builder, real_val, dst);
+   } else
+      LLVMBuildStore(mask->bld->builder, val, dst);
+}
+
 
 static LLVMValueRef
 emit_ddx(struct lp_build_tgsi_soa_context *bld,
@@ -287,13 +369,13 @@ emit_store(
 
    switch( reg->Register.File ) {
    case TGSI_FILE_OUTPUT:
-      LLVMBuildStore(bld->base.builder, value,
-                     bld->outputs[reg->Register.Index][chan_index]);
+      lp_exec_mask_store(&bld->exec_mask, value,
+                         bld->outputs[reg->Register.Index][chan_index]);
       break;
 
    case TGSI_FILE_TEMPORARY:
-      LLVMBuildStore(bld->base.builder, value,
-                     bld->temps[reg->Register.Index][chan_index]);
+      lp_exec_mask_store(&bld->exec_mask, value,
+                         bld->temps[reg->Register.Index][chan_index]);
       break;
 
    case TGSI_FILE_ADDRESS:
@@ -1272,8 +1354,8 @@ emit_instruction(
       break;
 
    case TGSI_OPCODE_IF:
-      /* FIXME */
-      return 0;
+      tmp0 = emit_fetch(bld, inst, 0, CHAN_X);
+      lp_exec_mask_cond_push(&bld->exec_mask, tmp0);
       break;
 
    case TGSI_OPCODE_BGNFOR:
@@ -1289,13 +1371,11 @@ emit_instruction(
       break;
 
    case TGSI_OPCODE_ELSE:
-      /* FIXME */
-      return 0;
+      lp_exec_mask_cond_invert(&bld->exec_mask);
       break;
 
    case TGSI_OPCODE_ENDIF:
-      /* FIXME */
-      return 0;
+      lp_exec_mask_cond_pop(&bld->exec_mask);
       break;
 
    case TGSI_OPCODE_ENDFOR:
@@ -1458,6 +1538,8 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
    bld.consts_ptr = consts_ptr;
    bld.sampler = sampler;
 
+   lp_exec_mask_init(&bld.exec_mask, &bld.base);
+
    tgsi_parse_init( &parse, tokens );
 
    while( !tgsi_parse_end_of_tokens( &parse ) ) {