static void createPushHeapFunction() { // Saving last BasicBlock; LLVMBasicBlockRef OldBB = LLVMGetInsertBlock(Builder); LLVMTypeRef ParamType = LLVMPointerType(RAType, 0); LLVMTypeRef FunctionType = LLVMFunctionType(LLVMVoidType(), &ParamType, 1, 0); LLVMValueRef Function = LLVMAddFunction(Module, "push.heap", FunctionType); LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry"); LLVMPositionBuilderAtEnd(Builder, Entry); // Function Body LLVMValueRef HeapMalloc = LLVMBuildMalloc(Builder, HeapType, "heap.malloc"); LLVMValueRef ExPtrIdx[] = { getSConstInt(0), getSConstInt(0) }; LLVMValueRef LastPtrIdx[] = { getSConstInt(0), getSConstInt(1) }; LLVMValueRef ExPtr = LLVMBuildInBoundsGEP(Builder, HeapMalloc, ExPtrIdx, 2, "heap.exec"); LLVMValueRef LastPtr = LLVMBuildInBoundsGEP(Builder, HeapMalloc, LastPtrIdx, 2, "heap.last"); LLVMBuildStore(Builder, LLVMGetParam(Function, 0), ExPtr); LLVMBuildStore(Builder, LLVMBuildLoad(Builder, HeapHead, "ld.heap.head"), LastPtr); LLVMBuildStore(Builder, HeapMalloc, HeapHead); LLVMBuildRetVoid(Builder); // Restoring last BasicBlock LLVMPositionBuilderAtEnd(Builder, OldBB); }
static LLVMTypeRef llvm_type(int type) { switch (type) { case SCM_FOREIGN_TYPE_FLOAT: return LLVMFloatType(); case SCM_FOREIGN_TYPE_DOUBLE: return LLVMDoubleType(); case SCM_FOREIGN_TYPE_BOOL: return LLVMInt1Type(); case SCM_FOREIGN_TYPE_UINT8: case SCM_FOREIGN_TYPE_INT8: return LLVMInt8Type(); case SCM_FOREIGN_TYPE_UINT16: case SCM_FOREIGN_TYPE_INT16: return LLVMInt16Type(); case SCM_FOREIGN_TYPE_UINT32: case SCM_FOREIGN_TYPE_INT32: return LLVMInt32Type(); case SCM_FOREIGN_TYPE_UINT64: case SCM_FOREIGN_TYPE_INT64: return LLVMInt64Type(); default: return LLVMVoidType(); }; }
struct vm_state * vm_state_create(const char *module_name) { struct vm_state *vm; LLVMTypeRef function_type; LLVMValueRef function_value; LLVMBasicBlockRef entry_block; vm = calloc(1, sizeof(struct vm_state)); if (vm == NULL) { fprintf(stderr, "Memory allocation request failed.\n"); exit(EXIT_FAILURE); } vm->module = LLVMModuleCreateWithName(module_name); vm->builder = LLVMCreateBuilder(); function_type = LLVMFunctionType(LLVMVoidType(), NULL, 0, 0); function_value = LLVMAddFunction(vm->module, "main", function_type); entry_block = LLVMAppendBasicBlock(function_value, "entry"); LLVMPositionBuilderAtEnd(vm->builder, entry_block); vm->symtab = symbol_table_create(); return vm; }
int main (void) { LLVMModuleRef module = LLVMModuleCreateWithName("kal"); LLVMBuilderRef builder = LLVMCreateBuilder(); // LLVMInitializeNativeTarget(); LLVMTypeRef funcType = LLVMFunctionType(LLVMVoidType(), NULL, 0, 0); LLVMValueRef func = LLVMAddFunction(module, "main", funcType); LLVMSetLinkage(func, LLVMExternalLinkage); LLVMBasicBlockRef block = LLVMAppendBasicBlock(func, "entry"); LLVMPositionBuilderAtEnd(builder, block); LLVMValueRef cond = LLVMBuildICmp(builder, LLVMIntNE, LLVMConstInt(LLVMInt32Type(), 2, 0), LLVMConstInt(LLVMInt32Type(), 1, 0), "ifcond"); LLVMValueRef owning_block = LLVMGetBasicBlockParent(LLVMGetInsertBlock(builder)); //TODO: WRONG?? //LLVMValueRef owning_block = LLVMBasicBlockAsValue(LLVMGetPreviousBasicBlock(LLVMGetInsertBlock(builder))); // 2. Generate new blocks for cases. LLVMBasicBlockRef then_ref = LLVMAppendBasicBlock(owning_block, "then"); LLVMBasicBlockRef else_ref = LLVMAppendBasicBlock(owning_block, "else"); LLVMBasicBlockRef merge_ref = LLVMAppendBasicBlock(owning_block, "ifmerge"); // 3. Branch conditionally on then or else. LLVMBuildCondBr(builder, cond, then_ref, else_ref); // 4. Build then branch prologue. LLVMPositionBuilderAtEnd(builder, then_ref); LLVMValueRef hi1 = LLVMBuildXor(builder, LLVMGetUndef(LLVMInt32Type()), LLVMGetUndef(LLVMInt32Type()), "subtmp"); // 5. Connect then branch to merge block. LLVMBuildBr(builder, merge_ref); then_ref = LLVMGetInsertBlock(builder); // 6. Build else branch prologue. LLVMPositionBuilderAtEnd(builder, else_ref); LLVMValueRef hi2 = LLVMBuildXor(builder, LLVMGetUndef(LLVMInt32Type()), LLVMGetUndef(LLVMInt32Type()), "subtmp2"); // 7. Connect else branch to merge block. LLVMBuildBr(builder, merge_ref); else_ref = LLVMGetInsertBlock(builder); // 8. Position ourselves after the merge block. LLVMPositionBuilderAtEnd(builder, merge_ref); // 9. Build the phi node. // LLVMValueRef phi = LLVMBuildPhi(builder, LLVMDoubleType(), "phi"); // 10. Add incoming edges. // LLVMAddIncoming(phi, &hi1, &then_ref, 1); // LLVMAddIncoming(phi, &hi2, &else_ref, 1); LLVMDumpModule(module); LLVMDisposeBuilder(builder); LLVMDisposeModule(module); return 0; }
static LLVMValueRef add_conv_test(LLVMModuleRef module, struct lp_type src_type, unsigned num_srcs, struct lp_type dst_type, unsigned num_dsts) { LLVMTypeRef args[2]; LLVMValueRef func; LLVMValueRef src_ptr; LLVMValueRef dst_ptr; LLVMBasicBlockRef block; LLVMBuilderRef builder; LLVMValueRef src[LP_MAX_VECTOR_LENGTH]; LLVMValueRef dst[LP_MAX_VECTOR_LENGTH]; unsigned i; args[0] = LLVMPointerType(lp_build_vec_type(src_type), 0); args[1] = LLVMPointerType(lp_build_vec_type(dst_type), 0); func = LLVMAddFunction(module, "test", LLVMFunctionType(LLVMVoidType(), args, 2, 0)); LLVMSetFunctionCallConv(func, LLVMCCallConv); src_ptr = LLVMGetParam(func, 0); dst_ptr = LLVMGetParam(func, 1); block = LLVMAppendBasicBlock(func, "entry"); builder = LLVMCreateBuilder(); LLVMPositionBuilderAtEnd(builder, block); for(i = 0; i < num_srcs; ++i) { LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0); LLVMValueRef ptr = LLVMBuildGEP(builder, src_ptr, &index, 1, ""); src[i] = LLVMBuildLoad(builder, ptr, ""); } lp_build_conv(builder, src_type, dst_type, src, num_srcs, dst, num_dsts); for(i = 0; i < num_dsts; ++i) { LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0); LLVMValueRef ptr = LLVMBuildGEP(builder, dst_ptr, &index, 1, ""); LLVMBuildStore(builder, dst[i], ptr); } LLVMBuildRetVoid(builder);; LLVMDisposeBuilder(builder); return func; }
/** * lp_build_assert. * * Build an assertion in LLVM IR by building a function call to the * lp_assert() function above. * * \param condition should be an 'i1' or 'i32' value * \param msg a string to print if the assertion fails. */ LLVMValueRef lp_build_assert(LLVMBuilderRef builder, LLVMValueRef condition, const char *msg) { LLVMModuleRef module; LLVMTypeRef arg_types[2]; LLVMValueRef msg_string, assert_func, params[2], r; module = LLVMGetGlobalParent(LLVMGetBasicBlockParent( LLVMGetInsertBlock(builder))); msg_string = lp_build_const_string_variable(module, msg, strlen(msg) + 1); arg_types[0] = LLVMInt32Type(); arg_types[1] = LLVMPointerType(LLVMInt8Type(), 0); /* lookup the lp_assert function */ assert_func = LLVMGetNamedFunction(module, "lp_assert"); /* Create the assertion function if not found */ if (!assert_func) { LLVMTypeRef func_type = LLVMFunctionType(LLVMVoidType(), arg_types, 2, 0); assert_func = LLVMAddFunction(module, "lp_assert", func_type); LLVMSetFunctionCallConv(assert_func, LLVMCCallConv); LLVMSetLinkage(assert_func, LLVMExternalLinkage); LLVMAddGlobalMapping(lp_build_engine, assert_func, func_to_pointer((func_pointer)lp_assert)); } assert(assert_func); /* build function call param list */ params[0] = LLVMBuildZExt(builder, condition, arg_types[0], ""); params[1] = LLVMBuildBitCast(builder, msg_string, arg_types[1], ""); /* check arg types */ assert(LLVMTypeOf(params[0]) == arg_types[0]); assert(LLVMTypeOf(params[1]) == arg_types[1]); r = LLVMBuildCall(builder, assert_func, params, 2, ""); return r; }
static LLVMValueRef zephir_get_add_function(zephir_context *context) { LLVMValueRef function; LLVMTypeRef arg_tys[3]; function = LLVMGetNamedFunction(context->module, "add_function"); if (!function) { arg_tys[0] = context->types.zval_pointer_type; arg_tys[1] = context->types.zval_pointer_type; arg_tys[2] = context->types.zval_pointer_type; function = LLVMAddFunction(context->module, "add_function", LLVMFunctionType(LLVMVoidType(), arg_tys, 3, 0)); if (!function) { zend_error(E_ERROR, "Cannot register add_function"); } LLVMAddGlobalMapping(context->engine, function, add_function); LLVMSetFunctionCallConv(function, LLVMCCallConv); LLVMAddFunctionAttr(function, LLVMNoUnwindAttribute); } return function; }
static void createPopHeapFunction() { // Saving last BasicBlock; LLVMBasicBlockRef OldBB = LLVMGetInsertBlock(Builder); LLVMTypeRef FunctionType = LLVMFunctionType(LLVMVoidType(), NULL, 0, 0); LLVMValueRef Function = LLVMAddFunction(Module, "pop.heap", FunctionType); LLVMBasicBlockRef Entry = LLVMAppendBasicBlock(Function, "entry"); LLVMPositionBuilderAtEnd(Builder, Entry); // Function Body LLVMValueRef HeapHdPtr = LLVMBuildLoad(Builder, HeapHead, ""); LLVMValueRef LastPtrIdx[] = { getSConstInt(0), getSConstInt(1) }; LLVMValueRef LastPtr = LLVMBuildInBoundsGEP(Builder, HeapHdPtr, LastPtrIdx, 2, "heap.last"); LLVMValueRef LastPtrLd = LLVMBuildLoad(Builder, LastPtr, "ld.heap.last"); LLVMBuildStore(Builder, LastPtrLd, HeapHead); LLVMBuildRetVoid(Builder); // Restoring last BasicBlock LLVMPositionBuilderAtEnd(Builder, OldBB); }
static LLVMValueRef add_blend_test(LLVMModuleRef module, const struct pipe_blend_state *blend, enum vector_mode mode, struct lp_type type) { LLVMTypeRef ret_type; LLVMTypeRef vec_type; LLVMTypeRef args[4]; LLVMValueRef func; LLVMValueRef src_ptr; LLVMValueRef dst_ptr; LLVMValueRef const_ptr; LLVMValueRef res_ptr; LLVMBasicBlockRef block; LLVMBuilderRef builder; ret_type = LLVMInt64Type(); vec_type = lp_build_vec_type(type); args[3] = args[2] = args[1] = args[0] = LLVMPointerType(vec_type, 0); func = LLVMAddFunction(module, "test", LLVMFunctionType(LLVMVoidType(), args, 4, 0)); LLVMSetFunctionCallConv(func, LLVMCCallConv); src_ptr = LLVMGetParam(func, 0); dst_ptr = LLVMGetParam(func, 1); const_ptr = LLVMGetParam(func, 2); res_ptr = LLVMGetParam(func, 3); block = LLVMAppendBasicBlock(func, "entry"); builder = LLVMCreateBuilder(); LLVMPositionBuilderAtEnd(builder, block); if (mode == AoS) { LLVMValueRef src; LLVMValueRef dst; LLVMValueRef con; LLVMValueRef res; src = LLVMBuildLoad(builder, src_ptr, "src"); dst = LLVMBuildLoad(builder, dst_ptr, "dst"); con = LLVMBuildLoad(builder, const_ptr, "const"); res = lp_build_blend_aos(builder, blend, type, src, dst, con, 3); lp_build_name(res, "res"); LLVMBuildStore(builder, res, res_ptr); } if (mode == SoA) { LLVMValueRef src[4]; LLVMValueRef dst[4]; LLVMValueRef con[4]; LLVMValueRef res[4]; unsigned i; for(i = 0; i < 4; ++i) { LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0); src[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, src_ptr, &index, 1, ""), ""); dst[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, dst_ptr, &index, 1, ""), ""); con[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, const_ptr, &index, 1, ""), ""); lp_build_name(src[i], "src.%c", "rgba"[i]); lp_build_name(con[i], "con.%c", "rgba"[i]); lp_build_name(dst[i], "dst.%c", "rgba"[i]); } lp_build_blend_soa(builder, blend, type, src, dst, con, res); for(i = 0; i < 4; ++i) { LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0); lp_build_name(res[i], "res.%c", "rgba"[i]); LLVMBuildStore(builder, res[i], LLVMBuildGEP(builder, res_ptr, &index, 1, "")); } } LLVMBuildRetVoid(builder);; LLVMDisposeBuilder(builder); return func; }
/** * Generate the runtime callable function for the whole fragment pipeline. * Note that the function which we generate operates on a block of 16 * pixels at at time. The block contains 2x2 quads. Each quad contains * 2x2 pixels. */ static void generate_fragment(struct llvmpipe_context *lp, struct lp_fragment_shader *shader, struct lp_fragment_shader_variant *variant, unsigned do_tri_test) { struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen); const struct lp_fragment_shader_variant_key *key = &variant->key; struct lp_type fs_type; struct lp_type blend_type; LLVMTypeRef fs_elem_type; LLVMTypeRef fs_vec_type; LLVMTypeRef fs_int_vec_type; LLVMTypeRef blend_vec_type; LLVMTypeRef blend_int_vec_type; LLVMTypeRef arg_types[14]; LLVMTypeRef func_type; LLVMTypeRef int32_vec4_type = lp_build_int32_vec4_type(); LLVMValueRef context_ptr; LLVMValueRef x; LLVMValueRef y; LLVMValueRef a0_ptr; LLVMValueRef dadx_ptr; LLVMValueRef dady_ptr; LLVMValueRef color_ptr_ptr; LLVMValueRef depth_ptr; LLVMValueRef c0, c1, c2, step0_ptr, step1_ptr, step2_ptr; LLVMBasicBlockRef block; LLVMBuilderRef builder; LLVMValueRef x0; LLVMValueRef y0; struct lp_build_sampler_soa *sampler; struct lp_build_interp_soa_context interp; LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH]; LLVMValueRef fs_out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][LP_MAX_VECTOR_LENGTH]; LLVMValueRef blend_mask; LLVMValueRef blend_in_color[NUM_CHANNELS]; LLVMValueRef function; unsigned num_fs; unsigned i; unsigned chan; unsigned cbuf; /* TODO: actually pick these based on the fs and color buffer * characteristics. */ memset(&fs_type, 0, sizeof fs_type); fs_type.floating = TRUE; /* floating point values */ fs_type.sign = TRUE; /* values are signed */ fs_type.norm = FALSE; /* values are not limited to [0,1] or [-1,1] */ fs_type.width = 32; /* 32-bit float */ fs_type.length = 4; /* 4 elements per vector */ num_fs = 4; /* number of quads per block */ memset(&blend_type, 0, sizeof blend_type); blend_type.floating = FALSE; /* values are integers */ blend_type.sign = FALSE; /* values are unsigned */ blend_type.norm = TRUE; /* values are in [0,1] or [-1,1] */ blend_type.width = 8; /* 8-bit ubyte values */ blend_type.length = 16; /* 16 elements per vector */ /* * Generate the function prototype. Any change here must be reflected in * lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa. */ fs_elem_type = lp_build_elem_type(fs_type); fs_vec_type = lp_build_vec_type(fs_type); fs_int_vec_type = lp_build_int_vec_type(fs_type); blend_vec_type = lp_build_vec_type(blend_type); blend_int_vec_type = lp_build_int_vec_type(blend_type); arg_types[0] = screen->context_ptr_type; /* context */ arg_types[1] = LLVMInt32Type(); /* x */ arg_types[2] = LLVMInt32Type(); /* y */ arg_types[3] = LLVMPointerType(fs_elem_type, 0); /* a0 */ arg_types[4] = LLVMPointerType(fs_elem_type, 0); /* dadx */ arg_types[5] = LLVMPointerType(fs_elem_type, 0); /* dady */ arg_types[6] = LLVMPointerType(LLVMPointerType(blend_vec_type, 0), 0); /* color */ arg_types[7] = LLVMPointerType(fs_int_vec_type, 0); /* depth */ arg_types[8] = LLVMInt32Type(); /* c0 */ arg_types[9] = LLVMInt32Type(); /* c1 */ arg_types[10] = LLVMInt32Type(); /* c2 */ /* Note: the step arrays are built as int32[16] but we interpret * them here as int32_vec4[4]. */ arg_types[11] = LLVMPointerType(int32_vec4_type, 0);/* step0 */ arg_types[12] = LLVMPointerType(int32_vec4_type, 0);/* step1 */ arg_types[13] = LLVMPointerType(int32_vec4_type, 0);/* step2 */ func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0); function = LLVMAddFunction(screen->module, "shader", func_type); LLVMSetFunctionCallConv(function, LLVMCCallConv); variant->function[do_tri_test] = function; /* XXX: need to propagate noalias down into color param now we are * passing a pointer-to-pointer? */ for(i = 0; i < Elements(arg_types); ++i) if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind) LLVMAddAttribute(LLVMGetParam(function, i), LLVMNoAliasAttribute); context_ptr = LLVMGetParam(function, 0); x = LLVMGetParam(function, 1); y = LLVMGetParam(function, 2); a0_ptr = LLVMGetParam(function, 3); dadx_ptr = LLVMGetParam(function, 4); dady_ptr = LLVMGetParam(function, 5); color_ptr_ptr = LLVMGetParam(function, 6); depth_ptr = LLVMGetParam(function, 7); c0 = LLVMGetParam(function, 8); c1 = LLVMGetParam(function, 9); c2 = LLVMGetParam(function, 10); step0_ptr = LLVMGetParam(function, 11); step1_ptr = LLVMGetParam(function, 12); step2_ptr = LLVMGetParam(function, 13); lp_build_name(context_ptr, "context"); lp_build_name(x, "x"); lp_build_name(y, "y"); lp_build_name(a0_ptr, "a0"); lp_build_name(dadx_ptr, "dadx"); lp_build_name(dady_ptr, "dady"); lp_build_name(color_ptr_ptr, "color_ptr"); lp_build_name(depth_ptr, "depth"); lp_build_name(c0, "c0"); lp_build_name(c1, "c1"); lp_build_name(c2, "c2"); lp_build_name(step0_ptr, "step0"); lp_build_name(step1_ptr, "step1"); lp_build_name(step2_ptr, "step2"); /* * Function body */ block = LLVMAppendBasicBlock(function, "entry"); builder = LLVMCreateBuilder(); LLVMPositionBuilderAtEnd(builder, block); generate_pos0(builder, x, y, &x0, &y0); lp_build_interp_soa_init(&interp, shader->base.tokens, key->flatshade, builder, fs_type, a0_ptr, dadx_ptr, dady_ptr, x0, y0); /* code generated texture sampling */ sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr); /* loop over quads in the block */ for(i = 0; i < num_fs; ++i) { LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0); LLVMValueRef out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS]; LLVMValueRef depth_ptr_i; int cbuf; if(i != 0) lp_build_interp_soa_update(&interp, i); depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, ""); generate_fs(lp, shader, key, builder, fs_type, context_ptr, i, &interp, sampler, &fs_mask[i], /* output */ out_color, depth_ptr_i, do_tri_test, c0, c1, c2, step0_ptr, step1_ptr, step2_ptr); for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) for(chan = 0; chan < NUM_CHANNELS; ++chan) fs_out_color[cbuf][chan][i] = out_color[cbuf][chan]; } sampler->destroy(sampler); /* Loop over color outputs / color buffers to do blending. */ for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) { LLVMValueRef color_ptr; LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), cbuf, 0); /* * Convert the fs's output color and mask to fit to the blending type. */ for(chan = 0; chan < NUM_CHANNELS; ++chan) { lp_build_conv(builder, fs_type, blend_type, fs_out_color[cbuf][chan], num_fs, &blend_in_color[chan], 1); lp_build_name(blend_in_color[chan], "color%d.%c", cbuf, "rgba"[chan]); } lp_build_conv_mask(builder, fs_type, blend_type, fs_mask, num_fs, &blend_mask, 1); color_ptr = LLVMBuildLoad(builder, LLVMBuildGEP(builder, color_ptr_ptr, &index, 1, ""), ""); lp_build_name(color_ptr, "color_ptr%d", cbuf); /* * Blending. */ generate_blend(&key->blend, builder, blend_type, context_ptr, blend_mask, blend_in_color, color_ptr); } LLVMBuildRetVoid(builder); LLVMDisposeBuilder(builder); /* Verify the LLVM IR. If invalid, dump and abort */ #ifdef DEBUG if(LLVMVerifyFunction(function, LLVMPrintMessageAction)) { if (1) LLVMDumpValue(function); abort(); } #endif /* Apply optimizations to LLVM IR */ if (1) LLVMRunFunctionPassManager(screen->pass, function); if (LP_DEBUG & DEBUG_JIT) { /* Print the LLVM IR to stderr */ LLVMDumpValue(function); debug_printf("\n"); } /* * Translate the LLVM IR into machine code. */ variant->jit_function[do_tri_test] = (lp_jit_frag_func)LLVMGetPointerToGlobal(screen->engine, function); if (LP_DEBUG & DEBUG_ASM) lp_disassemble(variant->jit_function[do_tri_test]); }
/* * Create a function that deforms a tuple of type desc up to natts columns. */ LLVMValueRef slot_compile_deform(LLVMJitContext *context, TupleDesc desc, int natts) { char *funcname; LLVMModuleRef mod; LLVMBuilderRef b; LLVMTypeRef deform_sig; LLVMValueRef v_deform_fn; LLVMBasicBlockRef b_entry; LLVMBasicBlockRef b_adjust_unavail_cols; LLVMBasicBlockRef b_find_start; LLVMBasicBlockRef b_out; LLVMBasicBlockRef b_dead; LLVMBasicBlockRef *attcheckattnoblocks; LLVMBasicBlockRef *attstartblocks; LLVMBasicBlockRef *attisnullblocks; LLVMBasicBlockRef *attcheckalignblocks; LLVMBasicBlockRef *attalignblocks; LLVMBasicBlockRef *attstoreblocks; LLVMValueRef v_offp; LLVMValueRef v_tupdata_base; LLVMValueRef v_tts_values; LLVMValueRef v_tts_nulls; LLVMValueRef v_slotoffp; LLVMValueRef v_slowp; LLVMValueRef v_nvalidp; LLVMValueRef v_nvalid; LLVMValueRef v_maxatt; LLVMValueRef v_slot; LLVMValueRef v_tupleheaderp; LLVMValueRef v_tuplep; LLVMValueRef v_infomask1; LLVMValueRef v_infomask2; LLVMValueRef v_bits; LLVMValueRef v_hoff; LLVMValueRef v_hasnulls; /* last column (0 indexed) guaranteed to exist */ int guaranteed_column_number = -1; /* current known alignment */ int known_alignment = 0; /* if true, known_alignment describes definite offset of column */ bool attguaranteedalign = true; int attnum; mod = llvm_mutable_module(context); funcname = llvm_expand_funcname(context, "deform"); /* * Check which columns do have to exist, so we don't have to check the * rows natts unnecessarily. */ for (attnum = 0; attnum < desc->natts; attnum++) { Form_pg_attribute att = TupleDescAttr(desc, attnum); /* * If the column is possibly missing, we can't rely on its (or * subsequent) NOT NULL constraints to indicate minimum attributes in * the tuple, so stop here. */ if (att->atthasmissing) break; /* * Column is NOT NULL and there've been no preceding missing columns, * it's guaranteed that all columns up to here exist at least in the * NULL bitmap. */ if (att->attnotnull) guaranteed_column_number = attnum; } /* Create the signature and function */ { LLVMTypeRef param_types[1]; param_types[0] = l_ptr(StructTupleTableSlot); deform_sig = LLVMFunctionType(LLVMVoidType(), param_types, lengthof(param_types), 0); } v_deform_fn = LLVMAddFunction(mod, funcname, deform_sig); LLVMSetLinkage(v_deform_fn, LLVMInternalLinkage); LLVMSetParamAlignment(LLVMGetParam(v_deform_fn, 0), MAXIMUM_ALIGNOF); llvm_copy_attributes(AttributeTemplate, v_deform_fn); b_entry = LLVMAppendBasicBlock(v_deform_fn, "entry"); b_adjust_unavail_cols = LLVMAppendBasicBlock(v_deform_fn, "adjust_unavail_cols"); b_find_start = LLVMAppendBasicBlock(v_deform_fn, "find_startblock"); b_out = LLVMAppendBasicBlock(v_deform_fn, "outblock"); b_dead = LLVMAppendBasicBlock(v_deform_fn, "deadblock"); b = LLVMCreateBuilder(); attcheckattnoblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attstartblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attisnullblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attcheckalignblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attalignblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); attstoreblocks = palloc(sizeof(LLVMBasicBlockRef) * natts); known_alignment = 0; LLVMPositionBuilderAtEnd(b, b_entry); /* perform allocas first, llvm only converts those to registers */ v_offp = LLVMBuildAlloca(b, TypeSizeT, "v_offp"); v_slot = LLVMGetParam(v_deform_fn, 0); v_tts_values = l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_VALUES, "tts_values"); v_tts_nulls = l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_ISNULL, "tts_ISNULL"); v_slotoffp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_OFF, ""); v_slowp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_SLOW, ""); v_nvalidp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, ""); v_tupleheaderp = l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_TUPLE, "tupleheader"); v_tuplep = l_load_struct_gep(b, v_tupleheaderp, FIELDNO_HEAPTUPLEDATA_DATA, "tuple"); v_bits = LLVMBuildBitCast(b, LLVMBuildStructGEP(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_BITS, ""), l_ptr(LLVMInt8Type()), "t_bits"); v_infomask1 = l_load_struct_gep(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK, "infomask1"); v_infomask2 = l_load_struct_gep(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_INFOMASK2, "infomask2"); /* t_infomask & HEAP_HASNULL */ v_hasnulls = LLVMBuildICmp(b, LLVMIntNE, LLVMBuildAnd(b, l_int16_const(HEAP_HASNULL), v_infomask1, ""), l_int16_const(0), "hasnulls"); /* t_infomask2 & HEAP_NATTS_MASK */ v_maxatt = LLVMBuildAnd(b, l_int16_const(HEAP_NATTS_MASK), v_infomask2, "maxatt"); v_hoff = l_load_struct_gep(b, v_tuplep, FIELDNO_HEAPTUPLEHEADERDATA_HOFF, "t_hoff"); v_tupdata_base = LLVMBuildGEP(b, LLVMBuildBitCast(b, v_tuplep, l_ptr(LLVMInt8Type()), ""), &v_hoff, 1, "v_tupdata_base"); /* * Load tuple start offset from slot. Will be reset below in case there's * no existing deformed columns in slot. */ { LLVMValueRef v_off_start; v_off_start = LLVMBuildLoad(b, v_slotoffp, "v_slot_off"); v_off_start = LLVMBuildZExt(b, v_off_start, TypeSizeT, ""); LLVMBuildStore(b, v_off_start, v_offp); } /* build the basic block for each attribute, need them as jump target */ for (attnum = 0; attnum < natts; attnum++) { attcheckattnoblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckattno", attnum); attstartblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.start", attnum); attisnullblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.attisnull", attnum); attcheckalignblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.attcheckalign", attnum); attalignblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.align", attnum); attstoreblocks[attnum] = l_bb_append_v(v_deform_fn, "block.attr.%d.store", attnum); } /* * Check if's guaranteed the all the desired attributes are available in * tuple. If so, we can start deforming. If not, need to make sure to * fetch the missing columns. */ if ((natts - 1) <= guaranteed_column_number) { /* just skip through unnecessary blocks */ LLVMBuildBr(b, b_adjust_unavail_cols); LLVMPositionBuilderAtEnd(b, b_adjust_unavail_cols); LLVMBuildBr(b, b_find_start); } else { LLVMValueRef v_params[3]; /* branch if not all columns available */ LLVMBuildCondBr(b, LLVMBuildICmp(b, LLVMIntULT, v_maxatt, l_int16_const(natts), ""), b_adjust_unavail_cols, b_find_start); /* if not, memset tts_isnull of relevant cols to true */ LLVMPositionBuilderAtEnd(b, b_adjust_unavail_cols); v_params[0] = v_slot; v_params[1] = LLVMBuildZExt(b, v_maxatt, LLVMInt32Type(), ""); v_params[2] = l_int32_const(natts); LLVMBuildCall(b, llvm_get_decl(mod, FuncSlotGetmissingattrs), v_params, lengthof(v_params), ""); LLVMBuildBr(b, b_find_start); } LLVMPositionBuilderAtEnd(b, b_find_start); v_nvalid = LLVMBuildLoad(b, v_nvalidp, ""); /* * Build switch to go from nvalid to the right startblock. Callers * currently don't have the knowledge, but it'd be good for performance to * avoid this check when it's known that the slot is empty (e.g. in scan * nodes). */ if (true) { LLVMValueRef v_switch = LLVMBuildSwitch(b, v_nvalid, b_dead, natts); for (attnum = 0; attnum < natts; attnum++) { LLVMValueRef v_attno = l_int32_const(attnum); LLVMAddCase(v_switch, v_attno, attcheckattnoblocks[attnum]); } } else { /* jump from entry block to first block */ LLVMBuildBr(b, attcheckattnoblocks[0]); } LLVMPositionBuilderAtEnd(b, b_dead); LLVMBuildUnreachable(b); /* * Iterate over each attribute that needs to be deformed, build code to * deform it. */ for (attnum = 0; attnum < natts; attnum++) { Form_pg_attribute att = TupleDescAttr(desc, attnum); LLVMValueRef v_incby; int alignto; LLVMValueRef l_attno = l_int16_const(attnum); LLVMValueRef v_attdatap; LLVMValueRef v_resultp; /* build block checking whether we did all the necessary attributes */ LLVMPositionBuilderAtEnd(b, attcheckattnoblocks[attnum]); /* * If this is the first attribute, slot->tts_nvalid was 0. Therefore * reset offset to 0 to, it be from a previous execution. */ if (attnum == 0) { LLVMBuildStore(b, l_sizet_const(0), v_offp); } /* * Build check whether column is available (i.e. whether the tuple has * that many columns stored). We can avoid the branch if we know * there's a subsequent NOT NULL column. */ if (attnum <= guaranteed_column_number) { LLVMBuildBr(b, attstartblocks[attnum]); } else { LLVMValueRef v_islast; v_islast = LLVMBuildICmp(b, LLVMIntUGE, l_attno, v_maxatt, "heap_natts"); LLVMBuildCondBr(b, v_islast, b_out, attstartblocks[attnum]); } LLVMPositionBuilderAtEnd(b, attstartblocks[attnum]); /* * Check for nulls if necessary. No need to take missing attributes * into account, because in case they're present the heaptuple's natts * would have indicated that a slot_getmissingattrs() is needed. */ if (!att->attnotnull) { LLVMBasicBlockRef b_ifnotnull; LLVMBasicBlockRef b_ifnull; LLVMBasicBlockRef b_next; LLVMValueRef v_attisnull; LLVMValueRef v_nullbyteno; LLVMValueRef v_nullbytemask; LLVMValueRef v_nullbyte; LLVMValueRef v_nullbit; b_ifnotnull = attcheckalignblocks[attnum]; b_ifnull = attisnullblocks[attnum]; if (attnum + 1 == natts) b_next = b_out; else b_next = attcheckattnoblocks[attnum + 1]; v_nullbyteno = l_int32_const(attnum >> 3); v_nullbytemask = l_int8_const(1 << ((attnum) & 0x07)); v_nullbyte = l_load_gep1(b, v_bits, v_nullbyteno, "attnullbyte"); v_nullbit = LLVMBuildICmp(b, LLVMIntEQ, LLVMBuildAnd(b, v_nullbyte, v_nullbytemask, ""), l_int8_const(0), "attisnull"); v_attisnull = LLVMBuildAnd(b, v_hasnulls, v_nullbit, ""); LLVMBuildCondBr(b, v_attisnull, b_ifnull, b_ifnotnull); LLVMPositionBuilderAtEnd(b, b_ifnull); /* store null-byte */ LLVMBuildStore(b, l_int8_const(1), LLVMBuildGEP(b, v_tts_nulls, &l_attno, 1, "")); /* store zero datum */ LLVMBuildStore(b, l_sizet_const(0), LLVMBuildGEP(b, v_tts_values, &l_attno, 1, "")); LLVMBuildBr(b, b_next); attguaranteedalign = false; } else {
/** * Generate the runtime callable function for the whole fragment pipeline. */ static struct lp_fragment_shader_variant * generate_fragment(struct llvmpipe_context *lp, struct lp_fragment_shader *shader, const struct lp_fragment_shader_variant_key *key) { struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen); struct lp_fragment_shader_variant *variant; struct lp_type fs_type; struct lp_type blend_type; LLVMTypeRef fs_elem_type; LLVMTypeRef fs_vec_type; LLVMTypeRef fs_int_vec_type; LLVMTypeRef blend_vec_type; LLVMTypeRef blend_int_vec_type; LLVMTypeRef arg_types[9]; LLVMTypeRef func_type; LLVMValueRef context_ptr; LLVMValueRef x; LLVMValueRef y; LLVMValueRef a0_ptr; LLVMValueRef dadx_ptr; LLVMValueRef dady_ptr; LLVMValueRef mask_ptr; LLVMValueRef color_ptr; LLVMValueRef depth_ptr; LLVMBasicBlockRef block; LLVMBuilderRef builder; LLVMValueRef x0; LLVMValueRef y0; struct lp_build_sampler_soa *sampler; struct lp_build_interp_soa_context interp; LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH]; LLVMValueRef fs_out_color[NUM_CHANNELS][LP_MAX_VECTOR_LENGTH]; LLVMValueRef blend_mask; LLVMValueRef blend_in_color[NUM_CHANNELS]; unsigned num_fs; unsigned i; unsigned chan; #ifdef DEBUG tgsi_dump(shader->base.tokens, 0); if(key->depth.enabled) { debug_printf("depth.format = %s\n", pf_name(key->zsbuf_format)); debug_printf("depth.func = %s\n", debug_dump_func(key->depth.func, TRUE)); debug_printf("depth.writemask = %u\n", key->depth.writemask); } if(key->alpha.enabled) { debug_printf("alpha.func = %s\n", debug_dump_func(key->alpha.func, TRUE)); debug_printf("alpha.ref_value = %f\n", key->alpha.ref_value); } if(key->blend.logicop_enable) { debug_printf("blend.logicop_func = %u\n", key->blend.logicop_func); } else if(key->blend.blend_enable) { debug_printf("blend.rgb_func = %s\n", debug_dump_blend_func (key->blend.rgb_func, TRUE)); debug_printf("rgb_src_factor = %s\n", debug_dump_blend_factor(key->blend.rgb_src_factor, TRUE)); debug_printf("rgb_dst_factor = %s\n", debug_dump_blend_factor(key->blend.rgb_dst_factor, TRUE)); debug_printf("alpha_func = %s\n", debug_dump_blend_func (key->blend.alpha_func, TRUE)); debug_printf("alpha_src_factor = %s\n", debug_dump_blend_factor(key->blend.alpha_src_factor, TRUE)); debug_printf("alpha_dst_factor = %s\n", debug_dump_blend_factor(key->blend.alpha_dst_factor, TRUE)); } debug_printf("blend.colormask = 0x%x\n", key->blend.colormask); for(i = 0; i < PIPE_MAX_SAMPLERS; ++i) { if(key->sampler[i].format) { debug_printf("sampler[%u] = \n", i); debug_printf(" .format = %s\n", pf_name(key->sampler[i].format)); debug_printf(" .target = %s\n", debug_dump_tex_target(key->sampler[i].target, TRUE)); debug_printf(" .pot = %u %u %u\n", key->sampler[i].pot_width, key->sampler[i].pot_height, key->sampler[i].pot_depth); debug_printf(" .wrap = %s %s %s\n", debug_dump_tex_wrap(key->sampler[i].wrap_s, TRUE), debug_dump_tex_wrap(key->sampler[i].wrap_t, TRUE), debug_dump_tex_wrap(key->sampler[i].wrap_r, TRUE)); debug_printf(" .min_img_filter = %s\n", debug_dump_tex_filter(key->sampler[i].min_img_filter, TRUE)); debug_printf(" .min_mip_filter = %s\n", debug_dump_tex_mipfilter(key->sampler[i].min_mip_filter, TRUE)); debug_printf(" .mag_img_filter = %s\n", debug_dump_tex_filter(key->sampler[i].mag_img_filter, TRUE)); if(key->sampler[i].compare_mode) debug_printf(" .compare_mode = %s\n", debug_dump_func(key->sampler[i].compare_func, TRUE)); debug_printf(" .normalized_coords = %u\n", key->sampler[i].normalized_coords); debug_printf(" .prefilter = %u\n", key->sampler[i].prefilter); } } #endif variant = CALLOC_STRUCT(lp_fragment_shader_variant); if(!variant) return NULL; variant->shader = shader; memcpy(&variant->key, key, sizeof *key); /* TODO: actually pick these based on the fs and color buffer * characteristics. */ memset(&fs_type, 0, sizeof fs_type); fs_type.floating = TRUE; /* floating point values */ fs_type.sign = TRUE; /* values are signed */ fs_type.norm = FALSE; /* values are not limited to [0,1] or [-1,1] */ fs_type.width = 32; /* 32-bit float */ fs_type.length = 4; /* 4 element per vector */ num_fs = 4; memset(&blend_type, 0, sizeof blend_type); blend_type.floating = FALSE; /* values are integers */ blend_type.sign = FALSE; /* values are unsigned */ blend_type.norm = TRUE; /* values are in [0,1] or [-1,1] */ blend_type.width = 8; /* 8-bit ubyte values */ blend_type.length = 16; /* 16 elements per vector */ /* * Generate the function prototype. Any change here must be reflected in * lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa. */ fs_elem_type = lp_build_elem_type(fs_type); fs_vec_type = lp_build_vec_type(fs_type); fs_int_vec_type = lp_build_int_vec_type(fs_type); blend_vec_type = lp_build_vec_type(blend_type); blend_int_vec_type = lp_build_int_vec_type(blend_type); arg_types[0] = screen->context_ptr_type; /* context */ arg_types[1] = LLVMInt32Type(); /* x */ arg_types[2] = LLVMInt32Type(); /* y */ arg_types[3] = LLVMPointerType(fs_elem_type, 0); /* a0 */ arg_types[4] = LLVMPointerType(fs_elem_type, 0); /* dadx */ arg_types[5] = LLVMPointerType(fs_elem_type, 0); /* dady */ arg_types[6] = LLVMPointerType(fs_int_vec_type, 0); /* mask */ arg_types[7] = LLVMPointerType(blend_vec_type, 0); /* color */ arg_types[8] = LLVMPointerType(fs_int_vec_type, 0); /* depth */ func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0); variant->function = LLVMAddFunction(screen->module, "shader", func_type); LLVMSetFunctionCallConv(variant->function, LLVMCCallConv); for(i = 0; i < Elements(arg_types); ++i) if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind) LLVMAddAttribute(LLVMGetParam(variant->function, i), LLVMNoAliasAttribute); context_ptr = LLVMGetParam(variant->function, 0); x = LLVMGetParam(variant->function, 1); y = LLVMGetParam(variant->function, 2); a0_ptr = LLVMGetParam(variant->function, 3); dadx_ptr = LLVMGetParam(variant->function, 4); dady_ptr = LLVMGetParam(variant->function, 5); mask_ptr = LLVMGetParam(variant->function, 6); color_ptr = LLVMGetParam(variant->function, 7); depth_ptr = LLVMGetParam(variant->function, 8); lp_build_name(context_ptr, "context"); lp_build_name(x, "x"); lp_build_name(y, "y"); lp_build_name(a0_ptr, "a0"); lp_build_name(dadx_ptr, "dadx"); lp_build_name(dady_ptr, "dady"); lp_build_name(mask_ptr, "mask"); lp_build_name(color_ptr, "color"); lp_build_name(depth_ptr, "depth"); /* * Function body */ block = LLVMAppendBasicBlock(variant->function, "entry"); builder = LLVMCreateBuilder(); LLVMPositionBuilderAtEnd(builder, block); generate_pos0(builder, x, y, &x0, &y0); lp_build_interp_soa_init(&interp, shader->base.tokens, builder, fs_type, a0_ptr, dadx_ptr, dady_ptr, x0, y0, 2, 0); #if 0 /* C texture sampling */ sampler = lp_c_sampler_soa_create(context_ptr); #else /* code generated texture sampling */ sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr); #endif for(i = 0; i < num_fs; ++i) { LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0); LLVMValueRef out_color[NUM_CHANNELS]; LLVMValueRef depth_ptr_i; if(i != 0) lp_build_interp_soa_update(&interp); fs_mask[i] = LLVMBuildLoad(builder, LLVMBuildGEP(builder, mask_ptr, &index, 1, ""), ""); depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, ""); generate_fs(lp, shader, key, builder, fs_type, context_ptr, i, &interp, sampler, &fs_mask[i], out_color, depth_ptr_i); for(chan = 0; chan < NUM_CHANNELS; ++chan) fs_out_color[chan][i] = out_color[chan]; } sampler->destroy(sampler); /* * Convert the fs's output color and mask to fit to the blending type. */ for(chan = 0; chan < NUM_CHANNELS; ++chan) { lp_build_conv(builder, fs_type, blend_type, fs_out_color[chan], num_fs, &blend_in_color[chan], 1); lp_build_name(blend_in_color[chan], "color.%c", "rgba"[chan]); } lp_build_conv_mask(builder, fs_type, blend_type, fs_mask, num_fs, &blend_mask, 1); /* * Blending. */ generate_blend(&key->blend, builder, blend_type, context_ptr, blend_mask, blend_in_color, color_ptr); LLVMBuildRetVoid(builder); LLVMDisposeBuilder(builder); /* * Translate the LLVM IR into machine code. */ if(LLVMVerifyFunction(variant->function, LLVMPrintMessageAction)) { LLVMDumpValue(variant->function); abort(); } LLVMRunFunctionPassManager(screen->pass, variant->function); #ifdef DEBUG LLVMDumpValue(variant->function); debug_printf("\n"); #endif variant->jit_function = (lp_jit_frag_func)LLVMGetPointerToGlobal(screen->engine, variant->function); #ifdef DEBUG lp_disassemble(variant->jit_function); #endif variant->next = shader->variants; shader->variants = variant; return variant; }
/** * Generate the runtime callable function for the whole fragment pipeline. * Note that the function which we generate operates on a block of 16 * pixels at at time. The block contains 2x2 quads. Each quad contains * 2x2 pixels. */ static void generate_fragment(struct llvmpipe_context *lp, struct lp_fragment_shader *shader, struct lp_fragment_shader_variant *variant, unsigned partial_mask) { struct llvmpipe_screen *screen = llvmpipe_screen(lp->pipe.screen); const struct lp_fragment_shader_variant_key *key = &variant->key; char func_name[256]; struct lp_type fs_type; struct lp_type blend_type; LLVMTypeRef fs_elem_type; LLVMTypeRef fs_int_vec_type; LLVMTypeRef blend_vec_type; LLVMTypeRef arg_types[11]; LLVMTypeRef func_type; LLVMValueRef context_ptr; LLVMValueRef x; LLVMValueRef y; LLVMValueRef a0_ptr; LLVMValueRef dadx_ptr; LLVMValueRef dady_ptr; LLVMValueRef color_ptr_ptr; LLVMValueRef depth_ptr; LLVMValueRef mask_input; LLVMValueRef counter = NULL; LLVMBasicBlockRef block; LLVMBuilderRef builder; struct lp_build_sampler_soa *sampler; struct lp_build_interp_soa_context interp; LLVMValueRef fs_mask[LP_MAX_VECTOR_LENGTH]; LLVMValueRef fs_out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS][LP_MAX_VECTOR_LENGTH]; LLVMValueRef blend_mask; LLVMValueRef function; LLVMValueRef facing; unsigned num_fs; unsigned i; unsigned chan; unsigned cbuf; /* TODO: actually pick these based on the fs and color buffer * characteristics. */ memset(&fs_type, 0, sizeof fs_type); fs_type.floating = TRUE; /* floating point values */ fs_type.sign = TRUE; /* values are signed */ fs_type.norm = FALSE; /* values are not limited to [0,1] or [-1,1] */ fs_type.width = 32; /* 32-bit float */ fs_type.length = 4; /* 4 elements per vector */ num_fs = 4; /* number of quads per block */ memset(&blend_type, 0, sizeof blend_type); blend_type.floating = FALSE; /* values are integers */ blend_type.sign = FALSE; /* values are unsigned */ blend_type.norm = TRUE; /* values are in [0,1] or [-1,1] */ blend_type.width = 8; /* 8-bit ubyte values */ blend_type.length = 16; /* 16 elements per vector */ /* * Generate the function prototype. Any change here must be reflected in * lp_jit.h's lp_jit_frag_func function pointer type, and vice-versa. */ fs_elem_type = lp_build_elem_type(fs_type); fs_int_vec_type = lp_build_int_vec_type(fs_type); blend_vec_type = lp_build_vec_type(blend_type); util_snprintf(func_name, sizeof(func_name), "fs%u_variant%u_%s", shader->no, variant->no, partial_mask ? "partial" : "whole"); arg_types[0] = screen->context_ptr_type; /* context */ arg_types[1] = LLVMInt32Type(); /* x */ arg_types[2] = LLVMInt32Type(); /* y */ arg_types[3] = LLVMFloatType(); /* facing */ arg_types[4] = LLVMPointerType(fs_elem_type, 0); /* a0 */ arg_types[5] = LLVMPointerType(fs_elem_type, 0); /* dadx */ arg_types[6] = LLVMPointerType(fs_elem_type, 0); /* dady */ arg_types[7] = LLVMPointerType(LLVMPointerType(blend_vec_type, 0), 0); /* color */ arg_types[8] = LLVMPointerType(fs_int_vec_type, 0); /* depth */ arg_types[9] = LLVMInt32Type(); /* mask_input */ arg_types[10] = LLVMPointerType(LLVMInt32Type(), 0);/* counter */ func_type = LLVMFunctionType(LLVMVoidType(), arg_types, Elements(arg_types), 0); function = LLVMAddFunction(screen->module, func_name, func_type); LLVMSetFunctionCallConv(function, LLVMCCallConv); variant->function[partial_mask] = function; /* XXX: need to propagate noalias down into color param now we are * passing a pointer-to-pointer? */ for(i = 0; i < Elements(arg_types); ++i) if(LLVMGetTypeKind(arg_types[i]) == LLVMPointerTypeKind) LLVMAddAttribute(LLVMGetParam(function, i), LLVMNoAliasAttribute); context_ptr = LLVMGetParam(function, 0); x = LLVMGetParam(function, 1); y = LLVMGetParam(function, 2); facing = LLVMGetParam(function, 3); a0_ptr = LLVMGetParam(function, 4); dadx_ptr = LLVMGetParam(function, 5); dady_ptr = LLVMGetParam(function, 6); color_ptr_ptr = LLVMGetParam(function, 7); depth_ptr = LLVMGetParam(function, 8); mask_input = LLVMGetParam(function, 9); lp_build_name(context_ptr, "context"); lp_build_name(x, "x"); lp_build_name(y, "y"); lp_build_name(a0_ptr, "a0"); lp_build_name(dadx_ptr, "dadx"); lp_build_name(dady_ptr, "dady"); lp_build_name(color_ptr_ptr, "color_ptr_ptr"); lp_build_name(depth_ptr, "depth"); lp_build_name(mask_input, "mask_input"); if (key->occlusion_count) { counter = LLVMGetParam(function, 10); lp_build_name(counter, "counter"); } /* * Function body */ block = LLVMAppendBasicBlock(function, "entry"); builder = LLVMCreateBuilder(); LLVMPositionBuilderAtEnd(builder, block); /* * The shader input interpolation info is not explicitely baked in the * shader key, but everything it derives from (TGSI, and flatshade) is * already included in the shader key. */ lp_build_interp_soa_init(&interp, lp->num_inputs, lp->inputs, builder, fs_type, a0_ptr, dadx_ptr, dady_ptr, x, y); /* code generated texture sampling */ sampler = lp_llvm_sampler_soa_create(key->sampler, context_ptr); /* loop over quads in the block */ for(i = 0; i < num_fs; ++i) { LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), i, 0); LLVMValueRef out_color[PIPE_MAX_COLOR_BUFS][NUM_CHANNELS]; LLVMValueRef depth_ptr_i; if(i != 0) lp_build_interp_soa_update(&interp, i); depth_ptr_i = LLVMBuildGEP(builder, depth_ptr, &index, 1, ""); generate_fs(lp, shader, key, builder, fs_type, context_ptr, i, &interp, sampler, &fs_mask[i], /* output */ out_color, depth_ptr_i, facing, partial_mask, mask_input, counter); for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) for(chan = 0; chan < NUM_CHANNELS; ++chan) fs_out_color[cbuf][chan][i] = out_color[cbuf][chan]; } sampler->destroy(sampler); /* Loop over color outputs / color buffers to do blending. */ for(cbuf = 0; cbuf < key->nr_cbufs; cbuf++) { LLVMValueRef color_ptr; LLVMValueRef index = LLVMConstInt(LLVMInt32Type(), cbuf, 0); LLVMValueRef blend_in_color[NUM_CHANNELS]; unsigned rt; /* * Convert the fs's output color and mask to fit to the blending type. */ for(chan = 0; chan < NUM_CHANNELS; ++chan) { lp_build_conv(builder, fs_type, blend_type, fs_out_color[cbuf][chan], num_fs, &blend_in_color[chan], 1); lp_build_name(blend_in_color[chan], "color%d.%c", cbuf, "rgba"[chan]); } if (partial_mask || !variant->opaque) { lp_build_conv_mask(builder, fs_type, blend_type, fs_mask, num_fs, &blend_mask, 1); } else { blend_mask = lp_build_const_int_vec(blend_type, ~0); } color_ptr = LLVMBuildLoad(builder, LLVMBuildGEP(builder, color_ptr_ptr, &index, 1, ""), ""); lp_build_name(color_ptr, "color_ptr%d", cbuf); /* which blend/colormask state to use */ rt = key->blend.independent_blend_enable ? cbuf : 0; /* * Blending. */ generate_blend(&key->blend, rt, builder, blend_type, context_ptr, blend_mask, blend_in_color, color_ptr); } #ifdef PIPE_ARCH_X86 /* Avoid corrupting the FPU stack on 32bit OSes. */ lp_build_intrinsic(builder, "llvm.x86.mmx.emms", LLVMVoidType(), NULL, 0); #endif LLVMBuildRetVoid(builder); LLVMDisposeBuilder(builder); /* Verify the LLVM IR. If invalid, dump and abort */ #ifdef DEBUG if(LLVMVerifyFunction(function, LLVMPrintMessageAction)) { if (1) lp_debug_dump_value(function); abort(); } #endif /* Apply optimizations to LLVM IR */ LLVMRunFunctionPassManager(screen->pass, function); if (gallivm_debug & GALLIVM_DEBUG_IR) { /* Print the LLVM IR to stderr */ lp_debug_dump_value(function); debug_printf("\n"); } /* * Translate the LLVM IR into machine code. */ { void *f = LLVMGetPointerToGlobal(screen->engine, function); variant->jit_function[partial_mask] = (lp_jit_frag_func)pointer_to_func(f); if (gallivm_debug & GALLIVM_DEBUG_ASM) { lp_disassemble(f); } lp_func_delete_body(function); } }