// 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 "ptx.tab.h" #include extern int ptx_error( const char *s ); extern int ptx_lineno; 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; } static bool g_debug_ir_generation=false; const char *g_filename; unsigned g_max_regs_per_thread = 0; // the program intermediate representation... static symbol_table *g_global_allfiles_symbol_table = NULL; static symbol_table *g_global_symbol_table = NULL; std::map g_sym_name_to_symbol_table; static symbol_table *g_current_symbol_table = NULL; static std::list g_instructions; static symbol *g_last_symbol = NULL; int g_error_detected = 0; // type specifier stuff: memory_space_t g_space_spec = undefined_space; memory_space_t g_ptr_spec = undefined_space; int g_scalar_type_spec = -1; int g_vector_spec = -1; int g_alignment_spec = -1; int g_extern_spec = 0; // variable declaration stuff: type_info *g_var_type = NULL; // instruction definition stuff: const symbol *g_pred; int g_neg_pred; int g_pred_mod; symbol *g_label; int g_opcode = -1; std::list g_operands; std::list g_options; std::list g_scalar_type; #define PTX_PARSE_DPRINTF(...) \ if( g_debug_ir_generation ) { \ printf(" %s:%u => ",g_filename,ptx_lineno); \ printf(" (%s:%u) ", __FILE__, __LINE__); \ printf(__VA_ARGS__); \ printf("\n"); \ fflush(stdout); \ } static unsigned g_entry_func_param_index=0; static function_info *g_func_info = NULL; static std::map g_ptx_token_decode; static operand_info g_return_var; const char *decode_token( int type ) { return g_ptx_token_decode[type].c_str(); } void 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; } } symbol_table *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); g_global_symbol_table = 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); } ptx_lineno = 1; #define DEF(X,Y) g_ptx_token_decode[X] = Y; #include "ptx_parser_decode.def" #undef DEF return g_global_symbol_table; } void 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_extern_spec = 0; g_scalar_type.clear(); g_operands.clear(); g_last_symbol = NULL; } void 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_return_var = operand_info(); init_directive_state(); } static int g_entry_point; void 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; } char *g_add_identifier_cached__identifier = NULL; int g_add_identifier_cached__array_dim; int g_add_identifier_cached__array_ident; void 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_lineno ); } //Jin: handle instruction group for cdp void start_inst_group() { PTX_PARSE_DPRINTF("start_instruction_group"); g_current_symbol_table = g_current_symbol_table->start_inst_group(); } void end_inst_group() { PTX_PARSE_DPRINTF("end_instruction_group"); g_current_symbol_table = g_current_symbol_table->end_inst_group(); } void add_directive() { PTX_PARSE_DPRINTF("add_directive"); init_directive_state(); } #define mymax(a,b) ((a)>(b)?(a):(b)) void 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 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_lineno, buf, file, line); ptx_error(NULL); abort(); exit(1); } void 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); } extern char linebuf[1024]; void 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 add_instruction() { PTX_PARSE_DPRINTF("add_instruction: %s", ((g_opcode>0)?g_opcode_string[g_opcode]:"