mirror of
https://gitflic.ru/project/e2khome/lccrt.git
synced 2024-11-23 10:19:32 +01:00
ecomp.r29.144265
: liblccopt: ecomp.r29.143691 - ecomp.r29.144265
This commit is contained in:
parent
b6d9981214
commit
84378aa8a0
356
docs/einfo.rst
Normal file
356
docs/einfo.rst
Normal file
@ -0,0 +1,356 @@
|
||||
======================================================================
|
||||
Дополнительные данные (Extended INFOrmation) в представлении lccrt-IR.
|
||||
======================================================================
|
||||
|
||||
Основные (пользовательские) типы данных в библиотеке liblccrt.
|
||||
--------------------------------------------------------------
|
||||
|
||||
* Тип **lccrt_einfo_category_t** (**lccrt_eic_t**) - идентификатор категории.
|
||||
|
||||
Категория - это любое строковое название, зарегистрированное в модуле (в качестве
|
||||
категории). Основное назначение - привязка дополнительных данных к элементу
|
||||
промежуточного представления, то есть к *модулю*, *глобалу*, *функции* и
|
||||
*операции*. Например, можно использовать название *"profile"* для назначения
|
||||
*операциям* профильных данных.
|
||||
|
||||
После регистрации категории с новым названием возвращается ее идентификатор. С помощью
|
||||
идентификатора можно назначить или прочитать ссылку на элемент дополнительных данных (ЭДД).
|
||||
При этом дополнительные данные сами по себе технически не связаны с категориями.
|
||||
С технической точки зрения категории используются только для установки/чтения ссылок.
|
||||
|
||||
Одновременно элементу промежуточного представления (*модуль*/*глобал*/*функция*/*операция*)
|
||||
могут проставляться ссылки для разных категорий, но для каждой категории назначается ровно
|
||||
одна ссылка. При установке новой ссылки старое значение ссылки на дополнительные данные
|
||||
затирается. Поскольку ссылка может указывать на структуру дополнительных данных, то в рамках
|
||||
одной категории для элемента промежуточного представления возможно тем самым указание
|
||||
произвольного набора данных.
|
||||
|
||||
После регистрации для любой категории ее идентификатор можно также узнать (найти) по
|
||||
исходному строковому названию. В целом использование идентификаторов вместо исходных
|
||||
строковых названий связано с заменой сравнения строк на сравнение целочисленных значений,
|
||||
то есть с оптимизацией операций сравнения в процессе обхода ссылок на дополнительные
|
||||
данные.
|
||||
|
||||
Интерфейсы:
|
||||
::
|
||||
|
||||
extern lccrt_eic_t lccrt_module_new_einfo_category( lccrt_m_ptr m, const char *name);
|
||||
extern lccrt_eic_t lccrt_module_find_einfo_category( lccrt_m_ptr m, const char *name);
|
||||
extern lccrt_eir_t lccrt_module_get_einfo( lccrt_m_ptr m, lccrt_eic_t eic);
|
||||
extern void lccrt_module_set_einfo( lccrt_m_ptr m, lccrt_eic_t eic, lccrt_eir_t value);
|
||||
extern lccrt_eir_t lccrt_var_get_einfo( lccrt_v_ptr v, lccrt_eic_t eic);
|
||||
extern void lccrt_var_set_einfo( lccrt_v_ptr v, lccrt_eic_t eic, lccrt_eir_t value);
|
||||
extern lccrt_eir_t lccrt_function_get_einfo( lccrt_f_ptr func, lccrt_eic_t eic);
|
||||
extern void lccrt_function_set_einfo( lccrt_f_ptr func, lccrt_eic_t eic, lccrt_eir_t value);
|
||||
extern lccrt_eir_t lccrt_oper_get_einfo( lccrt_o_ptr oper, lccrt_eic_t eic);
|
||||
extern void lccrt_oper_set_einfo( lccrt_o_ptr oper, lccrt_eic_t eic, lccrt_eir_t value);
|
||||
|
||||
* Тип **lccrt_einfo_reference_t** (**lccrt_eir_t**) - дескриптор элемента дополнительных данных.
|
||||
|
||||
При создании элемента дополнительных данных (ЭДД) возвращается дескриптор. В дескрипторе
|
||||
хранится тип данных, а также собственно значение (для простых типов), либо ссылка на значение
|
||||
(для агрегатных типов). Дескриптор элемента дополнительных данных может затем использоваться
|
||||
многократно, в частности, при простановке ссылок на ЭДД в рамках различных (!) категорий для
|
||||
элементов промежуточного представления. Также дескрипторы могут быть значениями в массивах и
|
||||
структурах (см. ниже).
|
||||
|
||||
Типы значений в дескрипторе:
|
||||
|
||||
* **EMPTY** - значение дескриптора не устанавливалось
|
||||
|
||||
* **INT64** - целочисленное значение (*хранится напрямую в дескрипторе*)
|
||||
|
||||
* **RAW** - байтовый массив фиксированной длины (*ссылка*)
|
||||
|
||||
* **ARRAY** - массив дескрипторов (*ссылка*)
|
||||
|
||||
* **STRUCT** - структура именнованных полей со значениями-дескрипторами (*ссылка*)
|
||||
|
||||
Байтовый RAW-массив создается с фиксированной длиной и сразу с инциализацией. Основное
|
||||
назначение RAW-массива - это хранение строк.
|
||||
|
||||
ARRAY-массив дескрипторов создается как массив с начальной длиной. При этом возможно
|
||||
добавление новых элементов в конец массива, с увеличением длины массива. При
|
||||
необходимости размер фактически выделенной памяти автоматически увеличивается.
|
||||
Уменьшение размера массива не предусмотрено. Также при создании ARRAY-массива необходимо
|
||||
указать описание типа элемента (**lccrt_einfo_tydescr_ptr**).
|
||||
|
||||
Про данные типа STRUCT описание приводится ниже (см. **lccrt_einfo_tydescr_ptr**).
|
||||
|
||||
Поскольку ARRAY-массивы и STRUCT-данные могут хранить дескрипторы дополнительных данных,
|
||||
то возможно построение графа дополнительных данных. Чтобы дополнительные данные были
|
||||
доступны при последующих обходах, должен иметься путь в графе данных, начинающийся с
|
||||
элемента промежуточного представления. Ссылка на данные в элементе промежуточного
|
||||
представления доступна через категорию. Тем самым дополнительные данные стоит создавать
|
||||
и рассматривать как независимые графы, с логической точки зрения разбитые на категории.
|
||||
Например, профильные данные, отладочные данные, результаты анализов и т.д.
|
||||
|
||||
Интерфейсы:
|
||||
::
|
||||
|
||||
extern lccrt_eir_t lccrt_einfo_new_empty();
|
||||
extern lccrt_eir_t lccrt_einfo_new_i64( uint64_t value);
|
||||
extern lccrt_eir_t lccrt_einfo_new_raw( lccrt_m_ptr m, int length, const uint8_t *data);
|
||||
extern lccrt_eir_t lccrt_einfo_new_raw_by_string( lccrt_m_ptr m, const char *data);
|
||||
extern lccrt_eir_t lccrt_einfo_new_struct( lccrt_eitd_ptr eitd);
|
||||
extern lccrt_eir_t lccrt_einfo_new_array( lccrt_eitd_ptr eitd, int alloc_elems);
|
||||
extern int lccrt_einfo_is_empty( lccrt_eir_t einfo);
|
||||
extern int lccrt_einfo_is_valued( lccrt_eir_t einfo);
|
||||
extern uint64_t lccrt_einfo_get_i64( lccrt_eir_t einfo);
|
||||
extern uint8_t * lccrt_einfo_get_raw_data( lccrt_eir_t einfo);
|
||||
extern lccrt_eir_t lccrt_einfo_get_elem( lccrt_eir_t einfo, int elem_ident);
|
||||
extern lccrt_eir_t lccrt_einfo_get_field( lccrt_eir_t einfo, lccrt_eifi_t fid);
|
||||
extern void lccrt_einfo_set_elem( lccrt_eir_t einfo, int elem_ident, lccrt_eir_t value);
|
||||
extern void lccrt_einfo_set_field( lccrt_eir_t einfo, lccrt_eifi_t fid, lccrt_eir_t value);
|
||||
extern void lccrt_einfo_push_elem( lccrt_eir_t einfo, lccrt_eir_t value);
|
||||
extern int lccrt_einfo_get_num_args( lccrt_eir_t einfo);
|
||||
extern int lccrt_einfo_get_raw_length( lccrt_eir_t einfo);
|
||||
extern int lccrt_einfo_get_array_length( lccrt_eir_t einfo);
|
||||
|
||||
* Типы **lccrt_einfo_tydescr_ptr** (**lccrt_eitd_ptr**) - описание типа дополнительных данных, **lccrt_einfo_field_id_t** (**lccrt_eifi_t**) - индекс поля в STRUCT-значении.
|
||||
|
||||
Описание типа данных можно сравнить с оператором typedef в языке Си. Имеются два тривиальных
|
||||
описания типов данных - это описания для INT64 и RAW. Данные тривиальные описания
|
||||
используются как базовые элементы при создании описаний массивов и структур. При создании
|
||||
описания массива нужно указать (произвольное) описание типа данных элементов массива.
|
||||
|
||||
Интерфейсы:
|
||||
|
||||
::
|
||||
|
||||
extern lccrt_einfo_tydescr_ptr lccrt_einfo_get_tydescr( lccrt_eir_t einfo);
|
||||
extern int lccrt_einfo_is_tydescr_i64( lccrt_einfo_tydescr_ptr eitd);
|
||||
extern int lccrt_einfo_is_tydescr_raw( lccrt_einfo_tydescr_ptr eitd);
|
||||
extern lccrt_eitd_ptr lccrt_einfo_make_tydescr_i64( lccrt_m_ptr m);
|
||||
extern lccrt_eitd_ptr lccrt_einfo_make_tydescr_raw( lccrt_m_ptr m);
|
||||
extern lccrt_eitd_ptr lccrt_einfo_make_tydescr_array( lccrt_m_ptr m, lccrt_eitd_ptr elem_type);
|
||||
|
||||
Если тривиальные описания и описание массивов не имеют тега-названия, то при создании
|
||||
описаний структур необходимо указывать уникальный (в пределах модуля) тег-название.
|
||||
Предлагается в качестве префикса в теге-названии использовать название логической
|
||||
категории, в рамках которой планируется создавать дополнительные данные. Также при создании
|
||||
описания структуры необходимо указать количество полей, строковые названия полей
|
||||
внутри структуры и описания типов для каждого из полей.
|
||||
|
||||
Интерфейсы:
|
||||
|
||||
::
|
||||
|
||||
extern lccrt_eitd_ptr lccrt_einfo_make_tydescr_struct( lccrt_m_ptr m, const char *name, int num_flds, const char **flds_names, lccrt_eitd_ptr *flds_types);
|
||||
|
||||
Для описания структуры по названию поля можно получить индекс поля (**lccrt_einfo_field_id_t**).
|
||||
Индекс поля содержит в себе ссылку на описание структуры, а также данные для доступа к полю.
|
||||
При создании ЭДД с типом **STRUCT** необходимо указать описание структуры. Соответственно чтение
|
||||
и запись поля в таком элементе дополнительных данных возможно только через индекс поля.
|
||||
Основное назначение индексов полей - обеспечить более быстрый доступ к полям по сравнению с
|
||||
возможным доступом через строковые названия, а также обеспечить контроль типов.
|
||||
|
||||
Интерфейсы:
|
||||
::
|
||||
|
||||
extern lccrt_eifi_t lccrt_einfo_find_tydescr_field( lccrt_einfo_tydescr_ptr eitd, const char *fld_name);
|
||||
extern lccrt_eir_t lccrt_einfo_get_field( lccrt_eir_t einfo, lccrt_eifi_t fid);
|
||||
extern void lccrt_einfo_set_field( lccrt_eir_t einfo, lccrt_eifi_t fid, lccrt_eir_t value);
|
||||
|
||||
Общие свойства дополнительных данных.
|
||||
-------------------------------------
|
||||
|
||||
В общем и целом для дополнительных данных использовался подход, приближенный к подходу
|
||||
со строгой типизацией данных. Как следствие при практическом использовании текущей
|
||||
реализации работа с дополнительными данными может требовать ряда рутинных действий. Создание
|
||||
описание типа, поиск и сохранение идентификаторов категорий, формирование и сохранение
|
||||
индексов полей в структурах.
|
||||
|
||||
При реализации механизма дополнительных данных главным образом решалась задача трансляции
|
||||
метаданных из llvm-подобного представления в расширенную информацию выходного представления.
|
||||
Другими словами в основном решалась транзитная задача. Модификация дополнительных данных
|
||||
возможна, но в текущей реализации отсутствует механизм удаления замещаемых данных. Все
|
||||
дополнительные данные будут удалены только вместе с удалением модуля. Поэтому изменения
|
||||
дополнительных данных возможно, но необходимо учитывать потребление памяти замещенными
|
||||
данными. Наиболее простое решение в текущей реализации - это разработка прохода, который
|
||||
пометит все достижимые дополнительные данные и автоматически удалит все недостижимые
|
||||
дополнительные данные.
|
||||
|
||||
Дополнительные данные сохраняются/читаются в текстовом формате вместе с основными данными
|
||||
модуля промежуточного представления *lccrt-IR*.
|
||||
|
||||
Примеры использования.
|
||||
----------------------
|
||||
|
||||
* Рассмотрим пример использования дополнительных данных для транслятора *llvm-IR -> EIR*, использующем промежуточное представление *lccrt-IR* в качестве транзитного представления.
|
||||
|
||||
В представлении *llvm-IR* для функции может быть указан набор атрибутов.
|
||||
::
|
||||
|
||||
define dso_local i32 @main() local_unnamed_addr #0 {
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
attributes #0 = {
|
||||
mustprogress nofree norecurse nosync nounwind readnone willreturn
|
||||
"frame-pointer"="all" "min-legal-vector-width"="0" "no-trapping-math"="true"
|
||||
"stack-protector-buffer-size"="8" "target-cpu"="elbrus-v2"
|
||||
}
|
||||
|
||||
* Транслятор преобразует набор атрибутов в дополнительные данные, для чего предварительно создаются категория и описания типов.
|
||||
::
|
||||
|
||||
// Создание категории "func_attrs" для привязки к функциям набора атрибутов.
|
||||
ecat_func_attrs = lccrt_module_new_einfo_category( m, "func_attrs");
|
||||
|
||||
В том числе, создается описание структурного типа с тег-названием *"func_attrs.value"*.
|
||||
Элементы дополнительных данных с данным структурным типом будут хранить значения атрибутов,
|
||||
поэтому в качестве префикса в тег-названии использовалось значение *"func_attrs.\*"*
|
||||
::
|
||||
|
||||
const char *fa_names[2] = {"src", "value"};
|
||||
lccrt_eitd_ptr fa_types[2] = {};
|
||||
|
||||
// Создание тривиальных описаний типов.
|
||||
etyde_i64 = lccrt_einfo_make_tydescr_i64( m);
|
||||
etyde_raw = lccrt_einfo_make_tydescr_raw( m);
|
||||
|
||||
// Структурный тип "func_attrs.value" состоит из двух raw-полей:
|
||||
// src - строка с информацией об источнике атрибута (в данном случае llvm-13)
|
||||
// value - строка с названием и значением атрибута
|
||||
fa_types[0] = etyde_raw;
|
||||
fa_types[1] = etyde_raw;
|
||||
etyde_func_attr = lccrt_einfo_make_tydescr_struct( m, "func_attrs.value", 2, fa_names, fa_types);
|
||||
eifi_fattr_src = lccrt_einfo_find_tydescr_field( etyde_func_attr, "src");
|
||||
eifi_fattr_val = lccrt_einfo_find_tydescr_field( etyde_func_attr, "value");
|
||||
|
||||
Для привязки к функции набора атрибутов используются ЭДД с типом **ARRAY**, где элементами
|
||||
массива являются структуры *"func_attrs.value"*. Такой ЭДД позволяет функции назначить сразу набор
|
||||
(список) атрибутов.
|
||||
::
|
||||
|
||||
etyde_func_attrs = lccrt_einfo_make_tydescr_array( m, etyde_func_attr);
|
||||
|
||||
Также создается **RAW** данные со строкой "llvm-13" для повторного использования в качестве
|
||||
значения поля *".src"* в структуре *"func_attrs.value"*.
|
||||
::
|
||||
|
||||
eref_raw_llvm13 = lccrt_einfo_new_raw_by_string( m, "llvm-13");
|
||||
|
||||
* Затем для каждой функции из *llvm-IR* выполняется трансляция *llvm-атрибутов* в *lccrt-IR* формат дополнительных данных.
|
||||
|
||||
Сначала создается массив (список) известной длины.
|
||||
::
|
||||
|
||||
lccrt_eir_t attrs = lccrt_einfo_new_array( etyde_func_attrs, arr_len);
|
||||
|
||||
Затем для каждого атрибута текущей функции создается структура "func_attrs.value".
|
||||
::
|
||||
|
||||
attr = lccrt_einfo_new_struct( etyde_func_attr);
|
||||
|
||||
Для обоих полей *".src"* и *".value"* формируются и устанавливаются значения.
|
||||
::
|
||||
|
||||
v0 = eref_raw_llvm13;
|
||||
v1 = lccrt_einfo_new_raw_by_string( m, it.getAsString( true).c_str());
|
||||
lccrt_einfo_set_field( attr, eifi_fattr_src, v0);
|
||||
lccrt_einfo_set_field( attr, eifi_fattr_val, v1);
|
||||
|
||||
После чего *k*-ый атрибут записывается в массив атрибутов.
|
||||
::
|
||||
|
||||
lccrt_einfo_set_elem( attrs, k, attr);
|
||||
|
||||
В завершении для функции устанавливается ссылка на список атрибутов в категории *"func_attrs"*.
|
||||
Поскольку для функций наборы атрибутов могут целиком повторяться, то в трансляторе выполняется
|
||||
хеширование для повторного переиспользования (*fai->second*), но для краткости операция
|
||||
хеширование не приводится.
|
||||
::
|
||||
|
||||
// Устанавливаем для функции набор атрибутов.
|
||||
lccrt_function_set_einfo( f, ecat_func_attrs, fai->second);
|
||||
//lccrt_function_set_einfo( f, ecat_func_attrs, attrs);
|
||||
|
||||
* После передачи представления модуля выполняется создание целевого промежуточного представления и в данном случае - это представление *EIR*.
|
||||
|
||||
При создании модуля в терминах представления EIR выполняется в том числе обход элементов
|
||||
дополнительных данных. В начале выполняется поиск в модуле категории *"func_attrs"*.
|
||||
::
|
||||
|
||||
lccrt_einfo_category_t attrs_ecat = lccrt_module_find_einfo_category( ci->lm, "func_attrs");
|
||||
|
||||
Затем для функции проверяется наличие данных в категории *"func_attrs"*.
|
||||
::
|
||||
|
||||
if ( lccrt_einfo_category_is_valued( attrs_ecat) ) {
|
||||
lccrt_einfo_reference_t eref = lccrt_function_get_einfo( f, attrs_ecat);
|
||||
|
||||
if ( lccrt_einfo_is_valued( eref) ) {
|
||||
// Чтение атрибутов функции.
|
||||
...;
|
||||
}
|
||||
}
|
||||
|
||||
При первом проходе по списку атрибутов выполняется инициализация вспомогательных переменных.
|
||||
::
|
||||
|
||||
if ( !fi->ci->etyde_fattr ) {
|
||||
lccrt_einfo_tydescr_ptr etyde_fattrs = lccrt_einfo_get_tydescr( eref);
|
||||
lccrt_einfo_tydescr_ptr etyde_fattr = lccrt_einfo_tydescr_get_elem( etyde_fattrs, 0);
|
||||
|
||||
fi->ci->etyde_fattr = etyde_fattr;
|
||||
fi->ci->eifi_fattr_src = lccrt_einfo_find_tydescr_field( etyde_fattr, "src");
|
||||
fi->ci->eifi_fattr_val = lccrt_einfo_find_tydescr_field( etyde_fattr, "value");
|
||||
}
|
||||
|
||||
Сохранение индексов полей в локальные переменные.
|
||||
::
|
||||
|
||||
fattr_src = fi->ci->eifi_fattr_src;
|
||||
fattr_val = fi->ci->eifi_fattr_val;
|
||||
|
||||
Проход по элементам списка атрибутов и обработка каждого атрибута.
|
||||
::
|
||||
|
||||
int len = lccrt_einfo_get_num_args( eref);
|
||||
|
||||
for ( i = 0; i < len; ++i ) {
|
||||
lccrt_eir_t erefi = lccrt_einfo_get_elem( eref, i);
|
||||
lccrt_eir_t src = lccrt_einfo_get_field( erefi, fattr_src);
|
||||
lccrt_eir_t val = lccrt_einfo_get_field( erefi, fattr_val);
|
||||
|
||||
lccrt_ProcessClFuncAttr( fi->proc, (char *)lccrt_einfo_get_raw_data( src), (char *)lccrt_einfo_get_raw_data( val));
|
||||
}
|
||||
|
||||
Обработка строкового значения конкретного атрибута с учетом его источника выполняется
|
||||
в данном случае в функции *lccrt_ProcessClFuncAttr*.
|
||||
|
||||
* В текстовом формате дополнительные данные будет сохранены следующим образом.
|
||||
|
||||
Привязка дополнительных данных к функции выполняется с помощью директивы *.einfo("%c1:%e25")*.
|
||||
В данном случае *%c1* - это сокращение для категории, а *%e25* - сокращение для дексриптора ЭДД.
|
||||
::
|
||||
|
||||
func main : () -> u32 .bind(glob) .nothrow .einfo("%c1:%e25")
|
||||
{
|
||||
__lccrt_l0:
|
||||
ret __lccrt_c0;
|
||||
__lccrt_l1:
|
||||
}
|
||||
|
||||
Регистрация в модуле категории *"func_attrs"*.
|
||||
::
|
||||
|
||||
eicat %c1 = func_attrs;
|
||||
|
||||
Определение описаний типов данных *"func_attrs.value"* и массива таких данных.
|
||||
::
|
||||
|
||||
eityde %s4 = struct "func_attrs.value" {src:raw,value:raw};
|
||||
eityde %s5 = array %s4;
|
||||
|
||||
Опредение дескрипторов ЭДД и их значений. Перед значением дескриптора приводится его тип.
|
||||
::
|
||||
|
||||
eidef %e0 = raw {"target-cpu=elbrus-v2"};
|
||||
eidef %e1 = raw {"llvm-13"};
|
||||
eidef %e2 = %s4 {%e1,%e0};
|
||||
...
|
||||
eidef %e25 = %s5 {%e24,%e22,%e20,%e18,%e16,%e14,%e12,%e10,%e8,%e6,%e4,%e2};
|
||||
|
Loading…
Reference in New Issue
Block a user