void genprim_string_serialise_trace(compile_t* c, reach_type_t* t) { // Generate the serialise_trace function. t->serialise_trace_fn = codegen_addfun(c, genname_serialise_trace(t->name), c->serialise_type); codegen_startfun(c, t->serialise_trace_fn, NULL, NULL); LLVMSetFunctionCallConv(t->serialise_trace_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->serialise_trace_fn, 0); LLVMValueRef arg = LLVMGetParam(t->serialise_trace_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->use_type, ""); // Read the size. LLVMValueRef size = field_value(c, object, 1); LLVMValueRef alloc = LLVMBuildAdd(c->builder, size, LLVMConstInt(c->intptr, 1, false), ""); // Reserve space for the contents. LLVMValueRef ptr = field_value(c, object, 3); LLVMValueRef args[3]; args[0] = ctx; args[1] = ptr; args[2] = alloc; gencall_runtime(c, "pony_serialise_reserve", args, 3, ""); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
void vm_state_destroy(struct vm_state *vm) { LLVMBasicBlockRef current_block, return_block; char *error; current_block = LLVMGetInsertBlock(vm->builder); return_block = LLVMInsertBasicBlock(current_block, "ret"); LLVMPositionBuilderAtEnd(vm->builder, current_block); LLVMBuildBr(vm->builder, return_block); LLVMPositionBuilderAtEnd(vm->builder, return_block); LLVMBuildRetVoid(vm->builder); LLVMMoveBasicBlockAfter(return_block, current_block); LLVMDumpModule(vm->module); error = NULL; LLVMVerifyModule(vm->module, LLVMAbortProcessAction, &error); LLVMDisposeMessage(error); LLVMDisposeBuilder(vm->builder); LLVMDisposeModule(vm->module); symbol_table_destroy(vm->symtab); }
void genprim_string_deserialise(compile_t* c, reach_type_t* t) { // Generate the deserisalise function. t->deserialise_fn = codegen_addfun(c, genname_serialise(t->name), c->trace_type); codegen_startfun(c, t->deserialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->deserialise_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->deserialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->deserialise_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); gendeserialise_typeid(c, t, object); // Deserialise the string contents. LLVMValueRef alloc = field_value(c, object, 2); LLVMValueRef ptr_offset = field_value(c, object, 3); ptr_offset = LLVMBuildPtrToInt(c->builder, ptr_offset, c->intptr, ""); LLVMValueRef args[3]; args[0] = ctx; args[1] = ptr_offset; args[2] = alloc; LLVMValueRef ptr_addr = gencall_runtime(c, "pony_deserialise_block", args, 3, ""); LLVMValueRef ptr = LLVMBuildStructGEP(c->builder, object, 3, ""); LLVMBuildStore(c->builder, ptr_addr, ptr); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
LLVMValueRef gen_return(compile_t* c, ast_t* ast) { ast_t* expr = ast_child(ast); LLVMValueRef value = gen_expr(c, expr); size_t clause; ast_t* try_expr = ast_try_clause(ast, &clause); // Do the then block only if we return in the body or else clause. // In the then block, return without doing the then block. if((try_expr != NULL) && (clause != 2)) gen_expr(c, ast_childidx(try_expr, 2)); LLVMTypeRef f_type = LLVMGetElementType(LLVMTypeOf(codegen_fun(c))); LLVMTypeRef r_type = LLVMGetReturnType(f_type); codegen_debugloc(c, ast); if(LLVMGetTypeKind(r_type) != LLVMVoidTypeKind) { LLVMValueRef ret = gen_assign_cast(c, r_type, value, ast_type(expr)); codegen_scope_lifetime_end(c); LLVMBuildRet(c->builder, ret); } else { codegen_scope_lifetime_end(c); LLVMBuildRetVoid(c->builder); } codegen_debugloc(c, NULL); return GEN_NOVALUE; }
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 LLVMValueRef add_printf_test(struct gallivm_state *gallivm) { LLVMModuleRef module = gallivm->module; LLVMTypeRef args[1] = { LLVMIntTypeInContext(gallivm->context, 32) }; LLVMValueRef func = LLVMAddFunction(module, "test_printf", LLVMFunctionType(LLVMVoidTypeInContext(gallivm->context), args, 1, 0)); LLVMBuilderRef builder = gallivm->builder; LLVMBasicBlockRef block = LLVMAppendBasicBlockInContext(gallivm->context, func, "entry"); LLVMSetFunctionCallConv(func, LLVMCCallConv); LLVMPositionBuilderAtEnd(builder, block); lp_build_printf(gallivm, "hello, world\n"); lp_build_printf(gallivm, "print 5 6: %d %d\n", LLVMConstInt(LLVMInt32TypeInContext(gallivm->context), 5, 0), LLVMConstInt(LLVMInt32TypeInContext(gallivm->context), 6, 0)); /* Also test lp_build_assert(). This should not fail. */ lp_build_assert(gallivm, LLVMConstInt(LLVMInt32TypeInContext(gallivm->context), 1, 0), "assert(1)"); LLVMBuildRetVoid(builder); gallivm_verify_function(gallivm, func); return func; }
static void make_serialise(compile_t* c, reach_type_t* t) { // Use the trace function as the serialise_trace function. t->serialise_trace_fn = t->trace_fn; // Generate the serialise function. t->serialise_fn = codegen_addfun(c, genname_serialise(t->name), c->serialise_type); codegen_startfun(c, t->serialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->serialise_fn, LLVMCCallConv); LLVMSetLinkage(t->serialise_fn, LLVMExternalLinkage); LLVMValueRef ctx = LLVMGetParam(t->serialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->serialise_fn, 1); LLVMValueRef addr = LLVMGetParam(t->serialise_fn, 2); LLVMValueRef offset = LLVMGetParam(t->serialise_fn, 3); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); LLVMValueRef offset_addr = LLVMBuildInBoundsGEP(c->builder, addr, &offset, 1, ""); serialise(c, t, ctx, object, offset_addr); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
static LLVMValueRef add_blend_test(struct gallivm_state *gallivm, const struct pipe_blend_state *blend, struct lp_type type) { LLVMModuleRef module = gallivm->module; LLVMContextRef context = gallivm->context; LLVMTypeRef vec_type; LLVMTypeRef args[5]; LLVMValueRef func; LLVMValueRef src_ptr; LLVMValueRef src1_ptr; LLVMValueRef dst_ptr; LLVMValueRef const_ptr; LLVMValueRef res_ptr; LLVMBasicBlockRef block; LLVMBuilderRef builder; const enum pipe_format format = PIPE_FORMAT_R8G8B8A8_UNORM; const unsigned rt = 0; const unsigned char swizzle[4] = { 0, 1, 2, 3 }; LLVMValueRef src; LLVMValueRef src1; LLVMValueRef dst; LLVMValueRef con; LLVMValueRef res; vec_type = lp_build_vec_type(gallivm, type); args[4] = args[3] = args[2] = args[1] = args[0] = LLVMPointerType(vec_type, 0); func = LLVMAddFunction(module, "test", LLVMFunctionType(LLVMVoidTypeInContext(context), args, 5, 0)); LLVMSetFunctionCallConv(func, LLVMCCallConv); src_ptr = LLVMGetParam(func, 0); src1_ptr = LLVMGetParam(func, 1); dst_ptr = LLVMGetParam(func, 2); const_ptr = LLVMGetParam(func, 3); res_ptr = LLVMGetParam(func, 4); block = LLVMAppendBasicBlockInContext(context, func, "entry"); builder = gallivm->builder; LLVMPositionBuilderAtEnd(builder, block); src = LLVMBuildLoad(builder, src_ptr, "src"); src1 = LLVMBuildLoad(builder, src1_ptr, "src1"); dst = LLVMBuildLoad(builder, dst_ptr, "dst"); con = LLVMBuildLoad(builder, const_ptr, "const"); res = lp_build_blend_aos(gallivm, blend, format, type, rt, src, NULL, src1, NULL, dst, NULL, con, NULL, swizzle, 4); lp_build_name(res, "res"); LLVMBuildStore(builder, res, res_ptr); LLVMBuildRetVoid(builder);; gallivm_verify_function(gallivm, func); return func; }
static LLVMValueRef genfun_newbe(compile_t* c, gentype_t* g, const char *name, ast_t* typeargs) { ast_t* fun = get_fun(g, name, typeargs); LLVMValueRef func = get_prototype(c, g, name, typeargs, fun); if(func == NULL) { ast_free_unattached(fun); return NULL; } codegen_startfun(c, func, ast_debug(fun)); name_params(c, g->ast, ast_childidx(fun, 3), func); genfun_dwarf(c, g, name, typeargs, fun); if(!gen_field_init(c, g)) { ast_free_unattached(fun); return NULL; } ast_t* body = ast_childidx(fun, 6); LLVMValueRef value = gen_expr(c, body); if(value == NULL) { ast_free_unattached(fun); return NULL; } LLVMBuildRetVoid(c->builder); codegen_finishfun(c); // Generate the sender. LLVMValueRef sender = get_sender(c, g, name, typeargs); codegen_startfun(c, sender, false); LLVMValueRef this_ptr = LLVMGetParam(sender, 0); // Send the arguments in a message to 'this'. uint32_t index = genfun_vtable_index(c, g, name, typeargs); LLVMTypeRef msg_type_ptr = send_message(c, fun, this_ptr, sender, index); genfun_dwarf_return(c, body); // Return 'this'. LLVMBuildRet(c->builder, this_ptr); codegen_finishfun(c); // Add the dispatch case. add_dispatch_case(c, g, fun, index, func, msg_type_ptr); ast_free_unattached(fun); return func; }
static bool make_trace(compile_t* c, gentype_t* g) { // Do nothing if we have no fields. if(g->field_count == 0) return true; if(g->underlying == TK_CLASS) { // Special case the array trace function. AST_GET_CHILDREN(g->ast, pkg, id); const char* package = ast_name(pkg); const char* name = ast_name(id); if((package == c->str_builtin) && (name == c->str_Array)) { genprim_array_trace(c, g); return true; } } // Create a trace function. const char* trace_name = genname_trace(g->type_name); LLVMValueRef trace_fn = codegen_addfun(c, trace_name, c->trace_type); codegen_startfun(c, trace_fn, false); LLVMSetFunctionCallConv(trace_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(trace_fn, 0); LLVMValueRef arg = LLVMGetParam(trace_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, g->structure_ptr, "object"); // If we don't ever trace anything, delete this function. int extra = 0; // Non-structs have a type descriptor. if(g->underlying != TK_STRUCT) extra++; // Actors have a pad. if(g->underlying == TK_ACTOR) extra++; bool need_trace = trace_fields(c, g, ctx, object, extra); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); if(!need_trace) LLVMDeleteFunction(trace_fn); return true; }
int llvm_set_metadata(void) { LLVMBuilderRef b = LLVMCreateBuilder(); LLVMValueRef values[] = { LLVMConstInt(LLVMInt32Type(), 0, 0) }; // This used to trigger an assertion LLVMSetMetadata( LLVMBuildRetVoid(b), LLVMGetMDKindID("kind", 4), LLVMMDNode(values, 1)); LLVMDisposeBuilder(b); return 0; }
static LLVMValueRef add_conv_test(struct gallivm_state *gallivm, struct lp_type src_type, unsigned num_srcs, struct lp_type dst_type, unsigned num_dsts) { LLVMModuleRef module = gallivm->module; LLVMContextRef context = gallivm->context; LLVMBuilderRef builder = gallivm->builder; LLVMTypeRef args[2]; LLVMValueRef func; LLVMValueRef src_ptr; LLVMValueRef dst_ptr; LLVMBasicBlockRef block; LLVMValueRef src[LP_MAX_VECTOR_LENGTH]; LLVMValueRef dst[LP_MAX_VECTOR_LENGTH]; unsigned i; args[0] = LLVMPointerType(lp_build_vec_type(gallivm, src_type), 0); args[1] = LLVMPointerType(lp_build_vec_type(gallivm, dst_type), 0); func = LLVMAddFunction(module, "test", LLVMFunctionType(LLVMVoidTypeInContext(context), args, 2, 0)); LLVMSetFunctionCallConv(func, LLVMCCallConv); src_ptr = LLVMGetParam(func, 0); dst_ptr = LLVMGetParam(func, 1); block = LLVMAppendBasicBlockInContext(context, func, "entry"); LLVMPositionBuilderAtEnd(builder, block); for(i = 0; i < num_srcs; ++i) { LLVMValueRef index = LLVMConstInt(LLVMInt32TypeInContext(context), i, 0); LLVMValueRef ptr = LLVMBuildGEP(builder, src_ptr, &index, 1, ""); src[i] = LLVMBuildLoad(builder, ptr, ""); } lp_build_conv(gallivm, src_type, dst_type, src, num_srcs, dst, num_dsts); for(i = 0; i < num_dsts; ++i) { LLVMValueRef index = LLVMConstInt(LLVMInt32TypeInContext(context), i, 0); LLVMValueRef ptr = LLVMBuildGEP(builder, dst_ptr, &index, 1, ""); LLVMBuildStore(builder, dst[i], ptr); } LLVMBuildRetVoid(builder);; gallivm_verify_function(gallivm, func); return func; }
static void add_dispatch_case(compile_t* c, gentype_t* g, ast_t* fun, uint32_t index, LLVMValueRef handler, LLVMTypeRef type) { // Add a case to the dispatch function to handle this message. codegen_startfun(c, g->dispatch_fn, false); LLVMBasicBlockRef block = codegen_block(c, "handler"); LLVMValueRef id = LLVMConstInt(c->i32, index, false); LLVMAddCase(g->dispatch_switch, id, block); // Destructure the message. LLVMPositionBuilderAtEnd(c->builder, block); LLVMValueRef ctx = LLVMGetParam(g->dispatch_fn, 0); LLVMValueRef this_ptr = LLVMGetParam(g->dispatch_fn, 1); LLVMValueRef msg = LLVMBuildBitCast(c->builder, LLVMGetParam(g->dispatch_fn, 2), type, ""); int count = LLVMCountParams(handler); size_t buf_size = count * sizeof(LLVMValueRef); LLVMValueRef* args = (LLVMValueRef*)pool_alloc_size(buf_size); args[0] = LLVMBuildBitCast(c->builder, this_ptr, g->use_type, ""); // Trace the message. LLVMValueRef start_trace = gencall_runtime(c, "pony_gc_recv", &ctx, 1, ""); ast_t* params = ast_childidx(fun, 3); ast_t* param = ast_child(params); bool need_trace = false; for(int i = 1; i < count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, msg, i + 2, ""); args[i] = LLVMBuildLoad(c->builder, field, ""); need_trace |= gentrace(c, ctx, args[i], ast_type(param)); param = ast_sibling(param); } if(need_trace) { gencall_runtime(c, "pony_recv_done", &ctx, 1, ""); } else { LLVMInstructionEraseFromParent(start_trace); } // Call the handler. codegen_call(c, handler, args, count); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); pool_free_size(buf_size, args); }
static bool genfun_newbe(compile_t* c, reachable_type_t* t, reachable_method_t* m) { assert(m->func != NULL); assert(m->func_handler != NULL); AST_GET_CHILDREN(m->r_fun, cap, id, typeparams, params, result, can_error, body); // Generate the handler. codegen_startfun(c, m->func_handler, m->di_file, m->di_method); name_params(c, t, m, params, m->func_handler); LLVMValueRef value = gen_expr(c, body); if(value == NULL) return false; LLVMBuildRetVoid(c->builder); codegen_finishfun(c); // Generate the sender. codegen_startfun(c, m->func, NULL, NULL); LLVMValueRef this_ptr = LLVMGetParam(m->func, 0); // Send the arguments in a message to 'this'. LLVMTypeRef msg_type_ptr = send_message(c, params, this_ptr, m->func, m->vtable_index); // Return 'this'. codegen_debugloc(c, ast_childlast(body)); LLVMBuildRet(c->builder, this_ptr); codegen_debugloc(c, NULL); codegen_finishfun(c); // Add the dispatch case. add_dispatch_case(c, t, params, m->vtable_index, m->func_handler, msg_type_ptr); return true; }
void genprim_array_trace(compile_t* c, reach_type_t* t) { codegen_startfun(c, t->trace_fn, NULL, NULL); LLVMSetFunctionCallConv(t->trace_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->trace_fn, 0); LLVMValueRef arg = LLVMGetParam(t->trace_fn, 1); // Read the base pointer. LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->use_type, ""); LLVMValueRef pointer = field_value(c, object, 3); // Trace the base pointer. LLVMValueRef args[2]; args[0] = ctx; args[1] = pointer; gencall_runtime(c, "pony_trace", args, 2, ""); trace_array_elements(c, t, ctx, object, pointer); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
void genprim_array_serialise_trace(compile_t* c, reach_type_t* t) { // Generate the serialise_trace function. t->serialise_trace_fn = codegen_addfun(c, genname_serialise_trace(t->name), c->trace_type); codegen_startfun(c, t->serialise_trace_fn, NULL, NULL); LLVMSetFunctionCallConv(t->serialise_trace_fn, LLVMCCallConv); LLVMSetLinkage(t->serialise_trace_fn, LLVMExternalLinkage); LLVMValueRef ctx = LLVMGetParam(t->serialise_trace_fn, 0); LLVMValueRef arg = LLVMGetParam(t->serialise_trace_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->use_type, ""); // Read the size. LLVMValueRef size = field_value(c, object, 1); // Calculate the size of the element type. ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); reach_type_t* t_elem = reach_type(c->reach, typearg); size_t abisize = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, abisize, false); // Reserve space for the array elements. LLVMValueRef pointer = field_value(c, object, 3); LLVMValueRef args[3]; args[0] = ctx; args[1] = pointer; args[2] = LLVMBuildMul(c->builder, size, l_size, ""); gencall_runtime(c, "pony_serialise_reserve", args, 3, ""); // Trace the array elements. trace_array_elements(c, t, ctx, object, pointer); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
/* * 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; }
static void make_deserialise(compile_t* c, reach_type_t* t) { // Generate the deserialise function. t->deserialise_fn = codegen_addfun(c, genname_deserialise(t->name), c->trace_type); codegen_startfun(c, t->deserialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->deserialise_fn, LLVMCCallConv); LLVMSetLinkage(t->deserialise_fn, LLVMExternalLinkage); LLVMValueRef ctx = LLVMGetParam(t->deserialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->deserialise_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); // At this point, the serialised contents have been copied to the allocated // object. deserialise(c, t, ctx, object); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
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); }
int qip_ast_freturn_codegen(qip_ast_node *node, qip_module *module, LLVMValueRef *value) { check(node != NULL, "Node is required"); check(node->type == QIP_AST_TYPE_FRETURN, "Node must be a function return"); LLVMBuilderRef builder = module->compiler->llvm_builder; // Return value if specified. if(node->freturn.value) { // Load return value. LLVMValueRef return_value = NULL; int rc = qip_ast_node_codegen(node->freturn.value, module, &return_value); check(rc == 0, "Unable to codegen function return value"); check(return_value != NULL, "Missing return value"); // Generate destroy for variable declarations. rc = qip_ast_block_codegen_destroy(node->parent, module); check(rc == 0, "Unable to generate block destroy"); // Execute return of value. *value = LLVMBuildRet(builder, return_value); check(*value != NULL, "Unable to generate function return"); } // Otherwise return void. else { *value = LLVMBuildRetVoid(builder); check(*value != NULL, "Unable to generate function return void"); } return 0; error: *value = NULL; return -1; }
static LLVMValueRef add_blend_test(struct gallivm_state *gallivm, const struct pipe_blend_state *blend, enum vector_mode mode, struct lp_type type) { LLVMModuleRef module = gallivm->module; LLVMContextRef context = gallivm->context; LLVMTypeRef vec_type; LLVMTypeRef args[4]; LLVMValueRef func; LLVMValueRef src_ptr; LLVMValueRef dst_ptr; LLVMValueRef const_ptr; LLVMValueRef res_ptr; LLVMBasicBlockRef block; LLVMBuilderRef builder; const enum pipe_format format = PIPE_FORMAT_R8G8B8A8_UNORM; const unsigned rt = 0; const unsigned char swizzle[4] = { 0, 1, 2, 3 }; vec_type = lp_build_vec_type(gallivm, type); args[3] = args[2] = args[1] = args[0] = LLVMPointerType(vec_type, 0); func = LLVMAddFunction(module, "test", LLVMFunctionType(LLVMVoidTypeInContext(context), 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 = LLVMAppendBasicBlockInContext(context, func, "entry"); builder = gallivm->builder; 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(gallivm, blend, &format, type, rt, src, dst, NULL, con, swizzle); 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(LLVMInt32TypeInContext(context), 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(gallivm, blend, type, rt, src, dst, con, res); for(i = 0; i < 4; ++i) { LLVMValueRef index = LLVMConstInt(LLVMInt32TypeInContext(context), i, 0); lp_build_name(res[i], "res.%c", "rgba"[i]); LLVMBuildStore(builder, res[i], LLVMBuildGEP(builder, res_ptr, &index, 1, "")); } } LLVMBuildRetVoid(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]); }
/** * 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; }
SCM llvm_function_return_void(SCM scm_self) { struct llvm_function_t *self = get_llvm_function(scm_self); LLVMBuildRetVoid(self->builder); return SCM_UNSPECIFIED; }
static bool make_trace(compile_t* c, reach_type_t* t) { if(t->trace_fn == NULL) return true; if(t->underlying == TK_CLASS) { // Special case the array trace function. AST_GET_CHILDREN(t->ast, pkg, id); const char* package = ast_name(pkg); const char* name = ast_name(id); if((package == c->str_builtin) && (name == c->str_Array)) { genprim_array_trace(c, t); return true; } } // Generate the trace function. codegen_startfun(c, t->trace_fn, NULL, NULL); LLVMSetFunctionCallConv(t->trace_fn, LLVMCCallConv); LLVMSetLinkage(t->trace_fn, LLVMExternalLinkage); LLVMValueRef ctx = LLVMGetParam(t->trace_fn, 0); LLVMValueRef arg = LLVMGetParam(t->trace_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, "object"); int extra = 0; // Non-structs have a type descriptor. if(t->underlying != TK_STRUCT) extra++; // Actors have a pad. if(t->underlying == TK_ACTOR) extra++; for(uint32_t i = 0; i < t->field_count; i++) { LLVMValueRef field = LLVMBuildStructGEP(c->builder, object, i + extra, ""); if(!t->fields[i].embed) { // Call the trace function indirectly depending on rcaps. LLVMValueRef value = LLVMBuildLoad(c->builder, field, ""); gentrace(c, ctx, value, t->fields[i].ast); } else { // Call the trace function directly without marking the field. LLVMValueRef trace_fn = t->fields[i].type->trace_fn; if(trace_fn != NULL) { LLVMValueRef args[2]; args[0] = ctx; args[1] = LLVMBuildBitCast(c->builder, field, c->object_ptr, ""); LLVMBuildCall(c->builder, trace_fn, args, 2, ""); } } } LLVMBuildRetVoid(c->builder); codegen_finishfun(c); return true; }
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 genprim_string_serialise(compile_t* c, reach_type_t* t) { // Generate the serialise function. t->serialise_fn = codegen_addfun(c, genname_serialise(t->name), c->serialise_type); codegen_startfun(c, t->serialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->serialise_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->serialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->serialise_fn, 1); LLVMValueRef addr = LLVMGetParam(t->serialise_fn, 2); LLVMValueRef offset = LLVMGetParam(t->serialise_fn, 3); LLVMValueRef mut = LLVMGetParam(t->serialise_fn, 4); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); LLVMValueRef offset_addr = LLVMBuildAdd(c->builder, LLVMBuildPtrToInt(c->builder, addr, c->intptr, ""), offset, ""); genserialise_typeid(c, t, offset_addr); // Don't serialise our contents if we are opaque. LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntNE, mut, LLVMConstInt(c->i32, PONY_TRACE_OPAQUE, false), ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); LLVMPositionBuilderAtEnd(c->builder, body_block); // Write the size, and rewrite alloc to be size + 1. LLVMValueRef size = field_value(c, object, 1); LLVMValueRef size_loc = field_loc(c, offset_addr, t->structure, c->intptr, 1); LLVMBuildStore(c->builder, size, size_loc); LLVMValueRef alloc = LLVMBuildAdd(c->builder, size, LLVMConstInt(c->intptr, 1, false), ""); LLVMValueRef alloc_loc = field_loc(c, offset_addr, t->structure, c->intptr, 2); LLVMBuildStore(c->builder, alloc, alloc_loc); // Write the pointer. LLVMValueRef ptr = field_value(c, object, 3); LLVMValueRef args[5]; args[0] = ctx; args[1] = ptr; LLVMValueRef ptr_offset = gencall_runtime(c, "pony_serialise_offset", args, 2, ""); LLVMValueRef ptr_loc = field_loc(c, offset_addr, t->structure, c->intptr, 3); LLVMBuildStore(c->builder, ptr_offset, ptr_loc); // Serialise the string contents. LLVMValueRef ptr_offset_addr = LLVMBuildAdd(c->builder, LLVMBuildPtrToInt(c->builder, addr, c->intptr, ""), ptr_offset, ""); args[0] = LLVMBuildIntToPtr(c->builder, ptr_offset_addr, c->void_ptr, ""); args[1] = LLVMBuildBitCast(c->builder, field_value(c, object, 3), c->void_ptr, ""); args[2] = alloc; args[3] = LLVMConstInt(c->i32, 1, false); args[4] = LLVMConstInt(c->i1, 0, false); if(target_is_ilp32(c->opt->triple)) { gencall_runtime(c, "llvm.memcpy.p0i8.p0i8.i32", args, 5, ""); } else { gencall_runtime(c, "llvm.memcpy.p0i8.p0i8.i64", args, 5, ""); } LLVMBuildBr(c->builder, post_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
static bool make_trace(compile_t* c, gentype_t* g) { // Do nothing if we have no fields. if(g->field_count == 0) return true; if(g->underlying == TK_CLASS) { // Special case the array trace function. AST_GET_CHILDREN(g->ast, pkg, id); const char* package = ast_name(pkg); const char* name = ast_name(id); if((package == c->str_1) && (name == c->str_Array)) { genprim_array_trace(c, g); return true; } } // Create a trace function. const char* trace_name = genname_trace(g->type_name); LLVMValueRef trace_fn = codegen_addfun(c, trace_name, c->trace_type); codegen_startfun(c, trace_fn, false); LLVMSetFunctionCallConv(trace_fn, LLVMCCallConv); LLVMValueRef arg = LLVMGetParam(trace_fn, 0); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, g->structure_ptr, "object"); // If we don't ever trace anything, delete this function. bool need_trace; if(g->underlying == TK_TUPLETYPE) { // Create another function that traces the tuple members. const char* trace_tuple_name = genname_tracetuple(g->type_name); LLVMTypeRef trace_tuple_type = LLVMFunctionType(c->void_type, &g->primitive, 1, false); LLVMValueRef trace_tuple_fn = codegen_addfun(c, trace_tuple_name, trace_tuple_type); codegen_startfun(c, trace_tuple_fn, false); LLVMSetFunctionCallConv(trace_tuple_fn, LLVMCCallConv); LLVMValueRef arg = LLVMGetParam(trace_tuple_fn, 0); need_trace = trace_elements(c, g, arg); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); if(need_trace) { // Get the tuple primitive. LLVMValueRef tuple_ptr = LLVMBuildStructGEP(c->builder, object, 1, ""); LLVMValueRef tuple = LLVMBuildLoad(c->builder, tuple_ptr, ""); // Call the tuple trace function with the unboxed primitive type. LLVMBuildCall(c->builder, trace_tuple_fn, &tuple, 1, ""); } else { LLVMDeleteFunction(trace_tuple_fn); } } else { int extra = 1; // Actors have a pad. if(g->underlying == TK_ACTOR) extra++; need_trace = trace_fields(c, g, object, extra); } LLVMBuildRetVoid(c->builder); codegen_finishfun(c); if(!need_trace) LLVMDeleteFunction(trace_fn); return true; }
void genprim_array_deserialise(compile_t* c, reach_type_t* t) { // Generate the deserisalise function. t->deserialise_fn = codegen_addfun(c, genname_serialise(t->name), c->trace_type); codegen_startfun(c, t->deserialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->deserialise_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->deserialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->deserialise_fn, 1); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); gendeserialise_typeid(c, t, object); // Deserialise the array contents. LLVMValueRef alloc = field_value(c, object, 2); LLVMValueRef ptr_offset = field_value(c, object, 3); ptr_offset = LLVMBuildPtrToInt(c->builder, ptr_offset, c->intptr, ""); ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); reach_type_t* t_elem = reach_type(c->reach, typearg); size_t abisize = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, abisize, false); LLVMValueRef args[3]; args[0] = ctx; args[1] = ptr_offset; args[2] = LLVMBuildMul(c->builder, alloc, l_size, ""); LLVMValueRef ptr = gencall_runtime(c, "pony_deserialise_block", args, 3, ""); LLVMValueRef ptr_loc = LLVMBuildStructGEP(c->builder, object, 3, ""); LLVMBuildStore(c->builder, ptr, ptr_loc); if((t_elem->underlying == TK_PRIMITIVE) && (t_elem->primitive != NULL)) { // Do nothing. A memcpy is sufficient. } else { LLVMValueRef size = field_value(c, object, 1); ptr = LLVMBuildBitCast(c->builder, ptr, LLVMPointerType(t_elem->use_type, 0), ""); LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef cond_block = codegen_block(c, "cond"); LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMBuildBr(c->builder, cond_block); // While the index is less than the size, deserialise an element. The // initial index when coming from the entry block is zero. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->intptr, ""); LLVMValueRef zero = LLVMConstInt(c->intptr, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, size, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get the element and deserialise it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, ptr, &phi, 1, ""); gendeserialise_element(c, t_elem, false, ctx, elem_ptr); // Add one to the phi node and branch back to the cond block. LLVMValueRef one = LLVMConstInt(c->intptr, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); body_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &inc, &body_block, 1); LLVMBuildBr(c->builder, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); } LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }
void genprim_array_serialise(compile_t* c, reach_type_t* t) { // Generate the serialise function. t->serialise_fn = codegen_addfun(c, genname_serialise(t->name), c->serialise_type); codegen_startfun(c, t->serialise_fn, NULL, NULL); LLVMSetFunctionCallConv(t->serialise_fn, LLVMCCallConv); LLVMValueRef ctx = LLVMGetParam(t->serialise_fn, 0); LLVMValueRef arg = LLVMGetParam(t->serialise_fn, 1); LLVMValueRef addr = LLVMGetParam(t->serialise_fn, 2); LLVMValueRef offset = LLVMGetParam(t->serialise_fn, 3); LLVMValueRef mut = LLVMGetParam(t->serialise_fn, 4); LLVMValueRef object = LLVMBuildBitCast(c->builder, arg, t->structure_ptr, ""); LLVMValueRef offset_addr = LLVMBuildAdd(c->builder, LLVMBuildPtrToInt(c->builder, addr, c->intptr, ""), offset, ""); genserialise_typeid(c, t, offset_addr); // Don't serialise our contents if we are opaque. LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntNE, mut, LLVMConstInt(c->i32, PONY_TRACE_OPAQUE, false), ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); LLVMPositionBuilderAtEnd(c->builder, body_block); // Write the size twice, effectively rewriting alloc to be the same as size. LLVMValueRef size = field_value(c, object, 1); LLVMValueRef size_loc = field_loc(c, offset_addr, t->structure, c->intptr, 1); LLVMBuildStore(c->builder, size, size_loc); LLVMValueRef alloc_loc = field_loc(c, offset_addr, t->structure, c->intptr, 2); LLVMBuildStore(c->builder, size, alloc_loc); // Write the pointer. LLVMValueRef ptr = field_value(c, object, 3); // The resulting offset will only be invalid (i.e. have the high bit set) if // the size is zero. For an opaque array, we don't serialise the contents, // so we don't get here, so we don't end up with an invalid offset. LLVMValueRef args[5]; args[0] = ctx; args[1] = ptr; LLVMValueRef ptr_offset = gencall_runtime(c, "pony_serialise_offset", args, 2, ""); LLVMValueRef ptr_loc = field_loc(c, offset_addr, t->structure, c->intptr, 3); LLVMBuildStore(c->builder, ptr_offset, ptr_loc); LLVMValueRef ptr_offset_addr = LLVMBuildAdd(c->builder, ptr_offset, LLVMBuildPtrToInt(c->builder, addr, c->intptr, ""), ""); // Serialise elements. ast_t* typeargs = ast_childidx(t->ast, 2); ast_t* typearg = ast_child(typeargs); reach_type_t* t_elem = reach_type(c->reach, typearg); size_t abisize = (size_t)LLVMABISizeOfType(c->target_data, t_elem->use_type); LLVMValueRef l_size = LLVMConstInt(c->intptr, abisize, false); if((t_elem->underlying == TK_PRIMITIVE) && (t_elem->primitive != NULL)) { // memcpy machine words args[0] = LLVMBuildIntToPtr(c->builder, ptr_offset_addr, c->void_ptr, ""); args[1] = LLVMBuildBitCast(c->builder, ptr, c->void_ptr, ""); args[2] = LLVMBuildMul(c->builder, size, l_size, ""); args[3] = LLVMConstInt(c->i32, 1, false); args[4] = LLVMConstInt(c->i1, 0, false); if(target_is_ilp32(c->opt->triple)) { gencall_runtime(c, "llvm.memcpy.p0i8.p0i8.i32", args, 5, ""); } else { gencall_runtime(c, "llvm.memcpy.p0i8.p0i8.i64", args, 5, ""); } } else { ptr = LLVMBuildBitCast(c->builder, ptr, LLVMPointerType(t_elem->use_type, 0), ""); LLVMBasicBlockRef entry_block = LLVMGetInsertBlock(c->builder); LLVMBasicBlockRef cond_block = codegen_block(c, "cond"); LLVMBasicBlockRef body_block = codegen_block(c, "body"); LLVMBasicBlockRef post_block = codegen_block(c, "post"); LLVMValueRef offset_var = LLVMBuildAlloca(c->builder, c->intptr, ""); LLVMBuildStore(c->builder, ptr_offset_addr, offset_var); LLVMBuildBr(c->builder, cond_block); // While the index is less than the size, serialise an element. The // initial index when coming from the entry block is zero. LLVMPositionBuilderAtEnd(c->builder, cond_block); LLVMValueRef phi = LLVMBuildPhi(c->builder, c->intptr, ""); LLVMValueRef zero = LLVMConstInt(c->intptr, 0, false); LLVMAddIncoming(phi, &zero, &entry_block, 1); LLVMValueRef test = LLVMBuildICmp(c->builder, LLVMIntULT, phi, size, ""); LLVMBuildCondBr(c->builder, test, body_block, post_block); // The phi node is the index. Get the element and serialise it. LLVMPositionBuilderAtEnd(c->builder, body_block); LLVMValueRef elem_ptr = LLVMBuildGEP(c->builder, ptr, &phi, 1, ""); ptr_offset_addr = LLVMBuildLoad(c->builder, offset_var, ""); genserialise_element(c, t_elem, false, ctx, elem_ptr, ptr_offset_addr); ptr_offset_addr = LLVMBuildAdd(c->builder, ptr_offset_addr, l_size, ""); LLVMBuildStore(c->builder, ptr_offset_addr, offset_var); // Add one to the phi node and branch back to the cond block. LLVMValueRef one = LLVMConstInt(c->intptr, 1, false); LLVMValueRef inc = LLVMBuildAdd(c->builder, phi, one, ""); body_block = LLVMGetInsertBlock(c->builder); LLVMAddIncoming(phi, &inc, &body_block, 1); LLVMBuildBr(c->builder, cond_block); LLVMPositionBuilderAtEnd(c->builder, post_block); } LLVMBuildBr(c->builder, post_block); LLVMPositionBuilderAtEnd(c->builder, post_block); LLVMBuildRetVoid(c->builder); codegen_finishfun(c); }