X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Fgallivm%2Flp_bld_flow.c;h=3bd24b4ba875b3d6a6df7b966e1122316a6fd4c2;hb=7730d583c207002e14ca2e95d30cab181db20082;hp=8f15b1d287d40076d75de1bf37405a78cebd33ab;hpb=a18c210a95794c79c6f26dbf4c66d4a85e29169d;p=mesa.git diff --git a/src/gallium/auxiliary/gallivm/lp_bld_flow.c b/src/gallium/auxiliary/gallivm/lp_bld_flow.c index 8f15b1d287d..3bd24b4ba87 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_flow.c +++ b/src/gallium/auxiliary/gallivm/lp_bld_flow.c @@ -34,352 +34,60 @@ #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. - * - * - */ -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. - * - * 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 . - * - * We keep track of variables by keeping around a pointer to where they're - * current. + * Insert a new block, right where builder is pointing to. * - * There are a few cautions to observe: + * 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. * - * - Variable's value must not be NULL. If there is no initial value then - * LLVMGetUndef() should be used. + * See also llvm/lib/Transforms/Scalar/BasicBlockPlacement.cpp. * - * - 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. */ LLVMBasicBlockRef -lp_build_insert_new_block(LLVMBuilderRef builder, const char *name) +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"); } @@ -388,81 +96,59 @@ lp_build_flow_skip_begin(struct lp_build_flow_context *flow) * 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); } @@ -475,36 +161,43 @@ lp_build_mask_check(struct lp_build_mask_context *mask) */ 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"); + + LLVMBuildStore(gallivm->builder, value, mask->var); + + lp_build_flow_skip_begin(&mask->skip, gallivm); +} - lp_build_flow_scope_begin(flow); - lp_build_flow_scope_declare(flow, &mask->value); - lp_build_flow_skip_begin(flow); - 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); } @@ -514,42 +207,42 @@ lp_build_mask_update(struct lp_build_mask_context *mask, 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; @@ -559,46 +252,109 @@ lp_build_loop_end(LLVMBuilderRef builder, 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_cond(LLVMBuilderRef builder, - LLVMValueRef end, - LLVMValueRef step, - int llvm_cond, - struct lp_build_loop_state *state) +lp_build_loop_force_set_counter(struct lp_build_loop_state *state, + LLVMValueRef end) { - LLVMBasicBlockRef block = LLVMGetInsertBlock(builder); - LLVMValueRef function = LLVMGetBasicBlockParent(block); - LLVMValueRef next; - LLVMValueRef cond; - LLVMBasicBlockRef after_block; + LLVMBuilderRef builder = state->gallivm->builder; + LLVMBuildStore(builder, end, state->counter_var); +} - if (!step) - step = LLVMConstInt(LLVMTypeOf(end), 1, 0); +void +lp_build_loop_force_reload_counter(struct lp_build_loop_state *state) +{ + LLVMBuilderRef builder = state->gallivm->builder; + state->counter = LLVMBuildLoad(builder, state->counter_var, ""); +} - next = LLVMBuildAdd(builder, state->counter, step, ""); +void +lp_build_loop_end(struct lp_build_loop_state *state, + LLVMValueRef end, + LLVMValueRef step) +{ + lp_build_loop_end_cond(state, end, step, LLVMIntNE); +} - cond = LLVMBuildICmp(builder, llvm_cond, next, end, ""); +/** + * 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; - after_block = LLVMAppendBasicBlock(function, ""); + assert(LLVMTypeOf(start) == LLVMTypeOf(end)); + assert(LLVMTypeOf(start) == LLVMTypeOf(step)); - LLVMBuildCondBr(builder, cond, after_block, state->block); + 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; - LLVMAddIncoming(state->counter, &next, &block, 1); + LLVMBuildStore(builder, start, state->counter_var); + LLVMBuildBr(builder, state->begin); - LLVMPositionBuilderAtEnd(builder, after_block); + 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); +} /* @@ -614,24 +370,16 @@ lp_build_loop_end_cond(LLVMBuilderRef builder, Is built with: - LLVMValueRef x = LLVMGetUndef(); // or something else - - flow = lp_build_flow_create(builder); - - lp_build_flow_scope_begin(flow); + // x needs an alloca variable + x = lp_build_alloca(builder, type, "x"); - // 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_else(ctx); - x = LLVMAdd(2, 3); - lp_build_endif(ctx); + 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_flow_scope_end(flow); - - lp_build_flow_destroy(flow); */ @@ -640,53 +388,28 @@ lp_build_loop_end_cond(LLVMBuilderRef builder, * 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; + LLVMBasicBlockRef block = LLVMGetInsertBlock(gallivm->builder); - /* push/create new scope */ - ifthen = &lp_build_flow_push(flow, LP_BUILD_FLOW_IF)->ifthen; - assert(ifthen); - - 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 */ - if (!LLVMIsUndef(*flow->variables[i])) - 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); } @@ -694,27 +417,21 @@ lp_build_if(struct lp_build_if_state *ctx, * 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); } @@ -722,75 +439,52 @@ lp_build_else(struct lp_build_if_state *ctx) * 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; - LLVMBasicBlockRef curBlock = LLVMGetInsertBlock(ctx->builder); - unsigned i; - - ifthen = &lp_build_flow_pop(flow, LP_BUILD_FLOW_IF)->ifthen; - assert(ifthen); + LLVMBuilderRef builder = ifthen->gallivm->builder; /* Insert branch to the merge block from current block */ - LLVMBuildBr(ctx->builder, ifthen->merge_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], &curBlock, 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); } - /* Insert branch from end of true_block to merge_block */ - if (ifthen->false_block) { - /* Append an unconditional Br(anch) instruction on the true_block */ - LLVMPositionBuilderAtEnd(ctx->builder, ifthen->true_block); - LLVMBuildBr(ctx->builder, ifthen->merge_block); - } - else { - /* No else clause. - * Note that we've already inserted the branch at the end of - * true_block. See the very first LLVMBuildBr() call in this function. - */ + /* Resume building code at end of the ifthen->merge_block */ + LLVMPositionBuilderAtEnd(builder, ifthen->merge_block); +} + + +static LLVMBuilderRef +create_builder_at_entry(struct gallivm_state *gallivm) +{ + 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); + + if (first_instr) { + LLVMPositionBuilderBefore(first_builder, first_instr); + } else { + LLVMPositionBuilderAtEnd(first_builder, first_block); } - /* Resume building code at end of the ifthen->merge_block */ - LLVMPositionBuilderAtEnd(ctx->builder, ifthen->merge_block); + return first_builder; } @@ -810,19 +504,33 @@ lp_build_endif(struct lp_build_if_state *ctx) * - http://www.llvm.org/docs/tutorial/OCamlLangImpl7.html#memory */ LLVMValueRef -lp_build_alloca(LLVMBuilderRef builder, +lp_build_alloca(struct gallivm_state *gallivm, 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(); + LLVMBuilderRef builder = gallivm->builder; + LLVMBuilderRef first_builder = create_builder_at_entry(gallivm); LLVMValueRef res; - LLVMPositionBuilderAtEnd(first_builder, first_block); - LLVMPositionBuilderBefore(first_builder, first_instr); + res = LLVMBuildAlloca(first_builder, type, name); + LLVMBuildStore(builder, LLVMConstNull(type), res); + + LLVMDisposeBuilder(first_builder); + + return res; +} + + +/** + * Like lp_build_alloca, but do not zero-initialize the variable. + */ +LLVMValueRef +lp_build_alloca_undef(struct gallivm_state *gallivm, + LLVMTypeRef type, + const char *name) +{ + LLVMBuilderRef first_builder = create_builder_at_entry(gallivm); + LLVMValueRef res; res = LLVMBuildAlloca(first_builder, type, name); @@ -840,27 +548,21 @@ lp_build_alloca(LLVMBuilderRef builder, * 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 + * 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(LLVMBuilderRef builder, +lp_build_array_alloca(struct gallivm_state *gallivm, 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(); + LLVMBuilderRef first_builder = create_builder_at_entry(gallivm); LLVMValueRef res; - LLVMPositionBuilderBefore(first_builder, first_instr); - res = LLVMBuildArrayAlloca(first_builder, type, count, name); LLVMDisposeBuilder(first_builder);