2012-04-25 15:22:16 +00:00
/*
2014-01-01 11:24:16 +00:00
* Copyright ( C ) 2012 , 2013 , 2014
2012-04-25 15:22:16 +00:00
* Wolfgang Bumiller
2013-05-29 03:29:04 +00:00
* Dale Weiler
2012-04-25 15:22:16 +00:00
*
* Permission is hereby granted , free of charge , to any person obtaining a copy of
* this software and associated documentation files ( the " Software " ) , to deal in
* the Software without restriction , including without limitation the rights to
* use , copy , modify , merge , publish , distribute , sublicense , and / or sell copies
* of the Software , and to permit persons to whom the Software is furnished to do
* so , subject to the following conditions :
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software .
*
* THE SOFTWARE IS PROVIDED " AS IS " , WITHOUT WARRANTY OF ANY KIND , EXPRESS OR
* IMPLIED , INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY ,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT . IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM , DAMAGES OR OTHER
* LIABILITY , WHETHER IN AN ACTION OF CONTRACT , TORT OR OTHERWISE , ARISING FROM ,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE .
*/
2012-04-25 12:43:23 +00:00
# include <stdlib.h>
# include <string.h>
2013-06-04 02:47:07 +00:00
2012-04-25 14:21:04 +00:00
# include "gmqcc.h"
2012-04-25 12:43:23 +00:00
# include "ir.h"
2012-06-25 17:27:50 +00:00
/***********************************************************************
* Type sizes used at multiple points in the IR codegen
*/
2012-07-20 19:19:30 +00:00
const char * type_name [ TYPE_COUNT ] = {
" void " ,
" string " ,
" float " ,
" vector " ,
" entity " ,
" field " ,
" function " ,
" pointer " ,
" integer " ,
2012-11-10 18:35:52 +00:00
" variant " ,
" struct " ,
" union " ,
2012-12-28 17:05:28 +00:00
" array " ,
2013-01-03 11:49:21 +00:00
" nil " ,
" <no-expression> "
2012-07-20 19:19:30 +00:00
} ;
2013-04-25 03:34:42 +00:00
static size_t type_sizeof_ [ TYPE_COUNT ] = {
2012-06-25 17:27:50 +00:00
1 , /* TYPE_VOID */
1 , /* TYPE_STRING */
1 , /* TYPE_FLOAT */
3 , /* TYPE_VECTOR */
1 , /* TYPE_ENTITY */
1 , /* TYPE_FIELD */
1 , /* TYPE_FUNCTION */
1 , /* TYPE_POINTER */
1 , /* TYPE_INTEGER */
2012-08-12 09:34:41 +00:00
3 , /* TYPE_VARIANT */
2012-11-10 18:35:52 +00:00
0 , /* TYPE_STRUCT */
0 , /* TYPE_UNION */
0 , /* TYPE_ARRAY */
2012-12-28 17:05:28 +00:00
0 , /* TYPE_NIL */
2013-01-03 11:49:21 +00:00
0 , /* TYPE_NOESPR */
2012-06-25 17:27:50 +00:00
} ;
2013-04-25 07:55:58 +00:00
const uint16_t type_store_instr [ TYPE_COUNT ] = {
2012-07-03 20:46:38 +00:00
INSTR_STORE_F , /* should use I when having integer support */
INSTR_STORE_S ,
INSTR_STORE_F ,
INSTR_STORE_V ,
INSTR_STORE_ENT ,
INSTR_STORE_FLD ,
INSTR_STORE_FNC ,
INSTR_STORE_ENT , /* should use I */
#if 0
2012-07-10 17:26:07 +00:00
INSTR_STORE_I , /* integer type */
2012-11-10 18:35:52 +00:00
# else
INSTR_STORE_F ,
2012-07-03 20:46:38 +00:00
# endif
2012-07-10 17:26:07 +00:00
2012-08-12 09:34:41 +00:00
INSTR_STORE_V , /* variant, should never be accessed */
2012-11-10 18:35:52 +00:00
2013-01-30 06:31:24 +00:00
VINSTR_END , /* struct */
VINSTR_END , /* union */
VINSTR_END , /* array */
VINSTR_END , /* nil */
VINSTR_END , /* noexpr */
2012-07-03 20:46:38 +00:00
} ;
2013-04-25 07:55:58 +00:00
const uint16_t field_store_instr [ TYPE_COUNT ] = {
2012-11-09 19:11:17 +00:00
INSTR_STORE_FLD ,
INSTR_STORE_FLD ,
INSTR_STORE_FLD ,
INSTR_STORE_V ,
INSTR_STORE_FLD ,
INSTR_STORE_FLD ,
INSTR_STORE_FLD ,
INSTR_STORE_FLD ,
#if 0
INSTR_STORE_FLD , /* integer type */
2012-11-10 18:35:52 +00:00
# else
INSTR_STORE_FLD ,
2012-11-09 19:11:17 +00:00
# endif
INSTR_STORE_V , /* variant, should never be accessed */
2012-11-10 18:35:52 +00:00
2013-01-30 06:31:24 +00:00
VINSTR_END , /* struct */
VINSTR_END , /* union */
VINSTR_END , /* array */
VINSTR_END , /* nil */
VINSTR_END , /* noexpr */
2012-11-09 19:11:17 +00:00
} ;
2013-04-25 07:55:58 +00:00
const uint16_t type_storep_instr [ TYPE_COUNT ] = {
2012-07-16 08:24:35 +00:00
INSTR_STOREP_F , /* should use I when having integer support */
INSTR_STOREP_S ,
INSTR_STOREP_F ,
INSTR_STOREP_V ,
INSTR_STOREP_ENT ,
INSTR_STOREP_FLD ,
INSTR_STOREP_FNC ,
INSTR_STOREP_ENT , /* should use I */
#if 0
INSTR_STOREP_ENT , /* integer type */
2012-11-10 18:35:52 +00:00
# else
INSTR_STOREP_F ,
2012-07-16 08:24:35 +00:00
# endif
2012-07-16 09:40:30 +00:00
2012-08-12 09:34:41 +00:00
INSTR_STOREP_V , /* variant, should never be accessed */
2012-11-10 18:35:52 +00:00
2013-01-30 06:31:24 +00:00
VINSTR_END , /* struct */
VINSTR_END , /* union */
VINSTR_END , /* array */
VINSTR_END , /* nil */
VINSTR_END , /* noexpr */
2012-07-16 08:24:35 +00:00
} ;
2013-04-25 07:55:58 +00:00
const uint16_t type_eq_instr [ TYPE_COUNT ] = {
2012-08-13 13:25:14 +00:00
INSTR_EQ_F , /* should use I when having integer support */
INSTR_EQ_S ,
INSTR_EQ_F ,
INSTR_EQ_V ,
INSTR_EQ_E ,
INSTR_EQ_E , /* FLD has no comparison */
INSTR_EQ_FNC ,
INSTR_EQ_E , /* should use I */
#if 0
INSTR_EQ_I ,
2012-11-10 18:35:52 +00:00
# else
INSTR_EQ_F ,
2012-08-13 13:25:14 +00:00
# endif
INSTR_EQ_V , /* variant, should never be accessed */
2012-11-10 18:35:52 +00:00
2013-01-30 06:31:24 +00:00
VINSTR_END , /* struct */
VINSTR_END , /* union */
VINSTR_END , /* array */
VINSTR_END , /* nil */
VINSTR_END , /* noexpr */
2012-08-13 13:25:14 +00:00
} ;
2013-04-25 07:55:58 +00:00
const uint16_t type_ne_instr [ TYPE_COUNT ] = {
2012-08-13 13:25:14 +00:00
INSTR_NE_F , /* should use I when having integer support */
INSTR_NE_S ,
INSTR_NE_F ,
INSTR_NE_V ,
INSTR_NE_E ,
INSTR_NE_E , /* FLD has no comparison */
INSTR_NE_FNC ,
INSTR_NE_E , /* should use I */
#if 0
INSTR_NE_I ,
2012-11-10 18:35:52 +00:00
# else
INSTR_NE_F ,
2012-08-13 13:25:14 +00:00
# endif
INSTR_NE_V , /* variant, should never be accessed */
2012-11-10 18:35:52 +00:00
2013-01-30 06:31:24 +00:00
VINSTR_END , /* struct */
VINSTR_END , /* union */
VINSTR_END , /* array */
VINSTR_END , /* nil */
VINSTR_END , /* noexpr */
2012-08-13 13:25:14 +00:00
} ;
2013-04-25 07:55:58 +00:00
const uint16_t type_not_instr [ TYPE_COUNT ] = {
2012-11-21 18:36:28 +00:00
INSTR_NOT_F , /* should use I when having integer support */
2013-04-25 07:55:58 +00:00
VINSTR_END , /* not to be used, depends on string related -f flags */
2012-11-21 18:36:28 +00:00
INSTR_NOT_F ,
INSTR_NOT_V ,
INSTR_NOT_ENT ,
INSTR_NOT_ENT ,
INSTR_NOT_FNC ,
INSTR_NOT_ENT , /* should use I */
#if 0
INSTR_NOT_I , /* integer type */
# else
INSTR_NOT_F ,
# endif
INSTR_NOT_V , /* variant, should never be accessed */
2013-01-30 06:31:24 +00:00
VINSTR_END , /* struct */
VINSTR_END , /* union */
VINSTR_END , /* array */
VINSTR_END , /* nil */
VINSTR_END , /* noexpr */
2012-11-21 18:36:28 +00:00
} ;
2012-12-01 10:43:54 +00:00
/* protos */
2013-05-29 03:29:04 +00:00
static ir_value * ir_value_var ( const char * name , int st , int vtype ) ;
static bool ir_value_set_name ( ir_value * , const char * name ) ;
static void ir_value_dump ( ir_value * , int ( * oprintf ) ( const char * , . . . ) ) ;
static ir_value * ir_gen_extparam_proto ( ir_builder * ir ) ;
2013-06-20 10:52:58 +00:00
static void ir_gen_extparam ( ir_builder * ir ) ;
2013-05-29 03:29:04 +00:00
static bool ir_builder_set_name ( ir_builder * self , const char * name ) ;
static ir_function * ir_function_new ( struct ir_builder_s * owner , int returntype ) ;
static bool ir_function_set_name ( ir_function * , const char * name ) ;
static void ir_function_delete ( ir_function * ) ;
static void ir_function_dump ( ir_function * , char * ind , int ( * oprintf ) ( const char * , . . . ) ) ;
2013-07-30 16:00:51 +00:00
static ir_value * ir_block_create_general_instr ( ir_block * self , lex_ctx_t , const char * label ,
2013-05-29 03:29:04 +00:00
int op , ir_value * a , ir_value * b , int outype ) ;
static void ir_block_delete ( ir_block * ) ;
static ir_block * ir_block_new ( struct ir_function_s * owner , const char * label ) ;
2013-07-30 16:00:51 +00:00
static bool GMQCC_WARN ir_block_create_store ( ir_block * , lex_ctx_t , ir_value * target , ir_value * what ) ;
2013-05-29 03:29:04 +00:00
static bool ir_block_set_label ( ir_block * , const char * label ) ;
static void ir_block_dump ( ir_block * , char * ind , int ( * oprintf ) ( const char * , . . . ) ) ;
static bool ir_instr_op ( ir_instr * , int op , ir_value * value , bool writing ) ;
static void ir_instr_delete ( ir_instr * ) ;
static void ir_instr_dump ( ir_instr * in , char * ind , int ( * oprintf ) ( const char * , . . . ) ) ;
2012-12-01 10:43:54 +00:00
/* error functions */
2013-07-30 16:00:51 +00:00
static void irerror ( lex_ctx_t ctx , const char * msg , . . . )
2012-08-14 11:14:32 +00:00
{
va_list ap ;
va_start ( ap , msg ) ;
2013-07-30 16:00:51 +00:00
con_cvprintmsg ( ctx , LVL_ERROR , " internal error " , msg , ap ) ;
2012-08-14 11:14:32 +00:00
va_end ( ap ) ;
}
2013-09-18 14:18:29 +00:00
static bool GMQCC_WARN irwarning ( lex_ctx_t ctx , int warntype , const char * fmt , . . . )
2012-08-19 19:26:14 +00:00
{
2012-12-17 17:25:06 +00:00
bool r ;
2012-12-18 04:57:17 +00:00
va_list ap ;
va_start ( ap , fmt ) ;
r = vcompile_warning ( ctx , warntype , fmt , ap ) ;
va_end ( ap ) ;
return r ;
2012-08-19 19:26:14 +00:00
}
2012-04-25 12:47:20 +00:00
/***********************************************************************
2012-11-15 17:32:03 +00:00
* Vector utility functions
*/
2013-05-29 03:29:04 +00:00
static bool GMQCC_WARN vec_ir_value_find ( ir_value * * vec , const ir_value * what , size_t * idx )
2012-11-15 17:32:03 +00:00
{
size_t i ;
size_t len = vec_size ( vec ) ;
for ( i = 0 ; i < len ; + + i ) {
if ( vec [ i ] = = what ) {
if ( idx ) * idx = i ;
return true ;
}
}
return false ;
}
2013-05-29 03:29:04 +00:00
static bool GMQCC_WARN vec_ir_block_find ( ir_block * * vec , ir_block * what , size_t * idx )
2012-11-15 17:32:03 +00:00
{
size_t i ;
size_t len = vec_size ( vec ) ;
for ( i = 0 ; i < len ; + + i ) {
if ( vec [ i ] = = what ) {
if ( idx ) * idx = i ;
return true ;
}
}
return false ;
}
2013-05-29 03:29:04 +00:00
static bool GMQCC_WARN vec_ir_instr_find ( ir_instr * * vec , ir_instr * what , size_t * idx )
2012-11-15 17:32:03 +00:00
{
size_t i ;
size_t len = vec_size ( vec ) ;
for ( i = 0 ; i < len ; + + i ) {
if ( vec [ i ] = = what ) {
if ( idx ) * idx = i ;
return true ;
}
}
return false ;
}
/***********************************************************************
* IR Builder
2012-04-25 12:47:20 +00:00
*/
2012-08-24 18:39:47 +00:00
static void ir_block_delete_quick ( ir_block * self ) ;
static void ir_instr_delete_quick ( ir_instr * self ) ;
static void ir_function_delete_quick ( ir_function * self ) ;
2012-04-25 12:43:23 +00:00
ir_builder * ir_builder_new ( const char * modulename )
{
2012-04-25 12:46:10 +00:00
ir_builder * self ;
2013-08-26 08:25:29 +00:00
size_t i ;
2012-04-25 12:43:23 +00:00
2012-04-25 12:46:10 +00:00
self = ( ir_builder * ) mem_a ( sizeof ( * self ) ) ;
2012-05-09 12:24:35 +00:00
if ( ! self )
return NULL ;
2012-11-15 17:32:03 +00:00
self - > functions = NULL ;
self - > globals = NULL ;
self - > fields = NULL ;
self - > filenames = NULL ;
self - > filestrings = NULL ;
2012-11-25 12:37:54 +00:00
self - > htglobals = util_htnew ( IR_HT_SIZE ) ;
self - > htfields = util_htnew ( IR_HT_SIZE ) ;
self - > htfunctions = util_htnew ( IR_HT_SIZE ) ;
2012-11-15 17:32:03 +00:00
2012-12-25 22:25:59 +00:00
self - > extparams = NULL ;
self - > extparam_protos = NULL ;
2012-12-26 22:18:45 +00:00
self - > first_common_globaltemp = 0 ;
self - > max_globaltemps = 0 ;
self - > first_common_local = 0 ;
self - > max_locals = 0 ;
2012-12-23 15:31:01 +00:00
2012-08-24 17:52:06 +00:00
self - > str_immediate = 0 ;
2012-04-25 12:46:10 +00:00
self - > name = NULL ;
2012-04-27 11:28:39 +00:00
if ( ! ir_builder_set_name ( self , modulename ) ) {
mem_d ( self ) ;
return NULL ;
}
2012-04-25 12:43:23 +00:00
2012-12-28 17:05:28 +00:00
self - > nil = ir_value_var ( " nil " , store_value , TYPE_NIL ) ;
self - > nil - > cvq = CV_CONST ;
2013-08-26 08:25:29 +00:00
for ( i = 0 ; i ! = IR_MAX_VINSTR_TEMPS ; + + i ) {
/* we write to them, but they're not supposed to be used outside the IR, so
* let ' s not allow the generation of ir_instrs which use these .
* So it ' s a constant noexpr .
*/
self - > vinstr_temp [ i ] = ir_value_var ( " vinstr_temp " , store_value , TYPE_NOEXPR ) ;
self - > vinstr_temp [ i ] - > cvq = CV_CONST ;
}
2013-01-12 12:29:47 +00:00
self - > reserved_va_count = NULL ;
2014-01-07 13:33:26 +00:00
self - > coverage_func = NULL ;
2013-06-20 10:52:58 +00:00
self - > code = code_init ( ) ;
2013-01-12 12:29:47 +00:00
2012-04-25 12:46:10 +00:00
return self ;
2012-04-25 12:43:23 +00:00
}
void ir_builder_delete ( ir_builder * self )
{
2012-04-25 12:46:10 +00:00
size_t i ;
2012-11-25 12:37:54 +00:00
util_htdel ( self - > htglobals ) ;
util_htdel ( self - > htfields ) ;
util_htdel ( self - > htfunctions ) ;
2012-04-25 12:46:10 +00:00
mem_d ( ( void * ) self - > name ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( self - > functions ) ; + + i ) {
2012-08-24 18:39:47 +00:00
ir_function_delete_quick ( self - > functions [ i ] ) ;
2012-04-25 12:46:10 +00:00
}
2012-11-15 17:32:03 +00:00
vec_free ( self - > functions ) ;
2012-11-18 19:06:28 +00:00
for ( i = 0 ; i ! = vec_size ( self - > extparams ) ; + + i ) {
ir_value_delete ( self - > extparams [ i ] ) ;
}
vec_free ( self - > extparams ) ;
2013-05-07 17:56:41 +00:00
vec_free ( self - > extparam_protos ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( self - > globals ) ; + + i ) {
2012-04-25 12:46:10 +00:00
ir_value_delete ( self - > globals [ i ] ) ;
}
2012-11-15 17:32:03 +00:00
vec_free ( self - > globals ) ;
for ( i = 0 ; i ! = vec_size ( self - > fields ) ; + + i ) {
2012-07-28 19:55:01 +00:00
ir_value_delete ( self - > fields [ i ] ) ;
}
2012-12-28 17:05:28 +00:00
ir_value_delete ( self - > nil ) ;
2013-08-26 08:25:29 +00:00
for ( i = 0 ; i ! = IR_MAX_VINSTR_TEMPS ; + + i ) {
ir_value_delete ( self - > vinstr_temp [ i ] ) ;
}
2012-11-15 17:32:03 +00:00
vec_free ( self - > fields ) ;
vec_free ( self - > filenames ) ;
vec_free ( self - > filestrings ) ;
2013-06-20 10:52:58 +00:00
code_cleanup ( self - > code ) ;
2012-04-25 12:46:10 +00:00
mem_d ( self ) ;
2012-04-25 12:43:23 +00:00
}
2012-04-27 11:28:39 +00:00
bool ir_builder_set_name ( ir_builder * self , const char * name )
2012-04-25 12:43:23 +00:00
{
2012-04-25 12:46:10 +00:00
if ( self - > name )
mem_d ( ( void * ) self - > name ) ;
self - > name = util_strdup ( name ) ;
2012-04-27 11:28:39 +00:00
return ! ! self - > name ;
2012-04-25 12:43:23 +00:00
}
2013-05-29 03:29:04 +00:00
static ir_function * ir_builder_get_function ( ir_builder * self , const char * name )
2012-04-25 12:43:23 +00:00
{
2012-11-25 12:37:54 +00:00
return ( ir_function * ) util_htget ( self - > htfunctions , name ) ;
2012-04-25 12:43:23 +00:00
}
2012-06-29 11:07:19 +00:00
ir_function * ir_builder_create_function ( ir_builder * self , const char * name , int outtype )
2012-04-25 12:43:23 +00:00
{
2012-04-25 12:46:10 +00:00
ir_function * fn = ir_builder_get_function ( self , name ) ;
if ( fn ) {
return NULL ;
}
2012-04-25 12:43:23 +00:00
2012-06-29 11:07:19 +00:00
fn = ir_function_new ( self , outtype ) ;
2012-11-15 17:32:03 +00:00
if ( ! ir_function_set_name ( fn , name ) )
2012-04-27 11:28:39 +00:00
{
ir_function_delete ( fn ) ;
return NULL ;
}
2012-11-15 17:32:03 +00:00
vec_push ( self - > functions , fn ) ;
2012-11-25 12:37:54 +00:00
util_htset ( self - > htfunctions , name , fn ) ;
2012-06-29 11:25:31 +00:00
fn - > value = ir_builder_create_global ( self , fn - > name , TYPE_FUNCTION ) ;
if ( ! fn - > value ) {
ir_function_delete ( fn ) ;
return NULL ;
}
2012-11-30 12:47:28 +00:00
fn - > value - > hasvalue = true ;
2012-06-29 11:25:31 +00:00
fn - > value - > outtype = outtype ;
fn - > value - > constval . vfunc = fn ;
fn - > value - > context = fn - > context ;
2012-04-25 12:46:10 +00:00
return fn ;
2012-04-25 12:43:23 +00:00
}
2013-05-29 03:29:04 +00:00
static ir_value * ir_builder_get_global ( ir_builder * self , const char * name )
2012-04-25 12:43:23 +00:00
{
2012-11-25 12:37:54 +00:00
return ( ir_value * ) util_htget ( self - > htglobals , name ) ;
2012-04-25 12:43:23 +00:00
}
2012-04-25 12:56:47 +00:00
ir_value * ir_builder_create_global ( ir_builder * self , const char * name , int vtype )
2012-04-25 12:43:23 +00:00
{
2012-07-20 19:36:37 +00:00
ir_value * ve ;
2013-08-14 07:19:49 +00:00
if ( name [ 0 ] ! = ' # ' )
2012-07-20 19:36:37 +00:00
{
ve = ir_builder_get_global ( self , name ) ;
if ( ve ) {
return NULL ;
}
2012-04-25 12:46:10 +00:00
}
2012-04-25 12:43:23 +00:00
2012-04-25 13:16:55 +00:00
ve = ir_value_var ( name , store_global , vtype ) ;
2012-11-15 17:32:03 +00:00
vec_push ( self - > globals , ve ) ;
2012-11-25 12:37:54 +00:00
util_htset ( self - > htglobals , name , ve ) ;
2012-04-25 12:46:10 +00:00
return ve ;
2012-04-25 12:43:23 +00:00
}
2012-04-25 12:47:20 +00:00
2013-01-12 12:29:47 +00:00
ir_value * ir_builder_get_va_count ( ir_builder * self )
{
if ( self - > reserved_va_count )
return self - > reserved_va_count ;
return ( self - > reserved_va_count = ir_builder_create_global ( self , " reserved:va_count " , TYPE_FLOAT ) ) ;
}
2013-05-29 03:29:04 +00:00
static ir_value * ir_builder_get_field ( ir_builder * self , const char * name )
2012-07-28 19:55:01 +00:00
{
2012-11-25 12:37:54 +00:00
return ( ir_value * ) util_htget ( self - > htfields , name ) ;
2012-07-28 19:55:01 +00:00
}
ir_value * ir_builder_create_field ( ir_builder * self , const char * name , int vtype )
{
ir_value * ve = ir_builder_get_field ( self , name ) ;
if ( ve ) {
return NULL ;
}
ve = ir_value_var ( name , store_global , TYPE_FIELD ) ;
ve - > fieldtype = vtype ;
2012-11-15 17:32:03 +00:00
vec_push ( self - > fields , ve ) ;
2012-11-25 12:37:54 +00:00
util_htset ( self - > htfields , name , ve ) ;
2012-07-28 19:55:01 +00:00
return ve ;
}
2012-04-25 12:47:20 +00:00
/***********************************************************************
* IR Function
*/
2013-05-29 03:29:04 +00:00
static bool ir_function_naive_phi ( ir_function * ) ;
static void ir_function_enumerate ( ir_function * ) ;
static bool ir_function_calculate_liferanges ( ir_function * ) ;
static bool ir_function_allocate_locals ( ir_function * ) ;
2012-04-25 12:47:20 +00:00
2012-06-29 11:07:19 +00:00
ir_function * ir_function_new ( ir_builder * owner , int outtype )
2012-04-25 12:47:20 +00:00
{
2012-04-25 12:49:29 +00:00
ir_function * self ;
self = ( ir_function * ) mem_a ( sizeof ( * self ) ) ;
2012-05-09 12:24:35 +00:00
if ( ! self )
return NULL ;
2012-08-19 16:03:56 +00:00
memset ( self , 0 , sizeof ( * self ) ) ;
2012-04-28 09:49:52 +00:00
self - > name = NULL ;
2012-04-27 11:28:39 +00:00
if ( ! ir_function_set_name ( self , " <@unnamed> " ) ) {
mem_d ( self ) ;
return NULL ;
}
2012-12-23 15:21:38 +00:00
self - > flags = 0 ;
2012-04-25 12:49:29 +00:00
self - > owner = owner ;
self - > context . file = " <@no context> " ;
self - > context . line = 0 ;
2012-06-29 11:07:19 +00:00
self - > outtype = outtype ;
2012-06-29 11:25:31 +00:00
self - > value = NULL ;
2012-07-03 21:38:38 +00:00
self - > builtin = 0 ;
2012-11-15 17:32:03 +00:00
self - > params = NULL ;
self - > blocks = NULL ;
self - > values = NULL ;
self - > locals = NULL ;
2012-04-25 12:49:29 +00:00
2013-01-12 15:38:49 +00:00
self - > max_varargs = 0 ;
2013-01-12 13:01:16 +00:00
2012-08-19 16:00:53 +00:00
self - > code_function_def = - 1 ;
2012-08-19 16:03:56 +00:00
self - > allocated_locals = 0 ;
2012-12-26 22:18:45 +00:00
self - > globaltemps = 0 ;
2012-08-19 16:00:53 +00:00
2012-04-25 12:49:29 +00:00
self - > run_id = 0 ;
return self ;
2012-04-25 12:47:20 +00:00
}
2012-04-27 11:28:39 +00:00
bool ir_function_set_name ( ir_function * self , const char * name )
2012-04-25 12:47:20 +00:00
{
2012-04-25 12:49:29 +00:00
if ( self - > name )
mem_d ( ( void * ) self - > name ) ;
self - > name = util_strdup ( name ) ;
2012-04-27 11:28:39 +00:00
return ! ! self - > name ;
2012-04-25 12:47:20 +00:00
}
2012-08-24 18:39:47 +00:00
static void ir_function_delete_quick ( ir_function * self )
{
size_t i ;
mem_d ( ( void * ) self - > name ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( self - > blocks ) ; + + i )
2012-08-24 18:39:47 +00:00
ir_block_delete_quick ( self - > blocks [ i ] ) ;
2012-11-15 17:32:03 +00:00
vec_free ( self - > blocks ) ;
2012-08-24 18:39:47 +00:00
2012-11-15 17:32:03 +00:00
vec_free ( self - > params ) ;
2012-08-24 18:39:47 +00:00
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( self - > values ) ; + + i )
2012-08-24 18:39:47 +00:00
ir_value_delete ( self - > values [ i ] ) ;
2012-11-15 17:32:03 +00:00
vec_free ( self - > values ) ;
2012-08-24 18:39:47 +00:00
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( self - > locals ) ; + + i )
2012-08-24 18:39:47 +00:00
ir_value_delete ( self - > locals [ i ] ) ;
2012-11-15 17:32:03 +00:00
vec_free ( self - > locals ) ;
2012-08-24 18:39:47 +00:00
/* self->value is deleted by the builder */
mem_d ( self ) ;
}
2012-04-25 12:47:20 +00:00
void ir_function_delete ( ir_function * self )
{
2012-04-25 12:49:29 +00:00
size_t i ;
mem_d ( ( void * ) self - > name ) ;
2012-04-25 12:47:20 +00:00
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( self - > blocks ) ; + + i )
2012-04-25 12:49:29 +00:00
ir_block_delete ( self - > blocks [ i ] ) ;
2012-11-15 17:32:03 +00:00
vec_free ( self - > blocks ) ;
2012-04-25 12:47:20 +00:00
2012-11-15 17:32:03 +00:00
vec_free ( self - > params ) ;
2012-04-25 12:47:20 +00:00
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( self - > values ) ; + + i )
2012-04-25 12:49:29 +00:00
ir_value_delete ( self - > values [ i ] ) ;
2012-11-15 17:32:03 +00:00
vec_free ( self - > values ) ;
2012-04-25 12:47:20 +00:00
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( self - > locals ) ; + + i )
2012-04-25 12:49:29 +00:00
ir_value_delete ( self - > locals [ i ] ) ;
2012-11-15 17:32:03 +00:00
vec_free ( self - > locals ) ;
2012-04-25 12:47:20 +00:00
2012-06-29 11:25:31 +00:00
/* self->value is deleted by the builder */
2012-04-25 12:49:29 +00:00
mem_d ( self ) ;
2012-04-25 12:47:20 +00:00
}
2013-05-29 03:29:04 +00:00
static void ir_function_collect_value ( ir_function * self , ir_value * v )
2012-04-25 12:47:20 +00:00
{
2012-11-15 17:32:03 +00:00
vec_push ( self - > values , v ) ;
2012-04-25 12:47:20 +00:00
}
2013-07-30 16:00:51 +00:00
ir_block * ir_function_create_block ( lex_ctx_t ctx , ir_function * self , const char * label )
2012-04-25 12:47:20 +00:00
{
2012-04-25 12:49:29 +00:00
ir_block * bn = ir_block_new ( self , label ) ;
2012-11-25 22:48:29 +00:00
bn - > context = ctx ;
2012-11-15 17:32:03 +00:00
vec_push ( self - > blocks , bn ) ;
2014-01-07 13:33:26 +00:00
if ( ( self - > flags & IR_FLAG_BLOCK_COVERAGE ) & & self - > owner - > coverage_func )
( void ) ir_block_create_call ( bn , ctx , NULL , self - > owner - > coverage_func , false ) ;
2012-04-25 12:49:29 +00:00
return bn ;
2012-04-25 12:47:20 +00:00
}
2012-12-05 13:14:35 +00:00
static bool instr_is_operation ( uint16_t op )
{
return ( ( op > = INSTR_MUL_F & & op < = INSTR_GT ) | |
( op > = INSTR_LOAD_F & & op < = INSTR_LOAD_FNC ) | |
( op = = INSTR_ADDRESS ) | |
( op > = INSTR_NOT_F & & op < = INSTR_NOT_FNC ) | |
2012-12-21 10:42:23 +00:00
( op > = INSTR_AND & & op < = INSTR_BITOR ) | |
2013-08-26 08:25:29 +00:00
( op > = INSTR_CALL0 & & op < = INSTR_CALL8 ) | |
2013-10-06 03:36:48 +00:00
( op > = VINSTR_BITAND_V & & op < = VINSTR_NEG_V ) ) ;
2012-12-05 13:14:35 +00:00
}
2013-05-29 03:29:04 +00:00
static bool ir_function_pass_peephole ( ir_function * self )
2012-12-05 13:14:35 +00:00
{
size_t b ;
for ( b = 0 ; b < vec_size ( self - > blocks ) ; + + b ) {
size_t i ;
ir_block * block = self - > blocks [ b ] ;
2012-12-06 21:10:31 +00:00
for ( i = 0 ; i < vec_size ( block - > instr ) ; + + i ) {
ir_instr * inst ;
inst = block - > instr [ i ] ;
2012-12-05 13:14:35 +00:00
2012-12-06 21:10:31 +00:00
if ( i > = 1 & &
( inst - > opcode > = INSTR_STORE_F & &
inst - > opcode < = INSTR_STORE_FNC ) )
2012-12-05 13:14:35 +00:00
{
2012-12-06 21:10:31 +00:00
ir_instr * store ;
ir_instr * oper ;
ir_value * value ;
2012-12-05 13:14:35 +00:00
2012-12-06 21:10:31 +00:00
store = inst ;
2012-12-05 13:14:35 +00:00
2012-12-06 21:10:31 +00:00
oper = block - > instr [ i - 1 ] ;
if ( ! instr_is_operation ( oper - > opcode ) )
continue ;
2012-12-05 13:14:35 +00:00
2013-08-27 10:27:20 +00:00
/* Don't change semantics of MUL_VF in engines where these may not alias. */
2013-01-14 10:15:06 +00:00
if ( OPTS_FLAG ( LEGACY_VECTOR_MATHS ) ) {
if ( oper - > opcode = = INSTR_MUL_VF & & oper - > _ops [ 2 ] - > memberof = = oper - > _ops [ 1 ] )
continue ;
if ( oper - > opcode = = INSTR_MUL_FV & & oper - > _ops [ 1 ] - > memberof = = oper - > _ops [ 2 ] )
continue ;
}
2012-12-06 21:10:31 +00:00
value = oper - > _ops [ 0 ] ;
2012-12-05 13:14:35 +00:00
2012-12-06 21:10:31 +00:00
/* only do it for SSA values */
if ( value - > store ! = store_value )
continue ;
2012-12-05 13:14:35 +00:00
2012-12-06 21:10:31 +00:00
/* don't optimize out the temp if it's used later again */
if ( vec_size ( value - > reads ) ! = 1 )
continue ;
2012-12-05 13:14:35 +00:00
2012-12-06 21:10:31 +00:00
/* The very next store must use this value */
if ( value - > reads [ 0 ] ! = store )
continue ;
2012-12-05 13:14:35 +00:00
2012-12-06 21:10:31 +00:00
/* And of course the store must _read_ from it, so it's in
* OP 1 */
if ( store - > _ops [ 1 ] ! = value )
continue ;
2012-12-05 13:14:35 +00:00
2012-12-18 04:57:17 +00:00
+ + opts_optimizationcount [ OPTIM_PEEPHOLE ] ;
2012-12-06 21:10:31 +00:00
( void ) ! ir_instr_op ( oper , 0 , store - > _ops [ 0 ] , true ) ;
vec_remove ( block - > instr , i , 1 ) ;
ir_instr_delete ( store ) ;
}
else if ( inst - > opcode = = VINSTR_COND )
{
/* COND on a value resulting from a NOT could
* remove the NOT and swap its operands
*/
while ( true ) {
ir_block * tmp ;
size_t inotid ;
ir_instr * inot ;
ir_value * value ;
value = inst - > _ops [ 0 ] ;
if ( value - > store ! = store_value | |
vec_size ( value - > reads ) ! = 1 | |
value - > reads [ 0 ] ! = inst )
{
break ;
}
inot = value - > writes [ 0 ] ;
if ( inot - > _ops [ 0 ] ! = value | |
inot - > opcode < INSTR_NOT_F | |
inot - > opcode > INSTR_NOT_FNC | |
2012-12-23 16:51:01 +00:00
inot - > opcode = = INSTR_NOT_V | | /* can't do these */
inot - > opcode = = INSTR_NOT_S )
2012-12-06 21:10:31 +00:00
{
break ;
}
/* count */
2012-12-18 04:57:17 +00:00
+ + opts_optimizationcount [ OPTIM_PEEPHOLE ] ;
2012-12-06 21:10:31 +00:00
/* change operand */
( void ) ! ir_instr_op ( inst , 0 , inot - > _ops [ 1 ] , false ) ;
/* remove NOT */
tmp = inot - > owner ;
for ( inotid = 0 ; inotid < vec_size ( tmp - > instr ) ; + + inotid ) {
if ( tmp - > instr [ inotid ] = = inot )
break ;
}
if ( inotid > = vec_size ( tmp - > instr ) ) {
compile_error ( inst - > context , " sanity-check failed: failed to find instruction to optimize out " ) ;
return false ;
}
vec_remove ( tmp - > instr , inotid , 1 ) ;
ir_instr_delete ( inot ) ;
/* swap ontrue/onfalse */
tmp = inst - > bops [ 0 ] ;
inst - > bops [ 0 ] = inst - > bops [ 1 ] ;
inst - > bops [ 1 ] = tmp ;
}
continue ;
}
2012-12-05 13:14:35 +00:00
}
}
return true ;
}
2013-05-29 03:29:04 +00:00
static bool ir_function_pass_tailrecursion ( ir_function * self )
2012-11-30 10:12:53 +00:00
{
size_t b , p ;
for ( b = 0 ; b < vec_size ( self - > blocks ) ; + + b ) {
ir_value * funcval ;
ir_instr * ret , * call , * store = NULL ;
ir_block * block = self - > blocks [ b ] ;
if ( ! block - > final | | vec_size ( block - > instr ) < 2 )
continue ;
ret = block - > instr [ vec_size ( block - > instr ) - 1 ] ;
if ( ret - > opcode ! = INSTR_DONE & & ret - > opcode ! = INSTR_RETURN )
continue ;
call = block - > instr [ vec_size ( block - > instr ) - 2 ] ;
if ( call - > opcode > = INSTR_STORE_F & & call - > opcode < = INSTR_STORE_FNC ) {
/* account for the unoptimized
* CALL
* STORE % return , % tmp
* RETURN % tmp
* version
*/
if ( vec_size ( block - > instr ) < 3 )
continue ;
store = call ;
call = block - > instr [ vec_size ( block - > instr ) - 3 ] ;
}
if ( call - > opcode < INSTR_CALL0 | | call - > opcode > INSTR_CALL8 )
continue ;
if ( store ) {
/* optimize out the STORE */
if ( ret - > _ops [ 0 ] & &
ret - > _ops [ 0 ] = = store - > _ops [ 0 ] & &
store - > _ops [ 1 ] = = call - > _ops [ 0 ] )
{
2012-12-18 04:57:17 +00:00
+ + opts_optimizationcount [ OPTIM_PEEPHOLE ] ;
2012-11-30 10:12:53 +00:00
call - > _ops [ 0 ] = store - > _ops [ 0 ] ;
2012-11-30 10:59:03 +00:00
vec_remove ( block - > instr , vec_size ( block - > instr ) - 2 , 1 ) ;
2012-11-30 10:12:53 +00:00
ir_instr_delete ( store ) ;
}
else
continue ;
}
if ( ! call - > _ops [ 0 ] )
continue ;
funcval = call - > _ops [ 1 ] ;
if ( ! funcval )
continue ;
if ( funcval - > vtype ! = TYPE_FUNCTION | | funcval - > constval . vfunc ! = self )
continue ;
/* now we have a CALL and a RET, check if it's a tailcall */
if ( ret - > _ops [ 0 ] & & call - > _ops [ 0 ] ! = ret - > _ops [ 0 ] )
continue ;
2012-12-18 04:57:17 +00:00
+ + opts_optimizationcount [ OPTIM_TAIL_RECURSION ] ;
2012-11-30 10:12:53 +00:00
vec_shrinkby ( block - > instr , 2 ) ;
block - > final = false ; /* open it back up */
/* emite parameter-stores */
for ( p = 0 ; p < vec_size ( call - > params ) ; + + p ) {
/* assert(call->params_count <= self->locals_count); */
2012-11-30 17:19:26 +00:00
if ( ! ir_block_create_store ( block , call - > context , self - > locals [ p ] , call - > params [ p ] ) ) {
2012-11-30 10:12:53 +00:00
irerror ( call - > context , " failed to create tailcall store instruction for parameter %i " , ( int ) p ) ;
return false ;
}
}
2012-11-30 17:19:26 +00:00
if ( ! ir_block_create_jump ( block , call - > context , self - > blocks [ 0 ] ) ) {
2012-11-30 10:12:53 +00:00
irerror ( call - > context , " failed to create tailcall jump " ) ;
return false ;
}
ir_instr_delete ( call ) ;
ir_instr_delete ( ret ) ;
}
return true ;
}
2012-04-27 11:28:39 +00:00
bool ir_function_finalize ( ir_function * self )
2012-04-25 12:47:20 +00:00
{
2012-12-25 22:51:29 +00:00
size_t i ;
2012-07-03 21:38:38 +00:00
if ( self - > builtin )
return true ;
2012-12-06 12:08:22 +00:00
if ( OPTS_OPTIMIZATION ( OPTIM_PEEPHOLE ) ) {
2012-12-06 20:39:34 +00:00
if ( ! ir_function_pass_peephole ( self ) ) {
2012-12-05 13:14:35 +00:00
irerror ( self - > context , " generic optimization pass broke something in `%s` " , self - > name ) ;
return false ;
}
}
2012-11-30 10:12:53 +00:00
if ( OPTS_OPTIMIZATION ( OPTIM_TAIL_RECURSION ) ) {
2012-12-21 10:33:44 +00:00
if ( ! ir_function_pass_tailrecursion ( self ) ) {
irerror ( self - > context , " tail-recursion optimization pass broke something in `%s` " , self - > name ) ;
2012-11-30 10:12:53 +00:00
return false ;
}
}
2012-12-31 11:08:47 +00:00
if ( ! ir_function_naive_phi ( self ) ) {
irerror ( self - > context , " internal error: ir_function_naive_phi failed " ) ;
2012-04-27 11:28:39 +00:00
return false ;
2012-12-31 11:08:47 +00:00
}
2012-04-27 11:28:39 +00:00
2012-12-25 22:51:29 +00:00
for ( i = 0 ; i < vec_size ( self - > locals ) ; + + i ) {
ir_value * v = self - > locals [ i ] ;
if ( v - > vtype = = TYPE_VECTOR | |
( v - > vtype = = TYPE_FIELD & & v - > outtype = = TYPE_VECTOR ) )
{
ir_value_vector_member ( v , 0 ) ;
ir_value_vector_member ( v , 1 ) ;
ir_value_vector_member ( v , 2 ) ;
}
}
for ( i = 0 ; i < vec_size ( self - > values ) ; + + i ) {
ir_value * v = self - > values [ i ] ;
if ( v - > vtype = = TYPE_VECTOR | |
( v - > vtype = = TYPE_FIELD & & v - > outtype = = TYPE_VECTOR ) )
{
ir_value_vector_member ( v , 0 ) ;
ir_value_vector_member ( v , 1 ) ;
ir_value_vector_member ( v , 2 ) ;
}
}
2012-04-25 12:49:29 +00:00
ir_function_enumerate ( self ) ;
2012-04-27 11:28:39 +00:00
if ( ! ir_function_calculate_liferanges ( self ) )
return false ;
2012-06-25 12:14:34 +00:00
if ( ! ir_function_allocate_locals ( self ) )
return false ;
2012-04-27 11:28:39 +00:00
return true ;
2012-04-25 12:47:20 +00:00
}
2012-07-22 10:15:48 +00:00
ir_value * ir_function_create_local ( ir_function * self , const char * name , int vtype , bool param )
2012-04-25 12:47:20 +00:00
{
2012-08-23 15:22:13 +00:00
ir_value * ve ;
2012-07-22 10:15:48 +00:00
if ( param & &
2012-11-15 17:32:03 +00:00
vec_size ( self - > locals ) & &
self - > locals [ vec_size ( self - > locals ) - 1 ] - > store ! = store_param ) {
2012-08-19 18:45:26 +00:00
irerror ( self - > context , " cannot add parameters after adding locals " ) ;
2012-07-22 10:15:48 +00:00
return NULL ;
}
ve = ir_value_var ( name , ( param ? store_param : store_local ) , vtype ) ;
2012-12-26 22:18:45 +00:00
if ( param )
ve - > locked = true ;
2012-11-15 17:32:03 +00:00
vec_push ( self - > locals , ve ) ;
2012-04-25 12:49:29 +00:00
return ve ;
2012-04-25 12:47:20 +00:00
}
2012-04-25 12:52:03 +00:00
/***********************************************************************
* IR Block
*/
ir_block * ir_block_new ( ir_function * owner , const char * name )
{
2012-04-25 12:54:37 +00:00
ir_block * self ;
self = ( ir_block * ) mem_a ( sizeof ( * self ) ) ;
2012-05-09 12:24:35 +00:00
if ( ! self )
return NULL ;
memset ( self , 0 , sizeof ( * self ) ) ;
2012-04-28 09:49:52 +00:00
self - > label = NULL ;
2012-08-24 16:03:57 +00:00
if ( name & & ! ir_block_set_label ( self , name ) ) {
2012-04-27 11:28:39 +00:00
mem_d ( self ) ;
return NULL ;
}
2012-04-25 12:54:37 +00:00
self - > owner = owner ;
self - > context . file = " <@no context> " ;
self - > context . line = 0 ;
2012-04-25 13:07:48 +00:00
self - > final = false ;
2012-11-15 17:32:03 +00:00
self - > instr = NULL ;
self - > entries = NULL ;
self - > exits = NULL ;
2012-04-25 12:54:37 +00:00
self - > eid = 0 ;
2012-04-25 13:07:48 +00:00
self - > is_return = false ;
2012-11-15 17:32:03 +00:00
self - > living = NULL ;
2012-05-09 12:24:35 +00:00
self - > generated = false ;
2012-04-25 12:54:37 +00:00
return self ;
}
2012-04-25 12:52:03 +00:00
2012-08-24 18:39:47 +00:00
static void ir_block_delete_quick ( ir_block * self )
{
size_t i ;
if ( self - > label ) mem_d ( self - > label ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( self - > instr ) ; + + i )
2012-08-24 18:39:47 +00:00
ir_instr_delete_quick ( self - > instr [ i ] ) ;
2012-11-15 17:32:03 +00:00
vec_free ( self - > instr ) ;
vec_free ( self - > entries ) ;
vec_free ( self - > exits ) ;
vec_free ( self - > living ) ;
2012-08-24 18:39:47 +00:00
mem_d ( self ) ;
}
2012-04-25 12:52:03 +00:00
void ir_block_delete ( ir_block * self )
{
2012-04-25 12:54:37 +00:00
size_t i ;
2012-08-24 16:03:57 +00:00
if ( self - > label ) mem_d ( self - > label ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( self - > instr ) ; + + i )
2012-04-25 12:54:37 +00:00
ir_instr_delete ( self - > instr [ i ] ) ;
2012-11-15 17:32:03 +00:00
vec_free ( self - > instr ) ;
vec_free ( self - > entries ) ;
vec_free ( self - > exits ) ;
vec_free ( self - > living ) ;
2012-04-25 12:54:37 +00:00
mem_d ( self ) ;
2012-04-25 12:52:03 +00:00
}
2012-04-27 11:28:39 +00:00
bool ir_block_set_label ( ir_block * self , const char * name )
2012-04-25 12:52:03 +00:00
{
2012-04-25 12:54:37 +00:00
if ( self - > label )
mem_d ( ( void * ) self - > label ) ;
self - > label = util_strdup ( name ) ;
2012-04-27 11:28:39 +00:00
return ! ! self - > label ;
2012-04-25 12:52:03 +00:00
}
2012-04-25 12:55:15 +00:00
/***********************************************************************
* IR Instructions
*/
2013-07-30 16:00:51 +00:00
static ir_instr * ir_instr_new ( lex_ctx_t ctx , ir_block * owner , int op )
2012-04-25 12:55:15 +00:00
{
2012-04-25 12:56:47 +00:00
ir_instr * self ;
self = ( ir_instr * ) mem_a ( sizeof ( * self ) ) ;
2012-05-09 12:24:35 +00:00
if ( ! self )
return NULL ;
2012-04-25 12:56:47 +00:00
self - > owner = owner ;
2012-11-30 17:19:26 +00:00
self - > context = ctx ;
2012-04-25 12:56:47 +00:00
self - > opcode = op ;
self - > _ops [ 0 ] = NULL ;
self - > _ops [ 1 ] = NULL ;
self - > _ops [ 2 ] = NULL ;
self - > bops [ 0 ] = NULL ;
self - > bops [ 1 ] = NULL ;
2012-11-15 17:32:03 +00:00
self - > phi = NULL ;
self - > params = NULL ;
2012-04-25 12:56:47 +00:00
self - > eid = 0 ;
2012-11-21 16:35:11 +00:00
self - > likely = true ;
2012-04-25 12:56:47 +00:00
return self ;
2012-04-25 12:55:15 +00:00
}
2012-08-24 18:39:47 +00:00
static void ir_instr_delete_quick ( ir_instr * self )
{
2012-11-15 17:32:03 +00:00
vec_free ( self - > phi ) ;
vec_free ( self - > params ) ;
2012-08-24 18:39:47 +00:00
mem_d ( self ) ;
}
2013-05-29 03:29:04 +00:00
static void ir_instr_delete ( ir_instr * self )
2012-04-25 12:55:15 +00:00
{
2012-04-27 11:28:39 +00:00
size_t i ;
/* The following calls can only delete from
* vectors , we still want to delete this instruction
* so ignore the return value . Since with the warn_unused_result attribute
* gcc doesn ' t care about an explicit : ( void ) foo ( ) ; to ignore the result ,
* I have to improvise here and use if ( foo ( ) ) ;
*/
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > phi ) ; + + i ) {
2012-04-27 11:28:39 +00:00
size_t idx ;
2012-11-15 17:32:03 +00:00
if ( vec_ir_instr_find ( self - > phi [ i ] . value - > writes , self , & idx ) )
vec_remove ( self - > phi [ i ] . value - > writes , idx , 1 ) ;
if ( vec_ir_instr_find ( self - > phi [ i ] . value - > reads , self , & idx ) )
vec_remove ( self - > phi [ i ] . value - > reads , idx , 1 ) ;
2012-04-27 11:28:39 +00:00
}
2012-11-15 17:32:03 +00:00
vec_free ( self - > phi ) ;
for ( i = 0 ; i < vec_size ( self - > params ) ; + + i ) {
2012-06-28 13:50:51 +00:00
size_t idx ;
2012-11-15 17:32:03 +00:00
if ( vec_ir_instr_find ( self - > params [ i ] - > writes , self , & idx ) )
vec_remove ( self - > params [ i ] - > writes , idx , 1 ) ;
if ( vec_ir_instr_find ( self - > params [ i ] - > reads , self , & idx ) )
vec_remove ( self - > params [ i ] - > reads , idx , 1 ) ;
}
vec_free ( self - > params ) ;
( void ) ! ir_instr_op ( self , 0 , NULL , false ) ;
( void ) ! ir_instr_op ( self , 1 , NULL , false ) ;
( void ) ! ir_instr_op ( self , 2 , NULL , false ) ;
2012-04-25 12:56:47 +00:00
mem_d ( self ) ;
2012-04-25 12:55:15 +00:00
}
2013-05-29 03:29:04 +00:00
static bool ir_instr_op ( ir_instr * self , int op , ir_value * v , bool writing )
2012-04-25 12:55:15 +00:00
{
2013-08-26 08:25:29 +00:00
if ( v & & v - > vtype = = TYPE_NOEXPR ) {
irerror ( self - > context , " tried to use a NOEXPR value " ) ;
return false ;
}
2012-04-25 12:56:47 +00:00
if ( self - > _ops [ op ] ) {
2012-04-27 11:28:39 +00:00
size_t idx ;
2012-11-15 17:32:03 +00:00
if ( writing & & vec_ir_instr_find ( self - > _ops [ op ] - > writes , self , & idx ) )
vec_remove ( self - > _ops [ op ] - > writes , idx , 1 ) ;
else if ( vec_ir_instr_find ( self - > _ops [ op ] - > reads , self , & idx ) )
vec_remove ( self - > _ops [ op ] - > reads , idx , 1 ) ;
2012-04-25 12:56:47 +00:00
}
if ( v ) {
2012-11-15 17:32:03 +00:00
if ( writing )
vec_push ( v - > writes , self ) ;
else
vec_push ( v - > reads , self ) ;
2012-04-25 12:56:47 +00:00
}
self - > _ops [ op ] = v ;
2012-04-27 11:28:39 +00:00
return true ;
2012-04-25 12:55:15 +00:00
}
2012-04-25 12:59:08 +00:00
/***********************************************************************
* IR Value
*/
2013-05-29 03:29:04 +00:00
static void ir_value_code_setaddr ( ir_value * self , int32_t gaddr )
2012-08-11 09:45:26 +00:00
{
self - > code . globaladdr = gaddr ;
if ( self - > members [ 0 ] ) self - > members [ 0 ] - > code . globaladdr = gaddr ;
if ( self - > members [ 1 ] ) self - > members [ 1 ] - > code . globaladdr = gaddr ;
if ( self - > members [ 2 ] ) self - > members [ 2 ] - > code . globaladdr = gaddr ;
}
2013-05-29 03:29:04 +00:00
static int32_t ir_value_code_addr ( const ir_value * self )
2012-08-08 12:49:37 +00:00
{
2012-08-11 15:53:41 +00:00
if ( self - > store = = store_return )
return OFS_RETURN + self - > code . addroffset ;
2012-08-08 12:49:37 +00:00
return self - > code . globaladdr + self - > code . addroffset ;
}
2012-04-25 12:59:08 +00:00
ir_value * ir_value_var ( const char * name , int storetype , int vtype )
{
ir_value * self ;
self = ( ir_value * ) mem_a ( sizeof ( * self ) ) ;
self - > vtype = vtype ;
2012-05-05 08:56:00 +00:00
self - > fieldtype = TYPE_VOID ;
2012-06-28 15:21:26 +00:00
self - > outtype = TYPE_VOID ;
2012-04-25 12:59:08 +00:00
self - > store = storetype ;
2013-01-11 18:15:59 +00:00
self - > flags = 0 ;
2012-11-15 17:32:03 +00:00
self - > reads = NULL ;
self - > writes = NULL ;
2012-11-30 12:47:28 +00:00
self - > cvq = CV_NONE ;
self - > hasvalue = false ;
2012-04-25 12:59:08 +00:00
self - > context . file = " <@no context> " ;
self - > context . line = 0 ;
self - > name = NULL ;
2012-08-24 16:14:39 +00:00
if ( name & & ! ir_value_set_name ( self , name ) ) {
irerror ( self - > context , " out of memory " ) ;
mem_d ( self ) ;
return NULL ;
}
2012-04-25 12:59:08 +00:00
2012-05-05 08:56:00 +00:00
memset ( & self - > constval , 0 , sizeof ( self - > constval ) ) ;
memset ( & self - > code , 0 , sizeof ( self - > code ) ) ;
2012-08-12 19:56:53 +00:00
self - > members [ 0 ] = NULL ;
self - > members [ 1 ] = NULL ;
self - > members [ 2 ] = NULL ;
2012-08-19 19:37:29 +00:00
self - > memberof = NULL ;
2012-08-12 19:56:53 +00:00
2012-12-06 12:08:22 +00:00
self - > unique_life = false ;
2012-12-25 20:03:26 +00:00
self - > locked = false ;
2012-12-25 22:25:59 +00:00
self - > callparam = false ;
2012-12-06 12:08:22 +00:00
2012-11-15 17:32:03 +00:00
self - > life = NULL ;
2012-04-25 12:59:08 +00:00
return self ;
}
2012-08-08 12:49:37 +00:00
2014-10-18 11:49:13 +00:00
/* helper function */
static ir_value * ir_builder_imm_float ( ir_builder * self , float value , bool add_to_list ) {
ir_value * v = ir_value_var ( " #IMMEDIATE " , store_global , TYPE_FLOAT ) ;
2014-10-18 12:27:16 +00:00
v - > flags | = IR_FLAG_ERASABLE ;
2014-10-18 11:49:13 +00:00
v - > hasvalue = true ;
2014-10-18 11:53:15 +00:00
v - > cvq = CV_CONST ;
2014-10-18 11:49:13 +00:00
v - > constval . vfloat = value ;
vec_push ( self - > globals , v ) ;
if ( add_to_list )
vec_push ( self - > const_floats , v ) ;
return v ;
}
2012-08-08 12:49:37 +00:00
ir_value * ir_value_vector_member ( ir_value * self , unsigned int member )
{
2012-12-20 13:06:25 +00:00
char * name ;
size_t len ;
2012-08-08 12:49:37 +00:00
ir_value * m ;
if ( member > = 3 )
return NULL ;
if ( self - > members [ member ] )
return self - > members [ member ] ;
2012-12-23 11:22:27 +00:00
if ( self - > name ) {
len = strlen ( self - > name ) ;
name = ( char * ) mem_a ( len + 3 ) ;
memcpy ( name , self - > name , len ) ;
name [ len + 0 ] = ' _ ' ;
name [ len + 1 ] = ' x ' + member ;
name [ len + 2 ] = ' \0 ' ;
}
else
name = NULL ;
2012-08-11 17:08:23 +00:00
if ( self - > vtype = = TYPE_VECTOR )
{
2012-12-20 13:06:25 +00:00
m = ir_value_var ( name , self - > store , TYPE_FLOAT ) ;
2012-12-23 11:22:27 +00:00
if ( name )
mem_d ( name ) ;
2012-08-11 17:08:23 +00:00
if ( ! m )
return NULL ;
m - > context = self - > context ;
2012-08-08 12:49:37 +00:00
2012-08-11 17:08:23 +00:00
self - > members [ member ] = m ;
m - > code . addroffset = member ;
}
else if ( self - > vtype = = TYPE_FIELD )
{
if ( self - > fieldtype ! = TYPE_VECTOR )
return NULL ;
2012-12-20 13:06:25 +00:00
m = ir_value_var ( name , self - > store , TYPE_FIELD ) ;
2012-12-23 11:22:27 +00:00
if ( name )
mem_d ( name ) ;
2012-08-11 17:08:23 +00:00
if ( ! m )
return NULL ;
m - > fieldtype = TYPE_FLOAT ;
m - > context = self - > context ;
2012-08-08 12:49:37 +00:00
2012-08-11 17:08:23 +00:00
self - > members [ member ] = m ;
m - > code . addroffset = member ;
}
2012-08-12 16:44:58 +00:00
else
{
2012-08-19 18:45:26 +00:00
irerror ( self - > context , " invalid member access on %s " , self - > name ) ;
2012-08-12 16:44:58 +00:00
return NULL ;
}
2012-08-08 12:49:37 +00:00
2012-08-19 19:37:29 +00:00
m - > memberof = self ;
2012-08-08 12:49:37 +00:00
return m ;
}
2012-12-20 22:48:41 +00:00
static GMQCC_INLINE size_t ir_value_sizeof ( const ir_value * self )
{
if ( self - > vtype = = TYPE_FIELD & & self - > fieldtype = = TYPE_VECTOR )
return type_sizeof_ [ TYPE_VECTOR ] ;
return type_sizeof_ [ self - > vtype ] ;
}
2013-05-29 03:29:04 +00:00
static ir_value * ir_value_out ( ir_function * owner , const char * name , int storetype , int vtype )
2012-04-25 12:59:08 +00:00
{
ir_value * v = ir_value_var ( name , storetype , vtype ) ;
2012-04-27 11:28:39 +00:00
if ( ! v )
return NULL ;
2012-11-15 17:32:03 +00:00
ir_function_collect_value ( owner , v ) ;
2012-04-25 12:59:08 +00:00
return v ;
}
void ir_value_delete ( ir_value * self )
{
2012-08-08 12:49:37 +00:00
size_t i ;
2012-06-25 14:06:01 +00:00
if ( self - > name )
mem_d ( ( void * ) self - > name ) ;
2012-11-30 12:47:28 +00:00
if ( self - > hasvalue )
2012-04-25 12:59:08 +00:00
{
2012-04-28 08:42:03 +00:00
if ( self - > vtype = = TYPE_STRING )
2012-04-25 14:21:04 +00:00
mem_d ( ( void * ) self - > constval . vstring ) ;
2012-04-25 12:59:08 +00:00
}
2014-10-18 11:49:13 +00:00
if ( ! ( self - > flags & IR_FLAG_SPLIT_VECTOR ) ) {
for ( i = 0 ; i < 3 ; + + i ) {
if ( self - > members [ i ] )
ir_value_delete ( self - > members [ i ] ) ;
}
2012-08-08 12:49:37 +00:00
}
2012-11-15 17:32:03 +00:00
vec_free ( self - > reads ) ;
vec_free ( self - > writes ) ;
vec_free ( self - > life ) ;
2012-04-25 12:59:08 +00:00
mem_d ( self ) ;
}
2012-08-24 16:14:39 +00:00
bool ir_value_set_name ( ir_value * self , const char * name )
2012-04-25 12:59:08 +00:00
{
if ( self - > name )
mem_d ( ( void * ) self - > name ) ;
self - > name = util_strdup ( name ) ;
2012-08-24 16:14:39 +00:00
return ! ! self - > name ;
2012-04-25 12:59:08 +00:00
}
2012-04-26 08:16:15 +00:00
bool ir_value_set_float ( ir_value * self , float f )
2012-04-25 12:59:08 +00:00
{
2012-04-28 08:42:03 +00:00
if ( self - > vtype ! = TYPE_FLOAT )
2012-04-25 13:07:48 +00:00
return false ;
2012-04-25 14:21:04 +00:00
self - > constval . vfloat = f ;
2012-11-30 12:47:28 +00:00
self - > hasvalue = true ;
2012-04-25 13:07:48 +00:00
return true ;
2012-04-25 12:59:08 +00:00
}
2012-07-03 21:38:38 +00:00
bool ir_value_set_func ( ir_value * self , int f )
{
if ( self - > vtype ! = TYPE_FUNCTION )
return false ;
self - > constval . vint = f ;
2012-11-30 12:47:28 +00:00
self - > hasvalue = true ;
2012-07-03 21:38:38 +00:00
return true ;
}
2013-07-30 16:00:51 +00:00
bool ir_value_set_vector ( ir_value * self , vec3_t v )
2012-04-25 12:59:08 +00:00
{
2012-04-28 08:42:03 +00:00
if ( self - > vtype ! = TYPE_VECTOR )
2012-04-25 13:07:48 +00:00
return false ;
2012-04-25 14:21:04 +00:00
self - > constval . vvec = v ;
2012-11-30 12:47:28 +00:00
self - > hasvalue = true ;
2012-04-25 13:07:48 +00:00
return true ;
2012-04-25 12:59:08 +00:00
}
2012-08-11 13:41:10 +00:00
bool ir_value_set_field ( ir_value * self , ir_value * fld )
{
if ( self - > vtype ! = TYPE_FIELD )
return false ;
self - > constval . vpointer = fld ;
2012-11-30 12:47:28 +00:00
self - > hasvalue = true ;
2012-08-11 13:41:10 +00:00
return true ;
}
2012-04-26 08:16:15 +00:00
bool ir_value_set_string ( ir_value * self , const char * str )
2012-04-25 12:59:08 +00:00
{
2012-04-28 08:42:03 +00:00
if ( self - > vtype ! = TYPE_STRING )
2012-04-25 13:07:48 +00:00
return false ;
2013-04-17 16:23:30 +00:00
self - > constval . vstring = util_strdupe ( str ) ;
2012-11-30 12:47:28 +00:00
self - > hasvalue = true ;
2012-04-25 13:07:48 +00:00
return true ;
2012-04-25 12:59:08 +00:00
}
2012-04-28 08:42:03 +00:00
#if 0
2012-04-26 08:16:15 +00:00
bool ir_value_set_int ( ir_value * self , int i )
2012-04-25 12:59:08 +00:00
{
2012-04-28 08:42:03 +00:00
if ( self - > vtype ! = TYPE_INTEGER )
2012-04-25 13:07:48 +00:00
return false ;
2012-04-25 14:21:04 +00:00
self - > constval . vint = i ;
2012-11-30 12:47:28 +00:00
self - > hasvalue = true ;
2012-04-25 13:07:48 +00:00
return true ;
2012-04-25 12:59:08 +00:00
}
2012-04-28 08:42:03 +00:00
# endif
2012-04-25 12:59:08 +00:00
2012-04-26 08:16:15 +00:00
bool ir_value_lives ( ir_value * self , size_t at )
2012-04-25 12:59:08 +00:00
{
size_t i ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > life ) ; + + i )
2012-04-25 12:59:08 +00:00
{
ir_life_entry_t * life = & self - > life [ i ] ;
if ( life - > start < = at & & at < = life - > end )
2012-04-25 13:07:48 +00:00
return true ;
2012-04-25 12:59:08 +00:00
if ( life - > start > at ) /* since it's ordered */
2012-04-25 13:07:48 +00:00
return false ;
2012-04-25 12:59:08 +00:00
}
2012-04-25 13:07:48 +00:00
return false ;
2012-04-25 12:59:08 +00:00
}
2013-05-29 03:29:04 +00:00
static bool ir_value_life_insert ( ir_value * self , size_t idx , ir_life_entry_t e )
2012-04-25 12:59:08 +00:00
{
size_t k ;
2012-11-15 17:32:03 +00:00
vec_push ( self - > life , e ) ;
for ( k = vec_size ( self - > life ) - 1 ; k > idx ; - - k )
2012-04-25 12:59:08 +00:00
self - > life [ k ] = self - > life [ k - 1 ] ;
self - > life [ idx ] = e ;
2012-04-27 11:28:39 +00:00
return true ;
2012-04-25 12:59:08 +00:00
}
2013-05-29 03:29:04 +00:00
static bool ir_value_life_merge ( ir_value * self , size_t s )
2012-04-25 12:59:08 +00:00
{
size_t i ;
2013-01-15 19:57:30 +00:00
const size_t vs = vec_size ( self - > life ) ;
2012-04-25 12:59:08 +00:00
ir_life_entry_t * life = NULL ;
ir_life_entry_t * before = NULL ;
ir_life_entry_t new_entry ;
/* Find the first range >= s */
2013-01-15 19:57:30 +00:00
for ( i = 0 ; i < vs ; + + i )
2012-04-25 12:59:08 +00:00
{
before = life ;
life = & self - > life [ i ] ;
if ( life - > start > s )
break ;
}
/* nothing found? append */
2013-01-15 19:57:30 +00:00
if ( i = = vs ) {
2012-04-28 22:56:09 +00:00
ir_life_entry_t e ;
2012-04-25 12:59:08 +00:00
if ( life & & life - > end + 1 = = s )
{
/* previous life range can be merged in */
life - > end + + ;
2012-04-25 13:07:48 +00:00
return true ;
2012-04-25 12:59:08 +00:00
}
if ( life & & life - > end > = s )
2012-04-25 13:07:48 +00:00
return false ;
2012-04-25 12:59:08 +00:00
e . start = e . end = s ;
2012-11-15 17:32:03 +00:00
vec_push ( self - > life , e ) ;
2012-04-25 13:07:48 +00:00
return true ;
2012-04-25 12:59:08 +00:00
}
/* found */
if ( before )
{
if ( before - > end + 1 = = s & &
life - > start - 1 = = s )
{
/* merge */
before - > end = life - > end ;
2012-11-15 17:32:03 +00:00
vec_remove ( self - > life , i , 1 ) ;
2012-04-25 13:07:48 +00:00
return true ;
2012-04-25 12:59:08 +00:00
}
if ( before - > end + 1 = = s )
{
/* extend before */
before - > end + + ;
2012-04-25 13:07:48 +00:00
return true ;
2012-04-25 12:59:08 +00:00
}
/* already contained */
if ( before - > end > = s )
2012-04-25 13:07:48 +00:00
return false ;
2012-04-25 12:59:08 +00:00
}
/* extend */
if ( life - > start - 1 = = s )
{
life - > start - - ;
2012-04-25 13:07:48 +00:00
return true ;
2012-04-25 12:59:08 +00:00
}
/* insert a new entry */
new_entry . start = new_entry . end = s ;
2012-04-27 11:28:39 +00:00
return ir_value_life_insert ( self , i , new_entry ) ;
2012-04-25 12:59:08 +00:00
}
2012-04-25 13:03:57 +00:00
2013-05-29 03:29:04 +00:00
static bool ir_value_life_merge_into ( ir_value * self , const ir_value * other )
2012-06-25 12:51:31 +00:00
{
size_t i , myi ;
2012-11-15 17:32:03 +00:00
if ( ! vec_size ( other - > life ) )
2012-06-25 12:51:31 +00:00
return true ;
2012-11-15 17:32:03 +00:00
if ( ! vec_size ( self - > life ) ) {
size_t count = vec_size ( other - > life ) ;
ir_life_entry_t * life = vec_add ( self - > life , count ) ;
memcpy ( life , other - > life , count * sizeof ( * life ) ) ;
2012-06-25 12:51:31 +00:00
return true ;
}
myi = 0 ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( other - > life ) ; + + i )
2012-06-25 12:51:31 +00:00
{
const ir_life_entry_t * life = & other - > life [ i ] ;
while ( true )
{
ir_life_entry_t * entry = & self - > life [ myi ] ;
if ( life - > end + 1 < entry - > start )
{
/* adding an interval before entry */
if ( ! ir_value_life_insert ( self , myi , * life ) )
return false ;
+ + myi ;
break ;
}
if ( life - > start < entry - > start & &
2012-08-23 20:07:32 +00:00
life - > end + 1 > = entry - > start )
2012-06-25 12:51:31 +00:00
{
/* starts earlier and overlaps */
entry - > start = life - > start ;
}
2012-08-24 13:06:30 +00:00
if ( life - > end > entry - > end & &
life - > start < = entry - > end + 1 )
2012-06-25 12:51:31 +00:00
{
/* ends later and overlaps */
entry - > end = life - > end ;
}
/* see if our change combines it with the next ranges */
2012-11-15 17:32:03 +00:00
while ( myi + 1 < vec_size ( self - > life ) & &
2012-06-25 12:51:31 +00:00
entry - > end + 1 > = self - > life [ 1 + myi ] . start )
{
/* overlaps with (myi+1) */
if ( entry - > end < self - > life [ 1 + myi ] . end )
entry - > end = self - > life [ 1 + myi ] . end ;
2012-11-15 17:32:03 +00:00
vec_remove ( self - > life , myi + 1 , 1 ) ;
2012-06-25 12:51:31 +00:00
entry = & self - > life [ myi ] ;
}
/* see if we're after the entry */
if ( life - > start > entry - > end )
{
+ + myi ;
/* append if we're at the end */
2012-11-15 17:32:03 +00:00
if ( myi > = vec_size ( self - > life ) ) {
vec_push ( self - > life , * life ) ;
2012-06-25 12:51:31 +00:00
break ;
}
/* otherweise check the next range */
continue ;
}
break ;
}
}
return true ;
}
2013-05-29 03:29:04 +00:00
static bool ir_values_overlap ( const ir_value * a , const ir_value * b )
2012-05-01 10:40:37 +00:00
{
/* For any life entry in A see if it overlaps with
* any life entry in B .
* Note that the life entries are orderes , so we can make a
* more efficient algorithm there than naively translating the
* statement above .
*/
ir_life_entry_t * la , * lb , * enda , * endb ;
/* first of all, if either has no life range, they cannot clash */
2012-11-15 17:32:03 +00:00
if ( ! vec_size ( a - > life ) | | ! vec_size ( b - > life ) )
2012-05-01 10:40:37 +00:00
return false ;
la = a - > life ;
lb = b - > life ;
2012-11-15 17:32:03 +00:00
enda = la + vec_size ( a - > life ) ;
endb = lb + vec_size ( b - > life ) ;
2012-05-01 10:40:37 +00:00
while ( true )
{
/* check if the entries overlap, for that,
* both must start before the other one ends .
*/
2012-08-19 19:00:42 +00:00
if ( la - > start < lb - > end & &
lb - > start < la - > end )
2012-05-01 10:40:37 +00:00
{
return true ;
}
/* entries are ordered
* one entry is earlier than the other
* that earlier entry will be moved forward
*/
2012-06-25 14:06:01 +00:00
if ( la - > start < lb - > start )
2012-05-01 10:40:37 +00:00
{
/* order: A B, move A forward
* check if we hit the end with A
*/
if ( + + la = = enda )
break ;
}
2012-08-16 14:38:36 +00:00
else /* if (lb->start < la->start) actually <= */
2012-05-01 10:40:37 +00:00
{
/* order: B A, move B forward
* check if we hit the end with B
*/
if ( + + lb = = endb )
break ;
}
}
return false ;
}
2012-04-25 13:03:57 +00:00
/***********************************************************************
* IR main operations
*/
2012-12-20 13:41:16 +00:00
static bool ir_check_unreachable ( ir_block * self )
{
/* The IR should never have to deal with unreachable code */
if ( ! self - > final /* || OPTS_FLAG(ALLOW_UNREACHABLE_CODE)*/ )
return true ;
irerror ( self - > context , " unreachable statement (%s) " , self - > label ) ;
return false ;
}
2013-07-30 16:00:51 +00:00
bool ir_block_create_store_op ( ir_block * self , lex_ctx_t ctx , int op , ir_value * target , ir_value * what )
2012-04-25 13:03:57 +00:00
{
2012-11-19 18:39:52 +00:00
ir_instr * in ;
2012-12-20 13:41:16 +00:00
if ( ! ir_check_unreachable ( self ) )
2012-11-19 18:39:52 +00:00
return false ;
2012-08-11 14:38:17 +00:00
if ( target - > store = = store_value & &
( op < INSTR_STOREP_F | | op > INSTR_STOREP_FNC ) )
{
2012-08-19 18:45:26 +00:00
irerror ( self - > context , " cannot store to an SSA value " ) ;
irerror ( self - > context , " trying to store: %s <- %s " , target - > name , what - > name ) ;
2013-07-28 00:23:15 +00:00
irerror ( self - > context , " instruction: %s " , util_instr_str [ op ] ) ;
2012-08-11 14:38:17 +00:00
return false ;
}
2012-12-18 15:45:18 +00:00
in = ir_instr_new ( ctx , self , op ) ;
if ( ! in )
return false ;
2012-12-23 20:29:15 +00:00
if ( ! ir_instr_op ( in , 0 , target , ( op < INSTR_STOREP_F | | op > INSTR_STOREP_FNC ) ) | |
2012-11-15 17:32:03 +00:00
! ir_instr_op ( in , 1 , what , false ) )
2012-08-11 14:38:17 +00:00
{
2012-12-18 15:45:18 +00:00
ir_instr_delete ( in ) ;
2012-04-25 13:07:48 +00:00
return false ;
2012-04-25 13:03:57 +00:00
}
2012-11-15 17:32:03 +00:00
vec_push ( self - > instr , in ) ;
2012-08-11 14:38:17 +00:00
return true ;
2012-04-25 13:03:57 +00:00
}
2014-04-08 12:34:55 +00:00
bool ir_block_create_state_op ( ir_block * self , lex_ctx_t ctx , ir_value * frame , ir_value * think )
{
ir_instr * in ;
if ( ! ir_check_unreachable ( self ) )
return false ;
in = ir_instr_new ( ctx , self , INSTR_STATE ) ;
if ( ! in )
return false ;
if ( ! ir_instr_op ( in , 0 , frame , false ) | |
! ir_instr_op ( in , 1 , think , false ) )
{
ir_instr_delete ( in ) ;
return false ;
}
vec_push ( self - > instr , in ) ;
return true ;
}
2013-07-30 16:00:51 +00:00
static bool ir_block_create_store ( ir_block * self , lex_ctx_t ctx , ir_value * target , ir_value * what )
2012-04-25 13:03:57 +00:00
{
int op = 0 ;
int vtype ;
2012-04-28 08:42:03 +00:00
if ( target - > vtype = = TYPE_VARIANT )
2012-04-25 13:03:57 +00:00
vtype = what - > vtype ;
else
vtype = target - > vtype ;
2012-04-25 14:21:04 +00:00
#if 0
2012-07-16 08:19:04 +00:00
if ( vtype = = TYPE_FLOAT & & what - > vtype = = TYPE_INTEGER )
op = INSTR_CONV_ITOF ;
else if ( vtype = = TYPE_INTEGER & & what - > vtype = = TYPE_FLOAT )
op = INSTR_CONV_FTOI ;
2012-04-25 14:21:04 +00:00
# endif
2012-07-16 08:19:04 +00:00
op = type_store_instr [ vtype ] ;
2012-08-11 17:38:02 +00:00
if ( OPTS_FLAG ( ADJUST_VECTOR_FIELDS ) ) {
if ( op = = INSTR_STORE_FLD & & what - > fieldtype = = TYPE_VECTOR )
op = INSTR_STORE_V ;
}
2012-11-30 17:19:26 +00:00
return ir_block_create_store_op ( self , ctx , op , target , what ) ;
2012-05-01 09:58:52 +00:00
}
2013-07-30 16:00:51 +00:00
bool ir_block_create_storep ( ir_block * self , lex_ctx_t ctx , ir_value * target , ir_value * what )
2012-05-01 09:58:52 +00:00
{
int op = 0 ;
int vtype ;
2012-05-01 10:05:47 +00:00
if ( target - > vtype ! = TYPE_POINTER )
2012-05-01 09:58:52 +00:00
return false ;
2012-05-01 10:05:47 +00:00
/* storing using pointer - target is a pointer, type must be
* inferred from source
*/
vtype = what - > vtype ;
2012-05-01 09:58:52 +00:00
2012-07-16 08:24:35 +00:00
op = type_storep_instr [ vtype ] ;
2012-08-11 17:38:02 +00:00
if ( OPTS_FLAG ( ADJUST_VECTOR_FIELDS ) ) {
if ( op = = INSTR_STOREP_FLD & & what - > fieldtype = = TYPE_VECTOR )
op = INSTR_STOREP_V ;
}
2012-07-16 08:19:04 +00:00
2012-11-30 17:19:26 +00:00
return ir_block_create_store_op ( self , ctx , op , target , what ) ;
2012-04-25 13:03:57 +00:00
}
2013-07-30 16:00:51 +00:00
bool ir_block_create_return ( ir_block * self , lex_ctx_t ctx , ir_value * v )
2012-04-25 13:03:57 +00:00
{
ir_instr * in ;
2012-12-20 13:41:16 +00:00
if ( ! ir_check_unreachable ( self ) )
2012-04-27 11:28:39 +00:00
return false ;
2013-10-17 08:45:24 +00:00
2012-04-25 13:07:48 +00:00
self - > final = true ;
2013-10-17 08:45:24 +00:00
2012-04-25 13:07:48 +00:00
self - > is_return = true ;
2012-11-30 17:19:26 +00:00
in = ir_instr_new ( ctx , self , INSTR_RETURN ) ;
2012-04-27 11:28:39 +00:00
if ( ! in )
return false ;
2012-12-18 15:45:18 +00:00
if ( v & & ! ir_instr_op ( in , 0 , v , false ) ) {
ir_instr_delete ( in ) ;
2012-08-18 15:58:38 +00:00
return false ;
2012-12-18 15:45:18 +00:00
}
2012-08-18 15:58:38 +00:00
2012-11-15 17:32:03 +00:00
vec_push ( self - > instr , in ) ;
2012-04-27 11:28:39 +00:00
return true ;
2012-04-25 13:03:57 +00:00
}
2013-07-30 16:00:51 +00:00
bool ir_block_create_if ( ir_block * self , lex_ctx_t ctx , ir_value * v ,
2012-04-25 13:03:57 +00:00
ir_block * ontrue , ir_block * onfalse )
{
ir_instr * in ;
2012-12-20 13:41:16 +00:00
if ( ! ir_check_unreachable ( self ) )
2012-04-27 11:28:39 +00:00
return false ;
2012-04-25 13:07:48 +00:00
self - > final = true ;
2012-11-30 17:19:26 +00:00
/*in = ir_instr_new(ctx, self, (v->vtype == TYPE_STRING ? INSTR_IF_S : INSTR_IF_F));*/
in = ir_instr_new ( ctx , self , VINSTR_COND ) ;
2012-04-27 11:28:39 +00:00
if ( ! in )
return false ;
if ( ! ir_instr_op ( in , 0 , v , false ) ) {
ir_instr_delete ( in ) ;
return false ;
}
2012-04-25 13:03:57 +00:00
in - > bops [ 0 ] = ontrue ;
in - > bops [ 1 ] = onfalse ;
2012-11-15 17:32:03 +00:00
vec_push ( self - > instr , in ) ;
2012-04-27 11:28:39 +00:00
2012-11-15 17:32:03 +00:00
vec_push ( self - > exits , ontrue ) ;
vec_push ( self - > exits , onfalse ) ;
vec_push ( ontrue - > entries , self ) ;
vec_push ( onfalse - > entries , self ) ;
2012-04-27 11:28:39 +00:00
return true ;
2012-04-25 13:03:57 +00:00
}
2013-07-30 16:00:51 +00:00
bool ir_block_create_jump ( ir_block * self , lex_ctx_t ctx , ir_block * to )
2012-04-25 13:03:57 +00:00
{
ir_instr * in ;
2012-12-20 13:41:16 +00:00
if ( ! ir_check_unreachable ( self ) )
2012-04-27 11:28:39 +00:00
return false ;
2012-04-25 13:07:48 +00:00
self - > final = true ;
2012-11-30 17:19:26 +00:00
in = ir_instr_new ( ctx , self , VINSTR_JUMP ) ;
2012-04-27 11:28:39 +00:00
if ( ! in )
return false ;
2012-04-25 13:03:57 +00:00
in - > bops [ 0 ] = to ;
2012-11-15 17:32:03 +00:00
vec_push ( self - > instr , in ) ;
2012-04-25 13:03:57 +00:00
2012-11-15 17:32:03 +00:00
vec_push ( self - > exits , to ) ;
vec_push ( to - > entries , self ) ;
2012-04-27 11:28:39 +00:00
return true ;
2012-04-25 13:03:57 +00:00
}
2013-07-30 16:00:51 +00:00
bool ir_block_create_goto ( ir_block * self , lex_ctx_t ctx , ir_block * to )
2012-04-25 13:03:57 +00:00
{
2012-12-23 15:21:38 +00:00
self - > owner - > flags | = IR_FLAG_HAS_GOTO ;
return ir_block_create_jump ( self , ctx , to ) ;
2012-04-25 13:03:57 +00:00
}
2013-07-30 16:00:51 +00:00
ir_instr * ir_block_create_phi ( ir_block * self , lex_ctx_t ctx , const char * label , int ot )
2012-04-25 13:03:57 +00:00
{
ir_value * out ;
ir_instr * in ;
2012-12-20 13:41:16 +00:00
if ( ! ir_check_unreachable ( self ) )
2012-12-23 07:51:19 +00:00
return NULL ;
2012-11-30 17:19:26 +00:00
in = ir_instr_new ( ctx , self , VINSTR_PHI ) ;
2012-04-27 11:28:39 +00:00
if ( ! in )
return NULL ;
2012-05-01 14:27:36 +00:00
out = ir_value_out ( self - > owner , label , store_value , ot ) ;
2012-04-27 11:28:39 +00:00
if ( ! out ) {
ir_instr_delete ( in ) ;
return NULL ;
}
if ( ! ir_instr_op ( in , 0 , out , true ) ) {
ir_instr_delete ( in ) ;
ir_value_delete ( out ) ;
return NULL ;
}
2012-11-15 17:32:03 +00:00
vec_push ( self - > instr , in ) ;
2012-04-25 13:03:57 +00:00
return in ;
}
ir_value * ir_phi_value ( ir_instr * self )
{
return self - > _ops [ 0 ] ;
}
2012-11-15 17:32:03 +00:00
void ir_phi_add ( ir_instr * self , ir_block * b , ir_value * v )
2012-04-25 13:03:57 +00:00
{
ir_phi_entry_t pe ;
2012-11-15 17:32:03 +00:00
if ( ! vec_ir_block_find ( self - > owner - > entries , b , NULL ) ) {
2012-04-25 13:03:57 +00:00
/* Must not be possible to cause this, otherwise the AST
* is doing something wrong .
*/
2012-08-19 18:45:26 +00:00
irerror ( self - > context , " Invalid entry block for PHI " ) ;
2013-04-14 01:14:14 +00:00
exit ( EXIT_FAILURE ) ;
2012-04-25 13:03:57 +00:00
}
pe . value = v ;
pe . from = b ;
2012-11-15 17:32:03 +00:00
vec_push ( v - > reads , self ) ;
vec_push ( self - > phi , pe ) ;
2012-04-25 13:03:57 +00:00
}
2012-04-25 13:07:48 +00:00
2012-06-28 15:21:26 +00:00
/* call related code */
2013-07-30 16:00:51 +00:00
ir_instr * ir_block_create_call ( ir_block * self , lex_ctx_t ctx , const char * label , ir_value * func , bool noreturn )
2012-06-28 15:21:26 +00:00
{
ir_value * out ;
ir_instr * in ;
2012-12-20 13:41:16 +00:00
if ( ! ir_check_unreachable ( self ) )
2012-12-23 07:51:19 +00:00
return NULL ;
2012-12-19 19:38:32 +00:00
in = ir_instr_new ( ctx , self , ( noreturn ? VINSTR_NRCALL : INSTR_CALL0 ) ) ;
2012-06-28 15:21:26 +00:00
if ( ! in )
return NULL ;
2012-12-19 19:40:45 +00:00
if ( noreturn ) {
self - > final = true ;
self - > is_return = true ;
}
2012-08-19 15:42:22 +00:00
out = ir_value_out ( self - > owner , label , ( func - > outtype = = TYPE_VOID ) ? store_return : store_value , func - > outtype ) ;
2012-06-28 15:21:26 +00:00
if ( ! out ) {
ir_instr_delete ( in ) ;
return NULL ;
}
if ( ! ir_instr_op ( in , 0 , out , true ) | |
2012-11-15 17:32:03 +00:00
! ir_instr_op ( in , 1 , func , false ) )
2012-06-28 15:21:26 +00:00
{
ir_instr_delete ( in ) ;
ir_value_delete ( out ) ;
return NULL ;
}
2012-11-15 17:32:03 +00:00
vec_push ( self - > instr , in ) ;
2012-12-20 21:03:51 +00:00
/*
2012-12-20 15:20:08 +00:00
if ( noreturn ) {
if ( ! ir_block_create_return ( self , ctx , NULL ) ) {
compile_error ( ctx , " internal error: failed to generate dummy-return instruction " ) ;
ir_instr_delete ( in ) ;
return NULL ;
}
}
2012-12-20 21:03:51 +00:00
*/
2012-06-28 15:21:26 +00:00
return in ;
}
ir_value * ir_call_value ( ir_instr * self )
{
return self - > _ops [ 0 ] ;
}
2012-11-15 17:32:03 +00:00
void ir_call_param ( ir_instr * self , ir_value * v )
2012-06-28 15:21:26 +00:00
{
2012-11-15 17:32:03 +00:00
vec_push ( self - > params , v ) ;
vec_push ( v - > reads , self ) ;
2012-06-28 15:21:26 +00:00
}
2012-04-25 13:07:48 +00:00
/* binary op related code */
2013-07-30 16:00:51 +00:00
ir_value * ir_block_create_binop ( ir_block * self , lex_ctx_t ctx ,
2012-04-25 13:07:48 +00:00
const char * label , int opcode ,
ir_value * left , ir_value * right )
{
2012-04-28 08:42:03 +00:00
int ot = TYPE_VOID ;
2012-04-25 13:07:48 +00:00
switch ( opcode ) {
case INSTR_ADD_F :
case INSTR_SUB_F :
case INSTR_DIV_F :
case INSTR_MUL_F :
case INSTR_MUL_V :
case INSTR_AND :
case INSTR_OR :
2012-04-25 14:21:04 +00:00
#if 0
2012-04-25 13:07:48 +00:00
case INSTR_AND_I :
case INSTR_AND_IF :
case INSTR_AND_FI :
case INSTR_OR_I :
case INSTR_OR_IF :
case INSTR_OR_FI :
2012-04-25 14:21:04 +00:00
# endif
2012-04-25 13:07:48 +00:00
case INSTR_BITAND :
case INSTR_BITOR :
2013-08-26 08:25:29 +00:00
case VINSTR_BITXOR :
2012-04-25 14:21:04 +00:00
#if 0
2012-04-25 13:07:48 +00:00
case INSTR_SUB_S : /* -- offset of string as float */
case INSTR_MUL_IF :
case INSTR_MUL_FI :
case INSTR_DIV_IF :
case INSTR_DIV_FI :
case INSTR_BITOR_IF :
case INSTR_BITOR_FI :
case INSTR_BITAND_FI :
case INSTR_BITAND_IF :
case INSTR_EQ_I :
case INSTR_NE_I :
2012-04-25 14:21:04 +00:00
# endif
2012-04-28 08:42:03 +00:00
ot = TYPE_FLOAT ;
2012-04-25 13:07:48 +00:00
break ;
2012-04-25 14:21:04 +00:00
#if 0
2012-04-25 13:07:48 +00:00
case INSTR_ADD_I :
case INSTR_ADD_IF :
case INSTR_ADD_FI :
case INSTR_SUB_I :
case INSTR_SUB_FI :
case INSTR_SUB_IF :
case INSTR_MUL_I :
case INSTR_DIV_I :
case INSTR_BITAND_I :
case INSTR_BITOR_I :
case INSTR_XOR_I :
case INSTR_RSHIFT_I :
case INSTR_LSHIFT_I :
2012-04-28 08:42:03 +00:00
ot = TYPE_INTEGER ;
2012-04-25 13:07:48 +00:00
break ;
2012-04-25 14:21:04 +00:00
# endif
2012-04-25 13:07:48 +00:00
case INSTR_ADD_V :
case INSTR_SUB_V :
case INSTR_MUL_VF :
2012-07-20 19:42:36 +00:00
case INSTR_MUL_FV :
2013-08-26 08:25:29 +00:00
case VINSTR_BITAND_V :
case VINSTR_BITOR_V :
case VINSTR_BITXOR_V :
case VINSTR_BITAND_VF :
case VINSTR_BITOR_VF :
case VINSTR_BITXOR_VF :
2013-08-31 18:49:06 +00:00
case VINSTR_CROSS :
2012-04-25 14:21:04 +00:00
#if 0
2012-04-25 13:07:48 +00:00
case INSTR_DIV_VF :
case INSTR_MUL_IV :
case INSTR_MUL_VI :
2012-04-25 14:21:04 +00:00
# endif
2012-04-28 08:42:03 +00:00
ot = TYPE_VECTOR ;
2012-04-25 13:07:48 +00:00
break ;
2012-04-25 14:21:04 +00:00
#if 0
2012-04-25 13:07:48 +00:00
case INSTR_ADD_SF :
2012-04-28 08:42:03 +00:00
ot = TYPE_POINTER ;
2012-04-25 13:07:48 +00:00
break ;
2012-04-25 14:21:04 +00:00
# endif
2013-06-21 23:40:51 +00:00
/*
* after the following default case , the value of opcode can never
* be 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 62 , 63 , 64 , 65
*/
2012-04-25 13:07:48 +00:00
default :
2012-04-28 22:56:09 +00:00
/* ranges: */
2012-04-25 13:07:48 +00:00
/* boolean operations result in floats */
2013-07-27 11:48:55 +00:00
2013-06-21 23:40:51 +00:00
/*
* opcode > = 10 takes true branch opcode is at least 10
* opcode < = 23 takes false branch opcode is at least 24
*/
2012-04-25 13:07:48 +00:00
if ( opcode > = INSTR_EQ_F & & opcode < = INSTR_GT )
2012-04-28 08:42:03 +00:00
ot = TYPE_FLOAT ;
2013-07-27 11:48:55 +00:00
/*
* At condition " opcode <= 23 " , the value of " opcode " must be
2013-06-21 23:40:51 +00:00
* at least 24.
* At condition " opcode <= 23 " , the value of " opcode " cannot be
* equal to any of { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 62 , 63 , 64 , 65 } .
* The condition " opcode <= 23 " cannot be true .
2013-07-27 11:48:55 +00:00
*
2013-06-21 23:40:51 +00:00
* Thus ot = 2 ( TYPE_FLOAT ) can never be true
*/
#if 0
2012-04-25 13:07:48 +00:00
else if ( opcode > = INSTR_LE & & opcode < = INSTR_GT )
2012-04-28 08:42:03 +00:00
ot = TYPE_FLOAT ;
2012-04-25 13:07:48 +00:00
else if ( opcode > = INSTR_LE_I & & opcode < = INSTR_EQ_FI )
2012-04-28 08:42:03 +00:00
ot = TYPE_FLOAT ;
2012-04-25 14:21:04 +00:00
# endif
2012-04-25 13:07:48 +00:00
break ;
} ;
2012-04-28 08:42:03 +00:00
if ( ot = = TYPE_VOID ) {
2012-04-25 14:21:04 +00:00
/* The AST or parser were supposed to check this! */
2012-04-25 13:07:48 +00:00
return NULL ;
}
2012-04-27 11:28:39 +00:00
2012-11-30 17:19:26 +00:00
return ir_block_create_general_instr ( self , ctx , label , opcode , left , right , ot ) ;
2012-05-01 10:12:53 +00:00
}
2013-07-30 16:00:51 +00:00
ir_value * ir_block_create_unary ( ir_block * self , lex_ctx_t ctx ,
2012-07-26 18:45:18 +00:00
const char * label , int opcode ,
ir_value * operand )
{
int ot = TYPE_FLOAT ;
switch ( opcode ) {
case INSTR_NOT_F :
case INSTR_NOT_V :
case INSTR_NOT_S :
case INSTR_NOT_ENT :
2013-09-30 02:01:46 +00:00
case INSTR_NOT_FNC : /*
case INSTR_NOT_I : */
2012-07-26 18:45:18 +00:00
ot = TYPE_FLOAT ;
break ;
2013-09-30 02:01:46 +00:00
/*
* Negation for virtual instructions is emulated with 0 - value . Thankfully
* the operand for 0 already exists so we just source it from here .
2012-07-26 18:45:18 +00:00
*/
2013-09-30 02:01:46 +00:00
case VINSTR_NEG_F :
return ir_block_create_general_instr ( self , ctx , label , INSTR_SUB_F , NULL , operand , ot ) ;
case VINSTR_NEG_V :
2013-11-13 13:57:14 +00:00
return ir_block_create_general_instr ( self , ctx , label , INSTR_SUB_V , NULL , operand , TYPE_VECTOR ) ;
2013-09-30 02:01:46 +00:00
2012-07-26 18:45:18 +00:00
default :
ot = operand - > vtype ;
break ;
} ;
if ( ot = = TYPE_VOID ) {
/* The AST or parser were supposed to check this! */
return NULL ;
}
/* let's use the general instruction creator and pass NULL for OPB */
2012-11-30 17:19:26 +00:00
return ir_block_create_general_instr ( self , ctx , label , opcode , operand , NULL , ot ) ;
2012-07-26 18:45:18 +00:00
}
2013-07-30 16:00:51 +00:00
static ir_value * ir_block_create_general_instr ( ir_block * self , lex_ctx_t ctx , const char * label ,
2012-05-01 14:23:45 +00:00
int op , ir_value * a , ir_value * b , int outype )
2012-05-01 14:20:44 +00:00
{
ir_instr * instr ;
ir_value * out ;
2012-05-01 14:23:45 +00:00
out = ir_value_out ( self - > owner , label , store_value , outype ) ;
2012-05-01 14:20:44 +00:00
if ( ! out )
return NULL ;
2012-11-30 17:19:26 +00:00
instr = ir_instr_new ( ctx , self , op ) ;
2012-05-01 14:20:44 +00:00
if ( ! instr ) {
ir_value_delete ( out ) ;
return NULL ;
}
if ( ! ir_instr_op ( instr , 0 , out , true ) | |
2012-05-01 14:23:45 +00:00
! ir_instr_op ( instr , 1 , a , false ) | |
! ir_instr_op ( instr , 2 , b , false ) )
2012-05-01 14:20:44 +00:00
{
goto on_error ;
}
2012-11-15 17:32:03 +00:00
vec_push ( self - > instr , instr ) ;
2012-05-01 14:20:44 +00:00
return out ;
on_error :
ir_instr_delete ( instr ) ;
ir_value_delete ( out ) ;
return NULL ;
}
2013-07-30 16:00:51 +00:00
ir_value * ir_block_create_fieldaddress ( ir_block * self , lex_ctx_t ctx , const char * label , ir_value * ent , ir_value * field )
2012-05-01 10:12:53 +00:00
{
2012-07-28 19:59:34 +00:00
ir_value * v ;
2012-05-01 14:23:45 +00:00
/* Support for various pointer types todo if so desired */
if ( ent - > vtype ! = TYPE_ENTITY )
return NULL ;
if ( field - > vtype ! = TYPE_FIELD )
return NULL ;
2012-11-30 17:19:26 +00:00
v = ir_block_create_general_instr ( self , ctx , label , INSTR_ADDRESS , ent , field , TYPE_POINTER ) ;
2012-07-28 19:59:34 +00:00
v - > fieldtype = field - > fieldtype ;
return v ;
2012-05-01 14:23:45 +00:00
}
2012-05-01 10:12:53 +00:00
2013-07-30 16:00:51 +00:00
ir_value * ir_block_create_load_from_ent ( ir_block * self , lex_ctx_t ctx , const char * label , ir_value * ent , ir_value * field , int outype )
2012-05-01 14:23:45 +00:00
{
2012-05-01 14:44:36 +00:00
int op ;
2012-05-01 10:12:53 +00:00
if ( ent - > vtype ! = TYPE_ENTITY )
return NULL ;
2012-05-01 10:14:07 +00:00
/* at some point we could redirect for TYPE_POINTER... but that could lead to carelessness */
if ( field - > vtype ! = TYPE_FIELD )
return NULL ;
2012-05-01 10:12:53 +00:00
switch ( outype )
{
2012-08-18 10:44:17 +00:00
case TYPE_FLOAT : op = INSTR_LOAD_F ; break ;
case TYPE_VECTOR : op = INSTR_LOAD_V ; break ;
case TYPE_STRING : op = INSTR_LOAD_S ; break ;
case TYPE_FIELD : op = INSTR_LOAD_FLD ; break ;
case TYPE_ENTITY : op = INSTR_LOAD_ENT ; break ;
case TYPE_FUNCTION : op = INSTR_LOAD_FNC ; break ;
2012-05-01 10:12:53 +00:00
#if 0
2012-05-01 10:13:04 +00:00
case TYPE_POINTER : op = INSTR_LOAD_I ; break ;
case TYPE_INTEGER : op = INSTR_LOAD_I ; break ;
2012-05-01 10:12:53 +00:00
# endif
default :
2012-11-10 18:35:52 +00:00
irerror ( self - > context , " invalid type for ir_block_create_load_from_ent: %s " , type_name [ outype ] ) ;
2012-05-01 10:12:53 +00:00
return NULL ;
}
2012-11-30 17:19:26 +00:00
return ir_block_create_general_instr ( self , ctx , label , op , ent , field , outype ) ;
2012-04-25 13:07:48 +00:00
}
2012-04-25 13:08:03 +00:00
/* PHI resolving breaks the SSA, and must thus be the last
* step before life - range calculation .
*/
2012-04-27 11:28:39 +00:00
static bool ir_block_naive_phi ( ir_block * self ) ;
bool ir_function_naive_phi ( ir_function * self )
2012-04-25 13:08:03 +00:00
{
size_t i ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > blocks ) ; + + i )
2012-04-27 11:28:39 +00:00
{
if ( ! ir_block_naive_phi ( self - > blocks [ i ] ) )
return false ;
}
return true ;
2012-04-25 13:08:03 +00:00
}
2012-04-27 11:28:39 +00:00
static bool ir_block_naive_phi ( ir_block * self )
2012-04-25 13:08:03 +00:00
{
2012-11-21 15:07:36 +00:00
size_t i , p ; /*, w;*/
2012-04-25 13:08:03 +00:00
/* FIXME: optionally, create_phi can add the phis
* to a list so we don ' t need to loop through blocks
* - anyway : " don't optimize YET "
*/
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > instr ) ; + + i )
2012-04-25 13:08:03 +00:00
{
ir_instr * instr = self - > instr [ i ] ;
if ( instr - > opcode ! = VINSTR_PHI )
continue ;
2012-11-15 17:32:03 +00:00
vec_remove ( self - > instr , i , 1 ) ;
2012-04-25 13:08:03 +00:00
- - i ; /* NOTE: i+1 below */
2012-11-15 17:32:03 +00:00
for ( p = 0 ; p < vec_size ( instr - > phi ) ; + + p )
2012-04-25 13:08:03 +00:00
{
2012-11-21 15:05:54 +00:00
ir_value * v = instr - > phi [ p ] . value ;
ir_block * b = instr - > phi [ p ] . from ;
if ( v - > store = = store_value & &
vec_size ( v - > reads ) = = 1 & &
vec_size ( v - > writes ) = = 1 )
{
/* replace the value */
2012-11-21 15:07:36 +00:00
if ( ! ir_instr_op ( v - > writes [ 0 ] , 0 , instr - > _ops [ 0 ] , true ) )
return false ;
2012-11-21 15:05:54 +00:00
}
else
{
/* force a move instruction */
ir_instr * prevjump = vec_last ( b - > instr ) ;
vec_pop ( b - > instr ) ;
b - > final = false ;
instr - > _ops [ 0 ] - > store = store_global ;
2012-11-30 17:19:26 +00:00
if ( ! ir_block_create_store ( b , instr - > context , instr - > _ops [ 0 ] , v ) )
2012-11-21 15:05:54 +00:00
return false ;
instr - > _ops [ 0 ] - > store = store_value ;
vec_push ( b - > instr , prevjump ) ;
b - > final = true ;
}
2012-04-25 13:08:03 +00:00
}
ir_instr_delete ( instr ) ;
}
2012-04-27 11:28:39 +00:00
return true ;
2012-04-25 13:08:03 +00:00
}
2012-04-25 13:16:55 +00:00
/***********************************************************************
* IR Temp allocation code
* Propagating value life ranges by walking through the function backwards
* until no more changes are made .
* In theory this should happen once more than once for every nested loop
* level .
* Though this implementation might run an additional time for if nests .
*/
/* Enumerate instructions used by value's life-ranges
*/
static void ir_block_enumerate ( ir_block * self , size_t * _eid )
{
size_t i ;
size_t eid = * _eid ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > instr ) ; + + i )
2012-04-25 13:16:55 +00:00
{
self - > instr [ i ] - > eid = eid + + ;
}
* _eid = eid ;
}
/* Enumerate blocks and instructions.
* The block - enumeration is unordered !
* We do not really use the block enumreation , however
* the instruction enumeration is important for life - ranges .
*/
void ir_function_enumerate ( ir_function * self )
{
size_t i ;
2013-01-08 14:22:24 +00:00
size_t instruction_id = 0 ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > blocks ) ; + + i )
2012-04-25 13:16:55 +00:00
{
2013-01-08 14:22:24 +00:00
/* each block now gets an additional "entry" instruction id
* we can use to avoid point - life issues
*/
2013-01-10 15:04:58 +00:00
self - > blocks [ i ] - > entry_id = instruction_id ;
2013-01-08 14:22:24 +00:00
+ + instruction_id ;
2012-04-25 13:16:55 +00:00
self - > blocks [ i ] - > eid = i ;
ir_block_enumerate ( self - > blocks [ i ] , & instruction_id ) ;
}
}
2012-06-25 12:14:34 +00:00
/* Local-value allocator
* After finishing creating the liferange of all values used in a function
* we can allocate their global - positions .
* This is the counterpart to register - allocation in register machines .
*/
2012-06-25 14:06:01 +00:00
typedef struct {
2012-11-15 17:32:03 +00:00
ir_value * * locals ;
size_t * sizes ;
size_t * positions ;
2012-12-06 12:08:22 +00:00
bool * unique ;
2012-06-25 14:06:01 +00:00
} function_allocator ;
2012-12-26 21:09:54 +00:00
static bool function_allocator_alloc ( function_allocator * alloc , ir_value * var )
2012-06-25 12:14:34 +00:00
{
2012-06-25 14:06:01 +00:00
ir_value * slot ;
2012-12-20 22:48:41 +00:00
size_t vsize = ir_value_sizeof ( var ) ;
2012-06-25 14:06:01 +00:00
2012-12-26 21:09:54 +00:00
var - > code . local = vec_size ( alloc - > locals ) ;
2012-06-25 14:06:01 +00:00
slot = ir_value_var ( " reg " , store_global , var - > vtype ) ;
if ( ! slot )
return false ;
if ( ! ir_value_life_merge_into ( slot , var ) )
goto localerror ;
2012-11-15 17:32:03 +00:00
vec_push ( alloc - > locals , slot ) ;
vec_push ( alloc - > sizes , vsize ) ;
2012-12-06 12:08:22 +00:00
vec_push ( alloc - > unique , var - > unique_life ) ;
2012-06-25 14:06:01 +00:00
2012-06-25 12:51:31 +00:00
return true ;
2012-06-25 14:06:01 +00:00
localerror :
ir_value_delete ( slot ) ;
return false ;
}
2012-12-26 21:09:54 +00:00
static bool ir_function_allocator_assign ( ir_function * self , function_allocator * alloc , ir_value * v )
{
size_t a ;
ir_value * slot ;
2013-01-07 13:55:01 +00:00
if ( v - > unique_life )
return function_allocator_alloc ( alloc , v ) ;
2012-12-26 21:09:54 +00:00
for ( a = 0 ; a < vec_size ( alloc - > locals ) ; + + a )
{
/* if it's reserved for a unique liferange: skip */
if ( alloc - > unique [ a ] )
continue ;
slot = alloc - > locals [ a ] ;
/* never resize parameters
* will be required later when overlapping temps + locals
*/
if ( a < vec_size ( self - > params ) & &
alloc - > sizes [ a ] < ir_value_sizeof ( v ) )
{
continue ;
}
if ( ir_values_overlap ( v , slot ) )
continue ;
if ( ! ir_value_life_merge_into ( slot , v ) )
return false ;
/* adjust size for this slot */
if ( alloc - > sizes [ a ] < ir_value_sizeof ( v ) )
alloc - > sizes [ a ] = ir_value_sizeof ( v ) ;
v - > code . local = a ;
return true ;
}
if ( a > = vec_size ( alloc - > locals ) ) {
if ( ! function_allocator_alloc ( alloc , v ) )
return false ;
}
return true ;
}
2012-06-25 14:06:01 +00:00
bool ir_function_allocate_locals ( ir_function * self )
{
2012-12-26 21:09:54 +00:00
size_t i ;
2012-06-25 14:06:01 +00:00
bool retval = true ;
size_t pos ;
2012-12-26 22:18:45 +00:00
bool opt_gt = OPTS_OPTIMIZATION ( OPTIM_GLOBAL_TEMPS ) ;
2012-06-25 14:06:01 +00:00
2012-12-25 22:25:59 +00:00
ir_value * v ;
2012-06-25 14:06:01 +00:00
2012-12-26 22:18:45 +00:00
function_allocator lockalloc , globalloc ;
2012-06-25 14:06:01 +00:00
2012-11-15 17:32:03 +00:00
if ( ! vec_size ( self - > locals ) & & ! vec_size ( self - > values ) )
2012-07-04 11:16:15 +00:00
return true ;
2012-12-26 22:18:45 +00:00
globalloc . locals = NULL ;
globalloc . sizes = NULL ;
globalloc . positions = NULL ;
globalloc . unique = NULL ;
lockalloc . locals = NULL ;
lockalloc . sizes = NULL ;
lockalloc . positions = NULL ;
lockalloc . unique = NULL ;
2012-06-25 14:06:01 +00:00
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > locals ) ; + + i )
2012-06-25 14:06:01 +00:00
{
2012-12-26 22:18:45 +00:00
v = self - > locals [ i ] ;
2013-01-12 13:02:45 +00:00
if ( ( self - > flags & IR_FLAG_MASK_NO_LOCAL_TEMPS ) | | ! OPTS_OPTIMIZATION ( OPTIM_LOCAL_TEMPS ) ) {
2012-12-26 22:18:45 +00:00
v - > locked = true ;
v - > unique_life = true ;
}
2012-12-26 21:09:54 +00:00
else if ( i > = vec_size ( self - > params ) )
break ;
2012-12-26 22:18:45 +00:00
else
v - > locked = true ; /* lock parameters locals */
2013-01-07 13:25:01 +00:00
if ( ! function_allocator_alloc ( ( v - > locked | | ! opt_gt ? & lockalloc : & globalloc ) , v ) )
2012-06-25 14:06:01 +00:00
goto error ;
}
2012-12-26 21:09:54 +00:00
for ( ; i < vec_size ( self - > locals ) ; + + i )
{
v = self - > locals [ i ] ;
if ( ! vec_size ( v - > life ) )
continue ;
2012-12-26 22:18:45 +00:00
if ( ! ir_function_allocator_assign ( self , ( v - > locked | | ! opt_gt ? & lockalloc : & globalloc ) , v ) )
2012-12-26 21:09:54 +00:00
goto error ;
}
2012-06-25 14:06:01 +00:00
/* Allocate a slot for any value that still exists */
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > values ) ; + + i )
2012-06-25 14:06:01 +00:00
{
v = self - > values [ i ] ;
2012-11-15 17:32:03 +00:00
if ( ! vec_size ( v - > life ) )
2012-06-25 14:06:01 +00:00
continue ;
2012-12-25 22:25:59 +00:00
/* CALL optimization:
* If the value is a parameter - temp : 1 write , 1 read from a CALL
* and it ' s not " locked " , write it to the OFS_PARM directly .
*/
2012-12-26 22:18:45 +00:00
if ( OPTS_OPTIMIZATION ( OPTIM_CALL_STORES ) & & ! v - > locked & & ! v - > unique_life ) {
2012-12-26 17:33:16 +00:00
if ( vec_size ( v - > reads ) = = 1 & & vec_size ( v - > writes ) = = 1 & &
2012-12-25 22:25:59 +00:00
( v - > reads [ 0 ] - > opcode = = VINSTR_NRCALL | |
( v - > reads [ 0 ] - > opcode > = INSTR_CALL0 & & v - > reads [ 0 ] - > opcode < = INSTR_CALL8 )
)
)
{
size_t param ;
ir_instr * call = v - > reads [ 0 ] ;
if ( ! vec_ir_value_find ( call - > params , v , & param ) ) {
irerror ( call - > context , " internal error: unlocked parameter %s not found " , v - > name ) ;
goto error ;
}
2012-12-26 18:11:26 +00:00
+ + opts_optimizationcount [ OPTIM_CALL_STORES ] ;
2012-12-25 22:25:59 +00:00
v - > callparam = true ;
if ( param < 8 )
ir_value_code_setaddr ( v , OFS_PARM0 + 3 * param ) ;
else {
2013-01-25 15:25:23 +00:00
size_t nprotos = vec_size ( self - > owner - > extparam_protos ) ;
2012-12-25 22:25:59 +00:00
ir_value * ep ;
param - = 8 ;
2013-01-25 15:25:23 +00:00
if ( nprotos > param )
2012-12-25 22:25:59 +00:00
ep = self - > owner - > extparam_protos [ param ] ;
2013-01-25 15:25:23 +00:00
else
{
ep = ir_gen_extparam_proto ( self - > owner ) ;
while ( + + nprotos < = param )
ep = ir_gen_extparam_proto ( self - > owner ) ;
}
2012-12-25 22:25:59 +00:00
ir_instr_op ( v - > writes [ 0 ] , 0 , ep , true ) ;
call - > params [ param + 8 ] = ep ;
}
continue ;
}
2012-12-26 17:33:16 +00:00
if ( vec_size ( v - > writes ) = = 1 & & v - > writes [ 0 ] - > opcode = = INSTR_CALL0 )
{
v - > store = store_return ;
2012-12-29 14:05:04 +00:00
if ( v - > members [ 0 ] ) v - > members [ 0 ] - > store = store_return ;
if ( v - > members [ 1 ] ) v - > members [ 1 ] - > store = store_return ;
if ( v - > members [ 2 ] ) v - > members [ 2 ] - > store = store_return ;
2012-12-26 18:11:26 +00:00
+ + opts_optimizationcount [ OPTIM_CALL_STORES ] ;
2012-12-26 17:33:16 +00:00
continue ;
}
2012-12-25 22:25:59 +00:00
}
2012-12-26 22:18:45 +00:00
if ( ! ir_function_allocator_assign ( self , ( v - > locked | | ! opt_gt ? & lockalloc : & globalloc ) , v ) )
2012-12-26 21:09:54 +00:00
goto error ;
2012-06-25 14:06:01 +00:00
}
2012-12-26 22:18:45 +00:00
if ( ! lockalloc . sizes & & ! globalloc . sizes ) {
2012-08-19 17:54:15 +00:00
goto cleanup ;
}
2012-12-26 22:18:45 +00:00
vec_push ( lockalloc . positions , 0 ) ;
vec_push ( globalloc . positions , 0 ) ;
2012-08-19 17:54:15 +00:00
2012-06-25 14:06:01 +00:00
/* Adjust slot positions based on sizes */
2012-12-26 22:18:45 +00:00
if ( lockalloc . sizes ) {
2012-12-27 10:46:08 +00:00
pos = ( vec_size ( lockalloc . sizes ) ? lockalloc . positions [ 0 ] : 0 ) ;
2012-12-26 22:18:45 +00:00
for ( i = 1 ; i < vec_size ( lockalloc . sizes ) ; + + i )
{
pos = lockalloc . positions [ i - 1 ] + lockalloc . sizes [ i - 1 ] ;
vec_push ( lockalloc . positions , pos ) ;
}
self - > allocated_locals = pos + vec_last ( lockalloc . sizes ) ;
}
if ( globalloc . sizes ) {
2012-12-27 10:46:08 +00:00
pos = ( vec_size ( globalloc . sizes ) ? globalloc . positions [ 0 ] : 0 ) ;
2012-12-26 22:18:45 +00:00
for ( i = 1 ; i < vec_size ( globalloc . sizes ) ; + + i )
{
pos = globalloc . positions [ i - 1 ] + globalloc . sizes [ i - 1 ] ;
vec_push ( globalloc . positions , pos ) ;
}
self - > globaltemps = pos + vec_last ( globalloc . sizes ) ;
2012-06-25 14:06:01 +00:00
}
2012-06-25 15:43:10 +00:00
2012-12-06 12:08:22 +00:00
/* Locals need to know their new position */
for ( i = 0 ; i < vec_size ( self - > locals ) ; + + i ) {
2012-12-26 22:18:45 +00:00
v = self - > locals [ i ] ;
if ( v - > locked | | ! opt_gt )
v - > code . local = lockalloc . positions [ v - > code . local ] ;
else
v - > code . local = globalloc . positions [ v - > code . local ] ;
2012-12-06 12:08:22 +00:00
}
/* Take over the actual slot positions on values */
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > values ) ; + + i ) {
2012-12-26 22:18:45 +00:00
v = self - > values [ i ] ;
if ( v - > locked | | ! opt_gt )
v - > code . local = lockalloc . positions [ v - > code . local ] ;
else
v - > code . local = globalloc . positions [ v - > code . local ] ;
2012-08-19 15:29:36 +00:00
}
2012-06-25 14:06:01 +00:00
goto cleanup ;
error :
retval = false ;
cleanup :
2012-12-26 22:18:45 +00:00
for ( i = 0 ; i < vec_size ( lockalloc . locals ) ; + + i )
ir_value_delete ( lockalloc . locals [ i ] ) ;
for ( i = 0 ; i < vec_size ( globalloc . locals ) ; + + i )
ir_value_delete ( globalloc . locals [ i ] ) ;
vec_free ( globalloc . unique ) ;
vec_free ( globalloc . locals ) ;
vec_free ( globalloc . sizes ) ;
vec_free ( globalloc . positions ) ;
vec_free ( lockalloc . unique ) ;
vec_free ( lockalloc . locals ) ;
vec_free ( lockalloc . sizes ) ;
vec_free ( lockalloc . positions ) ;
2012-06-25 14:06:01 +00:00
return retval ;
2012-06-25 12:14:34 +00:00
}
2012-04-25 13:16:55 +00:00
/* Get information about which operand
* is read from , or written to .
*/
static void ir_op_read_write ( int op , size_t * read , size_t * write )
{
switch ( op )
{
case VINSTR_JUMP :
case INSTR_GOTO :
* write = 0 ;
* read = 0 ;
break ;
case INSTR_IF :
case INSTR_IFNOT :
2012-04-25 14:21:04 +00:00
#if 0
2012-04-25 13:16:55 +00:00
case INSTR_IF_S :
case INSTR_IFNOT_S :
2012-04-25 14:21:04 +00:00
# endif
2012-04-25 13:16:55 +00:00
case INSTR_RETURN :
case VINSTR_COND :
* write = 0 ;
* read = 1 ;
break ;
2012-08-19 15:46:10 +00:00
case INSTR_STOREP_F :
case INSTR_STOREP_V :
case INSTR_STOREP_S :
case INSTR_STOREP_ENT :
case INSTR_STOREP_FLD :
case INSTR_STOREP_FNC :
* write = 0 ;
* read = 7 ;
break ;
2012-04-25 13:16:55 +00:00
default :
* write = 1 ;
* read = 6 ;
break ;
} ;
}
2012-04-26 08:16:15 +00:00
static bool ir_block_living_add_instr ( ir_block * self , size_t eid )
2012-04-25 13:16:55 +00:00
{
2013-01-15 19:27:23 +00:00
size_t i ;
const size_t vs = vec_size ( self - > living ) ;
bool changed = false ;
for ( i = 0 ; i ! = vs ; + + i )
2012-04-25 13:16:55 +00:00
{
2013-01-15 19:27:23 +00:00
if ( ir_value_life_merge ( self - > living [ i ] , eid ) )
changed = true ;
2012-04-25 13:16:55 +00:00
}
return changed ;
}
2012-12-25 20:03:26 +00:00
static bool ir_block_living_lock ( ir_block * self )
{
size_t i ;
bool changed = false ;
for ( i = 0 ; i ! = vec_size ( self - > living ) ; + + i )
{
2013-01-07 13:25:01 +00:00
if ( ! self - > living [ i ] - > locked ) {
self - > living [ i ] - > locked = true ;
2012-12-25 20:03:26 +00:00
changed = true ;
2013-01-07 13:25:01 +00:00
}
2012-12-25 20:03:26 +00:00
}
return changed ;
}
2013-02-11 10:37:39 +00:00
static bool ir_block_life_propagate ( ir_block * self , bool * changed )
2012-04-25 13:16:55 +00:00
{
ir_instr * instr ;
ir_value * value ;
2013-02-11 10:37:39 +00:00
size_t i , o , p , mem , cnt ;
2012-04-25 13:16:55 +00:00
/* bitmasks which operands are read from or written to */
size_t read , write ;
2012-12-28 12:54:20 +00:00
char dbg_ind [ 16 ] ;
dbg_ind [ 0 ] = ' # ' ;
dbg_ind [ 1 ] = ' 0 ' ;
2012-04-25 13:16:55 +00:00
( void ) dbg_ind ;
2013-02-11 10:37:39 +00:00
vec_free ( self - > living ) ;
p = vec_size ( self - > exits ) ;
for ( i = 0 ; i < p ; + + i ) {
ir_block * prev = self - > exits [ i ] ;
cnt = vec_size ( prev - > living ) ;
for ( o = 0 ; o < cnt ; + + o ) {
if ( ! vec_ir_value_find ( self - > living , prev - > living [ o ] , NULL ) )
vec_push ( self - > living , prev - > living [ o ] ) ;
}
2012-04-27 11:28:39 +00:00
}
2012-04-25 13:16:55 +00:00
2012-11-15 17:32:03 +00:00
i = vec_size ( self - > instr ) ;
2012-04-25 13:16:55 +00:00
while ( i )
{ - - i ;
instr = self - > instr [ i ] ;
/* See which operands are read and write operands */
ir_op_read_write ( instr - > opcode , & read , & write ) ;
2012-12-23 19:50:21 +00:00
/* Go through the 3 main operands
* writes first , then reads
*/
2012-04-25 13:16:55 +00:00
for ( o = 0 ; o < 3 ; + + o )
{
if ( ! instr - > _ops [ o ] ) /* no such operand */
continue ;
value = instr - > _ops [ o ] ;
/* We only care about locals */
2012-07-22 10:07:07 +00:00
/* we also calculate parameter liferanges so that locals
* can take up parameter slots */
2012-04-25 13:16:55 +00:00
if ( value - > store ! = store_value & &
2012-07-22 10:07:07 +00:00
value - > store ! = store_local & &
value - > store ! = store_param )
2012-04-25 13:16:55 +00:00
continue ;
/* write operands */
/* When we write to a local, we consider it "dead" for the
* remaining upper part of the function , since in SSA a value
* can only be written once ( = = created )
*/
if ( write & ( 1 < < o ) )
{
2012-05-04 08:20:04 +00:00
size_t idx ;
2012-11-15 17:32:03 +00:00
bool in_living = vec_ir_value_find ( self - > living , value , & idx ) ;
2012-05-04 08:20:04 +00:00
if ( ! in_living )
2012-04-25 13:16:55 +00:00
{
/* If the value isn't alive it hasn't been read before... */
/* TODO: See if the warning can be emitted during parsing or AST processing
* otherwise have warning printed here .
* IF printing a warning here : include filecontext_t ,
* and make sure it ' s only printed once
* since this function is run multiple times .
*/
2012-11-15 00:28:46 +00:00
/* con_err( "Value only written %s\n", value->name); */
2013-01-15 19:57:30 +00:00
if ( ir_value_life_merge ( value , instr - > eid ) )
* changed = true ;
2012-04-25 13:16:55 +00:00
} else {
/* since 'living' won't contain it
* anymore , merge the value , since
* ( A ) doesn ' t .
*/
2013-01-15 19:57:30 +00:00
if ( ir_value_life_merge ( value , instr - > eid ) )
* changed = true ;
2012-04-25 13:16:55 +00:00
/* Then remove */
2012-11-15 17:32:03 +00:00
vec_remove ( self - > living , idx , 1 ) ;
2012-04-25 13:16:55 +00:00
}
2012-12-24 11:43:05 +00:00
/* Removing a vector removes all members */
for ( mem = 0 ; mem < 3 ; + + mem ) {
if ( value - > members [ mem ] & & vec_ir_value_find ( self - > living , value - > members [ mem ] , & idx ) ) {
2013-01-15 19:57:30 +00:00
if ( ir_value_life_merge ( value - > members [ mem ] , instr - > eid ) )
* changed = true ;
2012-12-24 11:43:05 +00:00
vec_remove ( self - > living , idx , 1 ) ;
}
}
/* Removing the last member removes the vector */
if ( value - > memberof ) {
value = value - > memberof ;
for ( mem = 0 ; mem < 3 ; + + mem ) {
if ( value - > members [ mem ] & & vec_ir_value_find ( self - > living , value - > members [ mem ] , NULL ) )
break ;
}
if ( mem = = 3 & & vec_ir_value_find ( self - > living , value , & idx ) ) {
2013-01-15 19:57:30 +00:00
if ( ir_value_life_merge ( value , instr - > eid ) )
* changed = true ;
2012-12-24 11:43:05 +00:00
vec_remove ( self - > living , idx , 1 ) ;
}
}
2012-04-25 13:16:55 +00:00
}
}
2012-12-23 19:50:21 +00:00
2013-08-26 08:25:29 +00:00
/* These operations need a special case as they can break when using
* same source and destination operand otherwise , as the engine may
* read the source multiple times . */
if ( instr - > opcode = = INSTR_MUL_VF | |
instr - > opcode = = VINSTR_BITAND_VF | |
instr - > opcode = = VINSTR_BITOR_VF | |
2013-08-27 10:27:20 +00:00
instr - > opcode = = VINSTR_BITXOR | |
2013-08-26 08:25:29 +00:00
instr - > opcode = = VINSTR_BITXOR_VF | |
2013-08-31 18:49:06 +00:00
instr - > opcode = = VINSTR_BITXOR_V | |
instr - > opcode = = VINSTR_CROSS )
2013-01-08 20:21:52 +00:00
{
value = instr - > _ops [ 2 ] ;
/* the float source will get an additional lifetime */
if ( ir_value_life_merge ( value , instr - > eid + 1 ) )
* changed = true ;
if ( value - > memberof & & ir_value_life_merge ( value - > memberof , instr - > eid + 1 ) )
* changed = true ;
}
2013-08-27 10:27:20 +00:00
if ( instr - > opcode = = INSTR_MUL_FV | |
instr - > opcode = = INSTR_LOAD_V | |
instr - > opcode = = VINSTR_BITXOR | |
instr - > opcode = = VINSTR_BITXOR_VF | |
2013-08-31 18:49:06 +00:00
instr - > opcode = = VINSTR_BITXOR_V | |
instr - > opcode = = VINSTR_CROSS )
2013-01-08 20:21:52 +00:00
{
value = instr - > _ops [ 1 ] ;
/* the float source will get an additional lifetime */
if ( ir_value_life_merge ( value , instr - > eid + 1 ) )
* changed = true ;
if ( value - > memberof & & ir_value_life_merge ( value - > memberof , instr - > eid + 1 ) )
* changed = true ;
}
2012-12-23 19:50:21 +00:00
for ( o = 0 ; o < 3 ; + + o )
{
if ( ! instr - > _ops [ o ] ) /* no such operand */
continue ;
value = instr - > _ops [ o ] ;
/* We only care about locals */
/* we also calculate parameter liferanges so that locals
* can take up parameter slots */
if ( value - > store ! = store_value & &
value - > store ! = store_local & &
value - > store ! = store_param )
continue ;
/* read operands */
if ( read & ( 1 < < o ) )
{
if ( ! vec_ir_value_find ( self - > living , value , NULL ) )
vec_push ( self - > living , value ) ;
2012-12-24 11:43:05 +00:00
/* reading adds the full vector */
if ( value - > memberof & & ! vec_ir_value_find ( self - > living , value - > memberof , NULL ) )
vec_push ( self - > living , value - > memberof ) ;
for ( mem = 0 ; mem < 3 ; + + mem ) {
if ( value - > members [ mem ] & & ! vec_ir_value_find ( self - > living , value - > members [ mem ] , NULL ) )
vec_push ( self - > living , value - > members [ mem ] ) ;
}
2012-12-23 19:50:21 +00:00
}
}
/* PHI operands are always read operands */
for ( p = 0 ; p < vec_size ( instr - > phi ) ; + + p )
{
value = instr - > phi [ p ] . value ;
if ( ! vec_ir_value_find ( self - > living , value , NULL ) )
vec_push ( self - > living , value ) ;
2012-12-24 11:43:05 +00:00
/* reading adds the full vector */
if ( value - > memberof & & ! vec_ir_value_find ( self - > living , value - > memberof , NULL ) )
vec_push ( self - > living , value - > memberof ) ;
for ( mem = 0 ; mem < 3 ; + + mem ) {
if ( value - > members [ mem ] & & ! vec_ir_value_find ( self - > living , value - > members [ mem ] , NULL ) )
vec_push ( self - > living , value - > members [ mem ] ) ;
}
2012-12-23 19:50:21 +00:00
}
2012-12-25 22:24:31 +00:00
/* on a call, all these values must be "locked" */
if ( instr - > opcode > = INSTR_CALL0 & & instr - > opcode < = INSTR_CALL8 ) {
if ( ir_block_living_lock ( self ) )
* changed = true ;
}
2012-12-23 19:50:21 +00:00
/* call params are read operands too */
for ( p = 0 ; p < vec_size ( instr - > params ) ; + + p )
{
value = instr - > params [ p ] ;
if ( ! vec_ir_value_find ( self - > living , value , NULL ) )
vec_push ( self - > living , value ) ;
2012-12-24 11:43:05 +00:00
/* reading adds the full vector */
if ( value - > memberof & & ! vec_ir_value_find ( self - > living , value - > memberof , NULL ) )
vec_push ( self - > living , value - > memberof ) ;
for ( mem = 0 ; mem < 3 ; + + mem ) {
if ( value - > members [ mem ] & & ! vec_ir_value_find ( self - > living , value - > members [ mem ] , NULL ) )
vec_push ( self - > living , value - > members [ mem ] ) ;
}
2012-12-23 19:50:21 +00:00
}
2012-04-25 13:16:55 +00:00
/* (A) */
2013-01-15 19:57:30 +00:00
if ( ir_block_living_add_instr ( self , instr - > eid ) )
* changed = true ;
2012-04-25 13:16:55 +00:00
}
2013-01-08 14:22:24 +00:00
/* the "entry" instruction ID */
2013-01-15 19:57:30 +00:00
if ( ir_block_living_add_instr ( self , self - > entry_id ) )
* changed = true ;
2012-04-25 13:16:55 +00:00
2013-02-11 10:37:39 +00:00
return true ;
}
2012-04-27 16:00:57 +00:00
2013-02-11 10:37:39 +00:00
bool ir_function_calculate_liferanges ( ir_function * self )
{
size_t i , s ;
bool changed ;
2012-04-25 13:16:55 +00:00
2013-02-11 10:37:39 +00:00
/* parameters live at 0 */
for ( i = 0 ; i < vec_size ( self - > params ) ; + + i )
2013-06-22 01:56:22 +00:00
if ( ! ir_value_life_merge ( self - > locals [ i ] , 0 ) )
compile_error ( self - > context , " internal error: failed value-life merging " ) ;
2012-04-27 11:28:39 +00:00
2013-02-11 10:37:39 +00:00
do {
self - > run_id + + ;
changed = false ;
i = vec_size ( self - > blocks ) ;
while ( i - - ) {
ir_block_life_propagate ( self - > blocks [ i ] , & changed ) ;
}
} while ( changed ) ;
if ( vec_size ( self - > blocks ) ) {
ir_block * block = self - > blocks [ 0 ] ;
for ( i = 0 ; i < vec_size ( block - > living ) ; + + i ) {
ir_value * v = block - > living [ i ] ;
if ( v - > store ! = store_local )
continue ;
if ( v - > vtype = = TYPE_VECTOR )
continue ;
self - > flags | = IR_FLAG_HAS_UNINITIALIZED ;
/* find the instruction reading from it */
for ( s = 0 ; s < vec_size ( v - > reads ) ; + + s ) {
if ( v - > reads [ s ] - > eid = = v - > life [ 0 ] . end )
break ;
}
if ( s < vec_size ( v - > reads ) ) {
if ( irwarning ( v - > context , WARN_USED_UNINITIALIZED ,
" variable `%s` may be used uninitialized in this function \n "
" -> %s:%i " ,
v - > name ,
v - > reads [ s ] - > context . file , v - > reads [ s ] - > context . line )
)
{
return false ;
}
continue ;
}
if ( v - > memberof ) {
ir_value * vec = v - > memberof ;
for ( s = 0 ; s < vec_size ( vec - > reads ) ; + + s ) {
2013-06-22 18:31:50 +00:00
if ( vec - > reads [ s ] - > eid = = v - > life [ 0 ] . end )
2013-02-11 10:37:39 +00:00
break ;
}
if ( s < vec_size ( vec - > reads ) ) {
if ( irwarning ( v - > context , WARN_USED_UNINITIALIZED ,
" variable `%s` may be used uninitialized in this function \n "
" -> %s:%i " ,
v - > name ,
vec - > reads [ s ] - > context . file , vec - > reads [ s ] - > context . line )
)
{
return false ;
}
continue ;
}
}
if ( irwarning ( v - > context , WARN_USED_UNINITIALIZED ,
" variable `%s` may be used uninitialized in this function " , v - > name ) )
{
return false ;
}
}
}
2012-04-27 11:28:39 +00:00
return true ;
2012-04-25 13:16:55 +00:00
}
2012-04-28 09:50:01 +00:00
2012-05-04 22:03:18 +00:00
/***********************************************************************
* IR Code - Generation
*
* Since the IR has the convention of putting ' write ' operands
* at the beginning , we have to rotate the operands of instructions
* properly in order to generate valid QCVM code .
*
* Having destinations at a fixed position is more convenient . In QC
* this is * mostly * OPC , but FTE adds at least 2 instructions which
* read from from OPA , and store to OPB rather than OPC . Which is
* partially the reason why the implementation of these instructions
* in darkplaces has been delayed for so long .
*
* Breaking conventions is annoying . . .
*/
2013-06-20 10:52:58 +00:00
static bool ir_builder_gen_global ( ir_builder * self , ir_value * global , bool islocal ) ;
2012-05-05 08:56:00 +00:00
2013-04-25 09:35:30 +00:00
static bool gen_global_field ( code_t * code , ir_value * global )
2012-05-05 08:56:00 +00:00
{
2012-11-30 12:47:28 +00:00
if ( global - > hasvalue )
2012-05-05 08:56:00 +00:00
{
ir_value * fld = global - > constval . vpointer ;
if ( ! fld ) {
2012-08-19 18:45:26 +00:00
irerror ( global - > context , " Invalid field constant with no field: %s " , global - > name ) ;
2012-05-05 08:56:00 +00:00
return false ;
}
/* copy the field's value */
2013-04-25 09:35:30 +00:00
ir_value_code_setaddr ( global , vec_size ( code - > globals ) ) ;
vec_push ( code - > globals , fld - > code . fieldaddr ) ;
2012-08-11 17:34:58 +00:00
if ( global - > fieldtype = = TYPE_VECTOR ) {
2013-04-25 09:35:30 +00:00
vec_push ( code - > globals , fld - > code . fieldaddr + 1 ) ;
vec_push ( code - > globals , fld - > code . fieldaddr + 2 ) ;
2012-08-11 17:34:58 +00:00
}
2012-05-05 08:56:00 +00:00
}
else
{
2013-04-25 09:35:30 +00:00
ir_value_code_setaddr ( global , vec_size ( code - > globals ) ) ;
vec_push ( code - > globals , 0 ) ;
2012-08-11 17:34:58 +00:00
if ( global - > fieldtype = = TYPE_VECTOR ) {
2013-04-25 09:35:30 +00:00
vec_push ( code - > globals , 0 ) ;
vec_push ( code - > globals , 0 ) ;
2012-08-11 17:34:58 +00:00
}
2012-05-05 08:56:00 +00:00
}
if ( global - > code . globaladdr < 0 )
return false ;
return true ;
}
2013-04-25 09:35:30 +00:00
static bool gen_global_pointer ( code_t * code , ir_value * global )
2012-05-05 08:56:00 +00:00
{
2012-11-30 12:47:28 +00:00
if ( global - > hasvalue )
2012-05-05 08:56:00 +00:00
{
ir_value * target = global - > constval . vpointer ;
if ( ! target ) {
2012-08-19 18:45:26 +00:00
irerror ( global - > context , " Invalid pointer constant: %s " , global - > name ) ;
2012-05-05 08:56:00 +00:00
/* NULL pointers are pointing to the NULL constant, which also
* sits at address 0 , but still has an ir_value for itself .
*/
return false ;
}
/* Here, relocations ARE possible - in fteqcc-enhanced-qc:
* void ( ) foo ; < - proto
* void ( ) * fooptr = & foo ;
* void ( ) foo = { code }
*/
if ( ! target - > code . globaladdr ) {
/* FIXME: Check for the constant nullptr ir_value!
* because then code . globaladdr being 0 is valid .
*/
2012-08-19 18:45:26 +00:00
irerror ( global - > context , " FIXME: Relocation support " ) ;
2012-05-05 08:56:00 +00:00
return false ;
}
2013-04-25 09:35:30 +00:00
ir_value_code_setaddr ( global , vec_size ( code - > globals ) ) ;
vec_push ( code - > globals , target - > code . globaladdr ) ;
2012-05-05 08:56:00 +00:00
}
else
{
2013-04-25 09:35:30 +00:00
ir_value_code_setaddr ( global , vec_size ( code - > globals ) ) ;
vec_push ( code - > globals , 0 ) ;
2012-05-05 08:56:00 +00:00
}
if ( global - > code . globaladdr < 0 )
return false ;
return true ;
}
2013-04-25 09:35:30 +00:00
static bool gen_blocks_recursive ( code_t * code , ir_function * func , ir_block * block )
2012-05-09 13:02:58 +00:00
{
2013-07-30 16:00:51 +00:00
prog_section_statement_t stmt ;
2012-05-09 13:02:58 +00:00
ir_instr * instr ;
ir_block * target ;
ir_block * ontrue ;
ir_block * onfalse ;
size_t stidx ;
size_t i ;
2013-08-26 08:25:29 +00:00
int j ;
2012-05-09 13:02:58 +00:00
block - > generated = true ;
2013-04-25 09:35:30 +00:00
block - > code_start = vec_size ( code - > statements ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( block - > instr ) ; + + i )
2012-05-09 13:02:58 +00:00
{
instr = block - > instr [ i ] ;
if ( instr - > opcode = = VINSTR_PHI ) {
2012-08-19 18:45:26 +00:00
irerror ( block - > context , " cannot generate virtual instruction (phi) " ) ;
2012-05-09 13:02:58 +00:00
return false ;
}
if ( instr - > opcode = = VINSTR_JUMP ) {
target = instr - > bops [ 0 ] ;
/* for uncoditional jumps, if the target hasn't been generated
* yet , we generate them right here .
*/
2013-01-09 15:00:16 +00:00
if ( ! target - > generated )
2013-04-25 09:35:30 +00:00
return gen_blocks_recursive ( code , func , target ) ;
2012-05-09 13:02:58 +00:00
/* otherwise we generate a jump instruction */
stmt . opcode = INSTR_GOTO ;
2013-04-25 09:35:30 +00:00
stmt . o1 . s1 = ( target - > code_start ) - vec_size ( code - > statements ) ;
2012-05-09 13:02:58 +00:00
stmt . o2 . s1 = 0 ;
stmt . o3 . s1 = 0 ;
2012-12-18 10:57:30 +00:00
if ( stmt . o1 . s1 ! = 1 )
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2012-05-09 13:02:58 +00:00
/* no further instructions can be in this block */
return true ;
}
2013-08-26 08:25:29 +00:00
if ( instr - > opcode = = VINSTR_BITXOR ) {
stmt . opcode = INSTR_BITOR ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
stmt . opcode = INSTR_BITAND ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( func - > owner - > vinstr_temp [ 0 ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
stmt . opcode = INSTR_SUB_F ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
stmt . o2 . s1 = ir_value_code_addr ( func - > owner - > vinstr_temp [ 0 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
/* instruction generated */
continue ;
}
if ( instr - > opcode = = VINSTR_BITAND_V ) {
stmt . opcode = INSTR_BITAND ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
+ + stmt . o1 . s1 ;
+ + stmt . o2 . s1 ;
+ + stmt . o3 . s1 ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
+ + stmt . o1 . s1 ;
+ + stmt . o2 . s1 ;
+ + stmt . o3 . s1 ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
/* instruction generated */
continue ;
}
if ( instr - > opcode = = VINSTR_BITOR_V ) {
stmt . opcode = INSTR_BITOR ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
+ + stmt . o1 . s1 ;
+ + stmt . o2 . s1 ;
+ + stmt . o3 . s1 ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
+ + stmt . o1 . s1 ;
+ + stmt . o2 . s1 ;
+ + stmt . o3 . s1 ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
/* instruction generated */
continue ;
}
if ( instr - > opcode = = VINSTR_BITXOR_V ) {
for ( j = 0 ; j < 3 ; + + j ) {
stmt . opcode = INSTR_BITOR ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) + j ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) + j ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) + j ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
stmt . opcode = INSTR_BITAND ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) + j ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) + j ;
stmt . o3 . s1 = ir_value_code_addr ( func - > owner - > vinstr_temp [ 0 ] ) + j ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
}
stmt . opcode = INSTR_SUB_V ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
stmt . o2 . s1 = ir_value_code_addr ( func - > owner - > vinstr_temp [ 0 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
/* instruction generated */
continue ;
}
if ( instr - > opcode = = VINSTR_BITAND_VF ) {
stmt . opcode = INSTR_BITAND ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
+ + stmt . o1 . s1 ;
+ + stmt . o3 . s1 ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
+ + stmt . o1 . s1 ;
+ + stmt . o3 . s1 ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
/* instruction generated */
continue ;
}
if ( instr - > opcode = = VINSTR_BITOR_VF ) {
stmt . opcode = INSTR_BITOR ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
+ + stmt . o1 . s1 ;
+ + stmt . o3 . s1 ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
+ + stmt . o1 . s1 ;
+ + stmt . o3 . s1 ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
/* instruction generated */
continue ;
}
if ( instr - > opcode = = VINSTR_BITXOR_VF ) {
for ( j = 0 ; j < 3 ; + + j ) {
stmt . opcode = INSTR_BITOR ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) + j ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) + j ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
stmt . opcode = INSTR_BITAND ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) + j ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( func - > owner - > vinstr_temp [ 0 ] ) + j ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
}
stmt . opcode = INSTR_SUB_V ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
stmt . o2 . s1 = ir_value_code_addr ( func - > owner - > vinstr_temp [ 0 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2013-08-26 08:25:29 +00:00
/* instruction generated */
continue ;
}
2013-08-31 18:49:06 +00:00
if ( instr - > opcode = = VINSTR_CROSS ) {
stmt . opcode = INSTR_MUL_F ;
for ( j = 0 ; j < 3 ; + + j ) {
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) + ( j + 1 ) % 3 ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) + ( j + 2 ) % 3 ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) + j ;
code_push_statement ( code , & stmt , instr - > context ) ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) + ( j + 2 ) % 3 ;
stmt . o2 . s1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) + ( j + 1 ) % 3 ;
stmt . o3 . s1 = ir_value_code_addr ( func - > owner - > vinstr_temp [ 0 ] ) + j ;
code_push_statement ( code , & stmt , instr - > context ) ;
}
stmt . opcode = INSTR_SUB_V ;
stmt . o1 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
stmt . o2 . s1 = ir_value_code_addr ( func - > owner - > vinstr_temp [ 0 ] ) ;
stmt . o3 . s1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
code_push_statement ( code , & stmt , instr - > context ) ;
/* instruction generated */
continue ;
}
2012-05-09 13:02:58 +00:00
if ( instr - > opcode = = VINSTR_COND ) {
ontrue = instr - > bops [ 0 ] ;
onfalse = instr - > bops [ 1 ] ;
/* TODO: have the AST signal which block should
* come first : eg . optimize IFs without ELSE . . .
*/
2012-08-08 12:49:37 +00:00
stmt . o1 . u1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
2012-06-25 17:27:50 +00:00
stmt . o2 . u1 = 0 ;
2012-05-09 13:02:58 +00:00
stmt . o3 . s1 = 0 ;
2012-06-25 17:27:50 +00:00
2012-05-09 13:02:58 +00:00
if ( ontrue - > generated ) {
stmt . opcode = INSTR_IF ;
2013-04-25 09:35:30 +00:00
stmt . o2 . s1 = ( ontrue - > code_start ) - vec_size ( code - > statements ) ;
2012-12-18 11:57:09 +00:00
if ( stmt . o2 . s1 ! = 1 )
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2012-05-09 13:02:58 +00:00
}
if ( onfalse - > generated ) {
stmt . opcode = INSTR_IFNOT ;
2013-04-25 09:35:30 +00:00
stmt . o2 . s1 = ( onfalse - > code_start ) - vec_size ( code - > statements ) ;
2012-12-18 11:57:09 +00:00
if ( stmt . o2 . s1 ! = 1 )
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2012-05-09 13:02:58 +00:00
}
if ( ! ontrue - > generated ) {
2013-01-09 15:00:16 +00:00
if ( onfalse - > generated )
2013-04-25 09:35:30 +00:00
return gen_blocks_recursive ( code , func , ontrue ) ;
2012-05-09 13:02:58 +00:00
}
if ( ! onfalse - > generated ) {
2013-01-09 15:00:16 +00:00
if ( ontrue - > generated )
2013-04-25 09:35:30 +00:00
return gen_blocks_recursive ( code , func , onfalse ) ;
2012-05-09 13:02:58 +00:00
}
/* neither ontrue nor onfalse exist */
stmt . opcode = INSTR_IFNOT ;
2012-11-21 16:35:11 +00:00
if ( ! instr - > likely ) {
/* Honor the likelyhood hint */
ir_block * tmp = onfalse ;
stmt . opcode = INSTR_IF ;
onfalse = ontrue ;
ontrue = tmp ;
}
2013-04-25 09:35:30 +00:00
stidx = vec_size ( code - > statements ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2012-05-09 13:02:58 +00:00
/* on false we jump, so add ontrue-path */
2013-04-25 09:35:30 +00:00
if ( ! gen_blocks_recursive ( code , func , ontrue ) )
2012-05-09 13:02:58 +00:00
return false ;
/* fixup the jump address */
2013-04-25 09:35:30 +00:00
code - > statements [ stidx ] . o2 . s1 = vec_size ( code - > statements ) - stidx ;
2012-05-09 13:02:58 +00:00
/* generate onfalse path */
if ( onfalse - > generated ) {
2012-06-25 17:27:50 +00:00
/* fixup the jump address */
2013-04-25 09:35:30 +00:00
code - > statements [ stidx ] . o2 . s1 = ( onfalse - > code_start ) - ( stidx ) ;
if ( stidx + 2 = = vec_size ( code - > statements ) & & code - > statements [ stidx ] . o2 . s1 = = 1 ) {
code - > statements [ stidx ] = code - > statements [ stidx + 1 ] ;
if ( code - > statements [ stidx ] . o1 . s1 < 0 )
code - > statements [ stidx ] . o1 . s1 + + ;
code_pop_statement ( code ) ;
2012-12-18 12:40:59 +00:00
}
2013-04-25 09:35:30 +00:00
stmt . opcode = vec_last ( code - > statements ) . opcode ;
2012-11-21 16:40:35 +00:00
if ( stmt . opcode = = INSTR_GOTO | |
stmt . opcode = = INSTR_IF | |
stmt . opcode = = INSTR_IFNOT | |
stmt . opcode = = INSTR_RETURN | |
stmt . opcode = = INSTR_DONE )
{
/* no use jumping from here */
return true ;
}
2012-05-09 13:02:58 +00:00
/* may have been generated in the previous recursive call */
stmt . opcode = INSTR_GOTO ;
2013-04-25 09:35:30 +00:00
stmt . o1 . s1 = ( onfalse - > code_start ) - vec_size ( code - > statements ) ;
2012-05-09 13:02:58 +00:00
stmt . o2 . s1 = 0 ;
stmt . o3 . s1 = 0 ;
2012-12-18 10:57:30 +00:00
if ( stmt . o1 . s1 ! = 1 )
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2012-11-15 17:32:03 +00:00
return true ;
2012-05-09 13:02:58 +00:00
}
2013-04-25 09:35:30 +00:00
else if ( stidx + 2 = = vec_size ( code - > statements ) & & code - > statements [ stidx ] . o2 . s1 = = 1 ) {
code - > statements [ stidx ] = code - > statements [ stidx + 1 ] ;
if ( code - > statements [ stidx ] . o1 . s1 < 0 )
code - > statements [ stidx ] . o1 . s1 + + ;
code_pop_statement ( code ) ;
2012-12-18 12:40:59 +00:00
}
2012-05-09 13:02:58 +00:00
/* if not, generate now */
2013-04-25 09:35:30 +00:00
return gen_blocks_recursive ( code , func , onfalse ) ;
2012-05-09 13:02:58 +00:00
}
2012-12-19 19:38:32 +00:00
if ( ( instr - > opcode > = INSTR_CALL0 & & instr - > opcode < = INSTR_CALL8 )
| | instr - > opcode = = VINSTR_NRCALL )
{
2012-11-18 19:17:59 +00:00
size_t p , first ;
2012-07-03 20:47:01 +00:00
ir_value * retvalue ;
2012-11-18 19:17:59 +00:00
first = vec_size ( instr - > params ) ;
if ( first > 8 )
first = 8 ;
for ( p = 0 ; p < first ; + + p )
2012-07-03 20:47:01 +00:00
{
ir_value * param = instr - > params [ p ] ;
2012-12-25 22:25:59 +00:00
if ( param - > callparam )
continue ;
2012-07-03 20:47:01 +00:00
stmt . opcode = INSTR_STORE_F ;
stmt . o3 . u1 = 0 ;
2012-11-09 19:11:17 +00:00
if ( param - > vtype = = TYPE_FIELD )
stmt . opcode = field_store_instr [ param - > fieldtype ] ;
2012-12-31 12:19:34 +00:00
else if ( param - > vtype = = TYPE_NIL )
stmt . opcode = INSTR_STORE_V ;
2012-11-09 19:11:17 +00:00
else
stmt . opcode = type_store_instr [ param - > vtype ] ;
2012-08-08 12:49:37 +00:00
stmt . o1 . u1 = ir_value_code_addr ( param ) ;
2012-07-03 20:47:01 +00:00
stmt . o2 . u1 = OFS_PARM0 + 3 * p ;
2014-10-18 11:49:13 +00:00
if ( param - > vtype = = TYPE_VECTOR & & ( param - > flags & IR_FLAG_SPLIT_VECTOR ) ) {
/* fetch 3 separate floats */
stmt . opcode = INSTR_STORE_F ;
stmt . o1 . u1 = ir_value_code_addr ( param - > members [ 0 ] ) ;
code_push_statement ( code , & stmt , instr - > context ) ;
stmt . o2 . u1 + + ;
stmt . o1 . u1 = ir_value_code_addr ( param - > members [ 1 ] ) ;
code_push_statement ( code , & stmt , instr - > context ) ;
stmt . o2 . u1 + + ;
stmt . o1 . u1 = ir_value_code_addr ( param - > members [ 2 ] ) ;
code_push_statement ( code , & stmt , instr - > context ) ;
}
else
code_push_statement ( code , & stmt , instr - > context ) ;
2012-07-03 20:47:01 +00:00
}
2012-11-22 20:12:15 +00:00
/* Now handle extparams */
2012-11-18 19:17:59 +00:00
first = vec_size ( instr - > params ) ;
for ( ; p < first ; + + p )
{
ir_builder * ir = func - > owner ;
ir_value * param = instr - > params [ p ] ;
2012-11-22 20:12:15 +00:00
ir_value * targetparam ;
2012-11-18 19:17:59 +00:00
2012-12-25 22:25:59 +00:00
if ( param - > callparam )
continue ;
2012-12-01 10:43:54 +00:00
if ( p - 8 > = vec_size ( ir - > extparams ) )
2013-06-20 10:52:58 +00:00
ir_gen_extparam ( ir ) ;
2012-11-18 19:17:59 +00:00
2012-11-22 20:12:15 +00:00
targetparam = ir - > extparams [ p - 8 ] ;
2012-11-18 19:17:59 +00:00
stmt . opcode = INSTR_STORE_F ;
stmt . o3 . u1 = 0 ;
if ( param - > vtype = = TYPE_FIELD )
stmt . opcode = field_store_instr [ param - > fieldtype ] ;
2012-12-31 12:19:34 +00:00
else if ( param - > vtype = = TYPE_NIL )
stmt . opcode = INSTR_STORE_V ;
2012-11-18 19:17:59 +00:00
else
stmt . opcode = type_store_instr [ param - > vtype ] ;
stmt . o1 . u1 = ir_value_code_addr ( param ) ;
2012-11-22 20:12:15 +00:00
stmt . o2 . u1 = ir_value_code_addr ( targetparam ) ;
2014-10-18 11:49:13 +00:00
if ( param - > vtype = = TYPE_VECTOR & & ( param - > flags & IR_FLAG_SPLIT_VECTOR ) ) {
/* fetch 3 separate floats */
stmt . opcode = INSTR_STORE_F ;
stmt . o1 . u1 = ir_value_code_addr ( param - > members [ 0 ] ) ;
code_push_statement ( code , & stmt , instr - > context ) ;
stmt . o2 . u1 + + ;
stmt . o1 . u1 = ir_value_code_addr ( param - > members [ 1 ] ) ;
code_push_statement ( code , & stmt , instr - > context ) ;
stmt . o2 . u1 + + ;
stmt . o1 . u1 = ir_value_code_addr ( param - > members [ 2 ] ) ;
code_push_statement ( code , & stmt , instr - > context ) ;
}
else
code_push_statement ( code , & stmt , instr - > context ) ;
2012-11-18 19:17:59 +00:00
}
2012-11-15 17:32:03 +00:00
stmt . opcode = INSTR_CALL0 + vec_size ( instr - > params ) ;
2012-07-03 20:47:01 +00:00
if ( stmt . opcode > INSTR_CALL8 )
stmt . opcode = INSTR_CALL8 ;
2012-08-08 12:49:37 +00:00
stmt . o1 . u1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) ;
2012-07-03 20:47:01 +00:00
stmt . o2 . u1 = 0 ;
stmt . o3 . u1 = 0 ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2012-07-03 20:47:01 +00:00
retvalue = instr - > _ops [ 0 ] ;
2012-12-23 20:11:56 +00:00
if ( retvalue & & retvalue - > store ! = store_return & &
2012-12-23 20:34:04 +00:00
( retvalue - > store = = store_global | | vec_size ( retvalue - > life ) ) )
2012-07-03 20:47:01 +00:00
{
/* not to be kept in OFS_RETURN */
2012-12-21 10:33:44 +00:00
if ( retvalue - > vtype = = TYPE_FIELD & & OPTS_FLAG ( ADJUST_VECTOR_FIELDS ) )
stmt . opcode = field_store_instr [ retvalue - > fieldtype ] ;
2012-11-09 19:11:17 +00:00
else
stmt . opcode = type_store_instr [ retvalue - > vtype ] ;
2012-07-03 20:47:01 +00:00
stmt . o1 . u1 = OFS_RETURN ;
2012-08-08 12:49:37 +00:00
stmt . o2 . u1 = ir_value_code_addr ( retvalue ) ;
2012-07-03 20:47:01 +00:00
stmt . o3 . u1 = 0 ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2012-07-03 20:47:01 +00:00
}
2012-07-04 13:16:02 +00:00
continue ;
2012-05-09 13:02:58 +00:00
}
if ( instr - > opcode = = INSTR_STATE ) {
2014-04-08 12:34:55 +00:00
stmt . opcode = instr - > opcode ;
if ( instr - > _ops [ 0 ] )
stmt . o1 . u1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
if ( instr - > _ops [ 1 ] )
stmt . o2 . u1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) ;
stmt . o3 . u1 = 0 ;
code_push_statement ( code , & stmt , instr - > context ) ;
continue ;
2012-05-09 13:02:58 +00:00
}
stmt . opcode = instr - > opcode ;
stmt . o1 . u1 = 0 ;
stmt . o2 . u1 = 0 ;
stmt . o3 . u1 = 0 ;
/* This is the general order of operands */
if ( instr - > _ops [ 0 ] )
2012-08-08 12:49:37 +00:00
stmt . o3 . u1 = ir_value_code_addr ( instr - > _ops [ 0 ] ) ;
2012-05-09 13:02:58 +00:00
if ( instr - > _ops [ 1 ] )
2012-08-08 12:49:37 +00:00
stmt . o1 . u1 = ir_value_code_addr ( instr - > _ops [ 1 ] ) ;
2012-05-09 13:02:58 +00:00
if ( instr - > _ops [ 2 ] )
2012-08-08 12:49:37 +00:00
stmt . o2 . u1 = ir_value_code_addr ( instr - > _ops [ 2 ] ) ;
2012-05-09 13:02:58 +00:00
2012-06-25 09:52:18 +00:00
if ( stmt . opcode = = INSTR_RETURN | | stmt . opcode = = INSTR_DONE )
2012-05-09 13:02:58 +00:00
{
stmt . o1 . u1 = stmt . o3 . u1 ;
stmt . o3 . u1 = 0 ;
}
2012-08-11 16:06:10 +00:00
else if ( ( stmt . opcode > = INSTR_STORE_F & &
stmt . opcode < = INSTR_STORE_FNC ) | |
( stmt . opcode > = INSTR_STOREP_F & &
stmt . opcode < = INSTR_STOREP_FNC ) )
2012-06-25 09:52:18 +00:00
{
/* 2-operand instructions with A -> B */
stmt . o2 . u1 = stmt . o3 . u1 ;
stmt . o3 . u1 = 0 ;
2012-12-05 14:17:11 +00:00
/* tiny optimization, don't output
* STORE a , a
*/
if ( stmt . o2 . u1 = = stmt . o1 . u1 & &
2012-12-06 12:08:22 +00:00
OPTS_OPTIMIZATION ( OPTIM_PEEPHOLE ) )
2012-12-05 14:17:11 +00:00
{
2012-12-18 04:57:17 +00:00
+ + opts_optimizationcount [ OPTIM_PEEPHOLE ] ;
2012-12-05 14:17:11 +00:00
continue ;
}
2012-06-25 09:52:18 +00:00
}
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , instr - > context ) ;
2012-05-09 13:02:58 +00:00
}
return true ;
}
2013-04-25 09:35:30 +00:00
static bool gen_function_code ( code_t * code , ir_function * self )
2012-05-05 08:56:00 +00:00
{
2012-05-09 13:02:58 +00:00
ir_block * block ;
2013-07-30 16:00:51 +00:00
prog_section_statement_t stmt , * retst ;
2012-05-09 13:02:58 +00:00
/* Starting from entry point, we generate blocks "as they come"
* for now . Dead blocks will not be translated obviously .
*/
2012-11-15 17:32:03 +00:00
if ( ! vec_size ( self - > blocks ) ) {
2012-08-19 18:45:26 +00:00
irerror ( self - > context , " Function '%s' declared without body. " , self - > name ) ;
2012-05-09 13:02:58 +00:00
return false ;
}
block = self - > blocks [ 0 ] ;
if ( block - > generated )
return true ;
2013-04-25 09:35:30 +00:00
if ( ! gen_blocks_recursive ( code , self , block ) ) {
2012-08-19 18:45:26 +00:00
irerror ( self - > context , " failed to generate blocks for '%s' " , self - > name ) ;
2012-05-09 13:02:58 +00:00
return false ;
2012-05-09 15:39:17 +00:00
}
2012-07-04 11:29:26 +00:00
2012-12-18 10:46:26 +00:00
/* code_write and qcvm -disasm need to know that the function ends here */
2013-04-25 09:35:30 +00:00
retst = & vec_last ( code - > statements ) ;
2012-12-26 09:24:33 +00:00
if ( OPTS_OPTIMIZATION ( OPTIM_VOID_RETURN ) & &
self - > outtype = = TYPE_VOID & &
retst - > opcode = = INSTR_RETURN & &
! retst - > o1 . u1 & & ! retst - > o2 . u1 & & ! retst - > o3 . u1 )
{
retst - > opcode = INSTR_DONE ;
+ + opts_optimizationcount [ OPTIM_VOID_RETURN ] ;
} else {
2013-08-26 18:14:33 +00:00
lex_ctx_t last ;
2012-12-26 09:24:33 +00:00
stmt . opcode = INSTR_DONE ;
2013-08-26 18:14:33 +00:00
stmt . o1 . u1 = 0 ;
stmt . o2 . u1 = 0 ;
stmt . o3 . u1 = 0 ;
last . line = vec_last ( code - > linenums ) ;
last . column = vec_last ( code - > columnnums ) ;
code_push_statement ( code , & stmt , last ) ;
2012-12-26 09:24:33 +00:00
}
2012-05-09 13:02:58 +00:00
return true ;
2012-05-05 08:56:00 +00:00
}
2013-07-30 16:00:51 +00:00
static qcint_t ir_builder_filestring ( ir_builder * ir , const char * filename )
2012-08-24 17:44:29 +00:00
{
/* NOTE: filename pointers are copied, we never strdup them,
* thus we can use pointer - comparison to find the string .
*/
size_t i ;
2013-07-30 16:00:51 +00:00
qcint_t str ;
2012-08-24 17:44:29 +00:00
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( ir - > filenames ) ; + + i ) {
2012-08-24 17:44:29 +00:00
if ( ir - > filenames [ i ] = = filename )
return ir - > filestrings [ i ] ;
}
2013-06-20 10:52:58 +00:00
str = code_genstring ( ir - > code , filename ) ;
2012-11-15 17:32:03 +00:00
vec_push ( ir - > filenames , filename ) ;
vec_push ( ir - > filestrings , str ) ;
2012-08-24 17:44:29 +00:00
return str ;
}
2013-06-20 10:52:58 +00:00
static bool gen_global_function ( ir_builder * ir , ir_value * global )
2012-05-05 08:56:00 +00:00
{
2013-07-30 16:00:51 +00:00
prog_section_function_t fun ;
ir_function * irfun ;
2012-05-05 08:56:00 +00:00
size_t i ;
2012-11-30 12:47:28 +00:00
if ( ! global - > hasvalue | | ( ! global - > constval . vfunc ) )
2012-05-05 08:56:00 +00:00
{
2012-08-19 18:45:26 +00:00
irerror ( global - > context , " Invalid state of function-global: not constant: %s " , global - > name ) ;
2012-05-05 08:56:00 +00:00
return false ;
}
irfun = global - > constval . vfunc ;
fun . name = global - > code . name ;
2013-06-20 10:52:58 +00:00
fun . file = ir_builder_filestring ( ir , global - > context . file ) ;
2012-05-05 08:56:00 +00:00
fun . profile = 0 ; /* always 0 */
2012-11-15 17:32:03 +00:00
fun . nargs = vec_size ( irfun - > params ) ;
2012-11-18 19:32:06 +00:00
if ( fun . nargs > 8 )
fun . nargs = 8 ;
2012-05-05 08:56:00 +00:00
for ( i = 0 ; i < 8 ; + + i ) {
2012-11-30 19:20:13 +00:00
if ( ( int32_t ) i > = fun . nargs )
2012-05-05 08:56:00 +00:00
fun . argsize [ i ] = 0 ;
else
2012-12-20 22:48:41 +00:00
fun . argsize [ i ] = type_sizeof_ [ irfun - > params [ i ] ] ;
2012-05-05 08:56:00 +00:00
}
2012-12-23 16:32:39 +00:00
fun . firstlocal = 0 ;
fun . locals = irfun - > allocated_locals ;
2012-08-22 14:29:27 +00:00
2012-07-03 21:38:38 +00:00
if ( irfun - > builtin )
2012-11-30 23:36:24 +00:00
fun . entry = irfun - > builtin + 1 ;
2012-07-03 21:38:38 +00:00
else {
2013-06-20 10:52:58 +00:00
irfun - > code_function_def = vec_size ( ir - > code - > functions ) ;
fun . entry = vec_size ( ir - > code - > statements ) ;
2012-05-09 15:39:17 +00:00
}
2012-05-05 08:56:00 +00:00
2013-06-20 10:52:58 +00:00
vec_push ( ir - > code - > functions , fun ) ;
2012-11-15 17:32:03 +00:00
return true ;
2012-05-05 08:56:00 +00:00
}
2012-05-04 22:03:18 +00:00
2012-12-25 22:25:59 +00:00
static ir_value * ir_gen_extparam_proto ( ir_builder * ir )
{
ir_value * global ;
char name [ 128 ] ;
2013-10-11 10:12:56 +00:00
util_snprintf ( name , sizeof ( name ) , " EXTPARM#%i " , ( int ) ( vec_size ( ir - > extparam_protos ) ) ) ;
2012-12-25 22:25:59 +00:00
global = ir_value_var ( name , store_global , TYPE_VECTOR ) ;
vec_push ( ir - > extparam_protos , global ) ;
return global ;
}
2013-06-20 10:52:58 +00:00
static void ir_gen_extparam ( ir_builder * ir )
2012-11-18 19:06:28 +00:00
{
2013-07-30 16:00:51 +00:00
prog_section_def_t def ;
ir_value * global ;
2012-11-18 19:06:28 +00:00
2012-12-25 22:25:59 +00:00
if ( vec_size ( ir - > extparam_protos ) < vec_size ( ir - > extparams ) + 1 )
global = ir_gen_extparam_proto ( ir ) ;
else
global = ir - > extparam_protos [ vec_size ( ir - > extparams ) ] ;
2012-11-18 19:06:28 +00:00
2013-06-20 10:52:58 +00:00
def . name = code_genstring ( ir - > code , global - > name ) ;
2013-04-25 09:35:30 +00:00
def . type = TYPE_VECTOR ;
2013-06-20 10:52:58 +00:00
def . offset = vec_size ( ir - > code - > globals ) ;
2013-04-25 09:35:30 +00:00
2013-06-20 10:52:58 +00:00
vec_push ( ir - > code - > defs , def ) ;
2012-11-18 19:06:28 +00:00
ir_value_code_setaddr ( global , def . offset ) ;
2013-04-25 09:35:30 +00:00
2013-06-20 10:52:58 +00:00
vec_push ( ir - > code - > globals , 0 ) ;
vec_push ( ir - > code - > globals , 0 ) ;
vec_push ( ir - > code - > globals , 0 ) ;
2012-11-18 19:06:28 +00:00
vec_push ( ir - > extparams , global ) ;
}
2013-04-25 09:35:30 +00:00
static bool gen_function_extparam_copy ( code_t * code , ir_function * self )
2012-11-18 19:06:28 +00:00
{
2012-11-18 19:36:02 +00:00
size_t i , ext , numparams ;
2012-11-18 19:06:28 +00:00
ir_builder * ir = self - > owner ;
ir_value * ep ;
2013-07-30 16:00:51 +00:00
prog_section_statement_t stmt ;
2012-11-18 19:06:28 +00:00
2012-11-18 19:36:02 +00:00
numparams = vec_size ( self - > params ) ;
if ( ! numparams )
2012-11-18 19:06:28 +00:00
return true ;
stmt . opcode = INSTR_STORE_F ;
stmt . o3 . s1 = 0 ;
2012-11-18 19:36:02 +00:00
for ( i = 8 ; i < numparams ; + + i ) {
2012-11-18 19:06:28 +00:00
ext = i - 8 ;
if ( ext > = vec_size ( ir - > extparams ) )
2013-06-20 10:52:58 +00:00
ir_gen_extparam ( ir ) ;
2012-11-18 19:06:28 +00:00
ep = ir - > extparams [ ext ] ;
stmt . opcode = type_store_instr [ self - > locals [ i ] - > vtype ] ;
if ( self - > locals [ i ] - > vtype = = TYPE_FIELD & &
self - > locals [ i ] - > fieldtype = = TYPE_VECTOR )
{
stmt . opcode = INSTR_STORE_V ;
}
stmt . o1 . u1 = ir_value_code_addr ( ep ) ;
stmt . o2 . u1 = ir_value_code_addr ( self - > locals [ i ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , self - > context ) ;
2012-11-18 19:06:28 +00:00
}
return true ;
}
2013-04-25 09:35:30 +00:00
static bool gen_function_varargs_copy ( code_t * code , ir_function * self )
2013-01-12 13:11:34 +00:00
{
size_t i , ext , numparams , maxparams ;
ir_builder * ir = self - > owner ;
ir_value * ep ;
2013-07-30 16:00:51 +00:00
prog_section_statement_t stmt ;
2013-01-12 13:11:34 +00:00
numparams = vec_size ( self - > params ) ;
if ( ! numparams )
return true ;
stmt . opcode = INSTR_STORE_V ;
stmt . o3 . s1 = 0 ;
maxparams = numparams + self - > max_varargs ;
for ( i = numparams ; i < maxparams ; + + i ) {
2013-02-26 15:39:28 +00:00
if ( i < 8 ) {
2013-01-12 13:11:34 +00:00
stmt . o1 . u1 = OFS_PARM0 + 3 * i ;
stmt . o2 . u1 = ir_value_code_addr ( self - > locals [ i ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , self - > context ) ;
2013-01-12 13:11:34 +00:00
continue ;
}
2013-02-26 15:39:28 +00:00
ext = i - 8 ;
while ( ext > = vec_size ( ir - > extparams ) )
2013-06-20 10:52:58 +00:00
ir_gen_extparam ( ir ) ;
2013-01-12 13:11:34 +00:00
ep = ir - > extparams [ ext ] ;
stmt . o1 . u1 = ir_value_code_addr ( ep ) ;
stmt . o2 . u1 = ir_value_code_addr ( self - > locals [ i ] ) ;
2013-08-26 18:14:33 +00:00
code_push_statement ( code , & stmt , self - > context ) ;
2013-01-12 13:11:34 +00:00
}
return true ;
}
2013-06-20 10:52:58 +00:00
static bool gen_function_locals ( ir_builder * ir , ir_value * global )
2012-12-23 16:32:39 +00:00
{
2013-07-30 16:00:51 +00:00
prog_section_function_t * def ;
ir_function * irfun ;
size_t i ;
uint32_t firstlocal , firstglobal ;
2012-12-23 16:32:39 +00:00
irfun = global - > constval . vfunc ;
2013-06-20 10:52:58 +00:00
def = ir - > code - > functions + irfun - > code_function_def ;
2012-12-23 16:32:39 +00:00
2013-01-30 05:35:07 +00:00
if ( OPTS_OPTION_BOOL ( OPTION_G ) | |
2013-01-30 05:24:30 +00:00
! OPTS_OPTIMIZATION ( OPTIM_OVERLAP_LOCALS ) | |
( irfun - > flags & IR_FLAG_MASK_NO_OVERLAP ) )
{
2013-06-20 10:52:58 +00:00
firstlocal = def - > firstlocal = vec_size ( ir - > code - > globals ) ;
2013-01-30 05:24:30 +00:00
} else {
2012-12-23 16:32:39 +00:00
firstlocal = def - > firstlocal = ir - > first_common_local ;
2012-12-23 16:40:56 +00:00
+ + opts_optimizationcount [ OPTIM_OVERLAP_LOCALS ] ;
}
2012-12-23 16:32:39 +00:00
2012-12-26 22:18:45 +00:00
firstglobal = ( OPTS_OPTIMIZATION ( OPTIM_GLOBAL_TEMPS ) ? ir - > first_common_globaltemp : firstlocal ) ;
2013-06-20 10:52:58 +00:00
for ( i = vec_size ( ir - > code - > globals ) ; i < firstlocal + irfun - > allocated_locals ; + + i )
vec_push ( ir - > code - > globals , 0 ) ;
2012-12-23 16:32:39 +00:00
for ( i = 0 ; i < vec_size ( irfun - > locals ) ; + + i ) {
2012-12-26 22:18:45 +00:00
ir_value * v = irfun - > locals [ i ] ;
if ( v - > locked | | ! OPTS_OPTIMIZATION ( OPTIM_GLOBAL_TEMPS ) ) {
ir_value_code_setaddr ( v , firstlocal + v - > code . local ) ;
2013-06-20 10:52:58 +00:00
if ( ! ir_builder_gen_global ( ir , irfun - > locals [ i ] , true ) ) {
2012-12-26 22:18:45 +00:00
irerror ( irfun - > locals [ i ] - > context , " failed to generate local %s " , irfun - > locals [ i ] - > name ) ;
return false ;
}
2012-12-23 16:32:39 +00:00
}
2012-12-26 22:18:45 +00:00
else
ir_value_code_setaddr ( v , firstglobal + v - > code . local ) ;
2012-12-23 16:32:39 +00:00
}
for ( i = 0 ; i < vec_size ( irfun - > values ) ; + + i )
{
ir_value * v = irfun - > values [ i ] ;
2012-12-25 22:25:59 +00:00
if ( v - > callparam )
continue ;
2012-12-26 22:18:45 +00:00
if ( v - > locked )
ir_value_code_setaddr ( v , firstlocal + v - > code . local ) ;
else
ir_value_code_setaddr ( v , firstglobal + v - > code . local ) ;
2012-12-23 16:32:39 +00:00
}
return true ;
}
2013-06-20 10:52:58 +00:00
static bool gen_global_function_code ( ir_builder * ir , ir_value * global )
2012-08-19 16:00:53 +00:00
{
2013-07-30 16:00:51 +00:00
prog_section_function_t * fundef ;
ir_function * irfun ;
2012-08-19 16:00:53 +00:00
2012-11-22 20:41:22 +00:00
( void ) ir ;
2012-08-19 16:00:53 +00:00
irfun = global - > constval . vfunc ;
2012-08-22 10:33:24 +00:00
if ( ! irfun ) {
2012-11-30 13:05:25 +00:00
if ( global - > cvq = = CV_NONE ) {
2013-09-18 14:18:29 +00:00
if ( irwarning ( global - > context , WARN_IMPLICIT_FUNCTION_POINTER ,
" function `%s` has no body and in QC implicitly becomes a function-pointer " ,
global - > name ) )
{
/* Not bailing out just now. If this happens a lot you don't want to have
* to rerun gmqcc for each such function .
*/
/* return false; */
}
2012-11-30 13:05:25 +00:00
}
2012-08-22 10:33:24 +00:00
/* this was a function pointer, don't generate code for those */
return true ;
}
2012-08-19 16:00:53 +00:00
if ( irfun - > builtin )
return true ;
2013-08-29 04:05:37 +00:00
/*
* If there is no definition and the thing is eraseable , we can ignore
* outputting the function to begin with .
*/
2014-10-18 12:27:16 +00:00
if ( global - > flags & IR_FLAG_ERASABLE & & irfun - > code_function_def < 0 ) {
2013-08-29 04:05:37 +00:00
return true ;
}
2012-08-19 16:00:53 +00:00
if ( irfun - > code_function_def < 0 ) {
irerror ( irfun - > context , " `%s`: IR global wasn't generated, failed to access function-def " , irfun - > name ) ;
return false ;
}
2013-06-20 10:52:58 +00:00
fundef = & ir - > code - > functions [ irfun - > code_function_def ] ;
2012-08-19 16:00:53 +00:00
2013-06-20 10:52:58 +00:00
fundef - > entry = vec_size ( ir - > code - > statements ) ;
if ( ! gen_function_locals ( ir , global ) ) {
2012-12-23 16:32:39 +00:00
irerror ( irfun - > context , " Failed to generate locals for function %s " , irfun - > name ) ;
return false ;
}
2013-06-20 10:52:58 +00:00
if ( ! gen_function_extparam_copy ( ir - > code , irfun ) ) {
2012-11-18 19:06:28 +00:00
irerror ( irfun - > context , " Failed to generate extparam-copy code for function %s " , irfun - > name ) ;
return false ;
}
2013-06-20 10:52:58 +00:00
if ( irfun - > max_varargs & & ! gen_function_varargs_copy ( ir - > code , irfun ) ) {
2013-01-12 13:11:34 +00:00
irerror ( irfun - > context , " Failed to generate vararg-copy code for function %s " , irfun - > name ) ;
return false ;
}
2013-06-20 10:52:58 +00:00
if ( ! gen_function_code ( ir - > code , irfun ) ) {
2012-08-19 16:00:53 +00:00
irerror ( irfun - > context , " Failed to generate code for function %s " , irfun - > name ) ;
return false ;
}
return true ;
}
2013-07-30 16:00:51 +00:00
static void gen_vector_defs ( code_t * code , prog_section_def_t def , const char * name )
2012-12-18 11:41:38 +00:00
{
char * component ;
size_t len , i ;
2012-12-23 09:14:25 +00:00
if ( ! name | | name [ 0 ] = = ' # ' | | OPTS_FLAG ( SINGLE_VECTOR_DEFS ) )
2012-12-18 11:41:38 +00:00
return ;
2012-12-18 11:58:15 +00:00
def . type = TYPE_FLOAT ;
2012-12-18 11:41:38 +00:00
len = strlen ( name ) ;
component = ( char * ) mem_a ( len + 3 ) ;
memcpy ( component , name , len ) ;
len + = 2 ;
component [ len - 0 ] = 0 ;
component [ len - 2 ] = ' _ ' ;
component [ len - 1 ] = ' x ' ;
for ( i = 0 ; i < 3 ; + + i ) {
2013-04-25 09:35:30 +00:00
def . name = code_genstring ( code , component ) ;
vec_push ( code - > defs , def ) ;
2012-12-18 11:41:38 +00:00
def . offset + + ;
component [ len - 1 ] + + ;
}
2013-04-13 18:01:26 +00:00
mem_d ( component ) ;
2012-12-18 11:41:38 +00:00
}
2013-07-30 16:00:51 +00:00
static void gen_vector_fields ( code_t * code , prog_section_field_t fld , const char * name )
2012-12-18 11:41:38 +00:00
{
char * component ;
size_t len , i ;
2012-12-18 11:47:48 +00:00
if ( ! name | | OPTS_FLAG ( SINGLE_VECTOR_DEFS ) )
2012-12-18 11:41:38 +00:00
return ;
2012-12-18 12:13:54 +00:00
fld . type = TYPE_FLOAT ;
2012-12-18 11:58:15 +00:00
2012-12-18 11:41:38 +00:00
len = strlen ( name ) ;
component = ( char * ) mem_a ( len + 3 ) ;
memcpy ( component , name , len ) ;
len + = 2 ;
component [ len - 0 ] = 0 ;
component [ len - 2 ] = ' _ ' ;
component [ len - 1 ] = ' x ' ;
for ( i = 0 ; i < 3 ; + + i ) {
2013-04-25 09:35:30 +00:00
fld . name = code_genstring ( code , component ) ;
vec_push ( code - > fields , fld ) ;
2012-12-18 11:41:38 +00:00
fld . offset + + ;
component [ len - 1 ] + + ;
}
2013-04-13 18:01:26 +00:00
mem_d ( component ) ;
2012-12-18 11:41:38 +00:00
}
2013-06-20 10:52:58 +00:00
static bool ir_builder_gen_global ( ir_builder * self , ir_value * global , bool islocal )
2012-05-04 22:28:51 +00:00
{
2013-07-30 16:00:51 +00:00
size_t i ;
int32_t * iptr ;
prog_section_def_t def ;
bool pushdef = opts . optimizeoff ;
2013-02-25 08:52:17 +00:00
2014-10-18 11:49:13 +00:00
/* we don't generate split-vectors */
if ( global - > vtype = = TYPE_VECTOR & & ( global - > flags & IR_FLAG_SPLIT_VECTOR ) )
return true ;
2012-12-26 19:06:30 +00:00
def . type = global - > vtype ;
2013-06-20 10:52:58 +00:00
def . offset = vec_size ( self - > code - > globals ) ;
2012-12-26 19:06:30 +00:00
def . name = 0 ;
2013-01-30 05:35:07 +00:00
if ( OPTS_OPTION_BOOL ( OPTION_G ) | | ! islocal )
2012-12-23 11:22:27 +00:00
{
pushdef = true ;
2013-08-29 04:05:37 +00:00
/*
* if we ' re eraseable and the function isn ' t referenced ignore outputting
* the function .
*/
2014-10-18 12:27:16 +00:00
if ( global - > flags & IR_FLAG_ERASABLE & & vec_size ( global - > reads ) = = 0 ) {
2013-08-29 04:05:37 +00:00
return true ;
}
2012-12-23 21:58:46 +00:00
if ( OPTS_OPTIMIZATION ( OPTIM_STRIP_CONSTANT_NAMES ) & &
2013-01-11 18:15:59 +00:00
! ( global - > flags & IR_FLAG_INCLUDE_DEF ) & &
2012-12-23 21:58:46 +00:00
( global - > name [ 0 ] = = ' # ' | | global - > cvq = = CV_CONST ) )
{
pushdef = false ;
}
2013-08-14 07:19:49 +00:00
if ( pushdef ) {
2012-12-23 11:22:27 +00:00
if ( global - > name [ 0 ] = = ' # ' ) {
if ( ! self - > str_immediate )
2013-06-20 10:52:58 +00:00
self - > str_immediate = code_genstring ( self - > code , " IMMEDIATE " ) ;
2012-12-23 11:22:27 +00:00
def . name = global - > code . name = self - > str_immediate ;
}
else
2013-06-20 10:52:58 +00:00
def . name = global - > code . name = code_genstring ( self - > code , global - > name ) ;
2012-08-24 17:52:06 +00:00
}
else
2012-12-23 11:22:27 +00:00
def . name = 0 ;
2012-12-26 19:06:30 +00:00
if ( islocal ) {
2012-12-23 16:32:39 +00:00
def . offset = ir_value_code_addr ( global ) ;
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > defs , def ) ;
2012-12-23 16:32:39 +00:00
if ( global - > vtype = = TYPE_VECTOR )
2013-06-20 10:52:58 +00:00
gen_vector_defs ( self - > code , def , global - > name ) ;
2012-12-23 16:32:39 +00:00
else if ( global - > vtype = = TYPE_FIELD & & global - > fieldtype = = TYPE_VECTOR )
2013-06-20 10:52:58 +00:00
gen_vector_defs ( self - > code , def , global - > name ) ;
2012-12-23 16:32:39 +00:00
return true ;
}
2012-08-24 17:52:06 +00:00
}
2012-12-26 19:06:30 +00:00
if ( islocal )
2012-12-23 16:32:39 +00:00
return true ;
2012-05-05 08:56:00 +00:00
2012-05-04 22:28:51 +00:00
switch ( global - > vtype )
{
2012-08-21 13:49:53 +00:00
case TYPE_VOID :
if ( ! strcmp ( global - > name , " end_sys_globals " ) ) {
/* TODO: remember this point... all the defs before this one
* should be checksummed and added to progdefs . h when we generate it .
*/
}
2012-08-21 13:50:53 +00:00
else if ( ! strcmp ( global - > name , " end_sys_fields " ) ) {
2012-08-21 13:49:53 +00:00
/* TODO: same as above but for entity-fields rather than globsl
*/
}
2013-09-18 14:18:29 +00:00
else if ( irwarning ( global - > context , WARN_VOID_VARIABLES , " unrecognized variable of type void `%s` " ,
global - > name ) )
{
/* Not bailing out */
/* return false; */
}
2012-08-21 13:49:53 +00:00
/* I'd argue setting it to 0 is sufficient, but maybe some depend on knowing how far
* the system fields actually go ? Though the engine knows this anyway . . .
* Maybe this could be an - foption
2012-08-23 16:28:05 +00:00
* fteqcc creates data for end_sys_ * - of size 1 , so let ' s do the same
2012-08-21 13:49:53 +00:00
*/
2013-06-20 10:52:58 +00:00
ir_value_code_setaddr ( global , vec_size ( self - > code - > globals ) ) ;
vec_push ( self - > code - > globals , 0 ) ;
2012-08-21 13:49:53 +00:00
/* Add the def */
2013-06-20 10:52:58 +00:00
if ( pushdef ) vec_push ( self - > code - > defs , def ) ;
2012-08-21 13:49:53 +00:00
return true ;
2012-05-04 22:28:51 +00:00
case TYPE_POINTER :
2013-06-20 10:52:58 +00:00
if ( pushdef ) vec_push ( self - > code - > defs , def ) ;
return gen_global_pointer ( self - > code , global ) ;
2012-05-04 22:28:51 +00:00
case TYPE_FIELD :
2012-12-23 11:22:27 +00:00
if ( pushdef ) {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > defs , def ) ;
2012-12-25 22:51:29 +00:00
if ( global - > fieldtype = = TYPE_VECTOR )
2013-06-20 10:52:58 +00:00
gen_vector_defs ( self - > code , def , global - > name ) ;
2012-12-23 11:22:27 +00:00
}
2013-06-20 10:52:58 +00:00
return gen_global_field ( self - > code , global ) ;
2012-05-04 22:28:51 +00:00
case TYPE_ENTITY :
2012-06-25 09:52:18 +00:00
/* fall through */
2012-05-04 22:28:51 +00:00
case TYPE_FLOAT :
2012-05-05 08:56:00 +00:00
{
2013-06-20 10:52:58 +00:00
ir_value_code_setaddr ( global , vec_size ( self - > code - > globals ) ) ;
2012-11-30 12:47:28 +00:00
if ( global - > hasvalue ) {
2012-11-04 10:41:44 +00:00
iptr = ( int32_t * ) & global - > constval . ivec [ 0 ] ;
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , * iptr ) ;
2012-08-23 16:28:05 +00:00
} else {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , 0 ) ;
2012-08-23 16:28:05 +00:00
}
2012-12-18 11:02:33 +00:00
if ( ! islocal & & global - > cvq ! = CV_CONST )
def . type | = DEF_SAVEGLOBAL ;
2013-06-20 10:52:58 +00:00
if ( pushdef ) vec_push ( self - > code - > defs , def ) ;
2012-05-05 08:56:00 +00:00
return global - > code . globaladdr > = 0 ;
}
2012-05-04 22:28:51 +00:00
case TYPE_STRING :
2012-05-05 08:56:00 +00:00
{
2013-06-20 10:52:58 +00:00
ir_value_code_setaddr ( global , vec_size ( self - > code - > globals ) ) ;
2012-11-30 12:47:28 +00:00
if ( global - > hasvalue ) {
2013-06-20 10:52:58 +00:00
uint32_t load = code_genstring ( self - > code , global - > constval . vstring ) ;
vec_push ( self - > code - > globals , load ) ;
2012-11-15 17:32:03 +00:00
} else {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , 0 ) ;
2012-08-23 16:28:05 +00:00
}
2012-12-18 11:02:33 +00:00
if ( ! islocal & & global - > cvq ! = CV_CONST )
def . type | = DEF_SAVEGLOBAL ;
2013-06-20 10:52:58 +00:00
if ( pushdef ) vec_push ( self - > code - > defs , def ) ;
2012-05-05 08:56:00 +00:00
return global - > code . globaladdr > = 0 ;
}
2012-05-04 22:28:51 +00:00
case TYPE_VECTOR :
2012-05-05 08:56:00 +00:00
{
2012-07-10 17:26:07 +00:00
size_t d ;
2013-06-20 10:52:58 +00:00
ir_value_code_setaddr ( global , vec_size ( self - > code - > globals ) ) ;
2012-11-30 12:47:28 +00:00
if ( global - > hasvalue ) {
2012-11-04 10:41:44 +00:00
iptr = ( int32_t * ) & global - > constval . ivec [ 0 ] ;
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , iptr [ 0 ] ) ;
2012-07-10 17:26:07 +00:00
if ( global - > code . globaladdr < 0 )
2012-05-04 22:28:51 +00:00
return false ;
2012-12-20 22:48:41 +00:00
for ( d = 1 ; d < type_sizeof_ [ global - > vtype ] ; + + d ) {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , iptr [ d ] ) ;
2012-07-10 17:26:07 +00:00
}
2012-05-04 22:28:51 +00:00
} else {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , 0 ) ;
2012-07-10 17:26:07 +00:00
if ( global - > code . globaladdr < 0 )
2012-05-05 08:56:00 +00:00
return false ;
2012-12-20 22:48:41 +00:00
for ( d = 1 ; d < type_sizeof_ [ global - > vtype ] ; + + d ) {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , 0 ) ;
2012-07-10 17:26:07 +00:00
}
2012-05-04 22:28:51 +00:00
}
2012-12-18 11:02:33 +00:00
if ( ! islocal & & global - > cvq ! = CV_CONST )
def . type | = DEF_SAVEGLOBAL ;
2012-08-23 16:28:05 +00:00
2012-12-23 11:22:27 +00:00
if ( pushdef ) {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > defs , def ) ;
2012-12-23 11:22:27 +00:00
def . type & = ~ DEF_SAVEGLOBAL ;
2013-06-20 10:52:58 +00:00
gen_vector_defs ( self - > code , def , global - > name ) ;
2012-12-23 11:22:27 +00:00
}
2012-05-05 08:56:00 +00:00
return global - > code . globaladdr > = 0 ;
}
case TYPE_FUNCTION :
2013-06-20 10:52:58 +00:00
ir_value_code_setaddr ( global , vec_size ( self - > code - > globals ) ) ;
2012-11-30 12:47:28 +00:00
if ( ! global - > hasvalue ) {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , 0 ) ;
2012-08-23 16:28:05 +00:00
if ( global - > code . globaladdr < 0 )
return false ;
2012-08-21 14:01:28 +00:00
} else {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , vec_size ( self - > code - > functions ) ) ;
if ( ! gen_global_function ( self , global ) )
2012-08-23 16:28:05 +00:00
return false ;
2012-08-21 14:01:28 +00:00
}
2012-12-18 11:02:33 +00:00
if ( ! islocal & & global - > cvq ! = CV_CONST )
def . type | = DEF_SAVEGLOBAL ;
2013-06-20 10:52:58 +00:00
if ( pushdef ) vec_push ( self - > code - > defs , def ) ;
2012-08-23 16:28:05 +00:00
return true ;
2012-05-09 15:30:08 +00:00
case TYPE_VARIANT :
/* assume biggest type */
2013-06-20 10:52:58 +00:00
ir_value_code_setaddr ( global , vec_size ( self - > code - > globals ) ) ;
vec_push ( self - > code - > globals , 0 ) ;
2012-12-20 22:48:41 +00:00
for ( i = 1 ; i < type_sizeof_ [ TYPE_VARIANT ] ; + + i )
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , 0 ) ;
2012-05-09 15:30:08 +00:00
return true ;
2012-05-05 08:56:00 +00:00
default :
/* refuse to create 'void' type or any other fancy business. */
2012-08-19 18:45:26 +00:00
irerror ( global - > context , " Invalid type for global variable `%s`: %s " ,
2012-08-19 18:37:10 +00:00
global - > name , type_name [ global - > vtype ] ) ;
2012-05-05 08:56:00 +00:00
return false ;
2012-05-04 22:28:51 +00:00
}
}
2013-04-25 09:35:30 +00:00
static GMQCC_INLINE void ir_builder_prepare_field ( code_t * code , ir_value * field )
2012-11-30 20:22:48 +00:00
{
2013-04-25 09:35:30 +00:00
field - > code . fieldaddr = code_alloc_field ( code , type_sizeof_ [ field - > fieldtype ] ) ;
2012-11-30 20:22:48 +00:00
}
2013-06-20 10:52:58 +00:00
static bool ir_builder_gen_field ( ir_builder * self , ir_value * field )
2012-07-28 19:55:01 +00:00
{
2013-07-30 16:00:51 +00:00
prog_section_def_t def ;
prog_section_field_t fld ;
2012-07-28 19:55:01 +00:00
2012-11-22 20:41:22 +00:00
( void ) self ;
2012-11-22 20:25:02 +00:00
def . type = ( uint16_t ) field - > vtype ;
2013-06-20 10:52:58 +00:00
def . offset = ( uint16_t ) vec_size ( self - > code - > globals ) ;
2012-08-11 14:08:38 +00:00
/* create a global named the same as the field */
2013-01-30 05:35:07 +00:00
if ( OPTS_OPTION_U32 ( OPTION_STANDARD ) = = COMPILER_GMQCC ) {
2012-08-11 14:08:38 +00:00
/* in our standard, the global gets a dot prefix */
size_t len = strlen ( field - > name ) ;
char name [ 1024 ] ;
/* we really don't want to have to allocate this, and 1024
* bytes is more than enough for a variable / field name
*/
if ( len + 2 > = sizeof ( name ) ) {
2012-08-19 18:45:26 +00:00
irerror ( field - > context , " invalid field name size: %u " , ( unsigned int ) len ) ;
2012-08-11 14:08:38 +00:00
return false ;
}
name [ 0 ] = ' . ' ;
2012-08-15 15:02:48 +00:00
memcpy ( name + 1 , field - > name , len ) ; /* no strncpy - we used strlen above */
2012-08-11 14:08:38 +00:00
name [ len + 1 ] = 0 ;
2013-06-20 10:52:58 +00:00
def . name = code_genstring ( self - > code , name ) ;
2012-08-11 14:08:38 +00:00
fld . name = def . name + 1 ; /* we reuse that string table entry */
} else {
/* in plain QC, there cannot be a global with the same name,
* and so we also name the global the same .
* FIXME : fteqcc should create a global as well
* check if it actually uses the same name . Probably does
*/
2013-06-20 10:52:58 +00:00
def . name = code_genstring ( self - > code , field - > name ) ;
2012-08-11 14:08:38 +00:00
fld . name = def . name ;
}
field - > code . name = def . name ;
2012-07-28 19:55:01 +00:00
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > defs , def ) ;
2012-07-28 19:55:01 +00:00
fld . type = field - > fieldtype ;
if ( fld . type = = TYPE_VOID ) {
2012-08-19 18:45:26 +00:00
irerror ( field - > context , " field is missing a type: %s - don't know its size " , field - > name ) ;
2012-07-28 19:55:01 +00:00
return false ;
}
2012-11-30 20:22:48 +00:00
fld . offset = field - > code . fieldaddr ;
2012-08-11 14:08:38 +00:00
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > fields , fld ) ;
2012-07-28 19:55:01 +00:00
2013-06-20 10:52:58 +00:00
ir_value_code_setaddr ( field , vec_size ( self - > code - > globals ) ) ;
vec_push ( self - > code - > globals , fld . offset ) ;
2012-08-11 17:08:23 +00:00
if ( fld . type = = TYPE_VECTOR ) {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , fld . offset + 1 ) ;
vec_push ( self - > code - > globals , fld . offset + 2 ) ;
2012-08-11 17:08:23 +00:00
}
2012-07-28 19:55:01 +00:00
2012-12-18 11:41:38 +00:00
if ( field - > fieldtype = = TYPE_VECTOR ) {
2013-06-20 10:52:58 +00:00
gen_vector_defs ( self - > code , def , field - > name ) ;
gen_vector_fields ( self - > code , fld , field - > name ) ;
2012-12-18 11:41:38 +00:00
}
2012-07-28 19:55:01 +00:00
return field - > code . globaladdr > = 0 ;
}
2014-10-18 11:49:13 +00:00
static void ir_builder_collect_reusables ( ir_builder * builder ) {
size_t i ;
ir_value * * reusables = NULL ;
for ( i = 0 ; i < vec_size ( builder - > globals ) ; + + i ) {
ir_value * value = builder - > globals [ i ] ;
if ( value - > vtype ! = TYPE_FLOAT | | ! value - > hasvalue )
continue ;
if ( value - > cvq = = CV_CONST | | ( value - > name & & value - > name [ 0 ] = = ' # ' ) ) {
vec_push ( reusables , value ) ;
}
}
builder - > const_floats = reusables ;
}
static void ir_builder_split_vector ( ir_builder * self , ir_value * vec ) {
size_t i , count ;
ir_value * found [ 3 ] = { NULL , NULL , NULL } ;
/* must not be written to */
if ( vec_size ( vec - > writes ) )
return ;
/* must not be trying to access individual members */
if ( vec - > members [ 0 ] | | vec - > members [ 1 ] | | vec - > members [ 2 ] )
return ;
/* should be actually used otherwise it won't be generated anyway */
count = vec_size ( vec - > reads ) ;
if ( ! count )
return ;
/* may only be used directly as function parameters, so if we find some other instruction cancel */
for ( i = 0 ; i ! = count ; + + i ) {
/* we only split vectors if they're used directly as parameter to a call only! */
ir_instr * user = vec - > reads [ i ] ;
if ( ( user - > opcode < INSTR_CALL0 | | user - > opcode > INSTR_CALL8 ) & & user - > opcode ! = VINSTR_NRCALL )
return ;
}
vec - > flags | = IR_FLAG_SPLIT_VECTOR ;
/* find existing floats making up the split */
count = vec_size ( self - > const_floats ) ;
for ( i = 0 ; i ! = count ; + + i ) {
ir_value * c = self - > const_floats [ i ] ;
if ( ! found [ 0 ] & & c - > constval . vfloat = = vec - > constval . vvec . x )
found [ 0 ] = c ;
if ( ! found [ 1 ] & & c - > constval . vfloat = = vec - > constval . vvec . y )
found [ 1 ] = c ;
if ( ! found [ 2 ] & & c - > constval . vfloat = = vec - > constval . vvec . z )
found [ 2 ] = c ;
if ( found [ 0 ] & & found [ 1 ] & & found [ 2 ] )
break ;
}
/* generate floats for not yet found components */
if ( ! found [ 0 ] )
found [ 0 ] = ir_builder_imm_float ( self , vec - > constval . vvec . x , true ) ;
if ( ! found [ 1 ] ) {
if ( vec - > constval . vvec . y = = vec - > constval . vvec . x )
found [ 1 ] = found [ 0 ] ;
else
found [ 1 ] = ir_builder_imm_float ( self , vec - > constval . vvec . y , true ) ;
}
if ( ! found [ 2 ] ) {
if ( vec - > constval . vvec . z = = vec - > constval . vvec . x )
found [ 2 ] = found [ 0 ] ;
else if ( vec - > constval . vvec . z = = vec - > constval . vvec . y )
found [ 2 ] = found [ 1 ] ;
else
found [ 2 ] = ir_builder_imm_float ( self , vec - > constval . vvec . z , true ) ;
}
/* the .members array should be safe to use here. */
vec - > members [ 0 ] = found [ 0 ] ;
vec - > members [ 1 ] = found [ 1 ] ;
vec - > members [ 2 ] = found [ 2 ] ;
/* register the readers for these floats */
count = vec_size ( vec - > reads ) ;
for ( i = 0 ; i ! = count ; + + i ) {
vec_push ( found [ 0 ] - > reads , vec - > reads [ i ] ) ;
vec_push ( found [ 1 ] - > reads , vec - > reads [ i ] ) ;
vec_push ( found [ 2 ] - > reads , vec - > reads [ i ] ) ;
}
}
static void ir_builder_split_vectors ( ir_builder * self ) {
size_t i , count = vec_size ( self - > globals ) ;
for ( i = 0 ; i ! = count ; + + i ) {
ir_value * v = self - > globals [ i ] ;
if ( v - > vtype ! = TYPE_VECTOR | | ! v - > name | | v - > name [ 0 ] ! = ' # ' )
continue ;
ir_builder_split_vector ( self , self - > globals [ i ] ) ;
}
}
2013-06-20 10:52:58 +00:00
bool ir_builder_generate ( ir_builder * self , const char * filename )
2012-05-04 22:03:18 +00:00
{
2013-07-30 16:00:51 +00:00
prog_section_statement_t stmt ;
2012-05-04 22:28:51 +00:00
size_t i ;
2012-12-23 16:32:39 +00:00
char * lnofile = NULL ;
2012-05-04 22:28:51 +00:00
2014-10-18 11:49:13 +00:00
if ( OPTS_FLAG ( SPLIT_VECTOR_PARAMETERS ) ) {
ir_builder_collect_reusables ( self ) ;
if ( vec_size ( self - > const_floats ) > 0 )
ir_builder_split_vectors ( self ) ;
}
2012-11-30 20:22:48 +00:00
for ( i = 0 ; i < vec_size ( self - > fields ) ; + + i )
{
2013-06-20 10:52:58 +00:00
ir_builder_prepare_field ( self - > code , self - > fields [ i ] ) ;
2012-11-30 20:22:48 +00:00
}
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > globals ) ; + + i )
2012-07-28 19:55:01 +00:00
{
2013-06-20 10:52:58 +00:00
if ( ! ir_builder_gen_global ( self , self - > globals [ i ] , false ) ) {
2012-07-28 19:55:01 +00:00
return false ;
}
2012-12-23 15:31:01 +00:00
if ( self - > globals [ i ] - > vtype = = TYPE_FUNCTION ) {
ir_function * func = self - > globals [ i ] - > constval . vfunc ;
2012-12-23 16:32:39 +00:00
if ( func & & self - > max_locals < func - > allocated_locals & &
! ( func - > flags & IR_FLAG_MASK_NO_OVERLAP ) )
{
2012-12-23 15:31:01 +00:00
self - > max_locals = func - > allocated_locals ;
2012-12-23 16:32:39 +00:00
}
2012-12-26 22:18:45 +00:00
if ( func & & self - > max_globaltemps < func - > globaltemps )
self - > max_globaltemps = func - > globaltemps ;
2012-12-23 15:31:01 +00:00
}
2012-07-28 19:55:01 +00:00
}
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > fields ) ; + + i )
2012-05-04 22:28:51 +00:00
{
2013-06-20 10:52:58 +00:00
if ( ! ir_builder_gen_field ( self , self - > fields [ i ] ) ) {
2012-05-04 22:28:51 +00:00
return false ;
2012-06-25 09:52:18 +00:00
}
2012-05-04 22:28:51 +00:00
}
2012-12-31 12:25:18 +00:00
/* generate nil */
2013-06-20 10:52:58 +00:00
ir_value_code_setaddr ( self - > nil , vec_size ( self - > code - > globals ) ) ;
vec_push ( self - > code - > globals , 0 ) ;
vec_push ( self - > code - > globals , 0 ) ;
vec_push ( self - > code - > globals , 0 ) ;
2012-12-31 12:25:18 +00:00
2013-08-26 08:25:29 +00:00
/* generate virtual-instruction temps */
for ( i = 0 ; i < IR_MAX_VINSTR_TEMPS ; + + i ) {
ir_value_code_setaddr ( self - > vinstr_temp [ i ] , vec_size ( self - > code - > globals ) ) ;
vec_push ( self - > code - > globals , 0 ) ;
vec_push ( self - > code - > globals , 0 ) ;
vec_push ( self - > code - > globals , 0 ) ;
}
2012-12-26 22:18:45 +00:00
/* generate global temps */
2013-06-20 10:52:58 +00:00
self - > first_common_globaltemp = vec_size ( self - > code - > globals ) ;
2012-12-26 22:18:45 +00:00
for ( i = 0 ; i < self - > max_globaltemps ; + + i ) {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , 0 ) ;
2012-12-26 22:18:45 +00:00
}
2012-12-23 16:32:39 +00:00
/* generate common locals */
2013-06-20 10:52:58 +00:00
self - > first_common_local = vec_size ( self - > code - > globals ) ;
2012-12-23 16:32:39 +00:00
for ( i = 0 ; i < self - > max_locals ; + + i ) {
2013-06-20 10:52:58 +00:00
vec_push ( self - > code - > globals , 0 ) ;
2012-12-23 16:32:39 +00:00
}
2012-08-19 16:00:53 +00:00
/* generate function code */
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > globals ) ; + + i )
2012-08-19 16:00:53 +00:00
{
if ( self - > globals [ i ] - > vtype = = TYPE_FUNCTION ) {
2013-06-20 10:52:58 +00:00
if ( ! gen_global_function_code ( self , self - > globals [ i ] ) ) {
2012-08-19 16:00:53 +00:00
return false ;
}
}
}
2013-06-20 10:52:58 +00:00
if ( vec_size ( self - > code - > globals ) > = 65536 ) {
2014-10-18 11:49:13 +00:00
irerror ( vec_last ( self - > globals ) - > context , " This progs file would require more globals than the metadata can handle (%u). Bailing out. " , ( unsigned int ) vec_size ( self - > code - > globals ) ) ;
2012-11-22 20:25:02 +00:00
return false ;
}
2012-12-18 10:46:26 +00:00
/* DP errors if the last instruction is not an INSTR_DONE. */
2013-06-20 10:52:58 +00:00
if ( vec_last ( self - > code - > statements ) . opcode ! = INSTR_DONE )
2012-12-18 10:46:26 +00:00
{
2013-08-26 18:14:33 +00:00
lex_ctx_t last ;
2012-12-18 10:46:26 +00:00
stmt . opcode = INSTR_DONE ;
2013-08-26 18:14:33 +00:00
stmt . o1 . u1 = 0 ;
stmt . o2 . u1 = 0 ;
stmt . o3 . u1 = 0 ;
last . line = vec_last ( self - > code - > linenums ) ;
last . column = vec_last ( self - > code - > columnnums ) ;
code_push_statement ( self - > code , & stmt , last ) ;
2012-12-18 10:46:26 +00:00
}
2012-11-30 17:19:26 +00:00
2013-01-30 05:35:07 +00:00
if ( OPTS_OPTION_BOOL ( OPTION_PP_ONLY ) )
2012-11-30 17:19:26 +00:00
return true ;
2013-06-20 10:52:58 +00:00
if ( vec_size ( self - > code - > statements ) ! = vec_size ( self - > code - > linenums ) ) {
2012-11-30 17:19:26 +00:00
con_err ( " Linecounter wrong: %lu != %lu \n " ,
2013-06-20 10:52:58 +00:00
( unsigned long ) vec_size ( self - > code - > statements ) ,
( unsigned long ) vec_size ( self - > code - > linenums ) ) ;
2012-11-30 17:19:26 +00:00
} else if ( OPTS_FLAG ( LNO ) ) {
2013-04-25 09:35:30 +00:00
char * dot ;
2012-11-30 17:19:26 +00:00
size_t filelen = strlen ( filename ) ;
memcpy ( vec_add ( lnofile , filelen + 1 ) , filename , filelen + 1 ) ;
dot = strrchr ( lnofile , ' . ' ) ;
if ( ! dot ) {
vec_pop ( lnofile ) ;
} else {
vec_shrinkto ( lnofile , dot - lnofile ) ;
}
memcpy ( vec_add ( lnofile , 5 ) , " .lno " , 5 ) ;
}
2012-08-21 16:12:01 +00:00
2013-06-20 10:52:58 +00:00
if ( ! code_write ( self - > code , filename , lnofile ) ) {
2012-11-30 17:19:26 +00:00
vec_free ( lnofile ) ;
return false ;
}
2013-08-14 04:08:00 +00:00
2012-11-30 17:19:26 +00:00
vec_free ( lnofile ) ;
return true ;
2012-05-04 22:03:18 +00:00
}
2012-04-28 09:50:01 +00:00
/***********************************************************************
* IR DEBUG Dump functions . . .
*/
# define IND_BUFSZ 1024
2013-05-29 03:29:04 +00:00
static const char * qc_opname ( int op )
2012-04-28 09:50:01 +00:00
{
if ( op < 0 ) return " <INVALID> " ;
2013-07-28 00:23:15 +00:00
if ( op < VINSTR_END )
return util_instr_str [ op ] ;
2012-04-28 09:50:01 +00:00
switch ( op ) {
2013-08-26 08:25:29 +00:00
case VINSTR_END : return " END " ;
case VINSTR_PHI : return " PHI " ;
case VINSTR_JUMP : return " JUMP " ;
case VINSTR_COND : return " COND " ;
case VINSTR_BITXOR : return " BITXOR " ;
case VINSTR_BITAND_V : return " BITAND_V " ;
case VINSTR_BITOR_V : return " BITOR_V " ;
case VINSTR_BITXOR_V : return " BITXOR_V " ;
case VINSTR_BITAND_VF : return " BITAND_VF " ;
case VINSTR_BITOR_VF : return " BITOR_VF " ;
case VINSTR_BITXOR_VF : return " BITXOR_VF " ;
2013-08-31 18:49:06 +00:00
case VINSTR_CROSS : return " CROSS " ;
2013-10-06 03:36:48 +00:00
case VINSTR_NEG_F : return " NEG_F " ;
case VINSTR_NEG_V : return " NEG_V " ;
2013-08-26 08:25:29 +00:00
default : return " <UNK> " ;
2012-04-28 09:50:01 +00:00
}
}
void ir_builder_dump ( ir_builder * b , int ( * oprintf ) ( const char * , . . . ) )
{
2012-08-12 08:14:22 +00:00
size_t i ;
char indent [ IND_BUFSZ ] ;
indent [ 0 ] = ' \t ' ;
indent [ 1 ] = 0 ;
oprintf ( " module %s \n " , b - > name ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( b - > globals ) ; + + i )
2012-08-12 08:14:22 +00:00
{
oprintf ( " global " ) ;
2012-11-30 12:47:28 +00:00
if ( b - > globals [ i ] - > hasvalue )
2012-08-12 08:14:22 +00:00
oprintf ( " %s = " , b - > globals [ i ] - > name ) ;
ir_value_dump ( b - > globals [ i ] , oprintf ) ;
oprintf ( " \n " ) ;
}
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( b - > functions ) ; + + i )
2012-08-12 08:14:22 +00:00
ir_function_dump ( b - > functions [ i ] , indent , oprintf ) ;
oprintf ( " endmodule %s \n " , b - > name ) ;
2012-04-28 09:50:01 +00:00
}
2013-01-08 20:21:52 +00:00
static const char * storenames [ ] = {
" [global] " , " [local] " , " [param] " , " [value] " , " [return] "
} ;
2012-04-28 09:50:01 +00:00
void ir_function_dump ( ir_function * f , char * ind ,
int ( * oprintf ) ( const char * , . . . ) )
{
2012-08-12 08:14:22 +00:00
size_t i ;
if ( f - > builtin ! = 0 ) {
oprintf ( " %sfunction %s = builtin %i \n " , ind , f - > name , - f - > builtin ) ;
return ;
}
oprintf ( " %sfunction %s \n " , ind , f - > name ) ;
2013-10-11 10:12:56 +00:00
util_strncat ( ind , " \t " , IND_BUFSZ - 1 ) ;
2012-11-15 17:32:03 +00:00
if ( vec_size ( f - > locals ) )
2012-08-12 08:14:22 +00:00
{
2012-11-15 17:32:03 +00:00
oprintf ( " %s%i locals: \n " , ind , ( int ) vec_size ( f - > locals ) ) ;
for ( i = 0 ; i < vec_size ( f - > locals ) ; + + i ) {
2012-08-12 08:14:22 +00:00
oprintf ( " %s \t " , ind ) ;
ir_value_dump ( f - > locals [ i ] , oprintf ) ;
oprintf ( " \n " ) ;
}
}
2012-08-22 14:04:06 +00:00
oprintf ( " %sliferanges: \n " , ind ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( f - > locals ) ; + + i ) {
2012-12-26 22:18:45 +00:00
const char * attr = " " ;
2012-12-24 11:43:05 +00:00
size_t l , m ;
2012-08-22 14:04:06 +00:00
ir_value * v = f - > locals [ i ] ;
2012-12-26 22:18:45 +00:00
if ( v - > unique_life & & v - > locked )
attr = " unique,locked " ;
else if ( v - > unique_life )
attr = " unique " ;
else if ( v - > locked )
attr = " locked " ;
2013-01-08 20:21:52 +00:00
oprintf ( " %s \t %s: %s %s %s%s@%i " , ind , v - > name , type_name [ v - > vtype ] ,
storenames [ v - > store ] ,
2013-01-07 13:25:01 +00:00
attr , ( v - > callparam ? " callparam " : " " ) ,
( int ) v - > code . local ) ;
2013-01-08 20:21:52 +00:00
if ( ! v - > life )
oprintf ( " [null] " ) ;
2012-11-15 17:32:03 +00:00
for ( l = 0 ; l < vec_size ( v - > life ) ; + + l ) {
2012-08-22 14:19:35 +00:00
oprintf ( " [%i,%i] " , v - > life [ l ] . start , v - > life [ l ] . end ) ;
2012-08-22 14:04:06 +00:00
}
oprintf ( " \n " ) ;
2012-12-24 11:43:05 +00:00
for ( m = 0 ; m < 3 ; + + m ) {
ir_value * vm = v - > members [ m ] ;
if ( ! vm )
continue ;
2013-01-08 20:21:52 +00:00
oprintf ( " %s \t %s: @%i " , ind , vm - > name , ( int ) vm - > code . local ) ;
2012-12-24 11:43:05 +00:00
for ( l = 0 ; l < vec_size ( vm - > life ) ; + + l ) {
oprintf ( " [%i,%i] " , vm - > life [ l ] . start , vm - > life [ l ] . end ) ;
}
oprintf ( " \n " ) ;
}
2012-08-22 14:04:06 +00:00
}
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( f - > values ) ; + + i ) {
2012-12-29 14:05:04 +00:00
const char * attr = " " ;
size_t l , m ;
2012-08-22 14:04:06 +00:00
ir_value * v = f - > values [ i ] ;
2012-12-29 14:05:04 +00:00
if ( v - > unique_life & & v - > locked )
attr = " unique,locked " ;
else if ( v - > unique_life )
attr = " unique " ;
else if ( v - > locked )
attr = " locked " ;
2013-01-08 20:21:52 +00:00
oprintf ( " %s \t %s: %s %s %s%s@%i " , ind , v - > name , type_name [ v - > vtype ] ,
storenames [ v - > store ] ,
2013-01-07 13:25:01 +00:00
attr , ( v - > callparam ? " callparam " : " " ) ,
( int ) v - > code . local ) ;
2013-01-08 20:21:52 +00:00
if ( ! v - > life )
oprintf ( " [null] " ) ;
2012-11-15 17:32:03 +00:00
for ( l = 0 ; l < vec_size ( v - > life ) ; + + l ) {
2012-08-22 14:19:35 +00:00
oprintf ( " [%i,%i] " , v - > life [ l ] . start , v - > life [ l ] . end ) ;
2012-08-22 14:04:06 +00:00
}
oprintf ( " \n " ) ;
2012-12-29 14:05:04 +00:00
for ( m = 0 ; m < 3 ; + + m ) {
ir_value * vm = v - > members [ m ] ;
if ( ! vm )
continue ;
if ( vm - > unique_life & & vm - > locked )
attr = " unique,locked " ;
else if ( vm - > unique_life )
attr = " unique " ;
else if ( vm - > locked )
attr = " locked " ;
oprintf ( " %s \t %s: %s@%i " , ind , vm - > name , attr , ( int ) vm - > code . local ) ;
for ( l = 0 ; l < vec_size ( vm - > life ) ; + + l ) {
oprintf ( " [%i,%i] " , vm - > life [ l ] . start , vm - > life [ l ] . end ) ;
}
oprintf ( " \n " ) ;
}
2012-08-22 14:04:06 +00:00
}
2012-11-15 17:32:03 +00:00
if ( vec_size ( f - > blocks ) )
2012-08-12 08:14:22 +00:00
{
2013-04-21 10:24:55 +00:00
oprintf ( " %slife passes: %i \n " , ind , ( int ) f - > run_id ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( f - > blocks ) ; + + i ) {
2012-08-12 08:14:22 +00:00
ir_block_dump ( f - > blocks [ i ] , ind , oprintf ) ;
}
}
ind [ strlen ( ind ) - 1 ] = 0 ;
oprintf ( " %sendfunction %s \n " , ind , f - > name ) ;
2012-04-28 09:50:01 +00:00
}
void ir_block_dump ( ir_block * b , char * ind ,
int ( * oprintf ) ( const char * , . . . ) )
{
2012-08-12 08:14:22 +00:00
size_t i ;
oprintf ( " %s:%s \n " , ind , b - > label ) ;
2013-10-11 10:12:56 +00:00
util_strncat ( ind , " \t " , IND_BUFSZ - 1 ) ;
2012-04-28 09:50:01 +00:00
2013-01-08 14:22:24 +00:00
if ( b - > instr & & b - > instr [ 0 ] )
oprintf ( " %s (%i) [entry] \n " , ind , ( int ) ( b - > instr [ 0 ] - > eid - 1 ) ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( b - > instr ) ; + + i )
2012-08-12 08:14:22 +00:00
ir_instr_dump ( b - > instr [ i ] , ind , oprintf ) ;
ind [ strlen ( ind ) - 1 ] = 0 ;
2012-04-28 09:50:01 +00:00
}
2013-05-29 03:29:04 +00:00
static void dump_phi ( ir_instr * in , int ( * oprintf ) ( const char * , . . . ) )
2012-04-28 09:50:01 +00:00
{
2012-08-12 08:14:22 +00:00
size_t i ;
oprintf ( " %s <- phi " , in - > _ops [ 0 ] - > name ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( in - > phi ) ; + + i )
2012-08-12 08:14:22 +00:00
{
oprintf ( " ([%s] : %s) " , in - > phi [ i ] . from - > label ,
in - > phi [ i ] . value - > name ) ;
}
oprintf ( " \n " ) ;
2012-04-28 09:50:01 +00:00
}
void ir_instr_dump ( ir_instr * in , char * ind ,
int ( * oprintf ) ( const char * , . . . ) )
{
2012-08-12 08:14:22 +00:00
size_t i ;
const char * comma = NULL ;
oprintf ( " %s (%i) " , ind , ( int ) in - > eid ) ;
if ( in - > opcode = = VINSTR_PHI ) {
2012-11-22 20:41:22 +00:00
dump_phi ( in , oprintf ) ;
2012-08-12 08:14:22 +00:00
return ;
}
2013-10-11 10:12:56 +00:00
util_strncat ( ind , " \t " , IND_BUFSZ - 1 ) ;
2012-08-12 08:14:22 +00:00
if ( in - > _ops [ 0 ] & & ( in - > _ops [ 1 ] | | in - > _ops [ 2 ] ) ) {
ir_value_dump ( in - > _ops [ 0 ] , oprintf ) ;
if ( in - > _ops [ 1 ] | | in - > _ops [ 2 ] )
oprintf ( " <- " ) ;
}
2012-12-19 19:38:32 +00:00
if ( in - > opcode = = INSTR_CALL0 | | in - > opcode = = VINSTR_NRCALL ) {
2012-11-15 17:32:03 +00:00
oprintf ( " CALL%i \t " , vec_size ( in - > params ) ) ;
2012-08-12 08:19:33 +00:00
} else
oprintf ( " %s \t " , qc_opname ( in - > opcode ) ) ;
2012-08-12 08:14:22 +00:00
if ( in - > _ops [ 0 ] & & ! ( in - > _ops [ 1 ] | | in - > _ops [ 2 ] ) ) {
ir_value_dump ( in - > _ops [ 0 ] , oprintf ) ;
comma = " , \t " ;
}
else
{
for ( i = 1 ; i ! = 3 ; + + i ) {
if ( in - > _ops [ i ] ) {
if ( comma )
oprintf ( comma ) ;
ir_value_dump ( in - > _ops [ i ] , oprintf ) ;
comma = " , \t " ;
}
}
}
if ( in - > bops [ 0 ] ) {
if ( comma )
oprintf ( comma ) ;
oprintf ( " [%s] " , in - > bops [ 0 ] - > label ) ;
comma = " , \t " ;
}
if ( in - > bops [ 1 ] )
oprintf ( " %s[%s] " , comma , in - > bops [ 1 ] - > label ) ;
2012-11-15 17:32:03 +00:00
if ( vec_size ( in - > params ) ) {
2012-08-22 14:04:06 +00:00
oprintf ( " \t params: " ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i ! = vec_size ( in - > params ) ; + + i ) {
2012-08-22 14:04:06 +00:00
oprintf ( " %s, " , in - > params [ i ] - > name ) ;
}
}
2012-08-12 08:14:22 +00:00
oprintf ( " \n " ) ;
ind [ strlen ( ind ) - 1 ] = 0 ;
2012-04-28 09:50:01 +00:00
}
2013-05-29 03:29:04 +00:00
static void ir_value_dump_string ( const char * str , int ( * oprintf ) ( const char * , . . . ) )
2012-11-21 20:49:21 +00:00
{
oprintf ( " \" " ) ;
for ( ; * str ; + + str ) {
switch ( * str ) {
case ' \n ' : oprintf ( " \\ n " ) ; break ;
case ' \r ' : oprintf ( " \\ r " ) ; break ;
case ' \t ' : oprintf ( " \\ t " ) ; break ;
case ' \v ' : oprintf ( " \\ v " ) ; break ;
case ' \f ' : oprintf ( " \\ f " ) ; break ;
case ' \b ' : oprintf ( " \\ b " ) ; break ;
case ' \a ' : oprintf ( " \\ a " ) ; break ;
case ' \\ ' : oprintf ( " \\ \\ " ) ; break ;
case ' " ' : oprintf ( " \\ \" " ) ; break ;
default : oprintf ( " %c " , * str ) ; break ;
}
}
oprintf ( " \" " ) ;
}
2012-04-28 09:50:01 +00:00
void ir_value_dump ( ir_value * v , int ( * oprintf ) ( const char * , . . . ) )
{
2012-11-30 12:47:28 +00:00
if ( v - > hasvalue ) {
2012-08-12 08:14:22 +00:00
switch ( v - > vtype ) {
2012-08-12 09:28:18 +00:00
default :
2012-08-12 08:14:22 +00:00
case TYPE_VOID :
oprintf ( " (void) " ) ;
break ;
2012-08-12 08:15:27 +00:00
case TYPE_FUNCTION :
2012-08-22 14:04:06 +00:00
oprintf ( " fn:%s " , v - > name ) ;
2012-08-12 08:15:27 +00:00
break ;
2012-08-12 08:14:22 +00:00
case TYPE_FLOAT :
oprintf ( " %g " , v - > constval . vfloat ) ;
break ;
case TYPE_VECTOR :
oprintf ( " '%g %g %g' " ,
v - > constval . vvec . x ,
v - > constval . vvec . y ,
v - > constval . vvec . z ) ;
break ;
case TYPE_ENTITY :
oprintf ( " (entity) " ) ;
break ;
case TYPE_STRING :
2012-11-21 20:49:21 +00:00
ir_value_dump_string ( v - > constval . vstring , oprintf ) ;
2012-08-12 08:14:22 +00:00
break ;
2012-04-28 09:50:01 +00:00
#if 0
2012-08-12 08:14:22 +00:00
case TYPE_INTEGER :
oprintf ( " %i " , v - > constval . vint ) ;
break ;
2012-04-28 09:50:01 +00:00
# endif
2012-08-12 08:14:22 +00:00
case TYPE_POINTER :
oprintf ( " &%s " ,
v - > constval . vpointer - > name ) ;
break ;
}
} else {
oprintf ( " %s " , v - > name ) ;
}
2012-04-28 09:50:01 +00:00
}
2012-08-23 20:07:32 +00:00
void ir_value_dump_life ( const ir_value * self , int ( * oprintf ) ( const char * , . . . ) )
2012-04-28 09:50:01 +00:00
{
2012-08-12 08:14:22 +00:00
size_t i ;
2012-08-23 20:07:32 +00:00
oprintf ( " Life of %12s: " , self - > name ) ;
2012-11-15 17:32:03 +00:00
for ( i = 0 ; i < vec_size ( self - > life ) ; + + i )
2012-08-12 08:14:22 +00:00
{
oprintf ( " + [%i, %i] \n " , self - > life [ i ] . start , self - > life [ i ] . end ) ;
}
2012-04-28 09:50:01 +00:00
}