summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Paul <[email protected]>2010-01-08 11:01:00 -0700
committerBrian Paul <[email protected]>2010-01-08 11:06:16 -0700
commit70b8d59792a814a5a81b86d57016314754d91593 (patch)
tree760c3ba7395f471546dfa1db823870df05144267
parent080c40ab32b2abd6d8381b4a0cc143d36a1652b2 (diff)
llvmpipe: checkpoint if/else/endif contructs work
The LLVM IR looks correct now. Basic blocks are where they're supposed to be and the Phi functions have the right (var,block) information.
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_flow.c220
-rw-r--r--src/gallium/drivers/llvmpipe/lp_bld_flow.h5
2 files changed, 96 insertions, 129 deletions
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_flow.c b/src/gallium/drivers/llvmpipe/lp_bld_flow.c
index 230edc6a5cf..a347cedf038 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_flow.c
+++ b/src/gallium/drivers/llvmpipe/lp_bld_flow.c
@@ -87,13 +87,7 @@ struct lp_build_flow_if
{
unsigned num_variables;
- /** phi variables in the true clause */
- LLVMValueRef true_variables[LP_BUILD_IF_MAX_VARIABLES];
- unsigned num_true_variables;
-
- /** phi variables in the false clause */
- LLVMValueRef false_variables[LP_BUILD_IF_MAX_VARIABLES];
- unsigned num_false_variables;
+ LLVMValueRef *phi; /**< array [num_variables] */
};
@@ -310,28 +304,43 @@ lp_build_flow_scope_end(struct lp_build_flow_context *flow)
}
+/**
+ * Note: this function has no dependencies on the flow code and could
+ * be used elsewhere.
+ */
static LLVMBasicBlockRef
-lp_build_flow_insert_block(struct lp_build_flow_context *flow)
+lp_build_insert_new_block(LLVMBuilderRef builder, const char *name)
{
LLVMBasicBlockRef current_block;
LLVMBasicBlockRef next_block;
LLVMBasicBlockRef new_block;
- current_block = LLVMGetInsertBlock(flow->builder);
+ /* get current basic block */
+ current_block = LLVMGetInsertBlock(builder);
+ /* check if there's another block after this one */
next_block = LLVMGetNextBasicBlock(current_block);
- if(next_block) {
- new_block = LLVMInsertBasicBlock(next_block, "");
+ if (next_block) {
+ /* insert the new block before the next block */
+ new_block = LLVMInsertBasicBlock(next_block, name);
}
else {
+ /* append new block after current block */
LLVMValueRef function = LLVMGetBasicBlockParent(current_block);
- new_block = LLVMAppendBasicBlock(function, "");
+ new_block = LLVMAppendBasicBlock(function, name);
}
return new_block;
}
+static LLVMBasicBlockRef
+lp_build_flow_insert_block(struct lp_build_flow_context *flow)
+{
+ return lp_build_insert_new_block(flow->builder, "");
+}
+
+
/**
* Begin a "skip" block. Inside this block we can test a condition and
* skip to the end of the block if the condition is false.
@@ -576,22 +585,24 @@ lp_build_loop_end(LLVMBuilderRef builder,
Is built with:
+ LLVMValueRef x = LLVMGetUndef(); // or something else
+
flow = lp_build_flow_create(builder);
- ...
- lp_build_flow_scope_declare(flow, "x");
+ lp_build_flow_scope_begin(flow);
+
+ // x needs a phi node
+ lp_build_flow_scope_declare(flow, &x);
- lp_build_if(ctx, flow, builder, cond);
- x = LLVMAdd(1, 2);
- lp_build_if_phi_var(ctx, "x");
- lp_build_else(ctx);
- x = LLVMAdd(2, 3);
- lp_build_if_phi_var(ctx, "x");
- lp_build_endif(ctx);
+ lp_build_if(ctx, flow, builder, cond);
+ x = LLVMAdd(1, 2);
+ lp_build_else(ctx);
+ x = LLVMAdd(2, 3);
+ lp_build_endif(ctx);
- ...
+ lp_build_flow_scope_end(flow);
- flow = lp_build_flow_end(flow);
+ lp_build_flow_destroy(flow);
*/
@@ -606,8 +617,8 @@ lp_build_if(struct lp_build_if_state *ctx,
LLVMValueRef condition)
{
LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
- LLVMValueRef function = LLVMGetBasicBlockParent(block);
struct lp_build_flow_if *ifthen;
+ unsigned i;
memset(ctx, 0, sizeof(*ctx));
ctx->builder = builder;
@@ -620,12 +631,27 @@ lp_build_if(struct lp_build_if_state *ctx,
assert(ifthen);
ifthen->num_variables = flow->num_variables;
- ifthen->num_true_variables = 0;
- ifthen->num_false_variables = 0;
- /* allocate the block for the if/true clause */
- ctx->true_block = LLVMAppendBasicBlock(function, "true block");
- /* XXX is this correct ??? */
+ /* create a Phi node for each variable in this flow scope */
+ ifthen->phi = MALLOC(ifthen->num_variables * sizeof(*ifthen->phi));
+ if (!ifthen->phi) {
+ ifthen->num_variables = 0;
+ return;
+ }
+
+ /* create endif/merge basic block for the phi functions */
+ ctx->merge_block = lp_build_insert_new_block(builder, "endif-block");
+ LLVMPositionBuilderAtEnd(builder, ctx->merge_block);
+
+ /* create a phi node for each variable */
+ for (i = 0; i < flow->num_variables; i++)
+ ifthen->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
+
+
+ /* create/insert true_block before merge_block */
+ ctx->true_block = LLVMInsertBasicBlock(ctx->merge_block, "if-true-block");
+
+ /* successive code goes into the true block */
LLVMPositionBuilderAtEnd(builder, ctx->true_block);
}
@@ -636,86 +662,71 @@ lp_build_if(struct lp_build_if_state *ctx,
void
lp_build_else(struct lp_build_if_state *ctx)
{
- LLVMBasicBlockRef block = LLVMGetInsertBlock(ctx->builder);
- LLVMValueRef function = LLVMGetBasicBlockParent(block);
+ struct lp_build_flow_context *flow = ctx->flow;
struct lp_build_flow_if *ifthen;
+ unsigned i;
- ifthen = &lp_build_flow_peek(ctx->flow, LP_BUILD_FLOW_IF)->ifthen;
+ ifthen = &lp_build_flow_peek(flow, LP_BUILD_FLOW_IF)->ifthen;
assert(ifthen);
- /* allocate the block for the else/false clause */
- ctx->false_block = LLVMAppendBasicBlock(function, "false block");
- /* XXX is this correct ??? */
+ /* for each variable, update the Phi node with a (variable, block) pair */
+ LLVMPositionBuilderAtEnd(ctx->builder, ctx->merge_block);
+ for (i = 0; i < flow->num_variables; i++) {
+ assert(*flow->variables[i]);
+ LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ctx->true_block, 1);
+ }
+
+ /* create/insert false_block before the merge block */
+ ctx->false_block = LLVMInsertBasicBlock(ctx->merge_block, "if-false-block");
+
+ /* successive code goes into the else block */
LLVMPositionBuilderAtEnd(ctx->builder, ctx->false_block);
}
/**
* End a conditional.
- * This involves building a "merge" block at the endif which
- * contains the phi instructions.
*/
void
lp_build_endif(struct lp_build_if_state *ctx)
{
- LLVMBasicBlockRef block = LLVMGetInsertBlock(ctx->builder);
- LLVMValueRef function = LLVMGetBasicBlockParent(block);
- LLVMBasicBlockRef merge_block = LLVMAppendBasicBlock(function, "endif block");
- LLVMValueRef phi[LP_BUILD_FLOW_MAX_VARIABLES];
+ struct lp_build_flow_context *flow = ctx->flow;
struct lp_build_flow_if *ifthen;
unsigned i;
- /* build the endif/merge block now */
- /* XXX this is probably wrong */
- LLVMPositionBuilderAtEnd(ctx->builder, merge_block);
-
- ifthen = &lp_build_flow_pop(ctx->flow, LP_BUILD_FLOW_IF)->ifthen;
+ ifthen = &lp_build_flow_pop(flow, LP_BUILD_FLOW_IF)->ifthen;
assert(ifthen);
- memset(phi, 0, sizeof(phi));
-
- /* build phi nodes for any variables which were declared inside if part */
+ if (ctx->false_block) {
+ LLVMPositionBuilderAtEnd(ctx->builder, ctx->merge_block);
+ /* for each variable, update the Phi node with a (variable, block) pair */
+ for (i = 0; i < flow->num_variables; i++) {
+ assert(*flow->variables[i]);
+ LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ctx->false_block, 1);
+ }
+ }
+ else {
+ /* no else clause */
+ LLVMPositionBuilderAtEnd(ctx->builder, ctx->merge_block);
+ for (i = 0; i < flow->num_variables; i++) {
+ LLVMValueRef undef;
- for (i = 0; i < ifthen->num_variables; i++) {
- LLVMValueRef *var = ctx->flow->variables[i];
- const char *name = LLVMGetValueName(*var);
- unsigned j;
+ assert(*flow->variables[i]);
- /* search true-clause variables list for 'name' */
- for (j = 0; j < ifthen->num_true_variables; j++) {
- LLVMValueRef v = ifthen->true_variables[j];
- if (strcmp(LLVMGetValueName(v), name) == 0) {
- /* add phi */
- if (!phi[i])
- phi[i] = LLVMBuildPhi(ctx->builder, LLVMTypeOf(*var), "");
- LLVMAddIncoming(phi[i], &v, &ctx->true_block, 1);
- }
- }
+ LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ctx->true_block, 1);
- /* search false-clause variables list for 'name' */
- for (j = 0; j < ifthen->num_false_variables; j++) {
- LLVMValueRef v = ifthen->false_variables[j];
- if (strcmp(LLVMGetValueName(v), name) == 0) {
- /* add phi */
- if (!phi[i])
- phi[i] = LLVMBuildPhi(ctx->builder, LLVMTypeOf(*var), "");
- LLVMAddIncoming(phi[i], &v, &ctx->false_block, 1);
- }
+ /* undef value from the block preceeding the 'if' */
+ undef = LLVMGetUndef(LLVMTypeOf(*flow->variables[i]));
+ LLVMAddIncoming(ifthen->phi[i], &undef, &ctx->entry_block, 1);
}
-
- /* "return" new phi variable to calling code */
- if (phi[i])
- *var = phi[i];
}
/***
- *** Insert the various branch instructions here.
- *** XXX need to verify all the builder/block positioning is correct.
+ *** Now patch in the various branch instructions.
***/
/* Insert the conditional branch instruction at the end of entry_block */
LLVMPositionBuilderAtEnd(ctx->builder, ctx->entry_block);
-
if (ctx->false_block) {
/* we have an else clause */
LLVMBuildCondBr(ctx->builder, ctx->condition,
@@ -724,60 +735,19 @@ lp_build_endif(struct lp_build_if_state *ctx)
else {
/* no else clause */
LLVMBuildCondBr(ctx->builder, ctx->condition,
- ctx->true_block, merge_block);
+ ctx->true_block, ctx->merge_block);
}
/* Append an unconditional Br(anch) instruction on the true_block */
LLVMPositionBuilderAtEnd(ctx->builder, ctx->true_block);
- LLVMBuildBr(ctx->builder, merge_block);
+ LLVMBuildBr(ctx->builder, ctx->merge_block);
if (ctx->false_block) {
/* Append an unconditional Br(anch) instruction on the false_block */
LLVMPositionBuilderAtEnd(ctx->builder, ctx->false_block);
- LLVMBuildBr(ctx->builder, merge_block);
- }
-
-
- /* Finish-up: continue building at end of the merge_block */
- /* XXX is this right? */
- LLVMPositionBuilderAtEnd(ctx->builder, merge_block);
-}
-
-
-/**
- * Declare a variable that needs to be merged with another variable
- * via a phi function.
- * This function must be called after lp_build_if() and lp_build_endif().
- */
-void
-lp_build_if_phi_var(struct lp_build_if_state *ctx, LLVMValueRef var)
-{
- struct lp_build_flow_if *ifthen;
- const char *name;
-
- name = LLVMGetValueName(var);
- assert(name && "variable requires a name");
-
- /* make sure the var existed before the if/then/else */
- {
- boolean found = FALSE;
- uint i;
- for (i = 0; i < ctx->flow->num_variables; i++) {
- LLVMValueRef *var = ctx->flow->variables[i];
- if (strcmp(LLVMGetValueName(*var), name) == 0) {
- found = TRUE;
- break;
- }
- }
- assert(found);
+ LLVMBuildBr(ctx->builder, ctx->merge_block);
}
- ifthen = &lp_build_flow_pop(ctx->flow, LP_BUILD_FLOW_IF)->ifthen;
- if (ctx->false_block) {
- ifthen->false_variables[ifthen->num_false_variables++] = var;
- }
- else {
- assert(ctx->true_block);
- ifthen->true_variables[ifthen->num_true_variables++] = var;
- }
+ /* Resume building code at end of the ctx->merge_block */
+ LLVMPositionBuilderAtEnd(ctx->builder, ctx->merge_block);
}
diff --git a/src/gallium/drivers/llvmpipe/lp_bld_flow.h b/src/gallium/drivers/llvmpipe/lp_bld_flow.h
index 1f294b8a49d..7c7cc402a38 100644
--- a/src/gallium/drivers/llvmpipe/lp_bld_flow.h
+++ b/src/gallium/drivers/llvmpipe/lp_bld_flow.h
@@ -132,7 +132,7 @@ struct lp_build_if_state
LLVMBuilderRef builder;
struct lp_build_flow_context *flow;
LLVMValueRef condition;
- LLVMBasicBlockRef entry_block, true_block, false_block;
+ LLVMBasicBlockRef entry_block, true_block, false_block, merge_block;
};
@@ -143,9 +143,6 @@ lp_build_if(struct lp_build_if_state *ctx,
LLVMValueRef condition);
void
-lp_build_if_phi_var(struct lp_build_if_state *ctx, LLVMValueRef var);
-
-void
lp_build_else(struct lp_build_if_state *ctx);
void