1242 lines
34 KiB
C
1242 lines
34 KiB
C
/**
|
||
* Part of the Lccrt Project, under the Apache License v2.0
|
||
* See http://www.apache.org/licenses/LICENSE-2.0.txt for license information.
|
||
* SPDX-License-Identifier: Apache-2.0
|
||
*
|
||
* lccrt_func.c - реализация пользовательский интерфейс (динамической) компиляции.
|
||
*/
|
||
|
||
#include <stdlib.h>
|
||
#include <stdio.h>
|
||
#include <string.h>
|
||
#include <ctype.h>
|
||
#include <stdarg.h>
|
||
|
||
#include "lccrt_irv.h"
|
||
#include "lccrt_jit.h"
|
||
|
||
typedef enum
|
||
{
|
||
LCCRT_FCT_COPY, /* полное копирование функции (возможно в другой модуль) */
|
||
LCCRT_FCT_INLINE, /* встраивание функции (в рамках одного модуля) */
|
||
LCCRT_FCT_LAST
|
||
} lccrt_function_copy_type_t;
|
||
|
||
/**
|
||
* Данные, используемые при копировании функции.
|
||
*/
|
||
typedef struct
|
||
{
|
||
lccrt_function_copy_type_t type; /* тип копирования */
|
||
lccrt_function_ptr src_func; /* исходная функция */
|
||
lccrt_function_ptr dst_func; /* результирующая функция */
|
||
lccrt_hash_ptr vars; /* соответствие (src_var -> dst_var) */
|
||
lccrt_hash_ptr opers; /* соответствие (src_oper -> dst_oper) */
|
||
lccrt_hash_ptr types; /* соответствие (src_type -> dst_type) */
|
||
lccrt_oper_ptr call; /* операция вызова (для LCCRT_FCT_INLINE) */
|
||
} lccrt_function_copy_info_t;
|
||
|
||
extern int lccrt_function_set_attr( lccrt_f_ptr f, lccrt_function_attr_name_t attr, int value);
|
||
static int lccrt_function_get_attr( lccrt_f_ptr f, lccrt_function_attr_name_t attr);
|
||
|
||
/**
|
||
* Создание новой функции.
|
||
*/
|
||
lccrt_function_ptr
|
||
lccrt_function_new( lccrt_module_ptr module, lccrt_type_ptr sig,
|
||
const char *name, const char *asm_name, lccrt_link_t vlink,
|
||
int is_declaration, int is_builtin)
|
||
{
|
||
int k;
|
||
int is_fnew = 0;
|
||
lccrt_context_ptr ctx = module->ctx;
|
||
lccrt_function_ptr f = 0;
|
||
lccrt_hash_entry_ptr entry = 0;
|
||
lccrt_asmlink_t link = lccrt_link_unpack( vlink);
|
||
|
||
lccrt_assert( link.tls == LCCRT_LINK_TLS_NO);
|
||
lccrt_assert( !link.is_cnst);
|
||
|
||
lccrt_check_type_assert( module, lccrt_module_t);
|
||
lccrt_check_type_assert( sig, lccrt_type_t);
|
||
|
||
entry = lccrt_hash_push( module->funcs, (uintptr_t)name, &is_fnew);
|
||
if ( !is_fnew )
|
||
{
|
||
f = (lccrt_function_ptr)lccrt_hash_get( entry);
|
||
if ( (f->sig_type == sig)
|
||
&& is_declaration
|
||
&& lccrt_function_get_attr( f, LCCRT_FUNC_ATTR_DECLARATION)
|
||
&& (is_builtin == lccrt_function_get_attr( f, LCCRT_FUNC_ATTR_BUILTIN))
|
||
&& ((asm_name == f->asm_name)
|
||
|| (asm_name
|
||
&& f->asm_name
|
||
&& lccrt_str_eq( asm_name, f->asm_name)))
|
||
&& (vlink == lccrt_function_get_link( f)) )
|
||
{
|
||
} else
|
||
{
|
||
lccrt_assert( 0);
|
||
}
|
||
} else
|
||
{
|
||
f = lccrt_ctx_malloc( ctx, lccrt_function_t);
|
||
memset( f, 0, sizeof( f[0]));
|
||
lccrt_check_type_init( f, lccrt_function_t);
|
||
f->ctx = (lccrt_context_ptr)ctx;
|
||
f->module = (lccrt_module_ptr)module;
|
||
module->funcs_num++;
|
||
f->ident_num = module->funcs_num;
|
||
f->name = lccrt_ctx_copy_str( ctx, name);
|
||
f->asm_name = lccrt_ctx_copy_str( ctx, asm_name);
|
||
f->link = link;
|
||
f->sig_type = sig;
|
||
f->args = lccrt_ctx_mallocn( ctx, lccrt_var_ptr, sig->num_args);
|
||
f->sysargs = 0;
|
||
f->sysargs_num = 0;
|
||
f->lvars_num = 0;
|
||
f->opers_num = 0;
|
||
f->local_name_id = 0;
|
||
lccrt_ilist_unit_init( &(f->funcs_unit));
|
||
lccrt_ilist_head_init( &(f->lvars_head));
|
||
lccrt_check_type_init( &(f->cur), lccrt_oper_iterator_t);
|
||
f->cur.is_forward = 1;
|
||
f->lvars = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING);
|
||
for ( k = 0; k < sig->num_args; ++k )
|
||
{
|
||
f->args[k] = 0;
|
||
}
|
||
|
||
lccrt_function_set_attr( f, LCCRT_FUNC_ATTR_DECLARATION, is_declaration);
|
||
lccrt_function_set_attr( f, LCCRT_FUNC_ATTR_BUILTIN, is_builtin);
|
||
|
||
lccrt_hash_set( entry, (uintptr_t)f);
|
||
lccrt_ilist_head_insert( &(module->funcs_head), funcs_unit, f);
|
||
}
|
||
|
||
return (f);
|
||
} /* lccrt_function_new */
|
||
|
||
/**
|
||
* Удаление функции.
|
||
*/
|
||
void
|
||
lccrt_function_delete( lccrt_function_ptr f)
|
||
{
|
||
lccrt_oper_ptr o;
|
||
lccrt_he_ptr e;
|
||
lccrt_context_ptr ctx = f->ctx;
|
||
lccrt_module_ptr m = f->module;
|
||
lccrt_oper_ptr o_next = 0;
|
||
|
||
lccrt_check_type_assert( f, lccrt_function_t);
|
||
lccrt_ilist_head_remove( &(m->funcs_head), funcs_unit, f);
|
||
lccrt_ctx_free( ctx, f->name);
|
||
lccrt_ctx_free( ctx, f->asm_name);
|
||
|
||
for ( e = lccrt_hash_first( f->lvars); e; e = lccrt_hash_next( e) )
|
||
{
|
||
lccrt_var_delete( (lccrt_var_ptr)lccrt_hash_get( e));
|
||
}
|
||
|
||
lccrt_hash_delete( f->lvars);
|
||
|
||
lccrt_ctx_free( ctx, f->sysargs);
|
||
lccrt_ctx_free( ctx, f->args);
|
||
lccrt_ctx_free( ctx, f->section);
|
||
lccrt_ctx_free( ctx, f->comdat);
|
||
|
||
/* Удаляем промежуточное представление функции. */
|
||
for ( o = f->start; o; o = o_next )
|
||
{
|
||
o_next = o->next;
|
||
o->next = 0;
|
||
if ( o_next )
|
||
{
|
||
o_next->prev = 0;
|
||
}
|
||
|
||
o->res = 0;
|
||
lccrt_oper_delete( o);
|
||
}
|
||
|
||
f->einfo = lccrt_einfo_link_delete_chain( f->einfo);
|
||
|
||
lccrt_check_type_done( f, lccrt_function_t);
|
||
lccrt_ctx_free( ctx, f);
|
||
|
||
return;
|
||
} /* lccrt_function_delete */
|
||
|
||
/**
|
||
* Заполнение в функции jit-данных.
|
||
*/
|
||
void
|
||
lccrt_function_init_jit_info( lccrt_f_ptr f, lccrt_f_ptr root,
|
||
lccrt_v_ptr func_entry, lccrt_v_ptr profgen_tls)
|
||
{
|
||
lccrt_check_type_assert( f, lccrt_function_t);
|
||
|
||
lccrt_assert( func_entry);
|
||
if ( lccrt_function_is_profgen( f) )
|
||
{
|
||
lccrt_assert( root && (f != root));
|
||
lccrt_assert( profgen_tls);
|
||
} else
|
||
{
|
||
lccrt_assert( !root);
|
||
lccrt_assert( !profgen_tls);
|
||
}
|
||
|
||
return;
|
||
} /* lccrt_function_init_jit_info */
|
||
|
||
/**
|
||
* Получить значение поля.
|
||
*/
|
||
lccrt_fji_ptr
|
||
lccrt_function_get_jit_info( lccrt_f_ptr f)
|
||
{
|
||
lccrt_fji_ptr r = 0;
|
||
|
||
lccrt_check_type_assert( f, lccrt_function_t);
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_jit_info */
|
||
|
||
/**
|
||
* Получить имя функции.
|
||
*/
|
||
const char *
|
||
lccrt_function_get_name( lccrt_function_ptr func)
|
||
{
|
||
const char *r = func->name;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_name */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
lccrt_module_ptr
|
||
lccrt_function_get_module( lccrt_function_ptr func)
|
||
{
|
||
lccrt_module_ptr r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = func->module;
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_module */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
lccrt_type_ptr
|
||
lccrt_function_get_type( lccrt_function_ptr func)
|
||
{
|
||
lccrt_type_ptr r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = func->sig_type;
|
||
lccrt_assert( lccrt_type_is_function( func->sig_type));
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_type */
|
||
|
||
/**
|
||
* Проверяем, что у функции типом последнего аргумента является тип-многоточие.
|
||
*/
|
||
int
|
||
lccrt_function_is_var_arg( lccrt_function_ptr f)
|
||
{
|
||
int r = 0;
|
||
|
||
lccrt_check_type_assert( f, lccrt_function_t);
|
||
r = lccrt_type_is_function_var_arg( f->sig_type);
|
||
|
||
return (r);
|
||
} /* lccrt_function_is_var_arg */
|
||
|
||
/**
|
||
* Получить количество формальных параметров (без учета параметра "...").
|
||
*/
|
||
int
|
||
lccrt_function_get_num_args( lccrt_function_ptr f)
|
||
{
|
||
int r;
|
||
|
||
lccrt_check_type_assert( f, lccrt_function_t);
|
||
r = lccrt_type_get_num_args( f->sig_type) - lccrt_type_is_function_var_arg( f->sig_type);
|
||
lccrt_assert( r >= 0);
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_num_args */
|
||
|
||
/**
|
||
* Получить количество (специальных) параметров.
|
||
*/
|
||
int
|
||
lccrt_function_get_num_sysargs( lccrt_function_ptr f)
|
||
{
|
||
int r;
|
||
|
||
lccrt_check_type_assert( f, lccrt_function_t);
|
||
r = f->sysargs_num;
|
||
lccrt_assert( r >= 0);
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_num_sysargs */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
lccrt_var_ptr
|
||
lccrt_function_get_arg( lccrt_function_ptr func, int arg_num)
|
||
{
|
||
lccrt_var_ptr r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
lccrt_assert( (0 <= arg_num) && (arg_num < lccrt_function_get_num_args( func)));
|
||
r = func->args[arg_num];
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_arg */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
lccrt_var_ptr
|
||
lccrt_function_get_sysarg( lccrt_function_ptr func, int arg_num)
|
||
{
|
||
lccrt_var_ptr r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
lccrt_assert( (0 <= arg_num) && (arg_num < lccrt_function_get_num_sysargs( func)));
|
||
r = func->sysargs[arg_num];
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_sysarg */
|
||
|
||
/**
|
||
* Установить поле.
|
||
*/
|
||
void
|
||
lccrt_function_set_arg( lccrt_function_ptr func, int arg_num, lccrt_var_ptr arg)
|
||
{
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
lccrt_check_type_assert( arg, lccrt_var_t);
|
||
lccrt_assert( (0 <= arg_num) && (arg_num < lccrt_function_get_num_args( func)));
|
||
func->args[arg_num] = arg;
|
||
if ( arg )
|
||
{
|
||
arg->arg_num = arg_num;
|
||
lccrt_assert( lccrt_var_get_loc( arg) == LCCRT_VAR_LOC_ARG);
|
||
}
|
||
|
||
return;
|
||
} /* lccrt_function_set_arg */
|
||
|
||
/**
|
||
* Установить поле.
|
||
*/
|
||
void
|
||
lccrt_function_set_sysarg( lccrt_function_ptr func, int arg_num, lccrt_var_ptr arg)
|
||
{
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
lccrt_check_type_assert( arg, lccrt_var_t);
|
||
lccrt_assert( (0 <= arg_num) && (arg_num < lccrt_function_get_num_sysargs( func)));
|
||
func->sysargs[arg_num] = arg;
|
||
if ( arg )
|
||
{
|
||
arg->arg_num = arg_num;
|
||
lccrt_assert( lccrt_var_get_loc( arg) == LCCRT_VAR_LOC_SYSARG);
|
||
}
|
||
|
||
return;
|
||
} /* lccrt_function_set_sysarg */
|
||
|
||
/**
|
||
* Установить поле.
|
||
*/
|
||
void
|
||
lccrt_function_add_arg( lccrt_function_ptr func, int arg_num, lccrt_var_ptr arg)
|
||
{
|
||
int k;
|
||
lccrt_module_ptr m = lccrt_function_get_module( func);
|
||
lccrt_context_ptr ctx = lccrt_module_get_context( m);
|
||
int num_args = lccrt_function_get_num_args( func);
|
||
lccrt_type_ptr *types = lccrt_ctx_mallocn( ctx, lccrt_type_ptr, num_args + 1);
|
||
lccrt_var_ptr *args = lccrt_ctx_mallocn( ctx, lccrt_var_ptr, num_args + 1);
|
||
lccrt_type_ptr ftype = lccrt_function_get_type( func);
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
lccrt_check_type_assert( arg, lccrt_var_t);
|
||
lccrt_assert( (0 <= arg_num) && (arg_num == num_args));
|
||
types[arg_num] = lccrt_var_get_type( arg);
|
||
for ( k = 0; k < arg_num; ++k )
|
||
{
|
||
types[k] = lccrt_type_get_arg( ftype, k);
|
||
}
|
||
|
||
ftype = lccrt_type_make_func( lccrt_type_get_parent( ftype), arg_num + 1, types);
|
||
lccrt_ctx_free( ctx, types);
|
||
func->sig_type = ftype;
|
||
|
||
memset( args + num_args, 0, sizeof( args[0]));
|
||
memcpy( args, func->args, num_args*sizeof( args[0]));
|
||
lccrt_ctx_free( ctx, func->args);
|
||
func->args = args;
|
||
lccrt_function_set_arg( func, arg_num, arg);
|
||
|
||
return;
|
||
} /* lccrt_function_add_arg */
|
||
|
||
/**
|
||
* Добавить (с конца) новый (специальный) параметр.
|
||
*/
|
||
void
|
||
lccrt_function_add_sysarg( lccrt_function_ptr func, int arg_num, lccrt_var_ptr arg)
|
||
{
|
||
int k;
|
||
lccrt_module_ptr m = lccrt_function_get_module( func);
|
||
lccrt_context_ptr ctx = lccrt_module_get_context( m);
|
||
int num_args = lccrt_function_get_num_sysargs( func);
|
||
lccrt_var_ptr *args = lccrt_ctx_mallocn( ctx, lccrt_var_ptr, num_args + 1);
|
||
lccrt_type_ptr ftype = lccrt_function_get_type( func);
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
lccrt_check_type_assert( arg, lccrt_var_t);
|
||
lccrt_assert( (0 <= arg_num) && (arg_num == num_args));
|
||
|
||
memset( args + num_args, 0, sizeof( args[0]));
|
||
memcpy( args, func->sysargs, num_args*sizeof( args[0]));
|
||
lccrt_ctx_free( ctx, func->sysargs);
|
||
func->sysargs = args;
|
||
func->sysargs_num++;
|
||
lccrt_function_set_sysarg( func, arg_num, arg);
|
||
|
||
return;
|
||
} /* lccrt_function_add_sysarg */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
const char *
|
||
lccrt_function_get_asm_name( lccrt_function_ptr func)
|
||
{
|
||
const char *r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = func->asm_name;
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_asm_name */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
const char *
|
||
lccrt_function_get_section( lccrt_function_ptr func)
|
||
{
|
||
const char *r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = func->section;
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_section */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
const char *
|
||
lccrt_function_get_comdat( lccrt_function_ptr func)
|
||
{
|
||
const char *r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = func->comdat;
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_comdat */
|
||
|
||
/**
|
||
* Установить значение поля.
|
||
*/
|
||
lccrt_link_t
|
||
lccrt_function_get_link( lccrt_function_ptr func)
|
||
{
|
||
lccrt_link_t r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = lccrt_link_conv( func->link);
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_link */
|
||
|
||
/**
|
||
* Установить значение поля.
|
||
*/
|
||
void
|
||
lccrt_function_set_link( lccrt_function_ptr func, lccrt_link_t link)
|
||
{
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
func->link = lccrt_link_unpack( link);
|
||
|
||
return;
|
||
} /* lccrt_function_set_link */
|
||
|
||
/**
|
||
* Установить значение поля.
|
||
*/
|
||
void
|
||
lccrt_function_set_section( lccrt_function_ptr func, const char *section)
|
||
{
|
||
lccrt_context_ptr ctx = func->ctx;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
lccrt_assert( !func->section);
|
||
func->section = lccrt_ctx_copy_str( ctx, section);
|
||
|
||
return;
|
||
} /* lccrt_function_set_section */
|
||
|
||
/**
|
||
* Установить значение поля.
|
||
*/
|
||
void
|
||
lccrt_function_set_comdat( lccrt_function_ptr func, const char *comdat)
|
||
{
|
||
lccrt_context_ptr ctx = func->ctx;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
lccrt_assert( !func->comdat);
|
||
func->comdat = lccrt_ctx_copy_str( ctx, comdat);
|
||
|
||
return;
|
||
} /* lccrt_function_set_comdat */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
lccrt_oper_ptr
|
||
lccrt_function_get_first_oper( lccrt_function_ptr func)
|
||
{
|
||
lccrt_oper_ptr r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = func->start;
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_first_oper */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
lccrt_var_ptr
|
||
lccrt_function_get_first_var( lccrt_function_ptr func)
|
||
{
|
||
lccrt_var_ptr r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = func->lvars_head.first;
|
||
lccrt_assert( !r || lccrt_var_is_local( r));
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_first_var */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
lccrt_function_init_type_t
|
||
lccrt_function_get_init_type( lccrt_function_ptr func)
|
||
{
|
||
lccrt_function_init_type_t r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = func->init_type;
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_init_type */
|
||
|
||
/**
|
||
* Установить для функции значение атрибута.
|
||
*/
|
||
void
|
||
lccrt_function_set_init_priority( lccrt_f_ptr f, int value)
|
||
{
|
||
lccrt_check_type_assert( f, lccrt_function_t);
|
||
f->init_priority = value;
|
||
|
||
return;
|
||
} /* lccrt_function_set_init_priority */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
int
|
||
lccrt_function_get_init_priority( lccrt_function_ptr func)
|
||
{
|
||
int r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = func->init_priority;
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_init_priority */
|
||
|
||
/**
|
||
* Установить для функции значение атрибута.
|
||
*/
|
||
void
|
||
lccrt_function_set_init_type( lccrt_f_ptr f, lccrt_function_init_type_t value)
|
||
{
|
||
lccrt_check_type_assert( f, lccrt_function_t);
|
||
f->init_type = value;
|
||
|
||
return;
|
||
} /* lccrt_function_set_init_type */
|
||
|
||
/**
|
||
* Получить поле.
|
||
*/
|
||
lccrt_function_ptr
|
||
lccrt_function_get_next_func( lccrt_function_ptr func)
|
||
{
|
||
lccrt_function_ptr r;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
r = func->funcs_unit.next;
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_next_func */
|
||
|
||
/**
|
||
* Получить для функции значение атрибута.
|
||
*/
|
||
static int
|
||
lccrt_function_get_attr( lccrt_f_ptr f, lccrt_function_attr_name_t attr)
|
||
{
|
||
int r;
|
||
int k = attr / 64;
|
||
int j = attr % 64;
|
||
|
||
r = (f->attrs[k] >> j) & 0x1;
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_attr */
|
||
|
||
/**
|
||
* Установить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_set_attr( lccrt_f_ptr f, lccrt_function_attr_name_t attr, int value)
|
||
{
|
||
int k = attr / 64;
|
||
int j = attr % 64;
|
||
uint64_t bit = 1ULL << j;
|
||
uint64_t value_bit = value ? bit : 0ULL;
|
||
int r = lccrt_function_get_attr( f, attr);
|
||
|
||
f->attrs[k] = (f->attrs[k] & (~bit)) | value_bit;
|
||
|
||
return (r);
|
||
} /* lccrt_function_set_attr */
|
||
|
||
/**
|
||
* Скопировать значение булевых атрибутов.
|
||
*/
|
||
static void
|
||
lccrt_function_copy_attrs( lccrt_f_ptr dst, lccrt_f_ptr src)
|
||
{
|
||
int i;
|
||
|
||
for ( i = 0; i < LCCRT_FUNC_ATTRS_LENGTH; ++i )
|
||
{
|
||
dst->attrs[i] = src->attrs[i];
|
||
}
|
||
|
||
return;
|
||
} /* lccrt_function_copy_attrs */
|
||
|
||
/**
|
||
* Получить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_get_attr_does_not_throw( lccrt_f_ptr f)
|
||
{
|
||
int r = lccrt_function_get_attr( f, LCCRT_FUNC_ATTR_DOES_NOT_THROW);
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_attr_does_not_throw */
|
||
|
||
/**
|
||
* Установить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_set_attr_does_not_throw( lccrt_f_ptr f, int value)
|
||
{
|
||
int r = lccrt_function_set_attr( f, LCCRT_FUNC_ATTR_DOES_NOT_THROW, value);
|
||
|
||
return (r);
|
||
} /* lccrt_function_set_attr_does_not_throw */
|
||
|
||
/**
|
||
* Получить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_get_attr_extern_inline( lccrt_f_ptr f)
|
||
{
|
||
int r = lccrt_function_get_attr( f, LCCRT_FUNC_ATTR_EXTERN_INLINE);
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_attr_extern_inline */
|
||
|
||
/**
|
||
* Установить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_set_attr_extern_inline( lccrt_f_ptr f, int value)
|
||
{
|
||
int r = lccrt_function_set_attr( f, LCCRT_FUNC_ATTR_EXTERN_INLINE, value);
|
||
|
||
return (r);
|
||
} /* lccrt_function_set_attr_extern_inline */
|
||
|
||
/**
|
||
* Получить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_get_attr_used( lccrt_f_ptr f)
|
||
{
|
||
int r = lccrt_function_get_attr( f, LCCRT_FUNC_ATTR_USED);
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_attr_used */
|
||
|
||
/**
|
||
* Установить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_set_attr_used( lccrt_f_ptr f, int value)
|
||
{
|
||
int r = lccrt_function_set_attr( f, LCCRT_FUNC_ATTR_USED, value);
|
||
|
||
return (r);
|
||
} /* lccrt_function_set_attr_used */
|
||
|
||
/**
|
||
* Установить для функции значение поля.
|
||
*/
|
||
int
|
||
lccrt_function_set_declaration( lccrt_f_ptr f, int value)
|
||
{
|
||
int r = lccrt_function_set_attr( f, LCCRT_FUNC_ATTR_DECLARATION, value);
|
||
|
||
return (r);
|
||
} /* lccrt_function_set_declaration */
|
||
|
||
/**
|
||
* Установить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_get_attr_jit_profgen( lccrt_f_ptr f)
|
||
{
|
||
int r = lccrt_function_get_attr( f, LCCRT_FUNC_ATTR_JIT_PROFGEN);
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_attr_jit_profgen */
|
||
|
||
/**
|
||
* Установить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_set_attr_jit_profgen( lccrt_f_ptr f, int value)
|
||
{
|
||
int r = lccrt_function_set_attr( f, LCCRT_FUNC_ATTR_JIT_PROFGEN, value);
|
||
|
||
return (r);
|
||
} /* lccrt_function_set_attr_jit_profgen */
|
||
|
||
/**
|
||
* Получить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_is_declaration( lccrt_f_ptr f)
|
||
{
|
||
int r = lccrt_function_get_attr( f, LCCRT_FUNC_ATTR_DECLARATION);
|
||
|
||
return (r);
|
||
} /* lccrt_function_is_declaration */
|
||
|
||
/**
|
||
* Получить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_is_builtin( lccrt_f_ptr f)
|
||
{
|
||
int r = lccrt_function_get_attr( f, LCCRT_FUNC_ATTR_BUILTIN);
|
||
|
||
return (r);
|
||
} /* lccrt_function_is_builtin */
|
||
|
||
/**
|
||
* Получить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_is_used( lccrt_f_ptr f)
|
||
{
|
||
int r = lccrt_function_get_attr( f, LCCRT_FUNC_ATTR_USED);
|
||
|
||
return (r);
|
||
} /* lccrt_function_is_used */
|
||
|
||
/**
|
||
* Получить для функции значение атрибута.
|
||
*/
|
||
int
|
||
lccrt_function_is_profgen( lccrt_f_ptr f)
|
||
{
|
||
int r = lccrt_function_get_attr( f, LCCRT_FUNC_ATTR_JIT_PROFGEN);
|
||
|
||
return (r);
|
||
} /* lccrt_function_is_profgen */
|
||
|
||
/**
|
||
* Формирование нового имени для локальной переменной.
|
||
*/
|
||
char *
|
||
lccrt_function_name_new_local( lccrt_f_ptr func, const char *name)
|
||
{
|
||
char *result = 0;
|
||
lccrt_context_ptr ctx = func->ctx;
|
||
|
||
lccrt_check_type_assert( func, lccrt_function_t);
|
||
if ( name )
|
||
{
|
||
result = lccrt_ctx_copy_str( ctx, name);
|
||
} else
|
||
{
|
||
char str[1024];
|
||
|
||
snprintf( str, 1024, "__lccrt_l%d", func->local_name_id);
|
||
func->local_name_id++;
|
||
result = lccrt_ctx_copy_str( ctx, str);
|
||
}
|
||
|
||
return (result);
|
||
} /* lccrt_function_name_new_local */
|
||
|
||
/**
|
||
* Подготовка данных.
|
||
*/
|
||
static void
|
||
lccrt_function_copy_info_init( lccrt_function_copy_info_t *fci, lccrt_function_copy_type_t type,
|
||
lccrt_f_ptr src_func, lccrt_f_ptr dst_func, lccrt_hash_ptr types,
|
||
lccrt_o_ptr call)
|
||
{
|
||
memset( fci, 0, sizeof( fci[0]));
|
||
fci->type = type;
|
||
fci->src_func = src_func;
|
||
fci->dst_func = dst_func;
|
||
fci->vars = lccrt_hash_new( src_func->ctx, LCCRT_HASH_KEY_INTPTR);
|
||
fci->opers = lccrt_hash_new( src_func->ctx, LCCRT_HASH_KEY_INTPTR);
|
||
fci->types = types;
|
||
fci->call = call;
|
||
|
||
return;
|
||
} /* lccrt_function_copy_info_init */
|
||
|
||
/**
|
||
* Освобождение данных.
|
||
*/
|
||
static void
|
||
lccrt_function_copy_info_done( lccrt_function_copy_info_t *fci)
|
||
{
|
||
lccrt_hash_delete( fci->opers);
|
||
lccrt_hash_delete( fci->vars);
|
||
|
||
return;
|
||
} /* lccrt_function_copy_info_done */
|
||
|
||
/**
|
||
* Создание копии локальной переменной в новой функции.
|
||
*/
|
||
lccrt_var_ptr
|
||
lccrt_function_var_import( lccrt_f_ptr dst_func, lccrt_f_ptr src_func, lccrt_v_ptr v,
|
||
lccrt_h_ptr vars, lccrt_hash_ptr types, int is_same_name)
|
||
{
|
||
lccrt_he_ptr e;
|
||
lccrt_var_ptr r = 0;
|
||
lccrt_type_ptr type = 0;
|
||
lccrt_link_t ln = lccrt_link_conv( v->link);
|
||
|
||
e = vars ? lccrt_hash_find( vars, (uintptr_t)v) : 0;
|
||
r = e ? (lccrt_var_ptr)lccrt_hash_get( e) : 0;
|
||
if ( !r )
|
||
{
|
||
const char *new_name = is_same_name ? v->name : 0;
|
||
|
||
type = lccrt_type_import( lccrt_function_get_module( dst_func), v->type, types);
|
||
//r = lccrt_var_new( dst_func, v->loc, type, v->name, v->asm_name, ln, v->align);
|
||
r = lccrt_var_new( dst_func, v->loc, type, new_name, v->asm_name, ln, v->align);
|
||
r->arg_num = v->arg_num;
|
||
lccrt_var_copy_attrs( r, v);
|
||
lccrt_assert( !v->init_value);
|
||
|
||
if ( v->loc == LCCRT_VAR_LOC_ARG )
|
||
{
|
||
lccrt_function_set_arg( dst_func, v->arg_num, r);
|
||
|
||
} else if ( v->loc == LCCRT_VAR_LOC_SYSARG )
|
||
{
|
||
lccrt_function_set_sysarg( dst_func, v->arg_num, r);
|
||
|
||
} else if ( (v->loc == LCCRT_VAR_LOC_LOCAL)
|
||
|| (v->loc == LCCRT_VAR_LOC_ASM) )
|
||
{
|
||
} else
|
||
{
|
||
lccrt_assert( 0);
|
||
}
|
||
|
||
if ( vars )
|
||
{
|
||
e = lccrt_hash_push( vars, (uintptr_t)v, 0);
|
||
lccrt_hash_set( e, (uintptr_t)r);
|
||
}
|
||
}
|
||
|
||
return (r);
|
||
} /* lccrt_function_var_import */
|
||
|
||
/**
|
||
* Создание копии операции из другой функции (при копировании функции).
|
||
*/
|
||
static lccrt_oper_ptr
|
||
lccrt_function_oper_import( lccrt_function_copy_info_t *fci, lccrt_o_ptr op, lccrt_oi_ptr it)
|
||
{
|
||
int k;
|
||
lccrt_he_ptr e;
|
||
lccrt_oper_ptr r = 0;
|
||
lccrt_var_ptr res = 0;
|
||
lccrt_function_ptr dst_func = fci->dst_func;
|
||
lccrt_module_ptr dst_m = lccrt_function_get_module( dst_func);
|
||
lccrt_context_ptr dst_ctx = lccrt_module_get_context( dst_m);
|
||
|
||
if ( op->res )
|
||
{
|
||
if ( lccrt_var_is_global( op->res) )
|
||
{
|
||
res = op->res;
|
||
} else
|
||
{
|
||
e = lccrt_hash_find( fci->vars, (uintptr_t)op->res);
|
||
res = e ? (lccrt_var_ptr)lccrt_hash_get( e) : 0;
|
||
lccrt_assert( res);
|
||
}
|
||
}
|
||
|
||
r = lccrt_oper_new( fci->dst_func, op->name, 0, op->num_args, op->args,
|
||
op->num_sysargs, res, it);
|
||
r->ident_num = op->ident_num;
|
||
r->is_volatile = op->is_volatile;
|
||
r->is_atomic = op->is_atomic;
|
||
|
||
for ( k = 0; k < r->num_args; ++k )
|
||
{
|
||
if ( lccrt_oper_name_is_arg_var( r->name, k) )
|
||
{
|
||
lccrt_var_ptr v = op->args[k].v;
|
||
|
||
if ( lccrt_var_is_global( v) )
|
||
{
|
||
if ( (fci->type == LCCRT_FCT_INLINE)
|
||
&& lccrt_oper_is_label( r) )
|
||
{
|
||
char *new_name = lccrt_function_name_new_local( fci->dst_func, 0);
|
||
int new_len = strlen( new_name);
|
||
|
||
r->args[k].v = lccrt_var_new_constarg_str( dst_m, new_len + 1, new_name);
|
||
lccrt_ctx_free( dst_ctx, new_name);
|
||
} else
|
||
{
|
||
r->args[k].v = v;
|
||
}
|
||
} else
|
||
{
|
||
e = lccrt_hash_find( fci->vars, (uintptr_t)v);
|
||
r->args[k].v = e ? (lccrt_var_ptr)lccrt_hash_get( e) : 0;
|
||
lccrt_assert( !v || r->args[k].v);
|
||
}
|
||
} else
|
||
{
|
||
e = lccrt_hash_find( fci->opers, (uintptr_t)op->args[k].op);
|
||
r->args[k].op = e ? (lccrt_oper_ptr)lccrt_hash_get( e) : 0;
|
||
lccrt_assert( !op->args[k].op || r->args[k].op);
|
||
}
|
||
}
|
||
|
||
e = lccrt_hash_push( fci->opers, (uintptr_t)op, 0);
|
||
lccrt_hash_set( e, (uintptr_t)r);
|
||
|
||
return (r);
|
||
} /* lccrt_function_oper_import */
|
||
|
||
/**
|
||
* Удаление кода функции (локальных переменных и операций).
|
||
*/
|
||
void
|
||
lccrt_function_clear( lccrt_function_ptr f)
|
||
{
|
||
lccrt_he_ptr e;
|
||
lccrt_oper_ptr o, o_next;
|
||
|
||
/* Удаляем промежуточное представление функции. */
|
||
for ( o = f->start; o; o = o_next )
|
||
{
|
||
o_next = o->next;
|
||
o->next = 0;
|
||
if ( o_next )
|
||
{
|
||
o_next->prev = 0;
|
||
}
|
||
|
||
lccrt_oper_delete( o);
|
||
}
|
||
|
||
for ( e = lccrt_hash_first( f->lvars); e; e = lccrt_hash_first( f->lvars) )
|
||
{
|
||
lccrt_var_ptr v = (lccrt_var_ptr)lccrt_hash_get( e);
|
||
|
||
if ( (v->loc != LCCRT_VAR_LOC_ARG)
|
||
&& (v->loc != LCCRT_VAR_LOC_SYSARG) )
|
||
{
|
||
lccrt_var_delete( v);
|
||
}
|
||
|
||
lccrt_hash_remove( e);
|
||
}
|
||
|
||
lccrt_oper_iterator_set( &(f->cur), 0);
|
||
f->start = 0;
|
||
|
||
return;
|
||
} /* lccrt_function_clear */
|
||
|
||
/**
|
||
* Копирование содержимого одной функции в другую.
|
||
*/
|
||
static lccrt_oper_ptr
|
||
lccrt_function_copy_driver_run( lccrt_function_copy_info_t *fci)
|
||
{
|
||
lccrt_oper_ptr op, new_op;
|
||
lccrt_he_ptr e;
|
||
lccrt_oper_ptr r = 0;
|
||
lccrt_oper_ptr l_after = 0;
|
||
lccrt_oper_ptr l_start = 0;
|
||
lccrt_var_ptr rvar = 0;
|
||
lccrt_var_ptr v = 0;
|
||
lccrt_var_ptr w = 0;
|
||
lccrt_function_ptr dst = fci->dst_func;
|
||
lccrt_function_ptr src = fci->src_func;
|
||
lccrt_oper_iterator_ptr oi = lccrt_oper_iterator_new( dst->ctx);
|
||
|
||
if ( (fci->type == LCCRT_FCT_INLINE) )
|
||
{
|
||
int i;
|
||
int num_args = lccrt_oper_get_num_args( fci->call);
|
||
|
||
/* Создаем метку для замены возвратов из функции на операции передачи
|
||
управления. */
|
||
lccrt_oper_iterator_set( oi, fci->call);
|
||
l_after = lccrt_oper_new_label( dst, 0, oi);
|
||
r = l_after;
|
||
|
||
/* Создаем переменную для возврата результата из функции. */
|
||
if ( lccrt_oper_name_is_res( lccrt_oper_get_name( fci->call)) )
|
||
{
|
||
rvar = lccrt_var_new_local( dst, lccrt_oper_get_res_type( fci->call), 0);
|
||
}
|
||
|
||
/* Создаем переменные для передачи аргументов в функцию. */
|
||
lccrt_oper_iterator_set_prev( oi, fci->call);
|
||
for ( i = 1; i < num_args; ++i )
|
||
{
|
||
new_op = lccrt_oper_new_move( dst, lccrt_oper_get_arg_var( fci->call, i), 0, oi);
|
||
w = lccrt_oper_get_res( new_op);
|
||
v = lccrt_function_get_arg( src, i - 1);
|
||
lccrt_assert( lccrt_var_get_type( v) == lccrt_var_get_type( w));
|
||
e = lccrt_hash_push( fci->vars, (uintptr_t)v, 0);
|
||
lccrt_hash_set( e, (uintptr_t)w);
|
||
}
|
||
|
||
lccrt_oper_iterator_set_prev( oi, fci->call);
|
||
} else
|
||
{
|
||
lccrt_oper_iterator_set( oi, dst->start);
|
||
}
|
||
|
||
/* Копируем локальные переменные. */
|
||
for ( e = lccrt_hash_first( src->lvars); e; e = lccrt_hash_next( e) )
|
||
{
|
||
lccrt_function_var_import( fci->dst_func, fci->src_func, (lccrt_var_ptr)lccrt_hash_get( e),
|
||
fci->vars, fci->types, fci->type == LCCRT_FCT_COPY);
|
||
}
|
||
|
||
/* Копируем исходный код. */
|
||
for ( op = src->start; op; op = op->next )
|
||
{
|
||
/* Сначала копируем только метки. */
|
||
if ( (op->name == LCCRT_OPER_LABEL) )
|
||
{
|
||
lccrt_oper_ptr new_lbl = lccrt_function_oper_import( fci, op, oi);
|
||
|
||
if ( (op == src->start) )
|
||
{
|
||
lccrt_assert( !l_start);
|
||
l_start = new_lbl;
|
||
}
|
||
}
|
||
}
|
||
|
||
lccrt_oper_iterator_set( oi, dst->start);
|
||
|
||
/* Копируем исходный код. */
|
||
for ( op = src->start; op; op = op->next )
|
||
{
|
||
if ( lccrt_oper_is_label( op) )
|
||
{
|
||
/* Устанавливаем итератор после копии метки. */
|
||
e = lccrt_hash_find( fci->opers, (uintptr_t)op);
|
||
new_op = e ? (lccrt_oper_ptr)lccrt_hash_get( e) : 0;
|
||
lccrt_oper_iterator_set( oi, new_op);
|
||
|
||
} else if ( (fci->type == LCCRT_FCT_INLINE)
|
||
&& (lccrt_oper_is_ret( op)
|
||
|| lccrt_oper_is_retval( op)) )
|
||
{
|
||
if ( lccrt_oper_is_retval( op) )
|
||
{
|
||
/* Сохраняем результат функции в переменную возврата. */
|
||
v = lccrt_oper_get_arg_var( op, 0);
|
||
w = lccrt_function_var_import( dst, src, v, fci->vars, fci->types, 0);
|
||
new_op = lccrt_oper_new_move( dst, w, rvar, oi);
|
||
e = lccrt_hash_push( fci->opers, (uintptr_t)op, 0);
|
||
lccrt_hash_set( e, (uintptr_t)new_op);
|
||
}
|
||
|
||
/* Заменяем операцию возврата на операцию перехода. */
|
||
new_op = lccrt_oper_new_branch( dst, l_after, oi);
|
||
e = lccrt_hash_push( fci->opers, (uintptr_t)op, 0);
|
||
lccrt_hash_set( e, (uintptr_t)new_op);
|
||
} else
|
||
{
|
||
/* Копируем операцию. */
|
||
lccrt_function_oper_import( fci, op, oi);
|
||
}
|
||
}
|
||
|
||
if ( (fci->type == LCCRT_FCT_INLINE) )
|
||
{
|
||
lccrt_oper_iterator_set_prev( oi, l_start);
|
||
lccrt_oper_new_branch( dst, l_start, oi);
|
||
if ( lccrt_oper_name_is_res( lccrt_oper_get_name( fci->call)) )
|
||
{
|
||
lccrt_oper_iterator_set( oi, l_after);
|
||
lccrt_oper_new_move( dst, rvar, lccrt_oper_get_res( fci->call), oi);
|
||
}
|
||
|
||
lccrt_oper_delete( fci->call);
|
||
fci->call = 0;
|
||
}
|
||
|
||
lccrt_oper_iterator_delete( oi);
|
||
|
||
return (r);
|
||
} /* lccrt_function_copy_driver_run */
|
||
|
||
/**
|
||
* Создание копии функции.
|
||
*/
|
||
lccrt_function_ptr
|
||
lccrt_function_copy( lccrt_m_ptr m, lccrt_f_ptr f, const char *name, const char *asm_name,
|
||
lccrt_link_t ln, lccrt_hash_ptr types)
|
||
{
|
||
lccrt_function_ptr r;
|
||
|
||
m = m ? m : lccrt_function_get_module( f);
|
||
r = lccrt_function_new( m, f->sig_type, name, asm_name, ln,
|
||
lccrt_function_is_declaration( f),
|
||
lccrt_function_is_builtin( f));
|
||
|
||
lccrt_function_set_section( r, f->section);
|
||
lccrt_function_set_comdat( r, f->comdat);
|
||
lccrt_function_set_init_type( r, f->init_type);
|
||
lccrt_function_copy_attrs( r, f);
|
||
|
||
if ( !lccrt_function_is_declaration( r) )
|
||
{
|
||
lccrt_function_copy_info_t fci;
|
||
|
||
lccrt_function_copy_info_init( &fci, LCCRT_FCT_COPY, f, r, types, 0);
|
||
lccrt_function_copy_driver_run( &fci);
|
||
lccrt_function_copy_info_done( &fci);
|
||
}
|
||
|
||
r->opers_num = f->opers_num;
|
||
r->lvars_num = f->lvars_num;
|
||
r->local_name_id = f->local_name_id;
|
||
|
||
return (r);
|
||
} /* lccrt_function_copy */
|
||
|
||
/**
|
||
* Подстановка вызова функции.
|
||
*/
|
||
lccrt_oper_ptr
|
||
lccrt_function_call_inline( lccrt_o_ptr call, lccrt_f_ptr call_func)
|
||
{
|
||
lccrt_oper_ptr r;
|
||
lccrt_function_copy_info_t fci;
|
||
lccrt_function_ptr dst_func = lccrt_oper_get_function( call);
|
||
|
||
lccrt_function_copy_info_init( &fci, LCCRT_FCT_INLINE, call_func, dst_func, 0, call);
|
||
r = lccrt_function_copy_driver_run( &fci);
|
||
lccrt_function_copy_info_done( &fci);
|
||
|
||
return (r);
|
||
} /* lccrt_function_call_inline */
|
||
|
||
/**
|
||
* Добавить в функцию новые мета-данные, либо изменить значение старых.
|
||
*/
|
||
void
|
||
lccrt_function_set_einfo( lccrt_function_ptr f, lccrt_einfo_category_t ecat, lccrt_eir_t value)
|
||
{
|
||
lccrt_module_ptr m = lccrt_function_get_module( f);
|
||
|
||
lccrt_check_type_assert( f, lccrt_function_t);
|
||
lccrt_assert( !lccrt_einfo_is_scalar( value));
|
||
f->einfo = lccrt_einfo_link_push_value( m, f->einfo, ecat, value);
|
||
|
||
return;
|
||
} /* lccrt_function_set_einfo */
|
||
|
||
/**
|
||
* Получить значение мета-данных с заданным именем или 0, если таких данных нет.
|
||
*/
|
||
lccrt_einfo_reference_t
|
||
lccrt_function_get_einfo( lccrt_function_ptr f, lccrt_einfo_category_t ecat)
|
||
{
|
||
lccrt_einfo_link_ptr unit = lccrt_einfo_link_find( f->einfo, ecat);
|
||
lccrt_einfo_reference_t r = lccrt_einfo_link_get_value( unit);
|
||
|
||
lccrt_check_type_assert( f, lccrt_function_t);
|
||
|
||
return (r);
|
||
} /* lccrt_function_get_einfo */
|