/* This function is called for each user statement in the AST, * i.e., for each kernel body statement, copy statement or sync statement. */ static __isl_give isl_printer *print_kernel_stmt(__isl_take isl_printer *p, __isl_take isl_ast_print_options *print_options, __isl_keep isl_ast_node *node, void *user) { isl_id *id; struct ppcg_kernel_stmt *stmt; id = isl_ast_node_get_annotation(node); stmt = isl_id_get_user(id); isl_id_free(id); isl_ast_print_options_free(print_options); switch (stmt->type) { case ppcg_kernel_copy: return ppcg_kernel_print_copy(p, stmt); case ppcg_kernel_sync: return print_sync(p, stmt); case ppcg_kernel_domain: return ppcg_kernel_print_domain(p, stmt); } return p; }
/* Print the user statement of the host code to "p". * * The host code may contain original user statements, kernel launches, * statements that copy data to/from the device and statements * the initialize or clear the device. * The original user statements and the kernel launches have * an associated annotation, while the other statements do not. * The latter are handled by print_device_node. * The annotation on the user statements is called "user". * * In case of a kernel launch, print a block of statements that * defines the grid and the block and then launches the kernel. */ static __isl_give isl_printer *print_host_user(__isl_take isl_printer *p, __isl_take isl_ast_print_options *print_options, __isl_keep isl_ast_node *node, void *user) { isl_id *id; int is_user; struct ppcg_kernel *kernel; struct ppcg_kernel_stmt *stmt; struct print_host_user_data *data; isl_ast_print_options_free(print_options); data = (struct print_host_user_data *) user; id = isl_ast_node_get_annotation(node); if (!id) { //p = isl_printer_print_str(p,"marker_NO_ID_CASE"); return print_device_node(p, node, data->prog); } is_user = !strcmp(isl_id_get_name(id), "user"); kernel = is_user ? NULL : isl_id_get_user(id); stmt = is_user ? isl_id_get_user(id) : NULL; isl_id_free(id); if (is_user) return ppcg_kernel_print_domain(p, stmt); p = ppcg_start_block(p); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "dim3 k"); p = isl_printer_print_int(p, kernel->id); p = isl_printer_print_str(p, "_dimBlock"); print_reverse_list(isl_printer_get_file(p), kernel->n_block, kernel->block_dim); p = isl_printer_print_str(p, ";"); p = isl_printer_end_line(p); p = print_grid(p, kernel); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "kernel"); p = isl_printer_print_int(p, kernel->id); p = isl_printer_print_str(p, " <<<k"); p = isl_printer_print_int(p, kernel->id); p = isl_printer_print_str(p, "_dimGrid, k"); p = isl_printer_print_int(p, kernel->id); p = isl_printer_print_str(p, "_dimBlock>>> ("); p = print_kernel_arguments(p, data->prog, kernel, 0); p = isl_printer_print_str(p, ");"); p = isl_printer_end_line(p); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "cudaCheckKernel();"); p = isl_printer_end_line(p); p = ppcg_end_block(p); p = isl_printer_start_line(p); p = isl_printer_end_line(p); p = copy_data_from_device_to_device(p,kernel); printf("printing kernel"); print_kernel(data->prog, kernel, data->cuda); printf("printing kernel done"); return p; }
/* Print the user statement of the host code to "p". * * The host code may contain original user statements, kernel launches and * statements that copy data to/from the device. * The original user statements and the kernel launches have * an associated annotation, while the data copy statements do not. * The latter are handled by print_to_from_device. * The annotation on the user statements is called "user". * * In case of a kernel launch, print a block of statements that * defines the grid and the work group and then launches the kernel. * * A grid is composed of many work groups (blocks), each work group holds * many work-items (threads). * * global_work_size[kernel->n_block] represents the total number of work * items. It points to an array of kernel->n_block unsigned * values that describe the total number of work-items that will execute * the kernel. The total number of work-items is computed as: * global_work_size[0] *...* global_work_size[kernel->n_block - 1]. * * The size of each work group (i.e. the number of work-items in each work * group) is described using block_size[kernel->n_block]. The total * number of work-items in a block (work-group) is computed as: * block_size[0] *... * block_size[kernel->n_block - 1]. * * For more information check: * http://www.khronos.org/registry/cl/sdk/1.0/docs/man/xhtml/clEnqueueNDRangeKernel.html */ static __isl_give isl_printer *opencl_print_host_user( __isl_take isl_printer *p, __isl_take isl_ast_print_options *print_options, __isl_keep isl_ast_node *node, void *user) { isl_id *id; int is_user; struct ppcg_kernel *kernel; struct ppcg_kernel_stmt *stmt; struct print_host_user_data_opencl *data; isl_ast_print_options_free(print_options); data = (struct print_host_user_data_opencl *) user; id = isl_ast_node_get_annotation(node); if (!id) return print_to_from_device(p, node, data->prog); is_user = !strcmp(isl_id_get_name(id), "user"); kernel = is_user ? NULL : isl_id_get_user(id); stmt = is_user ? isl_id_get_user(id) : NULL; isl_id_free(id); if (is_user) return ppcg_kernel_print_domain(p, stmt); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "{"); p = isl_printer_end_line(p); p = isl_printer_indent(p, 2); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "size_t global_work_size["); if (kernel->n_block > 0) p = isl_printer_print_int(p, kernel->n_block); else p = isl_printer_print_int(p, 1); p = isl_printer_print_str(p, "] = {"); p = opencl_print_total_number_of_work_items_as_list(p, kernel); p = isl_printer_print_str(p, "};"); p = isl_printer_end_line(p); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "size_t block_size["); if (kernel->n_block > 0) p = isl_printer_print_int(p, kernel->n_block); else p = isl_printer_print_int(p, 1); p = isl_printer_print_str(p, "] = {"); p = opencl_print_block_sizes(p, kernel); p = isl_printer_print_str(p, "};"); p = isl_printer_end_line(p); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "cl_kernel kernel"); p = isl_printer_print_int(p, kernel->id); p = isl_printer_print_str(p, " = clCreateKernel(program, \"kernel"); p = isl_printer_print_int(p, kernel->id); p = isl_printer_print_str(p, "\", &err);"); p = isl_printer_end_line(p); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "openclCheckReturn(err);"); p = isl_printer_end_line(p); opencl_set_kernel_arguments(p, data->prog, kernel); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "openclCheckReturn(clEnqueueNDRangeKernel" "(queue, kernel"); p = isl_printer_print_int(p, kernel->id); p = isl_printer_print_str(p, ", "); if (kernel->n_block > 0) p = isl_printer_print_int(p, kernel->n_block); else p = isl_printer_print_int(p, 1); p = isl_printer_print_str(p, ", NULL, global_work_size, " "block_size, " "0, NULL, NULL));"); p = isl_printer_end_line(p); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "openclCheckReturn(" "clReleaseKernel(kernel"); p = isl_printer_print_int(p, kernel->id); p = isl_printer_print_str(p, "));"); p = isl_printer_end_line(p); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "clFinish(queue);"); p = isl_printer_end_line(p); p = isl_printer_indent(p, -2); p = isl_printer_start_line(p); p = isl_printer_print_str(p, "}"); p = isl_printer_end_line(p); p = isl_printer_start_line(p); p = isl_printer_end_line(p); data->opencl->kprinter = opencl_print_kernel(data->prog, kernel, data->opencl->kprinter); return p; }
isl_ast_node * ast_gen::after_for(isl_ast_node *node, isl_ast_build * builder) { if (verbose<ast_gen>::enabled()) cout << "-- After for" << endl; bool is_deepest_loop = m_deepest_loop == m_current_loop; bool is_requested_parallel = false; { auto iter_expr = isl_ast_node_for_get_iterator(node); auto id = isl_ast_expr_get_id(iter_expr); if (verbose<ast_gen>::enabled()) cout << " Loop iter: " << isl_id_get_name(id) << endl; auto data = isl_id_get_user(id); if (data == &m_parallel_loop_id) { if (verbose<ast_gen>::enabled()) cout << " Requested as parallel" << endl; is_requested_parallel = true; } id = isl_id_free(id); isl_ast_expr_free(iter_expr); } auto id = isl_ast_node_get_annotation(node); auto info = ast_node_info::get_from_id(id); // Mark loop parallel if parallelizable and // either requested by user or outermost parallizable. if (!m_options.parallel) { if (verbose<ast_gen>::enabled()) cout << " Explicit parallelization not enabled." << endl; } else if (!info->is_parallelizable) { if (verbose<ast_gen>::enabled()) cout << " Not parallelizable." << endl; } else if (m_options.parallel_dim < 0) { if (m_num_parallelizable_loops != 1) { if (verbose<ast_gen>::enabled()) cout << " Not the outermost parallelizable loop." << endl; } else { info->is_parallel = true; } } else { if (!is_requested_parallel) { if (verbose<ast_gen>::enabled()) cout << " Not the requested parallel loop." << endl; } else { if (verbose<ast_gen>::enabled()) cout << " Parallelized." << endl; info->is_parallel = true; } } // Mark loop vectorized if parallelizable and deepest. if (m_options.vectorize && is_deepest_loop && info->is_parallelizable) { if (verbose<ast_gen>::enabled()) cout << "-- Loop vectorized." << endl; info->is_vector = true; } if (info->is_parallel || info->is_vector) { store_parallel_accesses_for_current_dimension(builder); } if (info->is_parallelizable) --m_num_parallelizable_loops; --m_current_loop; id = isl_id_free(id); return node; }