llvmpipe: switch to using dynamic stack allocation instead of registers
authorZack Rusin <zackr@vmware.com>
Tue, 9 Feb 2010 02:50:33 +0000 (21:50 -0500)
committerZack Rusin <zackr@vmware.com>
Tue, 9 Feb 2010 02:50:33 +0000 (21:50 -0500)
with mutable vars we don't need to follow the phi nodes. meaning that
control flow becomes trivial as we don't have scan the rest of the tgsi
to figure out the variable usage anymore. futhermore the memory2register
pass promotes alloca/store/load to registers while inserting the right phi
nodes. so we get simplicity and performance.

src/gallium/auxiliary/gallivm/lp_bld_logic.c
src/gallium/auxiliary/gallivm/lp_bld_logic.h
src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
src/gallium/drivers/llvmpipe/lp_state_fs.c

index d23de4f0ef8ca7fafaf7f557ac9dd380338a6648..41ac81b7441d2af42e4fcab41dafbcdc92c6f118 100644 (file)
@@ -419,3 +419,15 @@ lp_build_select_aos(struct lp_build_context *bld,
 #endif
    }
 }
+
+LLVMValueRef
+lp_build_alloca(struct lp_build_context *bld)
+{
+   const struct lp_type type = bld->type;
+
+   if (type.length > 1) { /*vector*/
+      return LLVMBuildAlloca(bld->builder, lp_build_vec_type(type), "");
+   } else { /*scalar*/
+      return LLVMBuildAlloca(bld->builder, lp_build_elem_type(type), "");
+   }
+}
index 40d64eb2c1917c2089865224b7105e2f2b2c56f3..a399ebf39ef4076d84dbf8cfc9efd137a86a4779 100644 (file)
@@ -76,5 +76,7 @@ lp_build_select_aos(struct lp_build_context *bld,
                     LLVMValueRef b,
                     const boolean cond[4]);
 
+LLVMValueRef
+lp_build_alloca(struct lp_build_context *bld);
 
 #endif /* !LP_BLD_LOGIC_H */
index 85e3b1bdd421fde789da440eb5b777ac8c527e8b..a52c6c5028849292084091cce4d2ad87f9f54bc2 100644 (file)
@@ -185,7 +185,7 @@ emit_fetch(
          break;
 
       case TGSI_FILE_TEMPORARY:
-         res = bld->temps[reg->Register.Index][swizzle];
+         res = LLVMBuildLoad(bld->base.builder, bld->temps[reg->Register.Index][swizzle], "");
          if(!res)
             return bld->base.undef;
          break;
@@ -287,11 +287,13 @@ emit_store(
 
    switch( reg->Register.File ) {
    case TGSI_FILE_OUTPUT:
-      bld->outputs[reg->Register.Index][chan_index] = value;
+      LLVMBuildStore(bld->base.builder, value,
+                     bld->outputs[reg->Register.Index][chan_index]);
       break;
 
    case TGSI_FILE_TEMPORARY:
-      bld->temps[reg->Register.Index][chan_index] = value;
+      LLVMBuildStore(bld->base.builder, value,
+                     bld->temps[reg->Register.Index][chan_index]);
       break;
 
    case TGSI_FILE_ADDRESS:
@@ -438,6 +440,42 @@ indirect_temp_reference(const struct tgsi_full_instruction *inst)
    return FALSE;
 }
 
+static int
+emit_declaration(
+   struct lp_build_tgsi_soa_context *bld,
+   const struct tgsi_full_declaration *decl)
+{
+   unsigned first = decl->Range.First;
+   unsigned last = decl->Range.Last;
+   unsigned idx, i;
+
+   for (idx = first; idx <= last; ++idx) {
+      boolean ok;
+
+      switch (decl->Declaration.File) {
+      case TGSI_FILE_TEMPORARY:
+         for (i = 0; i < NUM_CHANNELS; i++)
+            bld->temps[idx][i] = lp_build_alloca(&bld->base);
+         ok = TRUE;
+         break;
+
+      case TGSI_FILE_OUTPUT:
+         for (i = 0; i < NUM_CHANNELS; i++)
+            bld->outputs[idx][i] = lp_build_alloca(&bld->base);
+         ok = TRUE;
+         break;
+
+      default:
+         /* don't need to declare other vars */
+         ok = TRUE;
+      }
+
+      if (!ok)
+         return FALSE;
+   }
+
+   return TRUE;
+}
 
 static int
 emit_instruction(
@@ -1429,6 +1467,10 @@ lp_build_tgsi_soa(LLVMBuilderRef builder,
       switch( parse.FullToken.Token.Type ) {
       case TGSI_TOKEN_TYPE_DECLARATION:
          /* Inputs already interpolated */
+         {
+            if (!emit_declaration( &bld, &parse.FullToken.FullDeclaration ))
+               _debug_printf("warning: failed to define LLVM variable\n");
+         }
          break;
 
       case TGSI_TOKEN_TYPE_INSTRUCTION:
index 320e2b72e43386e6e8113ae2e0125e85b24c1f77..2001a95661ede90eaaf4a0b9aa81a01ca10101b6 100644 (file)
@@ -468,20 +468,21 @@ generate_fs(struct llvmpipe_context *lp,
    for (attrib = 0; attrib < shader->info.num_outputs; ++attrib) {
       for(chan = 0; chan < NUM_CHANNELS; ++chan) {
          if(outputs[attrib][chan]) {
-            lp_build_name(outputs[attrib][chan], "output%u.%u.%c", i, attrib, "xyzw"[chan]);
+            LLVMValueRef out = LLVMBuildLoad(builder, outputs[attrib][chan], "");
+            lp_build_name(out, "output%u.%u.%c", i, attrib, "xyzw"[chan]);
 
             switch (shader->info.output_semantic_name[attrib]) {
             case TGSI_SEMANTIC_COLOR:
                {
                   unsigned cbuf = shader->info.output_semantic_index[attrib];
 
-                  lp_build_name(outputs[attrib][chan], "color%u.%u.%c", i, attrib, "rgba"[chan]);
+                  lp_build_name(out, "color%u.%u.%c", i, attrib, "rgba"[chan]);
 
                   /* Alpha test */
                   /* XXX: should the alpha reference value be passed separately? */
                  /* XXX: should only test the final assignment to alpha */
                   if(cbuf == 0 && chan == 3) {
-                     LLVMValueRef alpha = outputs[attrib][chan];
+                     LLVMValueRef alpha = out;
                      LLVMValueRef alpha_ref_value;
                      alpha_ref_value = lp_jit_context_alpha_ref_value(builder, context_ptr);
                      alpha_ref_value = lp_build_broadcast(builder, vec_type, alpha_ref_value);
@@ -489,13 +490,13 @@ generate_fs(struct llvmpipe_context *lp,
                                          &mask, alpha, alpha_ref_value);
                   }
 
-                 color[cbuf][chan] = outputs[attrib][chan];
+                 color[cbuf][chan] = out;
                   break;
                }
 
             case TGSI_SEMANTIC_POSITION:
                if(chan == 2)
-                  z = outputs[attrib][chan];
+                  z = out;
                break;
             }
          }