int main (int argc, char *argv[]) { char *p; int x; initlocale (); if (!argv[1] || !(*argv[1])) { usage (argv[0]); exit (1); } else while ((x=getopt(argc, argv, "VBhvsxze:f:c:")) != EOF) { switch (x) { case 'V': print_version (); exit (0); break; case 'h': usage (argv[0]); exit (0); break; case 'v': ST.verbose_mode = 1; break; case 's': ST.verbose_mode = 1; ST.vverbose_mode = 1; break; case 'c': ST.count = preprocess_retries (optarg); if (ST.count == -1) exit (1); break; case 'e': ST.exit_code = preprocess_code (optarg); if (ST.exit_code == -1) exit (1); break; case 'f': ST.forktime = preprocess_time (optarg); if (ST.forktime == -1) exit (1); break; case 'n': ST.nohup = 1; break; case 'x': ST.pscan = 1; break; case 'z': ST.always_zero = 1; break; case 'B': ST.buster = 1; break; default : usage (argv[0]); exit (0); break; } } if (argv[optind] == NULL || argv[optind] == '\0') { usage (argv[0]); exit (0); } command_name[sizeof(command_name)-1] = '\0'; strncpy (command_name, argv[optind], sizeof(command_name)-2); if ((p = strchr (command_name, ' '))) *p = '\0'; command[sizeof(command)-1] = '\0'; strncpy (command, argv[optind], sizeof(command)-2); if (ST.pscan) VERB fprintf (stderr, _("spawn: CPR mode enabled\n" " exit code cannot be resolved due to alternate scanning method\n")); init_invokes (); init_signals (); invoke_here (command); signals_start (); return (0); }
void oclraster_program::process_program(const string& raw_code, const kernel_spec default_spec) { // preprocess const string code = preprocess_code(raw_code); // parse static const array<const pair<const char*, const STRUCT_TYPE>, 6> oclraster_struct_types { { { u8"oclraster_in", STRUCT_TYPE::INPUT }, { u8"oclraster_out", STRUCT_TYPE::OUTPUT }, { u8"oclraster_uniforms", STRUCT_TYPE::UNIFORMS }, { u8"oclraster_buffers", STRUCT_TYPE::BUFFERS }, { u8"oclraster_images", STRUCT_TYPE::IMAGES }, { u8"oclraster_framebuffer", STRUCT_TYPE::FRAMEBUFFER } } }; static const set<const string> specifiers { "read_only", "write_only", "read_write" }; // current oclraster_struct grammar limitations/requirements: // * no interior/nested structs/unions // * no multi-variable declarations (e.g. "float x, y, z;") // * no __attribute__ (oclraster_structs already have a __attribute__ qualifier) // * use of any oclraster_struct specifier in other places is disallowed (no typedefs, comments, ...) // * otherwise standard OpenCL C // // example: // oclraster_in vertex_input { // float4 vertex; // float4 normal; // float2 tex_coord; // } inputs; // vector<size2> image_struct_positions; try { // parse and extract for(const auto& type : oclraster_struct_types) { size_t struct_pos = 0; while((struct_pos = code.find(type.first, struct_pos)) != string::npos) { // find first ' ' space char and open '{' bracket and extract the structs name const size_t space_pos = code.find_first_of(" {", struct_pos); const size_t open_bracket_pos = code.find("{", struct_pos); if(space_pos == string::npos || code[space_pos] == '{') throw oclraster_exception("no struct name"); if(open_bracket_pos == string::npos) throw oclraster_exception("no struct open bracket"); const string struct_name = core::trim(code.substr(space_pos+1, open_bracket_pos-space_pos-1)); //oclr_msg("struct type: \"%s\"", type.first); //oclr_msg("struct name: \"%s\"", struct_name); // open/close bracket match size_t bracket_pos = open_bracket_pos; size_t open_bracket_count = 1; while(open_bracket_count > 0) { bracket_pos = code.find_first_of("{}", bracket_pos + 1); if(bracket_pos == string::npos) throw oclraster_exception("struct open/close bracket mismatch"); code[bracket_pos] == '{' ? open_bracket_count++ : open_bracket_count--; } const size_t close_bracket_pos = bracket_pos; // const size_t end_semicolon_pos = code.find(";", close_bracket_pos+1); if(end_semicolon_pos == string::npos) { throw oclraster_exception("end-semicolon missing from struct \""+struct_name+"\"!"); } const string object_name = core::trim(code.substr(close_bracket_pos+1, end_semicolon_pos-close_bracket_pos-1)); //oclr_msg("object name: \"%s\"", object_name); // string struct_interior = code.substr(open_bracket_pos+1, close_bracket_pos-open_bracket_pos-1); //oclr_msg("struct interior:\n\t%s\n", struct_interior); // strip unnecessary whitespace and comments, and condense static const regex rx_space("\\s+", regex::optimize); static const regex rx_semicolon_space("[ ]*;[ ]*", regex::optimize); static const regex rx_newline("\n|\r", regex::optimize); static const regex rx_comments_sl("//(.*)", regex::optimize); static const regex rx_comments_ml("/\\*(.*)\\*/", regex::optimize); struct_interior = regex_replace(struct_interior, rx_comments_sl, ""); struct_interior = regex_replace(struct_interior, rx_newline, ""); struct_interior = regex_replace(struct_interior, rx_comments_ml, ""); struct_interior = regex_replace(struct_interior, rx_space, " "); struct_interior = regex_replace(struct_interior, rx_semicolon_space, ";"); struct_interior = core::trim(struct_interior); //oclr_msg("post-regex interior: >%s<", struct_interior); // extract all member variables vector<string> variable_names, variable_types, variable_specifiers; size_t semicolon_pos = 0, last_semicolon_pos = 0; while((semicolon_pos = struct_interior.find(";", last_semicolon_pos)) != string::npos) { const string var_decl = struct_interior.substr(last_semicolon_pos, semicolon_pos-last_semicolon_pos); //oclr_msg("decl: >%s<", var_decl); const size_t name_start_pos = var_decl.rfind(" "); if(name_start_pos == string::npos) { throw oclraster_exception("invalid variable declaration: \""+var_decl+"\""); } const string var_name = var_decl.substr(name_start_pos+1, var_decl.length()-name_start_pos-1); //oclr_msg("name: >%s<", var_name); variable_names.emplace_back(var_name); // check if type has an additional specifier (for images: read_only, write_only, read_write) const size_t type_start_pos = var_decl.find(" "); const string start_token = var_decl.substr(0, type_start_pos); if(specifiers.find(start_token) != specifiers.end()) { const string var_type = regex_replace(var_decl.substr(type_start_pos+1, name_start_pos-type_start_pos-1), rx_space, ""); // need to strip any whitespace //oclr_msg("type (s): >%s<", var_type); variable_types.emplace_back(var_type); const string var_spec = var_decl.substr(0, type_start_pos); //oclr_msg("spec: >%s<", var_spec); variable_specifiers.emplace_back(var_spec); } else { const string var_type = core::trim(var_decl.substr(0, name_start_pos)); //oclr_msg("type: >%s<", var_type); variable_types.emplace_back(var_type); variable_specifiers.emplace_back(""); } // continue last_semicolon_pos = semicolon_pos+1; } // create info struct if(type.second != STRUCT_TYPE::IMAGES && type.second != STRUCT_TYPE::FRAMEBUFFER) { const bool empty = (variable_names.size() == 0); // can't use variable_names when moving structs.push_back(new oclraster_struct_info { type.second, size2(struct_pos, end_semicolon_pos+1), struct_name, object_name, std::move(variable_names), std::move(variable_types), std::move(variable_specifiers), empty, {} }); } else { image_struct_positions.emplace_back(size2 { struct_pos, end_semicolon_pos+1 }); process_image_struct(variable_names, variable_types, variable_specifiers, (type.second == STRUCT_TYPE::FRAMEBUFFER)); } // continue struct_pos++; } } // process found structs for(auto& oclr_struct : structs) { if(oclr_struct->empty) continue; if(oclr_struct->type == STRUCT_TYPE::BUFFERS) continue; generate_struct_info_cl_program(*oclr_struct); } // order sort(structs.begin(), structs.end(), [](const oclraster_struct_info* info_0, const oclraster_struct_info* info_1) -> bool { return info_0->code_pos.x < info_1->code_pos.x; }); // write framebuffer struct bool has_framebuffer = false; string framebuffer_code = "typedef struct __attribute__((packed)) {\n"; for(size_t i = 0, fb_img_idx = 0, image_count = images.image_names.size(); i < image_count; i++) { if(!images.is_framebuffer[i]) continue; has_framebuffer = true; // TODO: for now, let the access always be read/write, so "const data" (depth) can be modified // between user program calls (downside: user has also read/write access -> create 2 structs?) /*if(images.image_specifiers[i] == ACCESS_TYPE::READ) { framebuffer_code += "const "; }*/ framebuffer_code += "###OCLRASTER_FRAMEBUFFER_IMAGE_" + size_t2string(fb_img_idx) + "### " + images.image_names[i] + ";\n"; fb_img_idx++; } framebuffer_code += "} oclraster_framebuffer;\n"; // recreate structs (in reverse, so that the offsets stay valid) processed_code = code; const size_t struct_count = structs.size() + image_struct_positions.size(); for(size_t i = 0, cur_struct = structs.size(), cur_image = image_struct_positions.size(); i < struct_count; i++) { // figure out which struct comes next (normal struct or image struct) size_t image_code_pos = 0, struct_code_pos = 0; if(cur_image > 0) image_code_pos = image_struct_positions[cur_image-1].x; if(cur_struct > 0) struct_code_pos = structs[cur_struct-1]->code_pos.x; // image if(image_code_pos > struct_code_pos) { cur_image--; processed_code.erase(image_struct_positions[cur_image].x, image_struct_positions[cur_image].y - image_struct_positions[cur_image].x); // insert framebuffer struct code at the last image or framebuffer struct position if(has_framebuffer && cur_image == (image_struct_positions.size()-1)) { processed_code.insert(image_struct_positions[cur_image].x, framebuffer_code); } } // struct else { cur_struct--; const oclraster_struct_info& oclr_struct = *structs[cur_struct]; processed_code.erase(oclr_struct.code_pos.x, oclr_struct.code_pos.y - oclr_struct.code_pos.x); if(!oclr_struct.empty && oclr_struct.type != STRUCT_TYPE::BUFFERS) { string struct_code = ""; switch(oclr_struct.type) { case STRUCT_TYPE::INPUT: struct_code += "oclraster_in"; break; case STRUCT_TYPE::OUTPUT: struct_code += "oclraster_out"; break; case STRUCT_TYPE::UNIFORMS: struct_code += "oclraster_uniforms"; break; case STRUCT_TYPE::BUFFERS: case STRUCT_TYPE::IMAGES: case STRUCT_TYPE::FRAMEBUFFER: oclr_unreachable(); } struct_code += " {\n"; for(size_t var_index = 0; var_index < oclr_struct.variables.size(); var_index++) { struct_code += oclr_struct.variable_types[var_index] + " " + oclr_struct.variables[var_index] + ";\n"; } struct_code += "} " + oclr_struct.name + ";\n"; processed_code.insert(oclr_struct.code_pos.x, struct_code); } } } // remove empty structs for(auto iter = structs.begin(); iter != structs.end();) { if((*iter)->empty) { delete *iter; iter = structs.erase(iter); } else iter++; } // build entry function parameter string const string entry_function_params = create_entry_function_parameters(); // check if entry function exists, and if so, replace it with a modified function name const regex rx_entry_function("("+entry_function+")\\s*\\(\\s*\\)", regex::optimize); if(!regex_search(code, rx_entry_function)) { throw oclraster_exception("entry function \""+entry_function+"\" not found!"); } processed_code = regex_replace(processed_code, rx_entry_function, "OCLRASTER_FUNC oclraster_user_"+entry_function+"("+entry_function_params+")"); // create default/first/hinted image spec, do the final processing and compile kernel_spec spec { default_spec }; if(!images.image_names.empty() && spec.image_spec.size() != images.image_names.size()) { // create kernel image spec for the hinted or default image specs // note: if default_spec already contains some image_spec entries, only insert the remaining ones for(size_t i = spec.image_spec.size(); i < images.image_names.size(); i++) { spec.image_spec.emplace_back(images.image_hints[i].is_valid() ? images.image_hints[i] : image_type { IMAGE_TYPE::UINT_8, IMAGE_CHANNEL::RGBA }); } } else if(images.image_names.empty() && !spec.image_spec.empty()) { // default spec contains image_spec entries, but the are no images -> clear spec.image_spec.clear(); } // else: no images in kernel/program -> just one kernel / "empty image spec" build_kernel(spec); } catch(oclraster_exception& ex) { invalidate(ex.what()); } valid = true; }