Path: blob/21.2-virgl/src/gallium/auxiliary/gallivm/lp_bld_flow.c
4565 views
/**************************************************************************1*2* Copyright 2009 VMware, Inc.3* All Rights Reserved.4*5* Permission is hereby granted, free of charge, to any person obtaining a6* copy of this software and associated documentation files (the7* "Software"), to deal in the Software without restriction, including8* without limitation the rights to use, copy, modify, merge, publish,9* distribute, sub license, and/or sell copies of the Software, and to10* permit persons to whom the Software is furnished to do so, subject to11* the following conditions:12*13* The above copyright notice and this permission notice (including the14* next paragraph) shall be included in all copies or substantial portions15* of the Software.16*17* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS18* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF19* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.20* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR21* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,22* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE23* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.24*25**************************************************************************/2627/**28* LLVM control flow build helpers.29*30* @author Jose Fonseca <[email protected]>31*/3233#include "util/u_debug.h"34#include "util/u_memory.h"3536#include "lp_bld_init.h"37#include "lp_bld_type.h"38#include "lp_bld_flow.h"394041/**42* Insert a new block, right where builder is pointing to.43*44* This is useful important not only for aesthetic reasons, but also for45* performance reasons, as frequently run blocks should be laid out next to46* each other and fall-throughs maximized.47*48* See also llvm/lib/Transforms/Scalar/BasicBlockPlacement.cpp.49*50* Note: this function has no dependencies on the flow code and could51* be used elsewhere.52*/53LLVMBasicBlockRef54lp_build_insert_new_block(struct gallivm_state *gallivm, const char *name)55{56LLVMBasicBlockRef current_block;57LLVMBasicBlockRef next_block;58LLVMBasicBlockRef new_block;5960/* get current basic block */61current_block = LLVMGetInsertBlock(gallivm->builder);6263/* check if there's another block after this one */64next_block = LLVMGetNextBasicBlock(current_block);65if (next_block) {66/* insert the new block before the next block */67new_block = LLVMInsertBasicBlockInContext(gallivm->context, next_block, name);68}69else {70/* append new block after current block */71LLVMValueRef function = LLVMGetBasicBlockParent(current_block);72new_block = LLVMAppendBasicBlockInContext(gallivm->context, function, name);73}7475return new_block;76}777879/**80* Begin a "skip" block. Inside this block we can test a condition and81* skip to the end of the block if the condition is false.82*/83void84lp_build_flow_skip_begin(struct lp_build_skip_context *skip,85struct gallivm_state *gallivm)86{87skip->gallivm = gallivm;88/* create new basic block */89skip->block = lp_build_insert_new_block(gallivm, "skip");90}919293/**94* Insert code to test a condition and branch to the end of the current95* skip block if the condition is true.96*/97void98lp_build_flow_skip_cond_break(struct lp_build_skip_context *skip,99LLVMValueRef cond)100{101LLVMBasicBlockRef new_block;102103new_block = lp_build_insert_new_block(skip->gallivm, "");104105/* if cond is true, goto skip->block, else goto new_block */106LLVMBuildCondBr(skip->gallivm->builder, cond, skip->block, new_block);107108LLVMPositionBuilderAtEnd(skip->gallivm->builder, new_block);109}110111112void113lp_build_flow_skip_end(struct lp_build_skip_context *skip)114{115/* goto block */116LLVMBuildBr(skip->gallivm->builder, skip->block);117LLVMPositionBuilderAtEnd(skip->gallivm->builder, skip->block);118}119120121/**122* Check if the mask predicate is zero. If so, jump to the end of the block.123*/124void125lp_build_mask_check(struct lp_build_mask_context *mask)126{127LLVMBuilderRef builder = mask->skip.gallivm->builder;128LLVMValueRef value;129LLVMValueRef cond;130131value = lp_build_mask_value(mask);132133/*134* XXX this doesn't quite generate the most efficient code possible, if135* the masks are vectors which have all bits set to the same value136* in each element.137* movmskps/pmovmskb would be more efficient to get the required value138* into ordinary reg (certainly with 8 floats).139* Not sure if llvm could figure that out on its own.140*/141142/* cond = (mask == 0) */143cond = LLVMBuildICmp(builder,144LLVMIntEQ,145LLVMBuildBitCast(builder, value, mask->reg_type, ""),146LLVMConstNull(mask->reg_type),147"");148149/* if cond, goto end of block */150lp_build_flow_skip_cond_break(&mask->skip, cond);151}152153154/**155* Begin a section of code which is predicated on a mask.156* \param mask the mask context, initialized here157* \param flow the flow context158* \param type the type of the mask159* \param value storage for the mask160*/161void162lp_build_mask_begin(struct lp_build_mask_context *mask,163struct gallivm_state *gallivm,164struct lp_type type,165LLVMValueRef value)166{167memset(mask, 0, sizeof *mask);168169mask->reg_type = LLVMIntTypeInContext(gallivm->context, type.width * type.length);170mask->var = lp_build_alloca(gallivm,171lp_build_int_vec_type(gallivm, type),172"execution_mask");173174LLVMBuildStore(gallivm->builder, value, mask->var);175176lp_build_flow_skip_begin(&mask->skip, gallivm);177}178179180LLVMValueRef181lp_build_mask_value(struct lp_build_mask_context *mask)182{183return LLVMBuildLoad(mask->skip.gallivm->builder, mask->var, "");184}185186187/**188* Update boolean mask with given value (bitwise AND).189* Typically used to update the quad's pixel alive/killed mask190* after depth testing, alpha testing, TGSI_OPCODE_KILL_IF, etc.191*/192void193lp_build_mask_update(struct lp_build_mask_context *mask,194LLVMValueRef value)195{196value = LLVMBuildAnd(mask->skip.gallivm->builder,197lp_build_mask_value(mask),198value, "");199LLVMBuildStore(mask->skip.gallivm->builder, value, mask->var);200}201202/*203* Update boolean mask with given value.204* Used for per-sample shading to force per-sample execution masks.205*/206void207lp_build_mask_force(struct lp_build_mask_context *mask,208LLVMValueRef value)209{210LLVMBuildStore(mask->skip.gallivm->builder, value, mask->var);211}212213/**214* End section of code which is predicated on a mask.215*/216LLVMValueRef217lp_build_mask_end(struct lp_build_mask_context *mask)218{219lp_build_flow_skip_end(&mask->skip);220return lp_build_mask_value(mask);221}222223224225void226lp_build_loop_begin(struct lp_build_loop_state *state,227struct gallivm_state *gallivm,228LLVMValueRef start)229230{231LLVMBuilderRef builder = gallivm->builder;232233state->block = lp_build_insert_new_block(gallivm, "loop_begin");234235state->counter_var = lp_build_alloca(gallivm, LLVMTypeOf(start), "loop_counter");236state->gallivm = gallivm;237238LLVMBuildStore(builder, start, state->counter_var);239240LLVMBuildBr(builder, state->block);241242LLVMPositionBuilderAtEnd(builder, state->block);243244state->counter = LLVMBuildLoad(builder, state->counter_var, "");245}246247248void249lp_build_loop_end_cond(struct lp_build_loop_state *state,250LLVMValueRef end,251LLVMValueRef step,252LLVMIntPredicate llvm_cond)253{254LLVMBuilderRef builder = state->gallivm->builder;255LLVMValueRef next;256LLVMValueRef cond;257LLVMBasicBlockRef after_block;258259if (!step)260step = LLVMConstInt(LLVMTypeOf(end), 1, 0);261262next = LLVMBuildAdd(builder, state->counter, step, "");263264LLVMBuildStore(builder, next, state->counter_var);265266cond = LLVMBuildICmp(builder, llvm_cond, next, end, "");267268after_block = lp_build_insert_new_block(state->gallivm, "loop_end");269270LLVMBuildCondBr(builder, cond, after_block, state->block);271272LLVMPositionBuilderAtEnd(builder, after_block);273274state->counter = LLVMBuildLoad(builder, state->counter_var, "");275}276277void278lp_build_loop_force_set_counter(struct lp_build_loop_state *state,279LLVMValueRef end)280{281LLVMBuilderRef builder = state->gallivm->builder;282LLVMBuildStore(builder, end, state->counter_var);283}284285void286lp_build_loop_force_reload_counter(struct lp_build_loop_state *state)287{288LLVMBuilderRef builder = state->gallivm->builder;289state->counter = LLVMBuildLoad(builder, state->counter_var, "");290}291292void293lp_build_loop_end(struct lp_build_loop_state *state,294LLVMValueRef end,295LLVMValueRef step)296{297lp_build_loop_end_cond(state, end, step, LLVMIntNE);298}299300/**301* Creates a c-style for loop,302* contrasts lp_build_loop as this checks condition on entry303* e.g. for(i = start; i cmp_op end; i += step)304* \param state the for loop state, initialized here305* \param gallivm the gallivm state306* \param start starting value of iterator307* \param cmp_op comparison operator used for comparing current value with end value308* \param end value used to compare against iterator309* \param step value added to iterator at end of each loop310*/311void312lp_build_for_loop_begin(struct lp_build_for_loop_state *state,313struct gallivm_state *gallivm,314LLVMValueRef start,315LLVMIntPredicate cmp_op,316LLVMValueRef end,317LLVMValueRef step)318{319LLVMBuilderRef builder = gallivm->builder;320321assert(LLVMTypeOf(start) == LLVMTypeOf(end));322assert(LLVMTypeOf(start) == LLVMTypeOf(step));323324state->begin = lp_build_insert_new_block(gallivm, "loop_begin");325state->step = step;326state->counter_var = lp_build_alloca(gallivm, LLVMTypeOf(start), "loop_counter");327state->gallivm = gallivm;328state->cond = cmp_op;329state->end = end;330331LLVMBuildStore(builder, start, state->counter_var);332LLVMBuildBr(builder, state->begin);333334LLVMPositionBuilderAtEnd(builder, state->begin);335state->counter = LLVMBuildLoad(builder, state->counter_var, "");336337state->body = lp_build_insert_new_block(gallivm, "loop_body");338LLVMPositionBuilderAtEnd(builder, state->body);339}340341/**342* End the for loop.343*/344void345lp_build_for_loop_end(struct lp_build_for_loop_state *state)346{347LLVMValueRef next, cond;348LLVMBuilderRef builder = state->gallivm->builder;349350next = LLVMBuildAdd(builder, state->counter, state->step, "");351LLVMBuildStore(builder, next, state->counter_var);352LLVMBuildBr(builder, state->begin);353354state->exit = lp_build_insert_new_block(state->gallivm, "loop_exit");355356/*357* We build the comparison for the begin block here,358* if we build it earlier the output llvm ir is not human readable359* as the code produced is not in the standard begin -> body -> end order.360*/361LLVMPositionBuilderAtEnd(builder, state->begin);362cond = LLVMBuildICmp(builder, state->cond, state->counter, state->end, "");363LLVMBuildCondBr(builder, cond, state->body, state->exit);364365LLVMPositionBuilderAtEnd(builder, state->exit);366}367368369/*370Example of if/then/else building:371372int x;373if (cond) {374x = 1 + 2;375}376else {377x = 2 + 3;378}379380Is built with:381382// x needs an alloca variable383x = lp_build_alloca(builder, type, "x");384385386lp_build_if(ctx, builder, cond);387LLVMBuildStore(LLVMBuildAdd(1, 2), x);388lp_build_else(ctx);389LLVMBuildStore(LLVMBuildAdd(2, 3). x);390lp_build_endif(ctx);391392*/393394395396/**397* Begin an if/else/endif construct.398*/399void400lp_build_if(struct lp_build_if_state *ifthen,401struct gallivm_state *gallivm,402LLVMValueRef condition)403{404LLVMBasicBlockRef block = LLVMGetInsertBlock(gallivm->builder);405406memset(ifthen, 0, sizeof *ifthen);407ifthen->gallivm = gallivm;408ifthen->condition = condition;409ifthen->entry_block = block;410411/* create endif/merge basic block for the phi functions */412ifthen->merge_block = lp_build_insert_new_block(gallivm, "endif-block");413414/* create/insert true_block before merge_block */415ifthen->true_block =416LLVMInsertBasicBlockInContext(gallivm->context,417ifthen->merge_block,418"if-true-block");419420/* successive code goes into the true block */421LLVMPositionBuilderAtEnd(gallivm->builder, ifthen->true_block);422}423424425/**426* Begin else-part of a conditional427*/428void429lp_build_else(struct lp_build_if_state *ifthen)430{431LLVMBuilderRef builder = ifthen->gallivm->builder;432433/* Append an unconditional Br(anch) instruction on the true_block */434LLVMBuildBr(builder, ifthen->merge_block);435436/* create/insert false_block before the merge block */437ifthen->false_block =438LLVMInsertBasicBlockInContext(ifthen->gallivm->context,439ifthen->merge_block,440"if-false-block");441442/* successive code goes into the else block */443LLVMPositionBuilderAtEnd(builder, ifthen->false_block);444}445446447/**448* End a conditional.449*/450void451lp_build_endif(struct lp_build_if_state *ifthen)452{453LLVMBuilderRef builder = ifthen->gallivm->builder;454455/* Insert branch to the merge block from current block */456LLVMBuildBr(builder, ifthen->merge_block);457458/*459* Now patch in the various branch instructions.460*/461462/* Insert the conditional branch instruction at the end of entry_block */463LLVMPositionBuilderAtEnd(builder, ifthen->entry_block);464if (ifthen->false_block) {465/* we have an else clause */466LLVMBuildCondBr(builder, ifthen->condition,467ifthen->true_block, ifthen->false_block);468}469else {470/* no else clause */471LLVMBuildCondBr(builder, ifthen->condition,472ifthen->true_block, ifthen->merge_block);473}474475/* Resume building code at end of the ifthen->merge_block */476LLVMPositionBuilderAtEnd(builder, ifthen->merge_block);477}478479480static LLVMBuilderRef481create_builder_at_entry(struct gallivm_state *gallivm)482{483LLVMBuilderRef builder = gallivm->builder;484LLVMBasicBlockRef current_block = LLVMGetInsertBlock(builder);485LLVMValueRef function = LLVMGetBasicBlockParent(current_block);486LLVMBasicBlockRef first_block = LLVMGetEntryBasicBlock(function);487LLVMValueRef first_instr = LLVMGetFirstInstruction(first_block);488LLVMBuilderRef first_builder = LLVMCreateBuilderInContext(gallivm->context);489490if (first_instr) {491LLVMPositionBuilderBefore(first_builder, first_instr);492} else {493LLVMPositionBuilderAtEnd(first_builder, first_block);494}495496return first_builder;497}498499500/**501* Allocate a scalar (or vector) variable.502*503* Although not strictly part of control flow, control flow has deep impact in504* how variables should be allocated.505*506* The mem2reg optimization pass is the recommended way to dealing with mutable507* variables, and SSA. It looks for allocas and if it can handle them, it508* promotes them, but only looks for alloca instructions in the entry block of509* the function. Being in the entry block guarantees that the alloca is only510* executed once, which makes analysis simpler.511*512* See also:513* - http://www.llvm.org/docs/tutorial/OCamlLangImpl7.html#memory514*/515LLVMValueRef516lp_build_alloca(struct gallivm_state *gallivm,517LLVMTypeRef type,518const char *name)519{520LLVMBuilderRef builder = gallivm->builder;521LLVMBuilderRef first_builder = create_builder_at_entry(gallivm);522LLVMValueRef res;523524res = LLVMBuildAlloca(first_builder, type, name);525LLVMBuildStore(builder, LLVMConstNull(type), res);526527LLVMDisposeBuilder(first_builder);528529return res;530}531532533/**534* Like lp_build_alloca, but do not zero-initialize the variable.535*/536LLVMValueRef537lp_build_alloca_undef(struct gallivm_state *gallivm,538LLVMTypeRef type,539const char *name)540{541LLVMBuilderRef first_builder = create_builder_at_entry(gallivm);542LLVMValueRef res;543544res = LLVMBuildAlloca(first_builder, type, name);545546LLVMDisposeBuilder(first_builder);547548return res;549}550551552/**553* Allocate an array of scalars/vectors.554*555* mem2reg pass is not capable of promoting structs or arrays to registers, but556* we still put it in the first block anyway as failure to put allocas in the557* first block may prevent the X86 backend from successfully align the stack as558* required.559*560* Also the scalarrepl pass is supposedly more powerful and can promote561* arrays in many cases.562*563* See also:564* - http://www.llvm.org/docs/tutorial/OCamlLangImpl7.html#memory565*/566LLVMValueRef567lp_build_array_alloca(struct gallivm_state *gallivm,568LLVMTypeRef type,569LLVMValueRef count,570const char *name)571{572LLVMBuilderRef first_builder = create_builder_at_entry(gallivm);573LLVMValueRef res;574575res = LLVMBuildArrayAlloca(first_builder, type, count, name);576577LLVMDisposeBuilder(first_builder);578579return res;580}581582583