/* * gen_shift * * Shifts are a little tricky, since LLVM has explicit left-shift and * right-shift instructions, which take non-negative shift values. BLISS, * on the other hand, has a single shift operator and generates right-shifts * when the RHS is negative. If the RHS is a constant, we can do the translation * here; otherwise, we have to build a conditional to check at runtime. */ static LLVMValueRef gen_shift (gencodectx_t gctx, expr_node_t *lhs, expr_node_t *rhs, LLVMTypeRef neededtype) { LLVMBuilderRef builder = gctx->curfn->builder; LLVMTypeRef inttype = gctx->fullwordtype; LLVMValueRef lval, rval, result, test; lval = (lhs == 0 ? 0 : llvmgen_expression(gctx, lhs, inttype)); if (expr_type(rhs) == EXPTYPE_PRIM_LIT) { long count = expr_litval(rhs); if (count < 0) { rval = LLVMConstInt(inttype, -count, 0); result = LLVMBuildLShr(builder, lval, rval, llvmgen_temp(gctx)); } else { rval = LLVMConstInt(inttype, count, 0); result = LLVMBuildShl(builder, lval, rval, llvmgen_temp(gctx)); } } else { LLVMBasicBlockRef exitblock = llvmgen_exitblock_create(gctx, 0); LLVMBasicBlockRef lshiftblk, rshiftblk; llvm_btrack_t *bt = llvmgen_btrack_create(gctx, exitblock); lshiftblk = LLVMInsertBasicBlockInContext(gctx->llvmctx, exitblock, llvmgen_label(gctx)); rshiftblk = LLVMInsertBasicBlockInContext(gctx->llvmctx, exitblock, llvmgen_label(gctx)); rval = llvmgen_expression(gctx, rhs, inttype); test = LLVMBuildICmp(builder, LLVMIntSLT, rval, LLVMConstNull(inttype), llvmgen_temp(gctx)); LLVMBuildCondBr(builder, test, rshiftblk, lshiftblk); LLVMPositionBuilderAtEnd(builder, lshiftblk); result = LLVMBuildShl(builder, lval, rval, llvmgen_temp(gctx)); llvmgen_btrack_update(gctx, bt, result); LLVMPositionBuilderAtEnd(builder, rshiftblk); rval = LLVMBuildNeg(builder, rval, llvmgen_temp(gctx)); result = LLVMBuildLShr(builder, lval, rval, llvmgen_temp(gctx)); llvmgen_btrack_update(gctx, bt, result); result = llvmgen_btrack_finalize(gctx, bt, inttype); } return llvmgen_adjustval(gctx, result, neededtype, 0); } /* gen_shift */
/** * Begin else-part of a conditional */ void lp_build_else(struct lp_build_if_state *ifthen) { 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 = LLVMInsertBasicBlockInContext(ifthen->gallivm->context, ifthen->merge_block, "if-false-block"); /* successive code goes into the else block */ LLVMPositionBuilderAtEnd(builder, ifthen->false_block); }
static LLVMValueRef invoke_fun(compile_t* c, LLVMValueRef fun, LLVMValueRef* args, int count, const char* ret, bool setcc) { if(fun == NULL) return NULL; LLVMBasicBlockRef this_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef then_block = LLVMInsertBasicBlockInContext(c->context, this_block, "invoke"); LLVMMoveBasicBlockAfter(then_block, this_block); LLVMBasicBlockRef else_block = c->frame->invoke_target; LLVMValueRef invoke = LLVMBuildInvoke(c->builder, fun, args, count, then_block, else_block, ret); if(setcc) LLVMSetInstructionCallConv(invoke, c->callconv); LLVMPositionBuilderAtEnd(c->builder, then_block); return invoke; }
/** * Insert a new block, right where builder is pointing to. * * 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. * * See also llvm/lib/Transforms/Scalar/BasicBlockPlacement.cpp. * * Note: this function has no dependencies on the flow code and could * be used elsewhere. */ 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(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 = LLVMInsertBasicBlockInContext(gallivm->context, next_block, name); } else { /* append new block after current block */ LLVMValueRef function = LLVMGetBasicBlockParent(current_block); new_block = LLVMAppendBasicBlockInContext(gallivm->context, function, name); } return new_block; }
/** * Begin an if/else/endif construct. */ void lp_build_if(struct lp_build_if_state *ifthen, struct gallivm_state *gallivm, LLVMValueRef condition) { LLVMBasicBlockRef block = LLVMGetInsertBlock(gallivm->builder); memset(ifthen, 0, sizeof *ifthen); ifthen->gallivm = gallivm; ifthen->condition = condition; ifthen->entry_block = block; /* create endif/merge basic block for the phi functions */ ifthen->merge_block = lp_build_insert_new_block(gallivm, "endif-block"); /* create/insert true_block before merge_block */ ifthen->true_block = LLVMInsertBasicBlockInContext(gallivm->context, ifthen->merge_block, "if-true-block"); /* successive code goes into the true block */ LLVMPositionBuilderAtEnd(gallivm->builder, ifthen->true_block); }