// 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 "ptx_ir.h" #include "../../libcuda/gpgpu_context.h" typedef void * yyscan_t; #include "ptx.tab.h" #include extern int ptx_get_lineno (yyscan_t yyscanner ); extern YYSTYPE* ptx_get_lval (yyscan_t yyscanner ); extern int ptx_error( yyscan_t yyscanner, 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); static const struct core_config *g_shader_core_config; void set_ptx_warp_size(const struct core_config * warp_size) { g_shader_core_config=warp_size; } const char *g_filename; // the program intermediate representation... std::map g_sym_name_to_symbol_table; #define PTX_PARSE_DPRINTF(...) \ if( g_debug_ir_generation ) { \ printf(" %s:%u => ",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() { 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(); 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); 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; } static int g_entry_point; 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, 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 = %d\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", g_filename, ptx_get_lineno(scanner), buf, file, line); ptx_error(scanner, 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(); } std::map > g_inst_lookup; const ptx_instruction *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]:"