// Copyright (c) 2009-2011, Tor M. Aamodt, Ali Bakhoda, Wilson W.L. Fung // The University of British Columbia // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // Redistributions of source code must retain the above copyright notice, this // list of conditions and the following disclaimer. // Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. Neither the name of // The University of British Columbia nor the names of its contributors may be // used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. #include "ptx_parser.h" #include "../../libcuda/gpgpu_context.h" #include "ptx_ir.h" typedef void *yyscan_t; #include #include "ptx.tab.h" extern int ptx_get_lineno(yyscan_t yyscanner); extern YYSTYPE *ptx_get_lval(yyscan_t yyscanner); extern int ptx_error(yyscan_t yyscanner, ptx_recognizer *recognizer, const char *s); extern int ptx_lex_init(yyscan_t *scanner); extern void ptx_set_in(FILE *_in_str, yyscan_t yyscanner); extern FILE *ptx_get_in(yyscan_t yyscanner); extern int ptx_parse(yyscan_t scanner, ptx_recognizer *recognizer); extern int ptx_lex_destroy(yyscan_t scanner); void ptx_recognizer::set_ptx_warp_size(const struct core_config *warp_size) { g_shader_core_config = warp_size; } #define PTX_PARSE_DPRINTF(...) \ if (g_debug_ir_generation) { \ printf(" %s:%u => ", gpgpu_ctx->g_filename, ptx_get_lineno(scanner)); \ printf(" (%s:%u) ", __FILE__, __LINE__); \ printf(__VA_ARGS__); \ printf("\n"); \ fflush(stdout); \ } static std::map g_ptx_token_decode; const char *decode_token(int type) { return g_ptx_token_decode[type].c_str(); } void ptx_recognizer::read_parser_environment_variables() { gpgpu_ctx->g_filename = getenv("PTX_SIM_KERNELFILE"); char *dbg_level = getenv("PTX_SIM_DEBUG"); if (dbg_level && strlen(dbg_level)) { int debug_execution = 0; sscanf(dbg_level, "%d", &debug_execution); if (debug_execution >= 30) g_debug_ir_generation = true; } } void ptx_recognizer::init_directive_state() { PTX_PARSE_DPRINTF("init_directive_state"); g_space_spec = undefined_space; g_ptr_spec = undefined_space; g_scalar_type_spec = -1; g_vector_spec = -1; g_opcode = -1; g_alignment_spec = -1; g_size = -1; g_extern_spec = 0; g_scalar_type.clear(); g_operands.clear(); g_last_symbol = NULL; } void ptx_recognizer::init_instruction_state() { PTX_PARSE_DPRINTF("init_instruction_state"); g_pred = NULL; g_neg_pred = 0; g_pred_mod = -1; g_label = NULL; g_opcode = -1; g_options.clear(); g_wmma_options.clear(); g_return_var = operand_info(gpgpu_ctx); init_directive_state(); } symbol_table *gpgpu_context::init_parser(const char *ptx_filename) { g_filename = strdup(ptx_filename); if (g_global_allfiles_symbol_table == NULL) { g_global_allfiles_symbol_table = new symbol_table("global_allfiles", 0, NULL, this); ptx_parser->g_global_symbol_table = ptx_parser->g_current_symbol_table = g_global_allfiles_symbol_table; } /*else { g_global_symbol_table = g_current_symbol_table = new symbol_table("global",0,g_global_allfiles_symbol_table); }*/ #define DEF(X, Y) g_ptx_token_decode[X] = Y; #include "ptx_parser_decode.def" #undef DEF g_ptx_token_decode[undefined_space] = "undefined_space"; g_ptx_token_decode[undefined_space] = "undefined_space=0"; g_ptx_token_decode[reg_space] = "reg_space"; g_ptx_token_decode[local_space] = "local_space"; g_ptx_token_decode[shared_space] = "shared_space"; g_ptx_token_decode[param_space_unclassified] = "param_space_unclassified"; g_ptx_token_decode[param_space_kernel] = "param_space_kernel"; g_ptx_token_decode[param_space_local] = "param_space_local"; g_ptx_token_decode[const_space] = "const_space"; g_ptx_token_decode[tex_space] = "tex_space"; g_ptx_token_decode[surf_space] = "surf_space"; g_ptx_token_decode[global_space] = "global_space"; g_ptx_token_decode[generic_space] = "generic_space"; g_ptx_token_decode[instruction_space] = "instruction_space"; ptx_lex_init(&(ptx_parser->scanner)); ptx_parser->init_directive_state(); ptx_parser->init_instruction_state(); FILE *ptx_in; ptx_in = fopen(ptx_filename, "r"); ptx_set_in(ptx_in, ptx_parser->scanner); ptx_parse(ptx_parser->scanner, ptx_parser); ptx_in = ptx_get_in(ptx_parser->scanner); ptx_lex_destroy(ptx_parser->scanner); fclose(ptx_in); return ptx_parser->g_global_symbol_table; } void ptx_recognizer::start_function(int entry_point) { PTX_PARSE_DPRINTF("start_function"); init_directive_state(); init_instruction_state(); g_entry_point = entry_point; g_func_info = NULL; g_entry_func_param_index = 0; } void ptx_recognizer::add_function_name(const char *name) { PTX_PARSE_DPRINTF( "add_function_name %s %s", name, ((g_entry_point == 1) ? "(entrypoint)" : ((g_entry_point == 2) ? "(extern)" : ""))); bool prior_decl = g_global_symbol_table->add_function_decl( name, g_entry_point, &g_func_info, &g_current_symbol_table); if (g_add_identifier_cached__identifier) { add_identifier(g_add_identifier_cached__identifier, g_add_identifier_cached__array_dim, g_add_identifier_cached__array_ident); free(g_add_identifier_cached__identifier); g_add_identifier_cached__identifier = NULL; g_func_info->add_return_var(g_last_symbol); init_directive_state(); } if (prior_decl) { g_func_info->remove_args(); } g_global_symbol_table->add_function(g_func_info, gpgpu_ctx->g_filename, ptx_get_lineno(scanner)); } // Jin: handle instruction group for cdp void ptx_recognizer::start_inst_group() { PTX_PARSE_DPRINTF("start_instruction_group"); g_current_symbol_table = g_current_symbol_table->start_inst_group(); } void ptx_recognizer::end_inst_group() { PTX_PARSE_DPRINTF("end_instruction_group"); g_current_symbol_table = g_current_symbol_table->end_inst_group(); } void ptx_recognizer::add_directive() { PTX_PARSE_DPRINTF("add_directive"); init_directive_state(); } #define mymax(a, b) ((a) > (b) ? (a) : (b)) void ptx_recognizer::end_function() { PTX_PARSE_DPRINTF("end_function"); init_directive_state(); init_instruction_state(); g_max_regs_per_thread = mymax(g_max_regs_per_thread, (g_current_symbol_table->next_reg_num() - 1)); g_func_info->add_inst(g_instructions); g_instructions.clear(); gpgpu_ptx_assemble(g_func_info->get_name(), g_func_info); g_current_symbol_table = g_global_symbol_table; PTX_PARSE_DPRINTF("function %s, PC = %llu\n", g_func_info->get_name().c_str(), g_func_info->get_start_PC()); } #define parse_error(msg, ...) \ parse_error_impl(__FILE__, __LINE__, msg, ##__VA_ARGS__) #define parse_assert(cond, msg, ...) \ parse_assert_impl((cond), __FILE__, __LINE__, msg, ##__VA_ARGS__) void ptx_recognizer::parse_error_impl(const char *file, unsigned line, const char *msg, ...) { va_list ap; char buf[1024]; va_start(ap, msg); vsnprintf(buf, 1024, msg, ap); va_end(ap); g_error_detected = 1; printf("%s:%u: Parse error: %s (%s:%u)\n\n", gpgpu_ctx->g_filename, ptx_get_lineno(scanner), buf, file, line); ptx_error(scanner, this, NULL); abort(); exit(1); } void ptx_recognizer::parse_assert_impl(int test_value, const char *file, unsigned line, const char *msg, ...) { va_list ap; char buf[1024]; va_start(ap, msg); vsnprintf(buf, 1024, msg, ap); va_end(ap); if (test_value == 0) parse_error_impl(file, line, msg); } void ptx_recognizer::set_return() { parse_assert((g_opcode == CALL_OP || g_opcode == CALLP_OP), "only call can have return value"); g_operands.front().set_return(); g_return_var = g_operands.front(); } const ptx_instruction *ptx_recognizer::ptx_instruction_lookup( const char *filename, unsigned linenumber) { std::map >::iterator f = g_inst_lookup.find(filename); if (f == g_inst_lookup.end()) return NULL; std::map::iterator l = f->second.find(linenumber); if (l == f->second.end()) return NULL; return l->second; } void ptx_recognizer::add_instruction() { PTX_PARSE_DPRINTF("add_instruction: %s", ((g_opcode > 0) ? g_opcode_string[g_opcode] : "