#include "util/u_debug.h"
#include "util/u_memory.h"
+#include "lp_bld_init.h"
#include "lp_bld_type.h"
#include "lp_bld_flow.h"
-#define LP_BUILD_FLOW_MAX_VARIABLES 32
-#define LP_BUILD_FLOW_MAX_DEPTH 32
-
-/**
- * Enumeration of all possible flow constructs.
- */
-enum lp_build_flow_construct_kind {
- LP_BUILD_FLOW_SCOPE,
- LP_BUILD_FLOW_SKIP,
- LP_BUILD_FLOW_IF
-};
-
-
-/**
- * Variable declaration scope.
- */
-struct lp_build_flow_scope
-{
- /** Number of variables declared in this scope */
- unsigned num_variables;
-};
-
-
-/**
- * Early exit. Useful to skip to the end of a function or block when
- * the execution mask becomes zero or when there is an error condition.
- */
-struct lp_build_flow_skip
-{
- /** Block to skip to */
- LLVMBasicBlockRef block;
-
- /** Number of variables declared at the beginning */
- unsigned num_variables;
-
- LLVMValueRef *phi; /**< array [num_variables] */
-};
-
-
-/**
- * if/else/endif.
- */
-struct lp_build_flow_if
-{
- unsigned num_variables;
-
- LLVMValueRef *phi; /**< array [num_variables] */
-
- LLVMValueRef condition;
- LLVMBasicBlockRef entry_block, true_block, false_block, merge_block;
-};
-
-
-/**
- * Union of all possible flow constructs' data
- */
-union lp_build_flow_construct_data
-{
- struct lp_build_flow_scope scope;
- struct lp_build_flow_skip skip;
- struct lp_build_flow_if ifthen;
-};
-
-
-/**
- * Element of the flow construct stack.
- */
-struct lp_build_flow_construct
-{
- enum lp_build_flow_construct_kind kind;
- union lp_build_flow_construct_data data;
-};
-
-
-/**
- * All necessary data to generate LLVM control flow constructs.
- *
- * Besides keeping track of the control flow construct themselves we also
- * need to keep track of variables in order to generate SSA Phi values.
- */
-struct lp_build_flow_context
-{
- LLVMBuilderRef builder;
-
- /**
- * Control flow stack.
- */
- struct lp_build_flow_construct constructs[LP_BUILD_FLOW_MAX_DEPTH];
- unsigned num_constructs;
-
- /**
- * Variable stack
- */
- LLVMValueRef *variables[LP_BUILD_FLOW_MAX_VARIABLES];
- unsigned num_variables;
-};
-
-
-struct lp_build_flow_context *
-lp_build_flow_create(LLVMBuilderRef builder)
-{
- struct lp_build_flow_context *flow;
-
- flow = CALLOC_STRUCT(lp_build_flow_context);
- if(!flow)
- return NULL;
-
- flow->builder = builder;
-
- return flow;
-}
-
-
-void
-lp_build_flow_destroy(struct lp_build_flow_context *flow)
-{
- assert(flow->num_constructs == 0);
- assert(flow->num_variables == 0);
- FREE(flow);
-}
-
-
-/**
- * Begin/push a new flow control construct, such as a loop, skip block
- * or variable scope.
- */
-static union lp_build_flow_construct_data *
-lp_build_flow_push(struct lp_build_flow_context *flow,
- enum lp_build_flow_construct_kind kind)
-{
- assert(flow->num_constructs < LP_BUILD_FLOW_MAX_DEPTH);
- if(flow->num_constructs >= LP_BUILD_FLOW_MAX_DEPTH)
- return NULL;
-
- flow->constructs[flow->num_constructs].kind = kind;
- return &flow->constructs[flow->num_constructs++].data;
-}
-
-
-/**
- * Return the current/top flow control construct on the stack.
- * \param kind the expected type of the top-most construct
- */
-static union lp_build_flow_construct_data *
-lp_build_flow_peek(struct lp_build_flow_context *flow,
- enum lp_build_flow_construct_kind kind)
-{
- assert(flow->num_constructs);
- if(!flow->num_constructs)
- return NULL;
-
- assert(flow->constructs[flow->num_constructs - 1].kind == kind);
- if(flow->constructs[flow->num_constructs - 1].kind != kind)
- return NULL;
-
- return &flow->constructs[flow->num_constructs - 1].data;
-}
-
-
-/**
- * End/pop the current/top flow control construct on the stack.
- * \param kind the expected type of the top-most construct
- */
-static union lp_build_flow_construct_data *
-lp_build_flow_pop(struct lp_build_flow_context *flow,
- enum lp_build_flow_construct_kind kind)
-{
- assert(flow->num_constructs);
- if(!flow->num_constructs)
- return NULL;
-
- assert(flow->constructs[flow->num_constructs - 1].kind == kind);
- if(flow->constructs[flow->num_constructs - 1].kind != kind)
- return NULL;
-
- return &flow->constructs[--flow->num_constructs].data;
-}
-
-
/**
- * Begin a variable scope.
- *
+ * Insert a new block, right where builder is pointing to.
*
- */
-void
-lp_build_flow_scope_begin(struct lp_build_flow_context *flow)
-{
- struct lp_build_flow_scope *scope;
-
- scope = &lp_build_flow_push(flow, LP_BUILD_FLOW_SCOPE)->scope;
- if(!scope)
- return;
-
- scope->num_variables = 0;
-}
-
-
-/**
- * Declare a variable.
+ * This is useful important not only for aesthetic reasons, but also for
+ * performance reasons, as frequently run blocks should be laid out next to
+ * each other and fall-throughs maximized.
*
- * A variable is a named entity which can have different LLVMValueRef's at
- * different points of the program. This is relevant for control flow because
- * when there are multiple branches to a same location we need to replace
- * the variable's value with a Phi function as explained in
- * http://en.wikipedia.org/wiki/Static_single_assignment_form .
+ * See also llvm/lib/Transforms/Scalar/BasicBlockPlacement.cpp.
*
- * We keep track of variables by keeping around a pointer to where they're
- * current.
- *
- * There are a few cautions to observe:
- *
- * - Variable's value must not be NULL. If there is no initial value then
- * LLVMGetUndef() should be used.
- *
- * - Variable's value must be kept up-to-date. If the variable is going to be
- * modified by a function then a pointer should be passed so that its value
- * is accurate. Failure to do this will cause some of the variables'
- * transient values to be lost, leading to wrong results.
- *
- * - A program should be written from top to bottom, by always appending
- * instructions to the bottom with a single LLVMBuilderRef. Inserting and/or
- * modifying existing statements will most likely lead to wrong results.
- *
- */
-void
-lp_build_flow_scope_declare(struct lp_build_flow_context *flow,
- LLVMValueRef *variable)
-{
- struct lp_build_flow_scope *scope;
-
- scope = &lp_build_flow_peek(flow, LP_BUILD_FLOW_SCOPE)->scope;
- if(!scope)
- return;
-
- assert(*variable);
- if(!*variable)
- return;
-
- assert(flow->num_variables < LP_BUILD_FLOW_MAX_VARIABLES);
- if(flow->num_variables >= LP_BUILD_FLOW_MAX_VARIABLES)
- return;
-
- flow->variables[flow->num_variables++] = variable;
- ++scope->num_variables;
-}
-
-
-void
-lp_build_flow_scope_end(struct lp_build_flow_context *flow)
-{
- struct lp_build_flow_scope *scope;
-
- scope = &lp_build_flow_pop(flow, LP_BUILD_FLOW_SCOPE)->scope;
- if(!scope)
- return;
-
- assert(flow->num_variables >= scope->num_variables);
- if(flow->num_variables < scope->num_variables) {
- flow->num_variables = 0;
- return;
- }
-
- flow->num_variables -= scope->num_variables;
-}
-
-
-/**
* Note: this function has no dependencies on the flow code and could
* be used elsewhere.
*/
-static LLVMBasicBlockRef
-lp_build_insert_new_block(LLVMBuilderRef builder, const char *name)
+LLVMBasicBlockRef
+lp_build_insert_new_block(struct gallivm_state *gallivm, const char *name)
{
LLVMBasicBlockRef current_block;
LLVMBasicBlockRef next_block;
LLVMBasicBlockRef new_block;
/* get current basic block */
- current_block = LLVMGetInsertBlock(builder);
+ current_block = LLVMGetInsertBlock(gallivm->builder);
/* check if there's another block after this one */
next_block = LLVMGetNextBasicBlock(current_block);
if (next_block) {
/* insert the new block before the next block */
- new_block = LLVMInsertBasicBlock(next_block, name);
+ new_block = LLVMInsertBasicBlockInContext(gallivm->context, next_block, name);
}
else {
/* append new block after current block */
LLVMValueRef function = LLVMGetBasicBlockParent(current_block);
- new_block = LLVMAppendBasicBlock(function, name);
+ new_block = LLVMAppendBasicBlockInContext(gallivm->context, 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.
*/
void
-lp_build_flow_skip_begin(struct lp_build_flow_context *flow)
+lp_build_flow_skip_begin(struct lp_build_skip_context *skip,
+ struct gallivm_state *gallivm)
{
- struct lp_build_flow_skip *skip;
- LLVMBuilderRef builder;
- unsigned i;
-
- skip = &lp_build_flow_push(flow, LP_BUILD_FLOW_SKIP)->skip;
- if(!skip)
- return;
-
+ skip->gallivm = gallivm;
/* create new basic block */
- skip->block = lp_build_flow_insert_block(flow);
-
- skip->num_variables = flow->num_variables;
- if(!skip->num_variables) {
- skip->phi = NULL;
- return;
- }
-
- /* Allocate a Phi node for each variable in this skip scope */
- skip->phi = MALLOC(skip->num_variables * sizeof *skip->phi);
- if(!skip->phi) {
- skip->num_variables = 0;
- return;
- }
-
- builder = LLVMCreateBuilder();
- LLVMPositionBuilderAtEnd(builder, skip->block);
-
- /* create a Phi node for each variable */
- for(i = 0; i < skip->num_variables; ++i)
- skip->phi[i] = LLVMBuildPhi(builder, LLVMTypeOf(*flow->variables[i]), "");
-
- LLVMDisposeBuilder(builder);
+ skip->block = lp_build_insert_new_block(gallivm, "skip");
}
* skip block if the condition is true.
*/
void
-lp_build_flow_skip_cond_break(struct lp_build_flow_context *flow,
+lp_build_flow_skip_cond_break(struct lp_build_skip_context *skip,
LLVMValueRef cond)
{
- struct lp_build_flow_skip *skip;
- LLVMBasicBlockRef current_block;
LLVMBasicBlockRef new_block;
- unsigned i;
-
- skip = &lp_build_flow_peek(flow, LP_BUILD_FLOW_SKIP)->skip;
- if(!skip)
- return;
-
- current_block = LLVMGetInsertBlock(flow->builder);
- new_block = lp_build_flow_insert_block(flow);
-
- /* for each variable, update the Phi node with a (variable, block) pair */
- for(i = 0; i < skip->num_variables; ++i) {
- assert(*flow->variables[i]);
- LLVMAddIncoming(skip->phi[i], flow->variables[i], ¤t_block, 1);
- }
+ new_block = lp_build_insert_new_block(skip->gallivm, "");
/* if cond is true, goto skip->block, else goto new_block */
- LLVMBuildCondBr(flow->builder, cond, skip->block, new_block);
+ LLVMBuildCondBr(skip->gallivm->builder, cond, skip->block, new_block);
- LLVMPositionBuilderAtEnd(flow->builder, new_block);
+ LLVMPositionBuilderAtEnd(skip->gallivm->builder, new_block);
}
void
-lp_build_flow_skip_end(struct lp_build_flow_context *flow)
+lp_build_flow_skip_end(struct lp_build_skip_context *skip)
{
- struct lp_build_flow_skip *skip;
- LLVMBasicBlockRef current_block;
- unsigned i;
-
- skip = &lp_build_flow_pop(flow, LP_BUILD_FLOW_SKIP)->skip;
- if(!skip)
- return;
-
- current_block = LLVMGetInsertBlock(flow->builder);
-
- /* add (variable, block) tuples to the phi nodes */
- for(i = 0; i < skip->num_variables; ++i) {
- assert(*flow->variables[i]);
- LLVMAddIncoming(skip->phi[i], flow->variables[i], ¤t_block, 1);
- *flow->variables[i] = skip->phi[i];
- }
-
/* goto block */
- LLVMBuildBr(flow->builder, skip->block);
- LLVMPositionBuilderAtEnd(flow->builder, skip->block);
-
- FREE(skip->phi);
+ LLVMBuildBr(skip->gallivm->builder, skip->block);
+ LLVMPositionBuilderAtEnd(skip->gallivm->builder, skip->block);
}
/**
* Check if the mask predicate is zero. If so, jump to the end of the block.
*/
-static void
+void
lp_build_mask_check(struct lp_build_mask_context *mask)
{
- LLVMBuilderRef builder = mask->flow->builder;
+ LLVMBuilderRef builder = mask->skip.gallivm->builder;
+ LLVMValueRef value;
LLVMValueRef cond;
+ value = lp_build_mask_value(mask);
+
+ /*
+ * XXX this doesn't quite generate the most efficient code possible, if
+ * the masks are vectors which have all bits set to the same value
+ * in each element.
+ * movmskps/pmovmskb would be more efficient to get the required value
+ * into ordinary reg (certainly with 8 floats).
+ * Not sure if llvm could figure that out on its own.
+ */
+
/* cond = (mask == 0) */
cond = LLVMBuildICmp(builder,
LLVMIntEQ,
- LLVMBuildBitCast(builder, mask->value, mask->reg_type, ""),
+ LLVMBuildBitCast(builder, value, mask->reg_type, ""),
LLVMConstNull(mask->reg_type),
"");
/* if cond, goto end of block */
- lp_build_flow_skip_cond_break(mask->flow, cond);
+ lp_build_flow_skip_cond_break(&mask->skip, cond);
}
*/
void
lp_build_mask_begin(struct lp_build_mask_context *mask,
- struct lp_build_flow_context *flow,
+ struct gallivm_state *gallivm,
struct lp_type type,
LLVMValueRef value)
{
memset(mask, 0, sizeof *mask);
- mask->flow = flow;
- mask->reg_type = LLVMIntType(type.width * type.length);
- mask->value = value;
+ mask->reg_type = LLVMIntTypeInContext(gallivm->context, type.width * type.length);
+ mask->var = lp_build_alloca(gallivm,
+ lp_build_int_vec_type(gallivm, type),
+ "execution_mask");
- lp_build_flow_scope_begin(flow);
- lp_build_flow_scope_declare(flow, &mask->value);
- lp_build_flow_skip_begin(flow);
+ LLVMBuildStore(gallivm->builder, value, mask->var);
+
+ lp_build_flow_skip_begin(&mask->skip, gallivm);
+}
- lp_build_mask_check(mask);
+
+LLVMValueRef
+lp_build_mask_value(struct lp_build_mask_context *mask)
+{
+ return LLVMBuildLoad(mask->skip.gallivm->builder, mask->var, "");
}
/**
* Update boolean mask with given value (bitwise AND).
* Typically used to update the quad's pixel alive/killed mask
- * after depth testing, alpha testing, TGSI_OPCODE_KIL, etc.
+ * after depth testing, alpha testing, TGSI_OPCODE_KILL_IF, etc.
*/
void
lp_build_mask_update(struct lp_build_mask_context *mask,
LLVMValueRef value)
{
- mask->value = LLVMBuildAnd( mask->flow->builder, mask->value, value, "");
-
- lp_build_mask_check(mask);
+ value = LLVMBuildAnd(mask->skip.gallivm->builder,
+ lp_build_mask_value(mask),
+ value, "");
+ LLVMBuildStore(mask->skip.gallivm->builder, value, mask->var);
}
LLVMValueRef
lp_build_mask_end(struct lp_build_mask_context *mask)
{
- lp_build_flow_skip_end(mask->flow);
- lp_build_flow_scope_end(mask->flow);
- return mask->value;
+ lp_build_flow_skip_end(&mask->skip);
+ return lp_build_mask_value(mask);
}
void
-lp_build_loop_begin(LLVMBuilderRef builder,
- LLVMValueRef start,
- struct lp_build_loop_state *state)
+lp_build_loop_begin(struct lp_build_loop_state *state,
+ struct gallivm_state *gallivm,
+ LLVMValueRef start)
+
{
- LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
- LLVMValueRef function = LLVMGetBasicBlockParent(block);
+ LLVMBuilderRef builder = gallivm->builder;
- state->block = LLVMAppendBasicBlock(function, "loop");
+ state->block = lp_build_insert_new_block(gallivm, "loop_begin");
- LLVMBuildBr(builder, state->block);
+ state->counter_var = lp_build_alloca(gallivm, LLVMTypeOf(start), "loop_counter");
+ state->gallivm = gallivm;
- LLVMPositionBuilderAtEnd(builder, state->block);
+ LLVMBuildStore(builder, start, state->counter_var);
- state->counter = LLVMBuildPhi(builder, LLVMTypeOf(start), "");
+ LLVMBuildBr(builder, state->block);
- LLVMAddIncoming(state->counter, &start, &block, 1);
+ LLVMPositionBuilderAtEnd(builder, state->block);
+ state->counter = LLVMBuildLoad(builder, state->counter_var, "");
}
void
-lp_build_loop_end(LLVMBuilderRef builder,
- LLVMValueRef end,
- LLVMValueRef step,
- struct lp_build_loop_state *state)
+lp_build_loop_end_cond(struct lp_build_loop_state *state,
+ LLVMValueRef end,
+ LLVMValueRef step,
+ LLVMIntPredicate llvm_cond)
{
- LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
- LLVMValueRef function = LLVMGetBasicBlockParent(block);
+ LLVMBuilderRef builder = state->gallivm->builder;
LLVMValueRef next;
LLVMValueRef cond;
LLVMBasicBlockRef after_block;
next = LLVMBuildAdd(builder, state->counter, step, "");
- cond = LLVMBuildICmp(builder, LLVMIntNE, next, end, "");
+ LLVMBuildStore(builder, next, state->counter_var);
- after_block = LLVMAppendBasicBlock(function, "");
+ cond = LLVMBuildICmp(builder, llvm_cond, next, end, "");
- LLVMBuildCondBr(builder, cond, after_block, state->block);
+ after_block = lp_build_insert_new_block(state->gallivm, "loop_end");
- LLVMAddIncoming(state->counter, &next, &block, 1);
+ LLVMBuildCondBr(builder, cond, after_block, state->block);
LLVMPositionBuilderAtEnd(builder, after_block);
+
+ state->counter = LLVMBuildLoad(builder, state->counter_var, "");
+}
+
+
+void
+lp_build_loop_end(struct lp_build_loop_state *state,
+ LLVMValueRef end,
+ LLVMValueRef step)
+{
+ lp_build_loop_end_cond(state, end, step, LLVMIntNE);
}
+/**
+ * Creates a c-style for loop,
+ * contrasts lp_build_loop as this checks condition on entry
+ * e.g. for(i = start; i cmp_op end; i += step)
+ * \param state the for loop state, initialized here
+ * \param gallivm the gallivm state
+ * \param start starting value of iterator
+ * \param cmp_op comparison operator used for comparing current value with end value
+ * \param end value used to compare against iterator
+ * \param step value added to iterator at end of each loop
+ */
+void
+lp_build_for_loop_begin(struct lp_build_for_loop_state *state,
+ struct gallivm_state *gallivm,
+ LLVMValueRef start,
+ LLVMIntPredicate cmp_op,
+ LLVMValueRef end,
+ LLVMValueRef step)
+{
+ LLVMBuilderRef builder = gallivm->builder;
+
+ assert(LLVMTypeOf(start) == LLVMTypeOf(end));
+ assert(LLVMTypeOf(start) == LLVMTypeOf(step));
+
+ state->begin = lp_build_insert_new_block(gallivm, "loop_begin");
+ state->step = step;
+ state->counter_var = lp_build_alloca(gallivm, LLVMTypeOf(start), "loop_counter");
+ state->gallivm = gallivm;
+ state->cond = cmp_op;
+ state->end = end;
+
+ LLVMBuildStore(builder, start, state->counter_var);
+ LLVMBuildBr(builder, state->begin);
+
+ LLVMPositionBuilderAtEnd(builder, state->begin);
+ state->counter = LLVMBuildLoad(builder, state->counter_var, "");
+
+ state->body = lp_build_insert_new_block(gallivm, "loop_body");
+ LLVMPositionBuilderAtEnd(builder, state->body);
+}
+
+/**
+ * End the for loop.
+ */
+void
+lp_build_for_loop_end(struct lp_build_for_loop_state *state)
+{
+ LLVMValueRef next, cond;
+ LLVMBuilderRef builder = state->gallivm->builder;
+
+ next = LLVMBuildAdd(builder, state->counter, state->step, "");
+ LLVMBuildStore(builder, next, state->counter_var);
+ LLVMBuildBr(builder, state->begin);
+
+ state->exit = lp_build_insert_new_block(state->gallivm, "loop_exit");
+
+ /*
+ * We build the comparison for the begin block here,
+ * if we build it earlier the output llvm ir is not human readable
+ * as the code produced is not in the standard begin -> body -> end order.
+ */
+ LLVMPositionBuilderAtEnd(builder, state->begin);
+ cond = LLVMBuildICmp(builder, state->cond, state->counter, state->end, "");
+ LLVMBuildCondBr(builder, cond, state->body, state->exit);
+
+ LLVMPositionBuilderAtEnd(builder, state->exit);
+}
/*
Is built with:
- LLVMValueRef x = LLVMGetUndef(); // or something else
-
- flow = lp_build_flow_create(builder);
+ // x needs an alloca variable
+ x = lp_build_alloca(builder, type, "x");
- lp_build_flow_scope_begin(flow);
- // x needs a phi node
- lp_build_flow_scope_declare(flow, &x);
+ lp_build_if(ctx, builder, cond);
+ LLVMBuildStore(LLVMBuildAdd(1, 2), x);
+ lp_build_else(ctx);
+ LLVMBuildStore(LLVMBuildAdd(2, 3). 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);
-
- lp_build_flow_destroy(flow);
*/
* Begin an if/else/endif construct.
*/
void
-lp_build_if(struct lp_build_if_state *ctx,
- struct lp_build_flow_context *flow,
- LLVMBuilderRef builder,
+lp_build_if(struct lp_build_if_state *ifthen,
+ struct gallivm_state *gallivm,
LLVMValueRef condition)
{
- LLVMBasicBlockRef block = LLVMGetInsertBlock(builder);
- struct lp_build_flow_if *ifthen;
- unsigned i;
-
- memset(ctx, 0, sizeof(*ctx));
- ctx->builder = builder;
- ctx->flow = flow;
-
- /* push/create new scope */
- ifthen = &lp_build_flow_push(flow, LP_BUILD_FLOW_IF)->ifthen;
- assert(ifthen);
+ LLVMBasicBlockRef block = LLVMGetInsertBlock(gallivm->builder);
- ifthen->num_variables = flow->num_variables;
+ memset(ifthen, 0, sizeof *ifthen);
+ ifthen->gallivm = gallivm;
ifthen->condition = condition;
ifthen->entry_block = block;
- /* 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 */
- ifthen->merge_block = lp_build_insert_new_block(builder, "endif-block");
- LLVMPositionBuilderAtEnd(builder, ifthen->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]), "");
-
- /* add add the initial value of the var from the entry block */
- LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->entry_block, 1);
- }
+ ifthen->merge_block = lp_build_insert_new_block(gallivm, "endif-block");
/* create/insert true_block before merge_block */
- ifthen->true_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-true-block");
+ ifthen->true_block =
+ LLVMInsertBasicBlockInContext(gallivm->context,
+ ifthen->merge_block,
+ "if-true-block");
/* successive code goes into the true block */
- LLVMPositionBuilderAtEnd(builder, ifthen->true_block);
+ LLVMPositionBuilderAtEnd(gallivm->builder, ifthen->true_block);
}
* Begin else-part of a conditional
*/
void
-lp_build_else(struct lp_build_if_state *ctx)
+lp_build_else(struct lp_build_if_state *ifthen)
{
- struct lp_build_flow_context *flow = ctx->flow;
- struct lp_build_flow_if *ifthen;
- unsigned i;
-
- ifthen = &lp_build_flow_peek(flow, LP_BUILD_FLOW_IF)->ifthen;
- assert(ifthen);
-
- /* for each variable, update the Phi node with a (variable, block) pair */
- LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
- for (i = 0; i < flow->num_variables; i++) {
- assert(*flow->variables[i]);
- LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
- }
+ LLVMBuilderRef builder = ifthen->gallivm->builder;
+
+ /* Append an unconditional Br(anch) instruction on the true_block */
+ LLVMBuildBr(builder, ifthen->merge_block);
/* create/insert false_block before the merge block */
- ifthen->false_block = LLVMInsertBasicBlock(ifthen->merge_block, "if-false-block");
+ ifthen->false_block =
+ LLVMInsertBasicBlockInContext(ifthen->gallivm->context,
+ ifthen->merge_block,
+ "if-false-block");
/* successive code goes into the else block */
- LLVMPositionBuilderAtEnd(ctx->builder, ifthen->false_block);
+ LLVMPositionBuilderAtEnd(builder, ifthen->false_block);
}
* End a conditional.
*/
void
-lp_build_endif(struct lp_build_if_state *ctx)
+lp_build_endif(struct lp_build_if_state *ifthen)
{
- struct lp_build_flow_context *flow = ctx->flow;
- struct lp_build_flow_if *ifthen;
- unsigned i;
+ LLVMBuilderRef builder = ifthen->gallivm->builder;
- ifthen = &lp_build_flow_pop(flow, LP_BUILD_FLOW_IF)->ifthen;
- assert(ifthen);
+ /* Insert branch to the merge block from current block */
+ LLVMBuildBr(builder, ifthen->merge_block);
- if (ifthen->false_block) {
- LLVMPositionBuilderAtEnd(ctx->builder, ifthen->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], &ifthen->false_block, 1);
-
- /* replace the variable ref with the phi function */
- *flow->variables[i] = ifthen->phi[i];
- }
- }
- else {
- /* no else clause */
- LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
- for (i = 0; i < flow->num_variables; i++) {
- assert(*flow->variables[i]);
- LLVMAddIncoming(ifthen->phi[i], flow->variables[i], &ifthen->true_block, 1);
-
- /* replace the variable ref with the phi function */
- *flow->variables[i] = ifthen->phi[i];
- }
- }
-
- FREE(ifthen->phi);
-
- /***
- *** Now patch in the various branch instructions.
- ***/
+ /*
+ * Now patch in the various branch instructions.
+ */
/* Insert the conditional branch instruction at the end of entry_block */
- LLVMPositionBuilderAtEnd(ctx->builder, ifthen->entry_block);
+ LLVMPositionBuilderAtEnd(builder, ifthen->entry_block);
if (ifthen->false_block) {
/* we have an else clause */
- LLVMBuildCondBr(ctx->builder, ifthen->condition,
+ LLVMBuildCondBr(builder, ifthen->condition,
ifthen->true_block, ifthen->false_block);
}
else {
/* no else clause */
- LLVMBuildCondBr(ctx->builder, ifthen->condition,
+ LLVMBuildCondBr(builder, ifthen->condition,
ifthen->true_block, ifthen->merge_block);
}
- /* Append an unconditional Br(anch) instruction on the true_block */
- LLVMPositionBuilderAtEnd(ctx->builder, ifthen->true_block);
- LLVMBuildBr(ctx->builder, ifthen->merge_block);
- if (ifthen->false_block) {
- /* Append an unconditional Br(anch) instruction on the false_block */
- LLVMPositionBuilderAtEnd(ctx->builder, ifthen->false_block);
- LLVMBuildBr(ctx->builder, ifthen->merge_block);
+ /* Resume building code at end of the ifthen->merge_block */
+ LLVMPositionBuilderAtEnd(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(struct gallivm_state *gallivm,
+ LLVMTypeRef type,
+ const char *name)
+{
+ LLVMBuilderRef builder = gallivm->builder;
+ LLVMBasicBlockRef current_block = LLVMGetInsertBlock(builder);
+ LLVMValueRef function = LLVMGetBasicBlockParent(current_block);
+ LLVMBasicBlockRef first_block = LLVMGetEntryBasicBlock(function);
+ LLVMValueRef first_instr = LLVMGetFirstInstruction(first_block);
+ LLVMBuilderRef first_builder = LLVMCreateBuilderInContext(gallivm->context);
+ LLVMValueRef res;
+
+ if (first_instr) {
+ LLVMPositionBuilderBefore(first_builder, first_instr);
+ } else {
+ LLVMPositionBuilderAtEnd(first_builder, first_block);
}
+ res = LLVMBuildAlloca(first_builder, type, name);
+ LLVMBuildStore(builder, LLVMConstNull(type), res);
- /* Resume building code at end of the ifthen->merge_block */
- LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block);
+ 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 supposedly 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(struct gallivm_state *gallivm,
+ LLVMTypeRef type,
+ LLVMValueRef count,
+ const char *name)
+{
+ LLVMBuilderRef builder = gallivm->builder;
+ LLVMBasicBlockRef current_block = LLVMGetInsertBlock(builder);
+ LLVMValueRef function = LLVMGetBasicBlockParent(current_block);
+ LLVMBasicBlockRef first_block = LLVMGetEntryBasicBlock(function);
+ LLVMValueRef first_instr = LLVMGetFirstInstruction(first_block);
+ LLVMBuilderRef first_builder = LLVMCreateBuilderInContext(gallivm->context);
+ LLVMValueRef res;
+
+ if (first_instr) {
+ LLVMPositionBuilderBefore(first_builder, first_instr);
+ } else {
+ LLVMPositionBuilderAtEnd(first_builder, first_block);
+ }
+
+ res = LLVMBuildArrayAlloca(first_builder, type, count, name);
+
+ LLVMDisposeBuilder(first_builder);
+
+ return res;
}