static LLVMValueRef translateArrayExpr(SymbolTable *TyTable, SymbolTable *ValTable, ASTNode *Node) { PtrVector *V = &(Node->Child); ASTNode *SizeNode = (ASTNode*) ptrVectorGet(V, 0), *InitNode = (ASTNode*) ptrVectorGet(V, 1); Type *ThisType = createType(IdTy, Node->Value); LLVMTypeRef ArrayType = getLLVMTypeFromType(TyTable, ThisType); LLVMValueRef SizeVal = translateExpr(TyTable, ValTable, SizeNode), InitVal = translateExpr(TyTable, ValTable, InitNode); LLVMValueRef ArrayVal = LLVMBuildArrayMalloc(Builder, ArrayType, SizeVal, ""); // This BasicBlock and ThisFunction LLVMBasicBlockRef ThisBB = LLVMGetInsertBlock(Builder); LLVMValueRef ThisFn = LLVMGetBasicBlockParent(ThisBB); LLVMValueRef Counter = LLVMBuildAlloca(Builder, LLVMInt32Type(), ""); LLVMBuildStore(Builder, LLVMConstInt(LLVMInt32Type(), 0, 1), Counter); LLVMTargetDataRef DataRef = LLVMCreateTargetData(LLVMGetDataLayout(Module)); unsigned long long Size = LLVMStoreSizeOfType(DataRef, ArrayType); LLVMBasicBlockRef InitBB, MidBB, EndBB; InitBB = LLVMAppendBasicBlock(ThisFn, "for.init"); EndBB = LLVMAppendBasicBlock(ThisFn, "for.end"); MidBB = LLVMAppendBasicBlock(ThisFn, "for.mid"); LLVMBuildBr(Builder, InitBB); LLVMPositionBuilderAtEnd(Builder, InitBB); LLVMValueRef CurrentCounter = LLVMBuildLoad(Builder, Counter, ""); LLVMValueRef Comparation = LLVMBuildICmp(Builder, LLVMIntSLT, CurrentCounter, SizeVal, ""); LLVMBuildCondBr(Builder, Comparation, MidBB, EndBB); LLVMPositionBuilderAtEnd(Builder, MidBB); CurrentCounter = LLVMBuildLoad(Builder, Counter, ""); LLVMValueRef TheValue = LLVMBuildLoad(Builder, InitVal, ""); LLVMValueRef ElemIdx[] = { LLVMConstInt(LLVMInt32Type(), 0, 1), CurrentCounter }; LLVMValueRef Elem = LLVMBuildInBoundsGEP(Builder, ArrayVal, ElemIdx, 2, ""); copyMemory(Elem, TheValue, getSConstInt(Size)); LLVMBuildBr(Builder, InitBB); LLVMPositionBuilderAtEnd(Builder, EndBB); return ArrayVal; }
static void set_descriptor(compile_t* c, reach_type_t* t, LLVMValueRef value) { if(t->underlying == TK_STRUCT) return; LLVMValueRef desc_ptr = LLVMBuildStructGEP(c->builder, value, 0, ""); LLVMValueRef store = LLVMBuildStore(c->builder, ((compile_type_t*)t->c_type)->desc, desc_ptr); #if PONY_LLVM >= 400 tbaa_tag(c, c->tbaa_descptr, store); #else const char id[] = "tbaa"; LLVMSetMetadata(store, LLVMGetMDKindID(id, sizeof(id) - 1), c->tbaa_descptr); #endif }
static LLVMValueRef assign_one(compile_t* c, LLVMValueRef l_value, LLVMValueRef r_value, ast_t* r_type) { LLVMValueRef result = LLVMBuildLoad(c->builder, l_value, ""); // Cast the rvalue appropriately. LLVMTypeRef l_type = LLVMGetElementType(LLVMTypeOf(l_value)); LLVMValueRef cast_value = gen_assign_cast(c, l_type, r_value, r_type); if(cast_value == NULL) return NULL; // Store to the field. LLVMBuildStore(c->builder, cast_value, l_value); return result; }
/** * Allocate a scalar (or vector) variable. * * Although not strictly part of control flow, control flow has deep impact in * how variables should be allocated. * * The mem2reg optimization pass is the recommended way to dealing with mutable * variables, and SSA. It looks for allocas and if it can handle them, it * promotes them, but only looks for alloca instructions in the entry block of * the function. Being in the entry block guarantees that the alloca is only * executed once, which makes analysis simpler. * * See also: * - http://www.llvm.org/docs/tutorial/OCamlLangImpl7.html#memory */ LLVMValueRef lp_build_alloca(struct gallivm_state *gallivm, LLVMTypeRef type, const char *name) { LLVMBuilderRef builder = gallivm->builder; LLVMBuilderRef first_builder = create_builder_at_entry(gallivm); LLVMValueRef res; res = LLVMBuildAlloca(first_builder, type, name); LLVMBuildStore(builder, LLVMConstNull(type), res); LLVMDisposeBuilder(first_builder); return res; }
LLVMValueRef gencall_allocstruct(compile_t* c, gentype_t* g) { // Disable debug anchor dwarf_location(&c->dwarf, NULL); // We explicitly want a boxed version. // Get the size of the structure. size_t size = (size_t)LLVMABISizeOfType(c->target_data, g->structure); // Get the finaliser, if there is one. const char* final = genname_finalise(g->type_name); LLVMValueRef final_fun = LLVMGetNamedFunction(c->module, final); // Allocate the object. LLVMValueRef args[3]; args[0] = codegen_ctx(c); LLVMValueRef result; if(final_fun == NULL) { if(size <= HEAP_MAX) { uint32_t index = ponyint_heap_index(size); args[1] = LLVMConstInt(c->i32, index, false); result = gencall_runtime(c, "pony_alloc_small", args, 2, ""); } else { args[1] = LLVMConstInt(c->intptr, size, false); result = gencall_runtime(c, "pony_alloc_large", args, 2, ""); } } else { args[1] = LLVMConstInt(c->intptr, size, false); args[2] = LLVMConstBitCast(final_fun, c->final_fn); result = gencall_runtime(c, "pony_alloc_final", args, 3, ""); } result = LLVMBuildBitCast(c->builder, result, g->structure_ptr, ""); // Set the descriptor. if(g->underlying != TK_STRUCT) { LLVMValueRef desc_ptr = LLVMBuildStructGEP(c->builder, result, 0, ""); LLVMBuildStore(c->builder, g->desc, desc_ptr); } return result; }
/** * Begin a section of code which is predicated on a mask. * \param mask the mask context, initialized here * \param flow the flow context * \param type the type of the mask * \param value storage for the mask */ void lp_build_mask_begin(struct lp_build_mask_context *mask, struct gallivm_state *gallivm, struct lp_type type, LLVMValueRef value) { memset(mask, 0, sizeof *mask); 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); }
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; }
TGSI_FOR_EACH_DST0_ENABLED_CHANNEL( inst, chan_index ) { LLVMValueRef value = dst[chan_index]; if (inst->Instruction.Saturate != TGSI_SAT_NONE) { struct lp_build_emit_data clamp_emit_data; memset(&clamp_emit_data, 0, sizeof(clamp_emit_data)); clamp_emit_data.arg_count = 3; clamp_emit_data.args[0] = value; clamp_emit_data.args[2] = base.one; switch(inst->Instruction.Saturate) { case TGSI_SAT_ZERO_ONE: clamp_emit_data.args[1] = base.zero; break; case TGSI_SAT_MINUS_PLUS_ONE: clamp_emit_data.args[1] = LLVMConstReal( base.elem_type, -1.0f); break; default: assert(0); } value = lp_build_emit_llvm(bld_base, TGSI_OPCODE_CLAMP, &clamp_emit_data); } switch(reg->Register.File) { case TGSI_FILE_OUTPUT: temp_ptr = bld->outputs[reg->Register.Index][chan_index]; break; case TGSI_FILE_TEMPORARY: temp_ptr = lp_get_temp_ptr_soa(bld, reg->Register.Index, chan_index); break; default: return; } value = bitcast(bld_base, TGSI_TYPE_FLOAT, value); LLVMBuildStore(builder, value, temp_ptr); }
static void update_cache_access(struct gallivm_state *gallivm, LLVMValueRef ptr, unsigned count, unsigned index) { LLVMBuilderRef builder = gallivm->builder; LLVMValueRef member_ptr, cache_access; assert(index == LP_BUILD_FORMAT_CACHE_MEMBER_ACCESS_TOTAL || index == LP_BUILD_FORMAT_CACHE_MEMBER_ACCESS_MISS); member_ptr = lp_build_struct_get_ptr(gallivm, ptr, index, ""); cache_access = LLVMBuildLoad(builder, member_ptr, "cache_access"); cache_access = LLVMBuildAdd(builder, cache_access, LLVMConstInt(LLVMInt64TypeInContext(gallivm->context), count, 0), ""); LLVMBuildStore(builder, cache_access, member_ptr); }
LLVMValueRef gen_init(struct node *ast) { LLVMValueRef var, array; char *name; int size; name = ast->one->val; var = LLVMBuildAlloca(builder, TYPE_INT, name); if (ast->two) { size = LLVMConstIntGetZExtValue(codegen(ast->two)); array = LLVMBuildAlloca(builder, TYPE_ARRAY(size), ""); LLVMBuildStore(builder, lvalue_to_rvalue(array), var); } symtab_enter(name, var); return NULL; }
// Generates the allocas for the function arguments. This has to be called // from the block since that is where the entry block is created. // // node - The function node. // module - The compilation unit this node is a part of. // // Returns 0 if successful, otherwise returns -1. int qip_ast_function_codegen_args(qip_ast_node *node, qip_module *module) { int rc; unsigned int i; check(node != NULL, "Node required"); check(node->type == QIP_AST_TYPE_FUNCTION, "Node type expected to be 'function'"); check(module != NULL, "Module required"); LLVMBuilderRef builder = module->compiler->llvm_builder; LLVMContextRef context = LLVMGetModuleContext(module->llvm_module); // Retrieve current function scope. qip_scope *scope = NULL; rc = qip_module_get_current_function_scope(module, &scope); check(rc == 0 && scope != NULL, "Unable to retrieve current function scope"); // Codegen allocas. LLVMValueRef *values = malloc(sizeof(LLVMValueRef) * node->function.arg_count); check_mem(values); for(i=0; i<node->function.arg_count; i++) { rc = qip_ast_node_codegen(node->function.args[i], module, &values[i]); check(rc == 0, "Unable to determine function argument type"); } scope->llvm_last_alloca = LLVMBuildAlloca(builder, LLVMInt1TypeInContext(context), "nop"); // Codegen store instructions. for(i=0; i<node->function.arg_count; i++) { LLVMValueRef param = LLVMGetParam(scope->llvm_function, i); LLVMValueRef build_value = LLVMBuildStore(builder, param, values[i]); check(build_value != NULL, "Unable to create store instruction"); } free(values); return 0; error: if(values) free(values); return -1; }
LLVMValueRef gen_return(struct node *ast) { LLVMValueRef func, retval; LLVMBasicBlockRef next_block, ret_block; ret_block = symtab_find(".return"); retval = symtab_find(".retval"); if (ast->one) LLVMBuildStore(builder, codegen(ast->one), retval); LLVMBuildBr(builder, ret_block); func = LLVMGetBasicBlockParent(LLVMGetInsertBlock(builder)); next_block = LLVMAppendBasicBlock(func, ""); LLVMPositionBuilderAtEnd(builder, next_block);; return NULL; }
void lp_build_loop_begin(struct lp_build_loop_state *state, struct gallivm_state *gallivm, LLVMValueRef start) { LLVMBuilderRef builder = gallivm->builder; state->block = lp_build_insert_new_block(gallivm, "loop_begin"); state->counter_var = lp_build_alloca(gallivm, LLVMTypeOf(start), "loop_counter"); state->gallivm = gallivm; LLVMBuildStore(builder, start, state->counter_var); LLVMBuildBr(builder, state->block); LLVMPositionBuilderAtEnd(builder, state->block); state->counter = LLVMBuildLoad(builder, state->counter_var, ""); }
LLVMValueRef gen_names(struct node *ast) { LLVMValueRef func, pam, var; char *name; func = LLVMGetBasicBlockParent(LLVMGetInsertBlock(builder)); /* Pam param, pam pam param... */ for (pam = LLVMGetLastParam(func); pam; pam = LLVMGetPreviousParam(pam)) { name = ast->one->val; var = LLVMBuildAlloca(builder, TYPE_INT, name); symtab_enter(name, var); LLVMBuildStore(builder, pam, var); ast = ast->two; } return NULL; }
static void pointer_update(compile_t* c, reach_type_t* t, reach_type_t* t_elem) { FIND_METHOD("_update"); LLVMTypeRef params[3]; params[0] = t->use_type; params[1] = c->intptr; params[2] = t_elem->use_type; start_function(c, m, t_elem->use_type, params, 3); LLVMValueRef ptr = LLVMGetParam(m->func, 0); LLVMValueRef index = LLVMGetParam(m->func, 1); LLVMValueRef elem_ptr = LLVMBuildBitCast(c->builder, ptr, LLVMPointerType(t_elem->use_type, 0), ""); LLVMValueRef loc = LLVMBuildGEP(c->builder, elem_ptr, &index, 1, ""); LLVMValueRef result = LLVMBuildLoad(c->builder, loc, ""); LLVMBuildStore(c->builder, LLVMGetParam(m->func, 2), loc); LLVMBuildRet(c->builder, result); codegen_finishfun(c); }
static LLVMValueRef assign_field(compile_t* c, LLVMValueRef l_value, LLVMValueRef r_value, ast_t* p_type, ast_t* r_type) { LLVMValueRef result = LLVMBuildLoad(c->builder, l_value, ""); // Cast the rvalue appropriately. LLVMTypeRef cast_type = LLVMGetElementType(LLVMTypeOf(l_value)); LLVMValueRef cast_value = gen_assign_cast(c, cast_type, r_value, r_type); if(cast_value == NULL) return NULL; // Store to the field. LLVMValueRef store = LLVMBuildStore(c->builder, cast_value, l_value); LLVMValueRef metadata = tbaa_metadata_for_type(c, p_type); const char id[] = "tbaa"; LLVMSetMetadata(result, LLVMGetMDKindID(id, sizeof(id) - 1), metadata); LLVMSetMetadata(store, LLVMGetMDKindID(id, sizeof(id) - 1), metadata); return result; }
/* * Build LLVM function that exercises the unary operator builder. */ static LLVMValueRef build_unary_test_func(struct gallivm_state *gallivm, const struct unary_test_t *test) { struct lp_type type = lp_type_float_vec(32, lp_native_vector_width); LLVMContextRef context = gallivm->context; LLVMModuleRef module = gallivm->module; LLVMTypeRef vf32t = lp_build_vec_type(gallivm, type); LLVMTypeRef args[2] = { LLVMPointerType(vf32t, 0), LLVMPointerType(vf32t, 0) }; LLVMValueRef func = LLVMAddFunction(module, test->name, LLVMFunctionType(LLVMVoidTypeInContext(context), args, Elements(args), 0)); LLVMValueRef arg0 = LLVMGetParam(func, 0); LLVMValueRef arg1 = LLVMGetParam(func, 1); LLVMBuilderRef builder = gallivm->builder; LLVMBasicBlockRef block = LLVMAppendBasicBlockInContext(context, func, "entry"); LLVMValueRef ret; struct lp_build_context bld; lp_build_context_init(&bld, gallivm, type); LLVMSetFunctionCallConv(func, LLVMCCallConv); LLVMPositionBuilderAtEnd(builder, block); arg1 = LLVMBuildLoad(builder, arg1, ""); ret = test->builder(&bld, arg1); LLVMBuildStore(builder, ret, arg0); LLVMBuildRetVoid(builder); gallivm_verify_function(gallivm, func); return func; }
/** * 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); }
/** * Perform the occlusion test and increase the counter. * Test the depth mask. Add the number of channel which has none zero mask * into the occlusion counter. e.g. maskvalue is {-1, -1, -1, -1}. * The counter will add 4. * * \param type holds element type of the mask vector. * \param maskvalue is the depth test mask. * \param counter is a pointer of the uint32 counter. */ static void lp_build_occlusion_count(LLVMBuilderRef builder, struct lp_type type, LLVMValueRef maskvalue, LLVMValueRef counter) { LLVMValueRef countmask = lp_build_const_int_vec(type, 1); LLVMValueRef countv = LLVMBuildAnd(builder, maskvalue, countmask, "countv"); LLVMTypeRef i8v16 = LLVMVectorType(LLVMInt8Type(), 16); LLVMValueRef counti = LLVMBuildBitCast(builder, countv, i8v16, "counti"); LLVMValueRef maskarray[4] = { LLVMConstInt(LLVMInt32Type(), 0, 0), LLVMConstInt(LLVMInt32Type(), 4, 0), LLVMConstInt(LLVMInt32Type(), 8, 0), LLVMConstInt(LLVMInt32Type(), 12, 0), }; LLVMValueRef shufflemask = LLVMConstVector(maskarray, 4); LLVMValueRef shufflev = LLVMBuildShuffleVector(builder, counti, LLVMGetUndef(i8v16), shufflemask, "shufflev"); LLVMValueRef shuffle = LLVMBuildBitCast(builder, shufflev, LLVMInt32Type(), "shuffle"); LLVMValueRef count = lp_build_intrinsic_unary(builder, "llvm.ctpop.i32", LLVMInt32Type(), shuffle); LLVMValueRef orig = LLVMBuildLoad(builder, counter, "orig"); LLVMValueRef incr = LLVMBuildAdd(builder, orig, count, "incr"); LLVMBuildStore(builder, incr, counter); }
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); }
LLVMValueRef encode_packed_struct_inline( struct llvm_ctx *ctx, LLVMValueRef first_mr_word, LLVMValueRef bit_offset, IDL_tree ctyp, LLVMValueRef src_base) { const struct packed_format *fmt = packed_format_of(ctyp); assert(fmt != NULL); /* for sub-word items, bit_offset is required. for word and larger ones it * is forbidden. */ assert(bit_offset == NULL || (fmt->num_bits < BITS_PER_WORD && fmt->num_words == 1)); assert(bit_offset != NULL || fmt->num_bits >= BITS_PER_WORD); char **names = NULL; T s_type = llvm_struct_type(ctx, &names, ctyp); int names_len = 0; while(names[names_len] != NULL) names_len++; assert(names_len == fmt->num_items); assert(LLVMCountStructElementTypes(s_type) == names_len); T types[MAX(names_len, 1)]; LLVMGetStructElementTypes(s_type, types); V wordval = CONST_WORD(0); int cur_word = 0, wordval_fill = 0; for(int i=0; i<fmt->num_items; i++) { assert(wordval_fill <= BITS_PER_WORD); const struct packed_item *pi = fmt->items[i]; assert(bit_offset == NULL || pi->word == 0); int field_ix = strv_lookup(names, pi->name); if(field_ix < 0) { fprintf(stderr, "%s: not the way to go.\n", __func__); abort(); } V start_mr = NULL; if(bit_offset == NULL) { start_mr = LLVMBuildAdd(ctx->builder, first_mr_word, CONST_INT(pi->word), "word.ix"); } /* flush previous word? */ if(wordval_fill > 0 && cur_word != pi->word) { assert(bit_offset == NULL); V mr_ix = LLVMBuildAdd(ctx->builder, first_mr_word, CONST_INT(cur_word), tmp_f(ctx->pr, "flush.w%d.ix", cur_word)); LLVMBuildStore(ctx->builder, wordval, UTCB_ADDR_VAL(ctx, mr_ix, tmp_f(ctx->pr, "flush.w%d.addr", cur_word))); wordval = CONST_WORD(0); wordval_fill = 0; cur_word = pi->word; } V valptr = LLVMBuildStructGEP(ctx->builder, src_base, field_ix, tmp_f(ctx->pr, "%s.start.ptr", pi->name)); if(pi->dim > 1) { /* array types. TODO */ fprintf(stderr, "%s: struct-member arrays not implemented\n", __func__); abort(); } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_STRUCT) { if(pi->len < BITS_PER_WORD) { wordval = encode_packed_struct(ctx, wordval, CONST_INT(pi->bit), pi->type, valptr); wordval_fill = (wordval_fill + pi->len) % BITS_PER_WORD; } else { encode_packed_struct(ctx, start_mr, NULL, pi->type, valptr); } } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_UNION) { fprintf(stderr, "%s: union-member types not implemented\n", __func__); abort(); } else if(IS_LONGLONG_TYPE(pi->type)) { assert(bit_offset == NULL); assert(pi->bit == 0 && wordval_fill == 0); V val = LLVMBuildLoad(ctx->builder, valptr, "longlong.fld"); build_write_ipc_parameter(ctx, start_mr, pi->type, &val); } else if(is_value_type(pi->type)) { /* word-size and smaller items. */ V val = LLVMBuildLoad(ctx->builder, valptr, tmp_f(ctx->pr, "fld.%s.val", pi->name)); val = LLVMBuildZExtOrBitCast(ctx->builder, val, ctx->wordt, tmp_f(ctx->pr, "fld.%s.word", pi->name)); V bitoffs = CONST_INT(pi->bit); V shifted = LLVMBuildShl(ctx->builder, val, bitoffs, tmp_f(ctx->pr, "fld.%s.shifted", pi->name)); wordval = LLVMBuildOr(ctx->builder, shifted, wordval, tmp_f(ctx->pr, "word%d.%s.merged", cur_word, pi->name)); wordval_fill += pi->len; } else if(IS_MAPGRANT_TYPE(pi->type)) { assert(bit_offset == NULL); assert(pi->bit == 0 && wordval_fill == 0); build_write_ipc_parameter(ctx, start_mr, pi->type, &valptr); } else { NOTDEFINED(pi->type); } } if(bit_offset == NULL && wordval_fill > 0) { /* flush final partial word if the last item was sub-word */ V mr_ix = LLVMBuildAdd(ctx->builder, first_mr_word, CONST_INT(cur_word), tmp_f(ctx->pr, "flush.w%d.ix", cur_word)); LLVMBuildStore(ctx->builder, wordval, UTCB_ADDR_VAL(ctx, mr_ix, tmp_f(ctx->pr, "flush.w%d.addr", cur_word))); wordval = NULL; } else if(bit_offset != NULL) { /* shift and merge */ wordval = LLVMBuildOr(ctx->builder, first_mr_word, LLVMBuildShl(ctx->builder, wordval, bit_offset, "short.shifted"), "rv.merged"); } g_strfreev(names); return wordval; }
static bool gen_field_init(compile_t* c, gentype_t* g) { LLVMValueRef this_ptr = LLVMGetParam(codegen_fun(c), 0); ast_t* def = (ast_t*)ast_data(g->ast); ast_t* members = ast_childidx(def, 4); ast_t* member = ast_child(members); // Struct index of the current field. int index = 1; if(ast_id(def) == TK_ACTOR) index++; // Iterate through all fields. while(member != NULL) { switch(ast_id(member)) { case TK_FVAR: case TK_FLET: { // Skip this field if it has no initialiser. AST_GET_CHILDREN(member, id, type, body); if(ast_id(body) != TK_NONE) { // Reify the initialiser. ast_t* this_type = set_cap_and_ephemeral(g->ast, TK_REF, TK_NONE); ast_t* var = lookup(NULL, NULL, this_type, ast_name(id)); ast_free_unattached(this_type); assert(var != NULL); body = ast_childidx(var, 2); // Get the field pointer. dwarf_location(&c->dwarf, body); LLVMValueRef l_value = LLVMBuildStructGEP(c->builder, this_ptr, index, ""); // Cast the initialiser to the field type. LLVMValueRef r_value = gen_expr(c, body); if(r_value == NULL) return false; LLVMTypeRef l_type = LLVMGetElementType(LLVMTypeOf(l_value)); LLVMValueRef cast_value = gen_assign_cast(c, l_type, r_value, ast_type(body)); if(cast_value == NULL) return false; // Store the result. LLVMBuildStore(c->builder, cast_value, l_value); } index++; break; } default: {} } member = ast_sibling(member); } return true; }
/** * Generate code to do cube face selection and compute per-face texcoords. */ void lp_build_cube_lookup(struct lp_build_sample_context *bld, LLVMValueRef s, LLVMValueRef t, LLVMValueRef r, LLVMValueRef *face, LLVMValueRef *face_s, LLVMValueRef *face_t) { struct lp_build_context *float_bld = &bld->float_bld; struct lp_build_context *coord_bld = &bld->coord_bld; LLVMBuilderRef builder = bld->gallivm->builder; LLVMValueRef rx, ry, rz; LLVMValueRef arx, ary, arz; LLVMValueRef c25 = lp_build_const_float(bld->gallivm, 0.25); LLVMValueRef arx_ge_ary, arx_ge_arz; LLVMValueRef ary_ge_arx, ary_ge_arz; LLVMValueRef arx_ge_ary_arz, ary_ge_arx_arz; assert(bld->coord_bld.type.length == 4); /* * Use the average of the four pixel's texcoords to choose the face. */ rx = lp_build_mul(float_bld, c25, lp_build_sum_vector(&bld->coord_bld, s)); ry = lp_build_mul(float_bld, c25, lp_build_sum_vector(&bld->coord_bld, t)); rz = lp_build_mul(float_bld, c25, lp_build_sum_vector(&bld->coord_bld, r)); arx = lp_build_abs(float_bld, rx); ary = lp_build_abs(float_bld, ry); arz = lp_build_abs(float_bld, rz); /* * Compare sign/magnitude of rx,ry,rz to determine face */ arx_ge_ary = LLVMBuildFCmp(builder, LLVMRealUGE, arx, ary, ""); arx_ge_arz = LLVMBuildFCmp(builder, LLVMRealUGE, arx, arz, ""); ary_ge_arx = LLVMBuildFCmp(builder, LLVMRealUGE, ary, arx, ""); ary_ge_arz = LLVMBuildFCmp(builder, LLVMRealUGE, ary, arz, ""); arx_ge_ary_arz = LLVMBuildAnd(builder, arx_ge_ary, arx_ge_arz, ""); ary_ge_arx_arz = LLVMBuildAnd(builder, ary_ge_arx, ary_ge_arz, ""); { struct lp_build_if_state if_ctx; LLVMValueRef face_s_var; LLVMValueRef face_t_var; LLVMValueRef face_var; face_s_var = lp_build_alloca(bld->gallivm, bld->coord_bld.vec_type, "face_s_var"); face_t_var = lp_build_alloca(bld->gallivm, bld->coord_bld.vec_type, "face_t_var"); face_var = lp_build_alloca(bld->gallivm, bld->int_bld.vec_type, "face_var"); lp_build_if(&if_ctx, bld->gallivm, arx_ge_ary_arz); { /* +/- X face */ LLVMValueRef sign = lp_build_sgn(float_bld, rx); LLVMValueRef ima = lp_build_cube_ima(coord_bld, s); *face_s = lp_build_cube_coord(coord_bld, sign, +1, r, ima); *face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima); *face = lp_build_cube_face(bld, rx, PIPE_TEX_FACE_POS_X, PIPE_TEX_FACE_NEG_X); LLVMBuildStore(builder, *face_s, face_s_var); LLVMBuildStore(builder, *face_t, face_t_var); LLVMBuildStore(builder, *face, face_var); } lp_build_else(&if_ctx); { struct lp_build_if_state if_ctx2; lp_build_if(&if_ctx2, bld->gallivm, ary_ge_arx_arz); { /* +/- Y face */ LLVMValueRef sign = lp_build_sgn(float_bld, ry); LLVMValueRef ima = lp_build_cube_ima(coord_bld, t); *face_s = lp_build_cube_coord(coord_bld, NULL, -1, s, ima); *face_t = lp_build_cube_coord(coord_bld, sign, -1, r, ima); *face = lp_build_cube_face(bld, ry, PIPE_TEX_FACE_POS_Y, PIPE_TEX_FACE_NEG_Y); LLVMBuildStore(builder, *face_s, face_s_var); LLVMBuildStore(builder, *face_t, face_t_var); LLVMBuildStore(builder, *face, face_var); } lp_build_else(&if_ctx2); { /* +/- Z face */ LLVMValueRef sign = lp_build_sgn(float_bld, rz); LLVMValueRef ima = lp_build_cube_ima(coord_bld, r); *face_s = lp_build_cube_coord(coord_bld, sign, -1, s, ima); *face_t = lp_build_cube_coord(coord_bld, NULL, +1, t, ima); *face = lp_build_cube_face(bld, rz, PIPE_TEX_FACE_POS_Z, PIPE_TEX_FACE_NEG_Z); LLVMBuildStore(builder, *face_s, face_s_var); LLVMBuildStore(builder, *face_t, face_t_var); LLVMBuildStore(builder, *face, face_var); } lp_build_endif(&if_ctx2); } lp_build_endif(&if_ctx); *face_s = LLVMBuildLoad(builder, face_s_var, "face_s"); *face_t = LLVMBuildLoad(builder, face_t_var, "face_t"); *face = LLVMBuildLoad(builder, face_var, "face"); } }
/** * Initialize the bld->a, dadq fields. This involves fetching * those values from the arrays which are passed into the JIT function. */ static void coeffs_init(struct lp_build_interp_soa_context *bld, LLVMValueRef a0_ptr, LLVMValueRef dadx_ptr, LLVMValueRef dady_ptr) { struct lp_build_context *coeff_bld = &bld->coeff_bld; struct lp_build_context *setup_bld = &bld->setup_bld; struct gallivm_state *gallivm = coeff_bld->gallivm; LLVMBuilderRef builder = gallivm->builder; LLVMValueRef pixoffx, pixoffy; unsigned attrib; unsigned chan; unsigned i; pixoffx = coeff_bld->undef; pixoffy = coeff_bld->undef; for (i = 0; i < coeff_bld->type.length; i++) { LLVMValueRef nr = lp_build_const_int32(gallivm, i); LLVMValueRef pixxf = lp_build_const_float(gallivm, quad_offset_x[i]); LLVMValueRef pixyf = lp_build_const_float(gallivm, quad_offset_y[i]); pixoffx = LLVMBuildInsertElement(builder, pixoffx, pixxf, nr, ""); pixoffy = LLVMBuildInsertElement(builder, pixoffy, pixyf, nr, ""); } for (attrib = 0; attrib < bld->num_attribs; ++attrib) { const unsigned mask = bld->mask[attrib]; const unsigned interp = bld->interp[attrib]; LLVMValueRef index = lp_build_const_int32(gallivm, attrib * TGSI_NUM_CHANNELS); LLVMValueRef ptr; LLVMValueRef dadxaos = setup_bld->zero; LLVMValueRef dadyaos = setup_bld->zero; LLVMValueRef a0aos = setup_bld->zero; /* always fetch all 4 values for performance/simplicity */ switch (interp) { case LP_INTERP_PERSPECTIVE: /* fall-through */ case LP_INTERP_LINEAR: ptr = LLVMBuildGEP(builder, dadx_ptr, &index, 1, ""); ptr = LLVMBuildBitCast(builder, ptr, LLVMPointerType(setup_bld->vec_type, 0), ""); dadxaos = LLVMBuildLoad(builder, ptr, ""); ptr = LLVMBuildGEP(builder, dady_ptr, &index, 1, ""); ptr = LLVMBuildBitCast(builder, ptr, LLVMPointerType(setup_bld->vec_type, 0), ""); dadyaos = LLVMBuildLoad(builder, ptr, ""); attrib_name(dadxaos, attrib, 0, ".dadxaos"); attrib_name(dadyaos, attrib, 0, ".dadyaos"); /* fall-through */ case LP_INTERP_CONSTANT: case LP_INTERP_FACING: ptr = LLVMBuildGEP(builder, a0_ptr, &index, 1, ""); ptr = LLVMBuildBitCast(builder, ptr, LLVMPointerType(setup_bld->vec_type, 0), ""); a0aos = LLVMBuildLoad(builder, ptr, ""); attrib_name(a0aos, attrib, 0, ".a0aos"); break; case LP_INTERP_POSITION: /* Nothing to do as the position coeffs are already setup in slot 0 */ continue; default: assert(0); break; } /* * a = a0 + (x * dadx + y * dady) * a0aos is the attrib value at top left corner of stamp */ if (interp != LP_INTERP_CONSTANT && interp != LP_INTERP_FACING) { LLVMValueRef x = lp_build_broadcast_scalar(setup_bld, bld->x); LLVMValueRef y = lp_build_broadcast_scalar(setup_bld, bld->y); a0aos = lp_build_fmuladd(builder, x, dadxaos, a0aos); a0aos = lp_build_fmuladd(builder, y, dadyaos, a0aos); } /* * dadq = {0, dadx, dady, dadx + dady} * for two quads (side by side) this is: * {0, dadx, dady, dadx+dady, 2*dadx, 2*dadx+dady, 3*dadx+dady} */ for (chan = 0; chan < TGSI_NUM_CHANNELS; ++chan) { /* this generates a CRAPLOAD of shuffles... */ if (mask & (1 << chan)) { LLVMValueRef dadx, dady; LLVMValueRef dadq, dadq2; LLVMValueRef a; LLVMValueRef chan_index = lp_build_const_int32(gallivm, chan); if (attrib == 0 && chan == 0) { a = bld->x; if (bld->pos_offset) { a = LLVMBuildFAdd(builder, a, lp_build_const_float(gallivm, bld->pos_offset), ""); } a = lp_build_broadcast_scalar(coeff_bld, a); dadx = coeff_bld->one; dady = coeff_bld->zero; } else if (attrib == 0 && chan == 1) { a = bld->y; if (bld->pos_offset) { a = LLVMBuildFAdd(builder, a, lp_build_const_float(gallivm, bld->pos_offset), ""); } a = lp_build_broadcast_scalar(coeff_bld, a); dady = coeff_bld->one; dadx = coeff_bld->zero; } else { dadx = lp_build_extract_broadcast(gallivm, setup_bld->type, coeff_bld->type, dadxaos, chan_index); dady = lp_build_extract_broadcast(gallivm, setup_bld->type, coeff_bld->type, dadyaos, chan_index); /* * a = {a, a, a, a} */ a = lp_build_extract_broadcast(gallivm, setup_bld->type, coeff_bld->type, a0aos, chan_index); } dadx = LLVMBuildFMul(builder, dadx, pixoffx, ""); dady = LLVMBuildFMul(builder, dady, pixoffy, ""); dadq = LLVMBuildFAdd(builder, dadx, dady, ""); /* * Compute the attrib values on the upper-left corner of each * group of quads. * Note that if we process 2 quads at once this doesn't * really exactly to what we want. * We need to access elem 0 and 2 respectively later if we process * 2 quads at once. */ if (interp != LP_INTERP_CONSTANT && interp != LP_INTERP_FACING) { dadq2 = LLVMBuildFAdd(builder, dadq, dadq, ""); a = LLVMBuildFAdd(builder, a, dadq2, ""); } #if PERSPECTIVE_DIVIDE_PER_QUAD /* * a *= 1 / w */ /* * XXX since we're only going to access elements 0,2 out of 8 * if we have 8-wide vectors we should do the division only 4-wide. * a is really a 2-elements in a 4-wide vector disguised as 8-wide * in this case. */ if (interp == LP_INTERP_PERSPECTIVE) { LLVMValueRef w = bld->a[0][3]; assert(attrib != 0); assert(bld->mask[0] & TGSI_WRITEMASK_W); if (!bld->oow) { bld->oow = lp_build_rcp(coeff_bld, w); lp_build_name(bld->oow, "oow"); } a = lp_build_mul(coeff_bld, a, bld->oow); } #endif attrib_name(a, attrib, chan, ".a"); attrib_name(dadq, attrib, chan, ".dadq"); bld->a[attrib][chan] = lp_build_alloca(gallivm, LLVMTypeOf(a), ""); LLVMBuildStore(builder, a, bld->a[attrib][chan]); bld->dadq[attrib][chan] = dadq; } } } }
/** * Initialize fragment shader input attribute info. */ void lp_build_interp_soa_init(struct lp_build_interp_soa_context *bld, struct gallivm_state *gallivm, unsigned num_inputs, const struct lp_shader_input *inputs, boolean pixel_center_integer, LLVMBuilderRef builder, struct lp_type type, LLVMValueRef a0_ptr, LLVMValueRef dadx_ptr, LLVMValueRef dady_ptr, LLVMValueRef x0, LLVMValueRef y0) { struct lp_type coeff_type; struct lp_type setup_type; unsigned attrib; unsigned chan; memset(bld, 0, sizeof *bld); memset(&coeff_type, 0, sizeof coeff_type); coeff_type.floating = TRUE; coeff_type.sign = TRUE; coeff_type.width = 32; coeff_type.length = type.length; memset(&setup_type, 0, sizeof setup_type); setup_type.floating = TRUE; setup_type.sign = TRUE; setup_type.width = 32; setup_type.length = TGSI_NUM_CHANNELS; /* XXX: we don't support interpolating into any other types */ assert(memcmp(&coeff_type, &type, sizeof coeff_type) == 0); lp_build_context_init(&bld->coeff_bld, gallivm, coeff_type); lp_build_context_init(&bld->setup_bld, gallivm, setup_type); /* For convenience */ bld->pos = bld->attribs[0]; bld->inputs = (const LLVMValueRef (*)[TGSI_NUM_CHANNELS]) bld->attribs[1]; /* Position */ bld->mask[0] = TGSI_WRITEMASK_XYZW; bld->interp[0] = LP_INTERP_LINEAR; /* Inputs */ for (attrib = 0; attrib < num_inputs; ++attrib) { bld->mask[1 + attrib] = inputs[attrib].usage_mask; bld->interp[1 + attrib] = inputs[attrib].interp; } bld->num_attribs = 1 + num_inputs; /* Ensure all masked out input channels have a valid value */ for (attrib = 0; attrib < bld->num_attribs; ++attrib) { for (chan = 0; chan < TGSI_NUM_CHANNELS; ++chan) { bld->attribs[attrib][chan] = bld->coeff_bld.undef; } } if (pixel_center_integer) { bld->pos_offset = 0.0; } else { bld->pos_offset = 0.5; } pos_init(bld, x0, y0); /* * Simple method (single step interpolation) may be slower if vector length * is just 4, but the results are different (generally less accurate) with * the other method, so always use more accurate version. */ if (1) { bld->simple_interp = TRUE; { /* XXX this should use a global static table */ unsigned i; unsigned num_loops = 16 / type.length; LLVMValueRef pixoffx, pixoffy, index; LLVMValueRef ptr; bld->xoffset_store = lp_build_array_alloca(gallivm, lp_build_vec_type(gallivm, type), lp_build_const_int32(gallivm, num_loops), ""); bld->yoffset_store = lp_build_array_alloca(gallivm, lp_build_vec_type(gallivm, type), lp_build_const_int32(gallivm, num_loops), ""); for (i = 0; i < num_loops; i++) { index = lp_build_const_int32(gallivm, i); calc_offsets(&bld->coeff_bld, i*type.length/4, &pixoffx, &pixoffy); ptr = LLVMBuildGEP(builder, bld->xoffset_store, &index, 1, ""); LLVMBuildStore(builder, pixoffx, ptr); ptr = LLVMBuildGEP(builder, bld->yoffset_store, &index, 1, ""); LLVMBuildStore(builder, pixoffy, ptr); } } coeffs_init_simple(bld, a0_ptr, dadx_ptr, dady_ptr); } else { bld->simple_interp = FALSE; coeffs_init(bld, a0_ptr, dadx_ptr, dady_ptr); } }
/* Perform view culling and small primitive elimination and return true * if the primitive is accepted and initially_accepted == true. */ static LLVMValueRef cull_bbox(struct ac_llvm_context *ctx, LLVMValueRef pos[3][4], LLVMValueRef initially_accepted, struct ac_position_w_info *w, LLVMValueRef vp_scale[2], LLVMValueRef vp_translate[2], LLVMValueRef small_prim_precision, bool cull_view_xy, bool cull_view_near_z, bool cull_view_far_z, bool cull_small_prims, bool use_halfz_clip_space) { LLVMBuilderRef builder = ctx->builder; if (!cull_view_xy && !cull_view_near_z && !cull_view_far_z && !cull_small_prims) return ctx->i1true; /* Skip the culling if the primitive has already been rejected or * if any W is negative. The bounding box culling doesn't work when * W is negative. */ LLVMValueRef cond = LLVMBuildAnd(builder, initially_accepted, w->all_w_positive, ""); LLVMValueRef accepted_var = ac_build_alloca_undef(ctx, ctx->i1, ""); LLVMBuildStore(builder, initially_accepted, accepted_var); ac_build_ifcc(ctx, cond, 10000000 /* does this matter? */); { LLVMValueRef bbox_min[3], bbox_max[3]; LLVMValueRef accepted = initially_accepted; /* Compute the primitive bounding box for easy culling. */ for (unsigned chan = 0; chan < 3; chan++) { bbox_min[chan] = ac_build_fmin(ctx, pos[0][chan], pos[1][chan]); bbox_min[chan] = ac_build_fmin(ctx, bbox_min[chan], pos[2][chan]); bbox_max[chan] = ac_build_fmax(ctx, pos[0][chan], pos[1][chan]); bbox_max[chan] = ac_build_fmax(ctx, bbox_max[chan], pos[2][chan]); } /* View culling. */ if (cull_view_xy || cull_view_near_z || cull_view_far_z) { for (unsigned chan = 0; chan < 3; chan++) { LLVMValueRef visible; if ((cull_view_xy && chan <= 1) || (cull_view_near_z && chan == 2)) { float t = chan == 2 && use_halfz_clip_space ? 0 : -1; visible = LLVMBuildFCmp(builder, LLVMRealOGE, bbox_max[chan], LLVMConstReal(ctx->f32, t), ""); accepted = LLVMBuildAnd(builder, accepted, visible, ""); } if ((cull_view_xy && chan <= 1) || (cull_view_far_z && chan == 2)) { visible = LLVMBuildFCmp(builder, LLVMRealOLE, bbox_min[chan], ctx->f32_1, ""); accepted = LLVMBuildAnd(builder, accepted, visible, ""); } } } /* Small primitive elimination. */ if (cull_small_prims) { /* Assuming a sample position at (0.5, 0.5), if we round * the bounding box min/max extents and the results of * the rounding are equal in either the X or Y direction, * the bounding box does not intersect the sample. * * See these GDC slides for pictures: * https://frostbite-wp-prd.s3.amazonaws.com/wp-content/uploads/2016/03/29204330/GDC_2016_Compute.pdf */ LLVMValueRef min, max, not_equal[2], visible; for (unsigned chan = 0; chan < 2; chan++) { /* Convert the position to screen-space coordinates. */ min = ac_build_fmad(ctx, bbox_min[chan], vp_scale[chan], vp_translate[chan]); max = ac_build_fmad(ctx, bbox_max[chan], vp_scale[chan], vp_translate[chan]); /* Scale the bounding box according to the precision of * the rasterizer and the number of MSAA samples. */ min = LLVMBuildFSub(builder, min, small_prim_precision, ""); max = LLVMBuildFAdd(builder, max, small_prim_precision, ""); /* Determine if the bbox intersects the sample point. * It also works for MSAA, but vp_scale, vp_translate, * and small_prim_precision are computed differently. */ min = ac_build_round(ctx, min); max = ac_build_round(ctx, max); not_equal[chan] = LLVMBuildFCmp(builder, LLVMRealONE, min, max, ""); } visible = LLVMBuildAnd(builder, not_equal[0], not_equal[1], ""); accepted = LLVMBuildAnd(builder, accepted, visible, ""); } LLVMBuildStore(builder, accepted, accepted_var); } ac_build_endif(ctx, 10000000); return LLVMBuildLoad(builder, accepted_var, ""); }
/** * Register store. */ void lp_emit_store_aos( struct lp_build_tgsi_aos_context *bld, const struct tgsi_full_instruction *inst, unsigned index, LLVMValueRef value) { LLVMBuilderRef builder = bld->bld_base.base.gallivm->builder; const struct tgsi_full_dst_register *reg = &inst->Dst[index]; LLVMValueRef mask = NULL; LLVMValueRef ptr; /* * Saturate the value */ switch (inst->Instruction.Saturate) { case TGSI_SAT_NONE: break; case TGSI_SAT_ZERO_ONE: value = lp_build_max(&bld->bld_base.base, value, bld->bld_base.base.zero); value = lp_build_min(&bld->bld_base.base, value, bld->bld_base.base.one); break; case TGSI_SAT_MINUS_PLUS_ONE: value = lp_build_max(&bld->bld_base.base, value, lp_build_const_vec(bld->bld_base.base.gallivm, bld->bld_base.base.type, -1.0)); value = lp_build_min(&bld->bld_base.base, value, bld->bld_base.base.one); break; default: assert(0); } /* * Translate the register file */ assert(!reg->Register.Indirect); switch (reg->Register.File) { case TGSI_FILE_OUTPUT: ptr = bld->outputs[reg->Register.Index]; break; case TGSI_FILE_TEMPORARY: ptr = bld->temps[reg->Register.Index]; break; case TGSI_FILE_ADDRESS: ptr = bld->addr[reg->Indirect.Index]; break; case TGSI_FILE_PREDICATE: ptr = bld->preds[reg->Register.Index]; break; default: assert(0); return; } if (!ptr) return; /* * Predicate */ if (inst->Instruction.Predicate) { LLVMValueRef pred; assert(inst->Predicate.Index < LP_MAX_TGSI_PREDS); pred = LLVMBuildLoad(builder, bld->preds[inst->Predicate.Index], ""); /* * Convert the value to an integer mask. */ pred = lp_build_compare(bld->bld_base.base.gallivm, bld->bld_base.base.type, PIPE_FUNC_NOTEQUAL, pred, bld->bld_base.base.zero); if (inst->Predicate.Negate) { pred = LLVMBuildNot(builder, pred, ""); } pred = bld->bld_base.emit_swizzle(&bld->bld_base, pred, inst->Predicate.SwizzleX, inst->Predicate.SwizzleY, inst->Predicate.SwizzleZ, inst->Predicate.SwizzleW); if (mask) { mask = LLVMBuildAnd(builder, mask, pred, ""); } else { mask = pred; } } /* * Writemask */ if (reg->Register.WriteMask != TGSI_WRITEMASK_XYZW) { LLVMValueRef writemask; writemask = lp_build_const_mask_aos_swizzled(bld->bld_base.base.gallivm, bld->bld_base.base.type, reg->Register.WriteMask, TGSI_NUM_CHANNELS, bld->swizzles); if (mask) { mask = LLVMBuildAnd(builder, mask, writemask, ""); } else { mask = writemask; } } if (mask) { LLVMValueRef orig_value; orig_value = LLVMBuildLoad(builder, ptr, ""); value = lp_build_select(&bld->bld_base.base, mask, value, orig_value); } LLVMBuildStore(builder, value, ptr); }
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; }
void decode_packed_struct_inline( struct llvm_ctx *ctx, LLVMValueRef dst, IDL_tree ctyp, LLVMValueRef first_mr, LLVMValueRef bit_offset) { const struct packed_format *fmt = packed_format_of(ctyp); assert(fmt != NULL); char **names = NULL; T s_type = llvm_struct_type(ctx, &names, ctyp); int names_len = 0; while(names[names_len] != NULL) names_len++; assert(names_len == fmt->num_items); assert(LLVMCountStructElementTypes(s_type) == names_len); T types[MAX(names_len, 1)]; LLVMGetStructElementTypes(s_type, types); int cur_word = 0; V wordval = NULL; for(int i=0; i<fmt->num_items; i++) { const struct packed_item *pi = fmt->items[i]; int field_ix = strv_lookup(names, pi->name); if(field_ix < 0) { fprintf(stderr, "%s: not the way to go.\n", __func__); abort(); } V start_mr = LLVMBuildAdd(ctx->builder, first_mr, CONST_INT(pi->word), tmp_f(ctx->pr, "%s.start.mr", pi->name)); V dstptr = LLVMBuildStructGEP(ctx->builder, dst, field_ix, tmp_f(ctx->pr, "%s.start.ptr", pi->name)); if(pi->dim > 1) { /* array types. TODO */ fprintf(stderr, "%s: struct-member arrays not implemented\n", __func__); abort(); } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_STRUCT) { decode_packed_struct(ctx, &dstptr, pi->type, start_mr, CONST_INT(pi->bit)); } else if(IDL_NODE_TYPE(pi->type) == IDLN_TYPE_UNION) { fprintf(stderr, "%s: union-member types not implemented\n", __func__); abort(); } else if(IS_LONGLONG_TYPE(pi->type)) { /* long long on a 32-bit architecture. can be #ifdef'd out for * 64-bit targets, where it'd be just a value type. */ V dtmp = NULL; build_read_ipc_parameter(ctx, &dtmp, pi->type, start_mr); LLVMBuildStore(ctx->builder, dtmp, dstptr); } else if(is_value_type(pi->type)) { /* word-size and smaller items. */ if(cur_word != pi->word || wordval == NULL) { cur_word = pi->word; V old_wv = wordval; wordval = build_ipc_input_val_ix(ctx, start_mr, tmp_f(ctx->pr, "st.word%d", pi->word)); if(old_wv == NULL) { /* shift it down, since we start at an offset. */ wordval = LLVMBuildLShr(ctx->builder, wordval, bit_offset, "st.bitoffs.shifted"); } } V subval = LLVMBuildLShr(ctx->builder, wordval, CONST_INT(pi->bit), tmp_f(ctx->pr, "st.word%d.shr%d", pi->word, pi->bit)); if(pi->len < BITS_PER_WORD) { subval = LLVMBuildAnd(ctx->builder, subval, CONST_WORD((1 << pi->len) - 1), tmp_f(ctx->pr, "st.word%d.s%d.m%d", pi->word, pi->bit, pi->len)); } subval = LLVMBuildTruncOrBitCast(ctx->builder, subval, types[field_ix], "st.val.cast"); LLVMBuildStore(ctx->builder, subval, dstptr); } else if(IS_MAPGRANT_TYPE(pi->type)) { /* two words, like peas in a pod */ assert(pi->bit == 0); build_read_ipc_parameter(ctx, &dstptr, pi->type, start_mr); } else { NOTDEFINED(pi->type); } } g_strfreev(names); }
/* * llvmgen_assignment * * Generates a store operation from an assignment expression. */ LLVMValueRef llvmgen_assignment (gencodectx_t gctx, expr_node_t *lhs, expr_node_t *rhs) { LLVMBuilderRef builder = (gctx->curfn == 0 ? 0 : gctx->curfn->builder); LLVMValueRef rhsvalue, v, lhsaddr; LLVMTypeRef lhstype, rhstype; llvm_accinfo_t accinfo; int shifts_required = 0; rhsvalue = llvmgen_expression(gctx, rhs, 0); if (rhsvalue == 0) { unsigned int bpval = machine_scalar_bits(gctx->mach); expr_signal(gctx->ectx, STC__EXPRVALRQ); rhsvalue = LLVMConstNull(LLVMIntTypeInContext(gctx->llvmctx, bpval)); } rhstype = LLVMTypeOf(rhsvalue); lhsaddr = llvmgen_addr_expression(gctx, lhs, &accinfo); if (lhsaddr == 0) { expr_signal(gctx->ectx, STC__ADDRVALRQ); return rhsvalue; } // If we're assigning into a field-reference with a non-zero // bit position or a non-CTCE size, we have to do some bit-shifting // to do the store. if (accinfo.posval != 0 || accinfo.sizeval != 0) { shifts_required = 1; lhstype = LLVMIntTypeInContext(gctx->llvmctx, accinfo.width); if ((accinfo.flags & LLVMGEN_M_ACC_CONSTSIZ) != 0) { accinfo.sizeval = LLVMConstInt(gctx->fullwordtype, accinfo.size, 0); } } else if ((accinfo.flags & LLVMGEN_M_ACC_CONSTSIZ) != 0) { lhstype = LLVMIntTypeInContext(gctx->llvmctx, accinfo.size); } else { lhstype = LLVMIntTypeInContext(gctx->llvmctx, accinfo.width); } lhsaddr = llvmgen_adjustval(gctx, lhsaddr, LLVMPointerType(lhstype, 0), 0); if (shifts_required) { LLVMValueRef neg1, srcmask, dstmask, rhstemp; if (LLVMGetTypeKind(rhstype) != LLVMIntegerTypeKind) { rhsvalue = llvmgen_adjustval(gctx, rhsvalue, gctx->fullwordtype, 0); rhstype = LLVMTypeOf(rhsvalue); } else { accinfo.sizeval = llvmgen_adjustval(gctx, accinfo.sizeval, rhstype, 0); accinfo.posval = llvmgen_adjustval(gctx, accinfo.posval, rhstype, 0); } neg1 = LLVMConstAllOnes(rhstype); v = LLVMBuildShl(builder, neg1, accinfo.sizeval, llvmgen_temp(gctx)); srcmask = LLVMBuildNot(builder, v, llvmgen_temp(gctx)); v = LLVMBuildAnd(builder, rhsvalue, srcmask, llvmgen_temp(gctx)); v = LLVMBuildShl(builder, v, accinfo.posval, llvmgen_temp(gctx)); rhstemp = llvmgen_adjustval(gctx, v, lhstype, 0); v = LLVMBuildShl(builder, srcmask, accinfo.posval, llvmgen_temp(gctx)); v = llvmgen_adjustval(gctx, v, lhstype, 0); dstmask = LLVMBuildNot(builder, v, llvmgen_temp(gctx)); v = LLVMBuildLoad(builder, lhsaddr, llvmgen_temp(gctx)); v = llvmgen_adjustval(gctx, v, lhstype, (accinfo.flags & LLVMGEN_M_SEG_SIGNEXT) != 0); v = LLVMBuildAnd(builder, v, dstmask, llvmgen_temp(gctx)); v = LLVMBuildOr(builder, v, rhstemp, llvmgen_temp(gctx)); } else { v = llvmgen_adjustval(gctx, rhsvalue, lhstype, (accinfo.flags & LLVMGEN_M_SEG_SIGNEXT) != 0); } LLVMBuildStore(builder, v, lhsaddr); if ((accinfo.flags & LLVMGEN_M_SEG_VOLATILE) != 0) LLVMSetVolatile(v, 1); return rhsvalue; } /* llvmgen_assignment */