Beispiel #1
0
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;
}