summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_flow.c75
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_flow.h10
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_format_aos.c7
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_logic.c12
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_logic.h3
-rw-r--r--src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c31
6 files changed, 97 insertions, 41 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_flow.c b/src/gallium/auxiliary/gallivm/lp_bld_flow.c
index e60ab4f6ba..8f15b1d287 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_flow.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_flow.c
@@ -792,3 +792,78 @@ lp_build_endif(struct lp_build_if_state *ctx)
/* Resume building code at end of the ifthen->merge_block */
LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
}
+
+
+/**
+ * Allocate a scalar (or vector) variable.
+ *
+ * Although not strictly part of control flow, control flow has deep impact in
+ * how variables should be allocated.
+ *
+ * The mem2reg optimization pass is the recommended way to dealing with mutable
+ * variables, and SSA. It looks for allocas and if it can handle them, it
+ * promotes them, but only looks for alloca instructions in the entry block of
+ * the function. Being in the entry block guarantees that the alloca is only
+ * executed once, which makes analysis simpler.
+ *
+ * See also:
+ * - http://www.llvm.org/docs/tutorial/OCamlLangImpl7.html#memory
+ */
+LLVMValueRef
+lp_build_alloca(LLVMBuilderRef builder,
+ LLVMTypeRef type,
+ const char *name)
+{
+ LLVMBasicBlockRef current_block = LLVMGetInsertBlock(builder);
+ LLVMValueRef function = LLVMGetBasicBlockParent(current_block);
+ LLVMBasicBlockRef first_block = LLVMGetEntryBasicBlock(function);
+ LLVMValueRef first_instr = LLVMGetFirstInstruction(first_block);
+ LLVMBuilderRef first_builder = LLVMCreateBuilder();
+ LLVMValueRef res;
+
+ LLVMPositionBuilderAtEnd(first_builder, first_block);
+ LLVMPositionBuilderBefore(first_builder, first_instr);
+
+ res = LLVMBuildAlloca(first_builder, type, name);
+
+ LLVMDisposeBuilder(first_builder);
+
+ return res;
+}
+
+
+/**
+ * Allocate an array of scalars/vectors.
+ *
+ * mem2reg pass is not capable of promoting structs or arrays to registers, but
+ * we still put it in the first block anyway as failure to put allocas in the
+ * first block may prevent the X86 backend from successfully align the stack as
+ * required.
+ *
+ * Also the scalarrepl pass is supossedly more powerful and can promote
+ * arrays in many cases.
+ *
+ * See also:
+ * - http://www.llvm.org/docs/tutorial/OCamlLangImpl7.html#memory
+ */
+LLVMValueRef
+lp_build_array_alloca(LLVMBuilderRef builder,
+ LLVMTypeRef type,
+ LLVMValueRef count,
+ const char *name)
+{
+ LLVMBasicBlockRef current_block = LLVMGetInsertBlock(builder);
+ LLVMValueRef function = LLVMGetBasicBlockParent(current_block);
+ LLVMBasicBlockRef first_block = LLVMGetEntryBasicBlock(function);
+ LLVMValueRef first_instr = LLVMGetFirstInstruction(first_block);
+ LLVMBuilderRef first_builder = LLVMCreateBuilder();
+ LLVMValueRef res;
+
+ LLVMPositionBuilderBefore(first_builder, first_instr);
+
+ res = LLVMBuildArrayAlloca(first_builder, type, count, name);
+
+ LLVMDisposeBuilder(first_builder);
+
+ return res;
+}
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_flow.h b/src/gallium/auxiliary/gallivm/lp_bld_flow.h
index 745838570c..fffb493a93 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_flow.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_flow.h
@@ -156,5 +156,15 @@ lp_build_endif(struct lp_build_if_state *ctx);
LLVMBasicBlockRef
lp_build_insert_new_block(LLVMBuilderRef builder, const char *name);
+LLVMValueRef
+lp_build_alloca(LLVMBuilderRef builder,
+ LLVMTypeRef type,
+ const char *name);
+
+LLVMValueRef
+lp_build_array_alloca(LLVMBuilderRef builder,
+ LLVMTypeRef type,
+ LLVMValueRef count,
+ const char *name);
#endif /* !LP_BLD_FLOW_H */
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c
index a5a019fa92..6257e9a404 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_format_aos.c
@@ -40,6 +40,7 @@
#include "lp_bld_init.h"
#include "lp_bld_type.h"
+#include "lp_bld_flow.h"
#include "lp_bld_format.h"
@@ -370,11 +371,7 @@ lp_build_fetch_rgba_aos(LLVMBuilderRef builder,
LLVMAddGlobalMapping(lp_build_engine, function, format_desc->fetch_rgba_float);
}
- /*
- * XXX: this should better go to the first block in the function
- */
-
- tmp = LLVMBuildAlloca(builder, LLVMVectorType(LLVMFloatType(), 4), "");
+ tmp = lp_build_alloca(builder, LLVMVectorType(LLVMFloatType(), 4), "");
/*
* Invoke format_desc->fetch_rgba_float() for each pixel and insert the result
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_logic.c b/src/gallium/auxiliary/gallivm/lp_bld_logic.c
index a3b6970116..d13fa1a5d0 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_logic.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_logic.c
@@ -472,18 +472,6 @@ lp_build_select_aos(struct lp_build_context *bld,
}
}
-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), "");
- }
-}
-
/** Return (a & ~b) */
LLVMValueRef
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_logic.h b/src/gallium/auxiliary/gallivm/lp_bld_logic.h
index 00a8c75019..29f9fc3b20 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_logic.h
+++ b/src/gallium/auxiliary/gallivm/lp_bld_logic.h
@@ -76,9 +76,6 @@ lp_build_select_aos(struct lp_build_context *bld,
LLVMValueRef b,
const boolean cond[4]);
-LLVMValueRef
-lp_build_alloca(struct lp_build_context *bld);
-
LLVMValueRef
lp_build_andc(struct lp_build_context *bld, LLVMValueRef a, LLVMValueRef b);
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
index fac90c6006..b9b13d8d6b 100644
--- a/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
+++ b/src/gallium/auxiliary/gallivm/lp_bld_tgsi_soa.c
@@ -744,22 +744,11 @@ 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);
+
unsigned first = decl->Range.First;
unsigned last = decl->Range.Last;
unsigned idx, i;
- LLVMBasicBlockRef current_block =
- LLVMGetInsertBlock(bld->base.builder);
- LLVMBasicBlockRef first_block =
- LLVMGetEntryBasicBlock(
- LLVMGetBasicBlockParent(current_block));
- LLVMValueRef first_inst =
- LLVMGetFirstInstruction(first_block);
-
- /* we want alloca's to be the first instruction
- * in the function so we need to rewind the builder
- * to the very beginning */
- LLVMPositionBuilderBefore(bld->base.builder,
- first_inst);
for (idx = first; idx <= last; ++idx) {
switch (decl->Declaration.File) {
@@ -767,23 +756,25 @@ emit_declaration(
if (bld->has_indirect_addressing) {
LLVMValueRef val = LLVMConstInt(LLVMInt32Type(),
last*4 + 4, 0);
- bld->temps_array = LLVMBuildArrayAlloca(bld->base.builder,
- lp_build_vec_type(bld->base.type),
- val, "");
+ bld->temps_array = lp_build_array_alloca(bld->base.builder,
+ vec_type, val, "");
} else {
for (i = 0; i < NUM_CHANNELS; i++)
- bld->temps[idx][i] = lp_build_alloca(&bld->base);
+ bld->temps[idx][i] = lp_build_alloca(bld->base.builder,
+ vec_type, "");
}
break;
case TGSI_FILE_OUTPUT:
for (i = 0; i < NUM_CHANNELS; i++)
- bld->outputs[idx][i] = lp_build_alloca(&bld->base);
+ bld->outputs[idx][i] = lp_build_alloca(bld->base.builder,
+ vec_type, "");
break;
case TGSI_FILE_ADDRESS:
for (i = 0; i < NUM_CHANNELS; i++)
- bld->addr[idx][i] = lp_build_alloca(&bld->base);
+ bld->addr[idx][i] = lp_build_alloca(bld->base.builder,
+ vec_type, "");
break;
default:
@@ -792,8 +783,6 @@ emit_declaration(
}
}
- LLVMPositionBuilderAtEnd(bld->base.builder,
- current_block);
return TRUE;
}