From 8add65e1e848a120ca9b96ec70849b888e2e2707 Mon Sep 17 00:00:00 2001 From: stepanov_pa Date: Thu, 26 Jan 2023 02:34:00 +0300 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=B2=20=D0=B0=D1=80=D1=85=D0=B8=D0=B2=20?= =?UTF-8?q?=D0=B8=D1=81=D1=85=D0=BE=D0=B4=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BA?= =?UTF-8?q?=D0=BE=D0=B4=D0=B0=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0?= =?UTF-8?q?=20=D0=B8=20=D0=B2=D1=8B=D0=B1=D0=BE=D1=80=20=D0=B4=D0=BB=D1=8F?= =?UTF-8?q?=20=D0=BF=D1=80=D0=BE=D0=B5=D0=BA=D1=82=D0=B0=20=D0=BB=D0=B8?= =?UTF-8?q?=D1=86=D0=B5=D0=BD=D0=B7=D0=B8=D0=B8=20'Apache=20License=202.0'?= =?UTF-8?q?.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- LICENSE | 202 ++ NOTICE | 5 + include/internal/lccrt_ctx.h | 325 ++ include/internal/lccrt_hash.h | 37 + include/internal/lccrt_ilist.h | 110 + include/internal/lccrt_irv.h | 478 +++ include/internal/lccrt_real.h | 22 + include/lccrt.h | 1539 +++++++++ lib/common/lccrt_ctx.c | 1284 +++++++ lib/common/lccrt_fs.c | 351 ++ lib/common/lccrt_hash.c | 557 ++++ lib/irv/lccrt_asmout.c | 147 + lib/irv/lccrt_func.c | 1241 +++++++ lib/irv/lccrt_irreader.c | 4045 +++++++++++++++++++++++ lib/irv/lccrt_irwriter.c | 1483 +++++++++ lib/irv/lccrt_link.c | 128 + lib/irv/lccrt_metadata.c | 1091 ++++++ lib/irv/lccrt_module.c | 452 +++ lib/irv/lccrt_oper.c | 2137 ++++++++++++ lib/irv/lccrt_type.c | 1405 ++++++++ lib/irv/lccrt_var.c | 1606 +++++++++ tools/lcbe/include/internal/lcbe_real.h | 15 + tools/lcbe/src/lcbe_driver.cpp | 1234 +++++++ tools/lcbe/src/lcbe_emit.cpp | 2345 +++++++++++++ tools/lccrt_s/include/lccrt_s.h | 511 +++ tools/lccrt_s/src/lccrt.c | 203 ++ tools/lccrt_s/src/lccrt_n.c | 3754 +++++++++++++++++++++ tools/lccrt_s/src/lccrt_overflow.c | 1608 +++++++++ tools/lccrt_s/src/lccrt_vec.c | 103 + 29 files changed, 28418 insertions(+) create mode 100644 LICENSE create mode 100644 NOTICE create mode 100644 include/internal/lccrt_ctx.h create mode 100644 include/internal/lccrt_hash.h create mode 100644 include/internal/lccrt_ilist.h create mode 100644 include/internal/lccrt_irv.h create mode 100644 include/internal/lccrt_real.h create mode 100644 include/lccrt.h create mode 100644 lib/common/lccrt_ctx.c create mode 100644 lib/common/lccrt_fs.c create mode 100644 lib/common/lccrt_hash.c create mode 100644 lib/irv/lccrt_asmout.c create mode 100644 lib/irv/lccrt_func.c create mode 100644 lib/irv/lccrt_irreader.c create mode 100644 lib/irv/lccrt_irwriter.c create mode 100644 lib/irv/lccrt_link.c create mode 100644 lib/irv/lccrt_metadata.c create mode 100644 lib/irv/lccrt_module.c create mode 100644 lib/irv/lccrt_oper.c create mode 100644 lib/irv/lccrt_type.c create mode 100644 lib/irv/lccrt_var.c create mode 100644 tools/lcbe/include/internal/lcbe_real.h create mode 100644 tools/lcbe/src/lcbe_driver.cpp create mode 100644 tools/lcbe/src/lcbe_emit.cpp create mode 100644 tools/lccrt_s/include/lccrt_s.h create mode 100644 tools/lccrt_s/src/lccrt.c create mode 100644 tools/lccrt_s/src/lccrt_n.c create mode 100644 tools/lccrt_s/src/lccrt_overflow.c create mode 100644 tools/lccrt_s/src/lccrt_vec.c diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..b0f235f --- /dev/null +++ b/NOTICE @@ -0,0 +1,5 @@ +Lccrt Project +Copyright 2023 AO "MCST" + +This product includes software developed at +AO "MCST" (http://www.mcst.ru/). diff --git a/include/internal/lccrt_ctx.h b/include/internal/lccrt_ctx.h new file mode 100644 index 0000000..a697ea6 --- /dev/null +++ b/include/internal/lccrt_ctx.h @@ -0,0 +1,325 @@ +/** + * 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_ctx.h - пользовательский интерфейс (динамической) компиляции. + */ + +#ifndef LCCRT_CTX_H +#define LCCRT_CTX_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include + +#include "lccrt.h" +#include "internal/lccrt_ilist.h" +#include "internal/lccrt_hash.h" + +#define LCCRT_MAX( a, b) (((a) >= (b)) ? (a) : (b)) +#define LCCRT_MIN( a, b) (((a) <= (b)) ? (a) : (b)) + +#ifndef NDEBUG +/** + * Макрос задающий тип сборки в отладочном режиме. + */ +#define LCCRT_DEBUG +#endif /* !NDEBUG */ + +/** + * Преобразование значения в строку. + */ +#define LCCRT_TO_STR_OPERATOR( x) #x +#define LCCRT_TO_STR( x) LCCRT_TO_STR_OPERATOR( x) + +#define LCCRT_ASM_SFUNC_COMPILE LCCRT_TO_STR( LCCRT_ASM_FUNC_COMPILE) +#define LCCRT_ASM_SFUNC_GETTOOL LCCRT_TO_STR( LCCRT_ASM_FUNC_GETTOOL) + +#define LCCRT_IRROBJ_SFUNC_NODE_COMPILE LCCRT_TO_STR( LCCRT_IRROBJ_FUNC_NODE_COMPILE) +#define LCCRT_IRROBJ_SFUNC_NODE_DECOMPILE LCCRT_TO_STR( LCCRT_IRROBJ_FUNC_NODE_DECOMPILE) +#define LCCRT_IRROBJ_SFUNC_RELOC_PATCH LCCRT_TO_STR( LCCRT_IRROBJ_FUNC_RELOC_PATCH) +#define LCCRT_IRROBJ_SFUNC_CODE_EXEC LCCRT_TO_STR( LCCRT_IRROBJ_FUNC_CODE_EXEC) +#define LCCRT_IRROBJ_SFUNC_GETCONF LCCRT_TO_STR( LCCRT_IRROBJ_FUNC_GETCONF) + +#define LCCRT_PLUGIN_LIBRARY_NAME_S LCCRT_TO_STR( LCCRT_PLUGIN_LIBRARY_NAME) +#define LCCRT_PLUGIN_LCCRT_VERSION_S LCCRT_TO_STR( LCCRT_PLUGIN_LCCRT_VERSION) +#define LCCRT_PLUGIN_TARGETS_S LCCRT_TO_STR( LCCRT_PLUGIN_TARGETS) + +/** + * Проверка двух строк на равенство. + */ +#define lccrt_str_eq( s, p) (strcmp( s, p) == 0) +#define lccrt_str_eqz( p, q) (!(p) || !(q) || lccrt_str_eq( p, q)) + +#define lccrt_min( a, b) ((a) < (b) ? (a) : (b)) +#define lccrt_max( a, b) ((a) > (b) ? (a) : (b)) + +/** + * Присвоение под условием. + */ +#define lccrt_assign( p, v) ((p) ? ((*(p) = (v)), 0) : 0) + +/** + * Исполнить выражение при нулевом значении флаговой переменной с сохранением во + * флаговую переменную результата выполнения выражения. + */ +#define lccrt_test0( flag, expr) ((flag) = ((expr) != 0) || (flag)) +#define lccrt_test1( flag, expr) ((flag) = (!(expr) != 0) || (flag)) + +/** + * Чтение числа из строки с продвижкой указателя (возвращается 1 при возможности чтения + * символов из строки s). + */ +#define lccrt_strtoll( s, se, base, p) \ +( \ + ((s) && (s)[0]) \ + ? (((p)[0] = strtoll( s, se, base)), 1) \ + : 0 \ +) + +/** + * Интерефейс динамической проверки типов структур. + */ +#ifdef LCCRT_DEBUG +int lccrt_assert_var __attribute__((weak)); +#define lccrt_assert( p) \ +( \ + lccrt_assert_var = ((p) \ + ? 0 \ + : (printf( "ERROR: %s: %s:%d\n", __FUNCTION__, __FILE__, __LINE__), \ + abort(), 0)) \ +) +//#define lccrt_assert( p) assert( p) +#define lccrt_check_type_name( type) lccrt_check_var__##type +#define lccrt_check_type_declare( type) extern void *lccrt_check_type_name( type) +#define lccrt_check_type_define( type) void *lccrt_check_type_name( type) +#define lccrt_check_type_assert( d, t) \ +( \ + lccrt_assert( !(d) \ + || (((t *)(d))->type_check.ptr == (void *)&lccrt_check_type_name( t))) \ +) +#define lccrt_check_type_init( d, t) \ +( \ + ((t *)(d))->type_check.ptr = (void *)&lccrt_check_type_name( t) \ +) +#define lccrt_check_type_done( d, t) \ +( \ + lccrt_check_type_assert( d, t), ((t *)(d))->type_check.ptr = 0 \ +) +#else /* !LCCRT_DEBUG */ +#define lccrt_assert( p) +#define lccrt_check_type_assert( d, t) +#define lccrt_check_type_declare( type) +#define lccrt_check_type_define( type) +#define lccrt_check_type_init( d, t) +#define lccrt_check_type_done( d, t) +#endif /* LCCRT_DEBUG */ + +/** + * Структура для динамического контроля типа структур. + */ +typedef struct +{ +#ifdef LCCRT_DEBUG + void *ptr; +#endif /* LCCRT_DEBUG */ +} lccrt_check_type_t; + +/** + * Типы плагинов. + */ +typedef enum +{ + LCCRT_PLUGIN_TYPE_ASM, + LCCRT_PLUGIN_TYPE_IRROBJ, + LCCRT_PLUGIN_TYPE_LAST +} lccrt_plugin_type_t; + +/** + * Типы функций в ассемблере. + */ +typedef enum +{ + LCCRT_PLUGIN_ASM_FUNC_COMP, + LCCRT_PLUGIN_ASM_FUNC_TOOL, + LCCRT_PLUGIN_ASM_FUNC_LAST +} lccrt_plugin_asm_func_name_t; + +/** + * Типы функций в трансляторе из IR-R в объектный код. + */ +typedef enum +{ + LCCRT_PLUGIN_IRROBJ_FUNC_NODE_COMPILE, + LCCRT_PLUGIN_IRROBJ_FUNC_NODE_DECOMPILE, + LCCRT_PLUGIN_IRROBJ_FUNC_RELOC_PATCH, + LCCRT_PLUGIN_IRROBJ_FUNC_CODE_EXEC, + LCCRT_PLUGIN_IRROBJ_FUNC_GETCONF, + LCCRT_PLUGIN_IRROBJ_FUNC_LAST +} lccrt_plugin_irrobj_func_name_t; + +/** + * Структура внешнего плагина. + */ +typedef struct lccrt_plugin_r +{ + lccrt_context_ptr ctx; + lccrt_plugin_type_t type; /* тип плагина */ + void *lib; /* плагин */ + const char *lib_name; /* название плагина */ + const char *lccrt_ver; /* версия lccrt-библиотеки, с которой был собран плагин */ + int num_targs; /* количество, поддерживаемых целей */ + const char **targs; /* массив целей */ + int num_funcs; /* количество методов в плагине */ + void **funcs; /* методы плагина */ + const char **lccrt_s; /* пути установки нативных (!) библиотек liblccrt_s */ + const char **include_s; /* пути установки нативных заголовочных файлов */ + lccrt_check_type_t type_check; +} lccrt_plugin_t; + +/** + * Штатные пути для поиска компонент. + */ +typedef struct +{ + char *home; /* корневая директория */ + char *plugin; /* директория поиска плагинов */ + char *plugins[LCCRT_PLUGIN_TYPE_LAST]; /* директория поиска плагинов по типу */ +} lccrt_context_paths_t; + +/** + * Данные по типам отладочных печатей. + */ +typedef struct +{ + int8_t is_base; /* информация о переменных окружения, плагинах и т.п. */ + int8_t is_ir; /* создание новых операций */ +} lccrt_context_verbose_t; + +/** + * \defgroup tyCtx lccrt_context_t + * Для работы с библиотекой в начале необходимо создать структуру контекста lccrt_context_t. + * В основном структура данных lccrt_context_t выполняет технические функции, + * в частности, можно одновременно создать несколько контекстов. Далее можно работать с разными контекстами + * независимым образом, причем все последующие данные создаются только в рамках одного из контекстов. + * При удалении контекста также (автоматически) удаляются все данные, созданные в рамках данного контекста. + * + * При создании контекста: + * - задается \ref lccrt_mem_t "менеджер памяти", с помощью которого должна выделяться память под структуры данных + * (при использовании внешних библиотек менеджер памяти не пропагируется), причем по умолчанию используются + * стандартные функции malloc/free + * - задается \ref lccrt_err_t "менеджер вывода сообщений об ошибках", причем по умолчанию используются + * стандартные функции printf/abort + * - происходит загрузка плагинов по штатным путям (см. \ref pgPlg "Загрузка плагинов") + * + */ +/** + * \class lccrt_context_t + * \copydoc tyCtx + * + * \copydoc tyCtxFns + * + * \ref tyCtxFns + */ +typedef struct lccrt_context_r +{ + lccrt_mem_t mem; /*!< интерфейс менеджера памяти */ + lccrt_err_t err; /*!< интерфейс менеджера ошибок */ + lccrt_hash_ptr modules; /* хеш-таблица модулей */ + uint64_t module_max; /* счетчик модулей */ + int num_plgs[LCCRT_PLUGIN_TYPE_LAST]; /* количество штатных плагинов */ + lccrt_plugin_t *plgs[LCCRT_PLUGIN_TYPE_LAST]; /* штатные плагины */ + lccrt_context_paths_t paths; /* пути поиска компонент */ + lccrt_context_verbose_t verbose; /* флаги отладочных печатетей */ + lccrt_check_type_t type_check; +} lccrt_context_t; + +/** + * Стандартный менеджер памяти и поток вывода ошибок. + */ +extern lccrt_mem_t lccrt_std_mem; +extern lccrt_err_t lccrt_std_err; + +/** + * Перечисление типов структур с динамической проверкой типа. + */ +lccrt_check_type_declare( lccrt_type_t); +lccrt_check_type_declare( lccrt_varinit_t); +lccrt_check_type_declare( lccrt_var_t); +lccrt_check_type_declare( lccrt_oper_t); +lccrt_check_type_declare( lccrt_oper_iterator_t); +lccrt_check_type_declare( lccrt_einfo_block_t); +lccrt_check_type_declare( lccrt_einfo_tydescr_t); +lccrt_check_type_declare( lccrt_einfo_link_t); +lccrt_check_type_declare( lccrt_function_t); +lccrt_check_type_declare( lccrt_function_jit_info_t); +lccrt_check_type_declare( lccrt_module_t); +lccrt_check_type_declare( lccrt_context_t); +lccrt_check_type_declare( lccrt_plugin_t); +lccrt_check_type_declare( lccrt_fs_t); +lccrt_check_type_declare( lccrt_jit_t); +lccrt_check_type_declare( lccrt_irr_code_area_t); +lccrt_check_type_declare( lccrt_irr_jit_region_t); +lccrt_check_type_declare( lccrt_irr_code_t); +lccrt_check_type_declare( lccrt_irr_execute_context_t); +lccrt_check_type_declare( lccrt_irr_reloc_unit_t); +lccrt_check_type_declare( lccrt_irr_reloc_t); +lccrt_check_type_declare( lccrt_irr_node_t); +lccrt_check_type_declare( lccrt_irr_oper_iter_t); +lccrt_check_type_declare( lccrt_irr_oper_t); +lccrt_check_type_declare( lccrt_irr_arg_t); +lccrt_check_type_declare( lccrt_irr_reg_t); +lccrt_check_type_declare( lccrt_irr_edge_t); + +extern void *lccrt_ctx_malloc_func( lccrt_ctx_ptr ctx, uint64_t size); +extern void *lccrt_ctx_realloc_func( lccrt_ctx_ptr ctx, void *ptr, uint64_t size); +extern void *lccrt_ctx_free_func( lccrt_ctx_ptr ctx, void *ptr); +extern void *lccrt_ctx_memdup_func( lccrt_ctx_ptr ctx, void *ptr, uint64_t len); +extern void **lccrt_ctx_copy_arr_func( lccrt_ctx_ptr ctx, void **ptr, uint64_t size, uint64_t len); +extern char *lccrt_ctx_copy_str( lccrt_context_ptr ctx, const char *str); +extern char *lccrt_ctx_cat_strs( lccrt_context_ptr ctx, const char *str1, const char *str2); +extern char *lccrt_ctx_catby_strs( lccrt_context_ptr ctx, const char *str1, const char *str2); +#define lccrt_ctx_malloc( ctx, type) (type *)lccrt_ctx_malloc_func( ctx, sizeof( type)) +#define lccrt_ctx_mallocn( ctx, type, n) ((type *)lccrt_ctx_malloc_func( ctx, (n) * sizeof( type))) +#define lccrt_ctx_realloc( ctx, ptr, len) lccrt_ctx_realloc_func( ctx, (void *)ptr, len) +#define lccrt_ctx_free( ctx, ptr) lccrt_ctx_free_func( ctx, (void *)ptr) +#define lccrt_ctx_memdup( ctx, ptr, len) lccrt_ctx_memdup_func( ctx, (void *)ptr, len) +#define lccrt_ctx_copy_arr( ctx, ptr, type, n) \ +( \ + (type *)lccrt_ctx_copy_arr_func( ctx, (void **)(ptr), sizeof( type), n) \ +) +#define lccrt_ctx_error( ctx, eid, fmt, ...) \ +( \ + (ctx)->err.error_func \ + ? ((ctx)->err.error_func( (ctx)->err.data, eid, "Error:%s:%d: " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__), 0) \ + : 0 \ +) +#define lccrt_ctx_warning( ctx, wid, fmt, ...) \ +( \ + (ctx)->err.warning_func \ + ? ((ctx)->err.warning_func( (ctx)->err.data, wid, "Warning:%s:%d: " fmt, __FUNCTION__, __LINE__, ##__VA_ARGS__), 0) \ + : 0 \ +) + +extern void *lccrt_ctx_plugin_get_func( lccrt_plg_ptr plg, int func_num); + +extern lccrt_fs_ptr lccrt_fs_new_file( lccrt_context_ptr ctx, FILE *file); +extern lccrt_fs_ptr lccrt_fs_open_file( lccrt_context_ptr ctx, const char *name, int is_load); +extern lccrt_fs_ptr lccrt_fs_new_buffer( lccrt_context_ptr ctx, char *buff, uint64_t buff_size); +extern int lccrt_fs_delete( lccrt_fs_ptr f); +extern int lccrt_fs_is_error( lccrt_fs_ptr f); +extern uint64_t lccrt_fs_get_syms_count( lccrt_fs_ptr f); +extern char *lccrt_fs_get_buffer( lccrt_fs_ptr f); +extern int lccrt_fs_get_sym( lccrt_fs_ptr f); +extern int lccrt_fs_printf( lccrt_fs_ptr f, const char *fmt, ...); +extern int lccrt_fs_print_name_str( lccrt_fs_ptr f, const char *name); + +#if defined(__cplusplus) +} +#endif + +#endif /* LCCRT_CTX_H */ diff --git a/include/internal/lccrt_hash.h b/include/internal/lccrt_hash.h new file mode 100644 index 0000000..3ae941a --- /dev/null +++ b/include/internal/lccrt_hash.h @@ -0,0 +1,37 @@ +/** + * 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_hash.h - пользовательский интерфейс (динамической) компиляции. + */ + +#ifndef LCCRT_HASH_H +#define LCCRT_HASH_H + +#if 0 +typedef enum +{ + LCCRT_HASH_KEY_INTPTR, + LCCRT_HASH_KEY_STRING, + LCCRT_HASH_KEY_LAST +} lccrt_hash_key_type_t; + +typedef lccrt_hash_key_type_t lccrt_hkt_t; +typedef struct lccrt_hash_entry_r *lccrt_hash_entry_ptr; +typedef struct lccrt_hash_r *lccrt_hash_ptr; +typedef lccrt_hash_entry_ptr lccrt_he_ptr; +typedef lccrt_hash_ptr lccrt_h_ptr; + +extern lccrt_h_ptr lccrt_hash_new( lccrt_ctx_ptr ctx, lccrt_hkt_t type); +extern void lccrt_hash_delete( lccrt_h_ptr ht); +extern lccrt_he_ptr lccrt_hash_push( lccrt_h_ptr ht, uintptr_t key, int *is_new); +extern lccrt_he_ptr lccrt_hash_find( lccrt_h_ptr ht, uintptr_t key); +extern uintptr_t lccrt_hash_remove( lccrt_he_ptr he); +extern uintptr_t lccrt_hash_get( lccrt_he_ptr he); +extern uintptr_t lccrt_hash_set( lccrt_he_ptr he, uintptr_t data); +extern lccrt_he_ptr lccrt_hash_first( lccrt_h_ptr ht); +extern lccrt_he_ptr lccrt_hash_next( lccrt_he_ptr he); +#endif + +#endif /* LCCRT_HASH_H */ diff --git a/include/internal/lccrt_ilist.h b/include/internal/lccrt_ilist.h new file mode 100644 index 0000000..38c6f32 --- /dev/null +++ b/include/internal/lccrt_ilist.h @@ -0,0 +1,110 @@ +/** + * 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_ilist.h - пользовательский интерфейс (динамической) компиляции. + */ + +#ifndef LCCRT_ILIST_H +#define LCCRT_ILIST_H + +/** + * Тип-шаблон для заголовка. + */ +#define lccrt_ilist_head( ptr) lccrt_ilist_head__##ptr +#define lccrt_ilist_head_typedef( ptr) \ +typedef struct \ +{ \ + ptr first; \ + ptr last; \ +} lccrt_ilist_head( ptr) + +/** + * Тип-шаблон для связи элементов. + */ +#define lccrt_ilist_unit( ptr) lccrt_ilist_unit__##ptr +#define lccrt_ilist_unit_typedef( ptr) \ +typedef struct \ +{ \ + ptr prev; \ + ptr next; \ +} lccrt_ilist_unit( ptr) + +/** + * Инициализация. + */ +#define lccrt_ilist_head_init( h) \ +( \ + (h)->first = 0, \ + (h)->last = 0 \ +) + +/** + * Инициализация. + */ +#define lccrt_ilist_unit_init( h) \ +( \ + (h)->prev = 0, \ + (h)->next = 0 \ +) + +/** + * Поменять значение ссылки. + */ +#define lccrt_ilist_assign_prev( l, u, v) ((u) ? ((u)->l.prev = (v)) : 0) +#define lccrt_ilist_assign_next( l, u, v) ((u) ? ((u)->l.next = (v)) : 0) + +/** + * Связывание двух узлов со внутренним списком. + */ +#define lccrt_ilist_link( l, u, v) \ +(\ + lccrt_ilist_assign_next( l, u, v), \ + lccrt_ilist_assign_prev( l, v, u), \ + 0 \ +) + +/** + * Вставка во внутренний список после заданного элемента нового узла. + */ +#define lccrt_ilist_insert( l, u, v) \ +( \ + lccrt_ilist_link( l, v, ((u) ? (u)->l.next : 0)), \ + lccrt_ilist_link( l, u, v), \ + (v) \ +) + +/** + * Вставка во внутренний список после заданного элемента нового узла. + */ +#define lccrt_ilist_head_insert( h, l, v) \ +( \ + lccrt_ilist_insert( l, (h)->last, v), \ + ((h)->last = v), \ + (((h)->first) ? 0 : ((h)->first = (v))), \ + (v) \ +) + +/** + * Удаление из списка текущего элемента. + */ +#define lccrt_ilist_remove( l, v) \ +( \ + lccrt_ilist_assign_next( l, (v)->l.prev, 0), \ + lccrt_ilist_assign_prev( l, (v)->l.next, 0), \ + (v)->l.prev \ +) + +/** + * Удаление из списка текущего элемента. + */ +#define lccrt_ilist_head_remove( h, l, v) \ +( \ + lccrt_ilist_remove( l, v), \ + (((h)->first == (v)) ? ((h)->first = (v)->l.next) : 0), \ + (((h)->last == (v)) ? ((h)->last = (v)->l.prev) : 0), \ + (v)->l.prev \ +) + +#endif /* LCCRT_ILIST_H */ diff --git a/include/internal/lccrt_irv.h b/include/internal/lccrt_irv.h new file mode 100644 index 0000000..9455be3 --- /dev/null +++ b/include/internal/lccrt_irv.h @@ -0,0 +1,478 @@ +/** + * 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_irv.h - пользовательский интерфейс (динамической) компиляции. + */ + +#ifndef LCCRT_IRV_H +#define LCCRT_IRV_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "internal/lccrt_ctx.h" + +/** + * Получить по битовому размеру целового типа его внутреннее название. + */ +#define lccrt_type_get_int_subtype_name( bs) \ +( \ + (bs) == 8 \ + ? LCCRT_INT_SUBTYPE_8 \ + : ((bs) == 16 \ + ? LCCRT_INT_SUBTYPE_16 \ + : ((bs) == 32 \ + ? LCCRT_INT_SUBTYPE_32 \ + : ((bs) == 64 \ + ? LCCRT_INT_SUBTYPE_64 \ + : ((bs) == 128 \ + ? LCCRT_INT_SUBTYPE_128 \ + : LCCRT_INT_SUBTYPE_LAST)))) \ +) + +/** + * Получить по битовому размеру плавающего типа его внутреннее название. + */ +#define lccrt_type_get_float_subtype_name( bs) \ +( \ + (bs) == 32 \ + ? LCCRT_FLOAT_SUBTYPE_32 \ + : ((bs) == 64 \ + ? LCCRT_FLOAT_SUBTYPE_64 \ + : ((bs) == 80 \ + ? LCCRT_FLOAT_SUBTYPE_80 \ + : ((bs) == 128 \ + ? LCCRT_FLOAT_SUBTYPE_128 \ + : LCCRT_FLOAT_SUBTYPE_LAST))) \ +) + +/** + * Определение типов для списков. + */ +lccrt_ilist_head_typedef( lccrt_t_ptr); +lccrt_ilist_unit_typedef( lccrt_t_ptr); +lccrt_ilist_head_typedef( lccrt_f_ptr); +lccrt_ilist_unit_typedef( lccrt_f_ptr); +lccrt_ilist_head_typedef( lccrt_v_ptr); +lccrt_ilist_unit_typedef( lccrt_v_ptr); +lccrt_ilist_head_typedef( lccrt_vi_ptr); +lccrt_ilist_unit_typedef( lccrt_vi_ptr); + +typedef struct lccrt_einfo_link_r *lccrt_einfo_link_ptr; +typedef struct lccrt_einfo_block_r *lccrt_einfo_block_ptr; +typedef lccrt_einfo_link_ptr lccrt_eil_ptr; +typedef lccrt_einfo_block_ptr lccrt_eib_ptr; + +/** + * IR-тип данных. + */ +typedef struct lccrt_type_r +{ + //lccrt_context_ptr ctx; + lccrt_module_ptr m; + lccrt_type_ptr parent; /* указуемый тип (для LCCRT_TYPE_PTR) + указуемый тип (для LCCRT_TYPE_NAME) + возвращаемый тип (для LCCRT_TYPE_FUNC) + элементарный тип (для LCCRT_TYPE_ARRAY) + элементарный тип (для LCCRT_TYPE_VLA_ARRAY) + элементарный тип (для LCCRT_TYPE_FIELD) */ + lccrt_type_ptr *args; /* массив аргументов (для LCCRT_TYPE_FUNC) + массив элементов (для LCCRT_TYPE_STRUCT) */ + uint64_t num_args; /* количество аргументов (для LCCRT_TYPE_FUNC) + количество элементов (для LCCRT_TYPE_ARRAY) + количество элементов (для LCCRT_TYPE_STRUCT) */ + lccrt_var_ptr vnum; /* количество элементов (для LCCRT_TYPE_VLA_ARRAY) */ + const char *sym_name; /* символьное имя (является ключем в ctx->types) */ + const char *usr_name; /* пользовательское имя (является ключем в ctx->type_usr_names), может быть + пустым */ + lccrt_ilist_unit( lccrt_t_ptr) types_unit; /* элемент списка типов */ + uint64_t bytealign; /* байтовое выравнивание */ + uint64_t bytesize; /* байтовый размер */ + uint64_t byteshift; /* смещение от начала объемлющего типа (для LCCRT_TYPE_FIELD) */ + uint64_t ident_num; /* уникальный номер типа */ + lccrt_type_name_t type_name; /* идентификатор типа */ + unsigned char bitsubshift; /* дополнительное битовое смещение (для LCCRT_TYPE_FIELD) */ + unsigned char bitsubsize; /* количество хранимых бит (для LCCRT_TYPE_FIELD) */ + unsigned char is_sign; /* знаковость (для LCCRT_TYPE_INT) */ + unsigned char is_union; /* флаг совмещения полей (для LCCRT_TYPE_STRUCT) */ + lccrt_check_type_t type_check; +} lccrt_type_t; + +/** + * Основные IR-типы данных. + */ +typedef struct lccrt_types_std_r +{ + int ptr_bytesize; /* байтовый размер указателей */ + lccrt_type_ptr void_type; /* тип void */ + lccrt_type_ptr bool_type; /* тип bool */ + lccrt_type_ptr int_types[2][LCCRT_INT_SUBTYPE_LAST+1]; /* целые типы */ + lccrt_type_ptr float_types[LCCRT_FLOAT_SUBTYPE_LAST+1]; /* плавающие типы */ + lccrt_type_ptr ellipsis; /* тип для аргумента функции вида "..." */ + lccrt_type_ptr intptr; /* целый тип по размеру эквивалентный указателю */ + lccrt_type_ptr ptr_byte; /* указатель на uint8 */ + lccrt_type_ptr ptr_char; /* указатель на sint8 */ + lccrt_type_ptr ptr_intptr; /* указатель на intptr */ +} lccrt_types_std_t; + +/** + * Тип einfo-данных. + */ +typedef enum +{ + LCCRT_EINFO_NULL = 0, + LCCRT_EINFO_INT64, + LCCRT_EINFO_STRUCT, + LCCRT_EINFO_UNION, + LCCRT_EINFO_ARRAY, + LCCRT_EINFO_RAW, + LCCRT_EINFO_LAST +} lccrt_einfo_type_t; + +/** + * Указатель на einfo-данные. + */ +typedef struct +{ + uint8_t type; /* тип einfo-данных */ + union + { + uint64_t i64; // значение типа LCCRT_EINFO_INT64 + lccrt_einfo_block_ptr ref; // указатель для типов LCCRT_EINFO_ARRAY, LCCRT_EINFO_STRUCT, + // LCCRT_EINFO_RAW, LCCRT_EINFO_UNION + } data; +} lccrt_einfo_handle_t; + +/** + * Описание типа метаданных. + */ +typedef struct lccrt_einfo_tydescr_r +{ + lccrt_einfo_tydescr_ptr next; /* общий список всех структур */ + lccrt_einfo_type_t type; /* тип einfo-данных */ + int num_flds; /* количество полей */ + lccrt_module_ptr m; /* ссылка на модуль */ + char *self_name; /* название структуры данных */ + char **flds; /* массив с названиями полей */ + lccrt_einfo_tydescr_ptr *types; /* массив с типами полей */ + lccrt_check_type_t type_check; +} lccrt_einfo_tydescr_t; + +/** + * Мета-данные. + */ +typedef struct lccrt_einfo_block_r +{ + lccrt_einfo_block_ptr next; /* общий список всех данных */ + uint8_t type; /* тип мета-данных */ + int32_t num_args; /* количество полей для LCCRT_EINFO_STRUCT, + количество элементов для LCCRT_EINFO_ARRAY, + байтовый размер для LCCRT_EINFO_RAW */ + int32_t max_args; /* длина выделения массива элементов для LCCRT_EINFO_ARRAY */ + lccrt_einfo_tydescr_ptr tydescr; /* описание типов полей для LCCRT_EINFO_STRUCT, LCCRT_EINFO_UNION, + описание типа элемента для LCCRT_EINFO_ARRAY */ + union + { + lccrt_einfo_handle_t *flds; /* значение полей для LCCRT_EINFO_STRUCT, LCCRT_EINFO_UNION */ + lccrt_einfo_handle_t *elems; /* значение элементов LCCRT_EINFO_ARRAY */ + uint8_t *rdata; /* данные для LCCRT_EINFO_RAW */ + } data; + lccrt_check_type_t type_check; +} lccrt_einfo_block_t; + +/** + * Элемент списка мета-данных. + */ +typedef struct lccrt_einfo_link_r +{ + lccrt_einfo_link_ptr prev; /* ссылка на предыдущий элемент */ + lccrt_einfo_link_ptr next; /* ссылка на следующий элемент */ + lccrt_einfo_category_t ident; /* дескриптор свойства */ + lccrt_einfo_handle_t value; /* значение свойства */ + lccrt_check_type_t type_check; +} lccrt_einfo_link_t; + +/** + * Размер диапазона кешируемых константных значений. + */ +#define LCCRT_MODULE_CARG_MIN (-32LL) +#define LCCRT_MODULE_CARG_MAX (+31LL) +#define LCCRT_MODULE_CARG_LEN (LCCRT_MODULE_CARG_MAX - LCCRT_MODULE_CARG_MIN + 1) + +/** + * Модуль - аналог языковой единицы компиляции. + */ +typedef struct lccrt_module_r +{ + lccrt_context_ptr ctx; + const char *name; /* название модуля */ + const char *asm_text; /* asm-inline текст модуля */ + uint64_t ident_num; /* уникальный идентификатор модуля */ + lccrt_types_std_t types_std; /* основные типы данных */ + lccrt_h_ptr types; /* хеш-таблица типов */ + lccrt_h_ptr type_usr_names; /* хеш-таблица (пользовательскоеИмя -> тип) */ + uint64_t type_max; /* счетчик типов */ + lccrt_h_ptr gvars; /* соответствие имя->глобальнаяПеременная */ + lccrt_h_ptr funcs; /* соответствие имя->функция */ + uintptr_t einfo_ident; /* идентификатор для следующего класса метаданных */ + lccrt_h_ptr einfo_cats; /* таблица названиеКатегории -> идентификаторКатегории */ + lccrt_einfo_tydescr_ptr etydescrs_head; /* список всех блоков описания мета-данных */ + lccrt_einfo_block_ptr eblocks_head; /* список всех блоков мета-данных */ + lccrt_einfo_tydescr_ptr einfo_tyi64; /* описание типа для i64-einfo */ + lccrt_einfo_tydescr_ptr einfo_tyraw; /* описание типа для raw-einfo */ + lccrt_h_ptr einfo_tyarrs; /* таблица типЭлемента -> типМассив */ + lccrt_h_ptr einfo_tysts; /* таблица тегНазвание -> типСтруктура */ + lccrt_einfo_link_ptr einfo; /* собственные мета-данные модуля */ + lccrt_ilist_head( lccrt_t_ptr) types_head; /* список всех типов */ + lccrt_ilist_head( lccrt_v_ptr) gvars_head; /* список всех глобальных переменных */ + lccrt_ilist_head( lccrt_f_ptr) funcs_head; /* список всех функций */ + lccrt_ilist_head( lccrt_vi_ptr) varinits_head; /* список всех инициализаторов */ + uint64_t funcs_num; /* нумерация функций */ + uint64_t gvars_num; /* нумерация глобальных переменных */ + uint64_t cargs_name_id; /* нумерация константных имен */ + uint64_t global_name_id; /* нумерация глобальных имен */ + lccrt_var_ptr carg_vars[2][LCCRT_MODULE_CARG_LEN]; /* переменные константные + аргументы [u32,u64][-32..+31] */ + uint8_t is_ptr32; /* компиляция для 32-битной модели памяти */ + uint8_t is_jit; /* компиляция в динамическом режиме */ + lccrt_check_type_t type_check; +} lccrt_module_t; + +/** + * Инициализатор переменной. + */ +typedef struct lccrt_varinit_r +{ + lccrt_type_ptr type; /* ir-тип */ + union lccrt_varinit_data_r + { + uint64_t ival; /* скалярное значение (для LCCRT_VARINIT_HEX) */ + char *sval; /* массив байт (для LCCRT_VARINIT_STR) */ + lccrt_varinit_ptr *vals; /* массив значений (для LCCRT_VARINIT_ARR) */ + lccrt_var_ptr var; /* адрес переменной (для LCCRT_VARINIT_ADDR_VAR) */ + struct lccrt_function_r *func; /* адрес функции (для LCCRT_VARINIT_ADDR_FUNC) */ + } data; + lccrt_varinit_inittype_t init_type; /* разновидность инициализатора */ + uint64_t num_elems; /* количество элементов (для LCCRT_VARINIT_ARR) + количество элементов (для LCCRT_VARINIT_STR) + смещение в байтах (для LCCRT_VARINIT_ADDR_VAR) + смещение в байтах (для LCCRT_VARINIT_ADDR_FUNC) */ + lccrt_ilist_unit( lccrt_vi_ptr) varinits_unit; /* элемент списка инициализаторов */ + lccrt_check_type_t type_check; +} lccrt_varinit_t; + +/** + * Информация о способе линковке. + */ +typedef struct +{ + lccrt_link_bind_t bnd; /* тип старшинства */ + lccrt_link_visibility_t vis; /* тип видимости */ + lccrt_link_tls_t tls; /* tls-тип */ + uint8_t is_cnst; /* флаг неизменности значения ячейки памяти */ + uint8_t is_alias; /* флаг алиаса */ +} lccrt_asmlink_t; + +/** + * Булевые атрибуты переменной (собираем вместе для экономии памяти). + */ +typedef enum +{ + LCCRT_VAR_ATTR_USED, /* признак (скрытого) использования */ + LCCRT_VAR_ATTR_COMMON, /* признак common-переменной */ + LCCRT_VAR_ATTR_RESTRICT, + LCCRT_VAR_ATTR_LAST +} lccrt_var_attr_name_t; + +/** + * Количество длинных слов (по 64 бита), которое необходимо для хранения значений + * всех атрибутов. + */ +#define LCCRT_VAR_ATTRS_LENGTH ((LCCRT_VAR_ATTR_LAST + 63) / 64) + +/** + * Аналог языковой переменной. + */ +typedef struct lccrt_var_r +{ + void *holder; /* полный контекст, модуль или функция (в зависимости от loc) */ + const char *name; /* название переменной */ + const char *asm_name; /* название в ассемблерном файле (для обычных переменных) + ассемблерный текст (для LCCRT_VAR_LOC_ASM) */ + const char *section_name; /* название секции в ассемблерном файле */ + const char *comdat; /* значение поля comdat (или 0) */ + lccrt_varinit_ptr init_value; /* инициализатор переменной */ + lccrt_type_ptr type; /* тип переменной */ + lccrt_einfo_link_ptr einfo; /* мета-данные переменной */ + lccrt_ilist_unit( lccrt_v_ptr) vars_unit; /* элемент списка переменных */ + lccrt_var_loc_t loc; /* тип размещения переменной */ + lccrt_asmlink_t link; /* тип связывания переменной */ + uint64_t ident_num; /* идентификатор (внутри holder-контекста) */ + unsigned align; /* минимальное выравнивание переменной */ + int arg_num; /* номер аргумента среди аргументов функции (для LCCRT_VAR_LOC_ARG) */ + int num_defs; /* количество использований переменной в качестве результата */ + uint64_t attrs[LCCRT_VAR_ATTRS_LENGTH]; /* булевые атрибуты переменной */ + lccrt_check_type_t type_check; +} lccrt_var_t; + +/** + * Итератор для ссылки на операции. + */ +typedef struct lccrt_oper_iterator_r +{ + lccrt_context_ptr ctx; + lccrt_oper_ptr prev; + lccrt_oper_ptr next; + lccrt_oper_ptr last; /* последняя, созданная с помощью итератора, операция */ + int is_forward; /* флаг замены prev новой операцией, иначе - замена next */ + lccrt_check_type_t type_check; +} lccrt_oper_iterator_t; + +#define LCCRT_GET_BYTE( d, k) (((unsigned char *)(d))[k]) +#define LCCRT_LINK_BYTE_BND( d) LCCRT_GET_BYTE( d, 0) +#define LCCRT_LINK_BYTE_VIS( d) LCCRT_GET_BYTE( d, 1) +#define LCCRT_LINK_BYTE_TLS( d) LCCRT_GET_BYTE( d, 2) +#define LCCRT_LINK_BYTE_CST( d) LCCRT_GET_BYTE( d, 3) +#define LCCRT_LINK_BYTE_ALS( d) LCCRT_GET_BYTE( d, 4) + +/** + * Булевые атрибуты функции (собираем вместе для экономии памяти). + */ +typedef enum +{ + LCCRT_FUNC_ATTR_DECLARATION, /* признак заголовочного объявления */ + LCCRT_FUNC_ATTR_BUILTIN, /* признак встроенной функции */ + LCCRT_FUNC_ATTR_USED, /* признак "used" */ + LCCRT_FUNC_ATTR_EXTERN_INLINE, /* признак declare-функции, для которой доступно тело + функции, но только для оптимизаций типа inline */ + LCCRT_FUNC_ATTR_DOES_NOT_THROW, /* признак "does not throw" */ + LCCRT_FUNC_ATTR_JIT_PROFGEN, /* признак генерации профиля */ + LCCRT_FUNC_ATTR_LAST +} lccrt_function_attr_name_t; + +/** + * Количество длинных слов (по 64 бита), которое необходимо для хранения значений + * всех атрибутов. + */ +#define LCCRT_FUNC_ATTRS_LENGTH ((LCCRT_FUNC_ATTR_LAST + 63) / 64) + +/** + * Функция. + */ +typedef struct lccrt_function_r +{ + lccrt_context_ptr ctx; + lccrt_module_ptr module; /* охватывающий модуль */ + const char *name; /* имя функции */ + const char *asm_name; /* имя функции в ассемблерном файле */ + const char *section; /* название секции в ассемблерном файле (или 0) */ + const char *comdat; /* значение поля comdat (или 0) */ + lccrt_hash_ptr lvars; /* локальные переменные функции */ + lccrt_asmlink_t link; /* информация о линковке */ + lccrt_type_ptr sig_type; /* сигнатура функции */ + lccrt_var_ptr *args; /* аргументы функции */ + lccrt_var_ptr *sysargs; /* (специальные) аргументы функции */ + lccrt_function_jit_info_ptr jit_info; /* данные для динамической компиляции */ + lccrt_einfo_link_ptr einfo; /* мета-данные функции */ + uint64_t ident_num; /* уникальный идентификатор функции (внутри модуля) */ + uint32_t sysargs_num; /* нумерация (специальных) аргументов функции */ + uint32_t lvars_num; /* нумерация локальных переменных */ + uint32_t opers_num; /* нумерация операций */ + uint32_t local_name_id; /* нумерация локальных имен */ + lccrt_ilist_unit( lccrt_f_ptr) funcs_unit; /* элемент списка функций */ + lccrt_oper_ptr start; /* стартовая ir-операция */ + lccrt_oper_iterator_t cur; /* ir-итератор */ + lccrt_ilist_head( lccrt_v_ptr) lvars_head; /* список всех локальных переменных */ + lccrt_function_init_type_t init_type; /* тип инициализации для функции */ + int init_priority; /* порядок инициализации функции */ + uint64_t attrs[LCCRT_FUNC_ATTRS_LENGTH]; /* булевые атрибуты функции */ + lccrt_check_type_t type_check; +} lccrt_function_t; + +/** + * IR-операция. + */ +typedef struct lccrt_oper_r +{ + lccrt_function_ptr func; + uint64_t ident_num; /* идентификатор операции */ + lccrt_oper_ptr prev; /* предыдущая операция */ + lccrt_oper_ptr next; /* следующая операция */ + lccrt_var_ptr res; /* результат операции */ + lccrt_arg_t *args; /* аргументы операции */ + const char *label; /* метка операции (для LCCRT_OPER_LABEL) */ + lccrt_einfo_link_ptr einfo; /* мета-данные операции */ + lccrt_oper_name_t name; /* название операции */ + int32_t num_args; /* количество аргументов */ + int32_t num_sysargs; /* количество (специальных) аргументов */ + char is_volatile; /* флаг volatile-обращение */ + char is_atomic; /* флаг atomic-обращение */ + char is_cleanup; /* флаг cleanup-landingpad'а */ + lccrt_check_type_t type_check; +} lccrt_oper_t; + +extern lccrt_t_ptr lccrt_type_make_simple( lccrt_m_ptr m, lccrt_type_name_t name, const char *sym_name, + int is_sign, uint64_t bytealign, uint64_t bytesize); +extern void lccrt_type_delete( lccrt_t_ptr type); +extern void lccrt_type_set_parent( lccrt_type_ptr type, lccrt_type_ptr parent); +extern void lccrt_type_set_arg( lccrt_type_ptr type, int arg_num, lccrt_type_ptr arg); +extern lccrt_t_ptr lccrt_type_import( lccrt_m_ptr m, lccrt_t_ptr type, lccrt_h_ptr types); + +extern lccrt_link_t lccrt_link_conv( lccrt_asmlink_t link); +extern lccrt_asmlink_t lccrt_link_unpack( lccrt_link_t link); + +extern void lccrt_varinit_delete( lccrt_vi_ptr vi); +extern void lccrt_var_copy_attrs( lccrt_v_ptr dst, lccrt_v_ptr src); + +extern void lccrt_module_delete_data( lccrt_m_ptr m); +extern char *lccrt_module_name_new_global( lccrt_m_ptr m, const char *name); +extern lccrt_hash_ptr lccrt_module_get_types( lccrt_m_ptr m); +extern lccrt_hash_ptr lccrt_module_get_gvars( lccrt_m_ptr m); +extern lccrt_hash_ptr lccrt_module_get_funcs( lccrt_m_ptr m); +extern uint64_t lccrt_module_get_type_max( lccrt_module_ptr m); +extern uint64_t lccrt_module_get_func_max( lccrt_module_ptr m); + +extern void lccrt_function_delete( lccrt_f_ptr f); +extern int lccrt_function_get_attr_jit_profgen( lccrt_f_ptr func); +extern int lccrt_function_set_attr_jit_profgen( lccrt_f_ptr func, int value); +extern char *lccrt_function_name_new_local( lccrt_f_ptr f, const char *name); +extern void lccrt_function_clear( lccrt_function_ptr f); +extern lccrt_f_ptr lccrt_function_copy( lccrt_m_ptr m, lccrt_f_ptr f, const char *name, + const char *asm_name, lccrt_link_t ln, lccrt_h_ptr types); +extern lccrt_o_ptr lccrt_function_call_inline( lccrt_o_ptr call, lccrt_f_ptr call_func); +extern 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_h_ptr types, + int is_same_name); +extern void lccrt_function_init_jit_info( lccrt_f_ptr f, lccrt_f_ptr root, + lccrt_v_ptr func_entry, lccrt_v_ptr profgen_tls); + +extern lccrt_einfo_handle_t lccrt_einfo_get_handle( lccrt_einfo_reference_t value); +extern int lccrt_einfo_is_scalar( lccrt_einfo_reference_t einfo); +extern lccrt_eir_t lccrt_einfo_get_block_reference( lccrt_eib_ptr eblock); +extern void lccrt_einfo_block_delete( lccrt_einfo_block_ptr eblock); +extern void lccrt_einfo_tydescr_delete( lccrt_einfo_tydescr_ptr etyde); +extern lccrt_einfo_link_ptr lccrt_einfo_link_new( lccrt_m_ptr m, lccrt_eil_ptr elink, + lccrt_eic_t ecat, lccrt_eir_t value); +extern lccrt_einfo_link_ptr lccrt_einfo_link_push_value( lccrt_m_ptr m, lccrt_eil_ptr elink0, + lccrt_eic_t ecat, lccrt_eir_t value); +extern lccrt_einfo_link_ptr lccrt_einfo_link_delete_chain( lccrt_einfo_link_ptr elink); +extern lccrt_einfo_link_ptr lccrt_einfo_link_find( lccrt_einfo_link_ptr elink, lccrt_eic_t ecat); +extern void lccrt_einfo_link_delete( lccrt_einfo_link_ptr elink); +extern lccrt_einfo_reference_t lccrt_einfo_link_get_value( lccrt_einfo_link_ptr elink); +extern void lccrt_module_einfo_number( lccrt_m_ptr m, lccrt_h_ptr btbl, lccrt_h_ptr ttbl); + +extern int lccrt_var_get_num_defs( lccrt_v_ptr v); +extern int lccrt_var_set_num_defs( lccrt_v_ptr v, int num_defs); + +extern const char *lccrt_oper_get_name_str( lccrt_oper_ptr op); +extern void lccrt_oper_print_opers( lccrt_o_ptr op1, lccrt_o_ptr op2); +extern int lccrt_oper_get_str_opername( const char *str); + +#if defined(__cplusplus) +} +#endif + +#endif /* LCCRT_IRV_H */ diff --git a/include/internal/lccrt_real.h b/include/internal/lccrt_real.h new file mode 100644 index 0000000..f0fe66c --- /dev/null +++ b/include/internal/lccrt_real.h @@ -0,0 +1,22 @@ +/** + * 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_real.h - пользовательский интерфейс (динамической) компиляции. + */ + +#ifndef LCCRT_REAL_H +#define LCCRT_REAL_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include "internal/lccrt_irv.h" + +#if defined(__cplusplus) +} +#endif + +#endif /* LCCRT_REAL_H */ diff --git a/include/lccrt.h b/include/lccrt.h new file mode 100644 index 0000000..60bd8a0 --- /dev/null +++ b/include/lccrt.h @@ -0,0 +1,1539 @@ +/** + * 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.h - пользовательский интерфейс (динамической) компиляции. + */ +#ifndef LCCRT_H +#define LCCRT_H + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#include +#include +#include + +#define LCCRT_VERSION "0.0.8" + +typedef struct lccrt_mem_r *lccrt_mem_ptr; +typedef struct lccrt_err_r *lccrt_err_ptr; +typedef struct lccrt_context_r *lccrt_context_ptr; +typedef struct lccrt_plugin_r *lccrt_plugin_ptr; +typedef struct lccrt_module_r *lccrt_module_ptr; +typedef struct lccrt_function_r *lccrt_function_ptr; +typedef struct lccrt_function_jit_info_r *lccrt_function_jit_info_ptr; +typedef struct lccrt_var_r *lccrt_var_ptr; +typedef struct lccrt_varinit_r *lccrt_varinit_ptr; +typedef struct lccrt_type_r *lccrt_type_ptr; +typedef struct lccrt_oper_r *lccrt_oper_ptr; +typedef struct lccrt_oper_iterator_r *lccrt_oper_iterator_ptr; +typedef struct { intptr_t data[2]; } lccrt_einfo_reference_t; +typedef struct lccrt_einfo_tydescr_r *lccrt_einfo_tydescr_ptr; +typedef struct { intptr_t id; } lccrt_einfo_category_t; +typedef struct { intptr_t data[2]; } lccrt_einfo_field_id_t; +typedef struct lccrt_fs_r *lccrt_fs_ptr; + +typedef struct lccrt_irr_jit_region_r *lccrt_irr_jit_region_ptr; +typedef struct lccrt_irr_execute_context_r *lccrt_irr_execute_context_ptr; +typedef struct lccrt_irr_code_r *lccrt_irr_code_ptr; +typedef struct lccrt_irr_node_r *lccrt_irr_node_ptr; +typedef struct lccrt_irr_oper_r *lccrt_irr_oper_ptr; +typedef struct lccrt_irr_oper_iter_r *lccrt_irr_oper_iter_ptr; +typedef struct lccrt_irr_arg_r *lccrt_irr_arg_ptr; +typedef struct lccrt_irr_reg_r *lccrt_irr_reg_ptr; +typedef struct lccrt_irr_label_r *lccrt_irr_label_ptr; +typedef struct lccrt_irr_reloc_r *lccrt_irr_reloc_ptr; +typedef struct lccrt_irr_reloc_unit_r *lccrt_irr_reloc_unit_ptr; +typedef lccrt_irr_node_ptr (* lccrt_irr_resolve_virt_addr_func_t)( void *, uint64_t); +typedef uint64_t lccrt_irr_hex_t; + +#define LCCRT_PLUGIN_LIBRARY_NAME lccrt_plugin_library_name +#define LCCRT_PLUGIN_LCCRT_VERSION lccrt_plugin_lccrt_version +#define LCCRT_PLUGIN_TARGETS lccrt_plugin_targets + +#define LCCRT_ASM_FUNC_COMPILE lccrt_asm_compile +#define LCCRT_ASM_FUNC_GETTOOL lccrt_asm_gettool + +#define LCCRT_IRROBJ_FUNC_NODE_COMPILE lccrt_irrobj_node_compile +#define LCCRT_IRROBJ_FUNC_NODE_DECOMPILE lccrt_irrobj_node_decompile +#define LCCRT_IRROBJ_FUNC_RELOC_PATCH lccrt_irrobj_reloc_patch +#define LCCRT_IRROBJ_FUNC_CODE_EXEC lccrt_irrobj_code_exec +#define LCCRT_IRROBJ_FUNC_GETCONF lccrt_irrobj_getconf + +typedef int (*lccrt_asm_write_t)( void *write_info, char *data, uint64_t length); + +/** + * Структура с настройками процесса компиляции. + */ +typedef struct +{ + const char *target; /* результирующая платформа */ + void *write_info; /* выходной поток */ + lccrt_asm_write_t write; /* функция записи в выходной поток */ + const char *out_type; /* тип выходной информации ("asm", "obj") */ + int opt_level; /* уровень оптимизации */ + int8_t is_pic; /* флаг PIC-режима */ + int8_t pie_level; /* только для PIC-режима: 0 - not pie, 1 - small pie, 2 - large pie */ + int8_t is_jit; /* включить режим компиляции */ + int8_t dbg_level; /* уровень отладочной информации в формате dwarf2 */ + int8_t function_sections; /* включить опцию -ffunction-sections */ + int8_t data_sections; /* включить опцию -fdata-sections */ + int8_t asm_verbose; /* включить опцию -fverbose-asm */ + int8_t is_llvmir_embed_static_only; /* включить режим "встроенный llvm-IR только в статике" */ + const char *eh_personality; /* название personality-функции */ + const char *cpu_arch; /* архитектура процессора */ + const char *cflags; /* дополнительные опции компиляции, которые могут быть не доступны в виде + самостоятельных параметров */ +} lccrt_asm_compile_config_t; + +typedef int (*lccrt_asm_compile_t)( lccrt_module_ptr m, lccrt_asm_compile_config_t *cnf); +typedef const char *(*lccrt_asm_gettool_t)( const char *targ, const char *type, const char *name); + +typedef lccrt_irr_code_ptr (*lccrt_irrobj_node_compile_t)( lccrt_irr_node_ptr n); +typedef int (*lccrt_irrobj_node_decompile_t)( lccrt_irr_node_ptr n); +typedef int (*lccrt_irrobj_reloc_patch_t)( lccrt_irr_reloc_ptr reloc, lccrt_irr_code_ptr code); +typedef int (*lccrt_irrobj_code_exec_t)( lccrt_irr_code_ptr code, lccrt_irr_execute_context_ptr ec); +typedef const char *(*lccrt_irrobj_getconf_t)( const char *targ, const char *name); + +extern int LCCRT_ASM_FUNC_COMPILE( lccrt_module_ptr m, lccrt_asm_compile_config_t *cnf); +extern const char *LCCRT_ASM_FUNC_GETTOOL( const char *targ, const char *type, const char *name); + +/** + * Типы данных для функций выделения/освобождения памяти. + */ +typedef void * (*lccrt_alloc_t)( void *pool, uint64_t size); +typedef void * (*lccrt_realloc_t)( void *pool, void *ptr, uint64_t size); +typedef void (*lccrt_free_t)( void *pool, void *ptr); + +/** + * Данные менеджера (аллокатора) памяти. + */ +typedef struct lccrt_mem_r +{ + void *pool; /*!< собственные данные менеджера (первый параметр методов) */ + lccrt_alloc_t palloc; /*!< функция выделения памяти */ + lccrt_realloc_t prealloc; /*!< функция увелечения размера памяти */ + lccrt_free_t pfree; /*!< функция освобождения памяти */ +} lccrt_mem_t; + +extern void lccrt_mem_init( lccrt_mem_t *mem, void *pool, + lccrt_alloc_t alloc_func, lccrt_realloc_t realloc_func, + lccrt_free_t free_func); + +/** + * Тип данных для выдачи события о возникновении ошибки. + */ +typedef void (*lccrt_errmsg_t)( void *data, int errid, const char *fmt, ...); + +/** + * Данные для менеджера вывода сообщений об ошибках и сообщений с предупреждениями. + */ +typedef struct lccrt_err_r +{ + void *data; /* собственные данные менеджера (первый параметр методов) */ + lccrt_errmsg_t error_func; /* функция вывода сообщения об ошибке */ + lccrt_errmsg_t warning_func; /* функция вывода сообщения с предупреждением */ +} lccrt_err_t; + +extern void lccrt_err_init( lccrt_err_t *mem, void *data, + lccrt_errmsg_t error_func, lccrt_errmsg_t warning_func); +extern lccrt_err_ptr lccrt_err_new( lccrt_err_ptr err, void *data, lccrt_errmsg_t err_func, + lccrt_errmsg_t warning_func); +extern lccrt_err_ptr lccrt_err_delete( lccrt_err_ptr err); + +typedef enum +{ + LCCRT_HASH_KEY_INTPTR, + LCCRT_HASH_KEY_STRING, + LCCRT_HASH_KEY_LAST +} lccrt_hash_key_type_t; + +extern int lccrt_exec_with_fork( const char *path, char *argv[], pid_t *wpid, int fds[2]); + +/** + * Тип размещения переменной. + */ +typedef enum +{ + LCCRT_VAR_LOC_GLOB = 0, /* глобальная переменная (модуля) */ + LCCRT_VAR_LOC_EXT, /* декларация глобальной переменной */ + LCCRT_VAR_LOC_CONSTARG, /* глобальная переменная для константных аргументов */ + LCCRT_VAR_LOC_LOCAL, /* локальная переменная (функции) */ + LCCRT_VAR_LOC_ARG, /* параметр функции */ + LCCRT_VAR_LOC_SYSARG, /* (специальный) параметр функции */ + LCCRT_VAR_LOC_ASM, /* основной параметр (описание) asm-вставки */ + LCCRT_VAR_LOC_LAST +} lccrt_var_loc_t; + +#define lccrt_loc_is_ext( l) ((l) == LCCRT_VAR_LOC_EXT) +#define lccrt_loc_is_constarg( l) ((l) == LCCRT_VAR_LOC_CONSTARG) +#define lccrt_loc_is_global( l) \ +( \ + ((l) == LCCRT_VAR_LOC_GLOB) \ + || lccrt_loc_is_constarg( l) \ + || lccrt_loc_is_ext( l) \ +) +#define lccrt_loc_is_local( l) \ +( \ + ((l) == LCCRT_VAR_LOC_LOCAL) \ + || ((l) == LCCRT_VAR_LOC_ARG) \ + || ((l) == LCCRT_VAR_LOC_SYSARG) \ + || lccrt_loc_is_asm( l) \ +) +#define lccrt_loc_is_asm( l) \ +( \ + ((l) == LCCRT_VAR_LOC_ASM) \ +) + +/** + * Тип старшинства при линковке. + */ +typedef enum +{ + LCCRT_LINK_BND_NO = 0, + LCCRT_LINK_BND_GLOBAL, + LCCRT_LINK_BND_WEAK, + LCCRT_LINK_BND_LOCAL, + LCCRT_LINK_BND_LAST +} lccrt_link_bind_t; + +/** + * Тип видимости при линковке. + */ +typedef enum +{ + LCCRT_LINK_VIS_DEFAULT = 0, + LCCRT_LINK_VIS_INTERNAL, + LCCRT_LINK_VIS_HIDDEN, + LCCRT_LINK_VIS_PROTECTED, + LCCRT_LINK_VIS_LAST +} lccrt_link_visibility_t; + +/** + * TLS-тип линковки. + */ +typedef enum +{ + LCCRT_LINK_TLS_NO = 0, + LCCRT_LINK_TLS_DYNAMIC_G, + LCCRT_LINK_TLS_DYNAMIC_L, + LCCRT_LINK_TLS_EXEC_I, + LCCRT_LINK_TLS_EXEC_L, + LCCRT_LINK_TLS_LAST +} lccrt_link_tls_t; + +typedef uint64_t lccrt_link_t; + +/** + * Разновидности флагов инициализации для функции. + */ +typedef enum lccrt_function_init_type_r +{ + LCCRT_FUNC_INIT_NONE, + LCCRT_FUNC_INIT_CTOR, + LCCRT_FUNC_INIT_DTOR, + LCCRT_FUNC_INIT_LAST +} lccrt_function_init_type_t; + +/** + * Названия IR-типов данных. + */ +typedef enum lccrt_type_name_r +{ + LCCRT_TYPE_VOID, + LCCRT_TYPE_BOOL, + LCCRT_TYPE_INT, + LCCRT_TYPE_FLOAT, + LCCRT_TYPE_PTR, + LCCRT_TYPE_ARRAY, + LCCRT_TYPE_VLA_ARRAY, + LCCRT_TYPE_VECTOR, + LCCRT_TYPE_STRUCT, + LCCRT_TYPE_FIELD, + LCCRT_TYPE_FUNC, + LCCRT_TYPE_ELLIPSIS, + LCCRT_TYPE_NAME, + LCCRT_TYPE_LAST +} lccrt_type_name_t; + +/** + * Нумерация целых IR-типов данных. + */ +typedef enum lccrt_type_name_int_r +{ + LCCRT_INT_SUBTYPE_8 = 0, + LCCRT_INT_SUBTYPE_16, + LCCRT_INT_SUBTYPE_32, + LCCRT_INT_SUBTYPE_64, + LCCRT_INT_SUBTYPE_128, + LCCRT_INT_SUBTYPE_LAST +} lccrt_type_name_int_t; + +/** + * Нумерация плавающих IR-типов данных. + */ +typedef enum lccrt_type_name_float_r +{ + LCCRT_FLOAT_SUBTYPE_32 = 0, + LCCRT_FLOAT_SUBTYPE_64, + LCCRT_FLOAT_SUBTYPE_80, + LCCRT_FLOAT_SUBTYPE_128, + LCCRT_FLOAT_SUBTYPE_LAST +} lccrt_type_name_float_t; + +/** + * Виды инициализаторов. + */ +typedef enum +{ + LCCRT_VARINIT_HEX, /* битовое представление скаляра (не более 64-бит) */ + LCCRT_VARINIT_STR, /* строка */ + LCCRT_VARINIT_ARR, /* массив (в том числе структура как массив собственных полей) */ + LCCRT_VARINIT_ZERO, /* инициализация типа нулями */ + LCCRT_VARINIT_ADDR_VAR, /* адрес переменной */ + LCCRT_VARINIT_ADDR_FUNC, /* адрес функции */ + LCCRT_VARINIT_LAST +} lccrt_varinit_inittype_t; + +/** + * Названия операций. + */ +typedef enum +{ + LCCRT_OPER_LABEL, + LCCRT_OPER_CMP, + LCCRT_OPER_BRANCH, + LCCRT_OPER_BRANCHIF, + LCCRT_OPER_SWITCH, + LCCRT_OPER_RET, + LCCRT_OPER_RETVAL, + LCCRT_OPER_CALLPROC, + LCCRT_OPER_CALLFUNC, + LCCRT_OPER_INVOKEPROC, + LCCRT_OPER_INVOKEFUNC, + LCCRT_OPER_LANDINGPAD, + LCCRT_OPER_VA_ARG, + LCCRT_OPER_ALLOCA, + LCCRT_OPER_BITCAST, + LCCRT_OPER_SELECT, + LCCRT_OPER_MOVE, + LCCRT_OPER_VARPTR, + LCCRT_OPER_ELEMPTR, + LCCRT_OPER_ELEMREAD, + LCCRT_OPER_ELEMWRITE, + LCCRT_OPER_SHUFFLE, + LCCRT_OPER_LOAD, + LCCRT_OPER_STORE, + LCCRT_OPER_SEXT, + LCCRT_OPER_ZEXT, + LCCRT_OPER_TRUNC, + LCCRT_OPER_FPTOFP, + LCCRT_OPER_FPTOUI, + LCCRT_OPER_FPTOSI, + LCCRT_OPER_UITOFP, + LCCRT_OPER_SITOFP, + LCCRT_OPER_ADD, + LCCRT_OPER_SUB, + LCCRT_OPER_MUL, + LCCRT_OPER_UDIV, + LCCRT_OPER_SDIV, + LCCRT_OPER_UMOD, + LCCRT_OPER_SMOD, + LCCRT_OPER_SHL, + LCCRT_OPER_SHR, + LCCRT_OPER_SAR, + LCCRT_OPER_AND, + LCCRT_OPER_OR, + LCCRT_OPER_XOR, + LCCRT_OPER_FNEG, + LCCRT_OPER_FADD, + LCCRT_OPER_FMUL, + LCCRT_OPER_FSUB, + LCCRT_OPER_FDIV, + LCCRT_OPER_FMOD, + LCCRT_OPER_LAST +} lccrt_oper_name_t; + +/** + * Операция формирует результат в переменной. + */ +#define lccrt_oper_name_is_res( n) \ +( ((n) == LCCRT_OPER_CMP) \ + || ((n) == LCCRT_OPER_CALLFUNC) \ + || ((n) == LCCRT_OPER_INVOKEFUNC) \ + || ((n) == LCCRT_OPER_LANDINGPAD) \ + || ((n) == LCCRT_OPER_VA_ARG) \ + || ((n) == LCCRT_OPER_ALLOCA) \ + || ((n) == LCCRT_OPER_BITCAST) \ + || ((n) == LCCRT_OPER_SELECT) \ + || ((n) == LCCRT_OPER_MOVE) \ + || ((n) == LCCRT_OPER_VARPTR) \ + || ((n) == LCCRT_OPER_ELEMPTR) \ + || ((n) == LCCRT_OPER_ELEMREAD) \ + || ((n) == LCCRT_OPER_SHUFFLE) \ + || ((n) == LCCRT_OPER_LOAD) \ + || ((n) == LCCRT_OPER_SEXT) \ + || ((n) == LCCRT_OPER_ZEXT) \ + || ((n) == LCCRT_OPER_TRUNC) \ + || ((n) == LCCRT_OPER_FPTOFP) \ + || ((n) == LCCRT_OPER_FPTOUI) \ + || ((n) == LCCRT_OPER_FPTOSI) \ + || ((n) == LCCRT_OPER_UITOFP) \ + || ((n) == LCCRT_OPER_SITOFP) \ + || ((n) == LCCRT_OPER_ADD) \ + || ((n) == LCCRT_OPER_SUB) \ + || ((n) == LCCRT_OPER_MUL) \ + || ((n) == LCCRT_OPER_UDIV) \ + || ((n) == LCCRT_OPER_SDIV) \ + || ((n) == LCCRT_OPER_UMOD) \ + || ((n) == LCCRT_OPER_SMOD) \ + || ((n) == LCCRT_OPER_SHL) \ + || ((n) == LCCRT_OPER_SHR) \ + || ((n) == LCCRT_OPER_SAR) \ + || ((n) == LCCRT_OPER_AND) \ + || ((n) == LCCRT_OPER_OR) \ + || ((n) == LCCRT_OPER_XOR) \ + || ((n) == LCCRT_OPER_FNEG) \ + || ((n) == LCCRT_OPER_FADD) \ + || ((n) == LCCRT_OPER_FSUB) \ + || ((n) == LCCRT_OPER_FMUL) \ + || ((n) == LCCRT_OPER_FDIV) \ + || ((n) == LCCRT_OPER_FMOD) \ +) + +/** + * Детализация типа сравнения. + */ +typedef enum lccrt_cmp_name_r +{ + LCCRT_CMP_EQ, + LCCRT_CMP_NE, + /* Знаковые целочисленные сравнения. */ + LCCRT_CMP_LT_I, + LCCRT_CMP_LE_I, + LCCRT_CMP_GT_I, + LCCRT_CMP_GE_I, + /* Беззнаковые целочисленные сравнения. */ + LCCRT_CMP_LT_U, + LCCRT_CMP_LE_U, + LCCRT_CMP_GT_U, + LCCRT_CMP_GE_U, + /* Плавающие сравнения с проверкой упорядоченности. */ + LCCRT_CMP_FO, + LCCRT_CMP_EQ_FO, + LCCRT_CMP_NE_FO, + LCCRT_CMP_LT_FO, + LCCRT_CMP_LE_FO, + LCCRT_CMP_GT_FO, + LCCRT_CMP_GE_FO, + /* Плавающие сравнения без проверки упорядоченности. */ + LCCRT_CMP_FU, + LCCRT_CMP_EQ_FU, + LCCRT_CMP_NE_FU, + LCCRT_CMP_LT_FU, + LCCRT_CMP_LE_FU, + LCCRT_CMP_GT_FU, + LCCRT_CMP_GE_FU, + LCCRT_CMP_LAST +} lccrt_cmp_name_t; + +/** + * Аргумент операции. + */ +typedef union lccrt_arg_r +{ + lccrt_oper_ptr op; /* аргумент-операция */ + lccrt_var_ptr v; /* аргумент-переменная */ +} lccrt_arg_t; + +/** + * Значение 'val', для которого нужно сделать переход на 'dst'. + */ +typedef struct lccrt_switch_alts_r +{ + lccrt_varinit_ptr val; /* значение */ + lccrt_oper_ptr dst; /* точка перехода */ +} lccrt_switch_alts_t; + +typedef lccrt_context_ptr lccrt_ctx_ptr; +typedef lccrt_plugin_ptr lccrt_plg_ptr; +typedef lccrt_module_ptr lccrt_m_ptr; +typedef lccrt_function_ptr lccrt_f_ptr; +typedef lccrt_function_jit_info_ptr lccrt_fji_ptr; +typedef lccrt_type_ptr lccrt_t_ptr; +typedef lccrt_var_ptr lccrt_v_ptr; +typedef lccrt_varinit_ptr lccrt_vi_ptr; +typedef lccrt_oper_ptr lccrt_o_ptr; +typedef lccrt_oper_iterator_ptr lccrt_oi_ptr; +typedef lccrt_einfo_reference_t lccrt_eir_t; +typedef lccrt_einfo_tydescr_ptr lccrt_eitd_ptr; +typedef lccrt_einfo_category_t lccrt_eic_t; +typedef lccrt_einfo_field_id_t lccrt_eifi_t; + +typedef lccrt_hash_key_type_t lccrt_hkt_t; +typedef struct lccrt_hash_entry_r *lccrt_hash_entry_ptr; +typedef struct lccrt_hash_r *lccrt_hash_ptr; +typedef lccrt_hash_entry_ptr lccrt_he_ptr; +typedef lccrt_hash_ptr lccrt_h_ptr; + +extern lccrt_h_ptr lccrt_hash_new( lccrt_ctx_ptr ctx, lccrt_hkt_t type); +extern void lccrt_hash_delete( lccrt_h_ptr ht); +extern int64_t lccrt_hash_length( lccrt_h_ptr ht); +extern lccrt_he_ptr lccrt_hash_push( lccrt_h_ptr ht, uintptr_t key, int *is_new); +extern lccrt_he_ptr lccrt_hash_find( lccrt_h_ptr ht, uintptr_t key); +extern uintptr_t lccrt_hash_remove( lccrt_he_ptr he); +extern uintptr_t lccrt_hash_get_key( lccrt_he_ptr he); +extern uintptr_t lccrt_hash_get( lccrt_he_ptr he); +extern uintptr_t lccrt_hash_set( lccrt_he_ptr he, uintptr_t data); +extern lccrt_he_ptr lccrt_hash_first( lccrt_h_ptr ht); +extern lccrt_he_ptr lccrt_hash_next( lccrt_he_ptr he); + +/** + * \defgroup tyCtxFns Методы структуры lccrt_context_t + * + * Список основных методов: + * - \ref lccrt_context_new + * - \ref lccrt_context_delete + * - \ref lccrt_context_get_plugin_asm + * - \ref lccrt_context_get_plugin_irrobj + * - \ref lccrt_context_find_plugin_irrobj_for_arch + * - \ref lccrt_context_get_toolchain + * + */ +extern lccrt_ctx_ptr lccrt_context_new( lccrt_mem_ptr mem, lccrt_err_ptr err); +extern void lccrt_context_delete( lccrt_ctx_ptr ctx); +extern int lccrt_context_get_verbose_ir( lccrt_ctx_ptr ctx); +extern void lccrt_context_set_verbose_ir( lccrt_ctx_ptr ctx, int value); +extern const char *lccrt_context_get_toolchain( lccrt_ctx_ptr ctx, const char *asm_lib, + const char *targ, const char *tool_type, + const char *tool_name); +extern lccrt_plg_ptr lccrt_context_get_plugin_asm( lccrt_ctx_ptr ctx, const char *plg_name); +extern lccrt_plg_ptr lccrt_context_get_plugin_irrobj( lccrt_ctx_ptr ctx, const char *plg_name); +extern lccrt_plg_ptr lccrt_context_find_plugin_irrobj_for_arch( lccrt_ctx_ptr ctx, + const char *arch); +extern lccrt_err_t lccrt_context_get_err_info( lccrt_ctx_ptr ctx); +extern lccrt_err_t lccrt_context_set_err_info( lccrt_ctx_ptr ctx, lccrt_err_t err); +#define lccrt_context_error( ctx, id, fmt, ...) \ +({ \ + lccrt_err_t e = lccrt_context_get_err_info( ctx); \ + if ( e.error_func ) \ + { \ + e.error_func( e.data, id, fmt, ##__VA_ARGS__); \ + } \ + 0; \ +}) + +extern lccrt_m_ptr lccrt_module_new( lccrt_ctx_ptr ctx, const char *mname, int is_m32); +extern void lccrt_module_delete( lccrt_m_ptr m); +extern void lccrt_module_rename( lccrt_m_ptr m, const char *new_name); +extern lccrt_ctx_ptr lccrt_module_get_context( lccrt_m_ptr m); +extern const char *lccrt_module_get_name( lccrt_m_ptr m); +extern void *lccrt_module_get_funcs_list( lccrt_m_ptr m); +extern lccrt_t_ptr lccrt_module_get_first_type( lccrt_m_ptr m); +extern lccrt_v_ptr lccrt_module_get_first_var( lccrt_m_ptr m); +extern lccrt_f_ptr lccrt_module_get_first_func( lccrt_m_ptr m); +extern const char *lccrt_module_get_inline_asm( lccrt_m_ptr m); +extern void lccrt_module_set_inline_asm( lccrt_m_ptr m, const char *asm_text); +extern int lccrt_module_apply_jit_support( lccrt_m_ptr m); +extern int lccrt_module_compile_asm( lccrt_m_ptr m, const char *asm_lib, + lccrt_asm_compile_config_t *cnf); +extern int lccrt_module_is_jit( lccrt_m_ptr m); +extern int lccrt_module_is_ptr32( lccrt_module_ptr m); +extern lccrt_f_ptr lccrt_module_find_function( lccrt_m_ptr m, const char *name); +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_einfo_category_t eic); +extern void lccrt_module_set_einfo( lccrt_m_ptr m, lccrt_eic_t eic, lccrt_eir_t value); +extern int lccrt_module_print( lccrt_asm_compile_config_t *acc, lccrt_module_ptr m, int fd); +extern int lccrt_module_print_stdout( lccrt_asm_compile_config_t *acc, lccrt_module_ptr m); +extern lccrt_m_ptr lccrt_module_load( lccrt_ctx_ptr ctx, int fd, lccrt_asm_compile_config_t *acc); + +extern lccrt_einfo_tydescr_ptr lccrt_einfo_tydescr_get_elem( lccrt_eitd_ptr eitd, int elem_k); +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); +extern lccrt_eitd_ptr lccrt_einfo_make_tydescr_union( lccrt_m_ptr m, int num_flds, + lccrt_eitd_ptr *flds_types); +extern lccrt_eifi_t lccrt_einfo_find_tydescr_field( lccrt_einfo_tydescr_ptr eitd, const char *fld_name); +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 lccrt_einfo_tydescr_ptr lccrt_einfo_get_tydescr( lccrt_eir_t einfo); +extern lccrt_einfo_category_t lccrt_einfo_category_empty(); +extern int lccrt_einfo_category_is_valued( lccrt_einfo_category_t ecat); +extern int lccrt_einfo_is_empty( lccrt_eir_t einfo); +extern int lccrt_einfo_is_valued( lccrt_eir_t einfo); +extern int lccrt_einfo_get_num_args( lccrt_eir_t einfo); +extern uint64_t lccrt_einfo_get_i64( lccrt_eir_t einfo); +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); +extern lccrt_eir_t lccrt_einfo_get_elem( lccrt_eir_t einfo, int elem_ident); +extern void lccrt_einfo_set_elem( lccrt_eir_t einfo, int elem_ident, lccrt_eir_t value); +extern void lccrt_einfo_push_elem( lccrt_eir_t einfo, lccrt_eir_t value); +extern uint8_t *lccrt_einfo_get_raw_data( 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); + +extern lccrt_f_ptr lccrt_function_new( lccrt_m_ptr m, lccrt_t_ptr fsig, + const char *fname, const char *asm_fname, + lccrt_link_t link, int is_declaration, + int is_builtin); +extern lccrt_m_ptr lccrt_function_get_module( lccrt_f_ptr func); +extern const char *lccrt_function_get_comdat( lccrt_f_ptr func); +extern void lccrt_function_set_comdat( lccrt_f_ptr func, const char *comdat); +extern lccrt_v_ptr lccrt_function_get_arg( lccrt_f_ptr func, int arg_num); +extern lccrt_v_ptr lccrt_function_get_sysarg( lccrt_f_ptr func, int arg_num); +extern void lccrt_function_set_arg( lccrt_f_ptr func, int k_arg, lccrt_v_ptr arg); +extern void lccrt_function_add_arg( lccrt_f_ptr func, int k_arg, lccrt_v_ptr arg); +extern void lccrt_function_set_sysarg( lccrt_f_ptr func, int k_arg, lccrt_v_ptr arg); +extern void lccrt_function_add_sysarg( lccrt_f_ptr func, int k_arg, lccrt_v_ptr arg); +extern lccrt_link_t lccrt_function_get_link( lccrt_f_ptr func); +extern void lccrt_function_set_link( lccrt_f_ptr func, lccrt_link_t li); +extern void lccrt_function_set_section( lccrt_f_ptr func, const char *section); +extern void lccrt_function_set_init_type( lccrt_f_ptr func, lccrt_function_init_type_t init_type); +extern void lccrt_function_set_init_priority( lccrt_f_ptr func, int priority); +extern int lccrt_function_get_attr_does_not_throw( lccrt_f_ptr func); +extern int lccrt_function_set_attr_does_not_throw( lccrt_f_ptr func, int value); +extern int lccrt_function_get_attr_extern_inline( lccrt_f_ptr func); +extern int lccrt_function_set_attr_extern_inline( lccrt_f_ptr func, int value); +extern int lccrt_function_get_attr_used( lccrt_f_ptr func); +extern int lccrt_function_set_attr_used( lccrt_f_ptr func, int value); +extern int lccrt_function_set_declaration( lccrt_f_ptr func, int is_declaration); +extern lccrt_f_ptr lccrt_function_get_next_func( lccrt_f_ptr func); +extern lccrt_t_ptr lccrt_function_get_type( lccrt_f_ptr func); +extern lccrt_v_ptr lccrt_function_get_arg( lccrt_f_ptr func, int arg_num); +extern const char *lccrt_function_get_name( lccrt_f_ptr func); +extern const char *lccrt_function_get_asm_name( lccrt_f_ptr func); +extern const char *lccrt_function_get_section( lccrt_f_ptr func); +extern lccrt_function_init_type_t lccrt_function_get_init_type( lccrt_f_ptr func); +extern int lccrt_function_get_init_priority( lccrt_f_ptr func); +extern lccrt_fji_ptr lccrt_function_get_jit_info( lccrt_f_ptr func); +extern int lccrt_function_get_num_args( lccrt_f_ptr func); +extern int lccrt_function_get_num_sysargs( lccrt_f_ptr func); +extern lccrt_v_ptr lccrt_function_get_first_var( lccrt_f_ptr func); +extern lccrt_o_ptr lccrt_function_get_first_oper( lccrt_f_ptr func); +extern int lccrt_function_is_var_arg( lccrt_f_ptr f); +extern int lccrt_function_is_declaration( lccrt_f_ptr func); +extern int lccrt_function_is_builtin( lccrt_f_ptr func); +extern int lccrt_function_is_used( lccrt_f_ptr func); +extern int lccrt_function_is_profgen( lccrt_f_ptr func); +extern void lccrt_function_set_einfo( lccrt_f_ptr func, 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 lccrt_v_ptr lccrt_fji_get_profgen_tls( lccrt_fji_ptr fji); +extern lccrt_v_ptr lccrt_fji_get_jit_entry( lccrt_fji_ptr fji); + +extern lccrt_type_name_t lccrt_type_get_name( lccrt_t_ptr type); +extern lccrt_t_ptr lccrt_type_get_next_type( lccrt_t_ptr type); +extern lccrt_t_ptr lccrt_type_get_parent( lccrt_t_ptr type); +extern uint64_t lccrt_type_get_num_args( lccrt_t_ptr type); +extern lccrt_t_ptr lccrt_type_get_arg( lccrt_t_ptr type, int arg_num); +extern uint64_t lccrt_type_get_bytealign( lccrt_t_ptr type); +extern uint64_t lccrt_type_get_bytesize( lccrt_t_ptr type); +extern uint64_t lccrt_type_get_byteshift( lccrt_t_ptr type); +extern uint64_t lccrt_type_get_bitsubshift( lccrt_t_ptr type); +extern uint64_t lccrt_type_get_bitsubsize( lccrt_t_ptr type); +extern lccrt_v_ptr lccrt_type_get_vla_size( lccrt_t_ptr type); +extern int lccrt_type_get_sign( lccrt_t_ptr type); +extern int lccrt_type_is_void( lccrt_t_ptr type); +extern int lccrt_type_is_bool( lccrt_t_ptr type); +extern int lccrt_type_is_int( lccrt_t_ptr type); +extern int lccrt_type_is_float( lccrt_t_ptr type); +extern int lccrt_type_is_pointer( lccrt_t_ptr type); +extern int lccrt_type_is_typename( lccrt_t_ptr type); +extern int lccrt_type_is_ellipsis( lccrt_t_ptr type); +extern int lccrt_type_is_field( lccrt_t_ptr type); +extern int lccrt_type_is_struct( lccrt_t_ptr type); +extern int lccrt_type_is_union( lccrt_t_ptr type); +extern int lccrt_type_is_array( lccrt_t_ptr type); +extern int lccrt_type_is_vector( lccrt_t_ptr type); +extern int lccrt_type_is_function( lccrt_t_ptr type); +extern int lccrt_type_is_class_elems( lccrt_t_ptr type); +extern int lccrt_type_is_class_struct( lccrt_t_ptr type); +extern int lccrt_type_is_function_var_arg( lccrt_t_ptr type); +extern lccrt_type_name_int_t lccrt_type_int_find_by_bitsize( uint64_t bitsize); +extern lccrt_type_name_float_t lccrt_type_float_find_by_bitsize( uint64_t bitsize); + +extern lccrt_t_ptr lccrt_type_make( lccrt_m_ptr m, int type_name, + lccrt_t_ptr parent, lccrt_t_ptr *args, + uint64_t num_args, lccrt_v_ptr vnum, + const char *sym_name, int is_sign, uint64_t bytealign, + uint64_t bytesize, uint64_t byteshift, int bitsubshift, + int bitsubsize, int is_union); +extern int lccrt_type_print( lccrt_t_ptr type, int is_ln); +extern void lccrt_type_set_parent( lccrt_t_ptr ty, lccrt_t_ptr pt); +extern void lccrt_type_set_arg( lccrt_t_ptr ty, int arg_num, lccrt_t_ptr arg); +extern void lccrt_type_set_typename_bytesize( lccrt_t_ptr ty, uint64_t bytesize); +extern void lccrt_type_set_typename_bytealign( lccrt_t_ptr ty, uint64_t bytealign); +extern lccrt_m_ptr lccrt_type_get_module( lccrt_t_ptr ty); +extern lccrt_t_ptr lccrt_type_make_void( lccrt_m_ptr m); +extern lccrt_t_ptr lccrt_type_make_bool( lccrt_m_ptr m); +extern lccrt_t_ptr lccrt_type_make_ellipsis( lccrt_m_ptr m); +extern lccrt_t_ptr lccrt_type_make_int( lccrt_m_ptr m, uint64_t bytesize, int sign); +extern lccrt_t_ptr lccrt_type_make_float( lccrt_m_ptr m, uint64_t bytesize); +extern lccrt_t_ptr lccrt_type_make_intptr( lccrt_m_ptr m); +extern lccrt_t_ptr lccrt_type_make_pintptr( lccrt_m_ptr m); +extern lccrt_t_ptr lccrt_type_make_pvoid( lccrt_m_ptr m); +extern lccrt_t_ptr lccrt_type_make_pbyte( lccrt_m_ptr m); +extern lccrt_t_ptr lccrt_type_make_pchar( lccrt_m_ptr m); +#define lccrt_type_make_u8( m) lccrt_type_make_int( m, 1, 0) +#define lccrt_type_make_u16( m) lccrt_type_make_int( m, 2, 0) +#define lccrt_type_make_u32( m) lccrt_type_make_int( m, 4, 0) +#define lccrt_type_make_u64( m) lccrt_type_make_int( m, 8, 0) +#define lccrt_type_make_u128( m) lccrt_type_make_int( m, 16, 0) +#define lccrt_type_make_f32( m) lccrt_type_make_float( m, 4) +#define lccrt_type_make_f64( m) lccrt_type_make_float( m, 8) +extern lccrt_t_ptr lccrt_type_make_ptr_type( lccrt_t_ptr parent); +extern lccrt_t_ptr lccrt_type_make_func( lccrt_t_ptr ret_type, int num_args, + lccrt_t_ptr *args); +extern lccrt_t_ptr lccrt_type_make_array( lccrt_t_ptr elem, uint64_t num_elems); +extern lccrt_t_ptr lccrt_type_make_vector( lccrt_t_ptr elem, uint64_t num_elems); +extern lccrt_t_ptr lccrt_type_make_vla( lccrt_t_ptr elem, lccrt_v_ptr vnum); +extern lccrt_t_ptr lccrt_type_make_field( lccrt_t_ptr parent, uint64_t bytealign, uint64_t byteshift, + int bitsubshift, int bitsubsize); +extern lccrt_t_ptr lccrt_type_make_struct( lccrt_m_ptr m, uint64_t bytealign, uint64_t bytesize, + int num_flds, lccrt_t_ptr *flds, int is_union); +extern lccrt_t_ptr lccrt_type_make_typename( lccrt_m_ptr m, const char *name, + lccrt_t_ptr type); +#define lccrt_type_make_ptypename( m, name) \ + ( \ + lccrt_type_make_ptr_type( lccrt_type_make_typename( m, name, 0)) \ + ) + +extern lccrt_link_t lccrt_link_get( lccrt_link_bind_t bind, lccrt_link_visibility_t vis, + lccrt_link_tls_t tls, int is_cnst, int is_alias); +extern lccrt_link_tls_t lccrt_link_get_tls( lccrt_link_t link); +extern lccrt_link_bind_t lccrt_link_get_bnd( lccrt_link_t link); +extern lccrt_link_visibility_t lccrt_link_get_vis( lccrt_link_t link); +extern int lccrt_link_is_alias( lccrt_link_t link); +extern int lccrt_link_is_const( lccrt_link_t link); + +extern lccrt_v_ptr lccrt_var_new( void *holder, lccrt_var_loc_t loc, + lccrt_t_ptr type, const char *name, + const char *asm_name, lccrt_link_t link, + unsigned align); +extern void lccrt_var_delete( lccrt_v_ptr var); +extern lccrt_v_ptr lccrt_var_new_local( lccrt_f_ptr f, lccrt_t_ptr type, + const char *name); +extern lccrt_v_ptr lccrt_var_new_asm( lccrt_f_ptr f, lccrt_t_ptr type, + const char *asm_text, const char *asm_cnstr); +extern lccrt_v_ptr lccrt_var_new_declaration( lccrt_m_ptr m, lccrt_t_ptr type, + const char *name, lccrt_link_t link); +extern lccrt_v_ptr lccrt_var_new_constarg( lccrt_m_ptr m, lccrt_t_ptr type, lccrt_vi_ptr vi); +extern lccrt_v_ptr lccrt_var_new_constarg_hex( lccrt_m_ptr m, lccrt_t_ptr type, uint64_t value); +extern lccrt_v_ptr lccrt_var_new_constarg_str( lccrt_m_ptr m, uint64_t s_len, const char *s); + +extern const char *lccrt_var_get_comdat( lccrt_v_ptr var); +extern const char *lccrt_var_get_section( lccrt_v_ptr v); +extern lccrt_link_t lccrt_var_get_link( lccrt_v_ptr var); +extern int lccrt_var_get_attr_common( lccrt_v_ptr var); +extern int lccrt_var_get_attr_used( lccrt_v_ptr var); +extern int lccrt_var_get_attr_restrict( lccrt_v_ptr var); +extern const char *lccrt_var_get_name( lccrt_v_ptr var); +extern const char *lccrt_var_get_asm_name( lccrt_v_ptr var); +extern lccrt_link_t lccrt_var_get_link( lccrt_v_ptr var); +extern unsigned lccrt_var_get_align( lccrt_v_ptr var); +extern lccrt_var_loc_t lccrt_var_get_loc( lccrt_v_ptr var); + +extern void lccrt_var_set_comdat( lccrt_v_ptr var, const char *comdat); +extern void lccrt_var_set_section( lccrt_v_ptr v, const char *section_name); +extern lccrt_link_t lccrt_var_set_link( lccrt_v_ptr var, lccrt_link_t li); +extern int lccrt_var_set_attr_common( lccrt_v_ptr var, int value); +extern int lccrt_var_set_attr_used( lccrt_v_ptr var, int value); +extern int lccrt_var_set_attr_restrict( lccrt_v_ptr var, int value); + +extern lccrt_m_ptr lccrt_var_get_module( lccrt_v_ptr var); +extern lccrt_t_ptr lccrt_var_get_type( lccrt_v_ptr var); +extern uint64_t lccrt_var_get_bytesize( lccrt_v_ptr var); +extern lccrt_vi_ptr lccrt_var_get_init_value( lccrt_v_ptr var); +extern lccrt_v_ptr lccrt_var_get_next_var( lccrt_v_ptr var); +extern uint64_t lccrt_var_get_constarg_hex64( lccrt_v_ptr v); +extern int64_t lccrt_var_get_constarg_int64( lccrt_v_ptr v); +extern const char *lccrt_var_get_constarg_str( lccrt_v_ptr v); +extern lccrt_f_ptr lccrt_var_get_constarg_func( lccrt_v_ptr v); +extern lccrt_t_ptr lccrt_var_expand_array( lccrt_v_ptr var, lccrt_t_ptr type); +extern void lccrt_var_set_init_value( lccrt_v_ptr v, lccrt_vi_ptr iv); +extern void lccrt_var_set_init_value_reduce( lccrt_v_ptr v, lccrt_vi_ptr iv); +extern void lccrt_var_set_einfo( lccrt_v_ptr v, 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 int lccrt_var_is_local( lccrt_v_ptr v); +extern int lccrt_var_is_global( lccrt_v_ptr v); +extern int lccrt_var_is_const( lccrt_var_ptr var); +extern int lccrt_var_is_constarg( lccrt_v_ptr v); +extern int lccrt_var_is_constarg_hex( lccrt_v_ptr v); +extern int lccrt_var_is_constarg_int( lccrt_v_ptr v); +extern int lccrt_var_is_constarg_addr_var( lccrt_v_ptr v); +extern int lccrt_var_is_constarg_addr_func( lccrt_v_ptr v); + +extern lccrt_vi_ptr lccrt_varinit_new_zero( lccrt_t_ptr type); +extern lccrt_vi_ptr lccrt_varinit_new_scalar( lccrt_t_ptr type, uint64_t value); +extern lccrt_vi_ptr lccrt_varinit_new_str( lccrt_t_ptr type, uint64_t value_len, + const char *value); +extern lccrt_vi_ptr lccrt_varinit_new_array( lccrt_t_ptr type, uint64_t num_init_elems, + lccrt_vi_ptr *init_data); +extern lccrt_vi_ptr lccrt_varinit_new_addr_var( lccrt_v_ptr var, uint64_t shift); +extern lccrt_vi_ptr lccrt_varinit_new_addr_func( lccrt_f_ptr func, uint64_t shift); + +extern lccrt_t_ptr lccrt_varinit_get_type( lccrt_vi_ptr vi); +extern lccrt_varinit_inittype_t lccrt_varinit_get_inittype( lccrt_vi_ptr vi); +extern uint64_t lccrt_varinit_get_num_elems( lccrt_vi_ptr vi); +extern uint64_t lccrt_varinit_get_hex64( lccrt_vi_ptr vi); +extern uint64_t lccrt_varinit_get_zero_or_hex64( lccrt_vi_ptr vi); +extern const char *lccrt_varinit_get_str( lccrt_vi_ptr vi); +extern lccrt_vi_ptr lccrt_varinit_get_elem( lccrt_vi_ptr vi, uint64_t elem_num); +extern lccrt_v_ptr lccrt_varinit_get_addr_var( lccrt_vi_ptr vi); +extern lccrt_f_ptr lccrt_varinit_get_addr_func( lccrt_vi_ptr vi); +extern int lccrt_varinit_is_hex( lccrt_vi_ptr vi); +extern int lccrt_varinit_is_zero( lccrt_vi_ptr vi); +extern int lccrt_varinit_is_zero_or_hex( lccrt_vi_ptr vi); +extern int lccrt_varinit_is_array( lccrt_vi_ptr vi); +extern int lccrt_varinit_is_str( lccrt_vi_ptr vi); +extern int lccrt_varinit_is_addr_var( lccrt_vi_ptr vi); +extern int lccrt_varinit_is_addr_func( lccrt_vi_ptr vi); + +extern lccrt_oi_ptr lccrt_oper_iterator_new( lccrt_ctx_ptr ctx); +extern lccrt_oi_ptr lccrt_oper_iterator_delete( lccrt_oi_ptr iter); +extern lccrt_oi_ptr lccrt_oper_iterator_set( lccrt_oi_ptr iter, lccrt_o_ptr oper); +extern lccrt_oi_ptr lccrt_oper_iterator_set_prev( lccrt_oi_ptr iter, lccrt_o_ptr oper); +extern lccrt_o_ptr lccrt_oper_iterator_get_prev( lccrt_oi_ptr iter); +extern lccrt_o_ptr lccrt_oper_iterator_get_next( lccrt_oi_ptr iter); +extern lccrt_v_ptr lccrt_oper_iterator_get_res( lccrt_oper_ptr iter); +#define lccrt_oper_iterator_get_next_res( i) \ +( \ + lccrt_oper_iterator_get_res( lccrt_oper_iterator_get_next( i)) \ +) +extern lccrt_o_ptr lccrt_oper_iterator_shift( lccrt_oi_ptr i); + +extern lccrt_oper_name_t lccrt_oper_get_name( lccrt_o_ptr oper); +extern lccrt_t_ptr lccrt_oper_get_type( lccrt_o_ptr oper); +extern int lccrt_oper_get_num_args( lccrt_o_ptr oper); +extern int lccrt_oper_get_num_sysargs( lccrt_o_ptr oper); +extern lccrt_o_ptr lccrt_oper_get_arg_oper( lccrt_o_ptr oper, int arg_num); +extern lccrt_v_ptr lccrt_oper_get_arg_var( lccrt_o_ptr oper, int arg_num); +extern void lccrt_oper_set_arg_var( lccrt_o_ptr oper, int arg_num, lccrt_v_ptr arg); +extern void lccrt_oper_set_arg_oper( lccrt_o_ptr oper, int arg_num, lccrt_o_ptr arg); +extern lccrt_o_ptr lccrt_oper_get_prev( lccrt_o_ptr oper); +extern lccrt_o_ptr lccrt_oper_get_next( lccrt_o_ptr oper); +extern lccrt_v_ptr lccrt_oper_get_res( lccrt_o_ptr oper); +extern void lccrt_oper_set_res( lccrt_o_ptr oper, lccrt_v_ptr res); +extern int lccrt_oper_is_atomic( lccrt_o_ptr oper); +extern int lccrt_oper_is_volatile( lccrt_o_ptr oper); +extern int lccrt_oper_is_cleanup( lccrt_o_ptr oper); +extern lccrt_o_ptr lccrt_oper_invoke_get_normal( lccrt_o_ptr oper); +extern lccrt_o_ptr lccrt_oper_invoke_get_unwind( lccrt_o_ptr oper); +extern void lccrt_oper_invoke_set_normal( lccrt_o_ptr oper, lccrt_o_ptr normal); +extern void lccrt_oper_invoke_set_unwind( lccrt_o_ptr oper, lccrt_o_ptr unwind); + +extern int lccrt_oper_name_is_arg_var( lccrt_oper_name_t name, int arg_num); +extern int lccrt_oper_name_is_arg_oper( lccrt_oper_name_t name, int arg_num); + +extern lccrt_o_ptr lccrt_oper_new( lccrt_f_ptr f, int oper_name, lccrt_t_ptr type, + int num_args, lccrt_arg_t *args, int num_sysargs, + lccrt_v_ptr res, lccrt_oi_ptr i); +extern int lccrt_oper_print( lccrt_o_ptr oper, int is_ln); +extern int lccrt_oper_snprint( lccrt_o_ptr op, int is_ln, char *s, int l); +extern void lccrt_oper_set_volatile( lccrt_oper_ptr oper, int value); +extern void lccrt_oper_set_atomic( lccrt_oper_ptr oper, int value); +extern void lccrt_oper_set_cleanup( lccrt_oper_ptr oper, int value); +extern int lccrt_oper_is_branch( lccrt_oper_ptr o); +extern int lccrt_oper_is_switch( lccrt_oper_ptr o); +extern int lccrt_oper_is_call( lccrt_oper_ptr o); +extern int lccrt_oper_is_invoke( lccrt_oper_ptr o); +extern int lccrt_oper_is_landingpad( lccrt_oper_ptr o); +extern int lccrt_oper_is_label( lccrt_oper_ptr o); +extern int lccrt_oper_is_ret( lccrt_oper_ptr o); +extern int lccrt_oper_is_retval( lccrt_oper_ptr o); +extern void lccrt_oper_delete( lccrt_o_ptr o); +extern lccrt_f_ptr lccrt_oper_get_function( lccrt_o_ptr oper); +extern lccrt_t_ptr lccrt_oper_get_res_type( lccrt_o_ptr oper); +extern const char *lccrt_oper_get_label( lccrt_o_ptr oper); +extern lccrt_o_ptr lccrt_oper_new_label( lccrt_f_ptr func, const char *name, + lccrt_oi_ptr iter); +extern lccrt_o_ptr lccrt_oper_new_branch( lccrt_f_ptr func, lccrt_oper_ptr dst, + lccrt_oi_ptr iter); +extern lccrt_o_ptr lccrt_oper_new_branchif( lccrt_f_ptr func, lccrt_v_ptr predct, + lccrt_o_ptr dst_true, lccrt_o_ptr dst_false, + lccrt_oi_ptr iter); +extern lccrt_o_ptr lccrt_oper_new_switch( lccrt_f_ptr f, lccrt_v_ptr pa, int num_alts, + lccrt_switch_alts_t *alts, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_va_arg( lccrt_f_ptr f, lccrt_v_ptr pa, lccrt_t_ptr pt, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_alloca( lccrt_f_ptr f, lccrt_v_ptr pa, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_cmp( lccrt_f_ptr f, lccrt_varinit_ptr pn, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pres, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_load( lccrt_f_ptr f, lccrt_v_ptr pa, lccrt_v_ptr pres, + lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_store( lccrt_f_ptr f, lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_sext( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr r, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_zext( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr r, lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_trunc( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr r, lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_fptofp( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr r, lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_fptoui( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr r, lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_fptosi( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr r, lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_uitofp( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr r, lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_sitofp( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr r, lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_bitcast( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr r, lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_select( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, + lccrt_v_ptr c, lccrt_v_ptr r, lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_move( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr r, + lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_varptr( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr r, + lccrt_oi_ptr i); +extern lccrt_o_ptr lccrt_oper_new_add( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_sub( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_mul( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_udiv( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_sdiv( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_umod( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_smod( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_shl( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_shr( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_sar( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_and( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_or( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_xor( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_fneg( lccrt_f_ptr f, + lccrt_v_ptr pa, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_fadd( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_fsub( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_fmul( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_fdiv( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_fmod( lccrt_f_ptr f, + lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pr, lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_return( lccrt_f_ptr f, lccrt_v_ptr pa, + lccrt_oi_ptr pi); +extern lccrt_o_ptr lccrt_oper_new_call( lccrt_f_ptr func, lccrt_t_ptr sig, int num_args, + lccrt_v_ptr *args, int num_sysargs, + lccrt_v_ptr *sysargs, lccrt_v_ptr res, + lccrt_oi_ptr iter); +extern lccrt_o_ptr lccrt_oper_new_invoke( lccrt_f_ptr func, lccrt_t_ptr sig, int num_args, + lccrt_v_ptr *args, int num_sysargs, + lccrt_v_ptr *sysargs, lccrt_o_ptr normal, + lccrt_o_ptr unwind, lccrt_v_ptr res, + lccrt_oi_ptr iter); +extern lccrt_o_ptr lccrt_oper_new_landingpad( lccrt_f_ptr func, int num_args, + lccrt_v_ptr *args, lccrt_t_ptr t, + lccrt_v_ptr res, lccrt_oi_ptr iter); +extern lccrt_o_ptr lccrt_oper_new_elemptr( lccrt_f_ptr func, + int num_args, lccrt_v_ptr *args, lccrt_v_ptr res, + lccrt_oi_ptr iter); +extern lccrt_o_ptr lccrt_oper_new_elemread( lccrt_f_ptr func, int num_args, + lccrt_v_ptr *args, lccrt_v_ptr res, + lccrt_oi_ptr iter); +extern lccrt_o_ptr lccrt_oper_new_elemwrite( lccrt_f_ptr func, int num_args, + lccrt_v_ptr *args, lccrt_oi_ptr iter); +extern lccrt_o_ptr lccrt_oper_new_shuffle( lccrt_f_ptr func, lccrt_v_ptr pa, lccrt_v_ptr pb, + lccrt_v_ptr pm, lccrt_v_ptr pr, lccrt_oi_ptr iter); +extern void lccrt_oper_set_einfo( lccrt_o_ptr oper, 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 lccrt_fs_ptr lccrt_fs_new_file( lccrt_ctx_ptr ctx, FILE *file); +extern lccrt_fs_ptr lccrt_fs_open_file( lccrt_ctx_ptr ctx, const char *name, int is_load); +extern lccrt_fs_ptr lccrt_fs_new_buffer( lccrt_ctx_ptr ctx, char *buff, uint64_t buff_size); +extern int lccrt_fs_delete( lccrt_fs_ptr f); +extern char *lccrt_fs_get_buffer( lccrt_fs_ptr f); +extern void lccrt_asm_print_module( lccrt_fs_ptr fs, lccrt_module_ptr m); + +typedef lccrt_irr_jit_region_ptr lccrt_irr_jr_ptr; +typedef lccrt_irr_execute_context_ptr lccrt_irr_ec_ptr; +typedef lccrt_irr_code_ptr lccrt_irr_c_ptr; +typedef lccrt_irr_node_ptr lccrt_irr_n_ptr; +typedef lccrt_irr_oper_ptr lccrt_irr_o_ptr; +typedef lccrt_irr_oper_iter_ptr lccrt_irr_oi_ptr; +typedef lccrt_irr_arg_ptr lccrt_irr_a_ptr; +typedef lccrt_irr_reg_ptr lccrt_irr_r_ptr; +typedef lccrt_irr_label_ptr lccrt_irr_l_ptr; +typedef lccrt_irr_reloc_ptr lccrt_irr_rl_ptr; +typedef lccrt_irr_reloc_unit_ptr lccrt_irr_rlu_ptr; +typedef lccrt_irr_resolve_virt_addr_func_t lccrt_irr_rva_func_t; + +#define LCCRT_IRR_TYPE_REGS_MAX (256ULL) +#define LCCRT_IRR_ARG_GET_REG_TYPE( a) ((a)->data.hex / LCCRT_IRR_TYPE_REGS_MAX) +#define LCCRT_IRR_ARG_GET_REG_ADDR( a) ((a)->data.hex % LCCRT_IRR_TYPE_REGS_MAX) +#define LCCRT_IRR_ARG_IS_REG( a, rtype, raddr) \ +( \ + ((a)->type == LCCRT_IRR_ARG_TYPE_REG) \ + && (LCCRT_IRR_ARG_GET_REG_TYPE( a) == rtype) \ + && (LCCRT_IRR_ARG_GET_REG_ADDR( a) == raddr) \ +) + +typedef enum +{ + LCCRT_IRR_REG_SYS, + LCCRT_IRR_REG_PHYS, + LCCRT_IRR_REG_VIRT, + LCCRT_IRR_REG_TYPE_LAST +} lccrt_irr_reg_type_t; + +typedef enum +{ + LCCRT_IRR_OPER_NOP, + LCCRT_IRR_OPER_ASSERT, + LCCRT_IRR_OPER_MOV_U32, + LCCRT_IRR_OPER_MOV_U64, + LCCRT_IRR_OPER_AND_U64, + LCCRT_IRR_OPER_OR_U64, + LCCRT_IRR_OPER_XOR_U64, + LCCRT_IRR_OPER_SHL_U64, + LCCRT_IRR_OPER_SHR_U64, + LCCRT_IRR_OPER_SAR_U64, + //LCCRT_IRR_OPER_SCL_U64, + //LCCRT_IRR_OPER_SCR_U64, + LCCRT_IRR_OPER_ADD_U64, + LCCRT_IRR_OPER_SUB_U64, + LCCRT_IRR_OPER_MUL_U64, + LCCRT_IRR_OPER_SDIV_U64, + LCCRT_IRR_OPER_UDIV_U64, + LCCRT_IRR_OPER_SMOD_U64, + LCCRT_IRR_OPER_UMOD_U64, + LCCRT_IRR_OPER_EXT_S8, + LCCRT_IRR_OPER_EXT_S16, + LCCRT_IRR_OPER_EXT_S32, + /* Взятие битового поля + arg0 (int64) - источник битового поля + arg1 (int64) - битовое смещение поля + arg2 (int64) - битовая длина поля */ + LCCRT_IRR_OPER_GETFIELD, + LCCRT_IRR_OPER_CONV_S32_F32, + LCCRT_IRR_OPER_CONV_S32_F64, + LCCRT_IRR_OPER_CONV_S64_F32, + LCCRT_IRR_OPER_CONV_S64_F64, + LCCRT_IRR_OPER_CONV_F32_F64, + LCCRT_IRR_OPER_CONV_F64_F32, + LCCRT_IRR_OPER_FADD_F32, + LCCRT_IRR_OPER_FADD_F64, + LCCRT_IRR_OPER_FSUB_F32, + LCCRT_IRR_OPER_FSUB_F64, + LCCRT_IRR_OPER_FMUL_F32, + LCCRT_IRR_OPER_FMUL_F64, + LCCRT_IRR_OPER_FDIV_F32, + LCCRT_IRR_OPER_FDIV_F64, + LCCRT_IRR_OPER_FSQRT_F64, + LCCRT_IRR_OPER_CMPE_U64, + LCCRT_IRR_OPER_CMPNE_U64, + LCCRT_IRR_OPER_CMPL_U64, + LCCRT_IRR_OPER_CMPLE_U64, + LCCRT_IRR_OPER_CMPB_U64, + LCCRT_IRR_OPER_CMPBE_U64, + /* Сравнение формата float64 на "не упорядочено" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float32/float64)arg0 vs (bitcast float32/float64)arg1)) */ + LCCRT_IRR_OPER_FCMP_U_F32, + LCCRT_IRR_OPER_FCMP_U_F64, + /* Сравнение формата float64 на "упорядочено" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float32/float64)arg0 vs (bitcast float32/float64)arg1)) */ + LCCRT_IRR_OPER_FCMP_O_F32, + LCCRT_IRR_OPER_FCMP_O_F64, + /* Сравнение формата float64 на "равно или не упорядочено" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float64)arg0 == (bitcast float64)arg1) || unordered) */ + LCCRT_IRR_OPER_FCMPE_U_F64, + /* Сравнение формата float64 на "равно" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float32/float64)arg0 == (bitcast float32/float64)arg1)) */ + LCCRT_IRR_OPER_FCMPE_O_F32, + LCCRT_IRR_OPER_FCMPE_O_F64, + /* Сравнение формата float64 на "равно или не упорядочено" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float64)arg0 < (bitcast float64)arg1) || unordered) */ + LCCRT_IRR_OPER_FCMPL_U_F64, + /* Сравнение формата float64 на "равно" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float32/float64)arg0 < (bitcast float32/float64)arg1)) */ + LCCRT_IRR_OPER_FCMPL_O_F32, + LCCRT_IRR_OPER_FCMPL_O_F64, + /* Сравнение формата float64 на "равно или не упорядочено" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float64)arg0 <= (bitcast float64)arg1) || unordered) */ + LCCRT_IRR_OPER_FCMPLE_U_F64, + /* Сравнение формата float64 на "равно" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float32/float64)arg0 <= (bitcast float32/float64)arg1)) */ + LCCRT_IRR_OPER_FCMPLE_O_F32, + LCCRT_IRR_OPER_FCMPLE_O_F64, + /* Выбор значения + arg0 (int64) - итоговое значение, если arg2 == true + arg1 (int64) - итоговое значение, если arg2 == false + arg2 (int64) - предикат выбора + res0 (int64) - (arg2 ? arg0 : arg1) */ + LCCRT_IRR_OPER_SELECT_U64, + /* Условная перессылка, если предикат true + arg0 (int64) - итоговое значение, если arg1 == true + arg1 (int64) - предикат выбора + res0 (int64) - (if ( arg1 ) res0 = arg1;) */ + LCCRT_IRR_OPER_MOVTHEN_U64, + /* Условная перессылка, если предикат false + arg0 (int64) - итоговое значение, если arg1 == false + arg1 (int64) - предикат выбора + res0 (int64) - (if ( !arg1 ) res0 = arg1;) */ + LCCRT_IRR_OPER_MOVELSE_U64, + LCCRT_IRR_OPER_LD_U8, + LCCRT_IRR_OPER_LD_U16, + LCCRT_IRR_OPER_LD_U32, + LCCRT_IRR_OPER_LD_U64, + LCCRT_IRR_OPER_LD_S8, + LCCRT_IRR_OPER_LD_S16, + LCCRT_IRR_OPER_LD_S32, + LCCRT_IRR_OPER_ST_U8, + LCCRT_IRR_OPER_ST_U16, + LCCRT_IRR_OPER_ST_U32, + LCCRT_IRR_OPER_ST_U64, + /* Безусловный переход по литералу "ленивой" линковки + arg0 (reloc) - литерал перехода */ + LCCRT_IRR_OPER_BRANCH_RELOC, + /* Условный переход по литералам "ленивой" линковки + arg0 (reloc) - литерал перехода, если arg2 == true + arg1 (reloc) - литерал перехода, если arg2 == false + arg2 (int64) - предикат перехода */ + LCCRT_IRR_OPER_BRANCHIF_RELOC, + /* Безусловный переход по виртуальному адресу + arg0 (int64) - виртуальный адрес перехода */ + LCCRT_IRR_OPER_BRANCH_DYNAMIC, + /* Выполнить вызов функции void (*)( int64, int64) + arg0 (int64) - адрес вызываемой функции + arg1 (int64) - 1-ый аргумент + arg2 (int64) - 2-ой аргумент */ + LCCRT_IRR_OPER_CALL_V_U64U64, + /* Завершить исполнение + arg0 (int64) - возвращаемое значение (через контекст исполнения) */ + LCCRT_IRR_OPER_EXIT, + /* Адресуемая метка */ + LCCRT_IRR_OPER_LABEL, + /* Проверить совпадение байтовых массивов и вызвать исключение (abort), + если массивы не равны + arg0 (int64) - байтовый размер массивов + arg1 (int64) - адрес первого массива + arg2 (int64) - адрес второго массива */ + LCCRT_IRR_OPER_TESTCODE, + /* Вызвать функцию обработчик особой ситуации + arg0 (int64) - адрес функции обработчика + arg1 (int64) - первый аргумент + arg2 (int64) - второй аргумент */ + LCCRT_IRR_OPER_BREAKPOINT, + LCCRT_IRR_OPER_LAST +} lccrt_irr_oper_name_t; + +#define lccrt_irr_oper_name_is_res( n) \ +( \ + (LCCRT_IRR_OPER_ASSERT < (n)) && ((n) <= LCCRT_IRR_OPER_LD_S32) \ +) + +#define lccrt_irr_oper_name_is_arith( n) \ +( \ + (LCCRT_IRR_OPER_NOP <= (n)) && ((n) <= LCCRT_IRR_OPER_MOVELSE_U64) \ +) + +#define lccrt_irr_oper_name_is_load( n) \ +( \ + ((LCCRT_IRR_OPER_LD_U8 <= (n)) && ((n) <= LCCRT_IRR_OPER_LD_U64)) \ +) + +#define lccrt_irr_oper_name_is_store( n) \ +( \ + ((LCCRT_IRR_OPER_ST_U8 <= (n)) && ((n) <= LCCRT_IRR_OPER_ST_U64)) \ +) + +#define lccrt_irr_oper_name_is_branch( n) \ +( \ + ((LCCRT_IRR_OPER_BRANCH_RELOC <= (n)) && ((n) <= LCCRT_IRR_OPER_BRANCH_DYNAMIC)) \ +) + +#define lccrt_irr_oper_name_is_exit( n) \ +( \ + ((LCCRT_IRR_OPER_EXIT <= (n)) && ((n) <= LCCRT_IRR_OPER_EXIT)) \ +) + +extern lccrt_irr_jr_ptr lccrt_irr_jit_region_new( lccrt_ctx_ptr ctx, const char *arch, lccrt_plg_ptr plg); +extern lccrt_irr_c_ptr lccrt_irr_code_new( lccrt_irr_jr_ptr jr, lccrt_irr_n_ptr node); +extern lccrt_irr_n_ptr lccrt_irr_node_new( lccrt_irr_jr_ptr jr, int64_t user_ident); +extern lccrt_irr_ec_ptr lccrt_irr_exec_ctx_new( lccrt_irr_jr_ptr jr, int max_regs[LCCRT_IRR_REG_TYPE_LAST], + uint64_t *regs[LCCRT_IRR_REG_TYPE_LAST]); +extern lccrt_irr_r_ptr lccrt_irr_reg_new( lccrt_irr_jr_ptr jr); +extern lccrt_irr_a_ptr lccrt_irr_arg_new( lccrt_irr_jr_ptr jr); +extern lccrt_irr_oi_ptr lccrt_irr_oper_iter_new( lccrt_irr_jr_ptr jr, lccrt_irr_n_ptr node); +extern lccrt_irr_rl_ptr lccrt_irr_reloc_new( lccrt_irr_jr_ptr jr, int64_t virt_addr, lccrt_irr_c_ptr code); +extern void lccrt_irr_reloc_delete( lccrt_irr_rl_ptr rel); +extern void lccrt_irr_exec_ctx_delete( lccrt_irr_ec_ptr ec); +extern void lccrt_irr_node_delete( lccrt_irr_n_ptr node); +extern void lccrt_irr_reg_delete( lccrt_ctx_ptr ctx, lccrt_irr_r_ptr arg); +extern void lccrt_irr_arg_delete( lccrt_ctx_ptr ctx, lccrt_irr_a_ptr arg); +extern void lccrt_irr_oper_iter_delete( lccrt_irr_oi_ptr oi); + +extern lccrt_ctx_ptr lccrt_irr_jit_region_get_context( lccrt_irr_jr_ptr jr); +extern lccrt_plg_ptr lccrt_irr_jit_region_get_plugin_irrobj( lccrt_irr_jr_ptr jr); +extern lccrt_irr_n_ptr lccrt_irr_jit_region_get_virt_addr_node( lccrt_irr_jr_ptr jr, uint64_t vaddr); +extern uint64_t lccrt_irr_jit_region_get_virt_addr_data( lccrt_irr_jr_ptr jr, uint64_t vaddr); +extern void lccrt_irr_jit_region_set_virt_addr_node( lccrt_irr_jr_ptr jr, uint64_t vaddr, lccrt_irr_n_ptr node); +extern void lccrt_irr_jit_region_set_virt_addr_data( lccrt_irr_jr_ptr jr, uint64_t vaddr, uint64_t data); +extern lccrt_irr_rva_func_t lccrt_irr_jit_region_get_ra_func( lccrt_irr_jr_ptr jr); +extern void *lccrt_irr_jit_region_get_ra_data( lccrt_irr_jr_ptr jr); +extern void **lccrt_irr_jit_region_get_ra_table0( lccrt_irr_jr_ptr jr); +extern int lccrt_irr_jit_region_get_ra_level( lccrt_irr_jr_ptr jr); +extern int lccrt_irr_jit_region_get_ra_bits( lccrt_irr_jr_ptr jr); +extern int lccrt_irr_jit_region_get_ra_tail_bits( lccrt_irr_jr_ptr jr); +extern void lccrt_irr_jit_region_set_ra_func( lccrt_irr_jr_ptr jr, lccrt_irr_rva_func_t func, void *data); +extern void lccrt_irr_jit_region_set_ra_table( lccrt_irr_jr_ptr jr, void **table0, int level, int bits, int tail_bits); +extern int lccrt_irr_jit_region_is_debug_exit_all( lccrt_irr_jr_ptr jr); +extern void lccrt_irr_jit_region_set_debug_exit_all( lccrt_irr_jr_ptr jr, int value); + +extern lccrt_irr_jr_ptr lccrt_irr_exec_ctx_get_jit_region( lccrt_irr_ec_ptr ec); +extern int lccrt_irr_exec_ctx_get_reg_max( lccrt_irr_ec_ptr ec, lccrt_irr_reg_type_t type); +/*extern uint64_t lccrt_irr_exec_ctx_get_reg( lccrt_irr_ec_ptr ec, lccrt_irr_reg_type_t type, + int64_t num); +extern uint64_t lccrt_irr_exec_ctx_set_reg( lccrt_irr_ec_ptr ec, lccrt_irr_reg_type_t type, + int64_t num, uint64_t value);*/ +extern uint64_t *lccrt_irr_exec_ctx_get_reg_addr( lccrt_irr_ec_ptr ec, lccrt_irr_reg_type_t type, int64_t num); +extern int64_t lccrt_irr_exec_ctx_get_exit_value( lccrt_irr_ec_ptr ec); +extern void lccrt_irr_exec_ctx_set_exit_value( lccrt_irr_ec_ptr ec, int64_t exit_value); + +extern lccrt_irr_r_ptr lccrt_irr_reg_init( lccrt_irr_r_ptr reg, lccrt_irr_reg_type_t type, + int64_t num); +#define lccrt_irr_reg_init_sys( reg, num) lccrt_irr_reg_init( reg, LCCRT_IRR_REG_SYS, num) +#define lccrt_irr_reg_init_phys( reg, num) lccrt_irr_reg_init( reg, LCCRT_IRR_REG_PHYS, num) +#define lccrt_irr_reg_init_virt( reg, num) lccrt_irr_reg_init( reg, LCCRT_IRR_REG_VIRT, num) +extern lccrt_irr_a_ptr lccrt_irr_arg_init_hex( lccrt_irr_a_ptr arg, lccrt_irr_hex_t c); +extern lccrt_irr_a_ptr lccrt_irr_arg_init_reg( lccrt_irr_a_ptr arg, lccrt_irr_r_ptr reg); +extern lccrt_irr_a_ptr lccrt_irr_arg_init_reloc( lccrt_irr_a_ptr arg, lccrt_irr_rl_ptr reloc); +extern int lccrt_irr_arg_is_hex( lccrt_irr_a_ptr arg); +extern int lccrt_irr_arg_is_reloc( lccrt_irr_a_ptr arg); +extern int lccrt_irr_arg_is_reg( lccrt_irr_a_ptr arg); +extern int lccrt_irr_arg_is_reg_type( lccrt_irr_a_ptr arg, lccrt_irr_reg_type_t type); +extern int64_t lccrt_irr_arg_get_hex( lccrt_irr_a_ptr arg); +extern lccrt_irr_rl_ptr lccrt_irr_arg_get_reloc( lccrt_irr_a_ptr arg); +extern int64_t lccrt_irr_arg_get_reg_addr( lccrt_irr_a_ptr arg); +extern lccrt_irr_reg_type_t lccrt_irr_arg_get_reg_type( lccrt_irr_a_ptr arg); +extern lccrt_irr_oi_ptr lccrt_irr_oper_iter_init( lccrt_irr_oi_ptr oi, lccrt_irr_n_ptr node); +extern lccrt_irr_oi_ptr lccrt_irr_oper_iter_init_after( lccrt_irr_oi_ptr j, lccrt_irr_n_ptr node, + lccrt_irr_o_ptr oper); +extern lccrt_irr_oi_ptr lccrt_irr_oper_iter_init_before( lccrt_irr_oi_ptr j, lccrt_irr_n_ptr node, + lccrt_irr_o_ptr oper); +extern lccrt_irr_n_ptr lccrt_irr_oper_iter_get_node( lccrt_irr_oi_ptr oi); +extern lccrt_irr_o_ptr lccrt_irr_oper_iter_get_prev( lccrt_irr_oi_ptr oi); +extern lccrt_irr_o_ptr lccrt_irr_oper_iter_get_next( lccrt_irr_oi_ptr oi); +extern lccrt_irr_oi_ptr lccrt_irr_oper_iter_shift( lccrt_irr_oi_ptr oi, int is_next); +#define lccrt_irr_oper_iter_shift_next( oi) lccrt_irr_oper_iter_shift( oi, 1) +#define lccrt_irr_oper_iter_shift_prev( oi) lccrt_irr_oper_iter_shift( oi, 0) +extern lccrt_irr_o_ptr lccrt_irr_oper_new( lccrt_irr_n_ptr node, lccrt_irr_oper_name_t name, + int num_args, lccrt_irr_a_ptr args[], + lccrt_irr_a_ptr res, lccrt_irr_oi_ptr iter); +extern void lccrt_irr_oper_delete( lccrt_irr_o_ptr oper); +extern lccrt_irr_oper_name_t lccrt_irr_oper_get_name( lccrt_irr_o_ptr oper); +extern int lccrt_irr_oper_get_num_args( lccrt_irr_o_ptr oper); +extern lccrt_irr_a_ptr lccrt_irr_oper_get_arg( lccrt_irr_o_ptr oper, int arg_num); +extern lccrt_irr_a_ptr lccrt_irr_oper_get_res( lccrt_irr_o_ptr oper); +extern lccrt_irr_c_ptr lccrt_irr_label_get_code( lccrt_irr_l_ptr lb); +extern void lccrt_irr_label_bind_code( lccrt_irr_l_ptr lb, lccrt_irr_c_ptr code); +extern void lccrt_irr_label_bind_node( lccrt_irr_l_ptr lb, lccrt_irr_n_ptr node); +extern lccrt_irr_jr_ptr lccrt_irr_node_get_jit_region( lccrt_irr_n_ptr node); +extern uint64_t lccrt_irr_node_get_ident( lccrt_irr_n_ptr node); +extern lccrt_irr_c_ptr lccrt_irr_node_get_code( lccrt_irr_n_ptr node); +extern void lccrt_irr_node_set_code( lccrt_irr_n_ptr node, lccrt_irr_c_ptr code); +extern uint64_t *lccrt_irr_node_get_count_addr( lccrt_irr_n_ptr node); +extern uint64_t lccrt_irr_node_get_attrs( lccrt_irr_n_ptr node); +extern uint64_t lccrt_irr_node_set_attrs( lccrt_irr_n_ptr node, uint64_t attrs); +extern int lccrt_irr_node_get_attr( lccrt_irr_n_ptr node, int index); +extern int lccrt_irr_node_set_attr( lccrt_irr_n_ptr node, int index, int attr); +extern void lccrt_irr_node_simplify( lccrt_irr_n_ptr node); +extern int lccrt_irr_code_get_num_relocs( lccrt_irr_c_ptr code); +extern lccrt_irr_jr_ptr lccrt_irr_code_get_jit_region( lccrt_irr_c_ptr code); +extern void lccrt_irr_code_set_phys_addr( lccrt_irr_c_ptr code, uint64_t addr, int64_t length); +extern uint64_t lccrt_irr_code_get_phys_addr( lccrt_irr_c_ptr code); +extern int64_t lccrt_irr_code_get_phys_len( lccrt_irr_c_ptr code); +extern void *lccrt_irr_code_get_relocs( lccrt_irr_c_ptr code); +extern void lccrt_irr_code_set_relocs( lccrt_irr_c_ptr code, void *relocs); +extern lccrt_irr_jr_ptr lccrt_irr_reloc_get_jit_region( lccrt_irr_rl_ptr reloc); +extern uint64_t lccrt_irr_reloc_get_virt_addr( lccrt_irr_rl_ptr reloc); +extern void lccrt_irr_reloc_set_phys_addr( lccrt_irr_rl_ptr reloc, uint64_t phys_addr); +extern void *lccrt_irr_reloc_get_link( lccrt_irr_rl_ptr reloc); +extern void lccrt_irr_reloc_set_link( lccrt_irr_rl_ptr reloc, void *link); +//extern void lccrt_irr_reloc_link( lccrt_irr_rl_ptr reloc, lccrt_irr_n_ptr node); +extern void lccrt_irr_reloc_unlink( lccrt_irr_rlu_ptr reloc_unit); + +extern lccrt_irr_c_ptr lccrt_irr_node_compile_code( lccrt_irr_n_ptr node); +extern int lccrt_irr_node_decompile_code( lccrt_irr_n_ptr node); +extern int lccrt_irr_reloc_patch( lccrt_irr_rl_ptr reloc, lccrt_irr_c_ptr code); +extern int64_t lccrt_irr_node_execute( lccrt_irr_n_ptr node, lccrt_irr_execute_context_ptr ec); + +extern int lccrt_irr_node_print( lccrt_irr_n_ptr node); +extern int lccrt_irr_oper_print( lccrt_irr_o_ptr oper, int is_ln); +extern int lccrt_irr_oper_fprint( FILE *fout, lccrt_irr_o_ptr oper, int is_ln); +extern int lccrt_irr_arg_fprint( FILE *fout, lccrt_irr_a_ptr a, int is_ln); +extern const char *lccrt_irr_oper_name_get_str( lccrt_irr_oper_name_t name); + +#define lccrt_irr_emit_oper_r0a0( b, l, n) lccrt_irr_emit_oper_r1a2( b, l, n, 0, 0, 0) +#define lccrt_irr_emit_oper_r1a0( b, l, n, r) lccrt_irr_emit_oper_r1a2( b, l, n, r, 0, 0) +#define lccrt_irr_emit_oper_r0a1( b, l, n, a0) lccrt_irr_emit_oper_r1a2( b, l, n, 0, a0, 0) +#define lccrt_irr_emit_oper_r1a1( b, l, n, r, a0) lccrt_irr_emit_oper_r1a2( b, l, n, r, a0, 0) +#define lccrt_irr_emit_oper_r0a2( b, l, n, a0, a1) lccrt_irr_emit_oper_r1a2( b, l, n, 0, a0, a1) +extern int64_t lccrt_irr_emit_oper_r1a2( void *buffer, int64_t max_length, lccrt_irr_oper_name_t name, + lccrt_irr_a_ptr r, lccrt_irr_a_ptr a0, lccrt_irr_a_ptr a1); +extern int64_t lccrt_irr_emit_bind_rel( void *inst, int64_t offset); + +/** + * Кодировка операции для Backend Bytecode (BB). + * name : 2 + * num_args : 2 + * arg_1 + * type : 1 + * value : 1,2,4,8 + * ... + * arg_N + * ... + * num_attrs : 2 + * attr_1 + * size : 2 + * type : 1 + * value : ... + * ... + * attr_K + * ... + * Если у операции есть результат, то он передается в качестве первого аргумента. + * Имя операции задается значениями lccrt_bb_oper_name_t. + * Тип аргумента задается значениями lccrt_bb_arg_type_t. + * Если num_args = 0, то у операции нет аргументов. + * Если num_attrs = 0, то у операции нет атрибутов. + * Поле attr.size определяет байтовый размер поля attr.value, если attr.size = 0, то + * это означает, что поле value отсутствует. + * Тип атрибута задается значениями lccrt_bb_attr_type_t. + */ + +/** + * Тип аргумента операции Backend Bytecode (BB). + */ +typedef enum +{ + LCCRT_BB_ARG_TYPE_HEX8 = 0, + LCCRT_BB_ARG_TYPE_HEX16, + LCCRT_BB_ARG_TYPE_HEX32, + LCCRT_BB_ARG_TYPE_HEX64, + LCCRT_BB_ARG_TYPE_LABEL8 = 8, + LCCRT_BB_ARG_TYPE_LABEL16, + LCCRT_BB_ARG_TYPE_LABEL32, + LCCRT_BB_ARG_TYPE_LABEL64, + LCCRT_BB_ARG_TYPE_REG_SYS = 16, + LCCRT_BB_ARG_TYPE_REG_GLOB, + LCCRT_BB_ARG_TYPE_REG_PHYS, + LCCRT_BB_ARG_TYPE_REG_VIRT, +} lccrt_bb_arg_type_t; + +/** + * Тип аргумента операции Backend Bytecode (BB). + */ +typedef enum +{ + LCCRT_BB_ATTR_TYPE_COUNTER, + LCCRT_BB_ATTR_TYPE_LAST +} lccrt_bb_attr_type_t; + +/** + * Название операции Backend Bytecode (BB). + */ +typedef enum +{ + LCCRT_BB_OPER_NOP, + /* Самая первая операция. */ + LCCRT_BB_OPER_START, + /* Самая последняя операция. */ + LCCRT_BB_OPER_STOP, + LCCRT_BB_OPER_MOV_U32, + LCCRT_BB_OPER_MOV_U64, + LCCRT_BB_OPER_EXT_S8, + LCCRT_BB_OPER_EXT_S16, + LCCRT_BB_OPER_EXT_S32, + LCCRT_BB_OPER_CONV_S32_F32, + LCCRT_BB_OPER_CONV_S32_F64, + LCCRT_BB_OPER_CONV_S64_F32, + LCCRT_BB_OPER_CONV_S64_F64, + LCCRT_BB_OPER_CONV_F32_F64, + LCCRT_BB_OPER_CONV_F64_F32, + LCCRT_BB_OPER_AND_U64, + LCCRT_BB_OPER_OR_U64, + LCCRT_BB_OPER_XOR_U64, + LCCRT_BB_OPER_SHL_U64, + LCCRT_BB_OPER_SHR_U64, + LCCRT_BB_OPER_SAR_U64, + LCCRT_BB_OPER_ADD_U64, + LCCRT_BB_OPER_SUB_U64, + LCCRT_BB_OPER_MUL_U64, + LCCRT_BB_OPER_SDIV_U64, + LCCRT_BB_OPER_UDIV_U64, + LCCRT_BB_OPER_SMOD_U64, + LCCRT_BB_OPER_UMOD_U64, + /* Взятие битового поля + arg0 (int64) - источник битового поля + arg1 (int64) - битовое смещение поля + arg2 (int64) - битовая длина поля */ + LCCRT_BB_OPER_GETFIELD, + LCCRT_BB_OPER_FADD_F32, + LCCRT_BB_OPER_FADD_F64, + LCCRT_BB_OPER_FSUB_F32, + LCCRT_BB_OPER_FSUB_F64, + LCCRT_BB_OPER_FMUL_F32, + LCCRT_BB_OPER_FMUL_F64, + LCCRT_BB_OPER_FDIV_F32, + LCCRT_BB_OPER_FDIV_F64, + LCCRT_BB_OPER_FSQRT_F64, + LCCRT_BB_OPER_CMPE_U64, + LCCRT_BB_OPER_CMPNE_U64, + LCCRT_BB_OPER_CMPL_U64, + LCCRT_BB_OPER_CMPLE_U64, + LCCRT_BB_OPER_CMPB_U64, + LCCRT_BB_OPER_CMPBE_U64, + /* Сравнение формата float64 на "не упорядочено" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float32/float64)arg0 vs (bitcast float32/float64)arg1)) */ + LCCRT_BB_OPER_FCMP_U_F32, + LCCRT_BB_OPER_FCMP_U_F64, + /* Сравнение формата float64 на "упорядочено" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float32/float64)arg0 vs (bitcast float32/float64)arg1)) */ + LCCRT_BB_OPER_FCMP_O_F32, + LCCRT_BB_OPER_FCMP_O_F64, + /* Сравнение формата float64 на "равно или не упорядочено" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float64)arg0 == (bitcast float64)arg1) || unordered) */ + LCCRT_BB_OPER_FCMPE_U_F64, + /* Сравнение формата float64 на "равно" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float32/float64)arg0 == (bitcast float32/float64)arg1)) */ + LCCRT_BB_OPER_FCMPE_O_F32, + LCCRT_BB_OPER_FCMPE_O_F64, + /* Сравнение формата float64 на "равно или не упорядочено" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float64)arg0 < (bitcast float64)arg1) || unordered) */ + LCCRT_BB_OPER_FCMPL_U_F64, + /* Сравнение формата float64 на "равно" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float32/float64)arg0 < (bitcast float32/float64)arg1)) */ + LCCRT_BB_OPER_FCMPL_O_F32, + LCCRT_BB_OPER_FCMPL_O_F64, + /* Сравнение формата float64 на "равно или не упорядочено" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float64)arg0 <= (bitcast float64)arg1) || unordered) */ + LCCRT_BB_OPER_FCMPLE_U_F64, + /* Сравнение формата float64 на "равно" + arg0 (int64) - первый аргумент + arg1 (int64) - второй аргумент + res0 (int64) - (((bitcast float32/float64)arg0 <= (bitcast float32/float64)arg1)) */ + LCCRT_BB_OPER_FCMPLE_O_F32, + LCCRT_BB_OPER_FCMPLE_O_F64, + /* Условная перессылка, если предикат true + arg0 (int64) - итоговое значение, если arg1 == true + arg1 (int64) - предикат выбора + res0 (int64) - (if ( arg1 ) res0 = arg1;) */ + LCCRT_BB_OPER_MOVTHEN_U64, + /* Условная перессылка, если предикат false + arg0 (int64) - итоговое значение, если arg1 == false + arg1 (int64) - предикат выбора + res0 (int64) - (if ( !arg1 ) res0 = arg1;) */ + LCCRT_BB_OPER_MOVELSE_U64, + LCCRT_BB_OPER_LD_U8, + LCCRT_BB_OPER_LD_U16, + LCCRT_BB_OPER_LD_U32, + LCCRT_BB_OPER_LD_U64, + LCCRT_BB_OPER_LD_S8, + LCCRT_BB_OPER_LD_S16, + LCCRT_BB_OPER_LD_S32, + LCCRT_BB_OPER_ST_U8, + LCCRT_BB_OPER_ST_U16, + LCCRT_BB_OPER_ST_U32, + LCCRT_BB_OPER_ST_U64, + /* Безусловный переход по литералу "ленивой" линковки + arg0 (reloc) - литерал перехода */ + LCCRT_BB_OPER_BRANCH_RELOC, + /* Условный переход по литералам "ленивой" линковки + arg0 (reloc) - литерал перехода, если arg2 == true + arg1 (reloc) - литерал перехода, если arg2 == false + arg2 (int64) - предикат перехода */ + LCCRT_BB_OPER_BRANCHIF_RELOC, + LCCRT_BB_OPER_BRANCH_DYNAMIC, + LCCRT_BB_OPER_CALL_V_U64U64, + /* Адресуемая метка */ + LCCRT_BB_OPER_LABEL, + LCCRT_BB_OPER_LAST +} lccrt_bb_oper_name_t; + +#if defined(__cplusplus) +} +#endif + +/** + * @} + */ + +#endif /* LCCRT_H */ diff --git a/lib/common/lccrt_ctx.c b/lib/common/lccrt_ctx.c new file mode 100644 index 0000000..aa3e56d --- /dev/null +++ b/lib/common/lccrt_ctx.c @@ -0,0 +1,1284 @@ +/** + * 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_ctx.c - реализация пользовательский интерфейс (динамической) компиляции. + */ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lccrt_irv.h" +#include "lccrt_jit.h" + +#define LCCRT_CTX_PLUGIN_MAX_NUMBER (256) +#define LCCRT_CTX_PLUGIN_TARGET_MAX_NUMBER (256) +#define LCCRT_CTX_PLUGIN_NAME_LENGTH (4096 - 1) + +#define lccrt_ctx_error_plugin_sym( ctx, lname, sname) \ + lccrt_ctx_error( ctx, 0, "Plugin library [%s] hasn't symbol [%s]\n", \ + lname, sname) + +lccrt_check_type_define( lccrt_type_t); +lccrt_check_type_define( lccrt_varinit_t); +lccrt_check_type_define( lccrt_var_t); +lccrt_check_type_define( lccrt_oper_t); +lccrt_check_type_define( lccrt_oper_iterator_t); +lccrt_check_type_define( lccrt_function_t); +lccrt_check_type_define( lccrt_function_jit_info_t); +lccrt_check_type_define( lccrt_module_t); +lccrt_check_type_define( lccrt_einfo_tydescr_t); +lccrt_check_type_define( lccrt_einfo_block_t); +lccrt_check_type_define( lccrt_einfo_link_t); +lccrt_check_type_define( lccrt_context_t); +lccrt_check_type_define( lccrt_plugin_t); +lccrt_check_type_define( lccrt_irr_code_area_t); +lccrt_check_type_define( lccrt_irr_jit_region_t); +lccrt_check_type_define( lccrt_irr_code_t); +lccrt_check_type_define( lccrt_irr_execute_context_t); +lccrt_check_type_define( lccrt_irr_reloc_unit_t); +lccrt_check_type_define( lccrt_irr_reloc_t); +lccrt_check_type_define( lccrt_irr_node_t); +lccrt_check_type_define( lccrt_irr_oper_iter_t); +lccrt_check_type_define( lccrt_irr_oper_t); +lccrt_check_type_define( lccrt_irr_arg_t); +lccrt_check_type_define( lccrt_irr_reg_t); +lccrt_check_type_define( lccrt_irr_edge_t); + +/** + * Данные стандартного менеджера вывода сообщений в файл. + */ +typedef struct +{ + int8_t is_init; /* флаг инициализации структуры */ + FILE *file; /* файл для печати сообщений */ + pid_t pid; /* идентификатор родительского процесса */ +} lccrt_dir_error_info_t; + +static void *lccrt_std_alloc( void *pool, uint64_t size); +static void *lccrt_std_realloc( void *pool, void *ptr, uint64_t size); +static void lccrt_std_free( void *pool, void *ptr); +static void lccrt_std_error( void *data, int errid, const char *fmt, ...); +static void lccrt_dir_error( void *data, int errid, const char *fmt, ...); +static void lccrt_std_warning( void *data, int errid, const char *fmt, ...); +static void lccrt_dir_warning( void *data, int errid, const char *fmt, ...); + +/** + * Стандартные менеджеры. + */ +lccrt_err_t lccrt_std_err = {0, &lccrt_std_error, &lccrt_std_warning}; +lccrt_mem_t lccrt_std_mem = {0, &lccrt_std_alloc, &lccrt_std_realloc, &lccrt_std_free}; +lccrt_err_t lccrt_dir_err = {0, &lccrt_dir_error, &lccrt_dir_warning}; + +/** + * Стандартный malloc. + */ +static void * +lccrt_std_alloc( void *pool, uint64_t size) +{ + void *result = (void *)malloc( size); + + return (result); +} /* lccrt_std_alloc */ + +/** + * Стандартный realloc. + */ +static void * +lccrt_std_realloc( void *pool, void *ptr, uint64_t size) +{ + void *result = (void *)realloc( ptr, size); + + return (result); +} /* lccrt_std_realloc */ + +/** + * Стандартный free. + */ +static void +lccrt_std_free( void *pool, void *ptr) +{ + free( ptr); + + return; +} /* lccrt_std_free */ + +/** + * Стандартная реакция на ошибку. + */ +static void +lccrt_std_error( void *data, int errid, const char *fmt, ...) +{ + char str[256]; + va_list ap; + + va_start( ap, fmt); + vsnprintf( str, 255, fmt, ap); + va_end( ap); + + perror( str); + if ( errid ) + { + exit( errid); + } + + return; +} /* lccrt_std_error */ + +/** + * Стандартная реакция на предупреждение. + */ +static void +lccrt_std_warning( void *data, int errid, const char *fmt, ...) +{ + char str[256]; + va_list ap; + + va_start( ap, fmt); + vsnprintf( str, 255, fmt, ap); + va_end( ap); + + printf( "%s", str); + + return; +} /* lccrt_std_warning */ + +/** + * Подготовка данных для вывода сообщений. + */ +static lccrt_dir_error_info_t * +lccrt_dir_error_init( void) +{ + static __thread lccrt_dir_error_info_t ei = {0}; + + if ( !ei.is_init + || (ei.pid != getpid()) ) + { + char s[1024]; + const char *dir_name = getenv( "LCCRT_ERRDIR"); + + ei.is_init = 1; + ei.pid = getpid(); + if ( !dir_name + || (dir_name[0] == 0) ) + { + dir_name = "."; + } + + snprintf( s, 1024, "mkdir -p -m a+rwx %s", dir_name); + system( s); + + snprintf( s, 1024, "%s/lccrt.errlog.pid_%d.tid_%d.txt", dir_name, getpid(), (unsigned)syscall( SYS_gettid)); + ei.file = fopen( s, "w"); + } + + return (&ei); +} /* lccrt_dir_error_init */ + +/** + * Стандартная реакция на ошибку. + */ +static void +lccrt_dir_error( void *data, int errid, const char *fmt, ...) +{ + va_list ap; + lccrt_dir_error_info_t *ei = lccrt_dir_error_init(); + + va_start( ap, fmt); + vfprintf( ei->file, fmt, ap); + va_end( ap); + + fflush( ei->file); + + if ( errid ) + { + exit( errid); + } + + return; +} /* lccrt_dir_error */ + +/** + * Стандартная реакция на предупреждение. + */ +static void +lccrt_dir_warning( void *data, int errid, const char *fmt, ...) +{ + va_list ap; + lccrt_dir_error_info_t *ei = lccrt_dir_error_init(); + + va_start( ap, fmt); + vfprintf( ei->file, fmt, ap); + va_end( ap); + + fflush( ei->file); + + return; +} /* lccrt_dir_warning */ + +/** + * Чтение из файла строки. + */ +static void +lccrt_getline( FILE *f, int max_str_len, char *line) +{ + int c; + int k = 0; + + c = getc( f); + while ( (c != '\n') + && (c != EOF) + && isspace( c) ) + { + c = getc( f); + } + + while ( (c != '\n') + && (c != EOF) ) + { + if ( (k < max_str_len) ) + { + line[k] = c; + ++k; + } + + c = getc( f); + } + + line[k] = 0; + + return; +} /* lccrt_getline */ + +/** + * Получить ссылку на метод. + */ +void * +lccrt_ctx_plugin_get_func( lccrt_plg_ptr p, int func_num) +{ + void *r = 0; + + lccrt_check_type_assert( p, lccrt_plugin_t); + if ( (0 <= func_num) + && (func_num < p->num_funcs) ) + { + r = p->funcs[func_num]; + } + + return (r); +} /* lccrt_ctx_plugin_get_func */ + +/** + * Закрытие библиотеки с ассемблером. + */ +static void +lccrt_ctx_plugin_unload( lccrt_plugin_t *a) +{ + int k; + lccrt_context_ptr ctx = a->ctx; + + lccrt_check_type_assert( a, lccrt_plugin_t); + if ( a->lib ) + { + dlclose( a->lib); + a->lib = 0; + } + + if ( a->targs ) + { + for ( k = 0; k < a->num_targs; ++k ) + { + lccrt_ctx_free( ctx, a->targs[k]); + lccrt_ctx_free( ctx, a->lccrt_s[k]); + lccrt_ctx_free( ctx, a->include_s[k]); + } + + lccrt_ctx_free( ctx, a->targs); + lccrt_ctx_free( ctx, a->lccrt_s); + lccrt_ctx_free( ctx, a->include_s); + a->targs = 0; + } + + lccrt_ctx_free( ctx, a->lib_name); + lccrt_ctx_free( ctx, a->lccrt_ver); + lccrt_ctx_free( ctx, a->lccrt_s); + lccrt_ctx_free( ctx, a->include_s); + a->lib_name = 0; + a->lccrt_ver = 0; + a->lccrt_s = 0; + a->include_s = 0; + + a->num_targs = 0; + a->num_funcs = 0; + lccrt_ctx_free( ctx, a->funcs); + a->funcs = 0; + + return; +} /* lccrt_ctx_plugin_unload */ + +/** + * Открытие библиотеки с ассемблером. + */ +static int +lccrt_ctx_load_plugin_lib( lccrt_plugin_t *a, const char *lib_name) +{ + int k; + int r = -1; + char *cur_name = 0; + lccrt_context_ptr ctx = a->ctx; + + lccrt_check_type_assert( a, lccrt_plugin_t); + if ( a->lib ) + { + lccrt_ctx_error( ctx, 0, "INTERNAL ERROR\n"); + return (r); + } + + if ( (lib_name[0] == '/') ) + { + cur_name = lccrt_ctx_copy_str( ctx, lib_name); + } else + { + cur_name = lccrt_ctx_cat_strs( ctx, ctx->paths.plugins[a->type], "/"); + cur_name = lccrt_ctx_catby_strs( ctx, cur_name, lib_name); + } + + a->lib = dlopen( cur_name, RTLD_LAZY); + if ( !a->lib ) + { + lccrt_ctx_error( ctx, 0, "Can't load plugin library [%s]\n", cur_name); + } else + { + const char **lname; + const char **lver; + const char *(*targs)[]; + int is_asm = (a->type == LCCRT_PLUGIN_TYPE_ASM); + + a->num_funcs = is_asm ? LCCRT_PLUGIN_ASM_FUNC_LAST : LCCRT_PLUGIN_IRROBJ_FUNC_LAST; + a->funcs = lccrt_ctx_mallocn( ctx, void *, a->num_funcs); + if ( is_asm ) + { + a->funcs[LCCRT_PLUGIN_ASM_FUNC_COMP] = dlsym( a->lib, LCCRT_ASM_SFUNC_COMPILE); + a->funcs[LCCRT_PLUGIN_ASM_FUNC_TOOL] = dlsym( a->lib, LCCRT_ASM_SFUNC_GETTOOL); + if ( !a->funcs[LCCRT_PLUGIN_ASM_FUNC_COMP] ) + { + lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_ASM_SFUNC_COMPILE); + + } else if ( !a->funcs[LCCRT_PLUGIN_ASM_FUNC_TOOL] ) + { + lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_ASM_SFUNC_GETTOOL); + } + } else + { + a->funcs[LCCRT_PLUGIN_IRROBJ_FUNC_NODE_COMPILE] = dlsym( a->lib, LCCRT_IRROBJ_SFUNC_NODE_COMPILE); + a->funcs[LCCRT_PLUGIN_IRROBJ_FUNC_NODE_DECOMPILE] = dlsym( a->lib, LCCRT_IRROBJ_SFUNC_NODE_DECOMPILE); + a->funcs[LCCRT_PLUGIN_IRROBJ_FUNC_RELOC_PATCH] = dlsym( a->lib, LCCRT_IRROBJ_SFUNC_RELOC_PATCH); + a->funcs[LCCRT_PLUGIN_IRROBJ_FUNC_CODE_EXEC] = dlsym( a->lib, LCCRT_IRROBJ_SFUNC_CODE_EXEC); + a->funcs[LCCRT_PLUGIN_IRROBJ_FUNC_GETCONF] = dlsym( a->lib, LCCRT_IRROBJ_SFUNC_GETCONF); + if ( !a->funcs[LCCRT_PLUGIN_IRROBJ_FUNC_NODE_COMPILE] ) + { + lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_IRROBJ_SFUNC_NODE_COMPILE); + + } else if ( !a->funcs[LCCRT_PLUGIN_IRROBJ_FUNC_NODE_DECOMPILE] ) + { + lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_IRROBJ_SFUNC_NODE_DECOMPILE); + + } else if ( !a->funcs[LCCRT_PLUGIN_IRROBJ_FUNC_RELOC_PATCH] ) + { + lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_IRROBJ_SFUNC_RELOC_PATCH); + + } else if ( !a->funcs[LCCRT_PLUGIN_IRROBJ_FUNC_CODE_EXEC] ) + { + lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_IRROBJ_SFUNC_CODE_EXEC); + + } else if ( !a->funcs[LCCRT_PLUGIN_IRROBJ_FUNC_GETCONF] ) + { + lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_IRROBJ_SFUNC_GETCONF); + } + } + + lname = dlsym( a->lib, LCCRT_PLUGIN_LIBRARY_NAME_S); + lver = dlsym( a->lib, LCCRT_PLUGIN_LCCRT_VERSION_S); + targs = dlsym( a->lib, LCCRT_PLUGIN_TARGETS_S); + if ( !lname + || !lname[0] ) + { + lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_PLUGIN_LIBRARY_NAME_S); + + } else if ( !lname[0][0] ) + { + lccrt_ctx_error( ctx, 0, "Plugin library [%s] name [%s] is incorrect\n", + cur_name, lname[0]); + + } else if ( !lver + || !lver[0] ) + { + lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_PLUGIN_LCCRT_VERSION_S); + + } else if ( !targs ) + { + lccrt_ctx_error_plugin_sym( ctx, cur_name, LCCRT_PLUGIN_TARGETS_S); + } else + { + if ( ctx->verbose.is_base ) + { + fprintf( stderr, "LCCRT: plugin [%s] config:\n", lib_name); + } + + a->lib_name = lccrt_ctx_copy_str( ctx, lname[0]); + a->lccrt_ver = lccrt_ctx_copy_str( ctx, lver[0]); + if ( ctx->verbose.is_base ) + { + fprintf( stderr, " plugin self-name : %s\n", a->lib_name); + fprintf( stderr, " plugin's version of lccrt-library : %s\n", a->lccrt_ver); + } + + a->num_targs = 0; + for ( k = 0; (*targs)[k]; ++k ) + { + a->num_targs++; + } + + if ( (0 < a->num_targs) + && (a->num_targs < LCCRT_CTX_PLUGIN_TARGET_MAX_NUMBER) ) + { + r = 0; + a->targs = lccrt_ctx_mallocn( ctx, const char *, a->num_targs); + a->lccrt_s = lccrt_ctx_mallocn( ctx, const char *, a->num_targs); + a->include_s = lccrt_ctx_mallocn( ctx, const char *, a->num_targs); + memset( a->targs, 0, a->num_targs*sizeof( a->lccrt_s[0])); + memset( a->lccrt_s, 0, a->num_targs*sizeof( a->lccrt_s[0])); + memset( a->include_s, 0, a->num_targs*sizeof( a->include_s[0])); + for ( k = 0; k < a->num_targs; ++k ) + { + char buf[1024] = {0}; + + a->targs[k] = lccrt_ctx_copy_str( ctx, (*targs)[k]); + if ( ctx->verbose.is_base ) + { + fprintf( stderr, " plugin's target (%d) : %s\n", k, a->targs[k]); + } + + snprintf( buf, 1024, "%s/lib/%s", ctx->paths.home, a->targs[k]); + a->lccrt_s[k] = lccrt_ctx_copy_str( ctx, buf); + if ( ctx->verbose.is_base ) + { + fprintf( stderr, " plugin's target system libraries path : %s\n", a->lccrt_s[k]); + } + + snprintf( buf, 1024, "%s/include/%s", ctx->paths.home, a->targs[k]); + a->include_s[k] = lccrt_ctx_copy_str( ctx, buf); + if ( ctx->verbose.is_base ) + { + fprintf( stderr, " plugin's target system include path : %s\n", a->include_s[k]); + } + + if ( lccrt_str_eq( a->lib_name, "lccopt-e2k64") ) + { + FILE *flib = 0; + + snprintf( buf, 1024, "%s/liblccrt_s.a", a->lccrt_s[k]); + flib = fopen( buf, "r"); + + if ( !flib ) + { + r = -1; + lccrt_ctx_error( ctx, 0, "Can't find system library [liblccrt_s.a] by path [%s]\n", + a->lccrt_s[k]); + break; + } else + { + fclose( flib); + } + } + } + } else + { + a->num_targs = 0; + lccrt_ctx_error( ctx, 0, "Plugin library [%s] number of targets [%d]\n", + cur_name, a->num_targs); + } + } + } + + lccrt_ctx_free( ctx, cur_name); + if ( r ) + { + lccrt_ctx_plugin_unload( a); + } + + return (r); +} /* lccrt_ctx_load_plugin_lib */ + +/** + * Поиск lccrt-home пути на основе пути к liblccrt.so (места расположения загруженной библиотеки). + */ +char * +lccrt_ctx_find_home_path( lccrt_ctx_ptr ctx) +{ + Dl_info dli; + char *t = 0; + char *s = 0; + + dladdr( &lccrt_ctx_find_home_path, &dli); + t = realpath( dli.dli_fname, 0); + if ( !t ) + { + lccrt_ctx_error( ctx, 0, "Can't resolve real path of lccrt-library's location [%s]\n", dli.dli_fname); + } + + s = dirname( t); + if ( !s ) + { + lccrt_ctx_error( ctx, 0, "Can't resolve directory of lccrt-library's location [%s]\n", t); + } + + s = lccrt_ctx_cat_strs( ctx, s, "/lccrt"); + free( t); + + return (s); +} /* lccrt_ctx_find_home_path */ + +#if 0 +/** + * Инициализация home-директории. + */ +void +lccrt_context_init_paths( lccrt_context_ptr ctx) +{ + const char *s; + + s = getenv( "LCCRT_HOME"); + if ( s ) + { + s = lccrt_ctx_copy_str( ctx, s); + + } else + { + Dl_info dli; + char *t = 0; + + dladdr( &lccrt_context_init_paths, &dli); + t = realpath( dli.dli_fname, 0); + if ( !t ) + { + lccrt_ctx_error( ctx, 0, "Can't resolve real path of lccrt-library's location [%s]\n", dli.dli_fname); + } + + s = dirname( t); + if ( !s ) + { + lccrt_ctx_error( ctx, 0, "Can't resolve directory of lccrt-library's location [%s]\n", t); + } + + s = lccrt_ctx_cat_strs( ctx, s, "/lccrt"); + free( t); + } + + ctx->paths.home = (char *)s; + + if ( getenv( "LCCRT_HOME_PLUGIN") ) + { + ctx->paths.plugin = lccrt_ctx_copy_str( ctx, getenv( "LCCRT_HOME_PLUGIN")); + } else + { + ctx->paths.plugin = lccrt_ctx_cat_strs( ctx, ctx->paths.home, "/plugin"); + } + + if ( getenv( "LCCRT_HOME_PLUGIN_ASM") ) + { + ctx->paths.plugins[LCCRT_PLUGIN_TYPE_ASM] = getenv( "LCCRT_HOME_PLUGIN_ASM"); + ctx->paths.plugins[LCCRT_PLUGIN_TYPE_ASM] = lccrt_ctx_copy_str( ctx, ctx->paths.plugins[LCCRT_PLUGIN_TYPE_ASM]; + } else + { + ctx->paths.plugins[LCCRT_PLUGIN_TYPE_ASM] = lccrt_ctx_cat_strs( ctx, ctx->paths.plugin, "/asm"); + } + + if ( getenv( "LCCRT_HOME_PLUGIN_IRROBJ") ) + { + ctx->paths.plugins[LCCRT_PLUGIN_TYPE_IRROBJ] = getenv( "LCCRT_HOME_PLUGIN_IRROBJ"); + ctx->paths.plugins[LCCRT_PLUGIN_TYPE_IRROBJ] = lccrt_ctx_copy_str( ctx, ctx->paths.plugins[LCCRT_PLUGIN_TYPE_IRROBJ]; + } else + { + ctx->paths.plugins[LCCRT_PLUGIN_TYPE_IRROBJ] = lccrt_ctx_cat_strs( ctx, ctx->paths.plugin, "/irrobj"); + } + + if ( ctx->verbose.is_base ) + { + fprintf( stderr, "\nLCCRT library config:\n\n"); + fprintf( stderr, " LCCRT_VERBOSE : %s\n", getenv( "LCCRT_VERBOSE")); + fprintf( stderr, " LCCRT_HOME : %s\n", ctx->paths.home); + fprintf( stderr, " LCCRT_HOME_PLUGIN : %s\n", ctx->paths.plugin); + fprintf( stderr, " LCCRT_HOME_PLUGIN_ASM : %s\n", ctx->paths.plugins[LCCRT_PLUGIN_TYPE_ASM]); + fprintf( stderr, " LCCRT_HOME_PLUGIN_IRROBJ : %s\n", ctx->paths.plugins[LCCRT_PLUGIN_TYPE_IRROBJ]); + } + + return; +} /* lccrt_context_init_paths */ +#endif + +/** + * Загрузка плагина. + */ +static int +lccrt_ctx_load_plugin( lccrt_ctx_ptr ctx, lccrt_plugin_type_t type, const char *env, const char *dir) +{ + int k; + int r = 0; + char *f_name = 0; + FILE *f = 0; + int num_ps = 0; + lccrt_plugin_t ps[LCCRT_CTX_PLUGIN_MAX_NUMBER] = {0}; + + if ( getenv( env) ) + { + ctx->paths.plugins[type] = lccrt_ctx_copy_str( ctx, getenv( env)); + } else + { + ctx->paths.plugins[type] = lccrt_ctx_cat_strs( ctx, ctx->paths.plugin, "/"); + ctx->paths.plugins[type] = lccrt_ctx_cat_strs( ctx, ctx->paths.plugins[type], dir); + } + + f_name = lccrt_ctx_cat_strs( ctx, ctx->paths.plugins[type], "/plugin.conf"); + f = fopen( f_name, "r"); + if ( !f ) + { + lccrt_ctx_error( ctx, 0, "Can't open plugin [%s] config file [%s]\n", dir, f_name); + lccrt_ctx_free( ctx, f_name); + r = -1; + } else + { + char name[LCCRT_CTX_PLUGIN_NAME_LENGTH + 1]; + + lccrt_ctx_free( ctx, f_name); + while ( !feof( f) ) + { + lccrt_getline( f, LCCRT_CTX_PLUGIN_NAME_LENGTH, name); + if ( (name[0] == '#') + || (name[0] == 0) ) + { + /* Пропускаем текущую строчку. */ + } else + { + if ( (num_ps < LCCRT_CTX_PLUGIN_MAX_NUMBER) ) + { + int is_load = 0; + + lccrt_check_type_init( ps + num_ps, lccrt_plugin_t); + ps[num_ps].ctx = ctx; + ps[num_ps].type = type; + if ( (lccrt_ctx_load_plugin_lib( ps + num_ps, name) == 0) ) + { + is_load = 1; + num_ps++; + for ( k = 0; k < num_ps - 1; ++k ) + { + if ( lccrt_str_eq( ps[k].lib_name, ps[num_ps-1].lib_name) ) + { + is_load = 0; + lccrt_ctx_error( ctx, 0, "Duplicate plugin name [%s]\n", + ps[k].lib_name); + break; + } + } + } + + if ( !is_load ) + { + lccrt_ctx_error( ctx, 0, "Can't load plugin [%s]\n", name); + for ( k = 0; k < num_ps; ++k ) + { + lccrt_ctx_plugin_unload( ps + k); + } + + lccrt_context_delete( ctx); + return (0); + } + } + } + } + + fclose( f); + if ( (num_ps == 0) ) + { + //lccrt_ctx_warning( ctx, 0, "The plugin [%s] set is empty\n", dir); + } else + { + ctx->num_plgs[type] = num_ps; + ctx->plgs[type] = lccrt_ctx_memdup( ctx, ps, num_ps * sizeof( ps[0])); + } + } + + return (r); +} /* lccrt_ctx_load_plugin */ + +/** + * Создание контекста (конструктор). + * --------------------------------- + * @param mem менеджер памяти (0 - менеджер по умолчанию) + * @param err менеджер сообщений об ошибках (0 - менеджер по умолчанию) + * @result новый контекст, созданный с помощью менеджера памяти + * + * @ingroup tyCtxFns + */ +lccrt_context_ptr +lccrt_context_new( lccrt_mem_ptr mem, lccrt_err_ptr err) +{ + int k; + lccrt_context_ptr ctx = 0; + FILE *pc = 0; + + if ( !mem ) + { + mem = &lccrt_std_mem; + } + + if ( !err ) + { + err = &lccrt_std_err; + } + + if ( getenv( "LCCRT_ERRDIR") ) + { + err = &lccrt_dir_err; + } + + ctx = (*mem->palloc)( mem->pool, sizeof( lccrt_context_t)); + memset( ctx, 0, sizeof( lccrt_context_t)); + lccrt_check_type_init( ctx, lccrt_context_t); + ctx->mem = *mem; + ctx->err = *err; + ctx->modules = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + ctx->module_max = 0; + + if ( getenv( "LCCRT_HOME") ) + { + ctx->paths.home = lccrt_ctx_copy_str( ctx, getenv( "LCCRT_HOME")); + } else + { + ctx->paths.home = lccrt_ctx_find_home_path( ctx); + } + + if ( getenv( "LCCRT_HOME_PLUGIN") ) + { + ctx->paths.plugin = lccrt_ctx_copy_str( ctx, getenv( "LCCRT_HOME_PLUGIN")); + } else + { + ctx->paths.plugin = lccrt_ctx_cat_strs( ctx, ctx->paths.home, "/plugin"); + } + + if ( getenv( "LCCRT_VERBOSE") ) + { + ctx->verbose.is_base = atoi( getenv( "LCCRT_VERBOSE")); + } + + lccrt_ctx_load_plugin( ctx, LCCRT_PLUGIN_TYPE_ASM, "LCCRT_PLUGIN_TYPE_ASM", "asm"); + lccrt_ctx_load_plugin( ctx, LCCRT_PLUGIN_TYPE_IRROBJ, "LCCRT_PLUGIN_TYPE_IRROBJ", "irrobj"); + + return (ctx); +} /* lccrt_context_new */ + +/** + * Удаление контекста (деструктор). + * -------------------------------- + * @param ctx удаляемый контекст + * + * @ingroup tyCtxFns + */ +void +lccrt_context_delete( lccrt_context_ptr ctx) +{ + lccrt_hash_entry_ptr he; + + lccrt_check_type_assert( ctx, lccrt_context_t); + + /* Удаляем все ранее созданные модули. */ + while ( (he = lccrt_hash_first( ctx->modules)) ) + { + lccrt_module_delete( (lccrt_module_ptr)lccrt_hash_get_key( he)); + } + lccrt_hash_delete( ctx->modules); + + lccrt_ctx_free( ctx, ctx->paths.home); + lccrt_ctx_free( ctx, ctx->paths.plugin); + lccrt_ctx_free( ctx, ctx->paths.plugins[LCCRT_PLUGIN_TYPE_ASM]); + lccrt_ctx_free( ctx, ctx->paths.plugins[LCCRT_PLUGIN_TYPE_IRROBJ]); + + lccrt_check_type_done( ctx, lccrt_context_t); + (*ctx->mem.pfree)( ctx->mem.pool, ctx); + + return; +} /* lccrt_context_delete */ + +/** + * Прочитать свойство. + */ +int +lccrt_context_get_verbose_ir( lccrt_context_ptr ctx) +{ + int r = ctx->verbose.is_ir; + + lccrt_check_type_assert( ctx, lccrt_context_t); + + return (r); +} /* lccrt_context_get_verbose_ir */ + +/** + * Установить свойство. + */ +void +lccrt_context_set_verbose_ir( lccrt_context_ptr ctx, int value) +{ + lccrt_check_type_assert( ctx, lccrt_context_t); + ctx->verbose.is_ir = value; + + return; +} /* lccrt_context_set_verbose_ir */ + +/** + * Поиск плагина. + */ +static lccrt_plugin_t * +lccrt_context_find_plugin( lccrt_context_ptr c, lccrt_plugin_type_t type, const char *plg_name, int is_assert) +{ + int k; + lccrt_plugin_t *r = 0; + + if ( plg_name ) + { + for ( k = 0; k < c->num_plgs[type]; ++k ) + { + if ( lccrt_str_eq( plg_name, c->plgs[type][k].lib_name) ) + { + r = c->plgs[type] + k; + break; + } + } + } + + if ( !r + && is_assert ) + { + lccrt_ctx_error( c, 0, "No plugin with name [%s]\n", plg_name); + } + + return (r); +} /* lccrt_context_find_plugin */ + +/** + * Поиск плагина. + */ +static lccrt_plg_ptr +lccrt_context_find_plugin_for_arch( lccrt_context_ptr c, lccrt_plugin_type_t type, const char *arch) +{ + int k, i; + lccrt_plg_ptr r = 0; + + for ( k = 0; k < c->num_plgs[type] && !r; ++k ) + { + lccrt_plg_ptr p = c->plgs[type] + k; + + for ( i = 0; i < p->num_targs; ++i ) + { + if ( lccrt_str_eq( arch, p->targs[i]) ) + { + r = p; + break; + } + } + } + + if ( !r ) + { + lccrt_ctx_error( c, 0, "No plugin for target [%s]\n", arch); + } + + return (r); +} /* lccrt_context_find_plugin_for_arch */ + +/** + * Получить ссылку на плагин. + */ +lccrt_plg_ptr +lccrt_context_get_plugin_asm( lccrt_ctx_ptr ctx, const char *plg_name) +{ + lccrt_plg_ptr r = lccrt_context_find_plugin( ctx, LCCRT_PLUGIN_TYPE_ASM, plg_name, 1); + + return (r); +} /* lccrt_context_get_plugin_asm */ + +/** + * Получить ссылку на плагин. + */ +lccrt_plg_ptr +lccrt_context_get_plugin_irrobj( lccrt_ctx_ptr ctx, const char *plg_name) +{ + lccrt_plg_ptr r = lccrt_context_find_plugin( ctx, LCCRT_PLUGIN_TYPE_IRROBJ, plg_name, 1); + + return (r); +} /* lccrt_context_get_plugin_irrobj */ + +/** + * Получить ссылку на плагин. + */ +lccrt_plg_ptr +lccrt_context_find_plugin_irrobj_for_arch( lccrt_ctx_ptr ctx, const char *arch) +{ + lccrt_plg_ptr r = lccrt_context_find_plugin_for_arch( ctx, LCCRT_PLUGIN_TYPE_IRROBJ, arch); + + return (r); +} /* lccrt_context_find_plugin_irrobj_for_arch */ + +/** + * Поиск ассемблера. + */ +static int +lccrt_context_find_target( lccrt_context_ptr c, lccrt_plugin_t *a, const char *targ, int is_assert) +{ + int k; + int r = -1; + + if ( a ) + { + if ( targ ) + { + for ( k = 0; k < a->num_targs; ++k ) + { + if ( lccrt_str_eq( targ, a->targs[k]) ) + { + r = k; + break; + } + } + } + + if ( (r < 0) + && is_assert ) + { + lccrt_ctx_error( c, 0, "In plugin [%s] no target [%s]\n", a->lib_name, targ); + } + } + + return (r); +} /* lccrt_context_find_target */ + +/** + * Компиляция модуля. + */ +int +lccrt_module_compile_asm( lccrt_module_ptr m, const char *asm_lib, + lccrt_asm_compile_config_t *cnf) +{ + int k; + int r = -1; + lccrt_context_ptr c = lccrt_module_get_context( m); + lccrt_plugin_t *a = lccrt_context_get_plugin_asm( c, asm_lib); + + if ( cnf->is_jit ) + { + assert( 0); + } + + if ( 0 ) + { + lccrt_fs_ptr fs = lccrt_fs_new_file( c, stdout); + + lccrt_asm_print_module( fs, m); + lccrt_fs_delete( fs); + } + + if ( (lccrt_context_find_target( c, a, cnf->target, 1) >= 0) ) + { + r = ((lccrt_asm_compile_t)a->funcs[LCCRT_PLUGIN_ASM_FUNC_COMP])( m, cnf); + } + + return (r); +} /* lccrt_module_compile_asm */ + +/** + * Получить значение утилиты. + */ +const char * +lccrt_context_get_toolchain( lccrt_ctx_ptr c, const char *asm_lib, const char *targ, + const char *tool_type, const char *tool_name) +{ + const char *r = ""; + lccrt_plugin_t *a = lccrt_context_get_plugin_asm( c, asm_lib); + int k = lccrt_context_find_target( c, a, targ, 1); + + if ( (k >= 0) ) + { + if ( lccrt_str_eq( tool_type, "lib_path") + && lccrt_str_eq( tool_name, "lccrt_s") ) + { + r = a->lccrt_s[k]; + + } else if ( lccrt_str_eq( tool_type, "include_path") + && lccrt_str_eq( tool_name, "system") ) + { + r = a->include_s[k]; + } else + { + r = ((lccrt_asm_gettool_t)a->funcs[LCCRT_PLUGIN_ASM_FUNC_TOOL])( targ, tool_type, tool_name); + } + } + + return (r); +} /* lccrt_context_get_toolchain */ + +/** + * Получить значение поля. + */ +lccrt_err_t +lccrt_context_get_err_info( lccrt_ctx_ptr ctx) +{ + lccrt_err_t r; + + lccrt_check_type_assert( ctx, lccrt_context_t); + r = ctx->err; + + return (r); +} /* lccrt_context_get_err_info */ + +/** + * Установить значение поля. + */ +lccrt_err_t +lccrt_context_set_err_info( lccrt_ctx_ptr ctx, lccrt_err_t err) +{ + lccrt_err_t r; + + lccrt_check_type_assert( ctx, lccrt_context_t); + r = ctx->err; + ctx->err = err; + + return (r); +} /* lccrt_context_set_err_info */ + +/** + * Выделение участка памяти. + */ +void * +lccrt_ctx_malloc_func( lccrt_ctx_ptr ctx, uint64_t size) +{ + void *r; + + lccrt_check_type_assert( ctx, lccrt_context_t); + r = ctx->mem.palloc( &(ctx->mem), size); + + return (r); +} /* lccrt_ctx_malloc_func */ + +/** + * Выделение участка памяти. + */ +void * +lccrt_ctx_realloc_func( lccrt_ctx_ptr ctx, void *ptr, uint64_t size) +{ + void *r; + + lccrt_check_type_assert( ctx, lccrt_context_t); + r = ctx->mem.prealloc( &(ctx->mem), ptr, size); + + return (r); +} /* lccrt_ctx_realloc_func */ + +/** + * Освобождение участка памяти. + */ +void * +lccrt_ctx_free_func( lccrt_ctx_ptr ctx, void *ptr) +{ + lccrt_check_type_assert( ctx, lccrt_context_t); + if ( ptr ) + { + ctx->mem.pfree( &(ctx->mem), ptr); + } + + return (0); +} /* lccrt_ctx_free_func */ + +/** + * Копирование участка памяти. + */ +void * +lccrt_ctx_memdup_func( lccrt_ctx_ptr ctx, void *ptr, uint64_t size) +{ + void *r = 0; + + lccrt_check_type_assert( ctx, lccrt_context_t); + if ( (size > 0) ) + { + r = ctx->mem.palloc( &(ctx->mem), size); + if ( ptr ) + { + memcpy( r, ptr, size); + } else + { + memset( r, 0, size); + } + } + + return (r); +} /* lccrt_ctx_memdup_func */ + +/** + * Копирование массива. + */ +void ** +lccrt_ctx_copy_arr_func( lccrt_ctx_ptr ctx, void **ptr, uint64_t size, uint64_t len) +{ + uint64_t k; + void **r = 0; + + if ( (len > 0) ) + { + r = lccrt_ctx_malloc_func( ctx, len * sizeof( r[0])); + for ( k = 0; k < len; ++k ) + { + r[k] = lccrt_ctx_memdup_func( ctx, ptr[k], size); + } + } + + return (r); +} /* lccrt_ctx_copy_arr_func */ + +/** + * Копирование участка памяти. + */ +char * +lccrt_ctx_copy_str( lccrt_ctx_ptr ctx, const char *str) +{ + void *r = 0; + + if ( str ) + { + r = (char *)lccrt_ctx_memdup_func( ctx, (void *)str, strlen( str) + 1); + } + + return (r); +} /* lccrt_ctx_copy_str */ + +/** + * Объединение строк. + */ +char * +lccrt_ctx_cat_strs( lccrt_ctx_ptr ctx, const char *str1, const char *str2) +{ + char *r = 0; + int len1 = str1 ? strlen( str1) : 0; + int len2 = str2 ? strlen( str2) : 0; + + r = lccrt_ctx_malloc_func( ctx, len1 + len2 + 1); + memcpy( r, str1, len1); + memcpy( r + len1, str2, len2); + r[len1 + len2] = 0; + + return (r); +} /* lccrt_ctx_cat_strs */ + +/** + * Объединение строк. + */ +char * +lccrt_ctx_catby_strs( lccrt_ctx_ptr ctx, const char *str1, const char *str2) +{ + char *r = lccrt_ctx_cat_strs( ctx, str1, str2); + + lccrt_ctx_free( ctx, str1); + + return (r); +} /* lccrt_ctx_catby_strs */ + +/** + * Старт внешней программы с перенаправлением стандартного потока вывода + * на канальные файловые дескрипторы. + */ +int +lccrt_exec_with_fork( const char *path, /* первый аргумент execv */ + char *argv[], /* второй аргумент execv */ + pid_t *wpid, + int fds[2]) /* fds[0] - выходной декскриптор для внешней программы, + fds[1] - входной декскриптор для внешней программы */ +{ + pid_t pid; + int ifd[2] = {-1, -1}; + int ofd[2] = {-1, -1}; + int r = -1; + + if ( wpid ) + { + wpid[0] = -1; + } + + if ( fds ) + { + if ( (pipe( ifd) != 0) ) + { + /* Не удалось создать канал. */ + return (r); + } + + if ( (pipe( ofd) != 0) ) + { + /* Не удалось создать канал. */ + return (r); + } + } + + pid = fork(); + if ( (pid < 0) ) + { + /* Не удалось создать процесс. */ + return (r); + } + + if ( (pid == 0) ) + { + /* Запускаем внешнюю программу. */ + if ( fds ) + { + close( ifd[1]); + dup2( ifd[0], STDIN_FILENO); + close( ifd[0]); + + close( ofd[0]); + dup2( ofd[1], STDOUT_FILENO); + dup2( ofd[1], STDERR_FILENO); + close( ofd[1]); + } + + execvp( path, argv); + } else + { + /* Возвращаем файловые дескрипторы с вводом и выводом внешней программы. */ + r = 0; + if ( fds ) + { + close( ifd[0]); + close( ofd[1]); + + fds[0] = ofd[0]; + fds[1] = ifd[1]; + } + + if ( wpid ) + { + (*wpid) = pid; + } + } + + return (r); +} /* lccrt_exec_with_fork */ diff --git a/lib/common/lccrt_fs.c b/lib/common/lccrt_fs.c new file mode 100644 index 0000000..6c853d6 --- /dev/null +++ b/lib/common/lccrt_fs.c @@ -0,0 +1,351 @@ +/** + * 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_fs.c - работа с потоками данных. + */ + +#include +#include +#include +#include + +#include "lccrt_real.h" + +/** + * Разновидности потоков данных. + */ +typedef enum +{ + LCCRT_FS_TYPE_FILE, + LCCRT_FS_TYPE_BUFFER, + LCCRT_FS_TYPE_LAST +} lccrt_fs_type_t; + +/** + * Файловый поток данных. + */ +typedef struct lccrt_fs_r +{ + lccrt_context_ptr ctx; /* etc */ + lccrt_fs_type_t type; /* тип потока данных */ + FILE *file; + char *buff; + uint64_t buff_size; /* размер буфера (для LCCRT_FS_TYPE_BUFFER) */ + uint64_t syms_count; /* счетчик записанных или прочитанных символов */ + int8_t is_self; /* флаг владением потоком данных */ + int8_t is_error; /* флаг возникновения ошибки при работе с потоком данных */ + lccrt_check_type_t type_check; /* средства динамического контроля типа данных */ +} lccrt_fs_t; + +lccrt_check_type_define( lccrt_fs_t); + +/** + * Открытие потока данных. + */ +static lccrt_fs_ptr +lccrt_fs_new( lccrt_context_ptr ctx) +{ + lccrt_fs_ptr r = 0; + + r = lccrt_ctx_malloc( ctx, lccrt_fs_t); + memset( r, 0, sizeof( r[0])); + lccrt_check_type_init( r, lccrt_fs_t); + r->ctx = ctx; + r->type = LCCRT_FS_TYPE_LAST; + r->file = 0; + r->buff = 0; + r->buff_size = 0; + r->is_self = 0; + r->is_error = 0; + r->syms_count = 0; + + return (r); +} /* lccrt_fs_new */ + +/** + * Открытие потока данных на основе файла. + */ +lccrt_fs_ptr +lccrt_fs_new_file( lccrt_context_ptr ctx, FILE *file) +{ + lccrt_fs_ptr r = 0; + + if ( file ) + { + r = lccrt_fs_new( ctx); + r->type = LCCRT_FS_TYPE_FILE; + r->file = file; + } + + return (r); +} /* lccrt_fs_new_file */ + +/** + * Открытие потока данных на основе файла. + */ +lccrt_fs_ptr +lccrt_fs_open_file( lccrt_context_ptr ctx, const char *name, int is_load) +{ + lccrt_fs_ptr r = 0; + FILE *file = 0; + + file = fopen( name, is_load ? "r" : "w"); + if ( file ) + { + r = lccrt_fs_new_file( ctx, file); + r->is_self = 1; + } + + return (r); +} /* lccrt_fs_open_file */ + +/** + * Открытие потока данных на основе буфера в памяти. + */ +lccrt_fs_ptr +lccrt_fs_new_buffer( lccrt_context_ptr ctx, char *buff, uint64_t buff_size) +{ + lccrt_fs_ptr r = 0; + + r = lccrt_fs_new( ctx); + r->type = LCCRT_FS_TYPE_BUFFER; + if ( buff ) + { + r->buff_size = buff_size; + r->buff = buff; + } else + { + r->is_self = 1; + r->buff_size = buff_size ? buff_size : 4096; + r->buff = lccrt_ctx_mallocn( ctx, char, r->buff_size); + } + + return (r); +} /* lccrt_fs_new_buffer */ + +/** + * Закрытие потока данных. + */ +int +lccrt_fs_delete( lccrt_fs_ptr f) +{ + int r = 0; + + if ( f ) + { + lccrt_check_type_assert( f, lccrt_fs_t); + if ( (f->type == LCCRT_FS_TYPE_FILE) ) + { + if ( f->is_self ) + { + r = fclose( f->file); + } + } else if ( (f->type == LCCRT_FS_TYPE_BUFFER) ) + { + if ( f->is_self ) + { + lccrt_ctx_free( f->ctx, f->buff); + } + } else + { + r = -1; + lccrt_assert( 0); + } + + lccrt_check_type_done( f, lccrt_fs_t); + lccrt_ctx_free( f->ctx, f); + } + + return (r); +} /* lccrt_fs_delete */ + +/** + * Получить значение поля. + */ +int +lccrt_fs_is_error( lccrt_fs_ptr f) +{ + int r = 0; + + lccrt_check_type_assert( f, lccrt_fs_t); + r = f->is_error; + + return (r); +} /* lccrt_fs_is_error */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_fs_get_syms_count( lccrt_fs_ptr f) +{ + uint64_t r = 0; + + lccrt_check_type_assert( f, lccrt_fs_t); + r = f->syms_count; + + return (r); +} /* lccrt_fs_get_syms_count */ + +/** + * Для потока данных на основе буфера дать ссылку на область данных + * (ссылка доступна только до первого действия с потоком данных). + */ +char * +lccrt_fs_get_buffer( lccrt_fs_ptr f) +{ + char *r = f->buff; + + lccrt_check_type_assert( f, lccrt_fs_t); + + return (r); +} /* lccrt_fs_get_buffer */ + +/** + * Чтение символа из потока. + */ +int +lccrt_fs_get_sym( lccrt_fs_ptr f) +{ + int r = EOF; + + lccrt_check_type_assert( f, lccrt_fs_t); + if ( (f->type == LCCRT_FS_TYPE_FILE) ) + { + r = fgetc( f->file); + if ( !feof( f->file) ) + { + f->syms_count++; + } + } else if ( (f->type == LCCRT_FS_TYPE_BUFFER) ) + { + if ( (f->syms_count < f->buff_size) ) + { + r = f->buff[f->syms_count]; + f->syms_count++; + } + } else + { + lccrt_assert( 0); + } + + return (r); +} /* lccrt_fs_get_sym */ + +/** + * Форматированный вывод в поток данных. + */ +int +lccrt_fs_printf( lccrt_fs_ptr f, const char *fmt, ...) +{ + va_list ap; + int r = 0; + + lccrt_check_type_assert( f, lccrt_fs_t); + if ( !f->is_error ) + { + if ( (f->type == LCCRT_FS_TYPE_FILE) ) + { + va_start( ap, fmt); + r = vfprintf( f->file, fmt, ap); + va_end( ap); + + } else if ( (f->type == LCCRT_FS_TYPE_BUFFER) ) + { + int k = f->buff_size; + int j = f->syms_count; + + lccrt_assert( f->syms_count <= f->buff_size); + lccrt_assert( f->buff_size > 0); + if ( !f->is_self ) + { + va_start( ap, fmt); + r = vsnprintf( f->buff + j, k - j, fmt, ap); + va_end( ap); + if ( (r == k - j) ) + { + int l = 0; + char *b = lccrt_ctx_mallocn( f->ctx, char, r + 1); + + /* Проверяем, что размера буфера было достаточно для вывода + всех данных. */ + va_start( ap, fmt); + l = vsnprintf( b, r + 1, fmt, ap); + va_end( ap); + lccrt_ctx_free( f->ctx, b); + if ( (r != l) ) + { + /* Превышен допустимый размер буфера. */ + f->is_error = 1; + } + } + } else + { + int is_work = 1; + + while ( is_work ) + { + va_start( ap, fmt); + r = vsnprintf( f->buff + j, k - j, fmt, ap); + va_end( ap); + if ( (r < k - j) ) + { + /* Текущего размера буфера достаточно. */ + is_work = 0; + } else + { + /* Необходимо увеличить размер буфера. */ + f->buff_size = 2*f->buff_size; + f->buff = lccrt_ctx_realloc( f->ctx, f->buff, f->buff_size); + k = f->buff_size; + } + } + } + } else + { + lccrt_assert( 0); + r = -1; + } + + if ( (r < 0) ) + { + f->is_error = 1; + } else + { + f->syms_count += r; + } + } + + return (r); +} /* lccrt_fs_printf */ + +/** + * Вывод на печать строки и символа '\0', после строки. + */ +int +lccrt_fs_print_name_str( lccrt_fs_ptr f, const char *name) +{ + int r = 0; + + if ( name ) + { + int k = 0; + + for ( k = 0; name[k]; ++k ) + { + if ( (name[k] == 0) + || (name[k] == '\\') ) + { + r += lccrt_fs_printf( f, "\\"); + } + + r += lccrt_fs_printf( f, "%c", name[k]); + } + + r += lccrt_fs_printf( f, "%c", 0); + } + + return (r); +} /* lccrt_fs_print_name_str */ diff --git a/lib/common/lccrt_hash.c b/lib/common/lccrt_hash.c new file mode 100644 index 0000000..8d85c19 --- /dev/null +++ b/lib/common/lccrt_hash.c @@ -0,0 +1,557 @@ +/** + * 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_hash.c - работа с хеш-таблицами. + */ + +#include "internal/lccrt_ctx.h" + +lccrt_check_type_define( lccrt_hash_entry_t); +lccrt_check_type_define( lccrt_hash_t); + +/** + * Запись. + */ +typedef struct lccrt_hash_entry_r +{ + uintptr_t key; /* значение ключа */ + uintptr_t data; /* пользовательские данные */ + int64_t bucket_ident; /* номер корзины */ + lccrt_hash_ptr table; /* исходная таблица */ + lccrt_hash_entry_ptr prev; /* список записей в корзине */ + lccrt_hash_entry_ptr next; /* список записей в корзине */ + lccrt_check_type_t type_check; +} lccrt_hash_entry_t; + +/** + * Таблица. + */ +typedef struct lccrt_hash_r +{ + lccrt_ctx_ptr ctx; + lccrt_hash_key_type_t key_type; /* тип ключа, используемый в таблице */ + int64_t num_entries; /* общее количество всех записей */ + int64_t num_buckets; /* текущее количество корзин */ + lccrt_hash_entry_ptr *buckets; /* массив корзин */ + int64_t bucket_path_len; /* суммарный путь поиска по спискам */ + lccrt_check_type_t type_check; +} lccrt_hash_t; + +#define LCCRT_HASH_IS_REDUCE( h) \ +( \ + ((h)->num_entries < (h)->num_buckets/8) \ + && ((h)->num_buckets > 8) \ +) + +/** + * Создание новой таблицы. + */ +lccrt_h_ptr +lccrt_hash_new( lccrt_ctx_ptr ctx, lccrt_hkt_t type) +{ + lccrt_h_ptr r = lccrt_ctx_malloc( ctx, lccrt_hash_t); + + memset( r, 0, sizeof( r[0])); + lccrt_check_type_init( r, lccrt_hash_t); + r->ctx = ctx; + r->key_type = type; + lccrt_assert( (0 <= type) && (type < LCCRT_HASH_KEY_LAST)); + + return (r); +} /* lccrt_hash_new */ + +/** + * Удаление данных записи. + */ +static void +lccrt_hash_entry_delete_internal( lccrt_hash_entry_ptr he) +{ + lccrt_hash_ptr h = he->table; + lccrt_ctx_ptr ctx = h->ctx; + + lccrt_check_type_assert( he, lccrt_hash_entry_t); + if ( (h->key_type == LCCRT_HASH_KEY_STRING) ) + { + lccrt_ctx_free( ctx, (char *)he->key); + } else + { + lccrt_assert( h->key_type == LCCRT_HASH_KEY_INTPTR); + } + + lccrt_check_type_done( he, lccrt_hash_entry_t); + lccrt_ctx_free( ctx, he); + + return; +} /* lccrt_hash_entry_delete_internal */ + +/** + * Удаление таблицы. + */ +void +lccrt_hash_delete( lccrt_hash_ptr h) +{ + int64_t i; + lccrt_ctx_ptr ctx = h->ctx; + + lccrt_check_type_assert( h, lccrt_hash_t); + for ( i = 0; i < h->num_buckets; ++i ) + { + lccrt_hash_entry_ptr he, he_next; + + he = h->buckets[i]; + while ( he ) + { + he_next = he->next; + lccrt_assert( i == he->bucket_ident); + lccrt_hash_entry_delete_internal( he); + he = he_next; + } + } + + lccrt_ctx_free( ctx, h->buckets); + lccrt_check_type_done( h, lccrt_hash_t); + lccrt_ctx_free( ctx, h); + + return; +} /* lccrt_hash_delete */ + +/** + * Количество элементов в хеш-таблице. + */ +int64_t +lccrt_hash_length( lccrt_hash_ptr ht) +{ + int64_t r = ht->num_entries; + + return (r); +} /* lccrt_hash_length */ + +/** + * Вычисление хеш-значения для ключа. + */ +static uint64_t +lccrt_hash_key_calc( lccrt_hash_key_type_t type, uintptr_t key) +{ + uint64_t r = 0; + + if ( (type == LCCRT_HASH_KEY_INTPTR) ) + { + r = (uint64_t)key * 1103515245ULL; + + } else if ( (type == LCCRT_HASH_KEY_STRING) ) + { + const char *p = (char *)key; + + while ( p[0] ) + { + r = ((r << 7) | (r >> (64 - 7))) ^ (uint64_t)p[0]; + ++p; + } + } else + { + lccrt_assert( 0); + } + + return (r); +} /* lccrt_hash_key_calc */ + +/** + * Вычисление корзины для ключа. + */ +static int64_t +lccrt_hash_key_calc_pos( lccrt_hash_ptr h, uintptr_t key) +{ + int64_t r = -1; + + lccrt_check_type_assert( h, lccrt_hash_t); + if ( (h->num_buckets > 0) ) + { + r = lccrt_hash_key_calc( h->key_type, key) % h->num_buckets; + } + + return (r); +} /* lccrt_hash_key_calc_pos */ + +/** + * Сравнение двух ключей на равенство. + */ +static uintptr_t +lccrt_hash_key_copy( lccrt_ctx_ptr ctx, lccrt_hkt_t type, uintptr_t key) +{ + uintptr_t r = 0; + + if ( (type == LCCRT_HASH_KEY_STRING) ) + { + r = (uintptr_t)lccrt_ctx_copy_str( ctx, (const char *)key); + + } else if ( (type == LCCRT_HASH_KEY_INTPTR) ) + { + r = key; + } else + { + lccrt_assert( 0); + } + + return (r); +} /* lccrt_hash_key_copy */ + +/** + * Сравнение двух ключей на равенство. + */ +static int +lccrt_hash_keys_equal( lccrt_hkt_t type, uintptr_t key1, uintptr_t key2) +{ + int r = 0; + + if ( (type == LCCRT_HASH_KEY_STRING) ) + { + r = lccrt_str_eq( (const char *)key1, (const char *)key2); + + } else if ( (type == LCCRT_HASH_KEY_INTPTR) ) + { + r = (key1 == key2); + } else + { + lccrt_assert( 0); + } + + return (r); +} /* lccrt_hash_keys_equal */ + +/** + * Поиск в корзине записи с ключом заданного значения. + */ +static lccrt_hash_entry_ptr +lccrt_hash_bucket_find_key( lccrt_hash_entry_ptr he, uintptr_t key) +{ + lccrt_hash_entry_ptr r = 0; + + lccrt_check_type_assert( he, lccrt_hash_entry_t); + if ( he ) + { + int64_t i = 0; + lccrt_hash_ptr h = he->table; + lccrt_hash_key_type_t type = h->key_type; + + lccrt_check_type_assert( h, lccrt_hash_t); + if ( (type == LCCRT_HASH_KEY_INTPTR) ) + { + for ( ; he ; he = he->next, i++ ) + { + if ( (key == he->key) ) + { + r = he; + break; + } + } + } else if ( (type == LCCRT_HASH_KEY_STRING) ) + { + for ( ; he ; he = he->next, i++ ) + { + if ( lccrt_hash_keys_equal( type, key, he->key) ) + { + r = he; + break; + } + } + } else + { + lccrt_assert( 0); + } + + h->bucket_path_len += i; + } + + return (r); +} /* lccrt_hash_bucket_find_key */ + +/** + * Создать новую запись и вставить ее в список записей. + */ +static lccrt_hash_entry_ptr +lccrt_hash_entry_new( lccrt_hash_ptr h, uintptr_t key, uintptr_t data, + int64_t bucket_ident, lccrt_he_ptr prev, lccrt_he_ptr next) +{ + lccrt_ctx_ptr ctx = h->ctx; + lccrt_hash_key_type_t type = h->key_type; + lccrt_hash_entry_ptr r = lccrt_ctx_malloc( ctx, lccrt_hash_entry_t); + + lccrt_check_type_assert( h, lccrt_hash_t); + memset( r, 0, sizeof( r[0])); + lccrt_check_type_init( r, lccrt_hash_entry_t); + r->table = h; + r->bucket_ident = bucket_ident; + r->key = lccrt_hash_key_copy( ctx, type, key); + r->data = data; + r->prev = prev; + r->next = next; + if ( next ) + { + next->prev = r; + } + + if ( prev ) + { + prev->next = r; + } + + return (r); +} /* lccrt_hash_entry_new */ + +/** + * Увеличение/уменьшение количества корзин. + */ +static void +lccrt_hash_rebuild( lccrt_hash_ptr h, int is_increase) +{ + lccrt_ctx_ptr ctx = h->ctx; + lccrt_hash_key_type_t type = h->key_type; + + lccrt_check_type_assert( h, lccrt_hash_t); + h->bucket_path_len = 0; + if ( (h->num_entries > 0) ) + { + int64_t i; + lccrt_hash_entry_ptr *buckets = h->buckets; + int64_t num_buckets = h->num_buckets; + + h->num_buckets = is_increase ? 2*num_buckets : num_buckets/2; + lccrt_assert( num_buckets > 0); + h->buckets = lccrt_ctx_mallocn( ctx, lccrt_hash_entry_ptr, h->num_buckets); + memset( h->buckets, 0, h->num_buckets*sizeof( h->buckets[0])); + for ( i = 0; i < num_buckets; ++i ) + { + lccrt_hash_entry_ptr e, e_next; + + for ( e = buckets[i]; e; e = e_next ) + { + int64_t key_pos = lccrt_hash_key_calc_pos( h, e->key); + + e_next = e->next; + h->buckets[key_pos] = lccrt_hash_entry_new( h, e->key, e->data, key_pos, 0, h->buckets[key_pos]); + lccrt_hash_entry_delete_internal( e); + } + } + + lccrt_ctx_free( ctx, buckets); + } + + return; +} /* lccrt_hash_rebuild */ + +/** + * Добавить в таблицу запись с заданным ключом. + */ +lccrt_hash_entry_ptr +lccrt_hash_push( lccrt_hash_ptr h, uintptr_t key, int *is_new) +{ + lccrt_hash_entry_ptr r = 0; + lccrt_ctx_ptr ctx = h->ctx; + lccrt_hash_key_type_t type = h->key_type; + int64_t key_pos = -1; + lccrt_hash_entry_ptr he = 0; + + lccrt_check_type_assert( h, lccrt_hash_t); + if ( (h->num_buckets == 0) ) + { + lccrt_assert( h->num_entries == 0); + h->num_buckets = 1; + h->buckets = lccrt_ctx_mallocn( ctx, lccrt_hash_entry_ptr, 1); + key_pos = 0; + he = 0; + } else + { + key_pos = lccrt_hash_key_calc_pos( h, key); + he = h->buckets[key_pos]; + r = lccrt_hash_bucket_find_key( he, key); + } + + if ( r ) + { + lccrt_assign( is_new, 0); + } else + { + lccrt_assign( is_new, 1); + r = lccrt_hash_entry_new( h, key, 0, key_pos, 0, he); + h->buckets[key_pos] = r; + h->num_entries++; + } + +#if 0 + if ( (h->bucket_path_len >= h->num_entries) ) + { + //lccrt_hash_rebuild( h); + } +#endif + + if ( (h->num_entries > 0) + && (h->num_entries >= 4*h->num_buckets) ) + { + lccrt_hash_rebuild( h, 1); + r = lccrt_hash_find( h, key); + } + + return (r); +} /* lccrt_hash_push */ + +/** + * Поиск записи. + */ +lccrt_hash_entry_ptr +lccrt_hash_find( lccrt_hash_ptr h, uintptr_t key) +{ + lccrt_hash_entry_ptr r = 0; + + lccrt_check_type_assert( h, lccrt_hash_t); + if ( (h->num_entries > 0) + && (h->num_entries >= 4*h->num_buckets) ) + { + lccrt_assert( 0); + //lccrt_hash_rebuild( h, 1); + } + + if ( (h->num_entries > 0) ) + { + int64_t key_pos = lccrt_hash_key_calc_pos( h, key); + lccrt_hash_entry_ptr he = h->buckets[key_pos]; + + r = lccrt_hash_bucket_find_key( he, key); + } + + return (r); +} /* lccrt_hash_find */ + +/** + * Поиск записи. + */ +uintptr_t +lccrt_hash_remove( lccrt_hash_entry_ptr he) +{ + lccrt_hash_entry_ptr r = 0; + lccrt_hash_entry_ptr he_prev = he->prev; + lccrt_hash_entry_ptr he_next = he->next; + lccrt_hash_ptr h = he->table; + + lccrt_check_type_assert( he, lccrt_hash_entry_t); + lccrt_check_type_assert( h, lccrt_hash_t); + if ( he->next ) + { + he_next->prev = he_prev; + } + + if ( he_prev ) + { + he_prev->next = he_next; + } else + { + h->buckets[he->bucket_ident] = he_next; + } + + lccrt_hash_entry_delete_internal( he); + he = 0; + + h->num_entries--; + if ( LCCRT_HASH_IS_REDUCE( h) ) + { + lccrt_hash_rebuild( h, 0); + } + + return (0); +} /* lccrt_hash_remove */ + +/** + * Получить пользовательские данные. + */ +uintptr_t +lccrt_hash_get_key( lccrt_hash_entry_ptr he) +{ + uintptr_t r = he->key; + + lccrt_check_type_assert( he, lccrt_hash_entry_t); + + return (r); +} /* lccrt_hash_get_key */ + +/** + * Получить пользовательские данные. + */ +uintptr_t +lccrt_hash_get( lccrt_hash_entry_ptr he) +{ + uintptr_t r = he->data; + + lccrt_check_type_assert( he, lccrt_hash_entry_t); + + return (r); +} /* lccrt_hash_get */ + +/** + * Получить пользовательские данные. + */ +uintptr_t +lccrt_hash_set( lccrt_hash_entry_ptr he, uintptr_t data) +{ + uintptr_t r = lccrt_hash_get( he); + + he->data = data; + + return (r); +} /* lccrt_hash_set */ + +/** + * Получить первую запись. + */ +lccrt_hash_entry_ptr +lccrt_hash_first( lccrt_hash_ptr h) +{ + int64_t i; + lccrt_hash_entry_ptr r = 0; + + lccrt_check_type_assert( h, lccrt_hash_t); + if ( (h->num_entries > 0) ) + { + for ( i = 0; i < h->num_buckets; ++i ) + { + if ( h->buckets[i] ) + { + r = h->buckets[i]; + break; + } + } + } + + return (r); +} /* lccrt_hash_first */ + +/** + * Получить следующую запись. + */ +lccrt_hash_entry_ptr +lccrt_hash_next( lccrt_hash_entry_ptr he) +{ + lccrt_hash_entry_ptr r = 0; + lccrt_hash_ptr h = he->table; + + lccrt_check_type_assert( he, lccrt_hash_entry_t); + lccrt_check_type_assert( h, lccrt_hash_t); + if ( he->next ) + { + r = he->next; + } else + { + int64_t i; + + for ( i = he->bucket_ident + 1; i < h->num_buckets; ++i ) + { + if ( h->buckets[i] ) + { + r = h->buckets[i]; + break; + } + } + } + + return (r); +} /* lccrt_hash_next */ diff --git a/lib/irv/lccrt_asmout.c b/lib/irv/lccrt_asmout.c new file mode 100644 index 0000000..7b9ff29 --- /dev/null +++ b/lib/irv/lccrt_asmout.c @@ -0,0 +1,147 @@ +/** + * 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_asm.c - реализация печати ассемблера. + */ + +#include +#include +#include +#include +#include + +#include "lccrt_real.h" + +#define lccrt_snprintf_max( l, j) ((j < (l)) ? ((l) - j) : 0) +#define lccrt_snprintf( s, l, j, ...) \ + (j += snprintf( s + j, lccrt_snprintf_max( l, j), __VA_ARGS__)) + +/** + * Основная структура данных модуля печати ассемблера. + */ +typedef struct +{ + lccrt_fs_ptr fs; /* выходной поток данных */ + lccrt_hash_ptr types; /* множество типов, определение которых уже напечатаны */ +} lccrt_asm_out_t; + +/** + * Печать название идентификатора с экранированием по необходимости. + */ +void +lccrt_asm_print_name( lccrt_asm_out_t *ao, const char *name) +{ + int i; + int is_simple = 1; + + for ( i = 0; name[i]; ++i ) + { + if ( 0 ) + { + is_simple = 0; + } + } + + if ( is_simple ) + { + lccrt_fs_printf( ao->fs, "%s", name); + } else + { + lccrt_fs_printf( ao->fs, "\""); + for ( i = 0; name[i]; ++i ) + { + if ( 0 ) + { + lccrt_fs_printf( ao->fs, "%c", name[i]); + } else + { + lccrt_fs_printf( ao->fs, "\\%c", name[i]); + } + } + + lccrt_fs_printf( ao->fs, "\""); + } + + return; +} /* lccrt_asm_print_name */ + +void +lccrt_asm_print_type_definition( lccrt_asm_out_t *ao, lccrt_type_ptr type) +{ + lccrt_hash_entry_ptr e; + + lccrt_check_type_assert( type, lccrt_type_t); + e = lccrt_hash_find( ao->types, (uintptr_t)type); + + if ( e ) + { + } else if ( (type->type_name == LCCRT_TYPE_VOID) + || (type->type_name == LCCRT_TYPE_BOOL) + || (type->type_name == LCCRT_TYPE_INT) + || (type->type_name == LCCRT_TYPE_FLOAT) + || (type->type_name == LCCRT_TYPE_ELLIPSIS) ) + { + } else if ( (type->type_name == LCCRT_TYPE_PTR) ) + { + //lccrt_fs_printf( ao->fs, "type "); + //lccrt_asm_print_type_definition( ao, type->parent); + + } else if ( (type->type_name == LCCRT_TYPE_FUNC) ) + { + + } else if ( (type->type_name == LCCRT_TYPE_STRUCT) ) + { + + } else if ( (type->type_name == LCCRT_TYPE_FIELD) ) + { + + } else if ( (type->type_name == LCCRT_TYPE_ARRAY) ) + { + } else + { + fprintf( stderr, "type: %s\n", type->sym_name); + lccrt_assert( 0); + } + + return; +} /* lccrt_asm_print_type */ + +void +lccrt_asm_print_var( lccrt_asm_out_t *ao, lccrt_var_ptr v, int is_global) +{ + lccrt_check_type_assert( v, lccrt_var_t); + + lccrt_fs_printf( ao->fs, "var "); + lccrt_asm_print_name( ao, v->name); + + return; +} /* lccrt_asm_print_var */ + +/** + * Печатаем в выходной поток модуль. + */ +void +lccrt_asm_print_module( lccrt_fs_ptr fs, lccrt_module_ptr m) +{ + lccrt_hash_entry_ptr e; + lccrt_asm_out_t ao = {0}; + + ao.fs = fs; + ao.types = lccrt_hash_new( m->ctx, LCCRT_HASH_KEY_INTPTR); + + for ( e = lccrt_hash_first( m->types); e; e = lccrt_hash_next( e) ) + { + lccrt_asm_print_type_definition( &ao, (lccrt_type_ptr)lccrt_hash_get( e)); + } + + for ( e = lccrt_hash_first( m->gvars); e; e = lccrt_hash_next( e) ) + { + lccrt_asm_print_var( &ao, (lccrt_var_ptr)lccrt_hash_get( e), 1); + } + + lccrt_hash_delete( ao.types); + + return; +} /* lccrt_asm_print_module */ diff --git a/lib/irv/lccrt_func.c b/lib/irv/lccrt_func.c new file mode 100644 index 0000000..6dd7d3a --- /dev/null +++ b/lib/irv/lccrt_func.c @@ -0,0 +1,1241 @@ +/** + * 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 +#include +#include +#include +#include + +#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 */ diff --git a/lib/irv/lccrt_irreader.c b/lib/irv/lccrt_irreader.c new file mode 100644 index 0000000..63c8a53 --- /dev/null +++ b/lib/irv/lccrt_irreader.c @@ -0,0 +1,4045 @@ +/** + * 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_irreader.c - реализация чтения представления модуля. + */ + +#include +#include +#include +#include +#include + +#include "lccrt_real.h" + +#ifndef LCCRT_MIN +#define LCCRT_MIN( x, y) ((x) < (y) ? (x) : (y)) +#endif /* LCCRT_MIN */ + +// Максимальное количество элементов в типе. +#define LCCRT_IRR_MAX_ELEMS (4096) + +// Максимальный размер буфера для чтения символов. +#define LCCRT_IRR_BUFFER_LENGTH (8*1024*1024) + +// Максимальный размер сообщения об ошибке. +#define LCCRT_IRR_ERROR_LENGTH (1024) + +#define lccrt_irreader_error( irr, fmt, ...) \ +( \ + lccrt_irreader_close( irr), \ + ((irr)->error[0] \ + ? 0 \ + : snprintf( (irr)->error, LCCRT_IRR_ERROR_LENGTH, "lccrt: module load error: " fmt, ##__VA_ARGS__)) \ +) + +/** + * Максимальное количество полей в векторе. + */ +#define LCCRT_IRR_VEC_MAX (4) + +/** + * Расширяемый массив. + */ +typedef struct +{ + lccrt_ctx_ptr ctx; + int cur_length; /* текущее количество элементов */ + int max_length; /* количество выделенных элементов */ + int num_fields; /* количество полей */ + int64_t *data[LCCRT_IRR_VEC_MAX]; /* данные в виде независимого массива для каждого поля */ +} lccrt_vector_t; + +/** + * Описание лексемы. + */ +typedef struct +{ + char type; /* тип лексемы */ + const char *value; /* значение лексемы */ +} lccrt_irreader_lexem_t; + +/** + * Структура для передачи переменной либо (!) функции, либо операции. + */ +typedef struct +{ + lccrt_var_ptr gvar; + lccrt_function_ptr func; + lccrt_oper_ptr oper; +} lccrt_irreader_gfi_variant_t; + +/** + * Описание атрибута. + */ +typedef struct +{ + char *name; /* название атрибута */ + char *sval; /* значение атрибута */ + int64_t ival; /* значение атрибута как целового числа */ + int64_t work; /* значение для обходов множества атрибутов */ +} lccrt_irreader_attr_t; + +/** + * Данные для запроса значения атрибута. + */ +typedef struct +{ + char *name; + const char **sval; + int64_t *ival; + int8_t is_value; +} lccrt_irreader_attr_value_t; + +/** + * Описание адреса перехода в операции перехода. + */ +typedef struct lccrt_irreader_ctarg_r +{ + struct lccrt_irreader_ctarg_r *next; + lccrt_oper_ptr oper; + int arg_num; + char *label; +} lccrt_irreader_ctarg_t; + +/** + * Данные буфера для чтения символов (в лексическом анализаторе). + */ +typedef struct +{ + //char data[LCCRT_IRR_BUFFER_LENGTH]; // прочитанные данные + char *data; // прочитанные данные + int len; // текущее количество, прочитанных символов + int ind; // текущая позиция в буфере + int bytesize; // текущий байтовый размер всего буфера +} lccrt_irreader_buffer_t; + +/** + * Данные текущей читаемой процедуры. + */ +typedef struct +{ + lccrt_function_ptr f; + lccrt_hash_ptr labels; // (название,операция) + lccrt_hash_ptr lvars; // (название,локальнаяПеременная) + lccrt_irreader_ctarg_t *ct_args; // список описаний аргументов переходов +} lccrt_irreader_func_t; + +/** + * Данные для печати представления модуля. + */ +typedef struct +{ + lccrt_context_ptr ctx; + lccrt_module_ptr m; + int fd; // файловый дескриптор, из которого происходит чтение модуля + lccrt_irreader_buffer_t *b; // ссылка на буфер + char error[LCCRT_IRR_ERROR_LENGTH]; // сообщение об ошибке или пустая строка + lccrt_hash_ptr types; // (название,тип) + lccrt_hash_ptr names; // (название,полноеНазвание) + lccrt_hash_ptr gvars; // (название,глобальнаяПеременная) + lccrt_hash_ptr funcs; // (название,функция) + lccrt_hash_ptr vi_addrs; // (название,адресПеременной) + lccrt_hash_ptr gvars_elinks; // (глобал,строкаСоСпискомМетаданных) + lccrt_hash_ptr funcs_elinks; // (функция,строкаСоСпискомМетаданных) + lccrt_hash_ptr opers_elinks; // (операция,строкаСоСпискомМетаданных) + lccrt_hash_ptr ecats; // (индетификаторКод,идентификаторМодуль) + lccrt_hash_ptr etydes; // (идентификатор,описаниеТипаМетаданных) + lccrt_hash_ptr einfos; // (идентификатор,метаданные) + lccrt_var_ptr addr0; // временная переменная для предварительного взятия адреса + lccrt_irreader_func_t finfo; // данные по читаемой функции + //uintptr_t tident; // идентификатор типов + //uintptr_t nident; // идентификатор сокращенных имен + //lccrt_hash_ptr ptypes; // хеш-таблица с напечатанными типами (тип,номер) + //lccrt_hash_ptr snames; // хеш-таблица с сокращенными именами для глобалов и функций + lccrt_vector_t elems_tydes; // вектор для накопления описаний типов +} lccrt_irreader_t; + +/** + * Описание операции. + */ +typedef struct +{ + lccrt_oper_name_t code; + char *name; // строковое название операции + int8_t is_conv; // признак операции конверсии + lccrt_oper_name_t code_res; // версия операции с результатом +} lccrt_irreader_oper_descr_t; + +static int lccrt_irreader_read_type( lccrt_irreader_t *irr, lccrt_type_ptr *type); + +/** + * Описание операций. + */ +static lccrt_irreader_oper_descr_t lccrt_irreader_opers_descr[] = +{ + {LCCRT_OPER_CMP, "cmp", 0, -1}, + {LCCRT_OPER_BRANCH, "branch", 0, -1}, + {LCCRT_OPER_BRANCHIF, "branchif", 0, -1}, + {LCCRT_OPER_SWITCH, "switch", 0, -1}, + {LCCRT_OPER_RET, "ret", 0, -1}, + {LCCRT_OPER_CALLPROC, "call", 0, LCCRT_OPER_CALLFUNC}, + {LCCRT_OPER_INVOKEPROC, "invoke", 0, LCCRT_OPER_INVOKEFUNC}, + {LCCRT_OPER_LANDINGPAD, "landingpad", 0, -1}, + {LCCRT_OPER_VA_ARG, "vaarg", 0, -1}, + {LCCRT_OPER_ALLOCA, "alloca", 0, -1}, + {LCCRT_OPER_BITCAST, "bitcast", 0, -1}, + {LCCRT_OPER_SELECT, "select", 0, -1}, + {LCCRT_OPER_MOVE, "move", 0, -1}, + {LCCRT_OPER_VARPTR, "varptr", 0, -1}, + {LCCRT_OPER_ELEMPTR, "elemptr", 0, -1}, + {LCCRT_OPER_ELEMREAD, "elemread", 0, -1}, + {LCCRT_OPER_ELEMWRITE, "elemwrite", 0, -1}, + {LCCRT_OPER_SHUFFLE, "shuffle", 0, -1}, + {LCCRT_OPER_LOAD, "load", 0, -1}, + {LCCRT_OPER_STORE, "store", 0, -1}, + {LCCRT_OPER_SEXT, "sext", 1, -1}, + {LCCRT_OPER_ZEXT, "zext", 1, -1}, + {LCCRT_OPER_TRUNC, "trunc", 1, -1}, + {LCCRT_OPER_FPTOFP, "fptofp", 1, -1}, + {LCCRT_OPER_FPTOUI, "fptoui", 1, -1}, + {LCCRT_OPER_FPTOSI, "fptosi", 1, -1}, + {LCCRT_OPER_UITOFP, "uitofp", 1, -1}, + {LCCRT_OPER_SITOFP, "sitofp", 1, -1}, + {LCCRT_OPER_ADD, "add", 0, -1}, + {LCCRT_OPER_SUB, "sub", 0, -1}, + {LCCRT_OPER_MUL, "mul", 0, -1}, + {LCCRT_OPER_UDIV, "udiv", 0, -1}, + {LCCRT_OPER_SDIV, "sdiv", 0, -1}, + {LCCRT_OPER_UMOD, "umod", 0, -1}, + {LCCRT_OPER_SMOD, "smod", 0, -1}, + {LCCRT_OPER_SHL, "shl", 0, -1}, + {LCCRT_OPER_SHR, "shr", 0, -1}, + {LCCRT_OPER_SAR, "sar", 0, -1}, + {LCCRT_OPER_AND, "and", 0, -1}, + {LCCRT_OPER_OR, "or", 0, -1}, + {LCCRT_OPER_XOR, "xor", 0, -1}, + {LCCRT_OPER_FNEG, "fneg", 0, -1}, + {LCCRT_OPER_FADD, "fadd", 0, -1}, + {LCCRT_OPER_FMUL, "fmul", 0, -1}, + {LCCRT_OPER_FSUB, "fsub", 0, -1}, + {LCCRT_OPER_FDIV, "fdiv", 0, -1}, + {LCCRT_OPER_FMOD, "fmod", 0, -1}, + {-1}, +}; + +/** + * Структура для чтения аргументов операции. + */ +typedef struct +{ + int length; /* размер выделения памяти в элементах */ + union + { + void **data; + char **vstr; + lccrt_arg_t *varg; + } v; +} lccrt_irreader_arrptr_t; + +/** + * По необходимости увеличить размер массива указателей, чтобы вместить еще одни указатель. + */ +static int +lccrt_irreader_resize_ptrs( lccrt_irreader_t *irr, int cur_elems, int *length, void ***ptrs) +{ + lccrt_ctx_ptr ctx = irr->ctx; + + if ( (cur_elems + 1 > (*length)) ) + { + void **new_ptrs; + + if ( ((*length) == 0) ) + { + (*length) = 4; + } else + { + (*length) = 2*(*length); + } + + new_ptrs = lccrt_ctx_mallocn( ctx, void *, (*length)); + + if ( (*ptrs) ) + { + memcpy( new_ptrs, (*ptrs), cur_elems*sizeof( new_ptrs[0])); + lccrt_ctx_free( ctx, (*ptrs)); + } + + (*ptrs) = new_ptrs; + } + + return (1); +} /* lccrt_irreader_resize_ptrs */ + +/** + * Инициализировать вектор. + */ +static void +lccrt_vector_init( lccrt_vector_t *vec, lccrt_ctx_ptr ctx, int num_fields) +{ + int i; + + lccrt_assert( (0 <= num_fields) && (num_fields < LCCRT_IRR_VEC_MAX)); + memset( vec, 0, sizeof( vec[0])); + vec->ctx = ctx; + vec->num_fields = num_fields; + + return; +} /* lccrt_vector_init */ + +/** + * Завершить работу с вектором. + */ +static void +lccrt_vector_done( lccrt_vector_t *vec) +{ + int i; + + for ( i = 0; i < vec->num_fields; ++i ) + { + lccrt_ctx_free( vec->ctx, vec->data[i]); + } + + return; +} /* lccrt_vector_done */ + +/** + * Добавить в конец массива нового элемента. + */ +static void +lccrt_vector_reset( lccrt_vector_t *vec) +{ + vec->cur_length = 0; + + return; +} /* lccrt_vector_reset */ + +/** + * Получить ссылку на массив координаты. + */ +static int64_t * +lccrt_vector_get_data( lccrt_vector_t *vec, int k) +{ + int64_t *r = vec->data[k]; + + lccrt_assert( (0 <= k) && (k < vec->num_fields)); + + return (r); +} /* lccrt_vector_get_data */ + +/** + * Добавить в конец массива нового элемента. + */ +static int +lccrt_vector_pushback( lccrt_vector_t *vec, int64_t val[LCCRT_IRR_VEC_MAX]) +{ + int i; + lccrt_ctx_ptr ctx = vec->ctx; + + lccrt_assert( (0 <= vec->cur_length) && (vec->cur_length <= vec->max_length)); + lccrt_assert( (vec->max_length == 0) == (vec->data[0] == 0)); + if ( (vec->cur_length + 1 > vec->max_length) ) + { + if ( (vec->max_length == 0) ) + { + vec->max_length = 4; + } else + { + vec->max_length = 2*vec->max_length; + } + + for ( i = 0; i < vec->num_fields; ++i ) + { + int64_t *new_data = lccrt_ctx_mallocn( ctx, int64_t, vec->max_length); + + if ( vec->data[i] ) + { + memcpy( new_data, vec->data[i], vec->cur_length*sizeof( int64_t)); + lccrt_ctx_free( ctx, vec->data[i]); + } + + vec->data[i] = new_data; + } + } + + for ( i = 0; i < vec->num_fields; ++i ) + { + vec->data[i][vec->cur_length] = val[i]; + } + + vec->cur_length++; + + return (1); +} /* lccrt_vector_pushback */ + +/** + * Преобразование символа с шестнадцатиричной цифровой в целое число. + */ +static uint8_t +lccrt_irreader_hex_char_to_value( uint8_t c) +{ + uint8_t r = isdigit( c) ? (c - '0') : ((c < 'a') ? (c - 'A' + 10) : ( c - 'a' + 10)); + + lccrt_assert( isxdigit( c)); + + return (r); +} /* lccrt_irreader_hex_char_to_value */ + +/** + * Копирование строки с заменой экранирования символов на их значения. + * + * Возврат длины получившейся строки. + */ +static int +lccrt_irreader_copy_eval_escaping( char *dst, const char *src, int len) +{ + int i; + int r = 0; + + for ( i = 0; i < len; ++i ) + { + int v = src[i]; + int w = -1; + + if ( (v == '\\') ) + { + ++i; + if ( (i < len) ) + { + v = src[i]; + if ( (v == 'n') ) + { + dst[r] = '\n'; + ++r; + + } else if ( (v == 't') ) + { + dst[r] = '\t'; + ++r; + + } else if ( isxdigit( v) ) + { + ++i; + if ( (i < len) ) + { + w = src[i]; + if ( isxdigit( w) ) + { + v = lccrt_irreader_hex_char_to_value( v); + w = lccrt_irreader_hex_char_to_value( w); + dst[r] = (v << 4) | w; + ++r; + } else + { + r = -1; + } + } else + { + r = -1; + } + } else + { + r = -1; + } + } + } else if ( isprint( v) ) + { + dst[r] = src[i]; + ++r; + } else + { + r = -1; + } + + if ( (r == -1) ) + { + lccrt_assert( 0); + break; + } + } + + return (r); +} /* lccrt_irreader_copy_eval_escaping */ + +/** + * Подготовка буфера к работе. + */ +static void +lccrt_irreader_buffer_init( lccrt_ctx_ptr ctx, lccrt_irreader_buffer_t *b) +{ + memset( b, 0, sizeof( b[0])); + b->bytesize = LCCRT_IRR_BUFFER_LENGTH; + b->data = lccrt_ctx_mallocn( ctx, char, b->bytesize); + + return; +} /* lccrt_irreader_buffer_init */ + +/** + * Печать начальной части буфера в заданный массив. + */ +static char * +lccrt_irreader_print_head( lccrt_irreader_t *irr, int len, char *s) +{ + lccrt_irreader_buffer_t *b = irr->b; + + len = LCCRT_MIN( len, b->len); + snprintf( s, len, "%s", b->data + b->ind); + + return (s); +} /* lccrt_irreader_print_head */ + +/** + * Проверка, что поток данных открыт. + */ +static int +lccrt_irreader_is_open( lccrt_irreader_t *irr) +{ + int r = (irr->fd >= 0); + + return (r); +} /* lccrt_irreader_is_open */ + +/** + * Закрытие потока данных. + */ +static void +lccrt_irreader_close( lccrt_irreader_t *irr) +{ + if ( (irr->fd >= 0) ) + { + close( irr->fd); + } + + irr->fd = -1; + + return; +} /* lccrt_irreader_close */ + +/** + * Прочитать из входного потока не более указанного количества байт и записать в буфер. + * При исчерпании потока данных записать в конец буфера нулевой символ конца строки. + * + * Возвращается количество записанных (!) в буфер символов. + */ +static int +lccrt_irreader_read_block( lccrt_irreader_t *irr, int length) +{ + int r = 0; + lccrt_irreader_buffer_t *b = irr->b; + lccrt_ctx_ptr ctx = irr->ctx; + + lccrt_assert( length >= 0); + if ( (length > 0) ) + { + if ( lccrt_irreader_is_open( irr) ) + { + int k; + + if ( (b->len + length > b->bytesize) ) + { + char *old_data = b->data; + + // Увеличиваем байтовый размер в два раза. + b->data = lccrt_ctx_mallocn( ctx, char, 2*b->bytesize); + memcpy( b->data, old_data + b->ind, b->len); + b->ind = 0; + b->bytesize = 2*b->bytesize; + lccrt_ctx_free( ctx, old_data); + lccrt_assert( b->len + length <= b->bytesize); + } + + if ( (b->ind + b->len + length > b->bytesize) ) + { + // Смещаем данные буфера на начальную позицию. + memmove( b->data, b->data + b->ind, b->len); + b->ind = 0; + } + + k = read( irr->fd, b->data + b->ind + b->len, length); + if ( (k < 0) ) + { + // При чтении из потока данных возникла ошибка. + lccrt_irreader_error( irr, "read from file descriptor was failed"); + + } else if ( (k == 0) ) + { + // В потоке данных закончились данные. Пишем нулевой символ в конец буфера. + r = 1; + b->len += 1; + b->data[b->ind + b->len] = 0; + lccrt_irreader_close( irr); + } else + { + r = k; + b->len += k; + } + + if ( (b->ind + b->len + 1 < b->bytesize) ) + { + // Для удобства отладки пишем символ конца строки в конец данных буфера. + b->data[b->ind + b->len] = 0; + } + } + } + + return (r); +} /* lccrt_irreader_read_block */ + +/** + * По необходимости прочитать блок данных. Вернуть символ с указанной позиции. + */ +static int +lccrt_irreader_read_char( lccrt_irreader_t *irr, int count) +{ + int r = -1; + lccrt_irreader_buffer_t *b = irr->b; + + while ( lccrt_irreader_is_open( irr) + && (count >= b->len) ) + { + lccrt_irreader_read_block( irr, 1024); + } + + if ( (count < b->len) ) + { + r = b->data[b->ind + count]; + } + + return (r); +} /* lccrt_irreader_read_char */ + +/** + * Проверить наличие заданного символа на указанной позиции. + */ +static int +lccrt_irreader_is_char( lccrt_irreader_t *irr, int position, char value) +{ + int r = (lccrt_irreader_read_char( irr, position) == value); + + return (r); +} /* lccrt_irreader_is_char */ + +/** + * Пропустить заданное количество символов в буфере (и последующие пробельные + * символы). + */ +static int +lccrt_irreader_skip( lccrt_irreader_t *irr, int len, int is_skip_space) +{ + int i; + lccrt_irreader_buffer_t *b = irr->b; + + lccrt_assert( (0 <= len) && (len <= b->len) && (b->ind + b->len <= b->bytesize)); + b->ind += len; + b->len -= len; + if ( (b->len == 0) ) + { + b->ind = 0; + } + + if ( is_skip_space ) + { + int v = lccrt_irreader_read_char( irr, 0); + + while ( (v > 0) && isspace( v) ) + { + b->ind++; + b->len--; + lccrt_assert( b->len >= 0); + if ( (b->len == 0) ) + { + b->ind = 0; + } + + v = lccrt_irreader_read_char( irr, 0); + } + } + + return (1); +} /* lccrt_irreader_skip */ + +/** + * Пропустить пробельные символы. + */ +static int +lccrt_irreader_skip_spaces( lccrt_irreader_t *irr) +{ + int r = lccrt_irreader_skip( irr, 0, 1); + + return (r); +} /* lccrt_irreader_skip_spaces */ + +/** + * Пропустить заданное количество символов. + */ +static int +lccrt_irreader_skip_chars( lccrt_irreader_t *irr, int n) +{ + int r = lccrt_irreader_skip( irr, n, 0); + + return (r); +} /* lccrt_irreader_skip_chars */ + +/** + * В предположении, что первые 'count' символов являются началом лексемы, проверить, что + * далее лексема завершается. + */ +static int +lccrt_irreader_is_lexem_from_count( lccrt_irreader_t *irr, int count, int *final_count) +{ + int i; + int r = 0; + lccrt_irreader_buffer_t *b = irr->b; + + for ( i = count; i < b->len; ++i ) + { + int v = b->data[b->ind + i]; + + if ( isspace( v) + || (v == ';') + || (v == 0) ) + { + if ( (i > 0) + || (count > 0) ) + { + r = 1; + } + + break; + } + } + + if ( final_count ) + { + (*final_count) = i; + } + + return (r); +} /* lccrt_irreader_is_lexem_from_count */ + +/** + * По необходимости прочитать и записать в буфер символы так, чтобы в начале буфера была + * строка. Строкой считается последовательность символов между двойными кавычками с + * экранированием. Прочитать строку, записать ее копию в выходной параметрой с преобразованием + * экранированных символов, и установить указатель буфера после строки. + * + * Возвращается не ноль, если удалось прочитать строку, а также копия строки в (*value). + * В случае возврата строки ее удаляет пользователь. + */ +static int +lccrt_irreader_read_string0( lccrt_irreader_t *irr, char **value, int *length) +{ + char s[64]; + int i = 0; + int r = 0; + int v = -1; + int w = -1; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_irreader_buffer_t *b = irr->b; + + (*value) = 0; + if ( length ) + { + (*length) = 0; + } + + v = lccrt_irreader_read_char( irr, i); + if ( (v == '"') ) + { + int is_work = 1; + + i++; + while ( is_work ) + { + is_work = 0; + v = lccrt_irreader_read_char( irr, i); + if ( (v == '"') ) + { + i++; + r = 1; + + } else if ( (v == '\\') ) + { + i++; + v = lccrt_irreader_read_char( irr, i); + w = lccrt_irreader_read_char( irr, i + 1); + if ( (v == 'n') + || (v == 't') ) + { + i++; + is_work = 1; + + } else if ( isxdigit( v) + && isxdigit( w) + && (length + || (v > 0) + || (w > 0)) ) + { + i += 2; + is_work = 1; + } else + { + lccrt_irreader_error( irr, "expected escaped value instead [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } else if ( isprint( v) ) + { + i++; + is_work = 1; + } else + { + lccrt_irreader_error( irr, "expected '\"' instead [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } + } else + { + lccrt_irreader_error( irr, "expected '\"' instead [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + if ( r ) + { + char *q; + int l = i - 2; + int slen = 0; + + lccrt_assert( i >= 2); + q = lccrt_ctx_mallocn( ctx, char, l + 1); + slen = lccrt_irreader_copy_eval_escaping( q, b->data + b->ind + 1, l); + q[slen] = 0; + lccrt_irreader_skip( irr, l + 2, 1); + (*value) = q; + if ( length ) + { + (*length) = slen; + } + } + + return (r); +} /* lccrt_irreader_read_string0 */ + +/** + * Пропустить пробельные символы и прочитать строку (см. lccrt_irreader_read_string0). + */ +static int +lccrt_irreader_read_string( lccrt_irreader_t *irr, char **value, int *length) +{ + int r = 0; + + lccrt_irreader_skip_spaces( irr); + r = lccrt_irreader_read_string0( irr, value, length); + + return (r); +} /* lccrt_irreader_read_string */ + +/** + * Прочитать плавающее значение. + */ +static int +lccrt_irreader_read_float( lccrt_irreader_t *irr, double *value) +{ + int i; + int v = -1; + int work = 1; + lccrt_irreader_buffer_t *b = irr->b; + const char *p = 0; + char *q = 0; + int r = 0; + + for ( i = 0; work; ++i ) + { + work = 0; + v = lccrt_irreader_read_char( irr, i); + if ( isalnum( v) + || (v == '-') + || (v == '+') + || (v == '.') ) + { + work = 1; + } + } + + p = b->data + b->ind; + (*value) = strtod( p, &q); + lccrt_irreader_skip_chars( irr, q - p); + r = (q > p); + + return (r); +} /* lccrt_irreader_read_float */ + +/** + * Прочитать целое значение (со знаком). + */ +static int +lccrt_irreader_read_int( lccrt_irreader_t *irr, int64_t *value, int is_hex) +{ + int i; + int r = 0; + lccrt_irreader_buffer_t *b = irr->b; + int v = lccrt_irreader_read_char( irr, 0); + int is_dig0 = isdigit( v) || (is_hex && isxdigit( v)); + + (*value) = 0; + if ( (!is_hex + && ((v == '-') + || (v == '+'))) + || is_dig0 ) + { + for ( i = 1; 1; ++i ) + { + int w = lccrt_irreader_read_char( irr, i); + + if ( !(isdigit( w) + || (is_hex + && isxdigit( w))) ) + { + break; + } + } + + if ( is_dig0 + || (i > 2) ) + { + char *p1 = 0; + char *p0 = b->data + b->ind; + + if ( is_hex ) + { + (*value) = strtoull( p0, &p1, 16); + } else + { + (*value) = strtoll( p0, &p1, 10); + } + + if ( (p1 - p0 == i) ) + { + r = 1; + lccrt_irreader_skip( irr, i, 0); + } + } + } + + return (r); +} /* lccrt_irreader_read_int */ + +/** + * Пропустить пробельные символы, затем по необходимости прочитать и записать в буфер + * символы так, чтобы в начале буфера была лексема. Считается, что в начале буфера + * находится лексема, если в начале буфера находится строка или первый символ не нулевой + * и не конец строки, а после него обязательно встретится нулевой символ, символ конца + * строки или точка с запятой. + * + * Возвращается не ноль, если в начале буфера теперь находится лексема или строка. + */ +static int +lccrt_irreader_read_lexem( lccrt_irreader_t *irr) +{ + int i = 0; + int r = 0; + lccrt_irreader_buffer_t *b = irr->b; + + lccrt_irreader_skip_spaces( irr); + while ( lccrt_irreader_is_open( irr) + && !lccrt_irreader_is_lexem_from_count( irr, i, &i) ) + { + lccrt_irreader_read_block( irr, 1024); + } + + if ( lccrt_irreader_is_lexem_from_count( irr, i, 0) ) + { + r = 1; + } + + return (r); +} /* lccrt_irreader_read_lexem */ + +/** + * Проверяем, что в начале буфера находится заданная лексема. + */ +static int +lccrt_irreader_is_lexem( lccrt_irreader_t *irr, const char *lexem, int is_skip) +{ + int r = 0; + lccrt_irreader_buffer_t *b = irr->b; + int lexem_len = strlen( lexem); + + while ( lccrt_irreader_is_open( irr) + && (b->len < lexem_len) ) + { + lccrt_irreader_read_block( irr, 1024); + } + + if ( (b->len > 0) + && (lexem_len <= b->len) + && (strncmp( lexem, b->data + b->ind, lexem_len) == 0) ) + { + r = 1; + lccrt_irreader_skip( irr, strlen( lexem), is_skip); + } + + return (r); +} /* lccrt_irreader_is_lexem */ + +/** + * Проверка на наличие и пропуск пробельного символа. + */ +static int +lccrt_irreader_is_delim( lccrt_irreader_t *irr) +{ + int r = 0; + + if ( isspace( lccrt_irreader_read_char( irr, 0)) + && lccrt_irreader_skip_chars( irr, 1) ) + { + r = 1; + } + + return (r); +} /* lccrt_irreader_is_delim */ + +/** + * Чтение имени идентификатора. + */ +static int +lccrt_irreader_read_ident_simple( lccrt_irreader_t *irr, char **ident) +{ + char s[64]; + int i = 0; + int r = 0; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_irreader_buffer_t *b = irr->b; + int v = lccrt_irreader_read_char( irr, 0); + + (*ident) = 0; + if ( (v == '_') + || isalpha( v) ) + { + char *q; + + r = 1; + for ( i = 1; 1; ++i ) + { + v = lccrt_irreader_read_char( irr, i); + if ( !((v == '_') + || isalnum( v)) ) + { + break; + } + } + + q = lccrt_ctx_mallocn( ctx, char, i + 1); + memcpy( q, b->data + b->ind, i); + q[i] = 0; + lccrt_irreader_skip( irr, i, 0); + (*ident) = q; + } else + { + lccrt_irreader_error( irr, "invalid ident, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return (r); +} /* lccrt_irreader_read_ident_simple */ + +/** + * Чтение имени идентификатора. + */ +static int +lccrt_irreader_read_ident( lccrt_irreader_t *irr, char **ident) +{ + char s[64]; + int i = 0; + int r = 0; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_irreader_buffer_t *b = irr->b; + int v = lccrt_irreader_read_char( irr, 0); + + (*ident) = 0; + if ( (v == '"') ) + { + if ( lccrt_irreader_read_string( irr, ident, 0) ) + { + r = 1; + } else + { + lccrt_irreader_error( irr, "invalid string, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } else if ( lccrt_irreader_is_lexem( irr, "@", 0) ) + { + char *nname = 0; + + if ( lccrt_irreader_read_ident_simple( irr, &nname) ) + { + lccrt_hash_entry_ptr e = lccrt_hash_find( irr->names, (uintptr_t)nname); + + if ( e ) + { + r = 1; + (*ident) = lccrt_ctx_copy_str( ctx, (char *)lccrt_hash_get( e)); + } else + { + lccrt_irreader_error( irr, "unknown @name [%s], [%s ...]", + nname, lccrt_irreader_print_head( irr, 64, s)); + } + } + + lccrt_ctx_free( ctx, nname); + } else + { + r = lccrt_irreader_read_ident_simple( irr, ident); + } + + return (r); +} /* lccrt_irreader_read_ident */ + +/** + * Прочитать цепочку лексем. + */ +static int +lccrt_irreader_is_lexems( lccrt_irreader_t *irr, lccrt_irreader_lexem_t *lexs, void *args[]) +{ + int i; + int r = 1; + int k = 0; + + for ( i = 0; r && (lexs[i].type > 0); ++i ) + { + int64_t ival = 0; + + switch ( lexs[i].type ) + { + case 'S': + // Должен быть прочитан пробельный символ. + r = lccrt_irreader_is_delim( irr); + break; + case 'l': + case 'L': + // Должна быть прочитана конкретная последовательность символов. + if ( (lexs[i].type == 'l') ) lccrt_irreader_skip_spaces( irr); + r = lccrt_irreader_is_lexem( irr, lexs[i].value, 1); + break; + case 'n': + case 'N': + // Должна быть прочитана строка. + if ( (lexs[i].type == 'n') ) lccrt_irreader_skip_spaces( irr); + r = lccrt_irreader_read_ident( irr, (char **)args[k]); + ++k; + break; + case 'x': + case 'X': + // Должно быть прочитано число в шестнадцатиричном формате. + if ( (lexs[i].type == 'x') ) lccrt_irreader_skip_spaces( irr); + if ( lccrt_irreader_is_char( irr, 0, '0') + && lccrt_irreader_is_char( irr, 1, 'x') + && lccrt_irreader_skip_chars( irr, 2) ) + { + r = lccrt_irreader_read_int( irr, &ival, 1); + ((int64_t**)args)[k][0] = ival; + ++k; + } + break; + case 'u': + case 'U': + // Должно быть прочитано число. + if ( (lexs[i].type == 'u') ) lccrt_irreader_skip_spaces( irr); + r = lccrt_irreader_read_int( irr, &ival, 0) && (ival >= 0); + ((int64_t**)args)[k][0] = ival; + ++k; + break; + default: + r = 0; + break; + } + } + + return (r); +} /* lccrt_irreader_is_lexems */ + +/** + * Чтение определения строкового значения. + */ +static char * +lccrt_irreader_read_define_str( lccrt_irreader_t *irr) +{ + char s[64]; + char *r = 0; + int len = -1; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_irreader_buffer_t *b = irr->b; + + if ( lccrt_irreader_is_lexem( irr, "=", 1) + && lccrt_irreader_read_string( irr, &r, 0) ) + { + if ( !lccrt_irreader_is_lexem( irr, ";", 1) ) + { + lccrt_ctx_free( ctx, r); + r = 0; + lccrt_irreader_error( irr, "expected ';' instead [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } else + { + lccrt_irreader_error( irr, "expected '= \"string\"' instead [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return (r); +} /* lccrt_irreader_read_define_str */ + +/** + * Чтение определения целого значения. + */ +static int64_t +lccrt_irreader_read_define_int( lccrt_irreader_t *irr) +{ + char s[64]; + int i; + int64_t r = 0; + lccrt_irreader_buffer_t *b = irr->b; + + if ( lccrt_irreader_is_lexem( irr, "=", 1) + && lccrt_irreader_read_lexem( irr) ) + { + if ( lccrt_irreader_read_int( irr, &r, 0) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, ";", 1) ) + { + } else + { + lccrt_irreader_error( irr, "expected ';' instead [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } else + { + lccrt_irreader_error( irr, "expected '= intval' instead [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return (r); +} /* lccrt_irreader_read_define_int */ + +/** + * Чтение значения директивы 'config'. + */ +static void +lccrt_irreader_read_config( lccrt_irreader_t *irr, lccrt_asm_compile_config_t *acc) +{ + char s[64]; + lccrt_ctx_ptr ctx = irr->ctx; + + if ( lccrt_irreader_is_lexem( irr, "target", 1) ) + { + lccrt_ctx_free( ctx, acc->target); + acc->target = lccrt_irreader_read_define_str( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "out_type", 1) ) + { + lccrt_ctx_free( ctx, acc->out_type); + acc->out_type = lccrt_irreader_read_define_str( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "opt_level", 1) ) + { + acc->opt_level = lccrt_irreader_read_define_int( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "is_pic", 1) ) + { + acc->is_pic = lccrt_irreader_read_define_int( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "pie_level", 1) ) + { + acc->pie_level = lccrt_irreader_read_define_int( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "dbg_level", 1) ) + { + acc->dbg_level = lccrt_irreader_read_define_int( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "function_sections", 1) ) + { + acc->function_sections = lccrt_irreader_read_define_int( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "data_sections", 1) ) + { + acc->data_sections = lccrt_irreader_read_define_int( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "asm_verbose", 1) ) + { + acc->asm_verbose = lccrt_irreader_read_define_int( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "llvmir_embed_static_only", 1) ) + { + acc->is_llvmir_embed_static_only = lccrt_irreader_read_define_int( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "eh_personality", 1) ) + { + lccrt_ctx_free( ctx, acc->eh_personality); + acc->eh_personality = lccrt_irreader_read_define_str( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "cpu_arch", 1) ) + { + lccrt_ctx_free( ctx, acc->cpu_arch); + acc->cpu_arch = lccrt_irreader_read_define_str( irr); + + } else if ( lccrt_irreader_is_lexem( irr, "cflags", 1) ) + { + lccrt_ctx_free( ctx, acc->cflags); + acc->cflags = lccrt_irreader_read_define_str( irr); + } else + { + lccrt_irreader_error( irr, "invalid config property [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return; +} /* lccrt_irreader_read_config */ + +/** + * Проверить название атрибута и вычислить его целое значение. + */ +static int +lccrt_irreader_eval_attr( const char *name, const char *sval, int64_t *ival) +{ + int r = 1; + int64_t v = 0; + + (*ival) = 0; + if ( (strcmp( name, "const") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "nothrow") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "used") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "restrict") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "volatile") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "common") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "extern") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "alias") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "atomic") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "cleanup") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "extinline") == 0) ) + { + r = (sval == 0); + v = 1; + + } else if ( (strcmp( name, "loc") == 0) ) + { + if ( (strcmp( sval, "carg") == 0) ) { v = LCCRT_VAR_LOC_CONSTARG; } + else if ( (strcmp( sval, "glob") == 0) ) { v = LCCRT_VAR_LOC_GLOB; } + else if ( (strcmp( sval, "ext") == 0) ) { v = LCCRT_VAR_LOC_EXT; } + else { r = 0; } + + } else if ( (strcmp( name, "bind") == 0) ) + { + if ( (strcmp( sval, "loc") == 0) ) { v = LCCRT_LINK_BND_LOCAL; } + else if ( (strcmp( sval, "glob") == 0) ) { v = LCCRT_LINK_BND_GLOBAL; } + else if ( (strcmp( sval, "weak") == 0) ) { v = LCCRT_LINK_BND_WEAK; } + else { r = 0; } + + } else if ( (strcmp( name, "vis") == 0) ) + { + if ( (strcmp( sval, "hid") == 0) ) { v = LCCRT_LINK_VIS_HIDDEN; } + else { r = 0; } + + } else if ( (strcmp( name, "tls") == 0) ) + { + if ( (strcmp( sval, "no") == 0) ) { v = LCCRT_LINK_TLS_NO; } + else if ( (strcmp( sval, "dyn_g") == 0) ) { v = LCCRT_LINK_TLS_DYNAMIC_G; } + else if ( (strcmp( sval, "dyn_l") == 0) ) { v = LCCRT_LINK_TLS_DYNAMIC_L; } + else if ( (strcmp( sval, "exec_i") == 0) ) { v = LCCRT_LINK_TLS_EXEC_I; } + else if ( (strcmp( sval, "exec_l") == 0) ) { v = LCCRT_LINK_TLS_EXEC_L; } + else { r = 0; } + + } else if ( (strcmp( name, "einfo") == 0) ) + { + r = (sval != 0); + + } else if ( (strcmp( name, "comdat") == 0) ) + { + r = (sval != 0); + + } else if ( (strcmp( name, "section") == 0) ) + { + r = (sval != 0); + + } else if ( (strcmp( name, "size") == 0) ) + { + r = (sval != 0); + v = r ? atoll( sval) : 0; + + } else if ( (strcmp( name, "align") == 0) ) + { + r = (sval != 0); + v = r ? atoll( sval) : 0; + + } else if ( (strcmp( name, "shift") == 0) ) + { + r = (sval != 0); + v = r ? atoll( sval) : 0; + + } else if ( (strcmp( name, "bitsize") == 0) ) + { + r = (sval != 0); + v = r ? atoll( sval) : 0; + + } else if ( (strcmp( name, "bitshift") == 0) ) + { + r = (sval != 0); + v = r ? atoll( sval) : 0; + + } else if ( (strcmp( name, "ctor") == 0) ) + { + r = (sval != 0); + v = r ? atoll( sval) : 0; + + } else if ( (strcmp( name, "dtor") == 0) ) + { + r = (sval != 0); + v = r ? atoll( sval) : 0; + } else + { + r = 0; + } + + if ( r ) + { + (*ival) = v; + } + + return (r); +} /* lccrt_irreader_eval_attr */ + +/** + * Удалить данные атрибутов. + */ +static void +lccrt_irreader_free_attrs( lccrt_irreader_t *irr, int num_attrs, lccrt_irreader_attr_t *attrs) +{ + int i; + lccrt_ctx_ptr ctx = irr->ctx; + + for ( i = 0; i < num_attrs; ++i ) + { + lccrt_ctx_free( ctx, attrs[i].name); + lccrt_ctx_free( ctx, attrs[i].sval); + } + + return; +} /* lccrt_irreader_free_attrs */ + +/** + * Чтение целого числа в качестве значения атрибута. + */ +static int +lccrt_irreader_read_attr_value_int( lccrt_irreader_t *irr, char **ident) +{ + char q[64]; + int64_t ival = 0; + int r = 0; + lccrt_ctx_ptr ctx = irr->ctx; + + (*ident) = 0; + if ( lccrt_irreader_read_int( irr, &ival, 0) ) + { + int ilen = snprintf( q, 64, "%jd", ival); + + r = 1; + (*ident) = lccrt_ctx_mallocn( ctx, char, 1 + ilen); + strcpy( (*ident), q); + } + + return (r); +} /* lccrt_irreader_read_attr_value_int */ + +/** + * Прочитать значение атрибута. + */ +static int +lccrt_irreader_read_attr_value( lccrt_irreader_t *irr, char **ident) +{ + int v; + int r = 0; + lccrt_ctx_ptr ctx = irr->ctx; + + (*ident) = 0; + lccrt_irreader_skip_spaces( irr); + v = lccrt_irreader_read_char( irr, 0); + if ( (v == '%') ) + { + v = lccrt_irreader_read_char( irr, 1); + if ( (v == 'd') ) + { + // Особый случай для метаданных. + lccrt_irreader_skip_chars( irr, 2); + r = lccrt_irreader_read_attr_value_int( irr, ident); + } + } else if ( isdigit( v) + || (v == '-') + || (v == '+') ) + { + r = lccrt_irreader_read_attr_value_int( irr, ident); + + } else if ( lccrt_irreader_read_ident( irr, ident) ) + { + r = 1; + } + + return (r); +} /* lccrt_irreader_read_attr_value */ + +/** + * Чтение атрибутов. + */ +static int +lccrt_irreader_read_attrs( lccrt_irreader_t *irr, int max_attrs, lccrt_irreader_attr_t *attrs, + int *num_attrs) +{ + char s[64]; + int k = 0; + int r = 1; + lccrt_ctx_ptr ctx = irr->ctx; + + (*num_attrs) = 0; + lccrt_irreader_skip_spaces( irr); + while ( lccrt_irreader_is_char( irr, 0, '.') ) + { + char *name = 0; + char *attr = 0; + int64_t ival = 0; + + r = 0; + if ( lccrt_irreader_skip_chars( irr, 1) + && lccrt_irreader_read_ident_simple( irr, &name) + && lccrt_irreader_skip_spaces( irr) + && ((lccrt_irreader_read_char( irr, 0) != '(') + || (lccrt_irreader_is_lexem( irr, "(", 1) + && lccrt_irreader_read_attr_value( irr, &attr) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, ")", 1))) ) + { + if ( (k < max_attrs) ) + { + if ( lccrt_irreader_eval_attr( name, attr, &ival) ) + { + r = 1; + attrs[k].name = name; + attrs[k].sval = attr; + attrs[k].ival = ival; + name = 0; + attr = 0; + ++k; + } else + { + lccrt_irreader_error( irr, "fails to read attribute [%s], [%s ...]", + name, lccrt_irreader_print_head( irr, 64, s)); + } + } else + { + lccrt_irreader_error( irr, "to many attributes, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } else + { + lccrt_irreader_error( irr, "fails to read attribute, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + lccrt_ctx_free( ctx, name); + lccrt_ctx_free( ctx, attr); + } + + if ( r ) + { + (*num_attrs) = k; + } else + { + lccrt_irreader_free_attrs( irr, k, attrs); + } + + return (r); +} /* lccrt_irreader_read_attrs */ + +/** + * Найти в таблице значений атрибутов заданное значение атрибута. + */ +static lccrt_irreader_attr_value_t * +lccrt_irreader_get_attr_value( lccrt_irreader_attr_value_t *attrs, const char *name) +{ + int i; + lccrt_irreader_attr_value_t *v = 0; + + for ( i = 0; attrs[i].name; ++i ) + { + if ( (strcmp( name, attrs[i].name) == 0) ) + { + v = attrs + i; + } + } + + return (v); +} /* lccrt_irreader_get_attr_value */ + +/** + * Для множества атрибутов, проверить что все атрибуты задействованы во множестве значений + * атрибутов. А также для каждого элемента из множества значений вычислить его значение. + */ +static int +lccrt_irreader_process_attrs( int num_attrs, lccrt_irreader_attr_t *attrs, + lccrt_irreader_attr_value_t *vals) +{ + int i, j; + int r = 1; + int num_vals = 0; + + for ( i = 0; i < num_attrs; ++i ) + { + attrs[i].work = 0; + } + + for ( i = 0; vals[i].name; ++i ) + { + lccrt_irreader_attr_value_t *vi = vals + i; + + vi->is_value = 0; + if ( vi->sval ) + { + (*vi->sval)= 0; + } + + if ( vi->ival ) + { + (*vi->ival)= 0; + } + + for ( j = 0; j < num_attrs; ++j ) + { + lccrt_irreader_attr_t *aj = attrs + j; + + if ( (strcmp( vi->name, aj->name) == 0) ) + { + vi->is_value = 1; + aj->work = 1; + if ( vi->sval ) + { + (*vi->sval) = aj->sval; + } + + if ( vi->ival ) + { + (*vi->ival) = aj->ival; + } + } + } + } + + for ( i = 0; i < num_attrs; ++i ) + { + if ( !attrs[i].work ) + { + r = 0; + break; + } + } + + return (r); +} /* lccrt_irreader_process_attrs */ + +/** + * Прочитать тип структура. + */ +static lccrt_type_ptr +lccrt_irreader_read_type_struct( lccrt_irreader_t *irr, int is_union) +{ + int i; + int v; + char s[64]; + lccrt_irreader_attr_t attrs[256]; + int64_t size = 0; + int64_t align = 0; + int num_attrs = 0; + lccrt_type_ptr r = 0; + lccrt_m_ptr m = irr->m; + lccrt_irreader_attr_value_t sattrs[] = + { + { "size", 0, &size}, + { "align", 0, &align}, + { 0, 0, 0} + }; + lccrt_irreader_attr_value_t *a_size = lccrt_irreader_get_attr_value( sattrs, "size"); + lccrt_irreader_attr_value_t *a_align = lccrt_irreader_get_attr_value( sattrs, "align"); + + if ( lccrt_irreader_read_attrs( irr, 256, attrs, &num_attrs) + && lccrt_irreader_process_attrs( num_attrs, attrs, sattrs) + && a_size->is_value + && a_align->is_value + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, "{", 1) ) + { + int num_flds = 0; + int length = 0; + lccrt_type_ptr *flds = 0; + + v = lccrt_irreader_read_char( irr, 0); + for ( i = 0; (v > 0) && (v != '}'); ++i ) + { + lccrt_type_ptr ftype; + int64_t shift = 0; + int64_t bitsize = 0; + int64_t bitshift = 0; + lccrt_irreader_attr_value_t fattrs[] = + { + { "shift", 0, &shift}, + { "bitshift", 0, &bitshift}, + { "bitsize", 0, &bitsize}, + { 0, 0, 0} + }; + lccrt_irreader_attr_value_t *a_shift = lccrt_irreader_get_attr_value( fattrs, "shift"); + lccrt_irreader_attr_value_t *a_bitshift = lccrt_irreader_get_attr_value( fattrs, "bitshift"); + lccrt_irreader_attr_value_t *a_bitsize = lccrt_irreader_get_attr_value( fattrs, "bitsize"); + + lccrt_irreader_free_attrs( irr, num_attrs, attrs); + num_attrs = 0; + if ( lccrt_irreader_skip_spaces( irr) + && ((i == 0) + || lccrt_irreader_is_lexem( irr, ",", 1)) + && lccrt_irreader_read_type( irr, &ftype) + && lccrt_irreader_read_attrs( irr, 256, attrs, &num_attrs) + && lccrt_irreader_process_attrs( num_attrs, attrs, fattrs) + && a_shift->is_value + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_resize_ptrs( irr, num_flds + 1, &length, (void ***)&flds) ) + { + v = lccrt_irreader_read_char( irr, 0); + bitshift = a_bitshift->is_value ? bitshift : 0; + bitsize = a_bitsize->is_value ? bitsize : 8*lccrt_type_get_bytesize( ftype); + flds[num_flds] = lccrt_type_make_field( ftype, 1, shift, bitshift, bitsize); + num_flds++; + } else + { + v = -1; + lccrt_irreader_error( irr, "fails to read a struct/union field, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } + + if ( lccrt_irreader_is_lexem( irr, "}", 1) ) + { + r = lccrt_type_make_struct( m, align, size, num_flds, flds, is_union); + } + + lccrt_ctx_free( irr->ctx, flds); + } + + lccrt_irreader_free_attrs( irr, num_attrs, attrs); + if ( !r ) + { + lccrt_irreader_error( irr, "fails to read a struct/union type, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return (r); +} /* lccrt_irreader_read_type_struct */ + +/** + * Прочитать тип. + */ +static int +lccrt_irreader_read_type( lccrt_irreader_t *irr, lccrt_type_ptr *type) +{ + int i; + char s[64]; + lccrt_type_ptr tarr[LCCRT_IRR_MAX_ELEMS]; + int v = -1; + lccrt_type_ptr r = 0; + lccrt_type_ptr t0 = 0; + lccrt_module_ptr m = irr->m; + lccrt_ctx_ptr ctx = irr->ctx; + + (*type) = 0; + lccrt_irreader_skip_spaces( irr); + v = lccrt_irreader_read_char( irr, 0); + if ( (v == '*') ) + { + lccrt_irreader_skip( irr, 1, 1); + if ( lccrt_irreader_read_type( irr, &t0) ) + { + r = lccrt_type_make_ptr_type( t0); + } + } else if ( (v == '[') ) + { + int64_t num_elems = 0; + + if ( lccrt_irreader_skip( irr, 1, 1) + && lccrt_irreader_read_int( irr, &num_elems, 0) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, "]", 1) + && lccrt_irreader_read_type( irr, &t0) ) + { + r = lccrt_type_make_array( t0, num_elems); + } + } else if ( (v == '%') ) + { + char *tname = 0; + + lccrt_irreader_skip_chars( irr, 1); + if ( lccrt_irreader_read_ident( irr, &tname) ) + { + lccrt_he_ptr e = lccrt_hash_find( irr->types, (uintptr_t)tname); + + lccrt_ctx_free( ctx, tname); + r = e ? (lccrt_type_ptr)lccrt_hash_get( e) : 0; + } + } else if ( lccrt_irreader_is_lexem( irr, "struct", 1) ) + { + r = lccrt_irreader_read_type_struct( irr, 0); + + } else if ( lccrt_irreader_is_lexem( irr, "union", 1) ) + { + r = lccrt_irreader_read_type_struct( irr, 1); + + } else if ( lccrt_irreader_is_lexem( irr, "typename", 1) ) + { + lccrt_assert( 0); + + } else if ( lccrt_irreader_is_lexem( irr, "func", 1) ) + { + if ( lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, "(", 1) + && lccrt_irreader_skip_spaces( irr) ) + { + lccrt_type_ptr t0 = 0; + + v = lccrt_irreader_read_char( irr, 0); + for ( i = 0; (i < LCCRT_IRR_MAX_ELEMS) && (v > 0) && (v != ')'); ++i ) + { + if ( lccrt_irreader_skip_spaces( irr) + && ((i == 0) + || lccrt_irreader_is_lexem( irr, ",", 1)) + && lccrt_irreader_read_type( irr, tarr + i) ) + { + v = lccrt_irreader_read_char( irr, 0); + } else + { + v = -1; + lccrt_irreader_error( irr, "fails to read a func type, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } + + if ( (i == 1) + && lccrt_type_is_void( tarr[0]) ) + { + i = 0; + } + + if ( (v == ')') ) + { + if ( lccrt_irreader_skip( irr, 1, 1) + && lccrt_irreader_is_lexem( irr, "->", 1) + && lccrt_irreader_read_type( irr, &t0) ) + { + r = lccrt_type_make_func( t0, i, tarr); + } + } + } + } else if ( (v == 'i') + || (v == 'u') + || (v == 'f') ) + { + int64_t bl = 0; + + lccrt_irreader_skip_chars( irr, 1); + if ( lccrt_irreader_read_int( irr, &bl, 0) ) + { + if ( (v == 'i') ) + { + switch ( bl ) + { + case 8: r = lccrt_type_make_int( m, 1, 1); break; + case 16: r = lccrt_type_make_int( m, 2, 1); break; + case 32: r = lccrt_type_make_int( m, 4, 1); break; + case 64: r = lccrt_type_make_int( m, 8, 1); break; + case 128: r = lccrt_type_make_int( m, 16, 1); break; + default: + lccrt_irreader_error( irr, "wrong bitsize [%jd] for type, [%s ...]", + bl, lccrt_irreader_print_head( irr, 64, s)); + break; + } + } else if ( (v == 'u') ) + { + switch ( bl ) + { + case 8: r = lccrt_type_make_int( m, 1, 0); break; + case 16: r = lccrt_type_make_int( m, 2, 0); break; + case 32: r = lccrt_type_make_int( m, 4, 0); break; + case 64: r = lccrt_type_make_int( m, 8, 0); break; + case 128: r = lccrt_type_make_int( m, 16, 0); break; + default: + lccrt_irreader_error( irr, "wrong bitsize [%jd] for type, [%s ...]", + bl, lccrt_irreader_print_head( irr, 64, s)); + break; + } + } else + { + switch ( bl ) + { + case 32: r = lccrt_type_make_float( m, 4); break; + case 64: r = lccrt_type_make_float( m, 8); break; + case 80: r = lccrt_type_make_float( m, 10); break; + case 128: r = lccrt_type_make_float( m, 16); break; + default: + lccrt_irreader_error( irr, "wrong bitsize [%jd] for type, [%s ...]", + bl, lccrt_irreader_print_head( irr, 64, s)); + break; + } + } + } + } else if ( lccrt_irreader_is_lexem( irr, "bool", 1) ) + { + r = lccrt_type_make_bool( m); + + } else if ( lccrt_irreader_is_lexem( irr, "void", 1) ) + { + r = lccrt_type_make_void( m); + + } else if ( lccrt_irreader_is_lexem( irr, "...", 1) ) + { + r = lccrt_type_make_ellipsis( m); + } + + if ( r ) + { + (*type) = r; + } else + { + lccrt_irreader_error( irr, "fails to read a type, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return (r != 0); +} /* lccrt_irreader_read_type */ + +/** + * Чтение значения директивы 'type'. + */ +static void +lccrt_irreader_read_type_definition( lccrt_irreader_t *irr) +{ + char s[64]; + int is_new; + char *tname = 0; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_module_ptr m = irr->m; + + lccrt_irreader_read_lexem( irr); + if ( lccrt_irreader_is_char( irr, 0, '%') + && lccrt_irreader_skip_chars( irr, 1) + && lccrt_irreader_read_ident( irr, &tname) ) + { + lccrt_he_ptr e = lccrt_hash_push( irr->types, (uintptr_t)tname, &is_new); + + lccrt_hash_set( e, 0); + if ( is_new ) + { + if ( lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, "=", 1) ) + { + lccrt_type_ptr type = 0; + + if ( lccrt_irreader_is_lexem( irr, "typename", 1) ) + { + lccrt_irreader_attr_t attrs[256]; + int64_t size = 0; + int64_t align = 0; + int num_attrs = 0; + lccrt_irreader_attr_value_t sattrs[] = + { + { "size", 0, &size}, + { "align", 0, &align}, + { 0, 0, 0} + }; + + if ( lccrt_irreader_read_attrs( irr, 256, attrs, &num_attrs) + && lccrt_irreader_process_attrs( num_attrs, attrs, sattrs) + && (size >= 0) + && (align >= 0) ) + { + type = lccrt_type_make_typename( m, tname, 0); + lccrt_type_set_typename_bytesize( type, size); + lccrt_type_set_typename_bytealign( type, align); + e = lccrt_hash_find( irr->types, (uintptr_t)tname); + lccrt_hash_set( e, (uintptr_t)type); + lccrt_irreader_skip_spaces( irr); + if ( !lccrt_irreader_is_lexem( irr, ";", 1) ) + { + lccrt_irreader_error( irr, "must be ';', [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } else + { + lccrt_irreader_error( irr, "fails to read attributes, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } else if ( lccrt_irreader_read_type( irr, &type) ) + { + e = lccrt_hash_find( irr->types, (uintptr_t)tname); + lccrt_hash_set( e, (uintptr_t)type); + if ( !lccrt_irreader_is_lexem( irr, ";", 1) ) + { + lccrt_irreader_error( irr, "must be ';', [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } + } else + { + lccrt_irreader_error( irr, "must be '=', [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } else + { + lccrt_irreader_error( irr, "type duplicate definition [%s], [%s ...]", + tname, lccrt_irreader_print_head( irr, 64, s)); + } + } else + { + lccrt_irreader_error( irr, "invalid directive 'type' usage, must be 'type " + "%%ident = ;', [%s]", + lccrt_irreader_print_head( irr, 64, s)); + } + + if ( tname ) + { + lccrt_ctx_free( ctx, tname); + } + + return; +} /* lccrt_irreader_read_type_definition */ + +/** + * Прочитать целочисленное значение. + */ +static int +lccrt_irreader_sread_int( const char *s, int i0, int *i, int64_t *value) +{ + int r = 0; + char *q = 0; + const char *p = s + i0; + + (*value) = strtoll( p, &q, 10); + (*i) = i0 + (q - p); + r = (q > p); + + return (r); +} /* lccrt_irreader_sread_int */ + +/** + * Добавить данные о привязке метеданных к функции либо к операции. + */ +static int +lccrt_irreader_einfo_add_links( lccrt_irreader_t *irr, lccrt_irreader_gfi_variant_t gfi, + const char *vstr) +{ + int r = 1; + int is_new = 0; + lccrt_he_ptr he = 0; + + if ( gfi.gvar ) + { + he = lccrt_hash_push( irr->gvars_elinks, (intptr_t)gfi.gvar, &is_new); + + } else if ( gfi.func ) + { + he = lccrt_hash_push( irr->funcs_elinks, (intptr_t)gfi.func, &is_new); + } else + { + he = lccrt_hash_push( irr->opers_elinks, (intptr_t)gfi.oper, &is_new); + } + + lccrt_assert( is_new); + lccrt_hash_set( he, (intptr_t)lccrt_ctx_copy_str( irr->ctx, vstr)); + + return (r); +} /* lccrt_irreader_einfo_add_links */ + +/** + * Чтение значения директивы 'eicat'. + */ +static void +lccrt_irreader_read_einfocat( lccrt_irreader_t *irr) +{ + char s[64]; + int r = 0; + char *cname = 0; + int64_t cident = -1; + lccrt_he_ptr he = 0; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_module_ptr m = irr->m; + lccrt_irreader_lexem_t lex0[] = {{'S'}, {'l',"%c"}, {'U'}, {'l',"="}, {'n'}, {'l',";"}, {0}}; + void *refs[] = {(void *)&cident, (void *)&cname, 0}; + + if ( lccrt_irreader_is_lexems( irr, lex0, refs) ) + { + if ( lccrt_hash_find( irr->ecats, cident) + || (lccrt_module_find_einfo_category( m, cname).id >= 0) ) + { + lccrt_irreader_error( irr, "duplicate definition einfo-category '%%c%jd = %s', [%s]", + cident, lccrt_irreader_print_head( irr, 64, s)); + } else + { + lccrt_eic_t ecat = lccrt_module_new_einfo_category( m, cname); + + r = 1; + he = lccrt_hash_push( irr->ecats, cident, 0); + lccrt_hash_set( he, ecat.id); + } + } + + lccrt_ctx_free( ctx, cname); + + if ( !r ) + { + lccrt_irreader_error( irr, "invalid directive 'eicat' usage, must be 'eicat " + "%%c = ;', [%s]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return; +} /* lccrt_irreader_read_einfocat */ + +/** + * Прочитать номер описания типа метаданных и вернуть признак успешного чтения. + */ +static int +lccrt_irreader_read_eityde( lccrt_irreader_t *irr, lccrt_einfo_tydescr_ptr *etyde) +{ + int r = 0; + lccrt_module_ptr m = irr->m; + + (*etyde) = 0; + if ( lccrt_irreader_is_lexem( irr, "i64", 1) ) + { + r = 1; + (*etyde) = lccrt_einfo_make_tydescr_i64( m); + + } else if ( lccrt_irreader_is_lexem( irr, "raw", 1) ) + { + r = 1; + (*etyde) = lccrt_einfo_make_tydescr_raw( m); + } else + { + lccrt_he_ptr he = 0; + int64_t aident = 0; + lccrt_irreader_lexem_t lex[] = {{'l',"%s"}, {'U'}, {0}}; + void *refs[] = {(void *)&aident, 0}; + + if ( lccrt_irreader_is_lexems( irr, lex, refs) + && (he = lccrt_hash_find( irr->etydes, aident)) ) + { + r = 1; + (*etyde) = (lccrt_einfo_tydescr_ptr)lccrt_hash_get( he); + } + } + + return (r); +} /* lccrt_irreader_read_eityde */ + +/** + * Чтение значения директивы 'eityde'. + */ +static void +lccrt_irreader_read_einfotydescr( lccrt_irreader_t *irr) +{ + char s[64]; + lccrt_vector_t *elems_tydes = &irr->elems_tydes; + int is_new = 0; + int64_t tident = 0; + char *sident = 0; + char *sfname = 0; + lccrt_einfo_tydescr_ptr atyde = 0; + lccrt_einfo_tydescr_ptr rtyde = 0; + lccrt_hash_entry_ptr he = 0; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_module_ptr m = irr->m; + lccrt_irreader_lexem_t lex0[] = {{'S'}, {'l',"%s"}, {'U'}, {'l',"="}, {0}}; + lccrt_irreader_lexem_t lex1[] = {{'S'}, {'n'}, {'l',"{"}, {0}}; + lccrt_irreader_lexem_t lex2[] = {{'n'}, {'l',":"}, {0}}; + lccrt_irreader_lexem_t lex3[] = {{'l',"}"}, {'l',";"}, {0}}; + void *refs0[] = {(void *)&tident, 0}; + void *refs1[] = {(void *)&sident, 0}; + void *refs2[] = {(void *)&sfname, 0}; + void *refs3[] = {0}; + + lccrt_vector_reset( elems_tydes); + + if ( lccrt_irreader_is_lexems( irr, lex0, refs0) ) + { + if ( lccrt_irreader_is_lexem( irr, "array", 0) ) + { + // Читаем тип элемента. + if ( lccrt_irreader_is_delim( irr) + && lccrt_irreader_read_eityde( irr, &atyde) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, ";", 1) ) + { + // Создаем результирующий массив. + rtyde = lccrt_einfo_make_tydescr_array( m, atyde); + } + } else if ( lccrt_irreader_is_lexem( irr, "union", 1) ) + { + if ( lccrt_irreader_is_lexem( irr, "{", 1) ) + { + int i; + int v = '{'; + lccrt_einfo_tydescr_ptr sftyde = 0; + + // Читаем все поля перечисления. + for ( i = 0; (v > 0) && (v != '}'); ++i ) + { + v = -1; + if ( ((i == 0) + || lccrt_irreader_is_lexem( irr, ",", 1)) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_read_eityde( irr, &sftyde) + && lccrt_irreader_skip_spaces( irr) ) + { + int64_t w[LCCRT_IRR_VEC_MAX] = {(int64_t)sftyde}; + + v = lccrt_irreader_read_char( irr, 0); + lccrt_vector_pushback( &irr->elems_tydes, w); + } + } + + // Создаем результирующее перечисление. + if ( lccrt_irreader_is_lexems( irr, lex3, refs3) ) + { + int length = irr->elems_tydes.cur_length; + lccrt_einfo_tydescr_ptr *tydes = 0; + + tydes = (lccrt_eitd_ptr *)lccrt_vector_get_data( &irr->elems_tydes, 0); + rtyde = lccrt_einfo_make_tydescr_union( m, length, tydes); + } + } + } else if ( lccrt_irreader_is_lexem( irr, "struct", 0) ) + { + if ( lccrt_irreader_is_lexems( irr, lex1, refs1) ) + { + int i; + int v = '{'; + lccrt_einfo_tydescr_ptr sftyde = 0; + + // Читаем все поля структуры. + for ( i = 0; (v > 0) && (v != '}'); ++i ) + { + v = -1; + if ( ((i == 0) + || lccrt_irreader_is_lexem( irr, ",", 1)) + && lccrt_irreader_is_lexems( irr, lex2, refs2) + && lccrt_irreader_read_eityde( irr, &sftyde) + && lccrt_irreader_skip_spaces( irr) ) + { + int64_t w[LCCRT_IRR_VEC_MAX] = {(int64_t)sfname, (int64_t)sftyde}; + + v = lccrt_irreader_read_char( irr, 0); + lccrt_vector_pushback( &irr->elems_tydes, w); + } + } + + // Создаем результирующую структуру. + if ( lccrt_irreader_is_lexems( irr, lex3, refs3) ) + { + int length = irr->elems_tydes.cur_length; + const char **names = 0; + lccrt_einfo_tydescr_ptr *tydes = 0; + + names = (const char **)lccrt_vector_get_data( &irr->elems_tydes, 0); + tydes = (lccrt_eitd_ptr *)lccrt_vector_get_data( &irr->elems_tydes, 1); + rtyde = lccrt_einfo_make_tydescr_struct( m, sident, length, names, tydes); + } + } + } + } + + if ( rtyde ) + { + // Сохраняем соответствие номер -> описаниеТипа. + he = lccrt_hash_push( irr->etydes, tident, &is_new); + lccrt_assert( is_new); + lccrt_hash_set( he, (uintptr_t)rtyde); + } + + lccrt_ctx_free( ctx, sident); + if ( !rtyde ) + { + lccrt_irreader_error( irr, + "invalid directive 'eityde' usage, must be\n" + " 'eityde %%s = array %%s;\n" + " 'eityde %%s = struct {:%%s, ...};\n" + "[%s]", lccrt_irreader_print_head( irr, 64, s)); + } + + return; +} /* lccrt_irreader_read_einfotydescr */ + +/** + * Чтение инициализатора метаданных. + */ +static int +lccrt_irreader_read_eiref( lccrt_irreader_t *irr, lccrt_eitd_ptr etyde, int k, lccrt_eir_t *eref) +{ + int r = 0; + lccrt_einfo_tydescr_ptr etydek = 0; + + if ( (etyde->type == LCCRT_EINFO_ARRAY) ) + { + etydek = etyde->types[0]; + + } else if ( (etyde->type == LCCRT_EINFO_STRUCT) ) + { + etydek = etyde->types[k]; + } else + { + lccrt_assert( 0); + } + + if ( (etydek->type == LCCRT_EINFO_UNION) ) + { + if ( lccrt_irreader_is_char( irr, 0, '0') ) + { + int i; + + for ( i = 0; i < etydek->num_flds; ++i ) + { + if ( (etydek->types[i]->type == LCCRT_EINFO_INT64) ) + { + etydek = etydek->types[i]; + break; + } + } + } + } + + if ( lccrt_irreader_is_char( irr, 0, 'n') ) + { + if ( lccrt_irreader_is_lexem( irr, "nil", 1) ) + { + r = 1; + eref->data[0] = 0; + eref->data[1] = 0; + } + } else if ( (etydek->type == LCCRT_EINFO_INT64) ) + { + int64_t eival; + lccrt_irreader_lexem_t lex0[] = {{'x'}, {0}}; + void *refs0[] = {(void *)&eival, 0}; + + if ( lccrt_irreader_is_lexems( irr, lex0, refs0) ) + { + r = 1; + eref->data[0] = etydek->type; + eref->data[1] = eival; + } + } else + { + int64_t eident; + lccrt_irreader_lexem_t lex0[] = {{'l',"%e"}, {'U'}, {0}}; + void *refs0[] = {(void *)&eident, 0}; + + if ( lccrt_irreader_is_lexems( irr, lex0, refs0) ) + { + lccrt_he_ptr he = lccrt_hash_find( irr->einfos, eident); + + r = 1; + eref->data[0] = etydek->type; + eref->data[1] = lccrt_hash_get( he); + } + } + + return (r); +} /* lccrt_irreader_read_eiref */ + +/** + * Чтение значения директивы 'eidef'. + */ +static void +lccrt_irreader_read_einfo( lccrt_irreader_t *irr) +{ + char s[64]; + lccrt_einfo_reference_t einfo; + lccrt_einfo_tydescr_ptr etyde = 0; + int r = 0; + int is_new = 0; + int64_t eident = 0; + lccrt_hash_entry_ptr he = 0; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_module_ptr m = irr->m; + lccrt_irreader_lexem_t lex0[] = {{'S'}, {'l',"%e"}, {'U'}, {'l',"="}, {0}}; + lccrt_irreader_lexem_t lex1[] = {{'l',"}"}, {'l',";"}, {0}}; + void *refs0[] = {(void *)&eident, 0}; + void *refs1[] = {0}; + + if ( lccrt_irreader_is_lexems( irr, lex0, refs0) + && lccrt_irreader_read_eityde( irr, &etyde) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, "{", 1) ) + { + if ( (etyde->type == LCCRT_EINFO_INT64) ) + { + lccrt_irreader_error( irr, "invalid directive 'eidef' usage, tydescr must be " + "'struct', 'array' or 'raw', [%s]", + lccrt_irreader_print_head( irr, 64, s)); + + } else if ( (etyde->type == LCCRT_EINFO_RAW) ) + { + char *vstr; + int vlen; + + if ( lccrt_irreader_read_string( irr, &vstr, &vlen) + && lccrt_irreader_is_lexems( irr, lex1, refs1) ) + { + r = 1; + einfo = lccrt_einfo_new_raw_by_string( m, vstr); + lccrt_ctx_free( ctx, vstr); + } + } else if ( (etyde->type == LCCRT_EINFO_ARRAY) + || (etyde->type == LCCRT_EINFO_STRUCT) ) + { + int i; + lccrt_einfo_reference_t eref; + int v = '{'; + int is_arr = (etyde->type == LCCRT_EINFO_ARRAY); + + einfo = is_arr ? lccrt_einfo_new_array( etyde, 0) : lccrt_einfo_new_struct( etyde); + + // Читаем все поля структуры или массива. + for ( i = 0; (v > 0) && (v != '}'); ++i ) + { + v = -1; + if ( ((i == 0) + || lccrt_irreader_is_lexem( irr, ",", 1)) + && lccrt_irreader_read_eiref( irr, etyde, i, &eref) + && lccrt_irreader_skip_spaces( irr) ) + { + v = lccrt_irreader_read_char( irr, 0); + if ( is_arr ) + { + lccrt_einfo_push_elem( einfo, eref); + } else + { + lccrt_einfo_field_id_t fid = {{(uintptr_t)etyde, i}}; + + lccrt_einfo_set_field( einfo, fid, eref); + } + } + } + + if ( (v == '}') + && lccrt_irreader_is_lexems( irr, lex1, refs1) ) + { + r = 1; + } + } else + { + lccrt_assert( 0); + } + } + + if ( r ) + { + // Сохраняем соответствие номер -> описаниеТипа. + he = lccrt_hash_push( irr->einfos, eident, &is_new); + lccrt_assert( is_new); + lccrt_hash_set( he, (uintptr_t)einfo.data[1]); + } + + if ( !r ) + { + lccrt_irreader_error( irr, + "invalid directive 'eidef' usage, must be\n" + " 'eidef %%e = %%s {%%e, ...};',\n[%s]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return; +} /* lccrt_irreader_read_einfo */ + +/** + * Чтение значения директивы 'eiroot'. + */ +static void +lccrt_irreader_read_eiroot( lccrt_irreader_t *irr) +{ + char s[64]; + lccrt_hash_entry_ptr he1, he2; + char *rname = 0; + int64_t cident = -1; + int64_t eident = -1; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_module_ptr m = irr->m; + lccrt_irreader_lexem_t lex0[] = {{'S'}, {'l',"%c"}, {'U'}, {'S'}, {'l',"%e"}, {'U'}, {'l',";"}}; + void *refs0[] = {(void *)&cident, (void *)&eident, 0}; + + if ( lccrt_irreader_is_lexems( irr, lex0, refs0) + && (he1 = lccrt_hash_find( irr->ecats, cident)) + && (he2 = lccrt_hash_find( irr->einfos, eident)) ) + { + lccrt_einfo_category_t ecat = {lccrt_hash_get( he1)}; + lccrt_einfo_block_ptr eblck = (lccrt_einfo_block_ptr)lccrt_hash_get( he2); + lccrt_einfo_reference_t eref = {{eblck->type, (int64_t)eblck}}; + + lccrt_module_set_einfo( m, ecat, eref); + } + + if ( !he2 ) + { + lccrt_irreader_error( irr, "invalid directive 'eiroot' usage, must be\n" + " 'eiroot %%c %%e;', [%s]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return; +} /* lccrt_irreader_read_einforoot */ + +/** + * Добавить данные о привязке метаданных к функции либо к операции. + */ +static int +lccrt_irreader_apply_elink( lccrt_irreader_t *irr, lccrt_irreader_gfi_variant_t gfi, char *vstr) +{ + int r = 1; + int i = 0; + const char *p = vstr; + + while ( (p[i] != 0) ) + { + int64_t ri = 0; + int64_t vi = 0; + + if ( (i > 0) ) + { + if ( (p[i+0] != ',') ) + { + r = 0; + break; + } else + { + ++i; + } + } + + if ( (p[i+0] == '%') + && (p[i+1] == 'c') + && lccrt_irreader_sread_int( p, i + 2, &i, &ri) + && (p[i+0] == ':') + && (p[i+1] == '%') + && (p[i+2] == 'e') + && lccrt_irreader_sread_int( p, i + 3, &i, &vi) ) + { + lccrt_he_ptr he1 = lccrt_hash_find( irr->ecats, ri); + lccrt_he_ptr he2 = lccrt_hash_find( irr->einfos, vi); + lccrt_einfo_block_ptr eblock = (lccrt_einfo_block_ptr)lccrt_hash_get( he2); + lccrt_einfo_category_t ecat = {lccrt_hash_get( he1)}; + lccrt_eir_t eref = lccrt_einfo_get_block_reference( eblock); + + if ( gfi.gvar ) + { + lccrt_var_set_einfo( gfi.gvar, ecat, eref); + + } else if ( gfi.func ) + { + lccrt_function_set_einfo( gfi.func, ecat, eref); + } else + { + lccrt_oper_set_einfo( gfi.oper, ecat, eref); + } + } else + { + r = 0; + } + } + + if ( !r ) + { + lccrt_irreader_error( irr, "einfo link must be .einfo(\"%%c:%%d,...\") [%s]", vstr); + } + + return (r); +} /* lccrt_irreader_apply_elink */ + +/** + * Завершающее создание метаданных на основе соданных в процессе чтения таблиц. + */ +static void +lccrt_irreader_realize_elinks( lccrt_irreader_t *irr) +{ + int i; + int r = 1; + lccrt_hash_entry_ptr he = 0; + lccrt_hash_ptr vals = 0; + lccrt_module_ptr m = irr->m; + lccrt_ctx_ptr ctx = irr->ctx; + + for ( he = lccrt_hash_first( irr->gvars_elinks); he && r; he = lccrt_hash_next( he) ) + { + lccrt_irreader_gfi_variant_t gfi = {(lccrt_var_ptr)lccrt_hash_get_key( he), 0, 0}; + char *vstr = (char *)lccrt_hash_get( he); + + r = lccrt_irreader_apply_elink( irr, gfi, vstr); + } + + for ( he = lccrt_hash_first( irr->funcs_elinks); he && r; he = lccrt_hash_next( he) ) + { + lccrt_irreader_gfi_variant_t gfi = {0, (lccrt_function_ptr)lccrt_hash_get_key( he), 0}; + char *vstr = (char *)lccrt_hash_get( he); + + r = lccrt_irreader_apply_elink( irr, gfi, vstr); + } + + for ( he = lccrt_hash_first( irr->opers_elinks); he && r; he = lccrt_hash_next( he) ) + { + lccrt_irreader_gfi_variant_t gfi = {0, 0, (lccrt_oper_ptr)lccrt_hash_get_key( he)}; + char *vstr = (char *)lccrt_hash_get( he); + + r = lccrt_irreader_apply_elink( irr, gfi, vstr); + } + + return; +} /* lccrt_irreader_realize_elinks */ + +/** + * Чтение значения директивы 'typelink'. + */ +static void +lccrt_irreader_read_typelink_definition( lccrt_irreader_t *irr) +{ + char s[64]; + char *tname0 = 0; + char *tname1 = 0; + lccrt_ctx_ptr ctx = irr->ctx; + + if ( lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, "%", 0) + && lccrt_irreader_read_ident( irr, &tname0) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, "=", 1) + && lccrt_irreader_is_lexem( irr, "%", 0) + && lccrt_irreader_read_ident( irr, &tname1) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, ";", 1) ) + { + lccrt_he_ptr e0 = lccrt_hash_find( irr->types, (uintptr_t)tname0); + lccrt_type_ptr t0 = e0 ? (lccrt_type_ptr)lccrt_hash_get( e0) : 0; + lccrt_he_ptr e1 = lccrt_hash_find( irr->types, (uintptr_t)tname1); + lccrt_type_ptr t1 = e1 ? (lccrt_type_ptr)lccrt_hash_get( e1) : 0; + + if ( t0 + && t1 + && lccrt_type_is_typename( t0) + && (lccrt_type_is_struct( t1) + || lccrt_type_is_union( t1)) + && (lccrt_type_get_parent( t0) == 0) ) + { + lccrt_type_set_parent( t0, t1); + } else + { + lccrt_irreader_error( irr, "fails to read typelink definition, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } else + { + lccrt_irreader_error( irr, "fails to read typelink definition, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + lccrt_ctx_free( ctx, tname0); + lccrt_ctx_free( ctx, tname1); + + return; +} /* lccrt_irreader_read_typelink_definition */ + +/** + * Чтение значения директивы 'name'. + */ +static void +lccrt_irreader_read_name_definition( lccrt_irreader_t *irr) +{ + int v; + char s[64]; + char *name = 0; + char *vname = 0; + lccrt_ctx_ptr ctx = irr->ctx; + + lccrt_irreader_skip_spaces( irr); + v = lccrt_irreader_read_char( irr, 0); + if ( (v == '@') + && lccrt_irreader_skip_chars( irr, 1) + && lccrt_irreader_read_ident_simple( irr, &name) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, "=", 1) + && lccrt_irreader_read_ident( irr, &vname) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, ";", 1) ) + { + int is_new = 0; + lccrt_he_ptr e = lccrt_hash_push( irr->names, (uintptr_t)name, &is_new); + + if ( is_new ) + { + lccrt_hash_set( e, (uintptr_t)vname); + vname = 0; + } else + { + lccrt_irreader_error( irr, "name duplicate definition [%s], [%s ...]", + name, lccrt_irreader_print_head( irr, 64, s)); + } + } else + { + lccrt_irreader_error( irr, "fails to read name directive [%s], [%s ...]", + name, lccrt_irreader_print_head( irr, 64, s)); + } + + lccrt_ctx_free( ctx, name); + lccrt_ctx_free( ctx, vname); + + return; +} /* lccrt_irreader_read_name_definition */ + +/** + * Чтение значения директивы 'var'. + */ +static int +lccrt_irreader_read_varinit( lccrt_irreader_t *irr, lccrt_varinit_ptr *vinit) +{ + int i; + int v; + char s[64]; + lccrt_hash_entry_ptr e; + int r = 0; + lccrt_type_ptr type = 0; + lccrt_varinit_ptr vi = 0; + lccrt_ctx_ptr ctx = irr->ctx; + + (*vinit) = 0; + if ( lccrt_irreader_read_type( irr, &type) + && lccrt_irreader_skip_spaces( irr) ) + { + v = lccrt_irreader_read_char( irr, 0); + if ( (v == 'z') ) + { + if ( lccrt_irreader_is_lexem( irr, "zeroinit", 1) ) + { + vi = lccrt_varinit_new_zero( type); + } + } else if ( (v == '0') ) + { + if ( lccrt_irreader_is_char( irr, 1, 'x') + && lccrt_irreader_skip_chars( irr, 2) ) + { + int64_t hv; + + if ( lccrt_irreader_read_int( irr, &hv, 1) ) + { + vi = lccrt_varinit_new_scalar( type, hv); + } + } + } else if ( lccrt_irreader_is_lexem( irr, "&", 0) ) + { + char *aname = 0; + int64_t shift = 0; + + if ( lccrt_irreader_read_ident( irr, &aname) + && lccrt_irreader_is_lexem( irr, "+", 0) + && lccrt_irreader_read_int( irr, &shift, 0) ) + { + vi = lccrt_varinit_new_addr_var( irr->addr0, shift); + vi->type = type; + e = lccrt_hash_push( irr->vi_addrs, (uintptr_t)vi, 0); + lccrt_hash_set( e, (uintptr_t)aname); + aname = 0; + } + + lccrt_ctx_free( ctx, aname); + + } else if ( (v == '"') ) + { + char *vstr; + int vlen; + + if ( lccrt_irreader_read_string( irr, &vstr, &vlen) ) + { + vi = lccrt_varinit_new_str( type, vlen, vstr); + } + + lccrt_ctx_free( ctx, vstr); + + } else if ( lccrt_irreader_is_lexem( irr, "{", 1) ) + { + int num_elems = 0; + int length = 0; + lccrt_varinit_ptr *elems = 0; + + for ( i = 0; (v > 0) && (v != '}'); ++i ) + { + lccrt_type_ptr ti = 0; + + if ( ((i == 0) + || lccrt_irreader_is_lexem( irr, ",", 1)) + && lccrt_irreader_resize_ptrs( irr, num_elems + 1, &length, (void ***)&elems) + && lccrt_irreader_read_varinit( irr, elems + num_elems) ) + { + num_elems++; + + lccrt_irreader_skip_spaces( irr); + v = lccrt_irreader_read_char( irr, 0); + } else + { + v = -1; + } + } + + if ( lccrt_irreader_is_lexem( irr, "}", 1) ) + { + vi = lccrt_varinit_new_array( type, num_elems, elems); + } + + lccrt_ctx_free( ctx, elems); + } + } + + if ( vi ) + { + r = 1; + (*vinit) = vi; + } else + { + lccrt_irreader_error( irr, "fails to read varinit, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return (r); +} /* lccrt_irreader_read_varinit */ + +/** + * Преобразование строки в идентификатор переменной. + */ +static int +lccrt_irreader_str_to_varid( const char *str, const char *head, int64_t *value) +{ + int r = 0; + char *q = 0; + + (*value) = 0; + if ( (strncmp( str, head, strlen( head)) == 0) ) + { + int64_t varid = strtol( str + strlen( head), &q, 10); + + if ( (varid >= 0) + && (q > str) + && (q[0] == 0) ) + { + r = 1; + (*value) = varid; + } + } + + return (r); +} /* lccrt_irreader_str_to_varid */ + +/** + * Чтение значения директивы 'var'. + */ +static int +lccrt_irreader_read_var_definition( lccrt_irreader_t *irr) +{ + int i; + char s[64]; + lccrt_irreader_attr_t attrs[256]; + lccrt_hash_entry_ptr e = 0; + int num_attrs = 0; + char *name = 0; + lccrt_type_ptr type = 0; + lccrt_var_ptr g = 0; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_module_ptr m = irr->m; + int r = 0; + + lccrt_irreader_skip_spaces( irr); + if ( lccrt_irreader_read_ident( irr, &name) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, ":", 1) + && lccrt_irreader_read_type( irr, &type) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_read_attrs( irr, 256, attrs, &num_attrs) ) + { + int is_init = 0; + lccrt_varinit_ptr vi = 0; + + if ( lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_char( irr, 0, '=') + && lccrt_irreader_skip_chars( irr, 1) ) + { + is_init = 1; + if ( !lccrt_irreader_read_varinit( irr, &vi) ) + { + if ( vi ) + { + lccrt_varinit_delete( vi); + vi = 0; + } + } + } + + if ( (!is_init + || vi) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, ";", 1) ) + { + lccrt_link_t lnk; + int64_t is_common = 0; + int64_t align = 0; + int64_t is_cnst = 0; + int64_t is_alias = 0; + int64_t is_used = 0; + int64_t is_restrict = 0; + int64_t loc = LCCRT_VAR_LOC_LAST; + int64_t bnd = LCCRT_LINK_BND_LAST; + int64_t vis = LCCRT_LINK_VIS_DEFAULT; + int64_t tls = LCCRT_LINK_TLS_NO; + const char *einfo = 0; + const char *asm_name = 0; + const char *comdat = 0; + const char *section = 0; + lccrt_irreader_attr_value_t gattrs[] = + { + { "common", 0, &is_common}, + { "align", 0, &align}, + { "const", 0, &is_cnst}, + { "alias", 0, &is_alias}, + { "used", 0, &is_used}, + {"restrict", 0, &is_restrict}, + { "loc", 0, &loc}, + { "bind", 0, &bnd}, + { "vis", 0, &vis}, + { "tls", 0, &tls}, + { "einfo", &einfo, 0}, + { "asm", &asm_name, 0}, + { "comdat", &comdat, 0}, + { "section", §ion, 0}, + { 0, 0, 0} + }; + + if ( lccrt_irreader_process_attrs( num_attrs, attrs, gattrs) ) + { + int64_t varid = -1; + + r = 1; + lnk = lccrt_link_get( bnd, vis, tls, is_cnst, is_alias); + g = lccrt_var_new( m, loc, type, name, asm_name, lnk, align); + e = lccrt_hash_push( irr->gvars, (uintptr_t)name, 0); + lccrt_hash_set( e, (uintptr_t)g); + + if ( is_used ) lccrt_var_set_attr_used( g, 1); + if ( is_restrict ) lccrt_var_set_attr_restrict( g, 1); + + if ( is_common ) + { + lccrt_var_set_attr_common( g, 1); + } + + if ( comdat ) + { + lccrt_var_set_comdat( g, comdat); + } + + if ( section ) + { + lccrt_var_set_section( g, section); + } + + if ( vi ) + { + lccrt_var_set_init_value_reduce( g, vi); + vi = 0; + } + + if ( einfo ) + { + lccrt_irreader_gfi_variant_t gfi = {g, 0, 0}; + + if ( !lccrt_irreader_einfo_add_links( irr, gfi, einfo) ) + { + r = 0; + } + } + + if ( lccrt_irreader_str_to_varid( name, "__lccrt_g", &varid) ) + { + m->global_name_id = LCCRT_MAX( m->global_name_id, varid + 1); + + } else if ( lccrt_irreader_str_to_varid( name, "__lccrt_c", &varid) ) + { + m->cargs_name_id = LCCRT_MAX( m->cargs_name_id, varid + 1); + } + } else + { + lccrt_irreader_error( irr, "fails to process var attributes, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } + + if ( vi ) + { + lccrt_varinit_delete( vi); + } + } + + if ( !r ) + { + lccrt_irreader_error( irr, "fails to read var directive, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + lccrt_ctx_free( ctx, name); + lccrt_irreader_free_attrs( irr, num_attrs, attrs); + + return (r); +} /* lccrt_irreader_read_var_definition */ + +/** + * Найти ранее определенную локальную переменную. + */ +lccrt_var_ptr +lccrt_irreader_get_var( lccrt_irreader_t *irr, const char *name) +{ + char s[64]; + lccrt_hash_entry_ptr e; + lccrt_var_ptr r = 0; + lccrt_irreader_func_t *fi = &irr->finfo; + + e = fi->lvars ? lccrt_hash_find( fi->lvars, (uintptr_t)name) : 0; + if ( !e ) + { + e = lccrt_hash_find( irr->gvars, (uintptr_t)name); + } + + r = e ? (lccrt_var_ptr)lccrt_hash_get( e) : 0; + if ( !r ) + { + lccrt_irreader_error( irr, "unknown variable [%s], [%s ...]", + name, lccrt_irreader_print_head( irr, 64, s)); + } + + return (r); +} /* lccrt_irreader_get_var */ + +/** + * Найти ранее определенную локальную переменную. + */ +lccrt_oper_ptr +lccrt_irreader_get_label( lccrt_irreader_t *irr, const char *name) +{ + char s[64]; + lccrt_hash_entry_ptr e; + lccrt_oper_ptr r = 0; + lccrt_irreader_func_t *fi = &irr->finfo; + + e = lccrt_hash_find( fi->labels, (uintptr_t)name); + r = e ? (lccrt_oper_ptr)lccrt_hash_get( e) : 0; + if ( !r ) + { + lccrt_irreader_error( irr, "unknown label [%s] in function [%s], [%s ...]", + name, lccrt_function_get_name( fi->f)); + } + + return (r); +} /* lccrt_irreader_get_label */ + +/** + * Чтение типа функции. + */ +static int +lccrt_irreader_read_func_head_type( lccrt_irreader_t *irr, lccrt_type_ptr *ftype, + int *num_anames, char **anames, char *arest) +{ + int i; + char s[64]; + lccrt_type_ptr atypes[LCCRT_IRR_MAX_ELEMS]; + int num_args = 0; + lccrt_type_ptr rtype = 0; + int r = 0; + + (*ftype) = 0; + (*num_anames) = 0; + + if ( lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, "(", 1) ) + { + int v = lccrt_irreader_read_char( irr, 0); + + for ( i = 0; (v > 0) && (v != ')'); ++i ) + { + anames[i] = 0; + atypes[i] = 0; + if ( (num_args < LCCRT_IRR_MAX_ELEMS) + && ((i == 0) + || (lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, ",", 1))) ) + { + // Пропускаем запятую. + v = lccrt_irreader_read_char( irr, 0); + } else + { + v = -1; + break; + } + + arest[i] = 0; + if ( (v != ':') ) + { + // Читаем название аргумента. + if ( lccrt_irreader_read_ident( irr, anames + i) + && lccrt_irreader_skip_spaces( irr) ) + { + v = lccrt_irreader_read_char( irr, 0); + if ( (v == '.') + && lccrt_irreader_is_lexem( irr, ".restrict", 1) ) + { + arest[i] = 1; + } + } else + { + v = -1; + break; + } + } + + // Читаем тип аргумента. + if ( lccrt_irreader_is_lexem( irr, ":", 1) + && lccrt_irreader_read_type( irr, atypes + i) + && lccrt_irreader_skip_spaces( irr) ) + { + num_args++; + v = lccrt_irreader_read_char( irr, 0); + } else + { + v = -1; + break; + } + } + + for ( i = 0; i < num_args; ++i ) + { + if ( lccrt_type_is_void( atypes[i]) ) + { + v = ((i > 0) || (anames[i] != 0)) ? -1 : v; + + } else if ( lccrt_type_is_ellipsis( atypes[i]) ) + { + v = ((i == num_args - 1) && (anames[i] == 0)) ? v : -1; + } + } + + if ( (num_args == 1) + && lccrt_type_is_void( atypes[0]) ) + { + num_args = 0; + } + + if ( (v == ')') + && lccrt_irreader_skip( irr, 1, 1) + && lccrt_irreader_is_lexem( irr, "->", 1) + && lccrt_irreader_read_type( irr, &rtype) ) + { + r = 1; + (*ftype) = lccrt_type_make_func( rtype, num_args, atypes); + } + } + + (*num_anames) = num_args; + if ( !r ) + { + lccrt_irreader_error( irr, "fails to read function type, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return (r); +} /* lccrt_irreader_read_func_head_type */ + +/** + * Чтение заголовка функции. + */ +static int +lccrt_irreader_read_func_head( lccrt_irreader_t *irr, lccrt_function_ptr *func) +{ + int v; + int i, j; + char s[64]; + lccrt_hash_entry_ptr e; + lccrt_irreader_attr_t attrs[256]; + char *anames[LCCRT_IRR_MAX_ELEMS]; + char arest[LCCRT_IRR_MAX_ELEMS]; + int num_anames = 0; + int num_attrs = 0; + char *fname = 0; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_module_ptr m = irr->m; + lccrt_type_ptr ftype = 0; + lccrt_function_ptr g = 0; + int r = 0; + + (*func) = 0; + if ( lccrt_irreader_read_ident( irr, &fname) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, ":", 1) + && lccrt_irreader_read_func_head_type( irr, &ftype, &num_anames, anames, arest) ) + { + lccrt_link_t lnk; + int64_t is_extern = 0; + int64_t is_extinl = 0; + int64_t bnd = LCCRT_LINK_BND_LAST; + int64_t vis = LCCRT_LINK_VIS_DEFAULT; + int64_t is_nothrow = 0; + int64_t is_used = 0; + int64_t is_builtin = 0; + int64_t ctor = -1; + int64_t dtor = -1; + const char *einfo = 0; + const char *asm_name = 0; + const char *comdat = 0; + const char *section = 0; + lccrt_irreader_attr_value_t fattrs[] = + { + { "extern", 0, &is_extern}, + { "extinline", 0, &is_extinl}, + { "bind", 0, &bnd}, + { "vis", 0, &vis}, + { "nothrow", 0, &is_nothrow}, + { "used", 0, &is_used}, + { "builtin", 0, &is_builtin}, + { "ctor", 0, &ctor}, + { "dtor", 0, &dtor}, + { "einfo", &einfo, 0}, + { "asm", &asm_name, 0}, + { "comdat", &comdat, 0}, + { "section", §ion, 0}, + { 0, 0, 0} + }; + lccrt_irreader_attr_value_t *a_ctor = lccrt_irreader_get_attr_value( fattrs, "ctor"); + lccrt_irreader_attr_value_t *a_dtor = lccrt_irreader_get_attr_value( fattrs, "dtor"); + + if ( lccrt_irreader_read_attrs( irr, 256, attrs, &num_attrs) + && lccrt_irreader_process_attrs( num_attrs, attrs, fattrs) + && (!lccrt_irreader_get_attr_value( fattrs, "ctor")->is_value + || !lccrt_irreader_get_attr_value( fattrs, "dtor")->is_value) + && lccrt_irreader_skip_spaces( irr) + && (is_extern == lccrt_irreader_is_char( irr, 0, ';')) ) + { + r = 1; + lnk = lccrt_link_get( bnd, vis, LCCRT_LINK_TLS_NO, 0, 0); + g = lccrt_function_new( m, ftype, fname, asm_name, lnk, is_extern, 0); + e = lccrt_hash_push( irr->funcs, (uintptr_t)fname, 0); + lccrt_hash_set( e, (uintptr_t)g); + + if ( is_nothrow ) + { + lccrt_function_set_attr_does_not_throw( g, 1); + } + + if ( is_used ) + { + lccrt_function_set_attr_used( g, 1); + } + + if ( is_builtin ) + { + lccrt_assert( 0); + } + + if ( section ) + { + lccrt_function_set_section( g, section); + } + + if ( is_extinl ) + { + lccrt_function_set_attr_extern_inline( g, 1); + } + + if ( comdat ) + { + lccrt_function_set_comdat( g, comdat); + } + + if ( a_ctor->is_value ) + { + lccrt_function_set_init_type( g, LCCRT_FUNC_INIT_CTOR); + lccrt_function_set_init_priority( g, ctor); + } + + if ( a_dtor->is_value ) + { + lccrt_function_set_init_type( g, LCCRT_FUNC_INIT_DTOR); + lccrt_function_set_init_priority( g, dtor); + } + + if ( einfo ) + { + lccrt_irreader_gfi_variant_t gfi = {0, g, 0}; + + if ( !lccrt_irreader_einfo_add_links( irr, gfi, einfo) ) + { + r = 0; + } + } + + for ( j = 0; j < num_anames; ++j ) + { + if ( anames[j] ) + { + char *nj = anames[j]; + lccrt_type_ptr tj = lccrt_type_get_arg( ftype, j); + lccrt_var_ptr arg = lccrt_var_new( g, LCCRT_VAR_LOC_ARG, tj, nj, 0, 0, 0); + + lccrt_var_set_attr_restrict( arg, arest[j]); + lccrt_function_set_arg( g, j, arg); + } else + { + if ( (j < lccrt_function_get_num_args( g)) ) + { + lccrt_function_set_arg( g, j, 0); + } + } + } + } + } + + lccrt_irreader_free_attrs( irr, num_attrs, attrs); + for ( i = 0; i < num_anames; ++i ) + { + lccrt_ctx_free( ctx, anames[i]); + } + + if ( r ) + { + (*func) = g; + } else + { + lccrt_irreader_error( irr, "fails to read function head, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return (r); +} /* lccrt_irreader_read_func_head */ + +/** + * Поиск описания операции. + */ +static lccrt_irreader_oper_descr_t * +lccrt_irreader_oper_descr_find( lccrt_irreader_t *irr, const char *name) +{ + int i; + lccrt_irreader_oper_descr_t *r = 0; + + for ( i = 0; (lccrt_irreader_opers_descr[i].code >= 0); ++i ) + { + if ( (strcmp( name, lccrt_irreader_opers_descr[i].name) == 0) ) + { + r = lccrt_irreader_opers_descr + i; + break; + } + } + + return (r); +} /* lccrt_irreader_oper_descr_find */ + +/** + * Чтение операндов операции. + */ +static int +lccrt_irreader_read_oper_args( lccrt_irreader_t *irr, lccrt_oper_name_t name, + int *num_args, lccrt_irreader_arrptr_t *args) +{ + int i; + int v; + char s[64]; + int n = 0; + int r = 0; + + (*num_args) = 0; + + lccrt_irreader_skip_spaces( irr); + if ( (name == LCCRT_OPER_SEXT) + || (name == LCCRT_OPER_ZEXT) + || (name == LCCRT_OPER_TRUNC) + || (name == LCCRT_OPER_FPTOFP) + || (name == LCCRT_OPER_FPTOUI) + || (name == LCCRT_OPER_FPTOSI) + || (name == LCCRT_OPER_UITOFP) + || (name == LCCRT_OPER_SITOFP) + || (name == LCCRT_OPER_BITCAST) + || (name == LCCRT_OPER_VA_ARG) + || (name == LCCRT_OPER_ALLOCA) ) + { + lccrt_irreader_resize_ptrs( irr, 1, &args->length, &args->v.data); + if ( lccrt_irreader_read_ident( irr, args->v.vstr + 0) ) + { + lccrt_type_ptr rtype; + + n = 1; + if ( lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, "to", 1) + && lccrt_irreader_read_type( irr, &rtype) + && lccrt_irreader_skip_spaces( irr) ) + { + r = 1; + v = lccrt_irreader_read_char( irr, 0); + } + } + + if ( !r ) + { + lccrt_irreader_error( irr, "fails to read operation arguments, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } else + { + v = lccrt_irreader_read_char( irr, 0); + for ( i = 0; (v > 0) && (v != ';'); ++i ) + { + int64_t a0; + + lccrt_irreader_resize_ptrs( irr, n + 1, &args->length, &args->v.data); + args->v.vstr[n] = 0; + if ( ((i == 0) + || lccrt_irreader_is_lexem( irr, ",", 1)) + && (lccrt_irreader_is_lexem( irr, "0", 1) + || lccrt_irreader_read_ident( irr, args->v.vstr + n)) + && lccrt_irreader_skip_spaces( irr) ) + { + ++n; + } else + { + v = -1; + break; + } + + v = lccrt_irreader_read_char( irr, 0); + } + } + + (*num_args) = n; + if ( lccrt_irreader_is_lexem( irr, ";", 1) ) + { + r = 1; + } else + { + lccrt_irreader_error( irr, "fails to read operation arguments, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return (r); +} /* lccrt_irreader_read_oper_args */ + +/** + * Подготовка аргументов операции перед созданием операции. + */ +static void +lccrt_irreader_oper_preprocess_args( lccrt_irreader_t *irr, lccrt_oper_name_t oper_name, + int num_args, lccrt_irreader_arrptr_t *args, char *sargs[]) +{ + int i; + + for ( i = 0; i < num_args; ++i ) + { + lccrt_irreader_resize_ptrs( irr, i, &args->length, &args->v.data); + if ( lccrt_oper_name_is_arg_var( oper_name, i) ) + { + args->v.varg[i].v = sargs[i] ? lccrt_irreader_get_var( irr, sargs[i]) : 0; + } else + { + args->v.varg[i].op = 0; + } + } + + return; +} /* lccrt_irreader_oper_preprocess_args */ + +/** + * Подготовка аргументов операции перед созданием операции. + */ +static void +lccrt_irreader_oper_postprocess_args( lccrt_irreader_t *irr, lccrt_oper_ptr oper, char *sargs[]) +{ + int i; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_irreader_func_t *fi = &irr->finfo; + lccrt_oper_name_t oper_name = lccrt_oper_get_name( oper); + int num_args = lccrt_oper_get_num_args( oper); + + for ( i = 0; i < num_args; ++i ) + { + if ( lccrt_oper_name_is_arg_oper( oper_name, i) ) + { + lccrt_irreader_ctarg_t *cta = lccrt_ctx_malloc( ctx, lccrt_irreader_ctarg_t); + + memset( cta, 0, sizeof( cta[0])); + cta->next = fi->ct_args; + cta->oper = oper; + cta->arg_num = i; + cta->label = sargs[i]; + sargs[i] = 0; + fi->ct_args = cta; + } + } + + return; +} /* lccrt_irreader_oper_postprocess_args */ + +/** + * Чтение очередной операции. + */ +static int +lccrt_irreader_read_func_oper( lccrt_irreader_t *irr, + lccrt_irreader_arrptr_t *sargs, + lccrt_irreader_arrptr_t *vargs) +{ + int i; + int v; + lccrt_hash_entry_ptr e; + lccrt_irreader_attr_t attrs[256]; + int num_attrs = 0; + int num_args = 0; + char *name0 = 0; + char *name1 = 0; + lccrt_var_ptr lvar = 0; + lccrt_oper_ptr oper0 = 0; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_irreader_func_t *fi = &irr->finfo; + lccrt_function_ptr f = fi->f; + int r = 0; + + if ( lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_read_ident( irr, &name0) + && lccrt_irreader_skip_spaces( irr) ) + { + int code = -1; + lccrt_irreader_oper_descr_t *od = 0; + int64_t is_atomic = 0; + int64_t is_volatile = 0; + int64_t is_cleanup = 0; + const char *einfo = 0; + lccrt_irreader_attr_value_t oattrs[] = + { + { "atomic", 0, &is_atomic}, + { "volatile", 0, &is_volatile}, + { "cleanup", 0, &is_cleanup}, + { "einfo", &einfo, 0}, + { 0, 0, 0} + }; + + v = lccrt_irreader_read_char( irr, 0); + if ( lccrt_irreader_is_lexem( irr, ":", 1) ) + { + r = 1; + oper0 = lccrt_oper_new_label( f, name0, 0); + e = lccrt_hash_push( fi->labels, (uintptr_t)name0, 0); + lccrt_hash_set( e, (uintptr_t)oper0); + + } else if ( lccrt_irreader_is_lexem( irr, "=", 1) + && lccrt_irreader_skip_spaces( irr) ) + { + lvar = lccrt_irreader_get_var( irr, name0); + if ( lvar + && lccrt_irreader_read_ident( irr, &name1) + && lccrt_irreader_read_attrs( irr, 256, attrs, &num_attrs) + && lccrt_irreader_process_attrs( num_attrs, attrs, oattrs) ) + { + od = lccrt_irreader_oper_descr_find( irr, name1); + if ( od ) + { + lccrt_type_ptr ltype = lccrt_var_get_type( lvar); + + code = lccrt_oper_name_is_res( od->code) ? od->code : od->code_res; + if ( (code >= 0) + && lccrt_irreader_read_oper_args( irr, code, &num_args, sargs) ) + { + lccrt_irreader_oper_preprocess_args( irr, code, num_args, vargs, sargs->v.vstr); + oper0 = lccrt_oper_new( f, code, ltype, num_args, vargs->v.varg, 0, lvar, 0); + lccrt_irreader_oper_postprocess_args( irr, oper0, sargs->v.vstr); + } + } + } + } else + { + if ( lccrt_irreader_read_attrs( irr, 256, attrs, &num_attrs) + && lccrt_irreader_process_attrs( num_attrs, attrs, oattrs) ) + { + od = lccrt_irreader_oper_descr_find( irr, name0); + if ( od ) + { + code = od->code; + if ( (code >= 0) + && lccrt_irreader_read_oper_args( irr, code, &num_args, sargs) ) + { + if ( (code == LCCRT_OPER_RET) ) + { + code = (num_args == 0) ? code : LCCRT_OPER_RETVAL; + } + + lccrt_irreader_oper_preprocess_args( irr, code, num_args, vargs, sargs->v.vstr); + oper0 = lccrt_oper_new( f, code, 0, num_args, vargs->v.varg, 0, 0, 0); + lccrt_irreader_oper_postprocess_args( irr, oper0, sargs->v.vstr); + } + } + } + } + + if ( oper0 ) + { + r = 1; + if ( is_atomic ) + { + lccrt_oper_set_atomic( oper0, 1); + } + + if ( is_volatile ) + { + lccrt_oper_set_volatile( oper0, 1); + } + + if ( is_cleanup ) + { + lccrt_oper_set_cleanup( oper0, 1); + } + + if ( einfo ) + { + lccrt_irreader_gfi_variant_t gfi = {0, 0, oper0}; + + if ( !lccrt_irreader_einfo_add_links( irr, gfi, einfo) ) + { + r = 0; + } + } + } + } + + lccrt_ctx_free( ctx, name0); + lccrt_ctx_free( ctx, name1); + lccrt_irreader_free_attrs( irr, num_attrs, attrs); + for ( i = 0; i < num_args; ++i ) + { + lccrt_ctx_free( ctx, sargs->v.data[i]); + } + + return (r); +} /* lccrt_irreader_read_func_oper */ + +/** + * Добавить новую локальную переменную. + */ +static void +lccrt_irreader_func_add_local( lccrt_irreader_t *irr, lccrt_var_ptr lvar) +{ + lccrt_hash_entry_ptr e; + int is_new; + lccrt_irreader_func_t *fi = &irr->finfo; + int64_t varid = -1; + const char *lname = lccrt_var_get_name( lvar); + + if ( lccrt_irreader_str_to_varid( lname, "__lccrt_l", &varid) ) + { + fi->f->local_name_id = LCCRT_MAX( fi->f->local_name_id, varid + 1); + } + + e = lccrt_hash_push( fi->lvars, (uintptr_t)lname, &is_new); + lccrt_hash_set( e, (uintptr_t)lvar); + lccrt_assert( is_new); + + return; +} /* lccrt_irreader_func_add_local */ + +/** + * Начало обработки новой функции. + */ +static void +lccrt_irreader_func_init( lccrt_irreader_t *irr, lccrt_function_ptr f) +{ + lccrt_irreader_func_t *fi = &irr->finfo; + lccrt_ctx_ptr ctx = irr->ctx; + + memset( fi, 0, sizeof( fi[0])); + fi->f = f; + fi->labels = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + fi->lvars = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + + return; +} /* lccrt_irreader_func_init */ + +/** + * Завершение обработки функции. + */ +static void +lccrt_irreader_func_done( lccrt_irreader_t *irr) +{ + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_irreader_func_t *fi = &irr->finfo; + + while ( fi->ct_args ) + { + lccrt_irreader_ctarg_t *cta = fi->ct_args; + lccrt_oper_ptr lbl = lccrt_irreader_get_label( irr, cta->label); + + fi->ct_args = cta->next; + lccrt_oper_set_arg_oper( cta->oper, cta->arg_num, lbl); + lccrt_ctx_free( ctx, cta); + } + + lccrt_hash_delete( fi->labels); + lccrt_hash_delete( fi->lvars); + + memset( fi, 0, sizeof( fi[0])); + + return; +} /* lccrt_irreader_func_done */ + +/** + * Чтение локальной переменной. + */ +static int +lccrt_irreader_is_local( lccrt_irreader_t *irr, int is_asm, char **lname, lccrt_type_ptr *ltype) +{ + char s[64]; + int r = 0; + lccrt_ctx_ptr ctx = irr->ctx; + + (*lname) = 0; + if ( (!is_asm + && isspace( lccrt_irreader_read_char( irr, 3)) + && lccrt_irreader_is_lexem( irr, "loc", 1)) + || (is_asm + && isspace( lccrt_irreader_read_char( irr, 6)) + && lccrt_irreader_is_lexem( irr, "locasm", 1)) ) + { + if ( lccrt_irreader_read_ident( irr, lname) + && lccrt_irreader_skip_spaces( irr) + && lccrt_irreader_is_lexem( irr, ":", 1) + && lccrt_irreader_read_type( irr, ltype) + && lccrt_irreader_is_lexem( irr, ";", 1) + && lccrt_irreader_skip_spaces( irr) ) + { + r = 1; + } else + { + lccrt_ctx_free( ctx, (*lname)); + lccrt_irreader_error( irr, "fails to read a local, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + } + + return (r); +} /* lccrt_irreader_is_local */ + +/** + * Чтение значения директивы 'func'. + */ +static void +lccrt_irreader_read_func_definition( lccrt_irreader_t *irr) +{ + int v; + int i; + char s[64]; + lccrt_type_ptr type = 0; + lccrt_function_ptr f = 0; + lccrt_ctx_ptr ctx = irr->ctx; + lccrt_module_ptr m = irr->m; + + if ( lccrt_irreader_read_func_head( irr, &f) + && lccrt_irreader_skip_spaces( irr) ) + { + if ( lccrt_irreader_is_lexem( irr, ";", 1) ) + { + } else if ( lccrt_irreader_is_lexem( irr, "{", 1) ) + { + lccrt_irreader_arrptr_t sargs, vargs; + lccrt_var_ptr lvar = 0; + lccrt_irreader_func_t *fi = &irr->finfo; + int v = lccrt_irreader_read_char( irr, 0); + + lccrt_irreader_func_init( irr, f); + for ( i = 0; i < lccrt_function_get_num_args( f); ++i ) + { + lvar = lccrt_function_get_arg( f, i); + if ( lvar ) + { + lccrt_irreader_func_add_local( irr, lvar); + } + } + + sargs.length = 0; + sargs.v.data = 0; + vargs.length = 0; + vargs.v.data = 0; + + while ( (v > 0) && (v != '}') ) + { + lccrt_type_ptr ltype = 0; + char *lname = 0; + + if ( lccrt_irreader_is_local( irr, 0, &lname, <ype) ) + { + lvar = lccrt_var_new_local( f, ltype, lname); + lccrt_irreader_func_add_local( irr, lvar); + v = lccrt_irreader_read_char( irr, 0); + + } else if ( lccrt_irreader_is_local( irr, 1, &lname, <ype) ) + { + lvar = lccrt_var_new_asm( f, ltype, lname, 0); + lccrt_irreader_func_add_local( irr, lvar); + v = lccrt_irreader_read_char( irr, 0); + + } else if ( lccrt_irreader_read_func_oper( irr, &sargs, &vargs) + && lccrt_irreader_skip_spaces( irr) ) + { + v = lccrt_irreader_read_char( irr, 0); + } else + { + v = -1; + } + + lccrt_ctx_free( ctx, lname); + } + + lccrt_ctx_free( ctx, sargs.v.data); + lccrt_ctx_free( ctx, vargs.v.data); + + lccrt_irreader_func_done( irr); + if ( lccrt_irreader_is_lexem( irr, "}", 1) ) + { + } else + { + f = 0; + } + } + } + + if ( f ) + { + } else + { + lccrt_irreader_error( irr, "fails to read a function, [%s ...]", + lccrt_irreader_print_head( irr, 64, s)); + } + + return; +} /* lccrt_irreader_read_func_definition */ + +/** + * Чтение модуля и параметров компиляции из файлового дескриптора. + */ +lccrt_m_ptr +lccrt_module_load( lccrt_ctx_ptr ctx, int fd, lccrt_asm_compile_config_t *acc) +{ + char s[64]; + lccrt_he_ptr e; + lccrt_type_ptr t0; + lccrt_link_t lnk0; + lccrt_irreader_t irr = {}; + //lccrt_irreader_buffer_t *buffer = lccrt_ctx_malloc( ctx, lccrt_irreader_buffer_t); + lccrt_irreader_buffer_t buffer = {}; + + memset( acc, 0, sizeof( acc[0])); + lccrt_irreader_buffer_init( ctx, &buffer); + + irr.ctx = ctx; + irr.m = lccrt_module_new( ctx, 0, 0); + irr.fd = fd; + irr.b = &buffer; + irr.types = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + irr.names = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + irr.gvars = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + irr.funcs = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + irr.vi_addrs = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + irr.gvars_elinks = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + irr.funcs_elinks = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + irr.opers_elinks = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + irr.ecats = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + irr.etydes = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + irr.einfos = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + t0 = lccrt_type_make_u8( irr.m); + lnk0 = lccrt_link_get( LCCRT_LINK_BND_LOCAL, LCCRT_LINK_VIS_DEFAULT, LCCRT_LINK_TLS_NO, 1, 0); + irr.addr0 = lccrt_var_new( irr.m, LCCRT_VAR_LOC_CONSTARG, t0, "__lccrt_irreader_addr0", 0, lnk0, 0); + lccrt_var_set_init_value_reduce( irr.addr0, lccrt_varinit_new_zero( t0)); + lccrt_vector_init( &irr.elems_tydes, irr.ctx, 2); + + while ( lccrt_irreader_is_open( &irr) ) + { + lccrt_irreader_skip_spaces( &irr); + if ( !lccrt_irreader_is_open( &irr) ) + { + } else if ( lccrt_irreader_read_lexem( &irr) ) + { + if ( lccrt_irreader_is_lexem( &irr, "config", 1) ) + { + lccrt_irreader_read_config( &irr, acc); + + } else if ( lccrt_irreader_is_lexem( &irr, "asm", 1) ) + { + char *astr = 0; + + if ( lccrt_irreader_is_lexem( &irr, "(", 1) + && lccrt_irreader_read_string( &irr, &astr, 0) + && lccrt_irreader_is_lexem( &irr, ")", 1) + && lccrt_irreader_is_lexem( &irr, ";", 1) ) + { + lccrt_module_set_inline_asm( irr.m, astr); + } else + { + lccrt_irreader_error( &irr, "fails to read asm directive [%s ...]", + lccrt_irreader_print_head( &irr, 64, s)); + } + + lccrt_ctx_free( ctx, astr); + + } else if ( lccrt_irreader_is_lexem( &irr, "typelink", 1) ) + { + lccrt_irreader_read_typelink_definition( &irr); + + } else if ( lccrt_irreader_is_lexem( &irr, "type", 1) ) + { + lccrt_irreader_read_type_definition( &irr); + + } else if ( lccrt_irreader_is_lexem( &irr, "name", 1) ) + { + lccrt_irreader_read_name_definition( &irr); + + } else if ( lccrt_irreader_is_lexem( &irr, "var", 1) ) + { + lccrt_irreader_read_var_definition( &irr); + + } else if ( lccrt_irreader_is_lexem( &irr, "func", 1) ) + { + lccrt_irreader_read_func_definition( &irr); + + } else if ( lccrt_irreader_is_lexem( &irr, "eicat", 0) ) + { + lccrt_irreader_read_einfocat( &irr); + + } else if ( lccrt_irreader_is_lexem( &irr, "eityde", 0) ) + { + lccrt_irreader_read_einfotydescr( &irr); + + } else if ( lccrt_irreader_is_lexem( &irr, "eidef", 0) ) + { + lccrt_irreader_read_einfo( &irr); + + } else if ( lccrt_irreader_is_lexem( &irr, "eiroot", 0) ) + { + lccrt_irreader_read_eiroot( &irr); + } else + { + lccrt_irreader_error( &irr, "invalid directive [%s ...], must be " + "'config', 'type', 'name', 'var' or 'func'", + lccrt_irreader_print_head( &irr, 64, s)); + } + } else + { + lccrt_irreader_error( &irr, "invalid lexem [%s ...], must be " + "'config', 'type', 'name', 'var' or 'func'", + lccrt_irreader_print_head( &irr, 64, s)); + } + } + + if ( (strlen( irr.error) == 0) ) + { + for ( e = lccrt_hash_first( irr.vi_addrs); e; e = lccrt_hash_next( e) ) + { + lccrt_varinit_ptr vi = (lccrt_varinit_ptr)lccrt_hash_get_key( e); + char *aname = (char *)lccrt_hash_get( e); + lccrt_hash_entry_ptr ve = lccrt_hash_find( irr.gvars, (uintptr_t)aname); + lccrt_hash_entry_ptr fe = ve ? 0 : lccrt_hash_find( irr.funcs, (uintptr_t)aname); + lccrt_var_ptr va = ve ? (lccrt_var_ptr)lccrt_hash_get( ve) : 0; + lccrt_function_ptr fa = fe ? (lccrt_function_ptr)lccrt_hash_get( fe) : 0; + + lccrt_assert( vi->data.var == irr.addr0); + if ( ve ) + { + vi->init_type = LCCRT_VARINIT_ADDR_VAR; + vi->data.var = va; + + } else if ( fe ) + { + vi->init_type = LCCRT_VARINIT_ADDR_FUNC; + vi->data.func = fa; + } else + { + lccrt_irreader_error( &irr, "unknown variable/function [%s], [%s ...]", + aname, lccrt_irreader_print_head( &irr, 64, s)); + } + + lccrt_ctx_free( ctx, aname); + } + + lccrt_irreader_realize_elinks( &irr); + } + + lccrt_hash_delete( irr.types); + lccrt_hash_delete( irr.names); + lccrt_hash_delete( irr.gvars); + lccrt_hash_delete( irr.funcs); + lccrt_hash_delete( irr.vi_addrs); + lccrt_hash_delete( irr.gvars_elinks); + lccrt_hash_delete( irr.funcs_elinks); + lccrt_hash_delete( irr.opers_elinks); + lccrt_hash_delete( irr.ecats); + lccrt_hash_delete( irr.etydes); + lccrt_hash_delete( irr.einfos); + lccrt_ctx_free( ctx, buffer.data); + lccrt_vector_done( &irr.elems_tydes); + + if ( (strlen( irr.error) > 0) ) + { + fprintf( stderr, "%s\n", irr.error); + exit( 1); + } + + return (irr.m); +} /* lccrt_module_load */ diff --git a/lib/irv/lccrt_irwriter.c b/lib/irv/lccrt_irwriter.c new file mode 100644 index 0000000..015d0b2 --- /dev/null +++ b/lib/irv/lccrt_irwriter.c @@ -0,0 +1,1483 @@ +/** + * 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_irwriter.c - реализация печати представления модуля. + */ + +#include +#include +#include +#include +#include + +#include "lccrt_real.h" + +/** + * Данные для печати представления модуля. + */ +typedef struct +{ + lccrt_context_ptr ctx; + lccrt_module_ptr m; + int fd; + uintptr_t tident; // идентификатор типов + uintptr_t nident; // идентификатор сокращенных имен + lccrt_hash_ptr ptypes; // хеш-таблица с напечатанными типами (тип,номер) + lccrt_hash_ptr snames; // хеш-таблица с сокращенными именами для глобалов и функций + lccrt_hash_ptr typelinks; // хеш-таблица с именованными типами, для которых выполнено связывание + lccrt_hash_ptr einfos; // хеш-таблица с идентификаторами метаданных + lccrt_hash_ptr eitydes; // хеш-таблица с идентификаторами типов метаданных +} lccrt_irwriter_t; + +/** + * Форматный вывод. + */ +static int +lccrt_printf( lccrt_irwriter_t *irw, const char *fmt, ...) +{ + int n1, n2; + va_list args; + int r = -1; + char *b = 0; + lccrt_ctx_ptr ctx = irw->ctx; + int fd = irw->fd; + + va_start( args, fmt); + n1 = vsnprintf( 0, 0, fmt, args); + va_end( args); + + b = lccrt_ctx_mallocn( ctx, char, n1 + 4); + + va_start( args, fmt); + n2 = vsnprintf( b, n1 + 2, fmt, args); + va_end( args); + + if ( (n1 > 0) + && (b != 0) + && (n2 == n1) ) + { + int k = 0; + + while ( (k >= 0) + && (k < n2) ) + { + int l = write( fd, b + k, n2 - k); + + k = (l > 0) ? (k + l) : -1; + } + + if ( (k == n2) ) + { + r = n2; + } + } + + lccrt_ctx_free( ctx, b); + lccrt_assert( r >= 0); + + return (r); +} /* lccrt_printf */ + +/** + * Получение стандартной строки для значения. + */ +static const char * +lccrt_get_loc_str( lccrt_var_loc_t loc) +{ + const char *r = "UNKNOWN"; + + switch ( loc ) + { + case LCCRT_VAR_LOC_GLOB: r = "glob"; break; + case LCCRT_VAR_LOC_EXT: r = "ext"; break; + case LCCRT_VAR_LOC_CONSTARG: r = "carg"; break; + case LCCRT_VAR_LOC_LOCAL: r = "local"; break; + case LCCRT_VAR_LOC_ARG: r = "arg"; break; + case LCCRT_VAR_LOC_SYSARG: r = "sarg"; break; + case LCCRT_VAR_LOC_ASM: r = "arg"; break; + default: lccrt_assert( 0); break; + } + + return (r); +} /* lccrt_get_loc_str */ + +/** + * Получение стандартной строки для значения. + */ +static const char * +lccrt_get_bnd_str( lccrt_link_bind_t bnd) +{ + const char *r = "UNKNOWN"; + + switch ( bnd ) + { + case LCCRT_LINK_BND_NO: r = "no"; break; + case LCCRT_LINK_BND_WEAK: r = "weak"; break; + case LCCRT_LINK_BND_GLOBAL: r = "glob"; break; + case LCCRT_LINK_BND_LOCAL: r = "loc"; break; + default: lccrt_assert( 0); break; + } + + return (r); +} /* lccrt_get_bnd_str */ + +/** + * Получение стандартной строки для значения. + */ +static const char * +lccrt_get_vis_str( lccrt_link_visibility_t vis) +{ + const char *r = "UNKNOWN"; + + switch ( vis ) + { + case LCCRT_LINK_VIS_DEFAULT: r = "def"; break; + case LCCRT_LINK_VIS_INTERNAL: r = "int"; break; + case LCCRT_LINK_VIS_HIDDEN: r = "hid"; break; + case LCCRT_LINK_VIS_PROTECTED: r = "pro"; break; + default: lccrt_assert( 0); break; + } + + return (r); +} /* lccrt_get_vis_str */ + +/** + * Получение стандартной строки для значения. + */ +static const char * +lccrt_get_tls_str( lccrt_link_tls_t tls) +{ + const char *r = "UNKNOWN"; + + switch ( tls ) + { + case LCCRT_LINK_TLS_NO: r = "no"; break; + case LCCRT_LINK_TLS_DYNAMIC_G: r = "dyn_g"; break; + case LCCRT_LINK_TLS_DYNAMIC_L: r = "dyn_l"; break; + case LCCRT_LINK_TLS_EXEC_I: r = "exec_i"; break; + case LCCRT_LINK_TLS_EXEC_L: r = "exec_l"; break; + default: lccrt_assert( 0); break; + } + + return (r); +} /* lccrt_get_tls_str */ + +/** + * Удаление таблицы вместе с данными. + */ +static lccrt_hash_ptr +lccrt_delete_hash_with_data( lccrt_ctx_ptr ctx, lccrt_hash_ptr tbl) +{ + lccrt_he_ptr e; + + for ( e = lccrt_hash_first( tbl); e; e = lccrt_hash_next( e) ) + { + lccrt_ctx_free( ctx, (char *)lccrt_hash_get( e)); + } + + lccrt_hash_delete( tbl); + + return (0); +} /* lccrt_delete_hash_with_data */ + +/** + * Печать массива симолов с помещением в двойные кавычки, а также экранирования всех + * не печатных символов. + */ +static int64_t +lccrt_print_escaped_bytearray( lccrt_irwriter_t *irw, int64_t len, const char *s) +{ + int64_t i; + int64_t r = 0; + + r += lccrt_printf( irw, "\""); + for ( i = 0; i < len; ++i ) + { + if ( isprint( s[i]) + && (s[i] != '"') + && (s[i] != '\\') ) + { + r += lccrt_printf( irw, "%c", s[i]); + } else + { + r += lccrt_printf( irw, "\\%02x", (uint8_t)s[i]); + } + } + r += lccrt_printf( irw, "\""); + + return (r); +} /* lccrt_print_escaped_bytearray */ + +/** + * Печать строки с помещением в двойные кавычки, а также экранирования всех + * не печатных символов. + */ +static int64_t +lccrt_print_escaped_string( lccrt_irwriter_t *irw, const char *s) +{ + int64_t r = lccrt_print_escaped_bytearray( irw, strlen( s), s); + + return (r); +} /* lccrt_print_escaped_string */ + +/** + * Напечатать определение, инициализируемое строкой с экранированием. + */ +static void +lccrt_print_define_string( lccrt_irwriter_t *irw, const char *var, const char *str) +{ + str = str ? str : ""; + lccrt_printf( irw, var); + lccrt_print_escaped_string( irw, str); + lccrt_printf( irw, ";\n"); + + return; +} /* lccrt_print_define_string */ + +/** + * Напечатать определение, инициализируемое строкой с экранированием. + */ +static void +lccrt_print_attr_string( lccrt_irwriter_t *irw, const char *attr, const char *str) +{ + lccrt_printf( irw, " %s(", attr); + lccrt_print_escaped_string( irw, str); + lccrt_printf( irw, ")"); + + return; +} /* lccrt_print_attr_string */ + +/** + * Проверяем, что строка является стандартным идентификатором. + */ +static int +lccrt_is_str_ident( const char *s) +{ + int i; + int r = 0; + + if ( (s[0] == '_') + || isalpha( s[0]) ) + { + r = 1; + for ( i = 1; s[i]; ++i ) + { + if ( !((s[i] == '_') + || isalnum( s[i])) ) + { + r = 0; + break; + } + } + } + + return (r); +} /* lccrt_is_str_ident */ + +/** + * Печать идентификатора с экранированием кавычками по необходимости. + */ +static int +lccrt_print_ident( lccrt_irwriter_t *irw, const char *s) +{ + int r = 0; + + if ( lccrt_is_str_ident( s) + && (strcmp( s, "loc") != 0) ) + { + r = lccrt_printf( irw, "%s", s); + } else + { + r = lccrt_print_escaped_string( irw, s); + } + + return (r); +} /* lccrt_print_ident */ + +/** + * Для ранее определенного типа получить его строковый идентификатор. + */ +static char * +lccrt_irwriter_get_type_ident( lccrt_irwriter_t *irw, lccrt_type_ptr t) +{ + lccrt_he_ptr e = lccrt_hash_find( irw->ptypes, (uintptr_t)t); + char *r = (char *)lccrt_hash_get( e); + + return (r); +} /* lccrt_irwriter_get_type_ident */ + +/** + * Для ранее определенного имени получить его сокращенное название. + */ +static char * +lccrt_irwriter_get_name_ident( lccrt_irwriter_t *irw, void *obj) +{ + lccrt_he_ptr e = lccrt_hash_find( irw->snames, (uintptr_t)obj); + char *r = (char *)lccrt_hash_get( e); + + return (r); +} /* lccrt_irwriter_get_name_ident */ + +/** + * Печать определения типа. + */ +static void +lccrt_irwriter_define_type( lccrt_irwriter_t *irw, lccrt_type_ptr t_src, lccrt_type_ptr t, + int is_pointer, char **tnameout) +{ + int fd = irw->fd; + int is_new = 0; + lccrt_he_ptr e = lccrt_hash_push( irw->ptypes, (uintptr_t)t, &is_new); + + if ( is_new ) + { + char tname[256]; + int tlen = -1; + int is_simple = 1; + char *tname0 = "UNKNOWN"; + uint64_t tnum_args = lccrt_type_get_num_args( t); + lccrt_type_ptr t0 = lccrt_type_get_parent( t); + + if ( lccrt_type_is_void( t) ) + { + tlen = snprintf( tname, 256, "void"); + + } else if ( lccrt_type_is_bool( t) ) + { + tlen = snprintf( tname, 256, "bool"); + + } else if ( lccrt_type_is_ellipsis( t) ) + { + tlen = snprintf( tname, 256, "..."); + + } else if ( lccrt_type_is_int( t) ) + { + if ( lccrt_type_get_sign( t) ) + { + tlen = snprintf( tname, 256, "i%d", (int)8*lccrt_type_get_bytesize( t)); + } else + { + tlen = snprintf( tname, 256, "u%d", (int)8*lccrt_type_get_bytesize( t)); + } + } else if ( lccrt_type_is_float( t) ) + { + tlen = snprintf( tname, 256, "f%d", (int)8*lccrt_type_get_bytesize( t)); + } else + { + is_simple = 0; + tlen = snprintf( tname, 256, "%%t%d", irw->tident); + irw->tident++; + } + + lccrt_assert( tlen <= 256); + lccrt_hash_set( e, (uintptr_t)lccrt_ctx_copy_str( irw->ctx, tname)); + + if ( is_simple ) + { + } else if ( lccrt_type_is_typename( t) ) + { + char sa[256]; + lccrt_type_ptr tp = lccrt_type_make_ptr_type( t); + + sa[0] = 0; + if ( t0 ) + { + snprintf( sa, 256, " .size(%jd) .align(%jd)", lccrt_type_get_bytesize( t0), + lccrt_type_get_bytealign( t0)); + } + + lccrt_printf( irw, "type %s = typename%s;\n", tname, sa); + lccrt_irwriter_define_type( irw, t, tp, 0, &tname0); + lccrt_printf( irw, "type %s = *%s;\n", tname0, tname); +#if 0 + if ( t0 + && !is_pointer ) + { + lccrt_irwriter_define_type( irw, t, t0, 0, &tname0); + lccrt_printf( irw, "typelink %s = %s;\n", tname, tname0); + lccrt_hash_push( irw->typelinks, (uintptr_t)t, 0); + } +#endif + } else if ( lccrt_type_is_pointer( t) ) + { + lccrt_irwriter_define_type( irw, t, t0, 1, &tname0); + if ( !lccrt_type_is_typename( t0) ) + { + lccrt_printf( irw, "type %s = *%s;\n", tname, tname0); + } + } else if ( lccrt_type_is_array( t) ) + { + lccrt_irwriter_define_type( irw, t, t0, 0, &tname0); + lccrt_printf( irw, "type %s = [%jd]%s;\n", tname, tnum_args, tname0); + + } else if ( lccrt_type_is_struct( t) + || lccrt_type_is_union( t) ) + { + int i; + const char *s = lccrt_type_is_union( t) ? "union" : "struct"; + + for ( i = 0; i < tnum_args; ++i ) + { + lccrt_type_ptr ti = lccrt_type_get_arg( t, i); + + ti = lccrt_type_get_parent( ti); + lccrt_irwriter_define_type( irw, t, ti, 0, 0); + } + + lccrt_printf( irw, "type %s = %s", tname, s); + lccrt_printf( irw, " .size(%jd)", lccrt_type_get_bytesize( t)); + lccrt_printf( irw, " .align(%jd)", lccrt_type_get_bytealign( t)); + lccrt_printf( irw, " {"); + for ( i = 0; i < tnum_args; ++i ) + { + lccrt_type_ptr ti = lccrt_type_get_arg( t, i); + lccrt_type_ptr ti_p = lccrt_type_get_parent( ti); + uint64_t shift = lccrt_type_get_byteshift( ti); + uint64_t bitsize = lccrt_type_get_bitsubsize( ti); + uint64_t bitshift = lccrt_type_get_bitsubshift( ti); + + if ( (i > 0) ) lccrt_printf( irw, ", "); + lccrt_printf( irw, "%s", lccrt_irwriter_get_type_ident( irw, ti_p)); + lccrt_printf( irw, " .shift(%jd)", shift); + if ( (bitshift > 0) ) + { + lccrt_printf( irw, " .bitshift(%jd)", bitshift); + lccrt_printf( irw, " .bitsize(%jd)", bitsize); + } + } + lccrt_printf( irw, "};\n"); + + } else if ( lccrt_type_is_function( t) ) + { + int i; + + lccrt_irwriter_define_type( irw, t, lccrt_type_get_parent( t), 0, &tname0); + for ( i = 0; i < tnum_args; ++i ) + { + lccrt_irwriter_define_type( irw, t, lccrt_type_get_arg( t, i), 0, 0); + } + + lccrt_printf( irw, "type %s = func (", tname); + for ( i = 0; i < tnum_args; ++i ) + { + lccrt_type_ptr ti = lccrt_type_get_arg( t, i); + + if ( (i > 0) ) lccrt_printf( irw, ", "); + lccrt_printf( irw, "%s", lccrt_irwriter_get_type_ident( irw, ti)); + } + + if ( lccrt_type_is_function_var_arg( t) ) + { + if ( (tnum_args == 0) ) + { + lccrt_printf( irw, "..."); + } else + { + if ( !lccrt_type_is_ellipsis( lccrt_type_get_arg( t, tnum_args - 1)) ) + { + lccrt_printf( irw, ", ..."); + } + } + } + lccrt_printf( irw, ") -> %s;\n", tname0); + } else + { + lccrt_type_print( t, 1); + lccrt_assert( 0); + } + + e = lccrt_hash_find( irw->ptypes, (uintptr_t)t); + } else + { + lccrt_type_ptr t0 = lccrt_type_get_parent( t); + + if ( lccrt_type_is_typename( t) + && !(t_src + && (lccrt_type_is_function( t_src))) ) + { + char *tname = (char *)lccrt_hash_get( e); + + if ( 0 && t0 + && !is_pointer + && !lccrt_hash_find( irw->typelinks, (uintptr_t)t) ) + { + char *tname0 = 0; + + lccrt_irwriter_define_type( irw, t, t0, 0, &tname0); + lccrt_printf( irw, "typelink %s = %s;\n", tname, tname0); + lccrt_hash_push( irw->typelinks, (uintptr_t)t, 0); + } + + e = lccrt_hash_find( irw->ptypes, (uintptr_t)t); + } + } + + if ( tnameout ) + { + (*tnameout) = (char *)lccrt_hash_get( e); + } + + return; +} /* lccrt_irwriter_define_type */ + +/** + * Печать для модуля представления всех типов. + */ +static void +lccrt_irwriter_print_types( lccrt_irwriter_t *irw) +{ + lccrt_type_ptr t; + int fd = irw->fd; + lccrt_module_ptr m = irw->m; + + // Печатаем определение типов. + for ( t = lccrt_module_get_first_type( m); t; t = lccrt_type_get_next_type( t) ) + { + if ( lccrt_type_is_field( t) ) + { + } else + { + lccrt_irwriter_define_type( irw, 0, t, 0, 0); + } + } + + // Печатаем связки типов-имен с их базовыми типами. + for ( t = lccrt_module_get_first_type( m); t; t = lccrt_type_get_next_type( t) ) + { + if ( lccrt_type_is_typename( t) ) + { + lccrt_type_ptr t0 = lccrt_type_get_parent( t); + + if ( t0 ) + { + lccrt_printf( irw, "typelink %s = %s;\n", + lccrt_irwriter_get_type_ident( irw, t), + lccrt_irwriter_get_type_ident( irw, t0)); + } + } + } + + lccrt_printf( irw, "\n"); + + return; +} /* lccrt_irwriter_print_types */ + +/** + * Печать сокращенных имен глобальных переменных и функций из представления модуля. + */ +static void +lccrt_irwriter_print_names( lccrt_irwriter_t *irw) +{ + lccrt_var_ptr v; + lccrt_function_ptr g; + char nname[256]; + lccrt_he_ptr e; + int fd = irw->fd; + lccrt_module_ptr m = irw->m; + + for ( v = lccrt_module_get_first_var( m); v; v = lccrt_var_get_next_var( v) ) + { + snprintf( nname, 256, "@n%d", irw->nident); + irw->nident++; + e = lccrt_hash_push( irw->snames, (uintptr_t)v, 0); + lccrt_hash_set( e, (uintptr_t)lccrt_ctx_copy_str( irw->ctx, nname)); + + lccrt_printf( irw, "name %s = ", nname); + lccrt_print_ident( irw, lccrt_var_get_name( v)); + lccrt_printf( irw, ";\n"); + } + + for ( g = lccrt_module_get_first_func( m); g; g = lccrt_function_get_next_func( g) ) + { + snprintf( nname, 256, "@n%d", irw->nident); + irw->nident++; + e = lccrt_hash_push( irw->snames, (uintptr_t)g, 0); + lccrt_hash_set( e, (uintptr_t)lccrt_ctx_copy_str( irw->ctx, nname)); + + lccrt_printf( irw, "name %s = ", nname); + lccrt_print_ident( irw, lccrt_function_get_name( g)); + lccrt_printf( irw, ";\n"); + } + + lccrt_printf( irw, "\n"); + + return; +} /* lccrt_irwriter_print_names */ + +/** + * Печать списка ссылок на метаданные как атрибуты. + */ +static void +lccrt_irwriter_print_attr_einfo_list( lccrt_irwriter_t *irw, lccrt_einfo_link_ptr elink0) +{ + lccrt_einfo_link_ptr elink; + lccrt_einfo_link_ptr prev = 0; + + if ( elink0 ) + { + // Проходимся по списку метаданных в обратном порядке. + for ( elink = elink0; elink->next; elink = elink->next ) ; + + lccrt_printf( irw, " .einfo(\""); + + for ( ; elink ; elink = elink->prev ) + { + lccrt_einfo_category_t eic = elink->ident; + lccrt_einfo_handle_t eih = elink->value; + lccrt_he_ptr he = lccrt_hash_find( irw->einfos, (uintptr_t)eih.data.ref); + + if ( prev ) lccrt_printf( irw, ","); + lccrt_printf( irw, "%%c%jd:%%e%jd", eic.id, lccrt_hash_get( he)); + prev = elink; + } + + lccrt_printf( irw, "\")"); + } + + return; +} /* lccrt_irwriter_print_attr_einfo_list */ + +/** + * Печать инициализатора переменной. + */ +static void +lccrt_irwriter_print_varinit( lccrt_irwriter_t *irw, lccrt_varinit_ptr vi) +{ + int64_t i; + int fd = irw->fd; + lccrt_var_ptr va = 0; + lccrt_function_ptr fa = 0; + lccrt_type_ptr t = lccrt_varinit_get_type( vi); + int64_t num_elems = lccrt_varinit_get_num_elems( vi); + + lccrt_printf( irw, "%s ", lccrt_irwriter_get_type_ident( irw, t)); + switch ( lccrt_varinit_get_inittype( vi) ) + { + case LCCRT_VARINIT_ZERO: + lccrt_printf( irw, "zeroinit"); + break; + case LCCRT_VARINIT_HEX: + lccrt_printf( irw, "0x%jx", lccrt_varinit_get_hex64( vi)); + break; + case LCCRT_VARINIT_STR: + lccrt_print_escaped_bytearray( irw, num_elems, lccrt_varinit_get_str( vi)); + break; + case LCCRT_VARINIT_ADDR_VAR: + va = lccrt_varinit_get_addr_var( vi); + lccrt_printf( irw, "&%s+%jd", lccrt_irwriter_get_name_ident( irw, va), + lccrt_varinit_get_num_elems( vi)); + break; + case LCCRT_VARINIT_ADDR_FUNC: + fa = lccrt_varinit_get_addr_func( vi); + lccrt_printf( irw, "&%s+%jd", lccrt_irwriter_get_name_ident( irw, fa), + lccrt_varinit_get_num_elems( vi)); + break; + case LCCRT_VARINIT_ARR: + lccrt_printf( irw, "{"); + for ( i = 0; i < num_elems; ++i ) + { + if ( (i > 0) ) lccrt_printf( irw, ","); + lccrt_irwriter_print_varinit( irw, lccrt_varinit_get_elem( vi, i)); + } + lccrt_printf( irw, "}"); + break; + default: + lccrt_assert( 0); + break; + } + + return; +} /* lccrt_irwriter_print_varinit */ + +/** + * Печать глобальных переменных из представления модуля. + */ +static void +lccrt_irwriter_print_gvars( lccrt_irwriter_t *irw) +{ + lccrt_var_ptr v; + lccrt_he_ptr e; + int fd = irw->fd; + lccrt_module_ptr m = irw->m; + + for ( v = lccrt_module_get_first_var( m); v; v = lccrt_var_get_next_var( v) ) + { + lccrt_type_ptr t = lccrt_var_get_type( v); + const char *asm_name = lccrt_var_get_asm_name( v); + const char *comdat = lccrt_var_get_comdat( v); + const char *section = lccrt_var_get_section( v); + lccrt_link_t link = lccrt_var_get_link( v); + int64_t align = lccrt_var_get_align( v); + lccrt_link_visibility_t vis = lccrt_link_get_vis( link); + lccrt_link_tls_t tls = lccrt_link_get_tls( link); + lccrt_varinit_ptr vi = lccrt_var_get_init_value( v); + + lccrt_printf( irw, "var "); + lccrt_print_ident( irw, lccrt_var_get_name( v)); + lccrt_printf( irw, " : %s", lccrt_irwriter_get_type_ident( irw, t)); + if ( asm_name + && (strcmp( asm_name, lccrt_var_get_name( v)) != 0) ) + { + lccrt_print_attr_string( irw, ".asm", asm_name); + } + + if ( (align > 1) ) lccrt_printf( irw, " .align(%jd)", align); + if ( lccrt_link_is_alias( link) ) lccrt_printf( irw, " .alias"); + if ( lccrt_link_is_const( link) ) lccrt_printf( irw, " .const"); + if ( lccrt_var_get_attr_common( v) ) lccrt_printf( irw, " .common"); + if ( lccrt_var_get_attr_used( v) ) lccrt_printf( irw, " .used"); + lccrt_printf( irw, " .loc(%s)", lccrt_get_loc_str( lccrt_var_get_loc( v))); + lccrt_printf( irw, " .bind(%s)", lccrt_get_bnd_str( lccrt_link_get_bnd( link))); + if ( (vis != LCCRT_LINK_VIS_DEFAULT) ) lccrt_printf( irw, " .vis(%s)", lccrt_get_vis_str( vis)); + if ( (tls != LCCRT_LINK_TLS_NO) ) lccrt_printf( irw, " .tls(%s)", lccrt_get_tls_str( tls)); + if ( section ) lccrt_print_attr_string( irw, ".section", section); + if ( comdat ) lccrt_print_attr_string( irw, ".comdat", comdat); + lccrt_irwriter_print_attr_einfo_list( irw, v->einfo); + + if ( vi ) + { + lccrt_printf( irw, " = "); + lccrt_irwriter_print_varinit( irw, vi); + } + + lccrt_printf( irw, ";\n"); + } + + lccrt_printf( irw, "\n"); + + return; +} /* lccrt_irwriter_print_gvars */ + +/** + * Для операций с результатом печать начальной части записи результата. + */ +static void +lccrt_irwriter_print_oper_define( lccrt_irwriter_t *irw, lccrt_oper_ptr inst) +{ + int fd = irw->fd; + lccrt_oper_name_t inst_name = lccrt_oper_get_name( inst); + + if ( lccrt_oper_name_is_res( inst_name) ) + { + lccrt_var_ptr res = lccrt_oper_get_res( inst); + + lccrt_print_ident( irw, lccrt_var_get_name( res)); + lccrt_printf( irw, " = "); + } + + return; +} /* lccrt_irwriter_print_oper_define */ + +/** + * Простой способ печати операции. + */ +static void +lccrt_irwriter_print_oper_simple( lccrt_irwriter_t *irw, lccrt_oper_ptr inst, const char *name) +{ + int i; + int fd = irw->fd; + int num_args = lccrt_oper_get_num_args( inst); + lccrt_oper_name_t inst_name = lccrt_oper_get_name( inst); + + lccrt_printf( irw, " "); + lccrt_irwriter_print_oper_define( irw, inst); + lccrt_printf( irw, "%s", name); + if ( lccrt_oper_is_atomic( inst) ) lccrt_printf( irw, " .atomic"); + if ( lccrt_oper_is_volatile( inst) ) lccrt_printf( irw, " .volatile"); + if ( lccrt_oper_is_cleanup( inst) ) lccrt_printf( irw, " .cleanup"); + for ( i = 0; i < num_args; ++i ) + { + lccrt_printf( irw, (i == 0) ? " " : ", "); + if ( lccrt_oper_name_is_arg_var( inst_name, i) ) + { + lccrt_var_ptr arg_var = lccrt_oper_get_arg_var( inst, i); + + if ( arg_var ) + { + lccrt_print_ident( irw, lccrt_var_get_name( arg_var)); + } else + { + lccrt_printf( irw, "0"); + } + } else + { + lccrt_oper_ptr arg_oper = lccrt_oper_get_arg_oper( inst, i); + + lccrt_print_ident( irw, lccrt_oper_get_label( arg_oper)); + } + } + + return; +} /* lccrt_irwriter_print_oper_simple */ + +/** + * Простой способ печати операции. + */ +static void +lccrt_irwriter_print_oper_conv( lccrt_irwriter_t *irw, lccrt_oper_ptr inst, const char *name) +{ + int fd = irw->fd; + int num_args = lccrt_oper_get_num_args( inst); + lccrt_oper_name_t inst_name = lccrt_oper_get_name( inst); + lccrt_type_ptr tr = lccrt_oper_get_res_type( inst); + + lccrt_printf( irw, " "); + lccrt_irwriter_print_oper_define( irw, inst); + lccrt_printf( irw, "%s ", name); + lccrt_print_ident( irw, lccrt_var_get_name( lccrt_oper_get_arg_var( inst, 0))); + lccrt_printf( irw, " to %s", lccrt_irwriter_get_type_ident( irw, tr)); + + return; +} /* lccrt_irwriter_print_oper_conv */ + +/** + * Печать представления операции. + */ +static void +lccrt_irwriter_print_oper( lccrt_irwriter_t *irw, lccrt_oper_ptr inst) +{ + int fd = irw->fd; + int is_label = 0; + + switch ( lccrt_oper_get_name( inst) ) + { + case LCCRT_OPER_LABEL: + is_label = 1; + lccrt_print_ident( irw, lccrt_oper_get_label( inst)); + break; + case LCCRT_OPER_BRANCH: + lccrt_irwriter_print_oper_simple( irw, inst, "branch"); + break; + case LCCRT_OPER_BRANCHIF: + lccrt_irwriter_print_oper_simple( irw, inst, "branchif"); + break; + case LCCRT_OPER_SWITCH: + lccrt_irwriter_print_oper_simple( irw, inst, "switch"); + break; + case LCCRT_OPER_VARPTR: + lccrt_irwriter_print_oper_simple( irw, inst, "varptr"); + break; + case LCCRT_OPER_MOVE: + lccrt_irwriter_print_oper_simple( irw, inst, "move"); + break; + case LCCRT_OPER_LOAD: + lccrt_irwriter_print_oper_simple( irw, inst, "load"); + break; + case LCCRT_OPER_STORE: + lccrt_irwriter_print_oper_simple( irw, inst, "store"); + break; + case LCCRT_OPER_ADD: + lccrt_irwriter_print_oper_simple( irw, inst, "add"); + break; + case LCCRT_OPER_SUB: + lccrt_irwriter_print_oper_simple( irw, inst, "sub"); + break; + case LCCRT_OPER_MUL: + lccrt_irwriter_print_oper_simple( irw, inst, "mul"); + break; + case LCCRT_OPER_UDIV: + lccrt_irwriter_print_oper_simple( irw, inst, "udiv"); + break; + case LCCRT_OPER_SDIV: + lccrt_irwriter_print_oper_simple( irw, inst, "sdiv"); + break; + case LCCRT_OPER_UMOD: + lccrt_irwriter_print_oper_simple( irw, inst, "umod"); + break; + case LCCRT_OPER_SMOD: + lccrt_irwriter_print_oper_simple( irw, inst, "smod"); + break; + case LCCRT_OPER_SHL: + lccrt_irwriter_print_oper_simple( irw, inst, "shl"); + break; + case LCCRT_OPER_SHR: + lccrt_irwriter_print_oper_simple( irw, inst, "shr"); + break; + case LCCRT_OPER_SAR: + lccrt_irwriter_print_oper_simple( irw, inst, "sar"); + break; + case LCCRT_OPER_AND: + lccrt_irwriter_print_oper_simple( irw, inst, "and"); + break; + case LCCRT_OPER_OR: + lccrt_irwriter_print_oper_simple( irw, inst, "or"); + break; + case LCCRT_OPER_XOR: + lccrt_irwriter_print_oper_simple( irw, inst, "xor"); + break; + case LCCRT_OPER_FNEG: + lccrt_irwriter_print_oper_simple( irw, inst, "fneg"); + break; + case LCCRT_OPER_FADD: + lccrt_irwriter_print_oper_simple( irw, inst, "fadd"); + break; + case LCCRT_OPER_FSUB: + lccrt_irwriter_print_oper_simple( irw, inst, "fsub"); + break; + case LCCRT_OPER_FMUL: + lccrt_irwriter_print_oper_simple( irw, inst, "fmul"); + break; + case LCCRT_OPER_FDIV: + lccrt_irwriter_print_oper_simple( irw, inst, "fdiv"); + break; + case LCCRT_OPER_CALLPROC: + case LCCRT_OPER_CALLFUNC: + lccrt_irwriter_print_oper_simple( irw, inst, "call"); + break; + case LCCRT_OPER_INVOKEPROC: + case LCCRT_OPER_INVOKEFUNC: + lccrt_irwriter_print_oper_simple( irw, inst, "invoke"); + break; + case LCCRT_OPER_LANDINGPAD: + lccrt_irwriter_print_oper_simple( irw, inst, "landingpad"); + break; + case LCCRT_OPER_RET: + case LCCRT_OPER_RETVAL: + lccrt_irwriter_print_oper_simple( irw, inst, "ret"); + break; + case LCCRT_OPER_ELEMPTR: + lccrt_irwriter_print_oper_simple( irw, inst, "elemptr"); + break; + case LCCRT_OPER_ELEMREAD: + lccrt_irwriter_print_oper_simple( irw, inst, "elemread"); + break; + case LCCRT_OPER_ELEMWRITE: + lccrt_irwriter_print_oper_simple( irw, inst, "elemwrite"); + break; + case LCCRT_OPER_SELECT: + lccrt_irwriter_print_oper_simple( irw, inst, "select"); + break; + case LCCRT_OPER_SHUFFLE: + lccrt_irwriter_print_oper_simple( irw, inst, "shuffle"); + break; + case LCCRT_OPER_CMP: + lccrt_irwriter_print_oper_simple( irw, inst, "cmp"); + break; + case LCCRT_OPER_BITCAST: + lccrt_irwriter_print_oper_conv( irw, inst, "bitcast"); + break; + case LCCRT_OPER_SEXT: + lccrt_irwriter_print_oper_conv( irw, inst, "sext"); + break; + case LCCRT_OPER_ZEXT: + lccrt_irwriter_print_oper_conv( irw, inst, "zext"); + break; + case LCCRT_OPER_TRUNC: + lccrt_irwriter_print_oper_conv( irw, inst, "trunc"); + break; + case LCCRT_OPER_FPTOFP: + lccrt_irwriter_print_oper_conv( irw, inst, "fptofp"); + break; + case LCCRT_OPER_FPTOUI: + lccrt_irwriter_print_oper_conv( irw, inst, "fptoui"); + break; + case LCCRT_OPER_FPTOSI: + lccrt_irwriter_print_oper_conv( irw, inst, "fptosi"); + break; + case LCCRT_OPER_UITOFP: + lccrt_irwriter_print_oper_conv( irw, inst, "uitofp"); + break; + case LCCRT_OPER_SITOFP: + lccrt_irwriter_print_oper_conv( irw, inst, "sitofp"); + break; + case LCCRT_OPER_ALLOCA: + lccrt_irwriter_print_oper_conv( irw, inst, "alloca"); + break; + case LCCRT_OPER_VA_ARG: + lccrt_irwriter_print_oper_conv( irw, inst, "vaarg"); + break; + default: + //lccrt_oper_print( inst, 1); + lccrt_assert( 0); + break; + } + + lccrt_irwriter_print_attr_einfo_list( irw, inst->einfo); + if ( is_label ) + { + lccrt_printf( irw, ":\n"); + } else + { + lccrt_printf( irw, ";\n"); + } + + return; +} /* lccrt_irwriter_print_oper */ + +/** + * Печать атрибутов функции. + */ +static void +lccrt_irwriter_print_func_attrs( lccrt_irwriter_t *irw, lccrt_function_ptr g) +{ + int fd = irw->fd; + const char *asm_name = lccrt_function_get_asm_name( g); + const char *comdat = lccrt_function_get_comdat( g); + const char *section = lccrt_function_get_section( g); + lccrt_link_t link = lccrt_function_get_link( g); + lccrt_link_visibility_t vis = lccrt_link_get_vis( link); + + if ( asm_name + && (strcmp( asm_name, lccrt_function_get_name( g)) != 0) ) + { + lccrt_print_attr_string( irw, ".asm", asm_name); + } + + if ( lccrt_function_is_declaration( g) ) lccrt_printf( irw, " .extern"); + lccrt_printf( irw, " .bind(%s)", lccrt_get_bnd_str( lccrt_link_get_bnd( link))); + if ( (vis != LCCRT_LINK_VIS_DEFAULT) ) lccrt_printf( irw, " .vis(%s)", lccrt_get_vis_str( vis)); + if ( lccrt_function_get_attr_used( g) ) lccrt_printf( irw, " .used"); + if ( lccrt_function_get_attr_does_not_throw( g) ) lccrt_printf( irw, " .nothrow"); + if ( lccrt_function_get_attr_extern_inline( g) ) lccrt_printf( irw, " .extinline"); + if ( lccrt_function_is_builtin( g) ) lccrt_printf( irw, " .builtin"); + if ( section ) lccrt_print_attr_string( irw, ".section", section); + if ( comdat ) lccrt_print_attr_string( irw, ".comdat", comdat); + if ( (lccrt_function_get_init_type( g) == LCCRT_FUNC_INIT_CTOR) ) + { + lccrt_printf( irw, " .ctor(%d)", lccrt_function_get_init_priority( g)); + + } else if ( (lccrt_function_get_init_type( g) == LCCRT_FUNC_INIT_DTOR) ) + { + lccrt_printf( irw, " .dtor(%d)", lccrt_function_get_init_priority( g)); + } + + lccrt_irwriter_print_attr_einfo_list( irw, g->einfo); + + return; +} /* lccrt_irwriter_print_func_attrs */ + +/** + * Печать глобальных переменных из представления модуля. + */ +static void +lccrt_irwriter_print_funcs( lccrt_irwriter_t *irw) +{ + lccrt_function_ptr g; + lccrt_he_ptr e; + int fd = irw->fd; + lccrt_module_ptr m = irw->m; + + for ( g = lccrt_module_get_first_func( m); g; g = lccrt_function_get_next_func( g) ) + { + int i; + int num_args = lccrt_function_get_num_args( g); + lccrt_type_ptr t = lccrt_function_get_type( g); + lccrt_type_ptr t0 = lccrt_type_get_parent( t); + + lccrt_printf( irw, "func "); + lccrt_print_ident( irw, lccrt_function_get_name( g)); + lccrt_printf( irw, " : ("); + for ( i = 0; i < num_args; ++i ) + { + lccrt_var_ptr v = lccrt_function_get_arg( g, i); + lccrt_type_ptr ti = lccrt_type_get_arg( t, i); + + if ( (i > 0) ) lccrt_printf( irw, ", "); + if ( v ) + { + lccrt_print_ident( irw, lccrt_var_get_name( v)); + lccrt_printf( irw, " "); + if ( lccrt_var_get_attr_restrict( v) ) lccrt_printf( irw, " .restrict"); + } + lccrt_printf( irw, ": "); + lccrt_printf( irw, "%s", lccrt_irwriter_get_type_ident( irw, ti)); + } + if ( lccrt_function_is_var_arg( g) ) + { + if ( (num_args > 0) ) lccrt_printf( irw, ", "); + lccrt_printf( irw, ": ..."); + } + + lccrt_printf( irw, ") -> "); + lccrt_printf( irw, "%s", lccrt_irwriter_get_type_ident( irw, t0)); + lccrt_irwriter_print_func_attrs( irw, g); + + if ( lccrt_function_is_declaration( g) ) + { + lccrt_printf( irw, ";\n"); + } else + { + lccrt_var_ptr v; + lccrt_oper_ptr inst; + + lccrt_printf( irw, "\n{\n"); + + for ( v = lccrt_function_get_first_var( g); + v; + v = lccrt_var_get_next_var( v) ) + { + lccrt_var_loc_t loc = lccrt_var_get_loc( v); + const char *vname = lccrt_var_get_name( v); + lccrt_type_ptr vtype = lccrt_var_get_type( v); + char *vtid = lccrt_irwriter_get_type_ident( irw, vtype); + + if ( (loc == LCCRT_VAR_LOC_LOCAL) ) + { + lccrt_printf( irw, " loc "); + lccrt_print_ident( irw, vname); + lccrt_printf( irw, " : %s;\n", vtid); + + } else if ( (loc == LCCRT_VAR_LOC_ASM) ) + { + lccrt_printf( irw, " locasm "); + lccrt_print_ident( irw, vname); + lccrt_printf( irw, " : %s;\n", vtid); + } + } + + for ( inst = lccrt_function_get_first_oper( g); + inst; + inst = lccrt_oper_get_next( inst) ) + { + lccrt_irwriter_print_oper( irw, inst); + } + + lccrt_printf( irw, "}\n"); + } + + lccrt_printf( irw, "\n"); + } + + return; +} /* lccrt_irwriter_print_funcs */ + +/** + * Печатаем дескриптор описания типа метаданных. + */ +static void +lccrt_irwriter_print_einfo_tydescr_ident( lccrt_irwriter_t *irw, lccrt_einfo_tydescr_ptr etyde) +{ + if ( lccrt_einfo_is_tydescr_i64( etyde) ) + { + lccrt_printf( irw, "i64"); + + } else if ( lccrt_einfo_is_tydescr_raw( etyde) ) + { + lccrt_printf( irw, "raw"); + } else + { + lccrt_he_ptr he = lccrt_hash_find( irw->eitydes, (uintptr_t)etyde); + + lccrt_printf( irw, "%%s%jd", lccrt_hash_get( he)); + } + + return; +} /* lccrt_irwriter_print_einfo_tydescr_ident */ + +/** + * Печатаем описание типа метаданных. + */ +static void +lccrt_irwriter_print_einfo_tydescr( lccrt_irwriter_t *irw, int ident, lccrt_einfo_tydescr_ptr etyde) +{ + int i; + + if ( (etyde->type == LCCRT_EINFO_ARRAY) ) + { + lccrt_printf( irw, "eityde %%s%d = array ", ident); + lccrt_assert( etyde->num_flds = 1); + lccrt_irwriter_print_einfo_tydescr_ident( irw, etyde->types[0]); + lccrt_printf( irw, ";\n"); + + } else if ( (etyde->type == LCCRT_EINFO_UNION) ) + { + lccrt_printf( irw, "eityde %%s%d = union {", ident); + for ( i = 0; i < etyde->num_flds; ++i ) + { + if ( (i > 0) ) lccrt_printf( irw, ","); + lccrt_irwriter_print_einfo_tydescr_ident( irw, etyde->types[i]); + } + lccrt_printf( irw, "};\n"); + + } else if ( (etyde->type == LCCRT_EINFO_STRUCT) ) + { + lccrt_printf( irw, "eityde %%s%d = struct ", ident); + lccrt_print_ident( irw, etyde->self_name); + lccrt_printf( irw, " {"); + for ( i = 0; i < etyde->num_flds; ++i ) + { + if ( (i > 0) ) lccrt_printf( irw, ","); + lccrt_print_ident( irw, etyde->flds[i]); + lccrt_printf( irw, ":"); + lccrt_irwriter_print_einfo_tydescr_ident( irw, etyde->types[i]); + } + lccrt_printf( irw, "};\n"); + } else + { + lccrt_assert( 0); + } + + return; +} /* lccrt_irwriter_print_einfo_tydescr */ + +/** + * Печать идетификатора блока метаданных. + */ +static void +lccrt_irwriter_print_einfo_block_ident( lccrt_irwriter_t *irw, lccrt_einfo_handle_t ehdl) +{ + if ( (ehdl.type == LCCRT_EINFO_NULL) ) + { + lccrt_printf( irw, "nil"); + + } else if ( (ehdl.type == LCCRT_EINFO_INT64) ) + { + lccrt_printf( irw, "0x%jx", ehdl.data.i64); + } else + { + lccrt_einfo_block_ptr eblock = ehdl.data.ref; + lccrt_he_ptr he = lccrt_hash_find( irw->einfos, (intptr_t)eblock); + + lccrt_printf( irw, "%%e%d", (int)lccrt_hash_get( he)); + } + + return; +} /* lccrt_irwriter_print_einfo_block_ident */ + +/** + * Печатаем значение блока метаданных. + */ +static void +lccrt_irwriter_print_einfo_block( lccrt_irwriter_t *irw, int ident, lccrt_einfo_block_ptr eblck) +{ + int i; + + lccrt_printf( irw, "eidef %%e%d = ", ident); + lccrt_irwriter_print_einfo_tydescr_ident( irw, eblck->tydescr); + lccrt_printf( irw, " {"); + if ( (eblck->type == LCCRT_EINFO_ARRAY) + || (eblck->type == LCCRT_EINFO_STRUCT) ) + { + for ( i = 0; i < eblck->num_args; ++i ) + { + if ( (i > 0) ) lccrt_printf( irw, ","); + lccrt_irwriter_print_einfo_block_ident( irw, eblck->data.elems[i]); + } + } else if ( (eblck->type == LCCRT_EINFO_RAW) ) + { + int is_str = 1; + int len = eblck->num_args; + const uint8_t *rdata = eblck->data.rdata; + + if ( (rdata[len - 1] == 0) ) + { + int escape_cnt = 0; + + for ( i = 0; i < len; ++i ) + { + int c = rdata[i]; + if ( !isprint( c) + || (c == '\\') + || (c == '"') ) + { + escape_cnt++; + } + } + + if ( (len - 1 + 2*escape_cnt <= 2*len) ) + { + is_str = 1; + } + } + + if ( is_str ) + { + lccrt_print_escaped_string( irw, rdata); + } else + { + lccrt_assert( 0); + } + } else + { + lccrt_assert( 0); + } + + lccrt_printf( irw, "};\n"); + + return; +} /* lccrt_irwriter_print_einfo_block */ + +/** + * Печатаем метаданные модуля. + */ +static void +lccrt_irwriter_print_einfo( lccrt_irwriter_t *irw) +{ + int64_t i; + lccrt_hash_entry_ptr he; + lccrt_einfo_link_ptr elink; + lccrt_module_ptr m = irw->m; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + + // Печатаем категории мета-данных. + if ( lccrt_hash_first( m->einfo_cats) ) + { + for ( he = lccrt_hash_first( m->einfo_cats); he; he = lccrt_hash_next( he) ) + { + intptr_t ecat = lccrt_hash_get( he); + const char *ecat_name = (char *)lccrt_hash_get_key( he); + + lccrt_printf( irw, "eicat %%c%jd = %s;\n", ecat, ecat_name); + } + + lccrt_printf( irw, "\n"); + } + + // Печатаем определения описания типов мета-данных. + if ( lccrt_hash_length( irw->eitydes ) ) + { + int tlen = lccrt_hash_length( irw->eitydes); + lccrt_einfo_tydescr_ptr *types = lccrt_ctx_mallocn( ctx, lccrt_einfo_tydescr_ptr, tlen); + + for ( he = lccrt_hash_first( irw->eitydes); he; he = lccrt_hash_next( he) ) + { + types[lccrt_hash_get( he)] = (lccrt_einfo_tydescr_ptr)lccrt_hash_get_key( he); + } + + for ( i = 0; i < tlen; ++i ) + { + if ( !lccrt_einfo_is_tydescr_i64( types[i]) + && !lccrt_einfo_is_tydescr_raw( types[i]) ) + { + lccrt_irwriter_print_einfo_tydescr( irw, i, types[i]); + } + } + + lccrt_printf( irw, "\n"); + lccrt_ctx_free( ctx, types); + } + + // Печатаем значения блоков мета-данных. + if ( lccrt_hash_length( irw->einfos) ) + { + int blen = lccrt_hash_length( irw->einfos); + lccrt_einfo_block_ptr *blocks = lccrt_ctx_mallocn( ctx, lccrt_einfo_block_ptr, blen); + + for ( he = lccrt_hash_first( irw->einfos); he; he = lccrt_hash_next( he) ) + { + blocks[lccrt_hash_get( he)] = (lccrt_einfo_block_ptr)lccrt_hash_get_key( he); + } + + for ( i = 0; i < blen; ++i ) + { + lccrt_irwriter_print_einfo_block( irw, i, blocks[i]); + } + + lccrt_printf( irw, "\n"); + lccrt_ctx_free( ctx, blocks); + } + + for ( elink = irw->m->einfo; elink; elink = elink->next ) + { + lccrt_printf( irw, "eiroot %%c%jd ", elink->ident); + //lccrt_irwriter_print_einfo_tydescr_ident( irw, elink->value.data.ref->tydescr); + //lccrt_printf( irw, " "); + lccrt_irwriter_print_einfo_block_ident( irw, elink->value); + lccrt_printf( irw, ";\n"); + } + + if ( irw->m->einfo ) lccrt_printf( irw, "\n"); + + return; +} /* lccrt_irwriter_print_einfo */ + +/** + * Печать для представления модуля конфигурации компиляции. + */ +static void +lccrt_irwriter_print_config( lccrt_irwriter_t *irw, lccrt_asm_compile_config_t *acc) +{ + int fd = irw->fd; + + lccrt_print_define_string( irw, "config target = ", acc->target); + lccrt_print_define_string( irw, "config out_type = ", acc->out_type); + lccrt_printf( irw, "config opt_level = %d;\n", acc->opt_level); + lccrt_printf( irw, "config is_pic = %d;\n", acc->is_pic); + lccrt_printf( irw, "config pie_level = %d;\n", acc->pie_level); + lccrt_printf( irw, "config dbg_level = %d;\n", acc->dbg_level); + lccrt_printf( irw, "config function_sections = %d;\n", acc->function_sections); + lccrt_printf( irw, "config data_sections = %d;\n", acc->data_sections); + lccrt_printf( irw, "config asm_verbose = %d;\n", acc->asm_verbose); + lccrt_printf( irw, "config llvmir_embed_static_only = %d;\n", acc->is_llvmir_embed_static_only); + lccrt_print_define_string( irw, "config eh_personality = ", acc->eh_personality); + lccrt_print_define_string( irw, "config cpu_arch = ", acc->cpu_arch); + lccrt_print_define_string( irw, "config cflags = ", acc->cflags); + + lccrt_printf( irw, "\n"); + + return; +} /* lccrt_irwriter_print_config */ + +/** + * Печать представления модуля в выходной поток данных. + */ +int +lccrt_module_print( lccrt_asm_compile_config_t *acc, lccrt_module_ptr m, int fd) +{ + lccrt_he_ptr e; + int r = 0; + lccrt_irwriter_t irw = {}; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + const char *sasm = lccrt_module_get_inline_asm( m); + + // Готовим данные. + irw.ctx = ctx; + irw.m = m; + irw.fd = fd; + irw.ptypes = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + irw.snames = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + irw.typelinks = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + irw.einfos = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + irw.eitydes = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + lccrt_module_einfo_number( m, irw.einfos, irw.eitydes); + + lccrt_irwriter_print_config( &irw, acc); + + // Печатаем глобальную ассемблерную вставку. + if ( sasm ) + { + lccrt_printf( &irw, "asm("); + lccrt_print_escaped_string( &irw, sasm); + lccrt_printf( &irw, ");\n\n"); + } + + // Печатаем определение типов. + lccrt_irwriter_print_types( &irw); + + // Печатаем сокращенные именования, чтобы не использовать потенциально длинные + // названия функций и переменных из-за C++-манглирования. + lccrt_irwriter_print_names( &irw); + + // Печатаем глобальные переменные. + lccrt_irwriter_print_gvars( &irw); + + // Печатаем функции. + lccrt_irwriter_print_funcs( &irw); + + // Печатаем метаданные модуля. + lccrt_irwriter_print_einfo( &irw); + + lccrt_printf( &irw, "\n"); + + // Удаляем таблицы вместе с данныим. + irw.ptypes = lccrt_delete_hash_with_data( ctx, irw.ptypes); + irw.snames = lccrt_delete_hash_with_data( ctx, irw.snames); + lccrt_hash_delete( irw.typelinks); + lccrt_hash_delete( irw.einfos); + lccrt_hash_delete( irw.eitydes); + + return (r); +} /* lccrt_module_print */ + +/** + * Печать представления модуля в стандартный поток данных. + */ +int +lccrt_module_print_stdout( lccrt_asm_compile_config_t *acc, lccrt_module_ptr m) +{ + int r = lccrt_module_print( acc, m, fileno( stdout)); + + return (r); +} /* lccrt_module_print_stdout */ diff --git a/lib/irv/lccrt_link.c b/lib/irv/lccrt_link.c new file mode 100644 index 0000000..b71982f --- /dev/null +++ b/lib/irv/lccrt_link.c @@ -0,0 +1,128 @@ +/** + * 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_link.c - реализация пользовательский интерфейс (динамической) компиляции. + */ + +#include +#include +#include +#include +#include + +#include "lccrt_real.h" + +/** + * Получить значение. + */ +lccrt_link_t +lccrt_link_get( lccrt_link_bind_t bnd, lccrt_link_visibility_t vis, lccrt_link_tls_t tls, + int is_cnst, int is_alias) +{ + lccrt_link_t r = 0; + + LCCRT_LINK_BYTE_BND( &r) = bnd; + LCCRT_LINK_BYTE_VIS( &r) = vis; + LCCRT_LINK_BYTE_TLS( &r) = tls; + LCCRT_LINK_BYTE_CST( &r) = is_cnst; + LCCRT_LINK_BYTE_ALS( &r) = is_alias; + + return (r); +} /* lccrt_link_get */ + +/** + * Получить значение. + */ +lccrt_link_t +lccrt_link_conv( lccrt_asmlink_t link) +{ + lccrt_link_t r = 0; + + r = lccrt_link_get( link.bnd, link.vis, link.tls, link.is_cnst, link.is_alias); + + return (r); +} /* lccrt_link_conv */ + +/** + * Получить значение поля. + */ +lccrt_link_bind_t +lccrt_link_get_bnd( lccrt_link_t link) +{ + lccrt_link_bind_t r; + + r = LCCRT_LINK_BYTE_BND( &link); + + return (r); +} /* lccrt_link_get_bnd */ + +/** + * Получить значение поля. + */ +lccrt_link_visibility_t +lccrt_link_get_vis( lccrt_link_t link) +{ + lccrt_link_visibility_t r; + + r = LCCRT_LINK_BYTE_VIS( &link); + + return (r); +} /* lccrt_link_get_vis */ + +/** + * Получить значение поля. + */ +lccrt_link_tls_t +lccrt_link_get_tls( lccrt_link_t link) +{ + lccrt_link_tls_t r; + + r = LCCRT_LINK_BYTE_TLS( &link); + + return (r); +} /* lccrt_link_get_tls */ + +/** + * Получить значение поля. + */ +int +lccrt_link_is_const( lccrt_link_t link) +{ + int r; + + r = LCCRT_LINK_BYTE_CST( &link); + + return (r); +} /* lccrt_link_is_const */ + +/** + * Получить значение поля. + */ +int +lccrt_link_is_alias( lccrt_link_t link) +{ + int r; + + r = LCCRT_LINK_BYTE_ALS( &link); + + return (r); +} /* lccrt_link_is_alias */ + +/** + * Получить значение. + */ +lccrt_asmlink_t +lccrt_link_unpack( lccrt_link_t link) +{ + lccrt_asmlink_t r = {0}; + + r.bnd = LCCRT_LINK_BYTE_BND( &link); + r.vis = LCCRT_LINK_BYTE_VIS( &link); + r.tls = LCCRT_LINK_BYTE_TLS( &link); + r.is_cnst = LCCRT_LINK_BYTE_CST( &link); + r.is_alias = LCCRT_LINK_BYTE_ALS( &link); + + return (r); +} /* lccrt_link_unpack */ diff --git a/lib/irv/lccrt_metadata.c b/lib/irv/lccrt_metadata.c new file mode 100644 index 0000000..17216b2 --- /dev/null +++ b/lib/irv/lccrt_metadata.c @@ -0,0 +1,1091 @@ +/** + * 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_metadata.c - реализация пользовательского интерфейса метаданных. + */ + +#include +#include +#include +#include +#include + +#include "lccrt_real.h" + +/** + * Получить "нулевое" значение для категории. + */ +lccrt_einfo_category_t +lccrt_einfo_category_empty() +{ + lccrt_einfo_category_t r = {-1LL}; + + return (r); +} /* lccrt_einfo_category_empty */ + +/** + * Проверка категории метаданных на инициализированность. + */ +int +lccrt_einfo_category_is_valued( lccrt_einfo_category_t ecat) +{ + int r = (ecat.id >= 0); + + return (r); +} /* lccrt_einfo_category_is_valued */ + +/** + * Преобразовать внешний дескриптор во внутреннюю реализацию. + */ +lccrt_einfo_handle_t +lccrt_einfo_get_handle( lccrt_einfo_reference_t eref) +{ + lccrt_einfo_handle_t r; + + r.type = eref.data[0]; + r.data.i64 = eref.data[1]; + + return (r); +} /* lccrt_einfo_get_handle */ + +/** + * Преобразовать внешний дескриптор во внутреннюю реализацию. + */ +lccrt_einfo_reference_t +lccrt_einfo_get_reference( lccrt_einfo_handle_t ehdl) +{ + lccrt_einfo_reference_t r; + + r.data[0] = ehdl.type; + r.data[1] = ehdl.data.i64; + + return (r); +} /* lccrt_einfo_get_reference */ + +/** + * Преобразовать внешний дескриптор во внутреннюю реализацию. + */ +lccrt_einfo_reference_t +lccrt_einfo_get_block_reference( lccrt_einfo_block_ptr eblock) +{ + lccrt_einfo_reference_t r; + lccrt_einfo_handle_t ehdl; + + lccrt_check_type_assert( eblock, lccrt_einfo_block_t); + ehdl.type = eblock->type; + ehdl.data.ref = eblock; + r = lccrt_einfo_get_reference( ehdl); + + return (r); +} /* lccrt_einfo_get_block_reference */ + +/** + * Проверяем возможность передачи значения в назначение указанного типа. + */ +int +lccrt_einfo_is_value_assignable( lccrt_einfo_tydescr_ptr etyde, lccrt_einfo_reference_t value) +{ + int i; + int r = 0; + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( value); + lccrt_einfo_block_ptr eblock = ehdl.data.ref; + + lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t); + if ( (ehdl.type == LCCRT_EINFO_NULL) ) + { + r = 1; + + } else if ( (ehdl.type == LCCRT_EINFO_INT64) ) + { + if ( (etyde->type == LCCRT_EINFO_INT64) ) + { + r = 1; + } else if ( (etyde->type == LCCRT_EINFO_UNION) ) + { + for ( i = 0; i < etyde->num_flds; ++i ) + { + if ( (etyde->types[i]->type == LCCRT_EINFO_INT64) ) + { + r = 1; + break; + } + } + } + } else if ( (etyde->type == LCCRT_EINFO_UNION) ) + { + for ( i = 0; i < etyde->num_flds; ++i ) + { + lccrt_einfo_tydescr_ptr etydei = etyde->types[i]; + + if ( (etydei->type == eblock->type) + && (etydei == eblock->tydescr) ) + { + r = 1; + break; + } + } + } else + { + if ( (etyde->type == eblock->type) + && (etyde == eblock->tydescr) ) + { + r = 1; + } + } + + return (r); +} /* lccrt_einfo_is_value_assignable */ + +/** + * Освободить выделенные данные. + */ +void +lccrt_einfo_tydescr_delete( lccrt_einfo_tydescr_ptr etyde) +{ + if ( etyde ) + { + int i; + lccrt_ctx_ptr ctx = lccrt_module_get_context( etyde->m); + + lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t); + if ( etyde->flds ) + { + for ( i = 0; i < etyde->num_flds; ++i ) lccrt_ctx_free( ctx, etyde->flds[i]); + } + lccrt_ctx_free( ctx, etyde->self_name); + lccrt_ctx_free( ctx, etyde->flds); + lccrt_ctx_free( ctx, etyde->types); + lccrt_check_type_done( etyde, lccrt_einfo_tydescr_t); + lccrt_ctx_free( ctx, etyde); + } + + return; +} /* lccrt_einfo_tydescr_delete */ + +/** + * Проверить описание типа данных на принадлежность к LCCRT_EINFO_INT64. + */ +int +lccrt_einfo_is_tydescr_i64( lccrt_einfo_tydescr_ptr etyde) +{ + int r = (etyde->type == LCCRT_EINFO_INT64); + + return (r); +} /* lccrt_einfo_is_tydescr_i64 */ + +/** + * Проверить описание типа данных на принадлежность к LCCRT_EINFO_RAW. + */ +int +lccrt_einfo_is_tydescr_raw( lccrt_einfo_tydescr_ptr etyde) +{ + int r = (etyde->type == LCCRT_EINFO_RAW); + + return (r); +} /* lccrt_einfo_is_tydescr_raw */ + +/** + * Получить значение поля в описании типа метаданных. + */ +lccrt_einfo_tydescr_ptr +lccrt_einfo_tydescr_get_elem( lccrt_einfo_tydescr_ptr etyde, int elem_k) +{ + lccrt_einfo_tydescr_ptr r = 0; + + lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t); + lccrt_assert( (0 <= elem_k) && (elem_k < etyde->num_flds)); + r = etyde->types[elem_k]; + + return (r); +} /* lccrt_einfo_tydescr_get_elem */ + +/** + * Создать описание типа данных LCCRT_EINFO_INT64. + */ +lccrt_einfo_tydescr_ptr +lccrt_einfo_make_tydescr_i64( lccrt_m_ptr m) +{ + lccrt_einfo_tydescr_ptr r = m->einfo_tyi64; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + + lccrt_check_type_assert( m, lccrt_module_t); + if ( !r ) + { + r = lccrt_ctx_malloc( ctx, lccrt_einfo_tydescr_t); + m->einfo_tyi64 = r; + r->next = m->etydescrs_head; + m->etydescrs_head = r; + memset( r, 0, sizeof( r[0])); + lccrt_check_type_init( r, lccrt_einfo_tydescr_t); + r->type = LCCRT_EINFO_INT64; + r->m = m; + } + + return (r); +} /* lccrt_einfo_make_tydescr_i64 */ + +/** + * Создать описание типа данных LCCRT_EINFO_RAW. + */ +lccrt_einfo_tydescr_ptr +lccrt_einfo_make_tydescr_raw( lccrt_m_ptr m) +{ + lccrt_einfo_tydescr_ptr r = m->einfo_tyraw; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + + lccrt_check_type_assert( m, lccrt_module_t); + if ( !r ) + { + r = lccrt_ctx_malloc( ctx, lccrt_einfo_tydescr_t); + m->einfo_tyraw = r; + r->next = m->etydescrs_head; + m->etydescrs_head = r; + memset( r, 0, sizeof( r[0])); + lccrt_check_type_init( r, lccrt_einfo_tydescr_t); + r->type = LCCRT_EINFO_RAW; + r->m = m; + } + + return (r); +} /* lccrt_einfo_make_tydescr_raw */ + +/** + * Создать описание типа данных LCCRT_EINFO_ARRAY. + */ +lccrt_einfo_tydescr_ptr +lccrt_einfo_make_tydescr_array( lccrt_m_ptr m, lccrt_einfo_tydescr_ptr etyde) +{ + int is_new; + lccrt_einfo_tydescr_ptr r = 0; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + lccrt_he_ptr he = lccrt_hash_push( m->einfo_tyarrs, (intptr_t)etyde, &is_new); + + lccrt_assert( etyde); + lccrt_check_type_assert( m, lccrt_module_t); + lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t); + + if ( is_new ) + { + r = lccrt_ctx_malloc( ctx, lccrt_einfo_tydescr_t); + lccrt_hash_set( he, (intptr_t)r); + memset( r, 0, sizeof( r[0])); + r->next = m->etydescrs_head; + m->etydescrs_head = r; + lccrt_check_type_init( r, lccrt_einfo_tydescr_t); + r->type = LCCRT_EINFO_ARRAY; + r->num_flds = 1; + r->m = m; + r->types = lccrt_ctx_mallocn( ctx, lccrt_einfo_tydescr_ptr, 1); + r->types[0] = etyde; + } else + { + r = (lccrt_einfo_tydescr_ptr)lccrt_hash_get( he); + } + + return (r); +} /* lccrt_einfo_make_tydescr_array */ + +/** + * Создать описание типа данных LCCRT_EINFO_UNION. + */ +lccrt_einfo_tydescr_ptr +lccrt_einfo_make_tydescr_union( lccrt_m_ptr m, int num_flds, lccrt_eitd_ptr *flds_types) +{ + int i; + lccrt_einfo_tydescr_ptr r = 0; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + + lccrt_assert( num_flds >= 0); + r = lccrt_ctx_malloc( ctx, lccrt_einfo_tydescr_t); + memset( r, 0, sizeof( r[0])); + r->next = m->etydescrs_head; + m->etydescrs_head = r; + lccrt_check_type_init( r, lccrt_einfo_tydescr_t); + r->type = LCCRT_EINFO_UNION; + r->num_flds = num_flds; + r->m = m; + r->flds = lccrt_ctx_mallocn( ctx, char *, num_flds); + r->types = lccrt_ctx_mallocn( ctx, lccrt_einfo_tydescr_ptr, num_flds); + for ( i = 0; i < num_flds; ++i ) + { + r->types[i] = flds_types[i]; + lccrt_assert( flds_types[i]->type != LCCRT_EINFO_UNION); + } + + return (r); +} /* lccrt_einfo_make_tydescr_union */ + +/** + * Создать описание типа данных LCCRT_EINFO_STRUCT. + */ +lccrt_einfo_tydescr_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) +{ + int i; + int is_new; + lccrt_einfo_tydescr_ptr r = 0; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + lccrt_he_ptr he = lccrt_hash_push( m->einfo_tysts, (intptr_t)name, &is_new); + + lccrt_check_type_assert( m, lccrt_module_t); + lccrt_assert( num_flds >= 0); + + if ( is_new ) + { + r = lccrt_ctx_malloc( ctx, lccrt_einfo_tydescr_t); + lccrt_hash_set( he, (intptr_t)r); + memset( r, 0, sizeof( r[0])); + r->next = m->etydescrs_head; + m->etydescrs_head = r; + lccrt_check_type_init( r, lccrt_einfo_tydescr_t); + r->type = LCCRT_EINFO_STRUCT; + r->num_flds = num_flds; + r->m = m; + r->self_name = lccrt_ctx_copy_str( ctx, name); + r->flds = lccrt_ctx_mallocn( ctx, char *, num_flds); + r->types = lccrt_ctx_mallocn( ctx, lccrt_einfo_tydescr_ptr, num_flds); + for ( i = 0; i < num_flds; ++i ) + { + r->types[i] = flds_types[i]; + r->flds[i] = lccrt_ctx_copy_str( ctx, flds_names[i]); + } + } else + { + int is_err = 0; + + r = (lccrt_einfo_tydescr_ptr)lccrt_hash_get( he); + if ( (strcmp( r->self_name, name) != 0) + || (r->num_flds != num_flds) ) + { + is_err = 1; + } + + for ( i = 0; i < num_flds; ++i ) + { + if ( (r->types[i] != flds_types[i]) + || (strcmp( r->flds[i], flds_names[i]) != 0) ) + { + is_err = 1; + break; + } + } + + if ( is_err ) + { + r = 0; + lccrt_ctx_error( ctx, 0, "type description of struct '%s' differs from the early one", name); + } + } + + return (r); +} /* lccrt_einfo_make_tydescr_struct */ + +/** + * Поиск в описании структурного типа дескриптора поля. + */ +lccrt_einfo_field_id_t +lccrt_einfo_find_tydescr_field( lccrt_einfo_tydescr_ptr etyde, const char *name) +{ + int i; + lccrt_einfo_field_id_t r = {{0, 0}}; + + lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t); + lccrt_assert( etyde->type == LCCRT_EINFO_STRUCT); + for ( i = 0; i < etyde->num_flds; ++i ) + { + if ( (strcmp( name, etyde->flds[i]) == 0) ) + { + r.data[0] = (intptr_t)etyde; + r.data[1] = i; + break; + } + } + + return (r); +} /* lccrt_einfo_find_tydescr_field */ + +/** + * Создать в рамках модуля новую категорию метаданных. + */ +lccrt_einfo_category_t +lccrt_module_new_einfo_category( lccrt_module_ptr m, const char *name) +{ + lccrt_einfo_category_t r; + int is_new = 0; + lccrt_he_ptr he = lccrt_hash_push( m->einfo_cats, (intptr_t)name, &is_new); + + lccrt_assert( is_new); + lccrt_hash_set( he, (intptr_t)m->einfo_ident); + r.id = m->einfo_ident; + m->einfo_ident++; + + return (r); +} /* lccrt_module_new_einfo_category */ + +/** + * Поиск в модуле категорию метаданных по имени. + */ +lccrt_einfo_category_t +lccrt_module_find_einfo_category( lccrt_module_ptr m, const char *name) +{ + lccrt_einfo_category_t r = {-1LL}; + lccrt_hash_entry_ptr he = lccrt_hash_find( m->einfo_cats, (intptr_t)name); + + if ( he ) + { + r.id = lccrt_hash_get( he); + } + + return (r); +} /* lccrt_module_find_einfo_category */ + +/** + * Проверка метаданных на наличие значения. + */ +int +lccrt_einfo_is_valued( lccrt_einfo_reference_t eref) +{ + int r = 0; + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + + if ( (ehdl.type == LCCRT_EINFO_INT64) + || (ehdl.type == LCCRT_EINFO_RAW) + || (ehdl.type == LCCRT_EINFO_ARRAY) + || (ehdl.type == LCCRT_EINFO_UNION) + || (ehdl.type == LCCRT_EINFO_STRUCT) ) + { + r = 1; + } + + return (r); +} /* lccrt_einfo_is_valued */ + +/** + * Получить количество элементов в метаданных. + */ +int +lccrt_einfo_get_num_args( lccrt_einfo_reference_t eref) +{ + int r = 0; + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + + if ( (ehdl.type == LCCRT_EINFO_ARRAY) + || (ehdl.type == LCCRT_EINFO_STRUCT) + || (ehdl.type == LCCRT_EINFO_RAW) ) + { + lccrt_einfo_block_ptr eblock = ehdl.data.ref; + + lccrt_check_type_assert( eblock, lccrt_einfo_block_t); + r = eblock->num_args; + } + + return (r); +} /* lccrt_einfo_get_num_args */ + +/** + * Получить элемент массива. + */ +lccrt_einfo_reference_t +lccrt_einfo_get_elem( lccrt_einfo_reference_t eref, int elem_k) +{ + lccrt_einfo_reference_t r = {0}; + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + lccrt_einfo_block_ptr eblock = ehdl.data.ref; + + lccrt_assert( ehdl.type == LCCRT_EINFO_ARRAY); + lccrt_check_type_assert( eblock, lccrt_einfo_block_t); + lccrt_assert( (0 <= elem_k) && (elem_k < eblock->num_args)); + r = lccrt_einfo_get_reference( eblock->data.elems[elem_k]); + + return (r); +} /* lccrt_einfo_get_elem */ + +/** + * Получить поле структуры. + */ +lccrt_einfo_reference_t +lccrt_einfo_get_field( lccrt_einfo_reference_t eref, lccrt_eifi_t eifi) +{ + lccrt_einfo_reference_t r = {0}; + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + lccrt_einfo_block_ptr eblock = ehdl.data.ref; + + lccrt_assert( ehdl.type == LCCRT_EINFO_STRUCT); + lccrt_check_type_assert( eblock, lccrt_einfo_block_t); + lccrt_assert( (intptr_t)eblock->tydescr == eifi.data[0]); + lccrt_assert( (0 <= eifi.data[1]) && (eifi.data[1] < eblock->num_args)); + r = lccrt_einfo_get_reference( eblock->data.flds[eifi.data[1]]); + + return (r); +} /* lccrt_einfo_get_field */ + +/** + * Получить значение байтового массива. + */ +uint8_t * +lccrt_einfo_get_raw_data( lccrt_einfo_reference_t eref) +{ + uint8_t *r = 0; + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + lccrt_einfo_block_ptr eblock = ehdl.data.ref; + + lccrt_assert( ehdl.type == LCCRT_EINFO_RAW); + lccrt_check_type_assert( eblock, lccrt_einfo_block_t); + r = eblock->data.rdata; + + return (r); +} /* lccrt_einfo_get_raw_data */ + +/** + * Получить для нескалярных метаданных ссылки на описание типа данных. + */ +lccrt_einfo_tydescr_ptr +lccrt_einfo_get_tydescr( lccrt_einfo_reference_t eref) +{ + lccrt_einfo_tydescr_ptr r = 0; + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + + if ( (ehdl.type == LCCRT_EINFO_ARRAY) + || (ehdl.type == LCCRT_EINFO_STRUCT) + || (ehdl.type == LCCRT_EINFO_RAW) ) + { + r = ehdl.data.ref->tydescr; + } + + return (r); +} /* lccrt_einfo_get_tydescr */ + +/** + * Проверка типа метаданных на передачу по значению. + */ +int +lccrt_einfo_is_scalar( lccrt_einfo_reference_t eref) +{ + int r = 0; + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + + if ( (ehdl.type == LCCRT_EINFO_INT64) ) + { + r = 1; + } + + return (r); +} /* lccrt_einfo_is_scalar */ + +/** + * Удалить данные структуры и саму структуру. + */ +void +lccrt_einfo_block_delete( lccrt_einfo_block_ptr eblock) +{ + if ( eblock ) + { + lccrt_ctx_ptr ctx = lccrt_module_get_context( eblock->tydescr->m); + + lccrt_check_type_assert( eblock, lccrt_einfo_block_t); + lccrt_check_type_assert( eblock->tydescr, lccrt_einfo_tydescr_t); + lccrt_ctx_free( ctx, eblock->data.flds); + lccrt_check_type_done( eblock, lccrt_einfo_block_t); + lccrt_ctx_free( ctx, eblock); + } + + return; +} /* lccrt_einfo_block_delete */ + +/** + * Проверить дескриптор на равенство нулевому дескриптору. + */ +int +lccrt_einfo_is_empty( lccrt_einfo_reference_t eref) +{ + int r = ((eref.data[0] == 0) && (eref.data[1] == 0)); + + lccrt_assert( r != lccrt_einfo_is_valued( eref)); + + return (r); +} /* lccrt_einfo_is_empty */ + +/** + * Создать нулевой дескриптор. + */ +lccrt_einfo_reference_t +lccrt_einfo_new_empty() +{ + lccrt_einfo_reference_t r; + lccrt_einfo_handle_t ehdl; + + ehdl.type = LCCRT_EINFO_NULL; + ehdl.data.i64 = 0; + r = lccrt_einfo_get_reference( ehdl); + + return (r); +} /* lccrt_einfo_new_empty */ + +/** + * Создать дескриптор целочисленных данных. + */ +lccrt_einfo_reference_t +lccrt_einfo_new_i64( uint64_t value) +{ + lccrt_einfo_reference_t r; + lccrt_einfo_handle_t ehdl; + + ehdl.type = LCCRT_EINFO_INT64; + ehdl.data.i64 = value; + r = lccrt_einfo_get_reference( ehdl); + + return (r); +} /* lccrt_einfo_new_i64 */ + +/** + * Создать дескриптор байтового массива. + */ +lccrt_einfo_reference_t +lccrt_einfo_new_raw( lccrt_module_ptr m, int length, const uint8_t *data) +{ + lccrt_einfo_reference_t r; + lccrt_einfo_handle_t ehdl; + lccrt_einfo_block_ptr eblock; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + + eblock = lccrt_ctx_malloc( ctx, lccrt_einfo_block_t); + memset( eblock, 0, sizeof( eblock[0])); + lccrt_check_type_init( eblock, lccrt_einfo_block_t); + eblock->next = m->eblocks_head; + m->eblocks_head = eblock; + eblock->type = LCCRT_EINFO_RAW; + eblock->tydescr = lccrt_einfo_make_tydescr_raw( m); + eblock->num_args = length; + eblock->data.rdata = lccrt_ctx_mallocn( ctx, uint8_t, length); + memcpy( eblock->data.rdata, data, length); + + ehdl.type = LCCRT_EINFO_RAW; + ehdl.data.ref = eblock; + r = lccrt_einfo_get_reference( ehdl); + + return (r); +} /* lccrt_einfo_new_raw */ + +/** + * Создать дескриптор байтового массива на основе строке. + */ +lccrt_einfo_reference_t +lccrt_einfo_new_raw_by_string( lccrt_module_ptr m, const char *data) +{ + lccrt_einfo_reference_t r = lccrt_einfo_new_raw( m, strlen( data) + 1, data); + + return (r); +} /* lccrt_einfo_new_raw_by_string */ + +/** + * Создать значение типа массив. + */ +lccrt_einfo_reference_t +lccrt_einfo_new_array( lccrt_einfo_tydescr_ptr etyde, int alloc_elems) +{ + lccrt_einfo_reference_t r; + lccrt_einfo_handle_t ehdl; + lccrt_einfo_block_ptr eblock; + lccrt_module_ptr m = etyde->m; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + + lccrt_assert( alloc_elems >= 0); + lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t); + + eblock = lccrt_ctx_malloc( ctx, lccrt_einfo_block_t); + memset( eblock, 0, sizeof( eblock[0])); + lccrt_check_type_init( eblock, lccrt_einfo_block_t); + eblock->next = m->eblocks_head; + m->eblocks_head = eblock; + eblock->type = LCCRT_EINFO_ARRAY; + eblock->tydescr = etyde; + //eblock->max_args = (alloc_elems == 0) ? 4 : alloc_elems; + eblock->num_args = alloc_elems; + eblock->max_args = alloc_elems; + eblock->data.elems = lccrt_ctx_mallocn( ctx, lccrt_einfo_handle_t, eblock->max_args); + memset( eblock->data.flds, 0, eblock->max_args*sizeof( eblock->data.elems[0])); + + ehdl.type = LCCRT_EINFO_ARRAY; + ehdl.data.ref = eblock; + r = lccrt_einfo_get_reference( ehdl); + + return (r); +} /* lccrt_einfo_new_array */ + +/** + * Создать значение типа структура. + */ +lccrt_einfo_reference_t +lccrt_einfo_new_struct( lccrt_einfo_tydescr_ptr etyde) +{ + lccrt_einfo_reference_t r; + lccrt_einfo_handle_t ehdl; + lccrt_einfo_block_ptr eblock; + lccrt_module_ptr m = etyde->m; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + + lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t); + lccrt_assert( etyde->type == LCCRT_EINFO_STRUCT); + eblock = lccrt_ctx_malloc( ctx, lccrt_einfo_block_t); + memset( eblock, 0, sizeof( eblock[0])); + lccrt_check_type_init( eblock, lccrt_einfo_block_t); + eblock->next = m->eblocks_head; + m->eblocks_head = eblock; + eblock->type = LCCRT_EINFO_STRUCT; + eblock->tydescr = etyde; + eblock->num_args = etyde->num_flds; + eblock->data.flds = lccrt_ctx_mallocn( ctx, lccrt_einfo_handle_t, eblock->num_args); + memset( eblock->data.flds, 0, eblock->num_args*sizeof( eblock->data.flds[0])); + + ehdl.type = LCCRT_EINFO_STRUCT; + ehdl.data.ref = eblock; + r = lccrt_einfo_get_reference( ehdl); + + return (r); +} /* lccrt_einfo_new_struct */ + +/** + * Установить значение элемента в массиве. + */ +void +lccrt_einfo_set_elem( lccrt_eir_t eref, int index, lccrt_eir_t value) +{ + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + lccrt_einfo_block_ptr eblock = ehdl.data.ref; + + lccrt_assert( (0 <= index) && (index < eblock->num_args)); + lccrt_assert( ehdl.type == LCCRT_EINFO_ARRAY); + lccrt_assert( lccrt_einfo_is_value_assignable( eblock->tydescr->types[0], value)); + eblock->data.elems[index] = lccrt_einfo_get_handle( value); + +#if 0 + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + lccrt_einfo_block_ptr eblock = ehdl.data.ref; + + elem_ident = (elem_ident < 0) ? eblock->num_args : elem_ident; +#endif + + return; +} /* lccrt_einfo_set_elem */ + +/** + * Добавить значение в массив, увеличив его длину по необходимости. + */ +void +lccrt_einfo_push_elem( lccrt_eir_t eref, lccrt_eir_t value) +{ + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + lccrt_einfo_block_ptr eblock = ehdl.data.ref; + int num_args = eblock->num_args; + lccrt_ctx_ptr ctx = lccrt_module_get_context( eblock->tydescr->m); + + lccrt_check_type_assert( eblock, lccrt_einfo_block_t); + lccrt_assert( eblock->type == LCCRT_EINFO_ARRAY); + lccrt_assert( (0 <= num_args) && (num_args <= eblock->max_args)); + lccrt_assert( lccrt_einfo_is_value_assignable( eblock->tydescr->types[0], value)); + + if ( (num_args == eblock->max_args) ) + { + lccrt_einfo_handle_t *new_data = 0; + + if ( (eblock->max_args == 0) ) + { + eblock->max_args = 4; + } else + { + eblock->max_args = 2*eblock->max_args; + } + + new_data = lccrt_ctx_mallocn( ctx, lccrt_einfo_handle_t, eblock->max_args); + memcpy( new_data, eblock->data.elems, num_args*sizeof( new_data[0])); + memset( new_data + num_args, 0, (eblock->max_args - num_args)*sizeof( new_data[0])); + lccrt_ctx_free( ctx, eblock->data.elems); + eblock->data.elems = new_data; + } + + eblock->data.elems[num_args] = lccrt_einfo_get_handle( value); + eblock->num_args++; + + return; +} /* lccrt_einfo_push_elem */ + +/** + * Установить значение поля структуры. + */ +void +lccrt_einfo_set_field( lccrt_eir_t eref, lccrt_eifi_t eifi, lccrt_eir_t value) +{ + int index = eifi.data[1]; + lccrt_einfo_tydescr_ptr etyde = (lccrt_einfo_tydescr_ptr)eifi.data[0]; + lccrt_einfo_handle_t ehdl = lccrt_einfo_get_handle( eref); + lccrt_einfo_handle_t ehdl_value = lccrt_einfo_get_handle( value); + lccrt_einfo_block_ptr eblock = ehdl.data.ref; + + lccrt_assert( eblock->tydescr == etyde); + lccrt_assert( (ehdl.type == LCCRT_EINFO_STRUCT) && (eblock->type == LCCRT_EINFO_STRUCT)); + lccrt_assert( (0 <= eifi.data[1]) && (eifi.data[1] < eblock->num_args)); + lccrt_check_type_assert( eblock, lccrt_einfo_block_t); + lccrt_assert( lccrt_einfo_is_value_assignable( eblock->tydescr->types[index], value)); + + eblock->data.flds[index] = ehdl_value; + + return; +} /* lccrt_einfo_set_field */ + +/** + * Получить значение метаданных из цепочки привязки. + */ +lccrt_einfo_reference_t +lccrt_einfo_link_get_value( lccrt_einfo_link_ptr elink) +{ + lccrt_einfo_reference_t r; + + if ( elink ) + { + r = lccrt_einfo_get_reference( elink->value); + } else + { + lccrt_einfo_handle_t ehdl = {LCCRT_EINFO_NULL}; + + r = lccrt_einfo_get_reference( ehdl); + } + + return (r); +} /* lccrt_einfo_link_get_value */ + +/** + * Создать звено для цепочки привязки мета-данные. + */ +lccrt_einfo_link_ptr +lccrt_einfo_link_new( lccrt_m_ptr m, lccrt_eil_ptr elink0, lccrt_eic_t ecat, lccrt_eir_t value) +{ + lccrt_einfo_link_ptr elink = 0; + lccrt_ctx_ptr ctx = lccrt_module_get_context( m); + + elink = lccrt_ctx_malloc( ctx, lccrt_einfo_link_t); + memset( elink, 0, sizeof( elink[0])); + lccrt_check_type_init( elink, lccrt_einfo_link_t); + elink->next = elink0; + elink->ident = ecat; + elink->value = lccrt_einfo_get_handle( value); + + return (elink); +} /* lccrt_einfo_link_new */ + +/** + * Поиск звена в цепочке привязки мета-данные по категории. + */ +lccrt_einfo_link_ptr +lccrt_einfo_link_find( lccrt_eil_ptr elink, lccrt_eic_t ecat) +{ + while ( elink + && (elink->ident.id != ecat.id) ) + { + elink = elink->next; + } + + return (elink); +} /* lccrt_einfo_link_find */ + +/** + * Добавить в цепочку привязки новые мета-данные, либо изменить значение старых. + */ +lccrt_einfo_link_ptr +lccrt_einfo_link_push_value( lccrt_m_ptr m, lccrt_eil_ptr elink0, lccrt_eic_t ecat, lccrt_eir_t value) +{ + lccrt_einfo_link_ptr elink = lccrt_einfo_link_find( elink0, ecat); + + if ( elink ) + { + /* Мета-данные с таким именем уже существуют. */ + elink->value = lccrt_einfo_get_handle( value); + } else + { + elink0 = lccrt_einfo_link_new( m, elink0, ecat, value); + } + + return (elink0); +} /* lccrt_einfo_link_push_value */ + +/** + * Удалить звено цепочки привязки einfo-данных. + */ +void +lccrt_einfo_link_delete( lccrt_einfo_link_ptr elink) +{ + if ( elink ) + { + lccrt_einfo_block_ptr eblock = elink->value.data.ref; + + lccrt_check_type_assert( elink, lccrt_einfo_link_t); + lccrt_check_type_assert( eblock, lccrt_einfo_block_t); + lccrt_check_type_assert( eblock->tydescr, lccrt_einfo_tydescr_t); + lccrt_check_type_done( elink, lccrt_einfo_link_t); + lccrt_ctx_free( lccrt_module_get_context( eblock->tydescr->m), elink); + } + + return; +} /* lccrt_einfo_link_delete */ + +/** + * Удалить цепочку привязки einfo-данных. + */ +lccrt_einfo_link_ptr +lccrt_einfo_link_delete_chain( lccrt_einfo_link_ptr elink) +{ + while ( elink ) + { + lccrt_einfo_link_ptr next = elink->next; + + lccrt_einfo_link_delete( elink); + elink = next; + } + + return (0); +} /* lccrt_einfo_link_delete_chain */ + +/** + * Пронумеровать описание типов einfo-данных с помощью указанной хеш-таблицы. + */ +static uint64_t +lccrt_einfo_tydescr_number( uint64_t ident, lccrt_einfo_tydescr_ptr etyde, lccrt_hash_ptr tbl) +{ + lccrt_hash_entry_ptr he; + int is_new = 0; + lccrt_ctx_ptr ctx = lccrt_module_get_context( etyde->m); + + lccrt_check_type_assert( etyde, lccrt_einfo_tydescr_t); + he = lccrt_hash_push( tbl, (intptr_t)etyde, &is_new); + if ( !is_new ) + { + intptr_t cur_ident = lccrt_hash_get( he); + + if ( (cur_ident < 0) ) + { + lccrt_ctx_error( ctx, 0, "Recursive loop in extended information types descriptions"); + } + } else + { + int64_t i; + + lccrt_hash_set( he, (uintptr_t)(-1LL)); + for ( i = 0; i < etyde->num_flds; ++i ) + { + ident = lccrt_einfo_tydescr_number( ident, etyde->types[i], tbl); + } + + he = lccrt_hash_find( tbl, (intptr_t)etyde); + lccrt_hash_set( he, (uintptr_t)ident); + ++ident; + } + + return (ident); +} /* lccrt_einfo_tydescr_number */ + +/** + * Пронумеровать поддерево метаданных с помощью указнной хеш-таблицы. + */ +static uint64_t +lccrt_einfo_block_number( uint64_t ident, lccrt_einfo_block_ptr eblock, lccrt_hash_ptr tbl) +{ + lccrt_hash_entry_ptr he; + int is_new = 0; + lccrt_ctx_ptr ctx = lccrt_module_get_context( eblock->tydescr->m); + + lccrt_check_type_assert( eblock, lccrt_einfo_block_t); + he = lccrt_hash_push( tbl, (intptr_t)eblock, &is_new); + if ( !is_new ) + { + intptr_t cur_ident = lccrt_hash_get( he); + + if ( (cur_ident < 0) ) + { + lccrt_ctx_error( ctx, 0, "Recursive loop in extended information"); + } + } else + { + int64_t i; + + lccrt_hash_set( he, (uintptr_t)(-1LL)); + if ( (eblock->type == LCCRT_EINFO_STRUCT) + || (eblock->type == LCCRT_EINFO_UNION) ) + { + for ( i = eblock->num_args - 1; i >= 0; --i ) + { + lccrt_einfo_handle_t q = eblock->data.flds[i]; + + if ( (q.type == LCCRT_EINFO_STRUCT) + || (q.type == LCCRT_EINFO_UNION) + || (q.type == LCCRT_EINFO_ARRAY) + || (q.type == LCCRT_EINFO_RAW) ) + { + ident = lccrt_einfo_block_number( ident, q.data.ref, tbl); + } + } + } else if ( (eblock->type == LCCRT_EINFO_ARRAY) ) + { + for ( i = eblock->num_args - 1; i >= 0; --i ) + { + lccrt_einfo_handle_t q = eblock->data.elems[i]; + + if ( (q.type == LCCRT_EINFO_STRUCT) + || (q.type == LCCRT_EINFO_UNION) + || (q.type == LCCRT_EINFO_ARRAY) + || (q.type == LCCRT_EINFO_RAW) ) + { + ident = lccrt_einfo_block_number( ident, q.data.ref, tbl); + } + } + } else if ( (eblock->type == LCCRT_EINFO_RAW) ) + { + } else + { + lccrt_assert( 0); + } + + he = lccrt_hash_find( tbl, (intptr_t)eblock); + lccrt_hash_set( he, (uintptr_t)ident); + ++ident; + } + + return (ident); +} /* lccrt_einfo_block_number */ + +/** + * Для каждого узла дерева метаданных (STRUCT или ARRAY) провести нумерацию + * с помощью хеширования в указанной хеш-таблице. + */ +void +lccrt_module_einfo_number( lccrt_module_ptr m, lccrt_hash_ptr btbl, lccrt_hash_ptr ttbl) +{ + lccrt_check_type_assert( m, lccrt_module_t); + + // Нумеруем блоки. + if ( btbl ) + { + lccrt_einfo_block_ptr unit; + uint64_t ident = 0; + + for ( unit = m->eblocks_head; unit; unit = unit->next ) + { + ident = lccrt_einfo_block_number( ident, unit, btbl); + } + } + + // Нумеруем описания типов. + if ( ttbl ) + { + lccrt_einfo_tydescr_ptr unit; + uint64_t ident = 0; + + for ( unit = m->etydescrs_head; unit; unit = unit->next ) + { + ident = lccrt_einfo_tydescr_number( ident, unit, ttbl); + } + } + + return; +} /* lccrt_module_einfo_number */ diff --git a/lib/irv/lccrt_module.c b/lib/irv/lccrt_module.c new file mode 100644 index 0000000..36de345 --- /dev/null +++ b/lib/irv/lccrt_module.c @@ -0,0 +1,452 @@ +/** + * 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_module.c - реализация пользовательский интерфейс (динамической) компиляции. + */ + +#include +#include +#include +#include +#include + +#include "lccrt_real.h" + +/** + * Инициализация контекста (стандартные типы). + */ +static void +lccrt_module_init_types_std( lccrt_module_ptr m) +{ + lccrt_types_std_t *ts = &(m->types_std); + + lccrt_check_type_assert( m, lccrt_module_t); + ts->ptr_bytesize = m->is_ptr32 ? 4 : 8; + ts->bool_type = lccrt_type_make_simple( m, LCCRT_TYPE_BOOL, "bool", 0, 1, 1); + //ts->bool_type = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "u8", 0, 1); + ts->void_type = lccrt_type_make_simple( m, LCCRT_TYPE_VOID, "void", 0, 1, 0); + ts->int_types[0][0] = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "u8", 0, 1, 1); + ts->int_types[0][1] = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "u16", 0, 2, 2); + ts->int_types[0][2] = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "u32", 0, 4, 4); + ts->int_types[0][3] = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "u64", 0, 8, 8); + ts->int_types[0][4] = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "u128", 0, 16, 16); + ts->int_types[0][5] = 0; + ts->int_types[1][0] = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "i8", 1, 1, 1); + ts->int_types[1][1] = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "i16", 1, 2, 2); + ts->int_types[1][2] = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "i32", 1, 4, 4); + ts->int_types[1][3] = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "i64", 1, 8, 8); + ts->int_types[1][4] = lccrt_type_make_simple( m, LCCRT_TYPE_INT, "i128", 1, 16, 16); + ts->int_types[1][5] = 0; + ts->float_types[0] = lccrt_type_make_simple( m, LCCRT_TYPE_FLOAT, "f32", 0, 4, 4); + ts->float_types[1] = lccrt_type_make_simple( m, LCCRT_TYPE_FLOAT, "f64", 0, 8, 8); + ts->float_types[2] = lccrt_type_make_simple( m, LCCRT_TYPE_FLOAT, "f80", 0, 16, 10); + ts->float_types[3] = lccrt_type_make_simple( m, LCCRT_TYPE_FLOAT, "f128", 0, 16, 16); + ts->float_types[4] = 0; + ts->ellipsis = lccrt_type_make_simple( m, LCCRT_TYPE_ELLIPSIS, "...", 0, 1, 0); + ts->intptr = ts->int_types[0][m->is_ptr32 ? LCCRT_INT_SUBTYPE_32 : LCCRT_INT_SUBTYPE_64]; + ts->ptr_byte = lccrt_type_make_ptr_type( ts->int_types[0][LCCRT_INT_SUBTYPE_8]); + ts->ptr_char = lccrt_type_make_ptr_type( ts->int_types[1][LCCRT_INT_SUBTYPE_8]); + ts->ptr_intptr = lccrt_type_make_ptr_type( ts->intptr); + + return; +} /* lccrt_module_init_types_std */ + +/** + * Создание нового модуля. + */ +lccrt_module_ptr +lccrt_module_new( lccrt_context_ptr ctx, const char *name, int is_m32) +{ + lccrt_module_ptr m = lccrt_ctx_malloc( ctx, lccrt_module_t); + + lccrt_check_type_assert( ctx, lccrt_context_t); + memset( m, 0, sizeof( m[0])); + lccrt_check_type_init( m, lccrt_module_t); + m->ctx = ctx; + m->name = lccrt_ctx_copy_str( ctx, name); + m->is_ptr32 = is_m32; + m->types = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + m->type_usr_names = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + m->type_max = 0; + m->gvars = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + m->funcs = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + m->einfo_cats = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + m->einfo_tyarrs = lccrt_hash_new( ctx, LCCRT_HASH_KEY_INTPTR); + m->einfo_tysts = lccrt_hash_new( ctx, LCCRT_HASH_KEY_STRING); + lccrt_ilist_head_init( &(m->types_head)); + lccrt_ilist_head_init( &(m->gvars_head)); + lccrt_ilist_head_init( &(m->funcs_head)); + lccrt_ilist_head_init( &(m->varinits_head)); + ctx->module_max++; + m->ident_num = ctx->module_max; + m->gvars_num = 0; + m->funcs_num = 0; + m->cargs_name_id = 0; + m->global_name_id = 0; + lccrt_hash_push( ctx->modules, (uintptr_t)m, 0); + lccrt_module_init_types_std( m); + + return (m); +} /* lccrt_module_new */ + +/** + * Удаление модуля. + */ +void +lccrt_module_delete_data( lccrt_m_ptr m) +{ + lccrt_varinit_ptr vi_unit; + lccrt_einfo_block_ptr eib_unit, eib_next; + lccrt_einfo_tydescr_ptr eitd_unit, eitd_next; + lccrt_hash_entry_ptr e = 0; + lccrt_context_ptr ctx = m->ctx; + + lccrt_check_type_assert( m, lccrt_module_t); + lccrt_ctx_free( ctx, m->name); + lccrt_ctx_free( ctx, m->asm_text); + + /* Удаляем все ранее созданные типы и сопутствующие структуры данных. */ + for ( e = lccrt_hash_first( m->funcs); e; e = lccrt_hash_next( e) ) + { + lccrt_function_delete( (lccrt_f_ptr)lccrt_hash_get( e)); + } + + lccrt_hash_delete( m->funcs); + + for ( e = lccrt_hash_first( m->gvars); e; e = lccrt_hash_next( e) ) + { + lccrt_var_delete( (lccrt_v_ptr)lccrt_hash_get( e)); + } + + lccrt_hash_delete( m->gvars); + + for ( vi_unit = m->varinits_head.first; vi_unit; vi_unit = m->varinits_head.first ) + { + lccrt_varinit_delete( vi_unit); + } + + /* Удаляем цепочку привязку к модулю собственных мета-данных. */ + m->einfo = lccrt_einfo_link_delete_chain( m->einfo); + + /* Удаляем все категории мета-данных. */ + lccrt_hash_delete( m->einfo_cats); + + /* Удаляем все мета-данные. */ + for ( eib_unit = m->eblocks_head; eib_unit; eib_unit = eib_next ) + { + eib_next = eib_unit->next; + lccrt_einfo_block_delete( eib_unit); + } + + /* Удаляем все описания типов мета-данных. */ + for ( eitd_unit = m->etydescrs_head; eitd_unit; eitd_unit = eitd_next ) + { + eitd_next = eitd_unit->next; + lccrt_einfo_tydescr_delete( eitd_unit); + } + + /* Удаляем таблицы хеширования описания мета-данных. */ + lccrt_hash_delete( m->einfo_tyarrs); + lccrt_hash_delete( m->einfo_tysts); + + for ( e = lccrt_hash_first( m->types); e; e = lccrt_hash_next( e) ) + { + lccrt_type_delete( (lccrt_t_ptr)lccrt_hash_get( e)); + } + + lccrt_hash_delete( m->types); + lccrt_hash_delete( m->type_usr_names); + + lccrt_check_type_done( m, lccrt_module_t); + lccrt_ctx_free( ctx, m); + + return; +} /* lccrt_module_delete_data */ + +/** + * Удаление модуля. + */ +void +lccrt_module_delete( lccrt_module_ptr m) +{ + lccrt_context_ptr ctx = m->ctx; + lccrt_hash_entry_ptr he = lccrt_hash_find( ctx->modules, (uintptr_t)m); + + lccrt_check_type_assert( m, lccrt_module_t); + lccrt_check_type_assert( ctx, lccrt_context_t); + lccrt_module_delete_data( m); + if ( he ) + { + lccrt_hash_remove( he); + } + + return; +} /* lccrt_module_delete */ + +/** + * Прочитать поле. + */ +lccrt_context_ptr +lccrt_module_get_context( lccrt_module_ptr m) +{ + lccrt_context_ptr r = m->ctx; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_module_get_context */ + +/** + * Прочитать поле. + */ +const char * +lccrt_module_get_inline_asm( lccrt_m_ptr m) +{ + const char *r = m->asm_text; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_module_get_inline_asm */ + +/** + * Прочитать поле. + */ +void +lccrt_module_set_inline_asm( lccrt_m_ptr m, const char *asm_text) +{ + lccrt_ctx_ptr ctx = m->ctx; + + lccrt_check_type_assert( m, lccrt_module_t); + lccrt_ctx_free( ctx, m->asm_text); + m->asm_text = lccrt_ctx_copy_str( ctx, asm_text); + + return; +} /* lccrt_module_set_inline_asm */ + +/** + * Прочитать поле. + */ +uint64_t +lccrt_module_get_type_max( lccrt_module_ptr m) +{ + uint64_t r = m->type_max; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_module_get_type_max */ + +/** + * Прочитать поле. + */ +uint64_t +lccrt_module_get_func_max( lccrt_module_ptr m) +{ + uint64_t r = m->funcs_num; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_module_get_func_max */ + +/** + * Прочитать поле. + */ +const char* +lccrt_module_get_name( lccrt_module_ptr m) +{ + const char *r = m->name; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_module_get_name */ + +/** + * Формирование нового имени для глобальной переменной. + */ +char * +lccrt_module_name_new_global( lccrt_m_ptr module, const char *name) +{ + char str[1024]; + const char *q = name; + char *result = 0; + + lccrt_check_type_assert( module, lccrt_module_t); + if ( !name ) + { + snprintf( str, 1024, "__lccrt_g%j", module->global_name_id); + module->global_name_id++; + q = str; + } + + result = lccrt_ctx_copy_str( module->ctx, q); + + return (result); +} /* lccrt_module_name_new_global */ + +/** + * Прочитать поле. + */ +int +lccrt_module_is_ptr32( lccrt_module_ptr m) +{ + int r = m->is_ptr32; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_module_is_ptr32 */ + +/** + * Прочитать поле. + */ +lccrt_hash_ptr +lccrt_module_get_types( lccrt_module_ptr m) +{ + lccrt_check_type_assert( m, lccrt_module_t); + + return (m->types); +} /* lccrt_module_get_types */ + +/** + * Прочитать поле. + */ +lccrt_hash_ptr +lccrt_module_get_gvars( lccrt_module_ptr m) +{ + lccrt_check_type_assert( m, lccrt_module_t); + + return (m->gvars); +} /* lccrt_module_get_gvars */ + +/** + * Прочитать поле. + */ +lccrt_hash_ptr +lccrt_module_get_funcs( lccrt_module_ptr m) +{ + lccrt_check_type_assert( m, lccrt_module_t); + + return (m->funcs); +} /* lccrt_module_get_funcs */ + +/** + * Получить первый тип модуля. + */ +lccrt_type_ptr +lccrt_module_get_first_type( lccrt_module_ptr m) +{ + lccrt_type_ptr r; + + lccrt_check_type_assert( m, lccrt_module_t); + r = m->types_head.first; + lccrt_check_type_assert( r, lccrt_type_t); + + return (r); +} /* lccrt_module_get_first_type */ + +/** + * Получить первую глобальную переменную модуля. + */ +lccrt_var_ptr +lccrt_module_get_first_var( lccrt_module_ptr m) +{ + lccrt_var_ptr r; + + lccrt_check_type_assert( m, lccrt_module_t); + r = m->gvars_head.first; + lccrt_assert( !r || lccrt_var_is_global( r)); + + return (r); +} /* lccrt_module_get_first_var */ + +/** + * Получить первую глобальную переменную модуля. + */ +lccrt_function_ptr +lccrt_module_get_first_func( lccrt_module_ptr m) +{ + lccrt_function_ptr r; + + lccrt_check_type_assert( m, lccrt_module_t); + r = m->funcs_head.first; + + return (r); +} /* lccrt_module_get_first_func */ + +/** + * Поиск функции по имени. + */ +lccrt_function_ptr +lccrt_module_find_function( lccrt_module_ptr m, const char *name) +{ + lccrt_hash_entry_ptr e = lccrt_hash_find( m->funcs, (uintptr_t)name); + lccrt_function_ptr r = e ? (lccrt_f_ptr)lccrt_hash_get( e) : 0; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_module_find_function */ + +/** + * Добавить в модуль новые мета-данные, либо изменить значение старых. + */ +void +lccrt_module_set_einfo( lccrt_module_ptr m, lccrt_einfo_category_t ecat, lccrt_eir_t value) +{ + lccrt_check_type_assert( m, lccrt_module_t); + lccrt_assert( !lccrt_einfo_is_scalar( value)); + m->einfo = lccrt_einfo_link_push_value( m, m->einfo, ecat, value); + + return; +} /* lccrt_module_set_einfo */ + +/** + * Получить значение мета-данных с заданным именем или 0, если таких данных нет. + */ +lccrt_einfo_reference_t +lccrt_module_get_einfo( lccrt_module_ptr m, lccrt_einfo_category_t ecat) +{ + lccrt_einfo_link_ptr unit = lccrt_einfo_link_find( m->einfo, ecat); + lccrt_einfo_reference_t r = lccrt_einfo_link_get_value( unit); + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_module_get_einfo */ + +/** + * Получить первую глобальную переменную модуля. + */ +void +lccrt_module_rename( lccrt_module_ptr m, const char *new_name) +{ + lccrt_check_type_assert( m, lccrt_module_t); + lccrt_assert( 0); + + return; +} /* lccrt_module_rename */ + +/** + * Всем типам, у которых не задано пользовательское имя, назначить пользовательское имя. + */ +void +lccrt_module_init_types_usr_names( lccrt_module_ptr m) +{ + lccrt_hash_entry_ptr e; + + for ( e = lccrt_hash_first( m->types); e; e = lccrt_hash_next( e) ) + { + lccrt_type_ptr t = (lccrt_type_ptr)(uintptr_t)lccrt_hash_get( e); + + if ( t->usr_name ) + { + } + } + + return; +} /* lccrt_module_init_types_usr_names */ diff --git a/lib/irv/lccrt_oper.c b/lib/irv/lccrt_oper.c new file mode 100644 index 0000000..a402092 --- /dev/null +++ b/lib/irv/lccrt_oper.c @@ -0,0 +1,2137 @@ +/** + * 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_oper.c - реализация пользовательский интерфейс (динамической) компиляции. + */ + +#include +#include +#include +#include +#include + +#include "lccrt_real.h" + +#define lccrt_snprintf_max( l, j) ((j < (l)) ? ((l) - j) : 0) +#define lccrt_snprintf( s, l, j, ...) \ + (j += snprintf( s + j, lccrt_snprintf_max( l, j), __VA_ARGS__)) + +/** + * Создание итератора. + */ +lccrt_oper_iterator_ptr +lccrt_oper_iterator_new( lccrt_context_ptr ctx) +{ + lccrt_oper_iterator_ptr r; + + r = lccrt_ctx_malloc( ctx, lccrt_oper_iterator_t); + r->ctx = ctx; + r->is_forward = 1; + r->prev = 0; + r->next = 0; + r->last = 0; + lccrt_check_type_init( r, lccrt_oper_iterator_t); + + return (r); +} /* lccrt_oper_iterator_new */ + +/** + * Удаление итератора. + */ +lccrt_oper_iterator_ptr +lccrt_oper_iterator_delete( lccrt_oper_iterator_ptr i) +{ + lccrt_check_type_assert( i, lccrt_oper_iterator_t); + lccrt_check_type_done( i, lccrt_oper_iterator_t); + lccrt_ctx_free( i->ctx, i); + + return (0); +} /* lccrt_oper_iterator_delete */ + +/** + * Инициализация прямого итератора {o,o->next}. + */ +lccrt_oper_iterator_ptr +lccrt_oper_iterator_set( lccrt_oper_iterator_ptr i, lccrt_o_ptr o) +{ + lccrt_check_type_assert( i, lccrt_oper_iterator_t); + lccrt_check_type_assert( o, lccrt_oper_t); + i->is_forward = 1; + i->prev = o; + i->next = o ? o->next : 0; + i->last = 0; + + return (i); +} /* lccrt_oper_iterator_set */ + +/** + * Инициализация прямого итератора {o->prev,o}. + */ +lccrt_oper_iterator_ptr +lccrt_oper_iterator_set_prev( lccrt_oper_iterator_ptr i, lccrt_o_ptr o) +{ + lccrt_check_type_assert( i, lccrt_oper_iterator_t); + lccrt_check_type_assert( o, lccrt_oper_t); + i->is_forward = 1; + i->prev = o ? o->prev : 0; + i->next = o; + i->last = 0; + + return (i); +} /* lccrt_oper_iterator_set_prev */ + +/** + * Получить операцию i->prev. + */ +lccrt_oper_ptr +lccrt_oper_iterator_get_prev( lccrt_oper_iterator_ptr i) +{ + lccrt_oper_ptr r = i->prev; + + return (r); +} /* lccrt_oper_iterator_get_prev */ + +/** + * Получить операцию i->next. + */ +lccrt_oper_ptr +lccrt_oper_iterator_get_next( lccrt_oper_iterator_ptr i) +{ + lccrt_oper_ptr r = i->next; + + return (r); +} /* lccrt_oper_iterator_get_next */ + +/** + * Перейти к следующей операции. + */ +lccrt_oper_ptr +lccrt_oper_iterator_shift( lccrt_oper_iterator_ptr i) +{ + lccrt_oper_ptr r = 0; + + if ( i->is_forward ) + { + r = i->next; + i->prev = r; + i->next = r ? r->next : 0; + } else + { + r = i->prev; + i->next = r; + i->prev = r ? r->prev : 0; + } + + return (r); +} /* lccrt_oper_iterator_shift */ + +/** + * Инициализация прямого итератора {o,o->next}. + */ +lccrt_oper_iterator_ptr +lccrt_oper_iterator_init( lccrt_oper_iterator_ptr i, lccrt_o_ptr o) +{ + lccrt_check_type_init( i, lccrt_oper_iterator_t); + i->ctx = 0; + lccrt_oper_iterator_set( i, o); + + return (i); +} /* lccrt_oper_iterator_init */ + +/** + * Проверка типа аргумента операции на тип-переменная по имени операции. + */ +int +lccrt_oper_name_is_arg_var( lccrt_oper_name_t oper_name, int arg_num) +{ + int r = 0; + + lccrt_assert( arg_num >= 0); + if ( (oper_name == LCCRT_OPER_INVOKEFUNC) + || (oper_name == LCCRT_OPER_INVOKEPROC) ) + { + r = !((1 <= arg_num) && (arg_num <= 2)); + + } else if ( (oper_name == LCCRT_OPER_BRANCH) ) + { + r = 0; + + } else if ( (oper_name == LCCRT_OPER_BRANCHIF) ) + { + r = (arg_num == 0); + + } else if ( (oper_name == LCCRT_OPER_SWITCH) ) + { + if ( (arg_num == 0) + || ((arg_num > 0) + && (((arg_num + 1) % 2) == 0)) ) + { + r = 1; + } + } else + { + r = 1; + } + + return (r); +} /* lccrt_oper_name_is_arg_var */ + +/** + * Проверка типа аргумента операции на тип-операция по имени операции. + */ +int +lccrt_oper_name_is_arg_oper( lccrt_oper_name_t oper_name, int arg_num) +{ + int r = !lccrt_oper_name_is_arg_var( oper_name, arg_num); + + return (r); +} /* lccrt_oper_name_is_arg_oper */ + +/** + * Получить значение поле. + */ +lccrt_function_ptr +lccrt_oper_get_function( lccrt_oper_ptr oper) +{ + lccrt_function_ptr r = oper->func; + + lccrt_check_type_assert( oper, lccrt_oper_t); + + return (r); +} /* lccrt_oper_get_function */ + +/** + * Получить результат операции. + */ +lccrt_var_ptr +lccrt_oper_get_res( lccrt_oper_ptr o) +{ + lccrt_var_ptr r = o->res; + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_get_res */ + +/** + * Изменить результат операции. + */ +void +lccrt_oper_set_res( lccrt_oper_ptr o, lccrt_var_ptr res) +{ + lccrt_check_type_assert( o, lccrt_oper_t); + lccrt_assert( !res || lccrt_oper_name_is_res( o->name)); + lccrt_var_set_num_defs( res, lccrt_var_get_num_defs( res) + 1); + lccrt_var_set_num_defs( o->res, lccrt_var_get_num_defs( o->res) - 1); + o->res = res; + + return; +} /* lccrt_oper_set_res */ + +/** + * Получить результат операции. + */ +lccrt_type_ptr +lccrt_oper_get_res_type( lccrt_oper_ptr o) +{ + lccrt_type_ptr r = o->res ? lccrt_var_get_type( o->res) : 0; + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_get_res_type */ + +/** + * Получить значение поле. + */ +lccrt_oper_name_t +lccrt_oper_get_name( lccrt_oper_ptr oper) +{ + lccrt_oper_name_t r; + + lccrt_check_type_assert( oper, lccrt_oper_t); + r = oper->name; + + return (r); +} /* lccrt_oper_get_name */ + +/** + * Получить значение поле. + */ +int +lccrt_oper_get_num_args( lccrt_oper_ptr oper) +{ + int r; + + lccrt_check_type_assert( oper, lccrt_oper_t); + r = oper->num_args; + lccrt_assert( r >= 0); + if ( !(lccrt_oper_is_call( oper) + || lccrt_oper_is_invoke( oper)) ) + { + lccrt_assert( oper->num_sysargs == 0); + } + + return (r); +} /* lccrt_oper_get_num_args */ + +/** + * Получить значение поле. + */ +int +lccrt_oper_get_num_sysargs( lccrt_oper_ptr oper) +{ + int r; + + lccrt_check_type_assert( oper, lccrt_oper_t); + r = oper->num_sysargs; + lccrt_assert( r >= 0); + if ( lccrt_oper_is_call( oper) ) + { + lccrt_assert( r < oper->num_args); + + } else if ( lccrt_oper_is_invoke( oper) ) + { + lccrt_assert( r + 2 < oper->num_args); + } else + { + lccrt_assert( r == 0); + } + + return (r); +} /* lccrt_oper_get_num_sysargs */ + +/** + * Получить тип результата операции. + */ +lccrt_type_ptr +lccrt_oper_get_type( lccrt_oper_ptr op) +{ + lccrt_type_ptr r; + + lccrt_check_type_assert( op, lccrt_oper_t); + if ( op->res ) + { + r = lccrt_var_get_type( op->res); + } else + { + r = lccrt_type_make_void( op->func->module); + } + + return (r); +} /* lccrt_oper_get_type */ + +/** + * Получить значение поле. + */ +lccrt_oper_ptr +lccrt_oper_get_arg_oper( lccrt_oper_ptr oper, int arg_num) +{ + lccrt_oper_ptr r; + + lccrt_assert( lccrt_oper_name_is_arg_oper( lccrt_oper_get_name( oper), arg_num)); + lccrt_assert( (0 <= arg_num) && (arg_num < oper->num_args)); + r = oper->args[arg_num].op; + + return (r); +} /* lccrt_oper_get_arg_oper */ + +/** + * Получить аргумент операции. + */ +lccrt_var_ptr +lccrt_oper_get_arg_var( lccrt_oper_ptr op, int arg_num) +{ + lccrt_var_ptr r; + + lccrt_check_type_assert( op, lccrt_oper_t); + lccrt_assert( (0 <= arg_num) && (arg_num < op->num_args)); + lccrt_assert( lccrt_oper_name_is_arg_var( op->name, arg_num)); + r = op->args[arg_num].v; + + return (r); +} /* lccrt_oper_get_arg_var */ + +/** + * Установить аргумент операции. + */ +void +lccrt_oper_set_arg_var( lccrt_oper_ptr op, int arg_num, lccrt_var_ptr arg) +{ + lccrt_var_ptr r; + + lccrt_check_type_assert( op, lccrt_oper_t); + lccrt_assert( (0 <= arg_num) && (arg_num < op->num_args)); + lccrt_assert( lccrt_oper_name_is_arg_var( op->name, arg_num)); + op->args[arg_num].v = arg; + + return; +} /* lccrt_oper_set_arg_var */ + +/** + * Установить аргумент операции. + */ +void +lccrt_oper_set_arg_oper( lccrt_oper_ptr op, int arg_num, lccrt_oper_ptr arg) +{ + lccrt_var_ptr r; + + lccrt_check_type_assert( op, lccrt_oper_t); + lccrt_assert( (0 <= arg_num) && (arg_num < op->num_args)); + lccrt_assert( lccrt_oper_name_is_arg_oper( op->name, arg_num)); + op->args[arg_num].op = arg; + + return; +} /* lccrt_oper_set_arg_oper */ + +/** + * Получить результат операции. + */ +const char * +lccrt_oper_get_label( lccrt_oper_ptr o) +{ + const char *r = o->label; + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_get_label */ + +/** + * Получить значение поле. + */ +lccrt_oper_ptr +lccrt_oper_get_prev( lccrt_oper_ptr oper) +{ + lccrt_oper_ptr r; + + lccrt_check_type_assert( oper, lccrt_oper_t); + r = oper->prev; + + return (r); +} /* lccrt_oper_get_prev */ + +/** + * Получить значение поле. + */ +lccrt_oper_ptr +lccrt_oper_get_next( lccrt_oper_ptr oper) +{ + lccrt_oper_ptr r; + + lccrt_check_type_assert( oper, lccrt_oper_t); + r = oper->next; + + return (r); +} /* lccrt_oper_get_next */ + +/** + * Получить значение поле. + */ +int +lccrt_oper_is_atomic( lccrt_oper_ptr oper) +{ + int r; + + lccrt_check_type_assert( oper, lccrt_oper_t); + r = oper->is_atomic; + + return (r); +} /* lccrt_oper_is_atomic */ + +/** + * Установка флага. + */ +void +lccrt_oper_set_atomic( lccrt_o_ptr o, int is_atomic) +{ + lccrt_check_type_assert( o, lccrt_oper_t); + o->is_atomic = is_atomic; + + return; +} /* lccrt_oper_set_atomic */ + +/** + * Получить значение поле. + */ +int +lccrt_oper_is_volatile( lccrt_oper_ptr oper) +{ + int r; + + lccrt_check_type_assert( oper, lccrt_oper_t); + r = oper->is_volatile; + + return (r); +} /* lccrt_oper_is_volatile */ + +/** + * Установка флага. + */ +void +lccrt_oper_set_volatile( lccrt_o_ptr o, int is_volatile) +{ + lccrt_check_type_assert( o, lccrt_oper_t); + o->is_volatile = is_volatile; + + return; +} /* lccrt_oper_set_volatile */ + +/** + * Получить значение поле. + */ +int +lccrt_oper_is_cleanup( lccrt_oper_ptr oper) +{ + int r; + + lccrt_check_type_assert( oper, lccrt_oper_t); + r = oper->is_cleanup; + + return (r); +} /* lccrt_oper_is_cleanup */ + +/** + * Установка флага. + */ +void +lccrt_oper_set_cleanup( lccrt_o_ptr o, int is_cleanup) +{ + lccrt_check_type_assert( o, lccrt_oper_t); + o->is_cleanup = is_cleanup; + + return; +} /* lccrt_oper_set_cleanup */ + +/** + * Проверка операции на переход (BRANCH, BRANCHIF). + */ +int +lccrt_oper_is_branch( lccrt_oper_ptr o) +{ + int r = (o->name == LCCRT_OPER_BRANCH) || (o->name == LCCRT_OPER_BRANCHIF); + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_is_branch */ + +/** + * Проверка операции на SWITCH. + */ +int +lccrt_oper_is_switch( lccrt_oper_ptr o) +{ + int r = (o->name == LCCRT_OPER_SWITCH); + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_is_switch */ + +/** + * Проверка операции на вызов (CALLPROC, CALLFUNC). + */ +int +lccrt_oper_is_call( lccrt_oper_ptr o) +{ + int r = (o->name == LCCRT_OPER_CALLPROC) || (o->name == LCCRT_OPER_CALLFUNC); + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_is_call */ + +/** + * Проверка операции на вызов (INVOKEPROC, INVOKEFUNC). + */ +int +lccrt_oper_is_invoke( lccrt_oper_ptr o) +{ + int r = (o->name == LCCRT_OPER_INVOKEPROC) || (o->name == LCCRT_OPER_INVOKEFUNC); + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_is_invoke */ + +/** + * Проверка операции на LANDINGPAD. + */ +int +lccrt_oper_is_landingpad( lccrt_oper_ptr o) +{ + int r = (o->name == LCCRT_OPER_LANDINGPAD); + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_is_landingpad */ + +/** + * Получить поле. + */ +lccrt_oper_ptr +lccrt_oper_invoke_get_normal( lccrt_oper_ptr o) +{ + lccrt_oper_ptr r = o->args[1].op; + + lccrt_check_type_assert( o, lccrt_oper_t); + lccrt_assert( lccrt_oper_is_invoke( o)); + + return (r); +} /* lccrt_oper_invoke_get_normal */ + +/** + * Установить поле. + */ +void +lccrt_oper_invoke_set_normal( lccrt_oper_ptr o, lccrt_oper_ptr normal) +{ + lccrt_check_type_assert( o, lccrt_oper_t); + lccrt_assert( lccrt_oper_is_invoke( o)); + o->args[1].op = normal; + + return; +} /* lccrt_oper_invoke_set_normal */ + +/** + * Получить поле. + */ +lccrt_oper_ptr +lccrt_oper_invoke_get_unwind( lccrt_oper_ptr o) +{ + lccrt_oper_ptr r = o->args[2].op; + + lccrt_check_type_assert( o, lccrt_oper_t); + lccrt_assert( lccrt_oper_is_invoke( o)); + + return (r); +} /* lccrt_oper_invoke_get_unwind */ + +/** + * Установить поле. + */ +void +lccrt_oper_invoke_set_unwind( lccrt_oper_ptr o, lccrt_oper_ptr unwind) +{ + lccrt_check_type_assert( o, lccrt_oper_t); + lccrt_assert( lccrt_oper_is_invoke( o)); + o->args[2].op = unwind; + + return; +} /* lccrt_oper_invoke_set_unwind */ + +/** + * Проверка операции на метку. + */ +int +lccrt_oper_is_label( lccrt_oper_ptr o) +{ + int r = (o->name == LCCRT_OPER_LABEL); + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_is_label */ + +/** + * Проверка операции на метку. + */ +int +lccrt_oper_is_ret( lccrt_oper_ptr o) +{ + int r = (o->name == LCCRT_OPER_RET); + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_is_ret */ + +/** + * Проверка операции на метку. + */ +int +lccrt_oper_is_retval( lccrt_oper_ptr o) +{ + int r = (o->name == LCCRT_OPER_RETVAL); + + lccrt_check_type_assert( o, lccrt_oper_t); + + return (r); +} /* lccrt_oper_is_ret */ + +/** + * Создание ir-операции. + */ +lccrt_oper_ptr +lccrt_oper_new( lccrt_f_ptr f, int name, lccrt_t_ptr type, int num_args, + lccrt_arg_t *args, int num_sysargs, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + int k; + lccrt_context_ptr ctx = f->ctx; + lccrt_oper_ptr prev = 0; + lccrt_oper_ptr next = 0; + lccrt_o_ptr o = lccrt_ctx_malloc( ctx, lccrt_oper_t); + + i = i ? i : &(f->cur); + lccrt_check_type_assert( i, lccrt_oper_iterator_t); + + if ( lccrt_oper_name_is_res( name) ) + { + if ( ra ) + { + lccrt_check_type_assert( ra, lccrt_var_t); + //lccrt_assert( !type || (type == ra->type)); + lccrt_assert( !lccrt_var_is_constarg( ra)); + } else + { + ra = lccrt_var_new_local( f, type, 0); + } + } + + for ( k = 0; k < num_args; ++k ) + { + if ( lccrt_oper_name_is_arg_var( name, k) ) + { + lccrt_check_type_assert( args[k].v, lccrt_var_t); + } else + { + lccrt_check_type_assert( args[k].op, lccrt_oper_t); + } + } + + lccrt_check_type_assert( f, lccrt_function_t); + lccrt_check_type_assert( type, lccrt_type_t); + memset( o, 0, sizeof( o[0])); + lccrt_check_type_init( o, lccrt_oper_t); + o->func = (lccrt_function_ptr)f; + o->name = name; + o->num_args = num_args; + o->num_sysargs = num_sysargs; + o->args = lccrt_ctx_memdup( ctx, args, num_args * sizeof( lccrt_arg_t)); + o->res = ra; + if ( ra ) lccrt_var_set_num_defs( ra, lccrt_var_get_num_defs( ra) + 1); + f->opers_num++; + o->ident_num = f->opers_num; + + prev = i->prev; + next = i->next; + if ( !f->start ) + { + f->start = o; + lccrt_assert( !prev && !next); + } else + { + lccrt_assert( prev || next); + } + + /* Вставляем операцию в цепочку операций. */ + o->prev = prev; + o->next = next; + if ( prev ) + { + prev->next = o; + } + + if ( next ) + { + next->prev = o; + } + + /* Обновление итератора. */ + i->last = o; + if ( i->is_forward ) + { + i->prev = o; + } else + { + i->next = o; + } + + if ( lccrt_context_get_verbose_ir( ctx) ) + { + lccrt_oper_print( o, 1); + fflush( stdout); + } + + return (o); +} /* lccrt_oper_new */ + +/** + * Удаление ir-операции. + */ +void +lccrt_oper_delete( lccrt_oper_ptr o) +{ + lccrt_function_ptr f = o->func; + lccrt_context_ptr ctx = f->ctx; + lccrt_oper_ptr next = o->next; + lccrt_oper_ptr prev = o->prev; + + lccrt_check_type_assert( o, lccrt_oper_t); + if ( o->res ) + { + lccrt_var_set_num_defs( o->res, lccrt_var_get_num_defs( o->res) - 1); + } + + lccrt_ctx_free( ctx, o->label); + lccrt_ctx_free( ctx, o->args); + if ( next ) + { + next->prev = prev; + } + + if ( prev ) + { + prev->next = next; + } + + o->einfo = lccrt_einfo_link_delete_chain( o->einfo); + + lccrt_check_type_done( o, lccrt_oper_t); + lccrt_ctx_free( ctx, o); + + return; +} /* lccrt_oper_delete */ + +/** + * Создание ir-операции с одним аргументом. + */ +static lccrt_o_ptr +lccrt_oper_new_arg1( lccrt_f_ptr f, lccrt_oper_name_t name, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + lccrt_arg_t args[1] = {{.v = a}}; + + r = lccrt_oper_new( f, name, t, 1, args, 0, ra, i); + + return (r); +} /* lccrt_oper_new_arg1 */ + +/** + * Создание ir-операции с двумя аргументами. + */ +static lccrt_o_ptr +lccrt_oper_new_arg2( lccrt_f_ptr f, lccrt_oper_name_t name, lccrt_v_ptr a, lccrt_v_ptr b, + lccrt_t_ptr t, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + lccrt_arg_t args[2] = {{.v = a}, {.v = b}}; + + r = lccrt_oper_new( f, name, t, 2, args, 0, ra, i); + + return (r); +} /* lccrt_oper_new_arg2 */ + +/** + * Создание арифметической ir-операции с 1 аргументом. + */ +static lccrt_o_ptr +lccrt_oper_new_arith1( lccrt_f_ptr f, lccrt_oper_name_t name, lccrt_v_ptr a, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new_arg1( f, name, a, a->type, ra, i); + + return (r); +} /* lccrt_oper_new_arith1 */ + +/** + * Создание арифметической ir-операции с 2 аргументами. + */ +static lccrt_o_ptr +lccrt_oper_new_arith2( lccrt_f_ptr f, lccrt_oper_name_t name, lccrt_v_ptr a, lccrt_v_ptr b, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new_arg2( f, name, a, b, a->type, ra, i); + + return (r); +} /* lccrt_oper_new_arith2 */ + +/** + * Создание ir-метки. + */ +lccrt_o_ptr +lccrt_oper_new_label( lccrt_f_ptr f, const char *name, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + lccrt_context_ptr ctx = f->ctx; + char *lname = lccrt_function_name_new_local( f, name); + + r = lccrt_oper_new( f, LCCRT_OPER_LABEL, 0, 0, 0, 0, 0, i); + r->label = lccrt_ctx_copy_str( ctx, lname); + lccrt_ctx_free( ctx, lname); + + return (r); +} /* lccrt_oper_new_label */ + +/** + * Создание ir-навигации по типу. + */ +lccrt_o_ptr +lccrt_oper_new_elemptr( lccrt_f_ptr f, int num_args, lccrt_v_ptr *args, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + int k; + lccrt_arg_t a[num_args]; + lccrt_o_ptr r; + lccrt_type_ptr res_type = args[0]->type; + + lccrt_assert( num_args >= 2); + lccrt_check_type_assert( args[0], lccrt_var_t); + lccrt_check_type_assert( args[1], lccrt_var_t); + lccrt_check_type_assert( res_type, lccrt_type_t); + lccrt_assert( res_type->type_name == LCCRT_TYPE_PTR); + res_type = lccrt_type_get_parent( res_type); + + a[0].v = args[0]; + a[1].v = args[1]; + for ( k = 2; k < num_args; ++k ) + { + lccrt_type_ptr rt = res_type; + + lccrt_check_type_assert( args[k], lccrt_var_t); + a[k].v = args[k]; + while ( (rt->type_name == LCCRT_TYPE_NAME) ) + { + rt = rt->parent; + } + + if ( (rt->type_name == LCCRT_TYPE_STRUCT) ) + { + lccrt_assert( lccrt_var_is_constarg_int( args[k])); + lccrt_assert( lccrt_var_get_constarg_int64( args[k]) >= 0); + lccrt_assert( lccrt_var_get_constarg_int64( args[k]) < rt->num_args); + rt = rt->args[lccrt_var_get_constarg_int64( args[k])]; + lccrt_assert( rt->type_name == LCCRT_TYPE_FIELD); + + } else if ( (rt->type_name == LCCRT_TYPE_ARRAY) + || (rt->type_name == LCCRT_TYPE_VECTOR) ) + { + } else + { + lccrt_assert( 0); + } + + res_type = lccrt_type_get_parent( rt); + } + + res_type = lccrt_type_make_ptr_type( res_type); + r = lccrt_oper_new( f, LCCRT_OPER_ELEMPTR, res_type, num_args, a, 0, ra, i); + + return (r); +} /* lccrt_oper_new_elemptr */ + +/** + * Создание ir-доступа к элементу данных. + */ +static lccrt_o_ptr +lccrt_oper_new_elemdata( lccrt_f_ptr f, lccrt_oper_name_t name, int num_args, lccrt_v_ptr *args, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + int k; + lccrt_arg_t a[num_args]; + lccrt_o_ptr r; + lccrt_type_ptr res_type = 0; + lccrt_type_ptr cur_type = args[0]->type; + int is_read = (name == LCCRT_OPER_ELEMREAD); + + lccrt_assert( is_read || (name == LCCRT_OPER_ELEMWRITE)); + lccrt_check_type_assert( args[0], lccrt_var_t); + lccrt_check_type_assert( cur_type, lccrt_type_t); + if ( is_read ) + { + lccrt_assert( num_args >= 2); + } else + { + lccrt_assert( num_args >= 3); + lccrt_check_type_assert( args[1], lccrt_var_t); + } + + a[0].v = args[0]; + if ( !is_read ) + { + a[1].v = args[1]; + } + + //cur_type = lccrt_type_get_parent( cur_type); + for ( k = 1 + !is_read; k < num_args; ++k ) + { + lccrt_check_type_assert( args[k], lccrt_var_t); + a[k].v = args[k]; + while ( (cur_type->type_name == LCCRT_TYPE_NAME) ) + { + cur_type = cur_type->parent; + } + + if ( (cur_type->type_name == LCCRT_TYPE_STRUCT) ) + { + lccrt_assert( lccrt_var_is_constarg_int( args[k])); + lccrt_assert( lccrt_var_get_constarg_int64( args[k]) >= 0); + lccrt_assert( lccrt_var_get_constarg_int64( args[k]) < cur_type->num_args); + cur_type = cur_type->args[lccrt_var_get_constarg_int64( args[k])]; + lccrt_assert( cur_type->type_name == LCCRT_TYPE_FIELD); + + } else if ( (cur_type->type_name == LCCRT_TYPE_ARRAY) + || (cur_type->type_name == LCCRT_TYPE_VECTOR) ) + { + } else + { + lccrt_assert( 0); + } + + cur_type = lccrt_type_get_parent( cur_type); + } + + if ( is_read ) + { + res_type = cur_type; + } + + r = lccrt_oper_new( f, name, res_type, num_args, a, 0, ra, i); + + return (r); +} /* lccrt_oper_new_elemdata */ + +/** + * Создание ir-чтения элемента данных. + */ +lccrt_o_ptr +lccrt_oper_new_elemread( lccrt_f_ptr f, int num_args, lccrt_v_ptr *args, lccrt_v_ptr ra, + lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + + r = lccrt_oper_new_elemdata( f, LCCRT_OPER_ELEMREAD, num_args, args, ra, i); + + return (r); +} /* lccrt_oper_new_elemread */ + +/** + * Создание ir-записи элемента данных. + */ +lccrt_o_ptr +lccrt_oper_new_elemwrite( lccrt_f_ptr f, int num_args, lccrt_v_ptr *args, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + + r = lccrt_oper_new_elemdata( f, LCCRT_OPER_ELEMWRITE, num_args, args, 0, i); + + return (r); +} /* lccrt_oper_new_elemwrite */ + +/** + * Создание ir-вызова. + */ +lccrt_o_ptr +lccrt_oper_new_call( lccrt_f_ptr f, lccrt_t_ptr sig, int num_args, + lccrt_v_ptr *call_args, int num_sysargs, lccrt_v_ptr *sysargs, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + lccrt_oper_name_t name; + lccrt_arg_t args[num_args + num_sysargs]; + int k; + lccrt_type_ptr res_type = lccrt_type_get_parent( sig); + + lccrt_assert( num_args >= 1); + lccrt_assert( sig->type_name == LCCRT_TYPE_FUNC); + if ( (res_type->type_name == LCCRT_TYPE_VOID) ) + { + name = LCCRT_OPER_CALLPROC; + } else + { + name = LCCRT_OPER_CALLFUNC; + } + + for ( k = 0; k < num_args; ++k ) + { + args[k].v = call_args[k]; + } + + for ( k = 0; k < num_sysargs; ++k ) + { + args[num_args + k].v = sysargs[k]; + } + + r = lccrt_oper_new( f, name, res_type, num_args + num_sysargs, args, num_sysargs, ra, i); + + return (r); +} /* lccrt_oper_new_call */ + +/** + * Создание ir-вызова. + */ +lccrt_o_ptr +lccrt_oper_new_invoke( lccrt_f_ptr f, lccrt_t_ptr sig, int num_args, + lccrt_v_ptr *call_args, int num_sysargs, lccrt_v_ptr *sysargs, + lccrt_o_ptr normal, lccrt_o_ptr unwind, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + lccrt_oper_name_t name; + lccrt_arg_t args[num_args + 2 + num_sysargs]; + int k; + lccrt_type_ptr res_type = lccrt_type_get_parent( sig); + + lccrt_assert( num_args >= 1); + lccrt_assert( sig->type_name == LCCRT_TYPE_FUNC); + if ( (res_type->type_name == LCCRT_TYPE_VOID) ) + { + name = LCCRT_OPER_INVOKEPROC; + } else + { + name = LCCRT_OPER_INVOKEFUNC; + } + + args[0].v = call_args[0]; + args[1].op = normal; + args[2].op = unwind; + for ( k = 1; k < num_args; ++k ) + { + args[k + 2].v = call_args[k]; + } + + for ( k = 0; k < num_sysargs; ++k ) + { + args[num_args + 2 + k].v = sysargs[k]; + } + + r = lccrt_oper_new( f, name, res_type, num_args + 2, args, num_sysargs, ra, i); + + return (r); +} /* lccrt_oper_new_invoke */ + +/** + * Создание landingpad'а. + */ +lccrt_o_ptr +lccrt_oper_new_landingpad( lccrt_f_ptr f, int num_args, lccrt_v_ptr *args, + lccrt_t_ptr t, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + int k; + lccrt_o_ptr r; + lccrt_arg_t oargs[num_args]; + + for ( k = 0; k < num_args; ++k ) + { + oargs[k].v = args[k]; + } + + r = lccrt_oper_new( f, LCCRT_OPER_LANDINGPAD, t, num_args, oargs, 0, ra, i); + + return (r); +} /* lccrt_oper_new_landingpad */ + +/** + * Создание безусловного ir-перехода. + */ +lccrt_o_ptr +lccrt_oper_new_branch( lccrt_f_ptr f, lccrt_o_ptr dst, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + lccrt_arg_t args[1] = {{.op = dst}}; + + r = lccrt_oper_new( f, LCCRT_OPER_BRANCH, 0, 1, args, 0, 0, i); + + return (r); +} /* lccrt_oper_new_branch */ + +/** + * Создание условного ir-перехода. + */ +lccrt_o_ptr +lccrt_oper_new_branchif( lccrt_f_ptr f, lccrt_v_ptr p, lccrt_o_ptr dt, lccrt_o_ptr df, + lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + lccrt_arg_t args[3] = {{.v = p}, {.op = dt}, {.op = df}}; + + r = lccrt_oper_new( f, LCCRT_OPER_BRANCHIF, 0, 3, args, 0, 0, i); + + return (r); +} /* lccrt_oper_new_branchif */ + +/** + * Создание ir-переключателя. + */ +lccrt_o_ptr +lccrt_oper_new_switch( lccrt_f_ptr f, lccrt_v_ptr p, int num_alts, + lccrt_switch_alts_t *alts, lccrt_oi_ptr i) +{ + int k; + lccrt_o_ptr r; + lccrt_arg_t args[1 + 2*num_alts]; + + //lccrt_assert( lccrt_var_is_local( p) || lccrt_var_is_const( p)); + args[0].v = p; + for ( k = 0; k < num_alts; k++ ) + { + lccrt_varinit_ptr val = alts[k].val; + + args[1 + 2*k + 0].v = val ? lccrt_var_new_constarg( f->module, val->type, val) : 0; + args[1 + 2*k + 1].op = alts[k].dst; + } + + r = lccrt_oper_new( f, LCCRT_OPER_SWITCH, 0, 1 + 2*num_alts, args, 0, 0, i); + + return (r); +} /* lccrt_oper_new_switch */ + +/** + * Создание ir-сравнения. + */ +lccrt_o_ptr +lccrt_oper_new_cmp( lccrt_f_ptr f, lccrt_vi_ptr n, lccrt_v_ptr a, lccrt_v_ptr b, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + lccrt_var_ptr vn = lccrt_var_new_constarg( f->module, n->type, n); + lccrt_arg_t args[3] = {{.v = vn}, {.v = a}, {.v = b}}; + lccrt_type_ptr bool_type = lccrt_type_make_bool( f->module); + + r = lccrt_oper_new( f, LCCRT_OPER_CMP, bool_type, 3, args, 0, ra, i); + + return (r); +} /* lccrt_oper_new_cmp */ + +/** + * Создание ir-возврата из процедуры. + */ +lccrt_o_ptr +lccrt_oper_new_ret( lccrt_f_ptr f, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new( f, LCCRT_OPER_RET, 0, 0, 0, 0, 0, i); + + return (r); +} /* lccrt_oper_new_ret */ + +/** + * Создание ir-возврата значения из процедуры. + */ +lccrt_o_ptr +lccrt_oper_new_retval( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new_arg1( f, LCCRT_OPER_RETVAL, a, 0, 0, i); + + return (r); +} /* lccrt_oper_new_retval */ + +/** + * Создание ir-операция для работы с переменным числом параметров. + */ +lccrt_o_ptr +lccrt_oper_new_va_arg( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new_arg1( f, LCCRT_OPER_VA_ARG, a, t, ra, i); + + return (r); +} /* lccrt_oper_new_va_arg */ + +/** + * Создание ir-операция для работы с переменным числом параметров. + */ +lccrt_o_ptr +lccrt_oper_new_alloca( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + + r = lccrt_oper_new_arg1( f, LCCRT_OPER_ALLOCA, a, lccrt_type_make_pchar( f->module), ra, i); + + return (r); +} /* lccrt_oper_new_alloca */ + +/** + * Создание ir-операции копирования значения. + */ +lccrt_o_ptr +lccrt_oper_new_move( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new_arg1( f, LCCRT_OPER_MOVE, a, a->type, ra, i); + + return (r); +} /* lccrt_oper_new_move */ + +/** + * Создание ir-операции взятия адреса. + */ +lccrt_o_ptr +lccrt_oper_new_varptr( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + + r = lccrt_oper_new_arg1( f, LCCRT_OPER_VARPTR, a, lccrt_type_make_ptr_type( a->type), ra, i); + + return (r); +} /* lccrt_oper_new_varptr */ + +/** + * Создание ir-операции чтения по адресу. + */ +lccrt_o_ptr +lccrt_oper_new_load( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + + r = lccrt_oper_new_arg1( f, LCCRT_OPER_LOAD, a, lccrt_type_get_parent( a->type), ra, i); + + return (r); +} /* lccrt_oper_new_load */ + +/** + * Создание ir-операции записи по адресу. + */ +lccrt_o_ptr +lccrt_oper_new_store( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + + r = lccrt_oper_new_arg2( f, LCCRT_OPER_STORE, a, b, 0, 0, i); + + return (r); +} /* lccrt_oper_new_store */ + +/** + * Создание ir-операции преобразования типа. + */ +lccrt_o_ptr +lccrt_oper_new_sext( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + + r = lccrt_oper_new_arg1( f, LCCRT_OPER_SEXT, a, t, ra, i); + + return (r); +} /* lccrt_oper_new_sext */ + +/** + * Создание ir-операции преобразования типа. + */ +lccrt_o_ptr +lccrt_oper_new_zext( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + + r = lccrt_oper_new_arg1( f, LCCRT_OPER_ZEXT, a, t, ra, i); + + return (r); +} /* lccrt_oper_new_zext */ + +/** + * Создание ir-операции преобразования типа. + */ +lccrt_o_ptr +lccrt_oper_new_trunc( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + + r = lccrt_oper_new_arg1( f, LCCRT_OPER_TRUNC, a, t, ra, i); + + return (r); +} /* lccrt_oper_new_trunc */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_fptofp( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new_arg1( f, LCCRT_OPER_FPTOFP, a, t, ra, i); + + return (r); +} /* lccrt_oper_new_fptofp */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_fptoui( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new_arg1( f, LCCRT_OPER_FPTOUI, a, t, ra, i); + + return (r); +} /* lccrt_oper_new_fptoui */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_fptosi( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new_arg1( f, LCCRT_OPER_FPTOSI, a, t, ra, i); + + return (r); +} /* lccrt_oper_new_fptosi */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_uitofp( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new_arg1( f, LCCRT_OPER_UITOFP, a, t, ra, i); + + return (r); +} /* lccrt_oper_new_uitofp */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_sitofp( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r = lccrt_oper_new_arg1( f, LCCRT_OPER_SITOFP, a, t, ra, i); + + return (r); +} /* lccrt_oper_new_sitofp */ + +/** + * Создание ir-операции преобразования типа. + */ +lccrt_o_ptr +lccrt_oper_new_bitcast( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_t_ptr t, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + + r = lccrt_oper_new_arg1( f, LCCRT_OPER_BITCAST, a, t, ra, i); + + return (r); +} /* lccrt_oper_new_bitcast */ + +/** + * Создание ir-операции выбора значения из пары (b,c). + */ +lccrt_o_ptr +lccrt_oper_new_select( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr c, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + lccrt_arg_t args[3] = {{.v = a}, {.v = b}, {.v = c}}; + + r = lccrt_oper_new( f, LCCRT_OPER_SELECT, b->type, 3, args, 0, ra, i); + + return (r); +} /* lccrt_oper_new_select */ + +/** + * Создание ir-операции идентичной __builtin_shuffle. + */ +lccrt_o_ptr +lccrt_oper_new_shuffle( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr c, + lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_o_ptr r; + lccrt_arg_t args[3] = {{.v = a}, {.v = b}, {.v = c}}; + + r = lccrt_oper_new( f, LCCRT_OPER_SHUFFLE, a->type, 3, args, 0, ra, i); + + return (r); +} /* lccrt_oper_new_shuffle */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_add( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_ADD, a, b, ra, i); + + return (r); +} /* lccrt_oper_new_add */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_sub( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_SUB, a, b, ra, i); + + return (r); +} /* lccrt_oper_new_sub */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_mul( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_MUL, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_mul */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_udiv( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_UDIV, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_udiv */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_sdiv( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_SDIV, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_sdiv */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_umod( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_UMOD, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_umod */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_smod( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_SMOD, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_smod */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_shl( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_SHL, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_shl */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_shr( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_SHR, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_shr */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_sar( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_SAR, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_sar */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_and( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_AND, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_and */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_or( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_OR, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_or */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_xor( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_XOR, a, b, ra, i); + + return (r); +} /* lccrt_oper_new_xor */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_fneg( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith1( f, LCCRT_OPER_FNEG, a, ra, i); + + return (r); +} /* lccrt_oper_new_fneg */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_fadd( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_FADD, a, b, ra, i); + + return (r); +} /* lccrt_oper_new_fadd */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_fsub( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr i) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_FSUB, a, b, ra, i); + + return (r); +} /* lccrt_oper_new_fsub */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_fmul( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_FMUL, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_fmul */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_fdiv( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_FDIV, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_fdiv */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_fmod( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_v_ptr b, lccrt_v_ptr ra, lccrt_oi_ptr pi) +{ + lccrt_oper_ptr r = lccrt_oper_new_arith2( f, LCCRT_OPER_FMOD, a, b, ra, pi); + + return (r); +} /* lccrt_oper_new_fmod */ + +/** + * Создание операции. + */ +lccrt_oper_ptr +lccrt_oper_new_return( lccrt_f_ptr f, lccrt_v_ptr a, lccrt_oi_ptr i) +{ + lccrt_oper_ptr r; + + if ( a ) + { + r = lccrt_oper_new_arg1( f, LCCRT_OPER_RETVAL, a, 0, 0, i); + } else + { + r = lccrt_oper_new( f, LCCRT_OPER_RET, 0, 0, 0, 0, 0, i); + } + + return (r); +} /* lccrt_oper_new_return */ + +/** + * Добавить в операцию новые мета-данные, либо изменить значение старых. + */ +void +lccrt_oper_set_einfo( lccrt_oper_ptr oper, lccrt_einfo_category_t ecat, lccrt_eir_t value) +{ + lccrt_function_ptr f = lccrt_oper_get_function( oper); + lccrt_module_ptr m = lccrt_function_get_module( f); + + lccrt_check_type_assert( oper, lccrt_oper_t); + lccrt_assert( !lccrt_einfo_is_scalar( value)); + oper->einfo = lccrt_einfo_link_push_value( m, oper->einfo, ecat, value); + + return; +} /* lccrt_oper_set_einfo */ + +/** + * Получить значение мета-данных с заданным именем или 0, если таких данных нет. + */ +lccrt_einfo_reference_t +lccrt_oper_get_einfo( lccrt_oper_ptr oper, lccrt_einfo_category_t ecat) +{ + lccrt_einfo_link_ptr unit = lccrt_einfo_link_find( oper->einfo, ecat); + lccrt_einfo_reference_t r = lccrt_einfo_link_get_value( unit); + + lccrt_check_type_assert( oper, lccrt_oper_t); + + return (r); +} /* lccrt_oper_get_einfo */ + +/** + * Получить по названию операции-сравнения строковое представление. + */ +static const char * +lccrt_opername_get_cmp_str( int cmp_name) +{ + const char *r = 0; + + switch ( cmp_name ) + { + case LCCRT_CMP_EQ: r = "EQ"; break; + case LCCRT_CMP_NE: r = "NE"; break; + case LCCRT_CMP_LT_I: r = "LT_I"; break; + case LCCRT_CMP_LE_I: r = "LE_I"; break; + case LCCRT_CMP_GT_I: r = "GT_I"; break; + case LCCRT_CMP_GE_I: r = "GE_I"; break; + case LCCRT_CMP_LT_U: r = "LT_U"; break; + case LCCRT_CMP_LE_U: r = "LE_U"; break; + case LCCRT_CMP_GT_U: r = "GT_U"; break; + case LCCRT_CMP_GE_U: r = "GE_U"; break; + case LCCRT_CMP_FO: r = "FO"; break; + case LCCRT_CMP_EQ_FO: r = "EQ_FO"; break; + case LCCRT_CMP_NE_FO: r = "NE_FO"; break; + case LCCRT_CMP_LT_FO: r = "LT_FO"; break; + case LCCRT_CMP_LE_FO: r = "LE_FO"; break; + case LCCRT_CMP_GT_FO: r = "GT_FO"; break; + case LCCRT_CMP_GE_FO: r = "GE_FO"; break; + case LCCRT_CMP_FU: r = "FU"; break; + case LCCRT_CMP_EQ_FU: r = "EQ_FU"; break; + case LCCRT_CMP_NE_FU: r = "NE_FU"; break; + case LCCRT_CMP_LT_FU: r = "LT_FU"; break; + case LCCRT_CMP_LE_FU: r = "LE_FU"; break; + case LCCRT_CMP_GT_FU: r = "GT_FU"; break; + case LCCRT_CMP_GE_FU: r = "GE_FU"; break; + default: lccrt_assert( 0); break; + } + + return (r); +} /* lccrt_opername_get_cmp_str */ + +/** + * Вывести в стандартный поток вывод текстовое представление операции. + */ +int +lccrt_oper_snprint( lccrt_oper_ptr op, int is_ln, char *s, int l) +{ + int k; + int j = 0; + int cmp_id = -1; + const char *cmp_name = 0; + + lccrt_check_type_assert( op, lccrt_oper_t); + lccrt_snprintf( s, l, j, " "); + if ( lccrt_oper_name_is_res( op->name) ) + { + lccrt_snprintf( s, l, j, " %s = ", op->res->name); + } else + { + if ( (op->name != LCCRT_OPER_LABEL) ) + { + lccrt_snprintf( s, l, j, " "); + } + } + + switch ( op->name ) + { + case LCCRT_OPER_LABEL: + lccrt_snprintf( s, l, j, "%s:", op->label); + break; + case LCCRT_OPER_BRANCH: + lccrt_snprintf( s, l, j, "branch %s", op->args[0].op->label); + break; + case LCCRT_OPER_BRANCHIF: + lccrt_snprintf( s, l, j, "branchif "); + lccrt_snprintf( s, l, j, "(predicate:%s, true:%s, false:%s)", op->args[0].v->name, + op->args[1].op->label, op->args[2].op->label); + break; + case LCCRT_OPER_SWITCH: + lccrt_snprintf( s, l, j, "switch (value:%s", op->args[0].v->name); + for ( k = 1; k < op->num_args; k += 2 ) + { + lccrt_var_ptr va = op->args[k].v; + + if ( va ) + { + if ( (lccrt_var_get_bytesize( va) == 16) ) + { + struct { uint64_t hi; uint64_t lo; } w; + memcpy( &w, lccrt_varinit_get_str( lccrt_var_get_init_value( va)), 16); + if ( w.hi ) + { + lccrt_snprintf( s, l, j, ", alt:0x%jx%016jx", w.hi, w.lo); + } else + { + lccrt_snprintf( s, l, j, ", alt:%ju", w.lo); + } + } else + { + lccrt_snprintf( s, l, j, ", alt:%jd", lccrt_var_get_constarg_int64( va)); + } + } else + { + lccrt_snprintf( s, l, j, ", alt:default"); + } + lccrt_snprintf( s, l, j, " dst:%s", op->args[k+1].op->label); + } + lccrt_snprintf( s, l, j, ")"); + break; + case LCCRT_OPER_RET: + lccrt_snprintf( s, l, j, "ret"); + break; + case LCCRT_OPER_RETVAL: + lccrt_snprintf( s, l, j, "retval %s", op->args[0].v->name); + break; + case LCCRT_OPER_LANDINGPAD: + lccrt_snprintf( s, l, j, "landingpad("); + for ( k = 0; k < op->num_args; ++k ) + { + lccrt_snprintf( s, l, j, "%s%s", (k > 0) ? "," : "", op->args[k].v->name); + } + lccrt_snprintf( s, l, j, ")"); + break; + case LCCRT_OPER_INVOKEPROC: + case LCCRT_OPER_INVOKEFUNC: + lccrt_snprintf( s, l, j, "invoke %s(", op->args[0].v->name); + for ( k = 3; k < op->num_args; ++k ) + { + lccrt_snprintf( s, l, j, "%s%s", (k > 3) ? "," : "", op->args[k].v->name); + } + lccrt_snprintf( s, l, j, ") normal:%s exception:%s", op->args[1].op->label, op->args[2].op->label); + break; + case LCCRT_OPER_CALLPROC: + case LCCRT_OPER_CALLFUNC: + lccrt_snprintf( s, l, j, "call %s(", op->args[0].v->name); + for ( k = 1; k < op->num_args; ++k ) + { + lccrt_snprintf( s, l, j, "%s%s", (k > 1) ? "," : "", op->args[k].v->name); + } + lccrt_snprintf( s, l, j, ")"); + break; + case LCCRT_OPER_MOVE: + lccrt_snprintf( s, l, j, "%s", op->args[0].v->name); + break; + case LCCRT_OPER_VARPTR: + lccrt_snprintf( s, l, j, "varptr(%s)", op->args[0].v->name); + break; + case LCCRT_OPER_LOAD: + lccrt_snprintf( s, l, j, "load(%s)", op->args[0].v->name); + break; + case LCCRT_OPER_STORE: + lccrt_snprintf( s, l, j, "store(%s) -> %s", op->args[1].v->name, op->args[0].v->name); + break; +#if 0 + case LCCRT_OPER_CONV: + lccrt_snprintf( s, l, j, "conv(%s to ", op->args[0].v->name); + lccrt_type_print( lccrt_oper_get_type( op), 0); + lccrt_snprintf( s, l, j, ")"); + break; +#endif + case LCCRT_OPER_SEXT: + case LCCRT_OPER_ZEXT: + case LCCRT_OPER_TRUNC: + case LCCRT_OPER_FPTOFP: + case LCCRT_OPER_FPTOUI: + case LCCRT_OPER_FPTOSI: + case LCCRT_OPER_UITOFP: + case LCCRT_OPER_SITOFP: + case LCCRT_OPER_BITCAST: + lccrt_snprintf( s, l, j, "%s(%s to ", + lccrt_oper_get_name_str( op), op->args[0].v->name); + lccrt_type_print( lccrt_oper_get_type( op), 0); + lccrt_snprintf( s, l, j, ")"); + break; + case LCCRT_OPER_SELECT: + lccrt_snprintf( s, l, j, "select(%s,%s,%s)", op->args[0].v->name, op->args[1].v->name, + op->args[2].v->name); + break; + case LCCRT_OPER_CMP: + cmp_id = lccrt_var_get_constarg_int64( op->args[0].v); + cmp_name = lccrt_opername_get_cmp_str( cmp_id); + lccrt_snprintf( s, l, j, "cmp(%s,%s,%s)", cmp_name, + op->args[1].v->name, op->args[2].v->name); + break; + case LCCRT_OPER_FNEG: + lccrt_snprintf( s, l, j, "fneg %s", op->args[0].v->name); + break; + case LCCRT_OPER_ADD: + case LCCRT_OPER_FADD: + lccrt_snprintf( s, l, j, "%s + %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_SUB: + case LCCRT_OPER_FSUB: + lccrt_snprintf( s, l, j, "%s - %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_MUL: + case LCCRT_OPER_FMUL: + lccrt_snprintf( s, l, j, "%s * %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_UDIV: + lccrt_snprintf( s, l, j, "%s /.u %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_SDIV: + lccrt_snprintf( s, l, j, "%s /.s %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_UMOD: + lccrt_snprintf( s, l, j, "%s %%.u %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_SMOD: + lccrt_snprintf( s, l, j, "%s %%.s %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_FDIV: + lccrt_snprintf( s, l, j, "%s / %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_FMOD: + lccrt_snprintf( s, l, j, "%s %% %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_SHL: + lccrt_snprintf( s, l, j, "%s << %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_SHR: + lccrt_snprintf( s, l, j, "%s >>.u %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_SAR: + lccrt_snprintf( s, l, j, "%s >>.s %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_AND: + lccrt_snprintf( s, l, j, "%s & %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_OR: + lccrt_snprintf( s, l, j, "%s | %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_XOR: + lccrt_snprintf( s, l, j, "%s ^ %s", op->args[0].v->name, op->args[1].v->name); + break; + case LCCRT_OPER_SHUFFLE: + lccrt_snprintf( s, l, j, "shuffle( %s, %s, %s)", + op->args[0].v->name, op->args[1].v->name, op->args[2].v->name); + break; + case LCCRT_OPER_ELEMPTR: + case LCCRT_OPER_ELEMREAD: + case LCCRT_OPER_ELEMWRITE: + if ( (op->name == LCCRT_OPER_ELEMWRITE) ) + { + lccrt_snprintf( s, l, j, "elemwrite("); + } else + { + lccrt_snprintf( s, l, j, "elem%s(", (op->name == LCCRT_OPER_ELEMPTR) ? "ptr" : "read"); + } + for ( k = 0; k < op->num_args; k++ ) + { + lccrt_snprintf( s, l, j, "%s%s", (k > 0) ? "," : "", op->args[k].v->name); + } + lccrt_snprintf( s, l, j, ")"); + break; + case LCCRT_OPER_VA_ARG: + lccrt_snprintf( s, l, j, "va_arg(%s,", op->args[0].v->name); + lccrt_type_print( lccrt_oper_get_type( op), 0); + lccrt_snprintf( s, l, j, ")"); + break; + case LCCRT_OPER_ALLOCA: + lccrt_snprintf( s, l, j, "alloca(%s)", op->args[0].v->name); + break; + default: + lccrt_assert( 0); + break; + } + + if ( is_ln ) + { + lccrt_snprintf( s, l, j, "\n"); + } + + s[l-1] = 0; + + j = (j < l) ? j : (l - 1); + + return (j); +} /* lccrt_oper_snprint */ + +/** + * Вывести в стандартный поток вывод текстовое представление операции. + */ +int +lccrt_oper_print( lccrt_oper_ptr op, int is_ln) +{ + char s[4096]; + int r = lccrt_oper_snprint( op, is_ln, s, 4096); + + printf( "%s", s); + + return (r); +} /* lccrt_oper_print */ + +/** + * Получение имени для строкового представления операции. + * (Должно быть согласовано с lccrt_oper_get_name_str). + */ +int +lccrt_oper_get_str_opername( const char *str) +{ + lccrt_oper_name_t r = LCCRT_OPER_LAST; + + if ( lccrt_str_eq( str, "lbl") ) { r = LCCRT_OPER_LABEL; } + else if ( lccrt_str_eq( str, "br") ) { r = LCCRT_OPER_BRANCH; } + else if ( lccrt_str_eq( str, "brif") ) { r = LCCRT_OPER_BRANCHIF; } + else if ( lccrt_str_eq( str, "switch") ) { r = LCCRT_OPER_SWITCH; } + else if ( lccrt_str_eq( str, "ret") ) { r = LCCRT_OPER_RET; } + else if ( lccrt_str_eq( str, "retval") ) { r = LCCRT_OPER_RETVAL; } + else if ( lccrt_str_eq( str, "invokeproc") ) { r = LCCRT_OPER_INVOKEPROC; } + else if ( lccrt_str_eq( str, "invokefunc") ) { r = LCCRT_OPER_INVOKEFUNC; } + else if ( lccrt_str_eq( str, "landingpad") ) { r = LCCRT_OPER_LANDINGPAD; } + else if ( lccrt_str_eq( str, "callproc") ) { r = LCCRT_OPER_CALLPROC; } + else if ( lccrt_str_eq( str, "callfunc") ) { r = LCCRT_OPER_CALLFUNC; } + else if ( lccrt_str_eq( str, "move") ) { r = LCCRT_OPER_MOVE; } + else if ( lccrt_str_eq( str, "ptr") ) { r = LCCRT_OPER_VARPTR; } + else if ( lccrt_str_eq( str, "ld") ) { r = LCCRT_OPER_LOAD; } + else if ( lccrt_str_eq( str, "st") ) { r = LCCRT_OPER_STORE; } + //else if ( lccrt_str_eq( str, "conv") ) { r = LCCRT_OPER_CONV; } + else if ( lccrt_str_eq( str, "sext") ) { r = LCCRT_OPER_SEXT; } + else if ( lccrt_str_eq( str, "zext") ) { r = LCCRT_OPER_ZEXT; } + else if ( lccrt_str_eq( str, "trunc") ) { r = LCCRT_OPER_TRUNC; } + else if ( lccrt_str_eq( str, "fptofp") ) { r = LCCRT_OPER_FPTOFP; } + else if ( lccrt_str_eq( str, "fptoui") ) { r = LCCRT_OPER_FPTOUI; } + else if ( lccrt_str_eq( str, "fptosi") ) { r = LCCRT_OPER_FPTOSI; } + else if ( lccrt_str_eq( str, "uitofp") ) { r = LCCRT_OPER_UITOFP; } + else if ( lccrt_str_eq( str, "sitofp") ) { r = LCCRT_OPER_SITOFP; } + else if ( lccrt_str_eq( str, "bitcast") ) { r = LCCRT_OPER_BITCAST; } + else if ( lccrt_str_eq( str, "select") ) { r = LCCRT_OPER_SELECT; } + else if ( lccrt_str_eq( str, "cmp") ) { r = LCCRT_OPER_CMP; } + else if ( lccrt_str_eq( str, "fneg") ) { r = LCCRT_OPER_FNEG; } + else if ( lccrt_str_eq( str, "+") ) { r = LCCRT_OPER_ADD; } + else if ( lccrt_str_eq( str, "+") ) { r = LCCRT_OPER_FADD; } + else if ( lccrt_str_eq( str, "-") ) { r = LCCRT_OPER_SUB; } + else if ( lccrt_str_eq( str, "-") ) { r = LCCRT_OPER_FSUB; } + else if ( lccrt_str_eq( str, "*") ) { r = LCCRT_OPER_MUL; } + else if ( lccrt_str_eq( str, "*") ) { r = LCCRT_OPER_FMUL; } + else if ( lccrt_str_eq( str, "/u") ) { r = LCCRT_OPER_UDIV; } + else if ( lccrt_str_eq( str, "/") ) { r = LCCRT_OPER_SDIV; } + else if ( lccrt_str_eq( str, "/") ) { r = LCCRT_OPER_FDIV; } + else if ( lccrt_str_eq( str, "<<") ) { r = LCCRT_OPER_SHL; } + else if ( lccrt_str_eq( str, ">>u") ) { r = LCCRT_OPER_SHR; } + else if ( lccrt_str_eq( str, ">>") ) { r = LCCRT_OPER_SAR; } + else if ( lccrt_str_eq( str, "&") ) { r = LCCRT_OPER_AND; } + else if ( lccrt_str_eq( str, "|") ) { r = LCCRT_OPER_OR; } + else if ( lccrt_str_eq( str, "^") ) { r = LCCRT_OPER_XOR; } + else if ( lccrt_str_eq( str, "elemptr") ) { r = LCCRT_OPER_ELEMPTR; } + else if ( lccrt_str_eq( str, "elemread") ) { r = LCCRT_OPER_ELEMREAD; } + else if ( lccrt_str_eq( str, "elemwrite") ) { r = LCCRT_OPER_ELEMWRITE; } + else if ( lccrt_str_eq( str, "va_arg") ) { r = LCCRT_OPER_VA_ARG; } + else if ( lccrt_str_eq( str, "alloca") ) { r = LCCRT_OPER_ALLOCA; } + else { r = LCCRT_OPER_LAST; } + + return (r); +} /* lccrt_oper_get_str_opername */ + +/** + * Получение для операции строкового представления имени. + * (Должно быть согласовано с lccrt_oper_get_str_opername). + */ +const char * +lccrt_oper_get_name_str( lccrt_oper_ptr op) +{ + const char *r = 0; + + lccrt_check_type_assert( op, lccrt_oper_t); + + switch ( op->name ) + { + case LCCRT_OPER_LABEL: r = "lbl"; break; + case LCCRT_OPER_BRANCH: r = "br"; break; + case LCCRT_OPER_BRANCHIF: r = "brif"; break; + case LCCRT_OPER_SWITCH: r = "switch"; break; + case LCCRT_OPER_RET: r = "ret"; break; + case LCCRT_OPER_RETVAL: r = "retval"; break; + case LCCRT_OPER_INVOKEPROC: r = "invokeproc"; break; + case LCCRT_OPER_INVOKEFUNC: r = "invokefunc"; break; + case LCCRT_OPER_CALLPROC: r = "callproc"; break; + case LCCRT_OPER_CALLFUNC: r = "callfunc"; break; + case LCCRT_OPER_LANDINGPAD: r = "landingpad"; break; + case LCCRT_OPER_MOVE: r = "move"; break; + case LCCRT_OPER_VARPTR: r = "ptr"; break; + case LCCRT_OPER_LOAD: r = "ld"; break; + case LCCRT_OPER_STORE: r = "st"; break; + //case LCCRT_OPER_CONV: r = "conv"; break; + case LCCRT_OPER_SEXT: r = "sext"; break; + case LCCRT_OPER_ZEXT: r = "zext"; break; + case LCCRT_OPER_TRUNC: r = "trunc"; break; + case LCCRT_OPER_FPTOFP: r = "fptofp"; break; + case LCCRT_OPER_FPTOUI: r = "fptoui"; break; + case LCCRT_OPER_FPTOSI: r = "fptosi"; break; + case LCCRT_OPER_UITOFP: r = "uitofp"; break; + case LCCRT_OPER_SITOFP: r = "sitofp"; break; + case LCCRT_OPER_BITCAST: r = "bitcast"; break; + case LCCRT_OPER_SELECT: r = "select"; break; + case LCCRT_OPER_CMP: r = "cmp"; break; + case LCCRT_OPER_FNEG: r = "fneg"; break; + case LCCRT_OPER_ADD: r = "+"; break; + case LCCRT_OPER_FADD: r = "+"; break; + case LCCRT_OPER_SUB: r = "-"; break; + case LCCRT_OPER_FSUB: r = "-"; break; + case LCCRT_OPER_MUL: r = "*"; break; + case LCCRT_OPER_FMUL: r = "*"; break; + case LCCRT_OPER_UDIV: r = "/u"; break; + case LCCRT_OPER_SDIV: r = "/"; break; + case LCCRT_OPER_FDIV: r = "/"; break; + case LCCRT_OPER_SHL: r = "<<"; break; + case LCCRT_OPER_SHR: r = ">>u"; break; + case LCCRT_OPER_SAR: r = ">>"; break; + case LCCRT_OPER_AND: r = "&"; break; + case LCCRT_OPER_OR: r = "|"; break; + case LCCRT_OPER_XOR: r = "^"; break; + case LCCRT_OPER_ELEMPTR: r = "elemptr"; break; + case LCCRT_OPER_ELEMREAD: r = "elemread"; break; + case LCCRT_OPER_ELEMWRITE: r = "elemwrite"; break; + case LCCRT_OPER_VA_ARG: r = "va_arg"; break; + case LCCRT_OPER_ALLOCA: r = "alloca"; break; + default: lccrt_assert( 0); break; + } + + return (r); +} /* lccrt_oper_get_name_str */ + +/** + * Печать инструкций. + */ +void +lccrt_oper_print_opers( lccrt_o_ptr op1, lccrt_o_ptr op2) +{ + lccrt_oper_ptr op; + + for ( op = op1; (op && op != op2); op = op->next ) + { + lccrt_oper_print( op, 1); + } + + return; +} /* lccrt_oper_print_opers */ diff --git a/lib/irv/lccrt_type.c b/lib/irv/lccrt_type.c new file mode 100644 index 0000000..e262226 --- /dev/null +++ b/lib/irv/lccrt_type.c @@ -0,0 +1,1405 @@ +/** + * 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_type.c - реализация пользовательский интерфейс (динамической) компиляции. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lccrt_real.h" + +#define LCCRT_TYPE_ALIGN( size, align) ((align)*(((size) + (align) - 1) / (align))) + +/** + * Оценка количества десятичных цифр для неотрицательного значения. + */ +#define lccrt_calc_num_digits( v) \ +( ((v) & 0xff000000) \ + ? 12 \ + : (((v) & 0x00ff0000) \ + ? 9 \ + : (((v) & 0x0000ff00) ? 6 : 3)) ) + +#define lccrt_is_char_shielded( c) \ +( (c == '@') \ + || (c == '.') \ + || (c == '\\') ) + +/** + * Вычислить длину строки вместе с символами экранирования. + */ +static int +lccrt_calc_name_shield( const char *name) +{ + int k; + int r = 0; + + for ( k = 0; name[k]; ++k, ++r ) + { + char c = name[k]; + + if ( (c == '\\') + && name[k+1] + && lccrt_is_char_shielded( name[k+1]) ) + { + ++k; + ++r; + + } else if ( lccrt_is_char_shielded( c) ) + { + ++r; + } + } + + return (r); +} /* lccrt_calc_name_shield */ + +/** + * Печать строки с экранированием. + */ +static int +lccrt_print_shield_name( char *dst, int max_len, const char *name) +{ + int k; + int r = 0; + + for ( k = 0; name[k] && (r <= max_len); ++k, ++r ) + { + char c = name[k]; + + if ( (c == '\\') + && name[k+1] + && lccrt_is_char_shielded( name[k+1]) ) + { + dst[r+0] = c; + c = name[k+1]; + ++k; + ++r; + + } else if ( lccrt_is_char_shielded( c) ) + { + dst[r] = '\\'; + ++r; + } + + dst[r] = c; + } + + dst[r] = 0; + + return (r); +} /* lccrt_print_shield_name */ + +/** + * Создание нового типа. + */ +lccrt_type_ptr +lccrt_type_make( lccrt_module_ptr m, int type_name, lccrt_type_ptr parent, + lccrt_type_ptr *args, uint64_t num_args, lccrt_var_ptr vnum, + const char *sym_name, int is_sign, uint64_t bytealign, + uint64_t bytesize, uint64_t byteshift, + int bitsubshift, int bitsubsize, int is_union) +{ + int k; + lccrt_type_ptr r; + lccrt_he_ptr e; + lccrt_context_ptr ctx = m->ctx; + + lccrt_check_type_assert( m, lccrt_module_t); + lccrt_check_type_assert( parent, lccrt_type_t); + if ( (type_name != LCCRT_TYPE_ARRAY) + && (type_name != LCCRT_TYPE_VECTOR) ) + { + for ( k = 0; k < num_args; ++k ) + { + lccrt_check_type_assert( args[k], lccrt_type_t); + } + } + + if ( parent + && (parent->type_name == LCCRT_TYPE_NAME) ) + { + if ( (type_name != LCCRT_TYPE_PTR) + && (type_name != LCCRT_TYPE_FIELD) + && (type_name != LCCRT_TYPE_FUNC) + && (type_name != LCCRT_TYPE_ARRAY) ) + { + lccrt_assert( 0); + return (0); + } + } + +#if 0 + if ( (type_name == LCCRT_TYPE_PTR) ) + { + if ( (parent->type_name == LCCRT_TYPE_STRUCT) ) + { + lccrt_assert( 0); + return (0); + } + } +#endif + + e = lccrt_hash_find( m->types, (uintptr_t)sym_name); + r = e ? (lccrt_type_ptr)lccrt_hash_get( e) : 0; + if ( r ) + { + lccrt_check_type_assert( r, lccrt_type_t); + lccrt_assert( r->type_name == type_name); + lccrt_assert( r->num_args == num_args); + lccrt_assert( r->vnum == vnum); + lccrt_assert( strcmp( r->sym_name, sym_name) == 0); + lccrt_assert( r->is_sign == is_sign); + if ( (r->type_name == LCCRT_TYPE_NAME) ) + { + if ( parent ) + { + lccrt_assert( (r->bytealign == parent->bytealign) || (r->bytealign == 0)); + lccrt_assert( (r->bytesize == parent->bytesize) || (r->bytesize == 0)); + } else + { + lccrt_assert( (r->bytealign == bytealign) || (bytealign == 0)); + lccrt_assert( (r->bytesize == bytesize) || (bytesize == 0)); + } + } else + { + lccrt_assert( r->bytealign == bytealign); + lccrt_assert( r->bytesize == bytesize); + } + lccrt_assert( r->byteshift == byteshift); + if ( (r->type_name == LCCRT_TYPE_FIELD) + && (r->parent->type_name == LCCRT_TYPE_INT) ) + { + lccrt_assert( r->bitsubshift == bitsubshift); + lccrt_assert( r->bitsubsize == bitsubsize); + } + + lccrt_assert( r->is_union == is_union); + for ( k = 0; k < num_args; ++k ) + { + if ( (type_name != LCCRT_TYPE_ARRAY) + && (type_name != LCCRT_TYPE_VECTOR) ) + { + lccrt_assert( (args[0] == 0) || (r->args[k] == args[k])); + } + } + + if ( (r->type_name == LCCRT_TYPE_NAME) ) + { + if ( r->parent ) + { + lccrt_assert( (parent == 0) || r->parent == (lccrt_type_ptr)parent); + } else + { + r->parent = parent; + } + } else + { + lccrt_assert( (parent == 0) || (r->parent == parent)); + } + } else + { + int is_fld = (type_name == LCCRT_TYPE_FIELD); + int is_fld_int = is_fld && (!parent || (parent->type_name == LCCRT_TYPE_INT)); + + r = lccrt_ctx_malloc( ctx, lccrt_type_t); + memset( r, 0, sizeof( r[0])); + lccrt_check_type_init( r, lccrt_type_t); + lccrt_ilist_unit_init( &(r->types_unit)); + + r->m = m; + m->type_max++; + r->ident_num = m->type_max; + r->type_name = type_name; + r->parent = (lccrt_type_ptr)parent; + r->num_args = num_args; + r->vnum = vnum; + r->sym_name = sym_name ? lccrt_ctx_copy_str( ctx, sym_name) : 0; + r->is_sign = is_sign; + r->bytealign = bytealign; + r->bytesize = bytesize; + r->byteshift = byteshift; + r->bitsubshift = is_fld_int ? bitsubshift : 0; + r->bitsubsize = is_fld_int ? bitsubsize : 0; + r->is_union = is_union; + r->args = 0; + if ( num_args + && (type_name != LCCRT_TYPE_ARRAY) + && (type_name != LCCRT_TYPE_VECTOR) ) + { + r->args = lccrt_ctx_mallocn( ctx, lccrt_type_ptr, num_args); + memcpy( r->args, args, num_args * sizeof( args[0])); + } + + e = lccrt_hash_push( m->types, (uintptr_t)r->sym_name, 0); + lccrt_hash_set( e, (uintptr_t)r); + lccrt_ilist_head_insert( &(m->types_head), types_unit, r); + } + + return (r); +} /* lccrt_type_make */ + +/** + * Удаление типа данных. + */ +void +lccrt_type_delete( lccrt_type_ptr type) +{ + lccrt_module_ptr m = type->m; + lccrt_context_ptr ctx = m->ctx; + + lccrt_check_type_assert( type, lccrt_type_t); + lccrt_ilist_head_remove( &(m->types_head), types_unit, type); + lccrt_ctx_free( ctx, type->sym_name); + lccrt_ctx_free( ctx, type->args); + lccrt_check_type_done( type, lccrt_type_t); + lccrt_ctx_free( ctx, type); + + return; +} /* lccrt_type_delete */ + +/** + * Получить значение поля. + */ +lccrt_type_ptr +lccrt_type_get_next_type( lccrt_type_ptr type) +{ + lccrt_type_ptr r; + + lccrt_check_type_assert( type, lccrt_type_t); + r = type->types_unit.next; + + return (r); +} /* lccrt_type_get_next_type */ + +/** + * Создание нового простого типа. + */ +lccrt_type_ptr +lccrt_type_make_simple( lccrt_m_ptr m, lccrt_type_name_t name, const char *sym_name, + int is_sign, uint64_t bytealign, uint64_t bytesize) +{ + lccrt_type_ptr r; + + r = lccrt_type_make( m, name, 0, 0, 0, 0, sym_name, is_sign, bytealign, bytesize, 0, 0, 0, 0); + + return (r); +} /* lccrt_type_make_simple */ + +/** + * Получить целый тип. + */ +lccrt_type_ptr +lccrt_type_make_int( lccrt_module_ptr m, uint64_t bytesize, int is_sign) +{ + lccrt_type_ptr r; + lccrt_type_name_int_t k = lccrt_type_int_find_by_bitsize( 8*bytesize); + + lccrt_check_type_assert( m, lccrt_module_t); + r = m->types_std.int_types[is_sign][k]; + + return (r); +} /* lccrt_type_make_int */ + +/** + * Создание типа указателя (с частичным "хешированием"). + */ +lccrt_type_ptr +lccrt_type_make_ptr_type( lccrt_type_ptr type) +{ + lccrt_type_ptr r = 0; + char s[64]; + lccrt_module_ptr m = type->m; + + lccrt_check_type_assert( type, lccrt_type_t); + lccrt_check_type_assert( m, lccrt_module_t); + if ( m->types_std.ptr_byte + && (type == lccrt_type_make_int( m, 1, 0)) ) + { + r = m->types_std.ptr_byte; + + } else if ( m->types_std.ptr_char + && (type == lccrt_type_make_int( m, 1, 1)) ) + { + r = m->types_std.ptr_char; + + } else if ( m->types_std.ptr_intptr + && (type == m->types_std.intptr) ) + { + r = m->types_std.ptr_intptr; + } else + { + uint64_t bytesize = m->types_std.ptr_bytesize; + + snprintf( s, 64, "*$%ju", type->ident_num); + r = lccrt_type_make( m, LCCRT_TYPE_PTR, type, 0, 0, 0, s, 0, + bytesize, bytesize, 0, 0, 0, 0); + } + + return (r); +} /* lccrt_type_make_ptr_type */ + +/** + * Получить void-тип. + */ +lccrt_type_ptr +lccrt_type_make_void( lccrt_module_ptr m) +{ + lccrt_type_ptr r = m->types_std.void_type; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_type_make_void */ + +/** + * Получить bool-тип. + */ +lccrt_type_ptr +lccrt_type_make_bool( lccrt_module_ptr m) +{ + lccrt_type_ptr r = m->types_std.bool_type; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_type_make_bool */ + +/** + * Получить тип-многоточие. + */ +lccrt_type_ptr +lccrt_type_make_ellipsis( lccrt_module_ptr m) +{ + lccrt_type_ptr r = m->types_std.ellipsis; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_type_make_ellipsis */ + +/** + * Получить плавающий тип. + */ +lccrt_type_ptr +lccrt_type_make_float( lccrt_module_ptr m, uint64_t bytesize) +{ + lccrt_type_name_float_t k = lccrt_type_float_find_by_bitsize( 8*bytesize); + lccrt_type_ptr r = m->types_std.float_types[k]; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_type_make_float */ + +/** + * Получить целый тип. + */ +lccrt_type_ptr +lccrt_type_make_intptr( lccrt_module_ptr m) +{ + lccrt_type_ptr r = m->types_std.intptr; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_type_make_intptr */ + +/** + * Получить указатель на целый тип. + */ +lccrt_type_ptr +lccrt_type_make_pintptr( lccrt_module_ptr m) +{ + lccrt_type_ptr r = m->types_std.ptr_intptr; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_type_make_pintptr */ + +/** + * Получить указатель на беззнаковый байт. + */ +lccrt_type_ptr +lccrt_type_make_pbyte( lccrt_module_ptr m) +{ + lccrt_type_ptr r = m->types_std.ptr_byte; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_type_make_pbyte */ + +/** + * Получить указатель на знаковый байт. + */ +lccrt_type_ptr +lccrt_type_make_pchar( lccrt_module_ptr m) +{ + lccrt_type_ptr r = m->types_std.ptr_char; + + lccrt_check_type_assert( m, lccrt_module_t); + + return (r); +} /* lccrt_type_make_pchar */ + +/** + * Получить указатель на void. + */ +lccrt_type_ptr +lccrt_type_make_pvoid( lccrt_module_ptr m) +{ + lccrt_type_ptr r = lccrt_type_make_ptr_type( m->types_std.void_type); + + return (r); +} /* lccrt_type_make_pvoid */ + +/** + * Получить тип - массив. + */ +lccrt_type_ptr +lccrt_type_make_array( lccrt_type_ptr elem, + uint64_t num_elems) +{ + lccrt_type_ptr r; + char s[64]; + lccrt_module_ptr m = elem->m; + uint64_t elem_bytesize = lccrt_type_get_bytesize( elem); + uint64_t elem_bytealign = lccrt_type_get_bytealign( elem); + uint64_t bytesize = num_elems * LCCRT_TYPE_ALIGN( elem_bytesize, elem_bytealign); + + lccrt_check_type_assert( elem, lccrt_type_t); + + snprintf( s, 64, "[%ju]$%ju", num_elems, elem->ident_num); + r = lccrt_type_make( m, LCCRT_TYPE_ARRAY, elem, 0, num_elems, 0, s, 0, elem_bytealign, + bytesize, 0, 0, 0, 0); + + return (r); +} /* lccrt_type_make_array */ + +/** + * Получить тип - вектор. + */ +lccrt_type_ptr +lccrt_type_make_vector( lccrt_type_ptr elem, uint64_t num_elems) +{ + lccrt_type_ptr r; + char s[64]; + lccrt_module_ptr m = elem->m; + uint64_t elem_bytesize = lccrt_type_get_bytesize( elem); + uint64_t elem_bytealign = lccrt_type_get_bytealign( elem); + uint64_t bytesize = num_elems * LCCRT_TYPE_ALIGN( elem_bytesize, elem_bytealign); + + lccrt_check_type_assert( elem, lccrt_type_t); + + snprintf( s, 64, "<%ju>$%ju", num_elems, elem->ident_num); + r = lccrt_type_make( m, LCCRT_TYPE_VECTOR, elem, 0, num_elems, 0, s, 0, elem_bytealign, + bytesize, 0, 0, 0, 0); + + return (r); +} /* lccrt_type_make_vector */ + +/** + * Получить тип - vla-массив. + */ +lccrt_type_ptr +lccrt_type_make_vla( lccrt_type_ptr elem, + lccrt_var_ptr vnum) +{ + lccrt_type_ptr r; + char s[64]; + lccrt_module_ptr m = elem->m; + uint64_t bytealign = lccrt_type_get_bytealign( elem); + + lccrt_check_type_assert( elem, lccrt_type_t); + + snprintf( s, 64, "[@%s]$%ju", vnum->name, elem->ident_num); + r = lccrt_type_make( m, LCCRT_TYPE_VLA_ARRAY, elem, 0, 0, vnum, s, + 0, bytealign, 0, 0, 0, 0, 0); + + return (r); +} /* lccrt_type_make_vla */ + +/** + * Получить тип - поле структуры. + */ +lccrt_type_ptr +lccrt_type_make_field( lccrt_type_ptr parent, + uint64_t bytealign, + uint64_t byteshift, + int bitsubshift, + int bitsubsize) +{ + lccrt_type_ptr r; + char s[64]; + lccrt_module_ptr m = parent->m; + + lccrt_check_type_assert( parent, lccrt_type_t); + + snprintf( s, 64, "$(%ju:%ju:%u:%u:%jd)", parent->ident_num, + byteshift, bitsubshift, bitsubsize, bytealign); + r = lccrt_type_make( m, LCCRT_TYPE_FIELD, parent, 0, 0, 0, s, 0, bytealign, + parent->bytesize, byteshift, bitsubshift, bitsubsize, 0); + + return (r); +} /* lccrt_type_make_field */ + +/** + * Получить тип - структура. + */ +lccrt_type_ptr +lccrt_type_make_struct( lccrt_module_ptr m, + uint64_t bytealign, + uint64_t bytesize, + int num_flds, + lccrt_type_ptr *flds, + int is_union) +{ + lccrt_type_ptr r; + char *s = 0; + int k; + int j = 0; + int len = 0; + + if ( (num_flds <= 1) ) + { + /* Не делаем различия между пустыми или состоящими из одного поля + структурами и объединениями. */ + is_union = 0; + } + + /* Делаем оценку на длину ключа. */ + for ( k = 0; k < num_flds; ++k ) + { + len += lccrt_calc_num_digits( flds[k]->ident_num) + 2; + } + + len += 2 + 128; + s = (char *)alloca( len); + + /* Вычисляем строковое представление ключа. */ + j += snprintf( s + j, len - j, is_union ? "<" : "{"); + for ( k = 0; k < num_flds; ++k ) + { + j += snprintf( s + j, len - j, "$%ju", flds[k]->ident_num); + } + + j += snprintf( s + j, len - j, is_union ? ">" : "}"); + j += snprintf( s + j, len - j, ":%ju:%ju", bytesize, bytealign); + + /* Создаем результирующий тип. */ + r = lccrt_type_make( m, LCCRT_TYPE_STRUCT, 0, flds, num_flds, 0, s, 0, bytealign, + bytesize, 0, 0, 0, is_union); + + return (r); +} /* lccrt_type_make_struct */ + +/** + * Получить тип - функция. + */ +lccrt_type_ptr +lccrt_type_make_func( lccrt_type_ptr rtype, + int num_args, + lccrt_type_ptr *args) +{ + lccrt_type_ptr r; + char *s = 0; + int k; + int j = 0; + int len = 0; + lccrt_module_ptr m = rtype->m; + + /* Делаем оценку на длину ключа. */ + for ( k = 0; k < num_args; ++k ) + { + len += lccrt_calc_num_digits( args[k]->ident_num); + } + + len += 2 + num_args + 1 + lccrt_calc_num_digits( rtype->ident_num); + s = (char *)alloca( len); + + /* Вычисляем строковое представление ключа. */ + j += snprintf( s + j, len - j, "$%ju(", rtype->ident_num); + for ( k = 0; k < num_args; ++k ) + { + j += snprintf( s + j, len - j, "$%ju", args[k]->ident_num); + } + + j += snprintf( s + j, len - j, ")"); + + /* Создаем результирующий тип. */ + r = lccrt_type_make( m, LCCRT_TYPE_FUNC, rtype, args, num_args, 0, s, + 0, 0, 0, 0, 0, 0, 0); + + return (r); +} /* lccrt_type_make_func */ + +/** + * Создать или реализовать именнованный тип. + */ +lccrt_type_ptr +lccrt_type_make_typename( lccrt_module_ptr m, + const char *name, + lccrt_type_ptr type) +{ + lccrt_type_ptr r = 0; + int len = 0; + char *s = 0; + int j = 0; + //uint64_t bytealign = type ? type->bytealign : 0; + //uint64_t bytesize = type ? type->bytesize : 0; + + len += 2; + len += lccrt_calc_num_digits( m->ident_num); + len += lccrt_calc_name_shield( name); + s = (char *)alloca( len + 1); + + j += snprintf( s + j, len - j, "@%ju.", m->ident_num); + j += lccrt_print_shield_name( s + j, len - j, name); + + //r = lccrt_type_make( m, LCCRT_TYPE_NAME, type, 0, 0, 0, s, 0, bytealign, bytesize, 0, 0, 0, 0); + r = lccrt_type_make( m, LCCRT_TYPE_NAME, type, 0, 0, 0, s, 0, 0, 0, 0, 0, 0, 0); + + return (r); +} /* lccrt_type_make_typename */ + +/** + * Импортирование типа. + */ +lccrt_type_ptr +lccrt_type_import( lccrt_module_ptr m, lccrt_t_ptr type, lccrt_hash_ptr types) +{ + lccrt_type_ptr r = type; + lccrt_he_ptr e = 0; + + if ( (m != lccrt_type_get_module( type)) ) + { + if ( types ) + { + e = lccrt_hash_find( types, (uintptr_t)type); + r = e ? (lccrt_type_ptr)lccrt_hash_get( e) : 0; + } + + if ( !r ) + { + int k; + lccrt_type_ptr p; + int num_args = type->num_args; + lccrt_type_ptr *args = 0; + + if ( lccrt_type_is_int( type) ) + { + r = lccrt_type_make_int( m, type->bytesize, type->is_sign); + + } else if ( lccrt_type_is_float( type) ) + { + r = lccrt_type_make_float( m, type->bytesize); + + } else if ( lccrt_type_is_bool( type) ) + { + r = lccrt_type_make_bool( m); + + } else if ( lccrt_type_is_ellipsis( type) ) + { + r = lccrt_type_make_ellipsis( m); + + } else if ( lccrt_type_is_void( type) ) + { + r = lccrt_type_make_void( m); + + } else if ( lccrt_type_is_pointer( type) ) + { + p = lccrt_type_get_parent( type); + r = lccrt_type_make_ptr_type( lccrt_type_import( m, p, types)); + + } else if ( lccrt_type_is_array( type) ) + { + p = lccrt_type_import( m, lccrt_type_get_parent( type), types); + r = lccrt_type_make_array( p, type->num_args); + + } else if ( lccrt_type_is_field( type) ) + { + p = lccrt_type_import( m, lccrt_type_get_parent( type), types); + r = lccrt_type_make_field( p, type->bytealign, type->byteshift, + type->bitsubshift, type->bitsubsize); + + } else if ( lccrt_type_is_struct( type) ) + { + args = lccrt_ctx_mallocn( m->ctx, lccrt_type_ptr, num_args); + for ( k = 0; k < num_args; ++k ) + { + args[k] = lccrt_type_import( m, type->args[k], types); + } + + r = lccrt_type_make_struct( m, type->bytealign, type->bytesize, num_args, args, type->is_union); + lccrt_ctx_free( m->ctx, args); + + } else if ( lccrt_type_is_function( type) ) + { + args = lccrt_ctx_mallocn( m->ctx, lccrt_type_ptr, num_args); + for ( k = 0; k < num_args; ++k ) + { + args[k] = lccrt_type_import( m, type->args[k], types); + } + + p = lccrt_type_import( m, lccrt_type_get_parent( type), types); + r = lccrt_type_make_func( p, num_args, args); + lccrt_ctx_free( m->ctx, args); + + } else if ( lccrt_type_is_typename( type) ) + { + const char *s = type->sym_name; + + lccrt_assert( s[0] == '@'); + lccrt_assert( isdigit( (int)s[1])); + lccrt_assert( (s[2] == '.') || (s[1] != '0')); + s = s + 2; + while ( isdigit( (int)s[0]) ) + { + ++s; + } + + lccrt_assert( s[0] == '.'); + r = lccrt_type_make_typename( m, s + 1, 0); + if ( types ) + { + e = lccrt_hash_push( types, (uintptr_t)type, 0); + lccrt_hash_set( e, (uintptr_t)r); + p = type->parent; + if ( p ) + { + //lccrt_type_set_parent( r, lccrt_type_import( m, p, types)); + } + } + } else + { + lccrt_assert( 0); + } + + if ( types + && !lccrt_type_is_typename( type) ) + { + e = lccrt_hash_push( types, (uintptr_t)type, 0); + lccrt_hash_set( e, (uintptr_t)r); + } + } + } + + return (r); +} /* lccrt_type_import */ + +/** + * Получить значение поля. + */ +lccrt_module_ptr +lccrt_type_get_module( lccrt_type_ptr type) +{ + lccrt_module_ptr r = type->m; + + lccrt_check_type_assert( type, lccrt_type_t); + + return (r); +} /* lccrt_type_get_module */ + +/** + * Установить значение поля. В обычной ситуации менять значение поля нельзя, т.к. + * значение данного поля влияет на уникальный (хеш-)идентификатор типа. + */ +void +lccrt_type_set_parent( lccrt_type_ptr type, lccrt_type_ptr parent) +{ + lccrt_check_type_assert( type, lccrt_type_t); + type->parent = parent; + + return; +} /* lccrt_type_set_parent */ + +/** + * Установить значение поля. В обычной ситуации менять значение поля нельзя, т.к. + * значение данного поля влияет на уникальный (хеш-)идентификатор типа. + */ +void +lccrt_type_set_arg( lccrt_type_ptr type, int arg_num, lccrt_type_ptr arg) +{ + lccrt_check_type_assert( type, lccrt_type_t); + lccrt_assert( type->args); + lccrt_assert( arg_num < type->num_args); + type->args[arg_num] = arg; + + return; +} /* lccrt_type_set_arg */ + +/** + * Получить значение поля. + */ +lccrt_type_ptr +lccrt_type_get_arg( lccrt_type_ptr type, int arg_num) +{ + lccrt_type_ptr r; + + lccrt_check_type_assert( type, lccrt_type_t); + lccrt_assert( (arg_num >= 0) && (arg_num < type->num_args)); + lccrt_assert( (type->type_name == LCCRT_TYPE_FUNC) || (type->type_name == LCCRT_TYPE_STRUCT)); + r = type->args[arg_num]; + + return (r); +} /* lccrt_type_get_arg */ + +/** + * Установить значение поля. + */ +void +lccrt_type_set_typename_bytesize( lccrt_type_ptr type, uint64_t bytesize) +{ + lccrt_assert( lccrt_type_is_typename( type)); + type->bytesize = bytesize; + + return; +} /* lccrt_type_set_typename_bytesize */ + +/** + * Установить значение поля. + */ +void +lccrt_type_set_typename_bytealign( lccrt_type_ptr type, uint64_t bytealign) +{ + lccrt_assert( lccrt_type_is_typename( type)); + type->bytealign = bytealign; + + return; +} /* lccrt_type_set_typename_bytealign */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_type_get_bitsubshift( lccrt_type_ptr type) +{ + uint64_t r; + + lccrt_check_type_assert( type, lccrt_type_t); + lccrt_assert( (type->type_name == LCCRT_TYPE_FIELD) || (type->bitsubshift == 0)); + r = type->bitsubshift; + + return (r); +} /* lccrt_type_get_bitsubshift */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_type_get_bitsubsize( lccrt_type_ptr type) +{ + uint64_t r; + + lccrt_check_type_assert( type, lccrt_type_t); + lccrt_assert( (type->type_name == LCCRT_TYPE_FIELD) || (type->bitsubshift == 0)); + r = type->bitsubsize; + + return (r); +} /* lccrt_type_get_bitsubsize */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_type_get_byteshift( lccrt_type_ptr type) +{ + uint64_t r; + + lccrt_check_type_assert( type, lccrt_type_t); + lccrt_assert( (type->type_name == LCCRT_TYPE_FIELD) || (type->byteshift == 0)); + r = type->byteshift; + + return (r); +} /* lccrt_type_get_byteshift */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_type_get_bytealign( lccrt_type_ptr type) +{ + uint64_t r; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( lccrt_type_is_typename( type) + && lccrt_type_get_parent( type) ) + { + r = lccrt_type_get_bytealign( lccrt_type_get_parent( type)); + } else + { + r = type->bytealign; + } + + return (r); +} /* lccrt_type_get_bytealign */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_type_get_bytesize( lccrt_type_ptr type) +{ + uint64_t r; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( lccrt_type_is_typename( type) + && lccrt_type_get_parent( type) ) + { + r = lccrt_type_get_bytesize( lccrt_type_get_parent( type)); + } else + { + r = type->bytesize; + } + + return (r); +} /* lccrt_type_get_bytesize */ + +/** + * Получить значение поля. + */ +lccrt_type_name_t +lccrt_type_get_name( lccrt_type_ptr type) +{ + lccrt_type_name_t r; + + lccrt_check_type_assert( type, lccrt_type_t); + r = type->type_name; + + return (r); +} /* lccrt_type_get_name */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_type_get_num_args( lccrt_type_ptr type) +{ + uint64_t r; + + lccrt_check_type_assert( type, lccrt_type_t); + r = type->num_args; + if ( (type->type_name == LCCRT_TYPE_FUNC) + || (type->type_name == LCCRT_TYPE_ARRAY) + || (type->type_name == LCCRT_TYPE_VECTOR) + || (type->type_name == LCCRT_TYPE_STRUCT) ) + { + lccrt_assert( r >= 0); + } else + { + lccrt_assert( r == 0); + } + + return (r); +} /* lccrt_type_get_num_args */ + +/** + * Получить значение поля. + */ +lccrt_type_ptr +lccrt_type_get_parent( lccrt_type_ptr type) +{ + lccrt_type_ptr r; + + lccrt_check_type_assert( type, lccrt_type_t); + r = type->parent; + if ( (type->type_name == LCCRT_TYPE_NAME) ) + { + } else if ( (type->type_name == LCCRT_TYPE_PTR) + || (type->type_name == LCCRT_TYPE_NAME) + || (type->type_name == LCCRT_TYPE_FUNC) + || (type->type_name == LCCRT_TYPE_ARRAY) + || (type->type_name == LCCRT_TYPE_VLA_ARRAY) + || (type->type_name == LCCRT_TYPE_VECTOR) + || (type->type_name == LCCRT_TYPE_FIELD) ) + { + lccrt_assert( r); + } else + { + lccrt_assert( !r); + } + + return (r); +} /* lccrt_type_get_parent */ + +/** + * Получить значение поля. + */ +lccrt_var_ptr +lccrt_type_get_vla_size( lccrt_type_ptr type) +{ + lccrt_var_ptr r; + + lccrt_check_type_assert( type, lccrt_type_t); + lccrt_assert( type->type_name == LCCRT_TYPE_VLA_ARRAY); + r = type->vnum; + lccrt_assert( 0); + + return (r); +} /* lccrt_type_get_vla_size */ + +/** + * Получить значение поля. + */ +int +lccrt_type_get_sign( lccrt_type_ptr type) +{ + int r; + + lccrt_check_type_assert( type, lccrt_type_t); + r = type->is_sign; + if ( (type->type_name != LCCRT_TYPE_INT) ) + { + lccrt_assert( !r); + } + + return (r); +} /* lccrt_type_get_sign */ + +/** + * Подобрать целый тип по битовому размеру. + */ +lccrt_type_name_int_t +lccrt_type_int_find_by_bitsize( uint64_t bitsize) +{ + lccrt_type_name_int_t r; + + switch ( bitsize ) + { + case 8: r = LCCRT_INT_SUBTYPE_8; break; + case 16: r = LCCRT_INT_SUBTYPE_16; break; + case 32: r = LCCRT_INT_SUBTYPE_32; break; + case 64: r = LCCRT_INT_SUBTYPE_64; break; + case 128: r = LCCRT_INT_SUBTYPE_128; break; + default: r = LCCRT_INT_SUBTYPE_LAST; break; + } + + return (r); +} /* lccrt_type_int_find_by_bitsize */ + +/** + * Подобрать плавающий тип по битовому размеру. + */ +lccrt_type_name_float_t +lccrt_type_float_find_by_bitsize( uint64_t bitsize) +{ + lccrt_type_name_float_t r; + + switch ( bitsize ) + { + case 32: r = LCCRT_FLOAT_SUBTYPE_32; break; + case 64: r = LCCRT_FLOAT_SUBTYPE_64; break; + case 80: r = LCCRT_FLOAT_SUBTYPE_80; break; + case 128: r = LCCRT_FLOAT_SUBTYPE_128; break; + default: r = LCCRT_INT_SUBTYPE_LAST; break; + } + + return (r); +} /* lccrt_type_float_find_by_bitsize */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_array( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_ARRAY) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_array */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_vector( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_VECTOR) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_vector */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_struct( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_STRUCT) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_struct */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_bool( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_BOOL) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_bool */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_void( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_VOID) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_void */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_ellipsis( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_ELLIPSIS) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_ellipsis */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_field( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_FIELD) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_field */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_float( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_FLOAT) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_float */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_int( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_INT) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_int */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_typename( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_NAME) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_typename */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_pointer( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_PTR) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_pointer */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_function( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_FUNC) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_function */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_union( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_STRUCT) + && (type->is_union) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_union */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_class_elems( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_ARRAY) + || (type->type_name == LCCRT_TYPE_VECTOR) + || (type->type_name == LCCRT_TYPE_STRUCT) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_class_elems */ + +/** + * Проверить тип на подтип. + */ +int +lccrt_type_is_class_struct( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + if ( (type->type_name == LCCRT_TYPE_STRUCT) ) + { + r = 1; + } + + return (r); +} /* lccrt_type_is_class_struct */ + +/** + * Проверяем, что у типа-функции типом последнего аргумента является тип-многоточие. + */ +int +lccrt_type_is_function_var_arg( lccrt_type_ptr type) +{ + int r = 0; + + lccrt_check_type_assert( type, lccrt_type_t); + lccrt_assert( type->type_name == LCCRT_TYPE_FUNC); + lccrt_assert( type->num_args >= 0); + if ( type->num_args ) + { + lccrt_type_ptr ta = type->args[type->num_args - 1]; + + r = (ta->type_name == LCCRT_TYPE_ELLIPSIS); + } + + return (r); +} /* lccrt_type_is_function_var_arg */ + +/** + * Вывод на стандартный вывод текстового представления типа. + */ +int +lccrt_type_print( lccrt_type_ptr type, int is_ln) +{ + lccrt_check_type_assert( type, lccrt_type_t); + printf( "%s%s", type->sym_name, is_ln ? "\n" : ""); + + return (0); +} /* lccrt_type_ptr */ + +#if 0 +lccrt_type_is_struct +lccrt_type_is_union +#endif diff --git a/lib/irv/lccrt_var.c b/lib/irv/lccrt_var.c new file mode 100644 index 0000000..0de792e --- /dev/null +++ b/lib/irv/lccrt_var.c @@ -0,0 +1,1606 @@ +/** + * 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_var.c - реализация пользовательский интерфейс (динамической) компиляции. + */ + +#include +#include +#include +#include +#include + +#include "lccrt_real.h" + +/** + * Пропустить typename определения в типе. + */ +lccrt_type_ptr +lccrt_var_skip_typename( lccrt_type_ptr type) +{ + while ( (lccrt_type_is_typename( type) + && lccrt_type_get_parent( type)) ) + { + type = lccrt_type_get_parent( type); + } + + return (type); +} /* lccrt_var_skip_typename */ + +/** + * Создание нового инициализатора переменной. + */ +static lccrt_varinit_ptr +lccrt_varinit_new( lccrt_type_ptr type) +{ + lccrt_module_ptr m = lccrt_type_get_module( type); + lccrt_context_ptr ctx = lccrt_module_get_context( m); + lccrt_varinit_ptr v = lccrt_ctx_malloc( ctx, lccrt_varinit_t); + + lccrt_check_type_assert( type, lccrt_type_t); + type = lccrt_var_skip_typename( type); + memset( v, 0, sizeof( v[0])); + lccrt_check_type_init( v, lccrt_varinit_t); + v->type = type; + v->init_type = LCCRT_VARINIT_LAST; + lccrt_ilist_unit_init( &(v->varinits_unit)); + lccrt_ilist_head_insert( &(m->varinits_head), varinits_unit, v); + + return (v); +} /* lccrt_varinit_new */ + +/** + * Удаление инициализатора переменной. + */ +void +lccrt_varinit_delete( lccrt_varinit_ptr v) +{ + lccrt_check_type_assert( v, lccrt_varinit_t); + if ( v ) + { + lccrt_module_ptr m = lccrt_type_get_module( v->type); + lccrt_context_ptr ctx = lccrt_module_get_context( m); + + lccrt_ilist_head_remove( &(m->varinits_head), varinits_unit, v); + lccrt_check_type_done( v, lccrt_varinit_t); + + if ( 0 ) + { + if ( (v->init_type == LCCRT_VARINIT_STR) ) + { + lccrt_ctx_free( ctx, v->data.sval); + + } else if ( (v->init_type == LCCRT_VARINIT_ARR) ) + { + int64_t i; + + for ( i = 0; i < v->num_elems; ++i ) + { + lccrt_varinit_delete( v->data.vals[i]); + } + + lccrt_ctx_free( ctx, v->data.vals); + } + } + + lccrt_ctx_free( ctx, v); + } + + return; +} /* lccrt_varinit_delete */ + +/** + * Создание нового инициализатора переменной. + */ +lccrt_varinit_ptr +lccrt_varinit_new_zero( lccrt_type_ptr type) +{ + //lccrt_context_ptr ctx = type->ctx; + lccrt_varinit_ptr v = lccrt_varinit_new( type); + + v->init_type = LCCRT_VARINIT_ZERO; + + return (v); +} /* lccrt_varinit_new_zero */ + +/** + * Создание нового инициализатора переменной. + */ +lccrt_varinit_ptr +lccrt_varinit_new_scalar( lccrt_t_ptr type, uint64_t value) +{ + //lccrt_context_ptr ctx = type->ctx; + lccrt_varinit_ptr v = lccrt_varinit_new( type); + + v->init_type = LCCRT_VARINIT_HEX; + v->data.ival = value; + + return (v); +} /* lccrt_varinit_new_scalar */ + +/** + * Создание нового инициализатора переменной. + */ +lccrt_varinit_ptr +lccrt_varinit_new_str( lccrt_t_ptr type, uint64_t value_len, const char *value) +{ + lccrt_context_ptr ctx = type->m->ctx; + lccrt_varinit_ptr v = lccrt_varinit_new( type); + + v->init_type = LCCRT_VARINIT_STR; + v->num_elems = value_len; + v->data.sval = lccrt_ctx_mallocn( ctx, char, value_len); + memcpy( v->data.sval, value, value_len); + + return (v); +} /* lccrt_varinit_new_str */ + +/** + * Создание нового инициализатора переменной. + */ +lccrt_varinit_ptr +lccrt_varinit_new_array( lccrt_t_ptr type, uint64_t num_init_elems, lccrt_varinit_ptr *init_data) +{ + lccrt_context_ptr ctx = type->m->ctx; + lccrt_varinit_ptr v = lccrt_varinit_new( type); + + type = lccrt_var_skip_typename( type); + if ( !((type->type_name == LCCRT_TYPE_ARRAY) + //|| (type->type_name == LCCRT_TYPE_PTR) + || (type->type_name == LCCRT_TYPE_VECTOR) + || (type->type_name == LCCRT_TYPE_STRUCT) + || ((type->type_name == LCCRT_TYPE_INT) + && (lccrt_type_get_int_subtype_name( 8*type->bytesize) == LCCRT_INT_SUBTYPE_128)) + || ((type->type_name == LCCRT_TYPE_FLOAT) + && (lccrt_type_get_float_subtype_name( 8*type->bytesize) == LCCRT_FLOAT_SUBTYPE_80))) ) + { + lccrt_assert( 0); + } + + v->init_type = LCCRT_VARINIT_ARR; + v->num_elems = num_init_elems; + v->data.vals = lccrt_ctx_memdup( ctx, init_data, num_init_elems * sizeof( v->data.vals[0])); + + return (v); +} /* lccrt_varinit_new_array */ + +/** + * Создание нового инициализатора переменной. + */ +lccrt_varinit_ptr +lccrt_varinit_new_addr_var( lccrt_var_ptr var, uint64_t shift) +{ + lccrt_type_ptr type = lccrt_type_make_ptr_type( var->type); + lccrt_varinit_ptr v = lccrt_varinit_new( type); + + v->init_type = LCCRT_VARINIT_ADDR_VAR; + v->data.var = var; + v->num_elems = shift; + + return (v); +} /* lccrt_varinit_new_addr_var */ + +/** + * Создание нового инициализатора переменной. + */ +lccrt_varinit_ptr +lccrt_varinit_new_addr_func( lccrt_function_ptr func, uint64_t shift) +{ + lccrt_type_ptr type = lccrt_type_make_ptr_type( func->sig_type); + lccrt_varinit_ptr v = lccrt_varinit_new( type); + + lccrt_check_type_assert( func, lccrt_function_t); + v->init_type = LCCRT_VARINIT_ADDR_FUNC; + v->data.func = func; + v->num_elems = shift; + + return (v); +} /* lccrt_varinit_new_addr_func */ + +/** + * Получить значение поля. + */ +lccrt_type_ptr +lccrt_varinit_get_type( lccrt_varinit_ptr vi) +{ + lccrt_type_ptr r; + + lccrt_check_type_assert( vi, lccrt_varinit_t); + r = vi->type; + + return (r); +} /* lccrt_varinit_get_type */ + +/** + * Получить значение поля. + */ +lccrt_varinit_inittype_t +lccrt_varinit_get_inittype( lccrt_varinit_ptr vi) +{ + lccrt_varinit_inittype_t r; + + lccrt_check_type_assert( vi, lccrt_varinit_t); + r = vi->init_type; + + return (r); +} /* lccrt_varinit_get_inittype */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_varinit_get_num_elems( lccrt_varinit_ptr vi) +{ + uint64_t r = 0; + + if ( lccrt_varinit_is_array( vi) + || lccrt_varinit_is_str( vi) + || lccrt_varinit_is_addr_var( vi) ) + { + r = vi->num_elems; + } + + return (r); +} /* lccrt_varinit_get_num_elems */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_varinit_get_hex64( lccrt_varinit_ptr vi) +{ + uint64_t r = 0; + + lccrt_assert( lccrt_varinit_is_hex( vi)); + r = vi->data.ival; + + return (r); +} /* lccrt_varinit_get_hex64 */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_varinit_get_zero_or_hex64( lccrt_varinit_ptr vi) +{ + uint64_t r = 0; + + if ( lccrt_varinit_is_zero( vi) ) + { + lccrt_assert( vi->data.ival == 0); + + } else if ( lccrt_varinit_is_hex( vi) ) + { + r = vi->data.ival; + } else + { + lccrt_assert( 0); + } + + return (r); +} /* lccrt_varinit_get_zero_or_hex64 */ + +/** + * Получить значение поля. + */ +const char * +lccrt_varinit_get_str( lccrt_varinit_ptr vi) +{ + const char *r; + + lccrt_assert( lccrt_varinit_is_str( vi)); + r = vi->data.sval; + + return (r); +} /* lccrt_varinit_get_str */ + +/** + * Получить значение поля. + */ +lccrt_varinit_ptr +lccrt_varinit_get_elem( lccrt_varinit_ptr vi, uint64_t elem_num) +{ + lccrt_varinit_ptr r; + + lccrt_assert( lccrt_varinit_is_array( vi) || lccrt_varinit_is_str( vi)); + lccrt_assert( (0 <= elem_num) && (elem_num < vi->num_elems)); + r = vi->data.vals[ elem_num]; + + return (r); +} /* lccrt_varinit_get_elem */ + +/** + * Получить значение поля. + */ +lccrt_function_ptr +lccrt_varinit_get_addr_func( lccrt_varinit_ptr vi) +{ + lccrt_function_ptr r; + + lccrt_assert( lccrt_varinit_is_addr_func( vi)); + r = vi->data.func; + + return (r); +} /* lccrt_varinit_get_addr_func */ + +/** + * Получить значение поля. + */ +lccrt_var_ptr +lccrt_varinit_get_addr_var( lccrt_varinit_ptr vi) +{ + lccrt_var_ptr r; + + lccrt_assert( lccrt_varinit_is_addr_var( vi)); + r = vi->data.var; + + return (r); +} /* lccrt_varinit_get_addr_var */ + +/** + * Проверить подтип. + */ +int +lccrt_varinit_is_zero( lccrt_varinit_ptr vi) +{ + int r = 0; + + lccrt_check_type_assert( vi, lccrt_varinit_t); + if ( (vi->init_type == LCCRT_VARINIT_ZERO) ) + { + r = 1; + } + + return (r); +} /* lccrt_varinit_is_zero */ + +/** + * Проверить подтип. + */ +int +lccrt_varinit_is_hex( lccrt_varinit_ptr vi) +{ + int r = 0; + + lccrt_check_type_assert( vi, lccrt_varinit_t); + if ( (vi->init_type == LCCRT_VARINIT_HEX) ) + { + r = 1; + } + + return (r); +} /* lccrt_varinit_is_hex */ + +/** + * Проверить подтип. + */ +int +lccrt_varinit_is_zero_or_hex( lccrt_varinit_ptr vi) +{ + int r = 0; + + r = lccrt_varinit_is_zero( vi) || lccrt_varinit_is_hex( vi); + + return (r); +} /* lccrt_varinit_is_zero_or_hex */ + +/** + * Проверить подтип. + */ +int +lccrt_varinit_is_str( lccrt_varinit_ptr vi) +{ + int r = 0; + + lccrt_check_type_assert( vi, lccrt_varinit_t); + if ( (vi->init_type == LCCRT_VARINIT_STR) ) + { + r = 1; + } + + return (r); +} /* lccrt_varinit_is_str */ + +/** + * Проверить подтип. + */ +int +lccrt_varinit_is_array( lccrt_varinit_ptr vi) +{ + int r = 0; + + lccrt_check_type_assert( vi, lccrt_varinit_t); + if ( (vi->init_type == LCCRT_VARINIT_ARR) ) + { + r = 1; + } + + return (r); +} /* lccrt_varinit_is_array */ + +/** + * Проверить подтип. + */ +int +lccrt_varinit_is_addr_var( lccrt_varinit_ptr vi) +{ + int r = 0; + + lccrt_check_type_assert( vi, lccrt_varinit_t); + if ( (vi->init_type == LCCRT_VARINIT_ADDR_VAR) ) + { + r = 1; + } + + return (r); +} /* lccrt_varinit_is_addr_var */ + +/** + * Проверить подтип. + */ +int +lccrt_varinit_is_addr_func( lccrt_varinit_ptr vi) +{ + int r = 0; + + lccrt_check_type_assert( vi, lccrt_varinit_t); + if ( (vi->init_type == LCCRT_VARINIT_ADDR_FUNC) ) + { + r = 1; + } + + return (r); +} /* lccrt_varinit_is_addr_func */ + +/** + * Создание новой переменной. + */ +lccrt_var_ptr +lccrt_var_new( void *holder, lccrt_var_loc_t loc, lccrt_t_ptr type, const char *name, + const char *asm_name, lccrt_link_t vlink, unsigned align) +{ + lccrt_var_ptr v = 0; + lccrt_context_ptr ctx = 0; + lccrt_module_ptr m = 0; + lccrt_function_ptr f = 0; + lccrt_he_ptr e = 0; + lccrt_asmlink_t link = lccrt_link_unpack( vlink); + + lccrt_assert( lccrt_type_get_bytesize( type) >= 0); + type = lccrt_var_skip_typename( type); + if ( (name + && name[0] == '\01') ) + { + name++; + } + + if ( (asm_name + && asm_name[0] == '\01') ) + { + asm_name++; + } + + if ( asm_name + && (asm_name[0] == 0) ) + { + asm_name = name; + } + + if ( (lccrt_type_get_bytesize( type) == 0) ) + { + //lccrt_assert( lccrt_loc_is_ext( loc) || (link.bnd == LCCRT_LINK_BND_WEAK)); + lccrt_assert( lccrt_type_is_array( type) || lccrt_type_is_struct( type) || lccrt_type_is_function( type)); + } + + if ( lccrt_loc_is_global( loc) ) + { + /* Глобальная переменная модуля. */ + m = (lccrt_module_ptr)holder; + name = lccrt_module_name_new_global( m, name); + if ( (loc == LCCRT_VAR_LOC_GLOB) ) + { + lccrt_assert( link.bnd != LCCRT_LINK_BND_NO); + + } else if ( (loc == LCCRT_VAR_LOC_CONSTARG) ) + { + lccrt_assert( link.bnd == LCCRT_LINK_BND_LOCAL); + lccrt_assert( link.vis == LCCRT_LINK_VIS_DEFAULT); + lccrt_assert( link.tls == LCCRT_LINK_TLS_NO); + lccrt_assert( link.is_cnst && !link.is_alias); + } else + { + if ( link.is_alias ) + { + if ( !((link.bnd == LCCRT_LINK_BND_GLOBAL) + || (link.bnd == LCCRT_LINK_BND_WEAK) + || (link.bnd == LCCRT_LINK_BND_LOCAL)) ) + { + lccrt_assert( 0); + } + } else + { + if ( !((link.bnd == LCCRT_LINK_BND_GLOBAL) + || (link.bnd == LCCRT_LINK_BND_WEAK)) ) + { + lccrt_assert( 0); + } + } + } + } else if ( lccrt_loc_is_local( loc) ) + { + /* Локальная переменная функции. */ + lccrt_assert( link.bnd == LCCRT_LINK_BND_NO); + lccrt_assert( link.vis == LCCRT_LINK_VIS_DEFAULT); + lccrt_assert( link.tls == LCCRT_LINK_TLS_NO); + f = (lccrt_function_ptr)holder; + m = (lccrt_module_ptr)f->module; + name = lccrt_function_name_new_local( f, name); + } else + { + lccrt_assert( 0); + } + + ctx = m->ctx; + lccrt_check_type_assert( f, lccrt_function_t); + lccrt_check_type_assert( m, lccrt_module_t); + lccrt_check_type_assert( ctx, lccrt_context_t); + lccrt_check_type_assert( type, lccrt_type_t); + + /* Проводим поиск на наличие переменной с заданным именем. */ + e = lccrt_hash_find( f ? f->lvars : m->gvars, (uintptr_t)name); + if ( e ) + { + /* Переменная уже создана. */ + v = (lccrt_var_ptr)lccrt_hash_get( e); + lccrt_assert( lccrt_str_eqz( asm_name, v->asm_name)); + lccrt_ctx_free( ctx, name); + if ( !((loc == LCCRT_VAR_LOC_GLOB) + && (v->loc == LCCRT_VAR_LOC_EXT)) ) + { + lccrt_assert( type == v->type); + } + + /* Проверяем (и изменяем для декларации) тип размещения переменной. */ + switch ( loc ) + { + case LCCRT_VAR_LOC_GLOB: + /* Создается определение, поэтому меняем тип размещения, который + должен быть декларацией. */ + lccrt_assert( v->loc == LCCRT_VAR_LOC_EXT); + v->type = type; + v->loc = loc; + v->align = v->align ? v->align : align; + break; + case LCCRT_VAR_LOC_EXT: + lccrt_assert( lccrt_var_is_global( v)); + align = align ? align : v->align; + break; + case LCCRT_VAR_LOC_LOCAL: + case LCCRT_VAR_LOC_ARG: + case LCCRT_VAR_LOC_SYSARG: + lccrt_assert( loc == v->loc); + break; + default: + break; + } + + /* Проверяем согласованность выравниваний. */ + lccrt_assert( align == v->align); + lccrt_assert( link.vis == v->link.vis); + lccrt_assert( link.tls == v->link.tls); + lccrt_assert( link.is_cnst == v->link.is_cnst); + lccrt_assert( link.is_alias == v->link.is_alias); + } else + { + /* Создаем новую переменную. */ + v = lccrt_ctx_malloc( ctx, lccrt_var_t); + memset( v, 0, sizeof( v[0])); + + lccrt_check_type_init( v, lccrt_var_t); + v->holder = holder; + v->loc = loc; + v->type = type; + v->name = name; + v->asm_name = lccrt_ctx_copy_str( ctx, asm_name); + lccrt_ilist_unit_init( &(v->vars_unit)); + v->align = align; + v->link = link; + v->arg_num = -1; + if ( f ) + { + f->lvars_num++; + v->ident_num = f->lvars_num; + lccrt_ilist_head_insert( &(f->lvars_head), vars_unit, v); + } else + { + m->gvars_num++; + v->ident_num = m->gvars_num; + lccrt_ilist_head_insert( &(m->gvars_head), vars_unit, v); + } + + if ( (link.bnd == LCCRT_LINK_BND_LOCAL) ) + { + } + + e = lccrt_hash_push( f ? f->lvars : m->gvars, (uintptr_t)name, 0); + lccrt_hash_set( e, (uintptr_t)v); + } + + return (v); +} /* lccrt_var_new */ + +/** + * Удаление переменной. + */ +void +lccrt_var_delete( lccrt_var_ptr v) +{ + lccrt_module_ptr m = lccrt_var_get_module( v); + lccrt_context_ptr ctx = m->ctx; + + lccrt_check_type_assert( v, lccrt_var_t); + + /* Корректируем структуру списка переменных. */ + if ( lccrt_var_is_local( v) ) + { + lccrt_function_ptr f = v->holder; + + lccrt_check_type_assert( f, lccrt_function_t); + lccrt_ilist_head_remove( &(f->lvars_head), vars_unit, v); + } else + { + lccrt_module_ptr m = v->holder; + + lccrt_check_type_assert( m, lccrt_module_t); + lccrt_ilist_head_remove( &(m->gvars_head), vars_unit, v); + } + + v->einfo = lccrt_einfo_link_delete_chain( v->einfo); + + //lccrt_varinit_delete( v->init_value); + lccrt_ctx_free( ctx, v->name); + lccrt_ctx_free( ctx, v->asm_name); + lccrt_ctx_free( ctx, v->section_name); + lccrt_ctx_free( ctx, v->comdat); + lccrt_check_type_done( v, lccrt_var_t); + lccrt_ctx_free( ctx, v); + + return; +} /* lccrt_var_delete */ + +/** + * Создание константы. + */ +lccrt_var_ptr +lccrt_var_new_constarg( lccrt_m_ptr m, lccrt_t_ptr type, lccrt_varinit_ptr vi) +{ + char name[256]; + lccrt_link_t lnk; + lccrt_var_ptr r = 0; + int cind = -1; + int tind = -1; + lccrt_type_ptr u32 = lccrt_type_make_u32( m); + lccrt_type_ptr u64 = lccrt_type_make_u64( m); + + if ( (type == u32) + && lccrt_varinit_is_zero_or_hex( vi) ) + { + int32_t v32 = lccrt_varinit_get_zero_or_hex64( vi); + + if ( (LCCRT_MODULE_CARG_MIN <= v32) + && (v32 <= LCCRT_MODULE_CARG_MAX) ) + { + tind = 0; + cind = (v32 - LCCRT_MODULE_CARG_MIN); + } + } else if ( (type == u64) + && lccrt_varinit_is_zero_or_hex( vi) ) + { + int64_t v64 = lccrt_varinit_get_zero_or_hex64( vi); + + if ( (LCCRT_MODULE_CARG_MIN <= v64) + && (v64 <= LCCRT_MODULE_CARG_MAX) ) + { + tind = 1; + cind = (v64 - LCCRT_MODULE_CARG_MIN); + } + } + + if ( (cind >= 0) + && m->carg_vars[tind][cind] ) + { + r = m->carg_vars[tind][cind]; + } else + { + snprintf( name, 256, "__lccrt_c%ju", m->cargs_name_id); + m->cargs_name_id++; + lnk = lccrt_link_get( LCCRT_LINK_BND_LOCAL, LCCRT_LINK_VIS_DEFAULT, + LCCRT_LINK_TLS_NO, 1, 0); + r = lccrt_var_new( m, LCCRT_VAR_LOC_CONSTARG, type, name, 0, lnk, 0); + lccrt_var_set_init_value_reduce( r, vi); + if ( (cind >= 0) ) + { + m->carg_vars[tind][cind] = r; + } + } + + return (r); +} /* lccrt_var_new_constarg */ + +/** + * Создание целочисленной константы. + */ +lccrt_var_ptr +lccrt_var_new_constarg_hex( lccrt_m_ptr m, lccrt_t_ptr type, uint64_t value) +{ + lccrt_var_ptr r; + + r = lccrt_var_new_constarg( m, type, lccrt_varinit_new_scalar( type, value)); + + return (r); +} /* lccrt_var_new_constarg_hex */ + +/** + * Создание целочисленной константы. + */ +lccrt_var_ptr +lccrt_var_new_constarg_str( lccrt_module_ptr m, uint64_t s_len, const char *s) +{ + lccrt_varinit_ptr vi; + lccrt_var_ptr r = 0; + lccrt_type_ptr tu8 = lccrt_type_make_u8( m); + + vi = lccrt_varinit_new_str( lccrt_type_make_pbyte( m), s_len, s); + r = lccrt_var_new_constarg( m, lccrt_type_make_array( tu8, s_len), vi); + + return (r); +} /* lccrt_var_new_constarg_str */ + +/** + * Создание нового заголовка глобальной переменной. + */ +lccrt_var_ptr +lccrt_var_new_declaration( lccrt_m_ptr m, lccrt_t_ptr type, const char *name, lccrt_link_t link) +{ + lccrt_var_ptr v; + + v = lccrt_var_new( m, LCCRT_VAR_LOC_EXT, type, name, 0, link, 0); + + return (v); +} /* lccrt_var_new_declaration */ + +/** + * Создание новой локальной переменной. + */ +lccrt_var_ptr +lccrt_var_new_local( lccrt_f_ptr f, lccrt_t_ptr type, const char *name) +{ + lccrt_var_ptr v; + lccrt_link_t link = lccrt_link_get( 0, 0, 0, 0, 0); + + if ( !name ) + { + name = lccrt_function_name_new_local( f, 0); + } + + v = lccrt_var_new( f, LCCRT_VAR_LOC_LOCAL, type, name, 0, link, 0); + + return (v); +} /* lccrt_var_new_local */ + +/** + * Создание новой локальной переменной. + */ +lccrt_var_ptr +lccrt_var_new_asm( lccrt_f_ptr f, lccrt_t_ptr type, const char *asm_text, const char *asm_cnstr) +{ + lccrt_var_ptr v; + lccrt_link_t link = lccrt_link_get( 0, 0, 0, 0, 0); + + v = lccrt_var_new( f, LCCRT_VAR_LOC_ASM, type, asm_text, asm_cnstr, link, 0); + + return (v); +} /* lccrt_var_new_asm */ + +lccrt_type_ptr +lccrt_var_expand_array( lccrt_var_ptr var, lccrt_type_ptr type) +{ + lccrt_type_ptr r = 0; + + lccrt_check_type_assert( var, lccrt_var_t); + lccrt_check_type_assert( type, lccrt_type_t); + if ( (var->type == type) ) + { + r = type; + } else + { + lccrt_assert( lccrt_type_is_array( var->type)); + lccrt_assert( lccrt_type_is_array( type)); + lccrt_assert( lccrt_type_get_parent( type) == lccrt_type_get_parent( var->type)); + if ( (lccrt_type_get_num_args( type) > lccrt_type_get_num_args( var->type)) ) + { + r = type; + var->type = type; + } else + { + r = var->type; + } + } + + return (r); +} /* lccrt_var_expand_array */ + +/** + * Получить значение поля. + */ +lccrt_module_ptr +lccrt_var_get_module( lccrt_var_ptr var) +{ + lccrt_module_ptr r; + + lccrt_check_type_assert( var, lccrt_var_t); + if ( lccrt_var_is_local( var) ) + { + r = lccrt_function_get_module( var->holder); + } else + { + r = var->holder; + } + + return (r); +} /* lccrt_var_get_module */ + +/** + * Получить для переменной значение атрибута. + */ +static int +lccrt_var_get_attr( lccrt_v_ptr v, lccrt_var_attr_name_t attr) +{ + int r; + int k = attr / 64; + int j = attr % 64; + + lccrt_check_type_assert( v, lccrt_var_t); + r = (v->attrs[k] >> j) & 0x1; + + return (r); +} /* lccrt_var_get_attr */ + +/** + * Установить для переменной значение атрибута. + */ +static int +lccrt_var_set_attr( lccrt_v_ptr v, lccrt_var_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_var_get_attr( v, attr); + + v->attrs[k] = (v->attrs[k] & (~bit)) | value_bit; + + return (r); +} /* lccrt_var_set_attr */ + +/** + * Скопировать значение булевых атрибутов. + */ +void +lccrt_var_copy_attrs( lccrt_v_ptr dst, lccrt_v_ptr src) +{ + int i; + + lccrt_check_type_assert( dst, lccrt_var_t); + lccrt_check_type_assert( src, lccrt_var_t); + for ( i = 0; i < LCCRT_FUNC_ATTRS_LENGTH; ++i ) + { + dst->attrs[i] = src->attrs[i]; + } + + return; +} /* lccrt_var_copy_attrs */ + +/** + * Получить для переменной значение атрибута. + */ +int +lccrt_var_get_attr_common( lccrt_v_ptr v) +{ + int r = lccrt_var_get_attr( v, LCCRT_VAR_ATTR_COMMON); + + return (r); +} /* lccrt_var_get_attr_common */ + +/** + * Установить для переменной значение атрибута. + */ +int +lccrt_var_set_attr_common( lccrt_v_ptr v, int value) +{ + int r = lccrt_var_set_attr( v, LCCRT_VAR_ATTR_COMMON, value); + + return (r); +} /* lccrt_var_set_attr_common */ + +/** + * Получить для переменной значение атрибута. + */ +int +lccrt_var_get_attr_used( lccrt_v_ptr v) +{ + int r = lccrt_var_get_attr( v, LCCRT_VAR_ATTR_USED); + + return (r); +} /* lccrt_var_get_attr_used */ + +/** + * Установить для переменной значение атрибута. + */ +int +lccrt_var_set_attr_used( lccrt_v_ptr v, int value) +{ + int r = lccrt_var_set_attr( v, LCCRT_VAR_ATTR_USED, value); + + return (r); +} /* lccrt_var_set_attr_used */ + +/** + * Получить для переменной значение атрибута. + */ +int +lccrt_var_get_attr_restrict( lccrt_v_ptr v) +{ + int r = lccrt_var_get_attr( v, LCCRT_VAR_ATTR_RESTRICT); + + return (r); +} /* lccrt_var_get_attr_restrict */ + +/** + * Установить для переменной значение атрибута. + */ +int +lccrt_var_set_attr_restrict( lccrt_v_ptr v, int value) +{ + int r = lccrt_var_set_attr( v, LCCRT_VAR_ATTR_RESTRICT, value); + + return (r); +} /* lccrt_var_set_attr_restrict */ + +/** + * Получить значение поля. + */ +const char * +lccrt_var_get_comdat( lccrt_var_ptr var) +{ + const char *r; + + lccrt_check_type_assert( var, lccrt_var_t); + r = var->comdat; + + return (r); +} /* lccrt_var_get_comdat */ + +/** + * Установить значение поля. + */ +void +lccrt_var_set_comdat( lccrt_var_ptr var, const char *comdat) +{ + lccrt_ctx_ptr ctx = lccrt_module_get_context( lccrt_var_get_module( var)); + + lccrt_check_type_assert( var, lccrt_var_t); + lccrt_assert( !var->comdat); + //lccrt_ctx_free( ctx, var->comdat); + var->comdat = lccrt_ctx_copy_str( ctx, comdat); + + return; +} /* lccrt_var_set_comdat */ + +/** + * Получить значение поля. + */ +uint64_t +lccrt_var_get_bytesize( lccrt_var_ptr var) +{ + uint64_t r; + + r = lccrt_type_get_bytesize( lccrt_var_get_type( var)); + + return (r); +} /* lccrt_var_get_bytesize */ + +/** + * Получить значение поля. + */ +const char * +lccrt_var_get_name( lccrt_var_ptr var) +{ + const char *r; + + lccrt_check_type_assert( var, lccrt_var_t); + r = var->name; + + return (r); +} /* lccrt_var_get_name */ + +/** + * Получить значение поля. + */ +const char * +lccrt_var_get_asm_name( lccrt_var_ptr var) +{ + const char *r; + + lccrt_check_type_assert( var, lccrt_var_t); + r = var->asm_name; + + return (r); +} /* lccrt_var_get_asm_name */ + +/** + * Получить значение поля. + */ +lccrt_type_ptr +lccrt_var_get_type( lccrt_var_ptr var) +{ + lccrt_type_ptr r; + + lccrt_check_type_assert( var, lccrt_var_t); + r = var->type; + + return (r); +} /* lccrt_var_get_type */ + +/** + * Получить значение поле. + */ +unsigned +lccrt_var_get_align( lccrt_var_ptr var) +{ + unsigned r; + + lccrt_check_type_assert( var, lccrt_var_t); + r = var->align; + + return (r); +} /* lccrt_var_get_align */ + +/** + * Получить значение поля. + */ +lccrt_var_ptr +lccrt_var_get_next_var( lccrt_var_ptr var) +{ + lccrt_var_ptr r; + + lccrt_check_type_assert( var, lccrt_var_t); + r = var->vars_unit.next; + + return (r); +} /* lccrt_var_get_next_var */ + +/** + * Получить значение поля. + */ +lccrt_varinit_ptr +lccrt_var_get_init_value( lccrt_var_ptr var) +{ + lccrt_varinit_ptr r; + + lccrt_check_type_assert( var, lccrt_var_t); + r = var->init_value; + + return (r); +} /* lccrt_var_get_init_value */ + +/** + * Получить значение поля. + */ +lccrt_link_t +lccrt_var_get_link( lccrt_var_ptr var) +{ + lccrt_link_t r; + + lccrt_check_type_assert( var, lccrt_var_t); + r = lccrt_link_get( var->link.bnd, var->link.vis, var->link.tls, var->link.is_cnst, var->link.is_alias); + + return (r); +} /* lccrt_var_get_link */ + +/** + * Получить значение поля. + */ +lccrt_var_loc_t +lccrt_var_get_loc( lccrt_var_ptr var) +{ + lccrt_var_loc_t r; + + lccrt_check_type_assert( var, lccrt_var_t); + r = var->loc; + + return (r); +} /* lccrt_var_get_loc */ + +/** + * Получить значение поля. + */ +const char * +lccrt_var_get_section( lccrt_var_ptr var) +{ + lccrt_check_type_assert( var, lccrt_var_t); + + return (var->section_name); +} /* lccrt_var_get_section */ + +/** + * Установить значение поля. + */ +void +lccrt_var_set_section( lccrt_var_ptr var, const char *section_name) +{ + lccrt_ctx_ptr ctx = lccrt_module_get_context( lccrt_var_get_module( var)); + + lccrt_check_type_assert( var, lccrt_var_t); + if ( var->section_name ) + { + lccrt_ctx_free( ctx, var->section_name); + } + + var->section_name = lccrt_ctx_copy_str( ctx, section_name); + + return; +} /* lccrt_var_set_section */ + +/** + * Получить значение поля. + */ +int +lccrt_var_is_local( lccrt_var_ptr var) +{ + int r = 0; + + lccrt_check_type_assert( var, lccrt_var_t); + r = lccrt_loc_is_local( var->loc); + + return (r); +} /* lccrt_var_is_local */ + +/** + * Получить значение поля. + */ +int +lccrt_var_is_global( lccrt_var_ptr var) +{ + int r = 0; + + lccrt_check_type_assert( var, lccrt_var_t); + r = lccrt_loc_is_global( var->loc); + + return (r); +} /* lccrt_var_is_global */ + +/** + * Получить значение поля. + */ +int +lccrt_var_is_const( lccrt_var_ptr var) +{ + int r = 0; + + lccrt_check_type_assert( var, lccrt_var_t); + r = var->link.is_cnst; + lccrt_assert( !r || lccrt_var_is_global( var)); + + return (r); +} /* lccrt_var_is_const */ + +/** + * Получить значение поля. + */ +int +lccrt_var_get_num_defs( lccrt_var_ptr v) +{ + int r = v->num_defs; + + lccrt_check_type_assert( v, lccrt_var_t); + + return (r); +} /* lccrt_var_get_num_defs */ + +/** + * Установить значение поля. + */ +int +lccrt_var_set_num_defs( lccrt_var_ptr v, int num_defs) +{ + int r = v->num_defs; + + lccrt_check_type_assert( v, lccrt_var_t); + v->num_defs = num_defs; + + return (r); +} /* lccrt_var_set_num_defs */ + +/** + * Назначение переменной инициализатора. + */ +void +lccrt_var_set_init_value( lccrt_var_ptr var, + lccrt_varinit_ptr value) +{ + lccrt_module_ptr m = lccrt_type_get_module( lccrt_var_get_type( var)); + int ptr_bytesize = lccrt_module_is_ptr32( m) ? 4 : 8; + + lccrt_check_type_assert( var, lccrt_var_t); + lccrt_check_type_assert( value, lccrt_varinit_t); + if ( (var->type == value->type) ) + { + } else if ( (var->type->type_name == LCCRT_TYPE_INT) ) + { + if ( (value->type->type_name == LCCRT_TYPE_ARRAY) + && (var->type->bytesize == 16) ) + { + } else if ( (value->type->type_name == LCCRT_TYPE_PTR) + && (var->type->bytesize == ptr_bytesize) ) + { + } else + { + lccrt_assert( 0); + } + } else if ( (var->type->type_name == LCCRT_TYPE_PTR) ) + { + if ( (value->type->type_name == LCCRT_TYPE_INT) ) + { + lccrt_assert( lccrt_type_get_bytesize( value->type) <= ptr_bytesize); + } else + { + lccrt_assert( 0); + } + } else + { + lccrt_assert( 0); + } + + var->init_value = value; + + return; +} /* lccrt_var_set_init_value */ + +/** + * Назначение переменной инициализатора (с приведением типа инициализатора). + */ +void +lccrt_var_set_init_value_reduce( lccrt_var_ptr var, + lccrt_varinit_ptr value) +{ + lccrt_module_ptr m = lccrt_type_get_module( lccrt_var_get_type( var)); + int ptr_bytesize = lccrt_module_is_ptr32( m) ? 4 : 8; + + lccrt_check_type_assert( var, lccrt_var_t); + lccrt_check_type_assert( value, lccrt_varinit_t); + if ( (var->type != value->type) ) + { + lccrt_type_ptr tv = lccrt_type_get_parent( var->type); + lccrt_type_ptr ti = lccrt_type_get_parent( value->type); + + if ( (var->type->type_name == LCCRT_TYPE_INT) ) + { + if ( (value->type->type_name == LCCRT_TYPE_ARRAY) + && (var->type->bytesize == 16) ) + { + } else if ( (value->type->type_name == LCCRT_TYPE_PTR) + && (var->type->bytesize == ptr_bytesize) ) + { + } else + { + lccrt_assert( 0); + } + } else if ( (var->type->type_name == LCCRT_TYPE_PTR) ) + { + if ( (value->type->type_name == LCCRT_TYPE_INT) ) + { + } else + { + lccrt_assert( value->type->type_name == LCCRT_TYPE_PTR); + if ( (tv->type_name == LCCRT_TYPE_NAME) ) + { + //lccrt_assert( tv->parent == (lccrt_type_ptr)ti); + value->type = var->type; + + } else if ( (ti->type_name == LCCRT_TYPE_NAME) ) + { + //lccrt_assert( ti->parent == (lccrt_type_ptr)tv); + value->type = var->type; + + } else if ( (value->type->type_name == LCCRT_TYPE_PTR) ) + { + value->type = var->type; + } else + { + lccrt_assert( 0); + } + } + } else if ( (var->type->type_name == LCCRT_TYPE_ARRAY) ) + { + lccrt_module_ptr m = var->type->m; + lccrt_type_ptr pi = lccrt_type_get_parent( value->type); + lccrt_type_ptr pv = lccrt_type_get_parent( var->type); + lccrt_type_ptr i8 = lccrt_type_make_int( m, 1, 1); + lccrt_type_ptr u8 = lccrt_type_make_int( m, 1, 0); + + lccrt_assert( value->type->type_name == LCCRT_TYPE_PTR); + lccrt_assert( (pi == i8) || (pi == u8)); + lccrt_assert( (pv == i8) || (pv == u8)); + lccrt_assert( value->init_type == LCCRT_VARINIT_STR); + lccrt_assert( value->num_elems == var->type->num_args); + value->type = var->type; + } else + { + lccrt_assert( 0); + } + } + + lccrt_var_set_init_value( var, value); + + return; +} /* lccrt_var_set_init_value_reduce */ + +/** + * Получить значение поля. + */ +int +lccrt_var_is_constarg( lccrt_var_ptr var) +{ + int r = 0; + + lccrt_check_type_assert( var, lccrt_var_t); + if ( lccrt_loc_is_constarg( var->loc) ) + { + r = 1; + lccrt_assert( var->link.bnd == LCCRT_LINK_BND_LOCAL); + lccrt_assert( var->link.vis == LCCRT_LINK_VIS_DEFAULT); + lccrt_assert( var->link.tls == LCCRT_LINK_TLS_NO); + lccrt_assert( var->link.is_cnst && !var->link.is_alias); + lccrt_assert( !lccrt_var_get_attr_used( var)); + lccrt_assert( !lccrt_var_get_attr_common( var)); + } + + return (r); +} /* lccrt_var_is_constarg */ + +/** + * Получить значение поля. + */ +int +lccrt_var_is_constarg_hex( lccrt_var_ptr var) +{ + int r = 0; + + if ( lccrt_var_is_constarg( var) + && var->init_value + && lccrt_varinit_is_hex( var->init_value) ) + { + r = 1; + } + + return (r); +} /* lccrt_var_is_constarg_hex */ + +/** + * Получить значение поля. + */ +int +lccrt_var_is_constarg_int( lccrt_var_ptr var) +{ + int r = 0; + + if ( lccrt_var_is_constarg( var) + && var->init_value + && lccrt_type_is_int( var->type) ) + { + r = 1; + } + + return (r); +} /* lccrt_var_is_constarg_int */ + +/** + * Переменная реализует строковую константy. + */ +int +lccrt_var_is_constarg_str( lccrt_var_ptr v) +{ + int r = 0; + + lccrt_check_type_assert( v, lccrt_var_t); + if ( lccrt_var_is_constarg( v) + && v->init_value + && ((v->type == lccrt_type_make_pchar( v->type->m)) + || ((v->type->type_name == LCCRT_TYPE_ARRAY) + && (v->type->parent == lccrt_type_make_u8( v->type->m)))) + && ((v->init_value->init_type == LCCRT_VARINIT_STR) + || (v->init_value->init_type == LCCRT_VARINIT_ZERO)) ) + { + r = 1; + } + + return (r); +} /* lccrt_var_is_constarg_str */ + +/** + * Переменная реализует константy адрес функции. + */ +int +lccrt_var_is_constarg_addr_func( lccrt_var_ptr v) +{ + int r = 0; + lccrt_varinit_ptr vi = v->init_value; + + lccrt_check_type_assert( v, lccrt_var_t); + if ( vi + && v->link.is_cnst + && ((vi->init_type == LCCRT_VARINIT_ADDR_FUNC) + || (vi->init_type == LCCRT_VARINIT_ZERO)) + && (v->type->type_name == LCCRT_TYPE_PTR) + && (v->type->parent->type_name == LCCRT_TYPE_FUNC) ) + { + r = 1; + } + + return (r); +} /* lccrt_var_is_constarg_addr_func */ + +/** + * Получить значение целочисленной константы. + */ +uint64_t +lccrt_var_get_constarg_hex64( lccrt_var_ptr v) +{ + uint64_t r = 0; + lccrt_varinit_ptr vi = v->init_value; + + lccrt_assert( lccrt_var_is_constarg( v)); + if ( (vi->init_type == LCCRT_VARINIT_ZERO) ) + { + } else if ( (vi->init_type == LCCRT_VARINIT_HEX) ) + { + r = vi->data.ival; + } else + { + lccrt_assert( 0); + } + + return (r); +} /* lccrt_var_get_constarg_hex64 */ + +/** + * Получить значение целочисленной константы. + */ +int64_t +lccrt_var_get_constarg_int64( lccrt_var_ptr v) +{ + int64_t r = 0; + lccrt_varinit_ptr vi = v->init_value; + + lccrt_assert( lccrt_var_is_constarg_int( v)); + if ( (vi->init_type == LCCRT_VARINIT_ZERO) ) + { + } else if ( (vi->init_type == LCCRT_VARINIT_HEX) ) + { + lccrt_type_ptr t = v->type; + + if ( (t->bytesize == 1) ) + { + r = (char)vi->data.ival; + + } else if ( (t->bytesize == 2) ) + { + r = (short)vi->data.ival; + + } else if ( (t->bytesize == 4) ) + { + r = (int)vi->data.ival; + + } else if ( (t->bytesize == 8) ) + { + r = vi->data.ival; + } else + { + lccrt_assert( 0); + } + } else + { + lccrt_assert( 0); + } + + return (r); +} /* lccrt_var_get_constarg_int64 */ + +/** + * Получить значение строковой константы. + */ +const char * +lccrt_var_get_constarg_str( lccrt_var_ptr v) +{ + const char *r = 0; + lccrt_varinit_ptr vi = v->init_value; + + if ( !lccrt_var_is_constarg_str( v) ) + { + printf( "vn : %s\n", lccrt_var_get_name( v)); + printf( "ic : %d\n", lccrt_var_is_constarg( v)); + printf( "iv : %d\n", !!v->init_value); + printf( "tp : %p\n", v->type); + printf( "tp : %p\n", lccrt_type_make_pchar( v->type->m)); + printf( "ta : %d\n", v->type->type_name == LCCRT_TYPE_ARRAY); + printf( "tp : %d\n", v->type->parent == lccrt_type_make_u8( v->type->m)); + printf( "ts : %d\n", v->init_value->init_type == LCCRT_VARINIT_STR); + printf( "vz : %d\n", v->init_value->init_type == LCCRT_VARINIT_ZERO); + } + + lccrt_assert( lccrt_var_is_constarg_str( v)); + if ( (vi->init_type == LCCRT_VARINIT_ZERO) ) + { + } else if ( (vi->init_type == LCCRT_VARINIT_STR) ) + { + r = vi->data.sval; + } else + { + lccrt_assert( 0); + } + + return (r); +} /* lccrt_var_get_constarg_str */ + +/** + * Получить значение константы адреса функции. + */ +lccrt_function_ptr +lccrt_var_get_constarg_func( lccrt_var_ptr v) +{ + lccrt_function_ptr r = 0; + lccrt_varinit_ptr vi = v->init_value; + + lccrt_assert( lccrt_var_is_constarg_addr_func( v)); + if ( (vi->init_type == LCCRT_VARINIT_ADDR_FUNC) ) + { + r = vi->data.func; + } else + { + lccrt_assert( vi->init_type == LCCRT_VARINIT_ZERO); + } + + return (r); +} /* lccrt_var_get_constarg_func */ + +/** + * Добавить в переменную новые мета-данные, либо изменить значение старых. + */ +void +lccrt_var_set_einfo( lccrt_var_ptr v, lccrt_einfo_category_t ecat, lccrt_eir_t value) +{ + lccrt_module_ptr m = lccrt_var_get_module( v); + + lccrt_check_type_assert( v, lccrt_var_t); + lccrt_assert( !lccrt_einfo_is_scalar( value)); + v->einfo = lccrt_einfo_link_push_value( m, v->einfo, ecat, value); + + return; +} /* lccrt_var_set_einfo */ + +/** + * Получить значение мета-данных с заданным именем или 0, если таких данных нет. + */ +lccrt_einfo_reference_t +lccrt_var_get_einfo( lccrt_var_ptr v, lccrt_einfo_category_t ecat) +{ + lccrt_einfo_link_ptr unit = lccrt_einfo_link_find( v->einfo, ecat); + lccrt_einfo_reference_t r = lccrt_einfo_link_get_value( unit); + + lccrt_check_type_assert( v, lccrt_var_t); + + return (r); +} /* lccrt_var_get_einfo */ diff --git a/tools/lcbe/include/internal/lcbe_real.h b/tools/lcbe/include/internal/lcbe_real.h new file mode 100644 index 0000000..d4c52dc --- /dev/null +++ b/tools/lcbe/include/internal/lcbe_real.h @@ -0,0 +1,15 @@ +/** + * 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 + */ + +#include +#include +#include +#include +#include + +#include "lccrt.h" + +extern int lcbe_emit_c( lccrt_module_ptr m, const char *c_name); diff --git a/tools/lcbe/src/lcbe_driver.cpp b/tools/lcbe/src/lcbe_driver.cpp new file mode 100644 index 0000000..d6e6cb5 --- /dev/null +++ b/tools/lcbe/src/lcbe_driver.cpp @@ -0,0 +1,1234 @@ +/** + * 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 + * + * lcbe - библиотека динамической компиляции. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "lcbe_real.h" + +#define lcbe_str_eq( a, b) (strcmp( a, b) == 0) +#define lcbe_assign( a, b) ((a) ? (*(a) = (b)) : 0) +#define lcbe_max( a, b) ((a) > (b) ? (a) : (b)) + +extern "C" int LCCRT_ASM_FUNC_COMPILE( lccrt_module_ptr m, lccrt_asm_compile_config_t *cnf); +extern "C" const char *LCCRT_ASM_FUNC_GETTOOL( const char *targ, const char *type, const char *name); + +const char *LCCRT_PLUGIN_LCCRT_VERSION = LCCRT_VERSION; +const char *LCCRT_PLUGIN_LIBRARY_NAME = "lcbe"; +const char *LCCRT_PLUGIN_TARGETS[] = {"e2k64", "x86_64", 0}; + +static void lcbe_init( void) __attribute__((constructor)); +static void lcbe_done( void) __attribute__((destructor)); + +/** + * Внешние утилиты. + */ +typedef struct +{ + char *gcc_path; /* путь установки программы gcc */ + char *gcc; /* компилятор */ + char *include_path; /* путь до стандартной директории include */ + char *include_cpp_stl_path; /* путь до стандартной директории include/c++/stl */ + char *ld_path; /* путь до программы линковщик */ + char *ld; /* линковщик */ + char *as_path; /* путь до программы ассемблер */ + char *as; /* ассемблер */ + char *lib32_path; /* путь до 32-битных библиотек компилятора */ + char *lib64_path; /* путь до 32-битных библиотек компилятора */ + char *gcc_base_path; /* путь до системных файлов компилятора */ + char *gcc_lib32_path; /* путь до 32-битных системных библиотек компилятора */ + char *gcc_lib64_path; /* путь до 64-битных системных библиотек компилятора */ + char *bd; /* путь до директории с утилитами (binutils) */ + char *fs; /* путь до системной директории */ +} lcbe_tools_t; + +/** + * Настройки оптимизирующего бекэнда. + */ +typedef struct +{ + int verbose; /* флаг информационного режима */ + const char *save_temps; /* флаг сохранения временных файлов */ + char *cc_flags; /* дополнительные флаги компиляции */ + int8_t is_dbg; /* флаг создания отладочных dwarf-структур */ + char *lcbe_cc_config; /* внешняя программа вычисления конфигурации */ + char *lcbe_home; /* home-директория библиотеки */ + char *lcbe_conf; /* конфигурационный файл библиотеки */ +} lcbe_config_t; + +/** + * Глобальные данные библиотеки. + */ +typedef struct +{ + lcbe_tools_t tools; /* внешние утилиты */ + lcbe_config_t conf; /* настройки оптимизирующего бекэнда */ +} lcbe_info_t; + +/** + * Данные потока компиляции. + */ +typedef struct +{ + lcbe_info_t *info; /* ссылка на глобальные данные библиотеки */ + lccrt_asm_compile_config_t *aci; + lccrt_module_ptr m; + char *tmp_dir; /* директория для размещения временных файлов */ + char *out_name; /* название выходного файла */ + char *src_name; /* название файла с Си-кодом */ + int8_t is_obj; + int8_t save_temps; /* флаг сохранения временных файлов */ + int ofd; /* дескриптор выходного файла */ +} lcbe_compile_t; + +/** + * Глобальные данные потока компиляции. + */ +static __thread lcbe_compile_t lcbe_comp = {0}; + +/** + * Глобальные данные библиотеки. + */ +static lcbe_info_t lcbe_info = {{0}}; + +/** + * Проверка на установку опции. + */ +static int +lcbe_is_option( const char *opt, + int default_value) +{ + int result = default_value; + const char *v = getenv( opt); + + if ( v ) + { + if ( (strcmp( v, "yes") == 0) + || (strcmp( v, "YES") == 0) + || (strcmp( v, "on") == 0) + || (strcmp( v, "ON") == 0) + || (strcmp( v, "enable") == 0) + || (strcmp( v, "ENABLE") == 0) + || (strcmp( v, "1") == 0) ) + { + result = 1; + } else + { + result = 0; + } + } + + return (result); +} /* lcbe_is_option */ + +/** + * Чтение опции. + */ +static char * +lcbe_get_option( const char *opt, + const char *default_value) +{ + char *result = (char *)default_value; + char *v = getenv( opt); + + if ( v ) + { + result = v; + } + + if ( result ) + { + result = strdup( result); + } + + return (result); +} /* lcbe_get_option */ + +/** + * Ожидание завершения дочернего процесса с возвратом кода завершения. + */ +static int +lcbe_waitpid( pid_t pid) +{ + int r = -1; + int state = -1; + + if ( (pid > 0) ) + { + pid_t wpid = waitpid( pid, &state, 0); + + if ( (wpid != pid) + || !WIFEXITED( state) + || (WEXITSTATUS( state) != 0) ) + { + r = WEXITSTATUS( state) ? WEXITSTATUS( state) : -1; + } else + { + r = 0; + } + } + + return (r); +} /* lcbe_waitpid */ + +/** + * Подготовка аргументов для компиляции модуля. + */ +static int +lcbe_compile_module_args_init( lcbe_compile_t *l, char *argv[50]) +{ + char b[4096]; + int k = 0; + lcbe_config_t *c = &(l->info->conf); + + //argv[k] = strdup( "lccrt"); k++; + argv[k] = strdup( l->src_name); k++; + argv[k] = strdup( "-O1"); k++; + argv[k] = strdup( "-fexceptions"); k++; + //argv[k] = strdup( "--mcpu-internal=elbrus-v2"); k++; + if ( (l->aci->is_pic == 0) ) + { + if ( (l->aci->pie_level == 0) ) + { + argv[k] = strdup( "-fPIC"); k++; + + } else if ( (l->aci->pie_level == 1) ) + { + argv[k] = strdup( "-fpie"); k++; + + } else if ( (l->aci->pie_level == 2) ) + { + argv[k] = strdup( "-fPIE"); k++; + } else + { + assert( 0); + } + } else + { + assert( l->aci->pie_level == 0); + } + if ( l->aci->function_sections ) + { + argv[k] = strdup( "-ffunction-sections"); k++; + } + if ( l->aci->data_sections ) + { + argv[k] = strdup( "-fdata-sections"); k++; + } + if ( 1 || (l->aci->dbg_level > 0) ) + { + argv[k] = strdup( "-g"); k++; + c->is_dbg = 1; + } + argv[k] = strdup( l->is_obj ? "-c" : "-S"); k++; + argv[k] = strdup( "-o"); k++; + argv[k] = strdup( l->out_name); k++; + if ( c->cc_flags ) + { + int j = 0; + char *p = c->cc_flags + 0; + + while ( p[j] + && (k < 50) ) + { + while ( p[j] + && (p[j] == ' ') ) + { + j++; + } + + if ( p[j] ) + { + int h = 0; + + while ( p[j+h] + && (p[j+h] != ' ') ) + { + h++; + } + + argv[k] = strndup( p + j, h); k++; + j += h; + } + } + } + + argv[k] = 0; + assert( k < 50); + + return (k); +} /* lcbe_compile_module_args_init */ + +/** + * Компиляция модуля до ассемблерного файла. + */ +static int +lcbe_compile_module( lcbe_compile_t *l) +{ + char data[4096]; + int i; + int r = 0; + int k = 0; + int read_count = 0; + int write_count = 0; + int argc = 0; + FILE *f = 0; + char *argv[50] = {0}; + + /* Преобразуем представление модуля в Си-код. */ + lcbe_emit_c( l->m, l->src_name); + + /* Подготовка задачи компиляции. */ + argc = lcbe_compile_module_args_init( l, argv); + k += snprintf( data + k, lcbe_max( 0, 4096 - k), "gcc"); + for ( i = 0; i < argc; ++i ) + { + k += snprintf( data + k, lcbe_max( 0, 4096 - k), " %s", argv[i]); + free( argv[i]); + } + + if ( (k >= 4096) ) + { + return (-1); + } + + /* Выполнение задачи компиляции. */ + if ( l->info->conf.verbose ) + { + printf( "COMPILE: %s\n", data); + } + + if ( (system( data) != 0) ) + { + return (-1); + } + + /* Передача результирующего файла в выходной файловой поток. */ + f = fopen( l->out_name, "r"); + if ( !f ) + { + return (-1); + } + + while ( !feof( f) ) + { + int n = fread( data, 1, 4096, f); + + if ( (n < 0) ) + { + fclose( f); + return (-1); + + } else if ( (n > 0) ) + { + l->aci->write( l->aci->write_info, data, n); + } + } + + fclose( f); + + return (r); +} /* lcbe_compile_module */ + +/** + * Подготовка к работе. + */ +static int +lcbe_compile_module_init( lcbe_compile_t *l, lccrt_module_ptr m, lccrt_asm_compile_config_t *cnf) +{ + char s[1024]; + int r = 0; + int sl = 0; + int sfd = -1; + unsigned mode = 0; + + memset( l, 0, sizeof( l[0])); + l->info = &lcbe_info; + l->m = m; + l->aci = cnf; + l->ofd = -1; + l->out_name = 0; + l->src_name = 0; + + if ( getenv( "LCBE_TMP") ) + { + l->tmp_dir = strdup( getenv( "LCBE_TMP")); + } else + { + l->tmp_dir = strdup( "/tmp/lcbe"); + } + + if ( getenv( "LCBE_SAVE") ) + { + l->save_temps = atoi( getenv( "LCBE_SAVE")); + } + + if ( lcbe_str_eq( cnf->out_type, "asm") ) + { + l->is_obj = 0; + + } else if ( lcbe_str_eq( cnf->out_type, "obj") ) + { + l->is_obj = 1; + } else + { + return (-1); + } + + sl = snprintf( s, 1024, "mkdir -p -m a+rwx %s", l->tmp_dir); + if ( (sl >= 1024) + || (system( s) != 0) ) + { + return (-1); + } + + mode |= S_IRWXU; + mode |= S_IRWXG; + mode |= S_IRWXO; + sl = snprintf( s, 1024, "%s/%d.XXXXXX.%s", l->tmp_dir, getpid(), l->is_obj ? "o" : "s"); + if ( (sl >= 1024) ) + { + return (-1); + } + + l->out_name = strdup( s); + l->ofd = mkostemps( l->out_name, 2, mode); + if ( (l->ofd < 0) ) + { + return (-1); + } + + l->src_name = strdup( l->out_name); + l->src_name[sl - 1] = 'c'; +#if 0 + sfd = mkostemps( l->src_name, 2, mode); + if ( (sfd < 0) ) + { + return (-1); + } else + { + close( sfd); + } +#endif + + return (0); +} /* lcbe_compile_module_init */ + +/** + * Завершение работы. + */ +static int +lcbe_compile_module_done( lcbe_compile_t *l) +{ + int r = 0; + + if ( (l->ofd >= 0) ) + { + close( l->ofd); + if ( !l->save_temps ) + { + unlink( l->out_name); + } + } + + if ( l->out_name ) + { + free( l->out_name); + } + + if ( l->src_name ) + { + if ( !l->save_temps ) + { + unlink( l->src_name); + } + + free( l->src_name); + } + + if ( l->tmp_dir ) + { + free( l->tmp_dir); + } + + memset( l, 0, sizeof( l[0])); + + l->ofd = -1; + + return (r); +} /* lcbe_compile_module_done */ + +/** + * Компиляция модуля до ассемблерного файла. + */ +int +LCCRT_ASM_FUNC_COMPILE( lccrt_module_ptr m, + lccrt_asm_compile_config_t *cnf) +{ + int r = -1; + lcbe_compile_t *l = &lcbe_comp; + + if ( (lcbe_compile_module_init( l, m, cnf) == 0) + && (lcbe_compile_module( l) == 0) ) + { + r = 0; + } + + if ( (lcbe_compile_module_done( l) != 0) ) + { + r = -1; + } + + return (r); +} /* LCCRT_ASM_FUNC_COMPILE */ + +/** + * Старт внешней программы с перенаправлением стандартного потока вывода + * на канальный файловый дескриптор. При успешном запуске возвращается + * файловый дескриптор, доступный на чтение, с выводом внешней программы + * и номер процесса с внешней программой (wpid) для проверки успешного + * выполнения внешней программы (см. lcbe_waitpid). + */ +static int +lcbe_exec_open( pid_t *wpid, + const char *path, /* первый аргумент execv */ + char *argv[]) /* второй аргумент execv */ +{ + pid_t pid; + int fd[2] = {-1, -1}; + int r = -1; + + lcbe_assign( wpid, -1); + + if ( (pipe( fd) != 0) ) + { + /* Не удалось создать канал. */ + return (r); + } + + pid = fork(); + if ( (pid < 0) ) + { + /* Не удалось создать процесс. */ + return (r); + } + + if ( (pid == 0) ) + { + /* Запускаем внешнюю программу. */ + close( fd[0]); + dup2( fd[1], STDOUT_FILENO); + dup2( fd[1], STDERR_FILENO); + close( fd[1]); + execvp( path, argv); + } else + { + /* Возвращаем файловый дескриптор с выводом внешней программы. */ + close( fd[1]); + r = fd[0]; + if ( wpid ) + { + (*wpid) = pid; + } + } + + return (r); +} /* lcbe_exec_open */ + +/** + * Удаление старого значения и возврат копии нового значения, либо сохранение + * старого значения, если новое значение равно 0. + */ +static char * +lcbe_reinit_str( char *old_value, + const char *new_value) +{ + char *r = old_value; + + if ( new_value ) + { + r = strdup( new_value); + if ( old_value ) + { + free( old_value); + } + } + + return (r); +} /* lcbe_reinit_str */ + +/** + * Возврат конкатенация строк a и b с удалением строки a. + */ +static char * +lcbe_concat_str_by( char *a, + const char *b) +{ + char *r = 0; + + if ( !a ) + { + r = strdup( b); + } else + { + int la = strlen( a); + int lb = strlen( b); + + r = (char *)malloc( la + lb + 1); + strcpy( r, a); + strcpy( r + la, b); + free( a); + } + + return (r); +} /* lcbe_concat_str_by */ + +/** + * Возврат количества пробельных символов с начала строки (без учета перевода строки). + */ +static int +lcbe_skip_space( const char *s) +{ + int k = 0; + + while ( s[k] + && isspace( s[k]) + && (s[k] != '\n') ) + { + k++; + } + + return (k); +} /* lcbe_skip_space */ + +/** + * Возврат количества непробельных символов в начале строки. + */ +static int +lcbe_skip_str( const char *s) +{ + int k = 0; + + while ( s[k] + && !isspace( s[k]) + && (s[k] != '\n') ) + { + k++; + } + + return (k); +} /* lcbe_skip_str */ + +/** + * Чтение из файлового потока значений переменных. + */ +static int +lcbe_read_block( int fd, + char *block, + int size) +{ + int n; + int is_work = 1; + + n = 0; + while ( is_work ) + { + int l = read( fd, block + n, size - n); + + is_work = (l > 0); + n += l; + } + + return (n); +} /* lcbe_read_block */ + +/** + * Исполнение внешней команды с записью выходного потока. + */ +static int +lcbe_get_exec_result( const char *cmd, char **argv, int max_len, char res[]) +{ + int n = 0; + int fd = -1; + pid_t pid = -1; + + if ( res ) + { + res[0] = 0; + } + + fd = lcbe_exec_open( &pid, cmd, argv); + if ( (fd < 0) ) + { + assert( 0); + return (0); + } + + if ( res ) + { + n = lcbe_read_block( fd, res, max_len); + res[n] = 0; + if ( (n > 0) + && (res[n-1] == '\n') ) + { + res[n-1] = 0; + } + } + + if ( (lcbe_waitpid( pid) != 0) ) + { + int k = 0; + + fprintf( stderr, "Can't execute programm [%s] with arguments:", cmd); + while ( argv[k] ) + { + fprintf( stderr, " [%s]", argv[k]); + k++; + } + fprintf( stderr, "\n"); + close( fd); + abort(); + return (0); + } + + close( fd); + + return (n); +} /* lcbe_get_exec_result */ + +/** + * Получить путь до библиотек. + */ +static const char * +lcbe_get_include_path( const char *name, + int ptr_bit_size) +{ + const char *r = 0; + + if ( (strcmp( name, "c") == 0) ) + { + r = lcbe_info.tools.include_path; + + } else if ( (strcmp( name, "c++-stl") == 0) ) + { + r = lcbe_info.tools.include_cpp_stl_path; + } + + return (r); +} /* lcbe_get_include_path */ + +/** + * Получить путь до библиотек. + */ +static const char * +lcbe_get_lib_path( const char *name, + int ptr_bit_size) +{ + const char *r = 0; + + if ( (strcmp( name, "mvec") == 0) ) + { + if ( (ptr_bit_size == 32) ) + { + r = lcbe_info.tools.gcc_lib32_path; + } else + { + r = lcbe_info.tools.gcc_lib64_path; + } + } else if ( (strcmp( name, "c") == 0) ) + { + if ( (ptr_bit_size == 32) ) + { + r = lcbe_info.tools.lib32_path; + } else + { + r = lcbe_info.tools.lib64_path; + } + } + + return (r); +} /* lcbe_get_lib_path */ + +/** + * Получить для программы полный путь размещения программы. + */ +static const char * +lcbe_get_toolchain_path( const char *tool, + int ptr_bit_size) +{ + const char *r = 0; + + if ( (strcmp( tool, "ld") == 0) ) + { + r = lcbe_info.tools.ld_path; + + } else if ( (strcmp( tool, "as") == 0) ) + { + r = lcbe_info.tools.as_path; + + } else if ( (strcmp( tool, "gcc") == 0) ) + { + r = lcbe_info.tools.gcc_path; + + } else if ( (strcmp( tool, "fs") == 0) ) + { + r = lcbe_info.tools.fs; + } + + return (r); +} /* lcbe_get_toolchain_path */ + +/** + * Получить название программы вместе с полным путем. + */ +static const char * +lcbe_get_toolchain( const char *tool, + int ptr_bit_size) +{ + const char *r = 0; + + if ( (strcmp( tool, "ld") == 0) ) + { + r = lcbe_info.tools.ld; + + } else if ( (strcmp( tool, "as") == 0) ) + { + r = lcbe_info.tools.as; + } + + return (r); +} /* lcbe_get_toolchain */ + +/** + * Получить название или местоположение утилиты. + */ +const char * +LCCRT_ASM_FUNC_GETTOOL( const char *targ, const char *type, const char *name) +{ + const char *r = 0; + + if ( (strcmp( targ, "e2k32") == 0) + || (strcmp( targ, "e2k64") == 0) ) + { + int ptr_bits = (strcmp( targ, "e2k32") == 0) ? 32 : 64; + + if ( (strcmp( type, "tool") == 0) ) + { + r = lcbe_get_toolchain( name, ptr_bits); + + } else if ( (strcmp( type, "tool_path") == 0) ) + { + r = lcbe_get_toolchain_path( name, ptr_bits); + + } else if ( (strcmp( type, "lib_path") == 0) ) + { + r = lcbe_get_lib_path( name, ptr_bits); + + } else if ( (strcmp( type, "include_path") == 0) ) + { + r = lcbe_get_include_path( name, ptr_bits); + } + } + + r = r ? r : ""; + + return (r); +} /* LCCRT_ASM_FUNC_GETTOOL */ + +/** + * Разбор строки из конфигурационного файла в формате "name : value". + * (В строку s вставляются символы '0' и возвращаются указатели по подстроки.) + */ +static int +lcbe_parse_config_line( char *s, char **name, char **value) +{ + int r = 0; + int i = 0; + + i += lcbe_skip_space( s + i); + if ( (s[i] == 0) + || (s[i] == '#') ) + { + /* Встретили комментарий. */ + } else + { + int n0 = 0; + int n1 = 0; + int v0 = 0; + int v1 = 0; + + n0 = i; + i += lcbe_skip_str( s + i); + i = (s[i] == ':') ? (i - 1) : i; + n1 = i; + i += lcbe_skip_space( s + i); + if ( !((n0 < n1) + && (s[i] == ':')) ) + { + r = -1; + } else + { + r = 1; + i++; + i += lcbe_skip_space( s + i); + v0 = i; + while ( s[i] && (s[i] != '#') ) i++; + v1 = i; + (*name) = s + n0; + (*value) = s + v0; + s[n1] = 0; + v1--; + while ( (v1 >= v0) + && isspace( (int)s[v1]) ) + { + v1--; + } + s[v1+1] = 0; + } + } + + return (r); +} /* lcbe_parse_config_line */ + +/** + * Чтение настроек из файла конфигурации. + */ +static void +lcbe_parse_config_file( lcbe_config_t *cnf, lcbe_tools_t *tls) +{ + FILE *f = 0; + + f = fopen( cnf->lcbe_conf, "r"); + if ( !f ) + { + fprintf( stderr, "Can't open file with lcbe-configuration [%s]\n", cnf->lcbe_conf); + abort(); + } else + { + int n = 0; + char *ld = 0; + size_t ld_len = 0; + + while ( !feof( f) ) + { + int v = 0; + char *name = 0; + char *value = 0; + + if ( (getline( &ld, &ld_len, f) > 0) + && ((v = lcbe_parse_config_line( ld, &name, &value)) > 0) ) + { + if ( lcbe_str_eq( name, "cc-config") ) + { + cnf->lcbe_cc_config = lcbe_reinit_str( cnf->lcbe_cc_config, value); + + } else if ( lcbe_str_eq( name, "ld") ) + { + tls->ld = lcbe_reinit_str( tls->ld, value); + + } else if ( lcbe_str_eq( name, "as") ) + { + tls->as = lcbe_reinit_str( tls->as, value); + + } else if ( lcbe_str_eq( name, "fs") ) + { + tls->fs = lcbe_reinit_str( tls->fs, value); + + } else if ( lcbe_str_eq( name, "include") ) + { + tls->include_path = lcbe_reinit_str( tls->include_path, value); + + } else if ( lcbe_str_eq( name, "lib32") ) + { + tls->lib32_path = lcbe_reinit_str( tls->lib32_path, value); + + } else if ( lcbe_str_eq( name, "lib64") ) + { + tls->lib64_path = lcbe_reinit_str( tls->lib64_path, value); + + } else if ( lcbe_str_eq( name, "cc-base") ) + { + tls->gcc_base_path = lcbe_reinit_str( tls->gcc_base_path, value); + + } else if ( lcbe_str_eq( name, "cc-lib32") ) + { + tls->gcc_lib32_path = lcbe_reinit_str( tls->gcc_lib32_path, value); + + } else if ( lcbe_str_eq( name, "cc-lib64") ) + { + tls->gcc_lib64_path = lcbe_reinit_str( tls->gcc_lib64_path, value); + } else + { + fprintf( stderr, "Wrong parameter's name in file with cc-configuration [%s]\n", name); + v = -1; + } + } else if ( (v == -1) ) + { + fprintf( stderr, "Wrong format in file with cc-configuration!\n"); + } + + if ( (v == -1) ) + { + fprintf( stderr, " line number : %d\n", n); + fprintf( stderr, " line : [%s]\n", ld); + abort(); + } + + n++; + } + + if ( ld ) + { + free( ld); + } + } + + fclose( f); + + return; +} /* lcbe_parse_config_file */ + +/** + * Вычисление утилит на базе параметров конфигурации. + */ +static void +lcbe_init_library_tools( lcbe_config_t *cnf, lcbe_tools_t *tls) +{ + char buf[4096]; + char *ld_args[] = {"cc-config", "-print-prog-name=ld", 0}; + char *as_args[] = {"cc-config", "-print-prog-name=as", 0}; + char *fs_args[] = {"cc-config", "-print-config=fs-dir", 0}; + char *in_args[] = {"cc-config", "-print-internal-dir=include", 0}; + char *in_cpp_stl_args[] = {"cc-config", "-print-internal-dir=include-c++-stl", 0}; + char *gcc_base_args[] = {"cc-config", "-print-internal-dir=base", 0}; + + tls->ld = lcbe_reinit_str( tls->ld, getenv( "LCBE_LD")); + tls->as = lcbe_reinit_str( tls->as, getenv( "LCBE_AS")); + tls->include_path = lcbe_reinit_str( tls->include_path, getenv( "LCBE_INCLUDE")); + tls->lib32_path = lcbe_reinit_str( tls->lib32_path, getenv( "LCBE_LIB32")); + tls->lib64_path = lcbe_reinit_str( tls->lib64_path, getenv( "LCBE_LIB64")); + tls->gcc_base_path = lcbe_reinit_str( tls->gcc_base_path, getenv( "LCBE_CC_BASE")); + tls->gcc_lib32_path = lcbe_reinit_str( tls->gcc_base_path, getenv( "LCBE_CC_LIB32")); + tls->gcc_lib64_path = lcbe_reinit_str( tls->gcc_base_path, getenv( "LCBE_CC_LIB64")); + tls->fs = lcbe_reinit_str( tls->fs, getenv( "LCBE_FS")); + + if ( !cnf->lcbe_cc_config ) + { + if ( !tls->ld + || !tls->as + || !tls->fs + || !tls->gcc_base_path ) + { + fprintf( stderr, "One of variables [ld], [as], [lcc-base] or [fs] doesn't set, " + "but [lcc-config] utility is unknown!\n"); + abort(); + } + } + + if ( 0 ) + { + if ( !tls->ld ) + { + lcbe_get_exec_result( cnf->lcbe_cc_config, ld_args, 4095, buf); + tls->ld = lcbe_reinit_str( 0, buf); + } + + if ( !tls->as ) + { + lcbe_get_exec_result( cnf->lcbe_cc_config, as_args, 4095, buf); + tls->as = lcbe_reinit_str( 0, buf); + } + + if ( !tls->fs ) + { + lcbe_get_exec_result( cnf->lcbe_cc_config, fs_args, 4095, buf); + tls->fs = lcbe_reinit_str( 0, buf); + } + + if ( !tls->gcc_base_path ) + { + lcbe_get_exec_result( cnf->lcbe_cc_config, gcc_base_args, 4095, buf); + tls->gcc_base_path = lcbe_reinit_str( 0, buf); + } + + tls->ld_path = dirname( strdup( tls->ld)); + tls->as_path = dirname( strdup( tls->ld)); + + if ( !tls->gcc_lib32_path ) + { + snprintf( buf, 4096, "ls -l %s/lib/ptr32 >& /dev/null", tls->gcc_base_path); + snprintf( buf, 4096, "%s/lib%s", tls->gcc_base_path, (system( buf) == 0) ? "/ptr32" : "32"); + tls->gcc_lib32_path = lcbe_reinit_str( 0, buf); + } + + if ( !tls->gcc_lib64_path ) + { + snprintf( buf, 4096, "ls -l %s/lib/ptr64 >& /dev/null", tls->gcc_base_path); + snprintf( buf, 4096, "%s/lib%s", tls->gcc_base_path, (system( buf) == 0) ? "/ptr64" : "64"); + tls->gcc_lib64_path = lcbe_reinit_str( 0, buf); + } + + if ( !tls->include_path ) + { + lcbe_get_exec_result( cnf->lcbe_cc_config, in_args, 4095, buf); + tls->include_path = lcbe_reinit_str( 0, buf); + } + + if ( !tls->include_cpp_stl_path ) + { + lcbe_get_exec_result( cnf->lcbe_cc_config, in_cpp_stl_args, 4095, buf); + tls->include_cpp_stl_path = lcbe_reinit_str( 0, buf); + } + + if ( !tls->lib32_path ) + { + snprintf( buf, 4096, "%s/usr/lib32", tls->fs); + tls->lib32_path = lcbe_reinit_str( 0, buf); + } + + if ( !tls->lib64_path ) + { + snprintf( buf, 4096, "%s/usr/lib64", tls->fs); + tls->lib64_path = lcbe_reinit_str( 0, buf); + } + } + + return; +} /* lcbe_init_library_tools */ + +/** + * Вычисление базовых параметров конфигурации библиотеки. + */ +static void +lcbe_init_config( lcbe_config_t *cnf, lcbe_tools_t *tls) +{ + Dl_info dli; + char *s = 0; + char *t = 0; + + memset( cnf, 0, sizeof( cnf[0])); + memset( tls, 0, sizeof( tls[0])); + + cnf->verbose = lcbe_is_option( "LCBE_VERBOSE", 0) ? ~0 : 0; + + dladdr( (void *)&lcbe_init_config, &dli); + s = strdup( dli.dli_fname); + cnf->lcbe_conf = lcbe_concat_str_by( strdup( basename( s)), ".conf"); + free( s); + + s = getenv( "LCBE_HOME"); + if ( s ) + { + s = strdup( s); + } else + { + t = realpath( dli.dli_fname, 0); + if ( !t ) + { + fprintf( stderr, "Can't resolve real path of lcbe-library's location [%s]\n", dli.dli_fname); + abort(); + } + + s = dirname( t); + if ( !s ) + { + fprintf( stderr, "Can't resolve directory of lcbe-library's location [%s]\n", t); + abort(); + } + + s = strdup( s); + free( t); + } + + t = cnf->lcbe_conf; + cnf->lcbe_home = s; + cnf->lcbe_conf = lcbe_concat_str_by( lcbe_concat_str_by( strdup( s), "/"), t); + free( t); + cnf->lcbe_conf = lcbe_reinit_str( cnf->lcbe_conf, getenv( "LCBE_CONF")); + + if ( cnf->verbose ) + { + fprintf( stderr, "\nLCBE (LCCRT-plugin) library config:\n\n"); + fprintf( stderr, " LCBE_VERBOSE : %s\n", getenv( "LCBE_VERBOSE")); + fprintf( stderr, " LCBE_HOME : %s\n", cnf->lcbe_home); + fprintf( stderr, " LCBE_CONF : %s\n", cnf->lcbe_conf); + } + + lcbe_parse_config_file( cnf, tls); + cnf->lcbe_cc_config = lcbe_reinit_str( cnf->lcbe_cc_config, getenv( "LCBE_CC_CONFIG")); + + if ( cnf->verbose ) + { + fprintf( stderr, " LCBE_CC_CONFIG : %s\n", cnf->lcbe_cc_config); + } + + lcbe_init_library_tools( cnf, tls); + + if ( cnf->verbose ) + { + fprintf( stderr, " LCBE_LD : %s\n", tls->ld); + fprintf( stderr, " LCBE_AS : %s\n", tls->as); + fprintf( stderr, " LCBE_FS : %s\n", tls->fs); + fprintf( stderr, " LCBE_INCLUDE : %s\n", tls->include_path); + fprintf( stderr, " LCBE_INCLUDE_CPP_STL : %s\n", tls->include_cpp_stl_path); + fprintf( stderr, " LCBE_LIB32 : %s\n", tls->lib32_path); + fprintf( stderr, " LCBE_LIB64 : %s\n", tls->lib64_path); + fprintf( stderr, " LCBE_CC_BASE : %s\n", tls->gcc_base_path); + fprintf( stderr, " LCBE_CC_LIB32 : %s\n", tls->gcc_lib32_path); + fprintf( stderr, " LCBE_CC_LIB64 : %s\n", tls->gcc_lib64_path); + } + + return; +} /* lcbe_init_config */ + +/** + * Инициализация библиотеки. + */ +static void +lcbe_init( void) +{ + lcbe_tools_t *t = &(lcbe_info.tools); + lcbe_config_t *c = &(lcbe_info.conf); + + lcbe_init_config( c, t); + + c->cc_flags = lcbe_get_option( "LCBE_CFLAGS", 0); + c->save_temps = lcbe_get_option( "LCBE_SAVE", 0); + + if ( c->verbose ) + { + fprintf( stderr, " LCBE_CFLAGS : %s\n", c->cc_flags); + fprintf( stderr, " LCBE_SAVE : %s\n", c->save_temps); + fprintf( stderr, "\n"); + } + + return; +} /* lcbe_init */ + +/** + * Завершение работы библиотеки. + */ +static void +lcbe_done( void) +{ + return; +} /* lcbe_done */ + diff --git a/tools/lcbe/src/lcbe_emit.cpp b/tools/lcbe/src/lcbe_emit.cpp new file mode 100644 index 0000000..3619fb6 --- /dev/null +++ b/tools/lcbe/src/lcbe_emit.cpp @@ -0,0 +1,2345 @@ +/** + * 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 + */ + +#include "lcbe_real.h" + +/** + * Преобразование типа tls-линковки в название атрибута. + */ +static const char *lcbe_Tls[] = +{ + /* LCCRT_LINK_TLS_NO */ 0, + /* LCCRT_LINK_TLS_DYNAMIC_G */ "__TLS_GD", + /* LCCRT_LINK_TLS_DYNAMIC_L */ "__TLS_LD", + /* LCCRT_LINK_TLS_EXEC_I */ "__TLS_EI", + /* LCCRT_LINK_TLS_EXEC_L */ "__TLS_EL", +}; + +/** + * Преобразование типа видимости в название атрибута. + */ +static const char *lcbe_Vis[] = +{ + /* LCCRT_LINK_VIS_DEFAULT */ 0, + /* LCCRT_LINK_VIS_INTERNAL */ "__VIS_IN", + /* LCCRT_LINK_VIS_HIDDEN */ "__VIS_HD", + /* LCCRT_LINK_VIS_PROTECTED */ "__VIS_PT" +}; + +/** + * Базовая структура модуля трансляции Си-кода. + */ +typedef struct +{ + lccrt_module_ptr m; /* транслируемый модуль */ + FILE *f; /* выходной Си-файл */ + lccrt_context_ptr ctx; /* локальный lccrt-контекст для технических нужд */ + lccrt_function_ptr cur_func; /* текущая транслируемая в модуле функция */ + lccrt_hash_ptr type_to_ident; /* соответствие: lccrt-тип => идентификатор */ + lccrt_hash_ptr type_to_name; /* соответствие: lccrt-тип => короткая форма Си-типа */ + lccrt_hash_ptr type_to_namefr; /* соответствие: lccrt-тип => короткая форма Си-типа */ + unsigned tname_ident; /* идентификатор следующего имени для типа */ + unsigned oname_ident; /* идентификатор следующего имени для объекта */ + unsigned lname_ident; /* идентификатор следующего имени для локальной переменной */ + lccrt_hash_ptr obj_to_name; /* соответствие: lccrt-объект => Си-имя, где объект - переменная или функция */ + lccrt_hash_ptr obj_to_namefr; /* соответствие: lccrt-объект => Си-имя, где объект - переменная или функция */ + lccrt_hash_ptr local_to_name; /* соответствие: lccrt-локал => Си-имя */ + lccrt_hash_ptr oper_to_name; /* соответствие: lccrt-метка операция => Си-имя */ +} lcbe_emit_t; + +/** + * Проверка типа на простое значение константы. + */ +static int +lcbe_emit_is_type_const_simple( lccrt_type_ptr type) +{ + int r = 0; + + if ( (lccrt_type_is_int( type) + && (lccrt_type_get_bytesize( type) <= 8)) + || lccrt_type_is_pointer( type) ) + { + r = 1; + } + + return (r); +} /* lcbe_emit_is_type_const_simple */ + +/** + * Удаление таблицы отображающей указатели на строки. + */ +static lccrt_hash_ptr +lcbe_name_hash_delete( lccrt_hash_ptr tbl) +{ + lccrt_he_ptr he; + + for ( he = lccrt_hash_first( tbl); he; he = lccrt_hash_next( he) ) + { + free( (char *)lccrt_hash_get( he)); + } + + lccrt_hash_delete( tbl); + + return (0); +} /* lcbe_name_hash_delete */ + +/** + * Печать строки с экранированием. + */ +static int +lcbe_fprint_symbol( lcbe_emit_t *ei, char c) +{ + if ( (c == '"') ) + { + fputs( "\\\"", ei->f); + + } else if ( (c == '\\') ) + { + fputs( "\\\\", ei->f); + + } else if ( (c == '\t') ) + { + fputs( "\\t", ei->f); + + } else if ( (c == '\n') ) + { + fputs( "\\n", ei->f); + + } else if ( isprint( c) ) + { + fputc( c, ei->f); + } else + { + fprintf( ei->f, "\\x%02x", (uint8_t)c); + } + + return (0); +} /* lcbe_fprint_symbol */ + +/** + * Печать строки с экранированием. + */ +static int +lcbe_fprint( lcbe_emit_t *ei, const char *s) +{ + int i; + + for ( i = 0; s[i]; ++i ) + { + lcbe_fprint_symbol( ei, s[i]); + } + + return (0); +} /* lcbe_fprint */ + +/** + * Выравнивание "выравнивания". + */ +static int64_t +lcbe_calc_align( int64_t align) +{ + int64_t r = 1; + + if ( (align < 0) ) + { + assert( 0); + + } else if ( (align == 0) ) + { + } else + { + while ( (r < 16) && (align % (2*r) == 0) ) + { + r = 2*r; + } + } + + return (r); +} /* lcbe_calc_align */ + +/** + * Получить идентификатор для типа. + */ +static unsigned +lcbe_emit_get_type_ident( lcbe_emit_t *ei, lccrt_type_ptr type) +{ + lccrt_he_ptr he = lccrt_hash_find( ei->type_to_ident, (uintptr_t)type); + unsigned r = lccrt_hash_get( he); + + return (r); +} /* lcbe_emit_get_type_ident */ + +/** + * Получить короткую форму Си-типа для ранее транслированного типа. + */ +static const char * +lcbe_emit_get_type_name( lcbe_emit_t *ei, lccrt_type_ptr type) +{ + lccrt_he_ptr he = lccrt_hash_find( ei->type_to_name, (uintptr_t)type); + char *r = (char *)lccrt_hash_get( he); + + return (r); +} /* lcbe_emit_get_type_name */ + +/** + * Получить короткую форму Си-типа для ранее транслированного типа. + */ +static const char * +lcbe_emit_get_type_namefr( lcbe_emit_t *ei, lccrt_type_ptr type) +{ + lccrt_he_ptr he = lccrt_hash_find( ei->type_to_namefr, (uintptr_t)type); + const char *r = (char *)lccrt_hash_get( he); + + r = r ? r : lcbe_emit_get_type_name( ei, type); + + return (r); +} /* lcbe_emit_get_type_namefr */ + +/** + * Получить короткую форму Си-типа для соответствующего целого типа. + */ +static const char * +lcbe_emit_get_type_int_name( lcbe_emit_t *ei, lccrt_type_ptr type0, int sign) +{ + lccrt_type_ptr type1 = 0; + const char *r = 0; + + if ( lccrt_type_is_vector( type0) ) + { + type0 = lccrt_type_get_parent( type0); + } + + type1 = lccrt_type_make_int( ei->m, lccrt_type_get_bytesize( type0), sign); + r = lcbe_emit_get_type_name( ei, type1); + + return (r); +} /* lcbe_emit_get_type_int_name */ + +/** + * Проверка имени на возможность использования в качестве Си-имени. + */ +static int +lcbe_is_name_normal( const char *name) +{ + int i; + int r = 0; + + if ( (strcmp( name, "default") == 0) + || (strcmp( name, "switch") == 0) + || (strcmp( name, "case") == 0) + || (strcmp( name, "if") == 0) + || (strcmp( name, "else") == 0) ) + { + } else if ( (name[0] == '_') + || isalpha( name[0]) ) + { + r = 1; + for ( i = 0; name[i]; ++i ) + { + if ( !((i < 256) + && ((name[i] == '_') + || isalnum( name[i]))) ) + { + r = 0; + break; + } + } + } + + return (r); +} /* lcbe_is_name_normal */ + +/** + * Получить Си-название для функции или переменной. + */ +static const char * +lcbe_emit_get_obj_name( lcbe_emit_t *ei, void *obj, int is_func) +{ + const char *r = 0; + const char *name = 0; + + if ( is_func ) + { + name = lccrt_function_get_name( (lccrt_function_ptr)obj); + } else + { + name = lccrt_var_get_name( (lccrt_var_ptr)obj); + } + + if ( lcbe_is_name_normal( name) ) + { + r = name; + } else + { + int is_new; + lccrt_he_ptr he = lccrt_hash_push( ei->obj_to_name, (uintptr_t)obj, &is_new); + + if ( is_new ) + { + char buf[1024]; + + snprintf( buf, 1024, is_func ? "__func%d" : "__g%d", ei->oname_ident); + ei->oname_ident++; + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + } + + r = (char *)lccrt_hash_get( he); + } + + if ( !is_func ) + { + lccrt_type_ptr type = lccrt_var_get_type( (lccrt_var_ptr)obj); + lccrt_he_ptr he = lccrt_hash_find( ei->obj_to_namefr, (uintptr_t)obj); + + if ( he ) + { + r = (char *)lccrt_hash_get( he); + } + } + + return (r); +} /* lcbe_emit_get_obj_name */ + +/** + * Получить Си-название для локальной переменной. + */ +static const char * +lcbe_emit_get_local_name( lcbe_emit_t *ei, lccrt_var_ptr var) +{ + const char *r = 0; + const char *name = lccrt_var_get_name( var); + + if ( lcbe_is_name_normal( name) ) + { + r = name; + } else + { + int is_new; + lccrt_he_ptr he = lccrt_hash_push( ei->local_to_name, (uintptr_t)var, &is_new); + + if ( is_new ) + { + char buf[1024]; + + snprintf( buf, 1024, "__v%d", ei->lname_ident); + ei->lname_ident++; + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + } + + r = (char *)lccrt_hash_get( he); + } + + return (r); +} /* lcbe_emit_get_local_name */ + +/** + * Получить Си-название для переменной. + */ +static const char * +lcbe_emit_get_var_name( lcbe_emit_t *ei, lccrt_var_ptr var) +{ + const char *r = 0; + lccrt_type_ptr type = lccrt_var_get_type( var); + + if ( lccrt_var_is_local( var) ) + { + r = lcbe_emit_get_local_name( ei, var); + } else + { + if ( lccrt_var_is_constarg( var) + && lcbe_emit_is_type_const_simple( type) ) + { + ; + } else + { + r = lcbe_emit_get_obj_name( ei, var, 0); + } + } + + return (r); +} /* lcbe_emit_get_var_name */ + +/** + * Получение названия метки. + */ +static const char * +lcbe_emit_oper_get_label( lcbe_emit_t *ei, lccrt_oper_ptr oper) +{ + const char *r = lccrt_oper_get_label( oper); + + if ( !lcbe_is_name_normal( r) ) + { + int is_new; + lccrt_he_ptr he = lccrt_hash_push( ei->oper_to_name, (uintptr_t)oper, &is_new); + + if ( is_new ) + { + char buf[1024]; + + snprintf( buf, 1024, "__label_%d", ei->lname_ident); + ei->lname_ident++; + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + } + + r = (char *)lccrt_hash_get( he); + } + + return (r); +} /* lcbe_emit_oper_get_label */ + +/** + * Эммиссия типа и его предшествующих типов. + */ +static int +lcbe_emit_type( lcbe_emit_t *ei, lccrt_type_ptr type) +{ + int i; + int is_new; + lccrt_type_ptr cur_type; + char buf[1024]; + lccrt_type_ptr parent = lccrt_type_get_parent( type); + lccrt_he_ptr he = lccrt_hash_push( ei->type_to_name, (uintptr_t)type, &is_new); + + if ( is_new ) + { + lccrt_hash_set( he, 0); + } + + if ( !is_new ) + { + return (0); + + } else if ( lccrt_type_is_field( type) ) + { + } else if ( lccrt_type_is_ellipsis( type) ) + { + lccrt_hash_set( he, (uintptr_t)strdup( "...")); + + } else if ( lccrt_type_is_void( type) ) + { + lccrt_hash_set( he, (uintptr_t)strdup( "void")); + + } else if ( lccrt_type_is_bool( type) ) + { + lccrt_hash_set( he, (uintptr_t)strdup( "uint8_t")); + + } else if ( lccrt_type_is_int( type) ) + { + if ( (lccrt_type_get_bytesize( type) == 16) ) + { + snprintf( buf, 1024, "__type_%sint128", lccrt_type_get_sign( type) ? "" : "u"); + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + } else + { + snprintf( buf, 1024, "%sint%d_t", lccrt_type_get_sign( type) ? "" : "u", + 8*lccrt_type_get_bytesize( type)); + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + } + } else if ( lccrt_type_is_float( type) ) + { + if ( (lccrt_type_get_bytesize( type) == 4) ) + { + lccrt_hash_set( he, (uintptr_t)strdup( "__type_float32")); + //lccrt_hash_set( he, (uintptr_t)strdup( "float")); + + } else if ( (lccrt_type_get_bytesize( type) == 8) ) + { + lccrt_hash_set( he, (uintptr_t)strdup( "__type_float64")); + //lccrt_hash_set( he, (uintptr_t)strdup( "double")); + + } else if ( (lccrt_type_get_bytesize( type) == 10) ) + { + lccrt_hash_set( he, (uintptr_t)strdup( "__type_float80")); + //lccrt_hash_set( he, (uintptr_t)strdup( "long double")); + + } else if ( (lccrt_type_get_bytesize( type) == 16) ) + { + assert( 0); + lccrt_hash_set( he, (uintptr_t)strdup( "__type_float128")); + } else + { + assert( 0); + return (-1); + } + } else if ( lccrt_type_is_pointer( type) ) + { + lcbe_emit_type( ei, parent); + snprintf( buf, 1024, "%s*", lcbe_emit_get_type_name( ei, parent)); + lccrt_hash_set( lccrt_hash_push( ei->type_to_name, (uintptr_t)type, 0), (uintptr_t)strdup( buf)); + + } else if ( lccrt_type_is_array( type) ) + { + snprintf( buf, 1024, "__type_arr%d", lcbe_emit_get_type_ident( ei, type)); + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + lcbe_emit_type( ei, parent); + fprintf( ei->f, "typedef %s %s[%jd];\n", lcbe_emit_get_type_name( ei, parent), buf, + lccrt_type_get_num_args( type)); + + } else if ( lccrt_type_is_vector( type) ) + { + int is_pointer = lccrt_type_is_pointer( parent); + int is_bool = lccrt_type_is_bool( parent); + + snprintf( buf, 1024, "__type_vec%d", lcbe_emit_get_type_ident( ei, type)); + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + lcbe_emit_type( ei, parent); + fprintf( ei->f, "typedef struct { %s v[%jd]; } %s;\n", lcbe_emit_get_type_name( ei, parent), + lccrt_type_get_num_args( type), buf); + fprintf( ei->f, "__VEC_TYPE%s(%jd,%s,%s)\n", is_pointer ? "_POINTER" : (is_bool ? "_BOOL" : ""), + lccrt_type_get_num_args( type), buf, lcbe_emit_get_type_name( ei, parent)); + + } else if ( lccrt_type_is_typename( type) ) + { + snprintf( buf, 1024, "__type_name%d", lcbe_emit_get_type_ident( ei, type)); + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + + } else if ( lccrt_type_is_struct( type) ) + { + uint64_t i_pad_ident = 0; + uint64_t shift = 0; + uint64_t align = lcbe_calc_align( lccrt_type_get_bytealign( type)); + + assert( !lccrt_type_is_union( type)); + snprintf( buf, 1024, "__type_struct%d", lcbe_emit_get_type_ident( ei, type)); + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + + for ( i = 0; i < lccrt_type_get_num_args( type); ++i ) + { + lcbe_emit_type( ei, lccrt_type_get_parent( lccrt_type_get_arg( type, i))); + } + + fprintf( ei->f, "typedef struct __PACKED __ALIGN( %jd) __type_tag%d {\n", + align, lcbe_emit_get_type_ident( ei, type)); + for ( i = 0; i < lccrt_type_get_num_args( type); ++i ) + { + int64_t fld_align = 1; + lccrt_type_ptr fld = lccrt_type_get_arg( type, i); + uint64_t fld_shift = lccrt_type_get_byteshift( fld); + uint64_t fld_size = lccrt_type_get_bytesize( fld); + + if ( (fld_shift != shift) ) + { + int i_pad; + int64_t delta = fld_shift - shift; + +#if 0 + for ( i_pad = 0; i_pad < delta; ++i_pad, ++i_pad_ident ) + { + fprintf( ei->f, " uint8_t pad%d;\n", i_pad_ident); + } +#endif + + for ( i_pad = 1; i_pad < 32; i_pad = 2*i_pad ) + { + if ( (shift % i_pad != 0) + && (fld_shift % i_pad == 0) + && (i_pad > delta) ) + { + fld_align = i_pad; + break; + } + } + + if ( (fld_align == 1) ) + { + assert( 0); + } + } + + assert( align % fld_align == 0); + fprintf( ei->f, " %s a%d", lcbe_emit_get_type_name( ei, lccrt_type_get_parent( fld)), i); + if ( (fld_align > 1) ) + { + fprintf( ei->f, " __ALIGN(%jd)", fld_align); + } + + fprintf( ei->f, "; // shift:%jd size:%jd", fld_shift, lccrt_type_get_bytesize( fld)); + fprintf( ei->f, "\n"); + + shift = fld_shift + fld_size; + } + + fprintf( ei->f, "} %s;\n", buf); + + } else if ( lccrt_type_is_function( type) ) + { + snprintf( buf, 1024, "__type_func%d", lcbe_emit_get_type_ident( ei, type)); + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + + lcbe_emit_type( ei, parent); + for ( i = 0; i < lccrt_type_get_num_args( type); ++i ) + { + lcbe_emit_type( ei, lccrt_type_get_arg( type, i)); + } + + fprintf( ei->f, "typedef %s (* %s)(", lcbe_emit_get_type_name( ei, parent), buf); + if ( (lccrt_type_get_num_args( type) == 1) + && lccrt_type_is_ellipsis( lccrt_type_get_arg( type, 0)) ) + { + } else + { + for ( i = 0; i < lccrt_type_get_num_args( type); ++i ) + { + cur_type = lccrt_type_get_arg( type, i); + fprintf( ei->f, "%s %s", (i > 0) ? "," : "", lcbe_emit_get_type_name( ei, cur_type)); + } + } + + fprintf( ei->f, ");\n"); + } else + { + assert( 0); + return (-1); + } + + return (0); +} /* lcbe_emit_type */ + +/** + * Эммиссия типа и его предшествующих типов. + */ +static int +lcbe_emit_typefr( lcbe_emit_t *ei, lccrt_type_ptr type, const char **namefr) +{ + int i; + int is_new; + char buf[1024]; + const char *elem_namefr = 0; + lccrt_type_ptr elem_parent = 0; + lccrt_type_ptr parent = lccrt_type_get_parent( type); + lccrt_he_ptr he = lccrt_hash_push( ei->type_to_namefr, (uintptr_t)type, &is_new); + + namefr[0] = 0; + if ( is_new ) + { + lccrt_hash_set( he, 0); + } + + if ( !is_new ) + { + namefr[0] = (char *)lccrt_hash_get( he); + + } else if ( lccrt_type_is_int( type) ) + { + if ( lccrt_type_get_bytesize( type) == 16 ) + { + if ( lccrt_type_get_sign( type) ) + { + namefr[0] = "__type_int128_fr"; + lccrt_hash_set( he, (uintptr_t)strdup( namefr[0])); + } else + { + namefr[0] = "__type_uint128_fr"; + lccrt_hash_set( he, (uintptr_t)strdup( namefr[0])); + } + } + } else if ( lccrt_type_is_float( type) ) + { + if ( (lccrt_type_get_bytesize( type) == 4) ) + { + namefr[0] = "__type_float32_fr"; + + } else if ( (lccrt_type_get_bytesize( type) == 8) ) + { + namefr[0] = "__type_float64_fr"; + + } else if ( (lccrt_type_get_bytesize( type) == 10) ) + { + namefr[0] = "__type_float80_fr"; + + } else if ( (lccrt_type_get_bytesize( type) == 16) ) + { + assert( 0); + namefr[0] = "__type_float128_fr"; + } else + { + assert( 0); + return (-1); + } + + lccrt_hash_set( he, (uintptr_t)strdup( namefr[0])); + + } else if ( lccrt_type_is_array( type) + || lccrt_type_is_vector( type) ) + { + lcbe_emit_typefr( ei, parent, &elem_namefr); + if ( elem_namefr ) + { + snprintf( buf, 1024, "__type_arr%d_fr", lcbe_emit_get_type_ident( ei, type)); + he = lccrt_hash_push( ei->type_to_namefr, (uintptr_t)type, 0); + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + fprintf( ei->f, "typedef %s %s[%jd];\n", elem_namefr, buf, lccrt_type_get_num_args( type)); + } + } else if ( lccrt_type_is_struct( type) ) + { + int is_fr = 0; + uint64_t shift = 0; + uint64_t align = lcbe_calc_align( lccrt_type_get_bytealign( type)); + + assert( !lccrt_type_is_union( type)); + for ( i = 0; i < lccrt_type_get_num_args( type); ++i ) + { + elem_parent = lccrt_type_get_parent( lccrt_type_get_arg( type, i)); + lcbe_emit_typefr( ei, elem_parent, &elem_namefr); + if ( elem_namefr ) + { + is_fr = 1; + } + } + + if ( is_fr ) + { + snprintf( buf, 1024, "__type_struct%d_fr", lcbe_emit_get_type_ident( ei, type)); + he = lccrt_hash_push( ei->type_to_namefr, (uintptr_t)type, 0); + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + + fprintf( ei->f, "typedef struct __PACKED __ALIGN( %jd) {\n", + align, lcbe_emit_get_type_ident( ei, type)); + + for ( i = 0; i < lccrt_type_get_num_args( type); ++i ) + { + int64_t fld_align = 1; + lccrt_type_ptr fld = lccrt_type_get_arg( type, i); + uint64_t fld_shift = lccrt_type_get_byteshift( fld); + uint64_t fld_size = lccrt_type_get_bytesize( fld); + + if ( (fld_shift != shift) ) + { + int64_t delta = fld_shift - shift; + + while ( (fld_align < delta) ) + { + fld_align = 2*fld_align; + } + + assert( fld_align <= 16); + } + + assert( align % fld_align == 0); + elem_parent = lccrt_type_get_parent( lccrt_type_get_arg( type, i)); + fprintf( ei->f, " %s a%d", lcbe_emit_get_type_namefr( ei, elem_parent), i); + if ( (fld_align > 1) ) + { + fprintf( ei->f, " __ALIGN(%jd)", fld_align); + } + + fprintf( ei->f, "; // shift:%jd size:%jd", fld_shift, lccrt_type_get_bytesize( fld)); + fprintf( ei->f, "\n"); + + shift = fld_shift + fld_size; + } + + fprintf( ei->f, "} %s;\n", buf); + } + } else + { + } + + return (0); +} /* lcbe_emit_typefr */ + +/** + * Трансляция всех типов модуля. + */ +static int +lcbe_emit_types( lcbe_emit_t *ei) +{ + lccrt_type_ptr type; + unsigned ident = 0; + + for ( type = lccrt_module_get_first_type( ei->m); type; type = lccrt_type_get_next_type( type) ) + { + if ( !lccrt_type_is_field( type) + && !lccrt_type_is_pointer( type) ) + { + lccrt_hash_set( lccrt_hash_push( ei->type_to_ident, (uintptr_t)type, 0), ei->tname_ident); + ei->tname_ident++; + } + } + + fprintf( ei->f, "\n"); + fprintf( ei->f, "// TAGS for TYPENAMES\n"); + for ( type = lccrt_module_get_first_type( ei->m); type; type = lccrt_type_get_next_type( type) ) + { + if ( lccrt_type_is_typename( type) ) + { + lccrt_type_ptr parent = lccrt_type_get_parent( type); + + ident = lcbe_emit_get_type_ident( ei, type); + if ( parent ) + { + assert( lccrt_type_is_struct( parent)); + fprintf( ei->f, "typedef struct __type_tag%d __type_name%d;\n", + lcbe_emit_get_type_ident( ei, parent), ident); + } else + { + fprintf( ei->f, "typedef void __type_name%d;\n", ident); + } + } + } + + fprintf( ei->f, "\n"); + fprintf( ei->f, "// TYPES\n"); + for ( type = lccrt_module_get_first_type( ei->m); type; type = lccrt_type_get_next_type( type) ) + { + lcbe_emit_type( ei, type); + } + + for ( type = lccrt_module_get_first_type( ei->m); type; type = lccrt_type_get_next_type( type) ) + { + const char *namefr; + + lcbe_emit_typefr( ei, type, &namefr); + } + + return (0); +} /* lcbe_emit_types */ + +/** + * Печать в буфер "простой" константы. + */ +static char * +lcbe_emit_varinit_simple_sprint( lcbe_emit_t *ei, char *buf, int len, lccrt_varinit_ptr vi) +{ + char *r = 0; + int rlen; + lccrt_type_ptr type = lccrt_varinit_get_type( vi); + const char *st = lcbe_emit_get_type_name( ei, type); + + if ( lccrt_varinit_is_hex( vi) ) + { + if ( lccrt_type_is_bool( type) + || lccrt_type_is_int( type) ) + { + r = buf; + rlen = snprintf( buf, len, "((%s)0x%jxULL)", st, lccrt_varinit_get_hex64( vi)); + + } else if ( lccrt_type_is_float( type) ) + { + if ( (lccrt_type_get_bytesize( type) == 4) + || (lccrt_type_get_bytesize( type) == 8) ) + { + r = buf; + rlen = snprintf( buf, len, "((%s_fr){i:0x%jxULL})", st, lccrt_varinit_get_hex64( vi)); + } else + { + assert( 0); + } + } else if ( lccrt_type_is_pointer( type) ) + { + r = buf; + rlen = snprintf( buf, len, "((%s)((uintptr_t)%jxULL))", st, lccrt_varinit_get_hex64( vi)); + } else + { + assert( 0); + } + } else if ( lccrt_varinit_is_addr_var( vi) + || lccrt_varinit_is_addr_func( vi) ) + { + int is_var = lccrt_varinit_is_addr_var( vi); + void *obj = is_var ? (void *)lccrt_varinit_get_addr_var( vi) : (void *)lccrt_varinit_get_addr_func( vi); + const char *s = lcbe_emit_get_obj_name( ei, obj, !is_var); + + if ( lccrt_varinit_get_num_elems( vi) ) + { + r = buf; + rlen = snprintf( buf, len, "((%s)((char *)&%s + %jd))", st, s, lccrt_varinit_get_num_elems( vi)); + } else + { + r = buf; + if ( 1 || is_var ) + { + rlen = snprintf( buf, len, "((%s)&%s)", st, s); + } else + { + rlen = snprintf( buf, len, "((%s)%s)", lcbe_emit_get_type_name( ei, lccrt_type_get_parent( type)), s); + } + } + } else if ( lccrt_varinit_is_zero( vi) ) + { + r = buf; + rlen = snprintf( buf, len, "((%s)0)", st); + } else + { + assert( 0); + } + + if ( r + && (rlen >= len) ) + { + r = 0; + assert( 0); + } + + return (r); +} /* lcbe_emit_varinit_simple_sprint */ + +/** + * Трансляция инициализатора переменной. + */ +static int +lcbe_emit_varinit( lcbe_emit_t *ei, lccrt_varinit_ptr vi) +{ + char buf[1024]; + lccrt_type_ptr type = lccrt_varinit_get_type( vi); + + if ( lccrt_varinit_is_hex( vi) ) + { + fprintf( ei->f, "%s", lcbe_emit_varinit_simple_sprint( ei, buf, 1024, vi)); + + } else if ( lccrt_varinit_is_addr_var( vi) + || lccrt_varinit_is_addr_func( vi) ) + { + fprintf( ei->f, "%s", lcbe_emit_varinit_simple_sprint( ei, buf, 1024, vi)); + + } else if ( lccrt_varinit_is_array( vi) ) + { + int i; + + fprintf( ei->f, "{"); + if ( lccrt_type_is_float( type) ) + { + assert( lccrt_type_get_bytesize( type) == 10); + assert( lccrt_varinit_get_num_elems( vi) == 2); + fprintf( ei->f, "i:{"); + lcbe_emit_varinit( ei, lccrt_varinit_get_elem( vi, 0)); + fprintf( ei->f, ","); + lcbe_emit_varinit( ei, lccrt_varinit_get_elem( vi, 1)); + fprintf( ei->f, "}"); + } else + { + for ( i = 0; i < lccrt_varinit_get_num_elems( vi); ++i ) + { + fprintf( ei->f, "%s", (i > 0) ? "," : ""); + lcbe_emit_varinit( ei, lccrt_varinit_get_elem( vi, i)); + } + } + + fprintf( ei->f, "}"); + + } else if ( lccrt_varinit_is_str( vi) ) + { + int i; + const char *s = lccrt_varinit_get_str( vi); + + if ( lccrt_type_is_int( type) ) + { + struct { uint64_t hi; uint64_t lo; } w; + + memcpy( &w, s, sizeof( w)); + fprintf( ei->f, "((%s_fr){hi:0x%jxULL,lo:0x%jxULL})", lcbe_emit_get_type_name( ei, type), w.hi, w.lo); + } else + { + fprintf( ei->f, "{"); + for ( i = 0; i < lccrt_varinit_get_num_elems( vi); ++i ) + { + if ( (i > 0) ) fputs( ", ", ei->f); + fprintf( ei->f, "0x%02x", s[i] & 0xff); + } + + //lcbe_fprint( ei, s); + fprintf( ei->f, "}"); + } + } else if ( lccrt_varinit_is_zero( vi) ) + { + if ( lccrt_type_is_bool( type) + || lccrt_type_is_int( type) + || lccrt_type_is_pointer( type) ) + { + fprintf( ei->f, "((%s)0)", lcbe_emit_get_type_name( ei, type)); + + } else if ( lccrt_type_is_float( type) ) + { + fprintf( ei->f, "((%s_fr){i:0})", lcbe_emit_get_type_name( ei, type)); + } else + { + fprintf( ei->f, "{0}"); + } + } else + { + assert( 0); + } + + return (0); +} /* lcbe_emit_varinit */ + +/** + * Трансляция глобальной переменной. + */ +static int +lcbe_emit_var( lcbe_emit_t *ei, lccrt_var_ptr var, int is_init) +{ + int i; + int is_alias_reduce = 0; + const char *stype = 0; + int is_fr = 0; + lccrt_type_ptr type = lccrt_var_get_type( var); + const char *name0 = lccrt_var_get_name( var); + const char *name = lcbe_emit_get_obj_name( ei, var, 0); + const char *asm_name = lccrt_var_get_asm_name( var); + lccrt_var_loc_t loc = lccrt_var_get_loc( var); + lccrt_link_t lnk = lccrt_var_get_link( var); + lccrt_link_bind_t bnd = lccrt_link_get_bnd( lnk); + lccrt_link_tls_t tls = lccrt_link_get_tls( lnk); + lccrt_link_visibility_t vis = lccrt_link_get_vis( lnk); + int is_const = lccrt_link_is_const( lnk); + int is_alias = lccrt_link_is_alias( lnk); + int is_common = lccrt_var_get_attr_common( var); + int is_used = lccrt_var_get_attr_used( var); + const char *comdat = lccrt_var_get_comdat( var); + const char *sec = lccrt_var_get_section( var); + int is_ext = (loc == LCCRT_VAR_LOC_EXT); + lccrt_varinit_ptr vi = lccrt_var_get_init_value( var); + lccrt_type_ptr type_parent = lccrt_type_get_parent( type); + + assert( !comdat); + //assert( !is_common); + if ( is_alias ) + { + assert( !asm_name && vi); + } + + if ( (loc == LCCRT_VAR_LOC_CONSTARG) ) + { + if ( lcbe_emit_is_type_const_simple( type) ) + { + return (0); + } + } + + if ( !asm_name + && (name != name0) + && (bnd != LCCRT_LINK_BND_LOCAL) ) + { + asm_name = name0; + } + + if ( is_ext ) + { + fprintf( ei->f, "extern "); + } + + if ( (bnd == LCCRT_LINK_BND_LOCAL) ) + { + fprintf( ei->f, "static "); + } + + if ( is_const ) + { + fprintf( ei->f, "const "); + } + + if ( (tls != LCCRT_LINK_TLS_NO) ) + { + fprintf( ei->f, "__thread "); + } + + stype = lcbe_emit_get_type_name( ei, type); + if ( vi ) + { + lccrt_he_ptr he = lccrt_hash_find( ei->type_to_namefr, (uintptr_t)type); + + if ( he + && lccrt_hash_get( he) ) + { + is_fr = 1; + is_used = 1; + stype = lcbe_emit_get_type_namefr( ei, type); + } + } + + if ( is_alias ) + { + if ( lccrt_type_is_pointer( type) + && lccrt_type_is_function( type_parent) ) + { + is_alias_reduce = 1; + stype = lcbe_emit_get_type_name( ei, lccrt_type_get_parent( type_parent)); + } + } + + fprintf( ei->f, "%s %s", stype, name); + if ( is_alias_reduce ) + { + fprintf( ei->f, "("); + for ( i = 0; i < lccrt_type_get_num_args( type_parent); ++i ) + { + const char *sarg = lcbe_emit_get_type_name( ei, lccrt_type_get_arg( type, i)); + + fprintf( ei->f, "%s%s", (i > 0) ? "," : "", sarg); + } + fprintf( ei->f, ")"); + } + + if ( asm_name ) + { + fprintf( ei->f, " asm( \"%s\")", asm_name); + } + + fputs( (bnd == LCCRT_LINK_BND_WEAK) ? " __WEAK" : "", ei->f); + fputs( is_used ? " __USED" : "", ei->f); + if ( (tls != LCCRT_LINK_TLS_NO) ) + { + fprintf( ei->f, " %s", lcbe_Tls[tls]); + } + + if ( (vis != LCCRT_LINK_VIS_DEFAULT) ) + { + fprintf( ei->f, " %s", lcbe_Vis[vis]); + } + + if ( sec ) + { + fprintf( ei->f, " __SEC( \"%s\")", sec); + } + + if ( is_init + && vi ) + { + if ( is_alias ) + { + const char *name = 0; + + if ( lccrt_varinit_is_addr_var( vi) ) + { + name = lccrt_var_get_name( lccrt_varinit_get_addr_var( vi)); + + } else if ( lccrt_varinit_is_addr_func( vi) ) + { + name = lccrt_function_get_name( lccrt_varinit_get_addr_func( vi)); + } else + { + assert( 0); + } + + fprintf( ei->f, " __ALIAS(\""); + lcbe_fprint( ei, name); + fprintf( ei->f, "\")"); + } else + { + fprintf( ei->f, " = "); + lcbe_emit_varinit( ei, vi); + if ( is_fr ) + { + char buf[1024]; + int lenfr; + lccrt_he_ptr he = lccrt_hash_push( ei->obj_to_namefr, (uintptr_t)var, 0); + + lenfr = snprintf( buf, 1024, "__fr_%s", name); + if ( (lenfr >= 1024) ) + { + assert( 0); + } + + fprintf( ei->f, ";\n"); + fprintf( ei->f, "static %s %s __USED __ALIAS(\"%s\")", + lcbe_emit_get_type_name( ei, type), buf, name); + lccrt_hash_set( he, (uintptr_t)strdup( buf)); + } + } + } + + fprintf( ei->f, ";\n"); + + return (0); +} /* lcbe_emit_var */ + +/** + * Печать в буфер значение аргумента. + */ +static char * +lcbe_emit_oper_arg_sprint( lcbe_emit_t *ei, char *b, const char **bt, int len, lccrt_oper_ptr oper, int arg_num, + lccrt_type_ptr *arg_type) +{ + char *r = 0; + lccrt_var_ptr var = 0; + lccrt_oper_name_t name = lccrt_oper_get_name( oper); + + if ( arg_type ) + { + arg_type[0] = 0; + } + + b[0] = 0; + (*bt) = 0; + if ( (0 <= arg_num) + && (arg_num < lccrt_oper_get_num_args( oper)) + && lccrt_oper_name_is_arg_var( name, arg_num) ) + { + var = lccrt_oper_get_arg_var( oper, arg_num); + + } else if ( (arg_num == -1) + && lccrt_oper_get_res( oper) ) + { + var = lccrt_oper_get_res( oper); + } + + if ( var ) + { + lccrt_type_ptr type = lccrt_var_get_type( var); + + if ( arg_type ) + { + arg_type[0] = type; + } + + (*bt) = lcbe_emit_get_type_name( ei, type); + if ( lccrt_var_is_constarg( var) + && lcbe_emit_is_type_const_simple( type) ) + { + r = lcbe_emit_varinit_simple_sprint( ei, b, len, lccrt_var_get_init_value( var)); + if ( !r ) + { + b[0] = 0; + } + } else + { + int rlen = snprintf( b, len, "%s", lcbe_emit_get_var_name( ei, var)); + + if ( (rlen < len) ) + { + r = b; + } else + { + b[0] = 0; + } + } + } + + return (r); +} /* lcbe_emit_oper_arg_sprint */ + +/** + * Трансляция операции elemptr. + */ +static int +lcbe_emit_oper_elemptr( lcbe_emit_t *ei, lccrt_oper_ptr oper) +{ + char b0[1024]; + const char *bt0; + int pnum0 = 1; + lccrt_oper_name_t oper_name = lccrt_oper_get_name( oper); + int num_args = lccrt_oper_get_num_args( oper); + lccrt_type_ptr type = lccrt_var_get_type( lccrt_oper_get_arg_var( oper, 0)); + + if ( (oper_name == LCCRT_OPER_ELEMPTR) + || (oper_name == LCCRT_OPER_ELEMREAD) ) + { + } else if ( (oper_name == LCCRT_OPER_ELEMWRITE) ) + { + pnum0 = 2; + } else + { + assert( 0); + } + + lcbe_emit_oper_arg_sprint( ei, b0, &bt0, 1024, oper, 0, 0); + if ( (num_args == pnum0) ) + { + fprintf( ei->f, "%s", b0); + + } else if ( (num_args == pnum0 + 1) + && (oper_name == LCCRT_OPER_ELEMPTR) ) + { + lccrt_var_ptr a1 = lccrt_oper_get_arg_var( oper, pnum0); + + if ( lccrt_var_is_constarg_hex( a1) + && (lccrt_var_get_constarg_int64( a1) == 0) ) + { + fprintf( ei->f, "%s", b0); + } else + { + fprintf( ei->f, "(%s+%jd)", b0, lccrt_var_get_constarg_int64( a1)); + } + } else + { + int i; + char bi[1024]; + const char *bti; + + if ( (oper_name == LCCRT_OPER_ELEMPTR) ) + { + lcbe_emit_oper_arg_sprint( ei, bi, &bti, 1024, oper, pnum0, 0); + fprintf( ei->f, "&(%s[%s]", b0, bi); + pnum0++; + type = lccrt_type_get_parent( type); + } else + { + fprintf( ei->f, "%s", b0); + } + + for ( i = pnum0; i < lccrt_oper_get_num_args( oper); ++i ) + { + lccrt_var_ptr var = lccrt_oper_get_arg_var( oper, i); + + if ( lccrt_type_is_typename( type) ) + { + type = lccrt_type_get_parent( type); + } + + if ( lccrt_type_is_vector( type) ) + { + fprintf( ei->f, ".v"); + type = lccrt_type_get_parent( type); + } + + if ( lccrt_type_is_struct( type) ) + { + int64_t elem_num = lccrt_var_get_constarg_int64( var); + + fprintf( ei->f, ".a%jd", elem_num); + type = lccrt_type_get_arg( type, elem_num); + } else + { + lcbe_emit_oper_arg_sprint( ei, bi, &bti, 1024, oper, i, 0); + fprintf( ei->f, "[%s]", bi); + } + + type = lccrt_type_get_parent( type); + } + + if ( (oper_name == LCCRT_OPER_ELEMPTR) ) + { + fprintf( ei->f, ")"); + } + } + + return (0); +} /* lcbe_emit_oper_elemptr */ + +/** + * Трансляция операции call. + */ +static int +lcbe_emit_oper_call( lcbe_emit_t *ei, lccrt_oper_ptr oper) +{ + int i; + char b0[1024]; + const char *bt0; + int num_args = lccrt_oper_get_num_args( oper); + lccrt_var_ptr v0 = lccrt_oper_get_arg_var( oper, 0); + lccrt_type_ptr t0 = lccrt_var_get_type( v0); + int is_carg = lccrt_var_is_constarg_addr_func( v0); + lccrt_function_ptr func = is_carg ? lccrt_var_get_constarg_func( v0) : 0; + const char *name = func ? lccrt_function_get_name( func) : ""; + + if ( (lccrt_var_get_loc( v0) == LCCRT_VAR_LOC_ASM) ) + { + int is_quote; + int i_code, i_clob_beg; + int is_res_sec = 1; + int num_clobs = 0; + int i_arg = 0; + char *s_code = 0; + const char *s_tag = "' tag:0x"; + const char *s = lccrt_var_get_name( v0); + + for ( i = 0; s[i] != '\n'; ++i ) + { + } + + if ( (strncmp( s, s_tag, strlen( s_tag)) != 0) ) + { + lccrt_oper_print( oper, 1); + assert( 0); + } + + fprintf( ei->f, "asm volatile( \""); + i_code = i + 1; + for ( i = i_code ; s[i] != '!'; ++i ) + { + } + + s_code = strndup( s + i_code, i - i_code); + lcbe_fprint( ei, s_code); + free( s_code); + fprintf( ei->f, "\" : "); + + is_quote = 0; + for ( i = i + 1; s[i] == '`'; ) + { + int j; + lccrt_var_ptr arg = lccrt_oper_get_arg_var( oper, i_arg + 1); + + if ( (s[i+1] != '=') ) + { + if ( is_res_sec ) + { + is_res_sec = 0; + is_quote = 0; + fprintf( ei->f, " : "); + } + } + + for ( j = i + 1; s[j] != '`' ; ++j ) + { + } + + s_code = strndup( s + i + 1, j - i - 1); + fprintf( ei->f, "%s\"", is_quote ? ", " : ""); + is_quote = 1; + lcbe_fprint( ei, s_code); + lcbe_emit_oper_arg_sprint( ei, b0, &bt0, 1024, oper, i_arg + 1, 0); + fprintf( ei->f, "\"(%s)", b0); + free( s_code); + i_arg++; + i = j + 1; + } + + if ( is_res_sec ) + { + fprintf( ei->f, " :"); + } + + fprintf( ei->f, " : \"memory\""); + is_quote = 1; + i_clob_beg = i + 1; + for ( i = i_clob_beg; s[i] == '?'; ) + { + int j; + + for ( j = i + 1; s[j] != '?'; ++j ) + { + } + + s_code = strndup( s + i + 1, j - i - 1); + if ( (strcmp( s_code, "dirflag") == 0) ) + { + free( s_code); + s_code = strdup( "cc"); + } + + fprintf( ei->f, "%s\"", is_quote ? ", " : ""); + is_quote = 1; + lcbe_fprint( ei, s_code); + fprintf( ei->f, "\""); + free( s_code); + num_clobs++; + i = j + 1; + } + + fprintf( ei->f, ")"); + + } else + { + lcbe_emit_oper_arg_sprint( ei, b0, &bt0, 1024, oper, 0, 0); + if ( lccrt_var_is_constarg_addr_func( v0) ) + { + if ( (strcmp( name, "__lccrt_va_start") == 0) ) + { + fprintf( ei->f, "__VA_START("); + + } else if ( (strcmp( name, "__lccrt_va_end") == 0) ) + { + fprintf( ei->f, "__VA_END("); + + } else if ( (strcmp( name, "__lccrt_stacksave") == 0) ) + { + fprintf( ei->f, "__builtin_stack_save("); + + } else if ( (strcmp( name, "__lccrt_stackrestore") == 0) ) + { + fprintf( ei->f, "__builtin_stack_restore("); + } else + { + t0 = lccrt_function_get_type( lccrt_var_get_constarg_func( v0)); + fprintf( ei->f, "((%s)%s)(", lcbe_emit_get_type_name( ei, t0), b0); + } + } else + { + fprintf( ei->f, "((%s)%s)(", lcbe_emit_get_type_name( ei, lccrt_type_get_parent( t0)), b0); + } + + for ( i = 1; i < lccrt_oper_get_num_args( oper); ++i ) + { + lcbe_emit_oper_arg_sprint( ei, b0, &bt0, 1024, oper, i, 0); + fprintf( ei->f, "%s%s", (i > 1) ? "," : "", b0); + } + + if ( (strcmp( name, "__lccrt_va_start") == 0) ) + { + int num_args = lccrt_function_get_num_args( ei->cur_func); + lccrt_var_ptr last_arg = lccrt_function_get_arg( ei->cur_func, num_args - 1); + + fprintf( ei->f, ",%s", lcbe_emit_get_local_name( ei, last_arg)); + } + + fprintf( ei->f, ")", b0); + } + + return (0); +} /* lcbe_emit_oper_call */ + +/** + * Трансляция операции switch. + */ +static int +lcbe_emit_oper_switch( lcbe_emit_t *ei, lccrt_oper_ptr oper) +{ + int i; + char b0[1024]; + const char *bt0; + lccrt_var_ptr v0 = lccrt_oper_get_arg_var( oper, 0); + + lcbe_emit_oper_arg_sprint( ei, b0, &bt0, 1024, oper, 0, 0); + if ( (lccrt_type_get_bytesize( lccrt_var_get_type( v0)) == 16) ) + { + fprintf( ei->f, " ((int *)0)[0] = 0;\n"); + } else + { + fprintf( ei->f, " switch ( %s ) {\n", b0); + for ( i = 1; i < lccrt_oper_get_num_args( oper); i += 2 ) + { + lccrt_var_ptr av = lccrt_oper_get_arg_var( oper, i); + lccrt_oper_ptr ao = lccrt_oper_get_arg_oper( oper, i + 1); + + if ( av ) + { + fprintf( ei->f, " case (%s)%jdLL:", bt0, lccrt_var_get_constarg_int64( av)); + } else + { + fprintf( ei->f, " default:"); + } + + fprintf( ei->f, " goto %s; break;\n", lcbe_emit_oper_get_label( ei, ao)); + } + + fprintf( ei->f, " }\n"); + } + + return (0); +} /* lcbe_emit_oper_switch */ + +/** + * Вычисление параметров операции сравнения. + */ +static const char * +lcbe_emit_cmp_get_op( lcbe_emit_t *ei, lccrt_oper_ptr oper, const char **type, int *fo, int *fu) +{ + const char *r = 0; + lccrt_var_ptr v0 = lccrt_oper_get_arg_var( oper, 0); + lccrt_var_ptr v1 = lccrt_oper_get_arg_var( oper, 1); + lccrt_type_ptr t1 = lccrt_var_get_type( v1); + + type[0] = 0; + fo[0] = 0; + fu[0] = 0; + + switch ( lccrt_var_get_constarg_int64( v0) ) + { + case LCCRT_CMP_EQ: + r = "=="; + type[0] = lcbe_emit_get_type_int_name( ei, t1, 0); + break; + case LCCRT_CMP_NE: + r = "!="; + type[0] = lcbe_emit_get_type_int_name( ei, t1, 0); + break; + case LCCRT_CMP_LT_I: + r = "<"; + type[0] = lcbe_emit_get_type_int_name( ei, t1, 1); + break; + case LCCRT_CMP_LT_U: + r = "<"; + type[0] = lcbe_emit_get_type_int_name( ei, t1, 0); + break; + case LCCRT_CMP_LE_I: + r = "<="; + type[0] = lcbe_emit_get_type_int_name( ei, t1, 1); + break; + case LCCRT_CMP_LE_U: + r = "<="; + type[0] = lcbe_emit_get_type_int_name( ei, t1, 0); + break; + case LCCRT_CMP_GT_I: + r = ">"; + type[0] = lcbe_emit_get_type_int_name( ei, t1, 1); + break; + case LCCRT_CMP_GT_U: + r = ">"; + type[0] = lcbe_emit_get_type_int_name( ei, t1, 0); + break; + case LCCRT_CMP_GE_I: + r = ">="; + type[0] = lcbe_emit_get_type_int_name( ei, t1, 1); + break; + case LCCRT_CMP_GE_U: + r = ">="; + type[0] = lcbe_emit_get_type_int_name( ei, t1, 0); + break; + case LCCRT_CMP_FO: + fo[0] = 1; + break; + case LCCRT_CMP_FU: + fu[0] = 1; + break; + case LCCRT_CMP_EQ_FO: + r = "=="; + fo[0] = 1; + break; + case LCCRT_CMP_EQ_FU: + r = "=="; + fu[0] = 1; + break; + case LCCRT_CMP_NE_FO: + r = "!="; + fo[0] = 1; + break; + case LCCRT_CMP_NE_FU: + r = "!="; + fu[0] = 1; + break; + case LCCRT_CMP_LT_FO: + r = "<"; + fo[0] = 1; + break; + case LCCRT_CMP_LT_FU: + r = "<"; + fu[0] = 1; + break; + case LCCRT_CMP_LE_FO: + r = "<="; + fo[0] = 1; + break; + case LCCRT_CMP_LE_FU: + r = "<="; + fu[0] = 1; + break; + case LCCRT_CMP_GT_FO: + r = ">"; + fo[0] = 1; + break; + case LCCRT_CMP_GT_FU: + r = ">"; + fu[0] = 1; + break; + case LCCRT_CMP_GE_FO: + r = ">="; + fo[0] = 1; + break; + case LCCRT_CMP_GE_FU: + r = ">="; + fu[0] = 1; + break; + default: + assert( 0); + break; + } + + return (r); +} /* lcbe_emit_cmp_get_op */ + +/** + * Трансляция операций функции. + */ +static int +lcbe_emit_func_opers( lcbe_emit_t *ei, lccrt_function_ptr func) +{ + lccrt_var_ptr var; + lccrt_oper_ptr oper; + + fprintf( ei->f, " // LOCAL VARIABLES\n"); + for ( var = lccrt_function_get_first_var( func); var; var = lccrt_var_get_next_var( var) ) + { + if ( (lccrt_var_get_loc( var) == LCCRT_VAR_LOC_LOCAL) ) + { + fprintf( ei->f, " %s %s;\n", + lcbe_emit_get_type_name( ei, lccrt_var_get_type( var)), + lcbe_emit_get_local_name( ei, var)); + } + } + + fprintf( ei->f, "\n // OPERATIONS\n"); + for ( oper = lccrt_function_get_first_oper( func); oper; oper = lccrt_oper_get_next( oper) ) + { + int i; + int fo, fu; + char r0[1024], b0[1024], b1[1024], b2[1024]; + const char *rt0, *bt0, *bt1, *bt2; + const char *s0, *s1; + lccrt_type_ptr type0 = 0; + lccrt_type_ptr type1 = 0; + int is_scalar_r0 = 0; + int r0_vlen = 0; + lccrt_oper_name_t oper_name = lccrt_oper_get_name( oper); + int num_args = lccrt_oper_get_num_args( oper); + lccrt_type_ptr rtype0 = lccrt_oper_get_type( oper); + int is_volatile = lccrt_oper_is_volatile( oper); + static unsigned oper_count = 0; + static unsigned oper_count_gdb = ~0U; + + if ( lccrt_oper_is_label( oper) + && !lccrt_oper_get_next( oper) ) + { + continue; + } + + if ( lccrt_type_is_bool( rtype0) + || lccrt_type_is_int( rtype0) + || lccrt_type_is_pointer( rtype0) + || lccrt_type_is_float( rtype0) ) + { + is_scalar_r0 = 1; + } else + { + r0_vlen = lccrt_type_get_num_args( rtype0); + } + + lcbe_emit_oper_arg_sprint( ei, r0, &rt0, 1024, oper, -1, 0); + lcbe_emit_oper_arg_sprint( ei, b0, &bt0, 1024, oper, 0, &type0); + lcbe_emit_oper_arg_sprint( ei, b1, &bt1, 1024, oper, 1, &type1); + lcbe_emit_oper_arg_sprint( ei, b2, &bt2, 1024, oper, 2, 0); + + if ( (oper_count == oper_count_gdb) ) + { + printf( "GDB-hit\n"); + } + + fprintf( ei->f, " // oper_count : %d\n", oper_count); + oper_count++; + //assert( !lccrt_oper_is_atomic( oper)); + if ( is_volatile ) + { + if ( !(lccrt_oper_is_call( oper) + || (oper_name == LCCRT_OPER_LOAD) + || (oper_name == LCCRT_OPER_STORE)) ) + { + assert( 0); + } + } + + if ( lccrt_type_is_bool( rtype0) ) + { + if ( !((oper_name == LCCRT_OPER_CMP) + || (oper_name == LCCRT_OPER_MOVE) + || (oper_name == LCCRT_OPER_AND) + || (oper_name == LCCRT_OPER_OR) + || (oper_name == LCCRT_OPER_XOR) + || (oper_name == LCCRT_OPER_LOAD) + || (oper_name == LCCRT_OPER_ELEMREAD) + || (oper_name == LCCRT_OPER_TRUNC)) ) + { + //lccrt_oper_print( oper, 1); + //assert( 0); + } + } + + if ( type0 + && lccrt_type_is_bool( type0) ) + { + if ( !((oper_name == LCCRT_OPER_SEXT) + || (oper_name == LCCRT_OPER_ZEXT) + || (oper_name == LCCRT_OPER_UITOFP) + || (oper_name == LCCRT_OPER_MOVE) + || (oper_name == LCCRT_OPER_AND) + || (oper_name == LCCRT_OPER_OR) + || (oper_name == LCCRT_OPER_XOR) + || (oper_name == LCCRT_OPER_VARPTR) + || (oper_name == LCCRT_OPER_BRANCHIF) + || (oper_name == LCCRT_OPER_SELECT)) ) + { + //lccrt_oper_print( oper, 1); + //assert( 0); + } + } + + switch ( oper_name ) + { + case LCCRT_OPER_LABEL: + fprintf( ei->f, "%s:\n", lcbe_emit_oper_get_label( ei, oper)); + break; + case LCCRT_OPER_VARPTR: + fprintf( ei->f, " %s = (%s)&%s;\n", r0, rt0, b0); + break; + case LCCRT_OPER_LOAD: + if ( lccrt_type_is_array( type0) ) + { + uint64_t size = lccrt_type_get_bytesize( rtype0); + + if ( is_volatile ) + { + fprintf( ei->f, " __MEMCPY_VOLATILE( %s, %s, %s);\n", r0, b0, size); + } else + { + fprintf( ei->f, " __builtin_memcpy(%s,%s,%jd);\n", r0, b0, size); + } + } else + { + if ( is_volatile ) + { + fprintf( ei->f, " %s = __LOAD_VOLATILE( %s, %s);\n", r0, rt0, b0); + } else + { + fprintf( ei->f, " %s = ((%s*)%s)[0];\n", r0, rt0, b0); + } + } + break; + case LCCRT_OPER_STORE: + if ( lccrt_type_is_array( type1) ) + { + uint64_t size = lccrt_type_get_bytesize( type1); + + if ( is_volatile ) + { + fprintf( ei->f, " __MEMCPY_VOLATILE( %s, %s, %jd);\n", bt1, b0, size); + } else + { + fprintf( ei->f, " __builtin_memcpy(%s,%s,%jd);\n", b0, b1, size); + } + } else + { + if ( is_volatile ) + { + fprintf( ei->f, " __STORE_VOLATILE( %s, %s, %s);\n", bt1, b0, b1); + } else + { + fprintf( ei->f, " ((%s*)%s)[0] = %s;\n", bt1, b0, b1); + } + } + break; + case LCCRT_OPER_MOVE: + if ( lccrt_type_is_array( rtype0) ) + { + fprintf( ei->f, " __builtin_memcpy( (char*)%s, (char*)%s, %jd);\n", r0, b0, + lccrt_type_get_bytesize( rtype0)); + } else + { + fprintf( ei->f, " %s = %s;\n", r0, b0); + } + break; + case LCCRT_OPER_TRUNC: + if ( is_scalar_r0 ) + { + fprintf( ei->f, " %s = %s;\n", r0, b0); + } else + { + lccrt_type_ptr rty = lccrt_type_get_parent( rtype0); + lccrt_type_ptr aty = lccrt_type_get_parent( type0); + + fprintf( ei->f, " %s = __VEC_TRUNC%s( %s, %s, %s.v);\n", + r0, lccrt_type_is_bool( rty) ? "_BOOL" : "", rt0, + lcbe_emit_get_type_name( ei, aty), b0); + } + break; + case LCCRT_OPER_BITCAST: + fprintf( ei->f, " %s = ((union {%s in; %s out;}){in:%s}).out;\n", r0, bt0, rt0, b0); + break; + case LCCRT_OPER_ZEXT: + if ( is_scalar_r0 ) + { + s0 = lcbe_emit_get_type_int_name( ei, type0, 0); + fprintf( ei->f, " %s = (uint64_t)(%s)%s;\n", r0, s0, b0); + } else + { + s0 = lcbe_emit_get_type_int_name( ei, lccrt_type_get_parent( type0), 0); + fprintf( ei->f, " %s = __VEC_ZEXT( %s, %s, %s);\n", r0, rt0, s0, b0); + } + break; + case LCCRT_OPER_SEXT: + if ( is_scalar_r0 ) + { + s0 = lcbe_emit_get_type_int_name( ei, type0, 1); + if ( lccrt_type_is_bool( type0) ) + { + fprintf( ei->f, " %s = (int64_t)(%s)(%s ? 0xff : 0);\n", r0, s0, b0); + } else + { + fprintf( ei->f, " %s = (int64_t)(%s)%s;\n", r0, s0, b0); + } + } else + { + s0 = lcbe_emit_get_type_int_name( ei, lccrt_type_get_parent( type0), 1); + s1 = lccrt_type_is_bool( type0) ? "_BOOL" : ""; + fprintf( ei->f, " %s = __VEC_SEXT%s( %s, %s, %s);\n", r0, s1, rt0, s0, b0); + } + break; + case LCCRT_OPER_SITOFP: + s0 = lcbe_emit_get_type_int_name( ei, type0, 1); + fprintf( ei->f, " %s = (%s)%s;\n", r0, s0, b0); + break; + case LCCRT_OPER_UITOFP: + s0 = lcbe_emit_get_type_int_name( ei, type0, 0); + fprintf( ei->f, " %s = (%s)%s;\n", r0, s0, b0); + break; + case LCCRT_OPER_FPTOSI: + case LCCRT_OPER_FPTOUI: + case LCCRT_OPER_FPTOFP: + fprintf( ei->f, " %s = %s;\n", r0, b0); + break; + case LCCRT_OPER_AND: + if ( is_scalar_r0 ) fprintf( ei->f, " %s = %s & %s;\n", r0, b0, b1); + else fprintf( ei->f, " %s = __VEC_AND( %s, %s, %s);\n", r0, rt0, b0, b1); + break; + case LCCRT_OPER_OR: + if ( is_scalar_r0 ) fprintf( ei->f, " %s = %s | %s;\n", r0, b0, b1); + else fprintf( ei->f, " %s = __VEC_IOR( %s, %s, %s);\n", r0, rt0, b0, b1); + break; + case LCCRT_OPER_XOR: + if ( is_scalar_r0 ) fprintf( ei->f, " %s = %s ^ %s;\n", r0, b0, b1); + else fprintf( ei->f, " %s = __VEC_XOR( %s, %s, %s);\n", r0, rt0, b0, b1); + break; + case LCCRT_OPER_SHL: + if ( is_scalar_r0 ) fprintf( ei->f, " %s = %s << %s;\n", r0, b0, b1); + else fprintf( ei->f, " %s = __VEC_SHL( %s, %s, %s);\n", r0, rt0, b0, b1); + break; + case LCCRT_OPER_SHR: + s0 = lcbe_emit_get_type_int_name( ei, type0, 0); + if ( is_scalar_r0 ) fprintf( ei->f, " %s = (%s)%s >> (%s)%s;\n", r0, s0, b0, s0, b1); + else fprintf( ei->f, " %s = __VEC_SHR( %s, %s, %s);\n", r0, rt0, b0, b1); + break; + case LCCRT_OPER_SAR: + s0 = lcbe_emit_get_type_int_name( ei, type0, 1); + if ( is_scalar_r0 ) fprintf( ei->f, " %s = (%s)%s >> (%s)%s;\n", r0, s0, b0, s0, b1); + else fprintf( ei->f, " %s = __VEC_SAR( %s, %s, %s);\n", r0, rt0, b0, b1); + break; + case LCCRT_OPER_ADD: + case LCCRT_OPER_FADD: + if ( is_scalar_r0 ) fprintf( ei->f, " %s = %s + %s;\n", r0, b0, b1); + else fprintf( ei->f, " %s = __VEC_ADD( %s, %s, %s);\n", r0, rt0, b0, b1); + break; + case LCCRT_OPER_SUB: + case LCCRT_OPER_FSUB: + if ( is_scalar_r0 ) fprintf( ei->f, " %s = %s - %s;\n", r0, b0, b1); + else fprintf( ei->f, " %s = __VEC_SUB( %s, %s, %s);\n", r0, rt0, b0, b1); + break; + case LCCRT_OPER_MUL: + case LCCRT_OPER_FMUL: + if ( is_scalar_r0 ) fprintf( ei->f, " %s = %s * %s;\n", r0, b0, b1); + else fprintf( ei->f, " %s = __VEC_MUL( %s, %s, %s);\n", r0, rt0, b0, b1); + break; + case LCCRT_OPER_SDIV: + s0 = lcbe_emit_get_type_int_name( ei, type0, 1); + if ( is_scalar_r0 ) fprintf( ei->f, " %s = (%s)%s / (%s)%s;\n", r0, s0, b0, s0, b1); + else fprintf( ei->f, " %s = __VEC_SDIV( %d, %s, %s, %s);\n", r0, r0_vlen, s0, b0, b1); + break; + case LCCRT_OPER_UDIV: + s0 = lcbe_emit_get_type_int_name( ei, type0, 0); + if ( is_scalar_r0 ) fprintf( ei->f, " %s = (%s)%s / (%s)%s;\n", r0, s0, b0, s0, b1); + else fprintf( ei->f, " %s = __VEC_UDIV( %d, %s, %s, %s);\n", r0, r0_vlen, s0, b0, b1); + break; + case LCCRT_OPER_FDIV: + if ( is_scalar_r0 ) fprintf( ei->f, " %s = %s / %s;\n", r0, b0, b1); + else fprintf( ei->f, " %s = __VEC_DIV( %s, %s, %s);\n", r0, rt0, b0, b1); + break; + case LCCRT_OPER_ELEMPTR: + fprintf( ei->f, " %s = ", r0); + lcbe_emit_oper_elemptr( ei, oper); + fprintf( ei->f, ";\n"); + break; + case LCCRT_OPER_ELEMREAD: + fprintf( ei->f, " %s = ", r0); + lcbe_emit_oper_elemptr( ei, oper); + fprintf( ei->f, ";\n"); + break; + case LCCRT_OPER_ELEMWRITE: + fprintf( ei->f, " "); + lcbe_emit_oper_elemptr( ei, oper); + fprintf( ei->f, " = %s;\n", b1); + break; + case LCCRT_OPER_CALLPROC: + fprintf( ei->f, " "); + lcbe_emit_oper_call( ei, oper); + fprintf( ei->f, ";\n"); + break; + case LCCRT_OPER_CALLFUNC: + fprintf( ei->f, " %s = ", r0); + lcbe_emit_oper_call( ei, oper); + fprintf( ei->f, ";\n"); + break; + case LCCRT_OPER_INVOKEPROC: + case LCCRT_OPER_INVOKEFUNC: + case LCCRT_OPER_LANDINGPAD: + fprintf( ei->f, " ((int*)0)[0] = 0;\n"); + break; + case LCCRT_OPER_SELECT: + fprintf( ei->f, " %s = %s ? %s : %s;\n", r0, b0, b1, b2); + break; + case LCCRT_OPER_SHUFFLE: + fprintf( ei->f, " %s = __VEC_SHUFFLE( %s, %s.v, %jd, %s.v, %s.v);\n", r0, rt0, b2, + lccrt_type_get_num_args( type0), b0, b1); + break; + case LCCRT_OPER_CMP: + fprintf( ei->f, " %s = ", r0); + s0 = lcbe_emit_cmp_get_op( ei, oper, &s1, &fo, &fu); + if ( !s0 ) + { + fprintf( ei->f, "%s(%s,%s);\n", fo ? "__FO" : "__FU", b1, b2); + } else + { + if ( s1 ) + { + fprintf( ei->f, "((%s)%s %s (%s)%s);\n", s1, b1, s0, s1, b2); + } else + { + fprintf( ei->f, "(%s %s %s)", b1, s0, b2); + fprintf( ei->f, " %s(%s,%s);\n", fo ? "&& __FO" : "|| __FU", b1, b2); + } + } + break; + case LCCRT_OPER_BRANCH: + fprintf( ei->f, " goto %s;\n", lcbe_emit_oper_get_label( ei, lccrt_oper_get_arg_oper( oper, 0))); + break; + case LCCRT_OPER_BRANCHIF: + fprintf( ei->f, " if ( %s )", b0); + fprintf( ei->f, " goto %s;\n", lcbe_emit_oper_get_label( ei, lccrt_oper_get_arg_oper( oper, 2))); + fprintf( ei->f, " else"); + fprintf( ei->f, " goto %s;\n", lcbe_emit_oper_get_label( ei, lccrt_oper_get_arg_oper( oper, 1))); + break; + case LCCRT_OPER_SWITCH: + lcbe_emit_oper_switch( ei, oper); + break; + case LCCRT_OPER_RET: + fprintf( ei->f, " return;\n"); + break; + case LCCRT_OPER_RETVAL: + fprintf( ei->f, " return (%s);\n", b0); + break; + case LCCRT_OPER_ALLOCA: + fprintf( ei->f, " %s = __builtin_alloca(%s);\n", r0, b0); + break; + default: + lccrt_oper_print( oper, 1); + exit( 1); + assert( 0); + break; + } + } + + return (0); +} /* lcbe_emit_func_opers */ + +/** + * Трансляция функции. + */ +static int +lcbe_emit_func( lcbe_emit_t *ei, lccrt_function_ptr func, int is_decl) +{ + int i; + lccrt_type_ptr type = lccrt_function_get_type( func); + const char *name0 = lccrt_function_get_name( func); + const char *name = lcbe_emit_get_obj_name( ei, func, 1); + const char *asm_name = lccrt_function_get_asm_name( func); + lccrt_link_t lnk = lccrt_function_get_link( func); + lccrt_link_bind_t bnd = lccrt_link_get_bnd( lnk); + lccrt_link_visibility_t vis = lccrt_link_get_vis( lnk); + int is_alias = lccrt_link_is_alias( lnk); + int is_ext_inline = lccrt_function_get_attr_extern_inline( func); + int is_used = lccrt_function_get_attr_used( func); + const char *comdat = lccrt_function_get_comdat( func); + const char *sec = lccrt_function_get_section( func); + + assert( !is_alias); + assert( !is_ext_inline || (bnd == LCCRT_LINK_BND_GLOBAL)); + assert( !comdat); + + if ( !asm_name + && (name != name0) ) + { + asm_name = name0; + } + + if ( is_decl ) + { + fputs( (bnd == LCCRT_LINK_BND_LOCAL) ? "static " : "extern ", ei->f); + } else + { + fprintf( ei->f, "\n"); + fputs( (bnd == LCCRT_LINK_BND_LOCAL) ? "static " : "", ei->f); + if ( is_ext_inline ) fputs( "extern __inline __attribute__((__gnu_inline__)) ", ei->f); + } + + fprintf( ei->f, "%s ", lcbe_emit_get_type_name( ei, lccrt_type_get_parent( type))); + + if ( !is_decl ) + { + if ( (bnd == LCCRT_LINK_BND_WEAK) ) fputs( "__WEAK ", ei->f); + if ( is_used ) fputs( "__USED ", ei->f); + //if ( asm_name ) fprintf( ei->f, "asm(\"%s\") ", asm_name); + if ( sec ) fprintf( ei->f, "__SEC(\"%s\") ", sec); + if ( (vis != LCCRT_LINK_VIS_DEFAULT) ) fprintf( ei->f, "%s ", lcbe_Vis[vis]); + } + + fprintf( ei->f, "%s(", name); + + if ( (lccrt_type_get_num_args( type) == 1) + && lccrt_function_is_var_arg( func) ) + { + } else + { + for ( i = 0; i < lccrt_type_get_num_args( type); ++i ) + { + fputs( (i > 0) ? "," : "", ei->f); + fprintf( ei->f, "%s", lcbe_emit_get_type_name( ei, lccrt_type_get_arg( type, i))); + if ( !is_decl ) + { + if ( (i + 1 < lccrt_type_get_num_args( type)) + || !lccrt_function_is_var_arg( func) ) + { + fprintf( ei->f, " %s", lcbe_emit_get_local_name( ei, lccrt_function_get_arg( func, i))); + } + } + } + } + + fprintf( ei->f, ")"); + if ( is_decl ) + { + if ( (bnd == LCCRT_LINK_BND_WEAK) ) fputs( " __WEAK", ei->f); + if ( is_used ) fputs( " __USED", ei->f); + if ( asm_name ) fprintf( ei->f, " asm(\"%s\")", asm_name); + if ( sec ) fprintf( ei->f, " __SEC( \"%s\")", sec); + if ( (vis != LCCRT_LINK_VIS_DEFAULT) ) fprintf( ei->f, " %s", lcbe_Vis[vis]); + fprintf( ei->f, ";\n"); + } else + { + fprintf( ei->f, "\n{\n"); + lcbe_emit_func_opers( ei, func); + fprintf( ei->f, " ;\n"); + fprintf( ei->f, "}\n"); + } + + return (0); +} /* lcbe_emit_func */ + +/** + * Завершение трансляции. + */ +static int +lcbe_emit_done( lcbe_emit_t *ei) +{ + ei->obj_to_name = lcbe_name_hash_delete( ei->obj_to_name); + ei->obj_to_namefr = lcbe_name_hash_delete( ei->obj_to_namefr); + ei->type_to_namefr = lcbe_name_hash_delete( ei->type_to_namefr); + ei->type_to_name = lcbe_name_hash_delete( ei->type_to_name); + lccrt_hash_delete( ei->type_to_ident); + lccrt_context_delete( ei->ctx); + + if ( ei->f ) + { + fclose( ei->f); + } + + memset( ei, 0, sizeof( ei[0])); + + return (0); +} /* lcbe_emit_done */ + +/** + * Формирование стандартной заголовочной части модуля. + */ +static int +lcbe_emit_head( lcbe_emit_t *ei) +{ + fprintf( ei->f, "#include \n"); + fprintf( ei->f, "#include \n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __PACKED __attribute__((packed))\n"); + fprintf( ei->f, "#define __ALIGN(x) __attribute__((aligned(x)))\n"); + fprintf( ei->f, "#define __USED __attribute__((__used__))\n"); + fprintf( ei->f, "#define __WEAK __attribute__((weak))\n"); + fprintf( ei->f, "#define __ALIAS(x) __attribute__((alias(x)))\n"); + fprintf( ei->f, "#define __TLS_GD __attribute__((tls_model(\"global-dynamic\")))\n"); + fprintf( ei->f, "#define __TLS_LD __attribute__((tls_model(\"local-dynamic\")))\n"); + fprintf( ei->f, "#define __TLS_IE __attribute__((tls_model(\"initial-exec\")))\n"); + fprintf( ei->f, "#define __TLS_LE __attribute__((tls_model(\"local-exec\")))\n"); + fprintf( ei->f, "#define __VIS_IN __attribute__((visibility(\"internal\")))\n"); + fprintf( ei->f, "#define __VIS_HD __attribute__((visibility(\"hidden\")))\n"); + fprintf( ei->f, "#define __VIS_PT __attribute__((visibility(\"private\")))\n"); + fprintf( ei->f, "#define __SEC(x) __attribute__((section(x)))\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VA_START(x,y) va_start(x,y)\n"); + fprintf( ei->f, "#define __VA_END(x) va_end(x)\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "typedef struct { uint64_t hi; uint64_t lo; } __type_uint128_fr;\n"); + fprintf( ei->f, "typedef struct { int64_t hi; uint64_t lo; } __type_int128_fr;\n"); + fprintf( ei->f, "typedef unsigned __int128 __type_uint128;\n"); + fprintf( ei->f, "typedef __int128 __type_int128;\n"); + fprintf( ei->f, "typedef union { float f; uint32_t i; } __type_float32_fr;\n"); + fprintf( ei->f, "typedef union { double f; uint64_t i; } __type_float64_fr;\n"); + fprintf( ei->f, "typedef union { long double f; struct { uint64_t lo; uint16_t hi; } i; } __type_float80_fr;\n"); + fprintf( ei->f, "typedef float __type_float32;\n"); + fprintf( ei->f, "typedef double __type_float64;\n"); + fprintf( ei->f, "typedef long double __type_float80;\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __FO(x,y) (((x)==(y)) || ((x)!=(y)))\n"); + fprintf( ei->f, "#define __FU(x,y) (!__FO(x,y))\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __LOAD_VOLATILE(t,p) ({volatile t* __a = (t*)(p); *(__a);})\n"); + fprintf( ei->f, "#define __STORE_VOLATILE(t,p,v) {volatile t* __a = (t*)(p); *(__a) = (v);}\n"); + fprintf( ei->f, "#define __MEMCPY_VOLATILE(d,s,l) ({volatile char* __a = (d); __builtin_memcpy(__a,s,l);})\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VEC_TRUNC(T,S,x) __VEC_TRUNC##T##S(x)\n"); + fprintf( ei->f, "#define __VEC_ZEXT(T,S,x) __VEC_ZEXT##T##S((S*)(x).v)\n"); + fprintf( ei->f, "#define __VEC_SEXT(T,S,x) __VEC_SEXT##T##S((S*)(x).v)\n"); + fprintf( ei->f, "#define __VEC_AND(T,x,y) __VEC_AND##T(x,y)\n"); + fprintf( ei->f, "#define __VEC_IOR(T,x,y) __VEC_IOR##T(x,y)\n"); + fprintf( ei->f, "#define __VEC_XOR(T,x,y) __VEC_XOR##T(x,y)\n"); + fprintf( ei->f, "#define __VEC_SHL(T,x,y) __VEC_SHL##T(x,y)\n"); + fprintf( ei->f, "#define __VEC_SHR(T,x,y) __VEC_SHR##T(x,y)\n"); + fprintf( ei->f, "#define __VEC_SAR(T,x,y) __VEC_SAR##T(x,y)\n"); + fprintf( ei->f, "#define __VEC_ADD(T,x,y) __VEC_ADD##T(x,y)\n"); + fprintf( ei->f, "#define __VEC_SUB(T,x,y) __VEC_SUB##T(x,y)\n"); + fprintf( ei->f, "#define __VEC_MUL(T,x,y) __VEC_MUL##T(x,y)\n"); + fprintf( ei->f, "#define __VEC_DIV(T,x,y) __VEC_DIV##T(x,y)\n"); + fprintf( ei->f, "#define __VEC_SHUFFLE(T,p,xl,x,y) __VEC_SHUFFLE##T(p,xl,x,y)\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VEC_FUNC1(n,T,S,R,NAME) \\\n"); + fprintf( ei->f, " static T __VEC_##NAME##T##S(S *x) \\\n"); + fprintf( ei->f, " { \\\n"); + fprintf( ei->f, " int i; \\\n"); + fprintf( ei->f, " T r; \\\n"); + fprintf( ei->f, " for ( i = 0; i < n; ++i ) r.v[i] = (R)x[i]; \\\n"); + fprintf( ei->f, " return (r); \\\n"); + fprintf( ei->f, " }\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VEC_FUNC2(n,T,NAME,op) \\\n"); + fprintf( ei->f, " static T __VEC_##NAME##T(T x, T y) \\\n"); + fprintf( ei->f, " { \\\n"); + fprintf( ei->f, " int i; \\\n"); + fprintf( ei->f, " T r; \\\n"); + fprintf( ei->f, " for ( i = 0; i < n; ++i ) r.v[i] = x.v[i] op y.v[i]; \\\n"); + fprintf( ei->f, " return (r); \\\n"); + fprintf( ei->f, " }\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VEC_FUNC2_ST(n,T,TE,NAME,op) \\\n"); + fprintf( ei->f, " static T __VEC_##NAME##T(T x, T y) \\\n"); + fprintf( ei->f, " { \\\n"); + fprintf( ei->f, " int i; \\\n"); + fprintf( ei->f, " T r; \\\n"); + fprintf( ei->f, " for ( i = 0; i < n; ++i ) r.v[i] = (TE)(x.v[i]) op (TE)(y.v[i]); \\\n"); + fprintf( ei->f, " return (r); \\\n"); + fprintf( ei->f, " }\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VEC_FUNC_SHUFFLE(n,T,TE) \\\n"); + fprintf( ei->f, " static T __VEC_SHUFFLE##T( uint32_t *p, uint32_t x_len, TE *x, TE *y) \\\n"); + fprintf( ei->f, " { \\\n"); + fprintf( ei->f, " int i; \\\n"); + fprintf( ei->f, " T r; \\\n"); + fprintf( ei->f, " for ( i = 0; i < n; ++i ) \\\n"); + fprintf( ei->f, " { \\\n"); + fprintf( ei->f, " uint32_t p_i = p[i]; \\\n"); + fprintf( ei->f, " r.v[i] = (p_i < x_len) ? x[p_i] : y[p_i - x_len]; \\\n"); + fprintf( ei->f, " } \\\n"); + fprintf( ei->f, " return (r); \\\n"); + fprintf( ei->f, " }\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VEC_FUNC1_INT(n,T,NAME) \\\n"); + fprintf( ei->f, " __VEC_FUNC1(n,T,int8_t,int64_t,NAME) \\\n"); + fprintf( ei->f, " __VEC_FUNC1(n,T,int16_t,int64_t,NAME) \\\n"); + fprintf( ei->f, " __VEC_FUNC1(n,T,int32_t,int64_t,NAME) \\\n"); + fprintf( ei->f, " __VEC_FUNC1(n,T,int64_t,int64_t,NAME) \\\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VEC_FUNC1_UINT(n,T,NAME) \\\n"); + fprintf( ei->f, " __VEC_FUNC1(n,T,uint8_t,uint64_t,NAME) \\\n"); + fprintf( ei->f, " __VEC_FUNC1(n,T,uint16_t,uint64_t,NAME) \\\n"); + fprintf( ei->f, " __VEC_FUNC1(n,T,uint32_t,uint64_t,NAME) \\\n"); + fprintf( ei->f, " __VEC_FUNC1(n,T,uint64_t,uint64_t,NAME) \\\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VEC_TYPE_POINTER(n,T,TE) \\\n"); + fprintf( ei->f, " __VEC_FUNC_SHUFFLE(n,T,TE) \\\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VEC_TYPE_BOOL(n,T,TE) \\\n"); + fprintf( ei->f, "\n"); + fprintf( ei->f, "#define __VEC_TYPE(n,T,TE) \\\n"); + fprintf( ei->f, " __VEC_FUNC1_UINT(n,T,TRUNC) \\\n"); + fprintf( ei->f, " __VEC_FUNC1_INT(n,T,TRUNC) \\\n"); + fprintf( ei->f, " __VEC_FUNC1_UINT(n,T,ZEXT) \\\n"); + fprintf( ei->f, " __VEC_FUNC1_INT(n,T,SEXT) \\\n"); + fprintf( ei->f, " __VEC_FUNC2(n,T,AND,&) \\\n"); + fprintf( ei->f, " __VEC_FUNC2(n,T,IOR,|) \\\n"); + fprintf( ei->f, " __VEC_FUNC2(n,T,XOR,^) \\\n"); + fprintf( ei->f, " __VEC_FUNC2(n,T,SHL,<<) \\\n"); + fprintf( ei->f, " __VEC_FUNC2_ST(n,T,uint64_t,SHR,>>) \\\n"); + fprintf( ei->f, " __VEC_FUNC2_ST(n,T, int64_t,SAR,>>) \\\n"); + fprintf( ei->f, " __VEC_FUNC2(n,T,ADD,+) \\\n"); + fprintf( ei->f, " __VEC_FUNC2(n,T,SUB,-) \\\n"); + fprintf( ei->f, " __VEC_FUNC2(n,T,MUL,*) \\\n"); + fprintf( ei->f, " __VEC_FUNC2(n,T,DIV,/) \\\n"); + fprintf( ei->f, " __VEC_FUNC2_ST(n,T,uint64_t,UDIV,/) \\\n"); + fprintf( ei->f, " __VEC_FUNC2_ST(n,T, int64_t,SDIV,>>) \\\n"); + fprintf( ei->f, " __VEC_FUNC_SHUFFLE(n,T,TE) \\\n"); + fprintf( ei->f, "\n"); + + return (0); +} /* lcbe_emit_head */ + +int +lcbe_emit_c( lccrt_module_ptr m, const char *c_name) +{ + lccrt_type_ptr type; + lccrt_var_ptr gvar; + lccrt_function_ptr func; + lcbe_emit_t ei; + FILE *f = fopen( c_name, "w"); + + memset( &ei, 0, sizeof( ei)); + ei.f = f; + ei.m = m; + ei.ctx = lccrt_context_new( 0, 0); + ei.type_to_ident = lccrt_hash_new( ei.ctx, LCCRT_HASH_KEY_INTPTR); + ei.type_to_name = lccrt_hash_new( ei.ctx, LCCRT_HASH_KEY_INTPTR); + ei.type_to_namefr = lccrt_hash_new( ei.ctx, LCCRT_HASH_KEY_INTPTR); + ei.obj_to_name = lccrt_hash_new( ei.ctx, LCCRT_HASH_KEY_INTPTR); + ei.obj_to_namefr = lccrt_hash_new( ei.ctx, LCCRT_HASH_KEY_INTPTR); + + if ( !f ) + { + lcbe_emit_done( &ei); + return (-1); + } + + lcbe_emit_head( &ei); + lcbe_emit_types( &ei); + + fprintf( ei.f, "\n"); + fprintf( ei.f, "// DECLARATIONS\n"); + for ( gvar = lccrt_module_get_first_var( m); gvar; gvar = lccrt_var_get_next_var( gvar) ) + { + lcbe_emit_var( &ei, gvar, 0); + } + + for ( func = lccrt_module_get_first_func( m); func; func = lccrt_function_get_next_func( func) ) + { + lcbe_emit_func( &ei, func, 1); + } + + fprintf( ei.f, "\n"); + fprintf( ei.f, "// GLOBAL VARIABLES\n"); + for ( gvar = lccrt_module_get_first_var( m); gvar; gvar = lccrt_var_get_next_var( gvar) ) + { + lcbe_emit_var( &ei, gvar, 1); + } + + for ( func = lccrt_module_get_first_func( m); func; func = lccrt_function_get_next_func( func) ) + { + if ( !lccrt_function_is_declaration( func) ) + { + ei.cur_func = func; + ei.local_to_name = lccrt_hash_new( ei.ctx, LCCRT_HASH_KEY_INTPTR); + ei.oper_to_name = lccrt_hash_new( ei.ctx, LCCRT_HASH_KEY_INTPTR); + ei.lname_ident = 0; + lcbe_emit_func( &ei, func, 0); + ei.oper_to_name = lcbe_name_hash_delete( ei.oper_to_name); + ei.local_to_name = lcbe_name_hash_delete( ei.local_to_name); + ei.cur_func = 0; + } + } + + if ( lccrt_module_get_inline_asm( m) ) + { + fprintf( f, "\n"); + fprintf( f, "asm( \""); + lcbe_fprint( &ei, lccrt_module_get_inline_asm( m)); + fprintf( f, "\");\n"); + } + + fprintf( f, "\n"); + + lcbe_emit_done( &ei); + + return (0); +} /* lcbe_emit_c */ + diff --git a/tools/lccrt_s/include/lccrt_s.h b/tools/lccrt_s/include/lccrt_s.h new file mode 100644 index 0000000..cee47fd --- /dev/null +++ b/tools/lccrt_s/include/lccrt_s.h @@ -0,0 +1,511 @@ +/** + * 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 + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif /* !_GNU_SOURCE */ +#include +#include +#include +#include + +#define __LCCRT_UMAX_U32 (0xffffffffULL) +#define __LCCRT_SMIN_S32 ((int32_t)0x80000000LL) +#define __LCCRT_SMAX_S32 ((int32_t)0x7fffffffLL) +#define __LCCRT_UMAX_U64 (0xffffffffffffffffULL) +#define __LCCRT_SMIN_S64 ((int64_t)0x8000000000000000LL) +#define __LCCRT_SMAX_S64 ((int64_t)0x7fffffffffffffffLL) +#define __LCCRT_SMIN_U64 (0x8000000000000000ULL) +#define __LCCRT_SMAX_U64 (0x7fffffffffffffffULL) + +#define __LCCRT_MIN( a, b) (((a) <= (b)) ? (a) : (b)) +#define __LCCRT_MAX( a, b) (((a) >= (b)) ? (a) : (b)) +#define __LCCRT_BITS( x, h, l) ((((x) << (63ULL - (h)))) >> ((63ULL - (h)) + (l))) + +#define __LCCRT_PRINT_BITS2( b0, b1) \ +( \ + printf( "%s:%d\n%s:%d\n", #b0, (int)(b0), #b1, (int)(b1)) \ +) + +#define __LCCRT_PRINT_BITS3( b0, b1, b2) \ +( \ + printf( "%s:%d\n%s:%d\n%s:%d\n", #b0, (int)(b0), #b1, (int)(b1), #b2, (int)(b2)) \ +) + +#define __LCCRT_PRINT_BITS4( b0, b1, b2, b3) \ +( \ + printf( "%s:%d\n%s:%d\n%s:%d\n:%s:%d\n", #b0, (int)(b0), #b1, (int)(b1), #b2, (int)(b2), #b3, (int)(b3)) \ +) + +#define __LCCRT_N_ARG1( rbits, abits, r, a) \ + uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a + +#define __LCCRT_N_ARG2( rbits, abits, bbits, r, a, b) \ + uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b + +#define __LCCRT_N_ARG3( rbits, abits, bbits, cbits, r, a, b, c) \ + uint32_t rbits, uint32_t abits, uint32_t bbits, uint32_t cbits, uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c + +#define __LCCRT_VEC_ARGS1( rbits, abits, r, a, rnum, anum, rebits, aebits) \ + uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a, \ + uint32_t rnum, uint32_t anum, uint32_t rebits, uint32_t aebits + +#define __LCCRT_VEC_ARGS2( rbits, abits, bbits, r, a, b, rnum, anum, bnum, rebits, aebits, bebits) \ + uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, \ + uint32_t rnum, uint32_t anum, uint32_t bnum, uint32_t rebits, uint32_t aebits, uint32_t bebits + +#define __LCCRT_VEC_ARGS3( rb, ab, bb, cb, r, a, b, c, rn, an, bn, cn, reb, aeb, beb, ceb) \ + uint32_t rb, uint32_t ab, uint32_t bb, uint32_t cb, \ + uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c, \ + uint32_t rn, uint32_t an, uint32_t bn, uint32_t cn, \ + uint32_t reb, uint32_t aeb, uint32_t beb, uint32_t ceb + +typedef float __lccrt_f32_t; +typedef double __lccrt_f64_t; +typedef long double __lccrt_f80_t; + +typedef __lccrt_f32_t f32_t; +typedef __lccrt_f64_t f64_t; + +#define __define_lccrt_nint_t( N) typedef struct { uint8_t a[((N) + 7)/8]; } __lccrt_nint##N##_t + +__define_lccrt_nint_t( 96); + +#if __LCC__ <= 123 +typedef struct +{ + float x; + float y; +} __lccrt_complex_f32; + +typedef struct +{ + double x; + double y; +} __lccrt_complex_f64; + +typedef struct +{ + long double x; + long double y; +} __lccrt_complex_f80; +#endif /* __LCC__ <= 123 */ + +#define __lccrt_vec_typedef( type, N) typedef struct { type a[N]; } __lccrt_vec_##type##_##N +#define __lccrt_vec_si( k, N) __lccrt_vec_int##k##_t_##N +#define __lccrt_vec_ui( k, N) __lccrt_vec_uint##k##_t_##N +#define __lccrt_vec_f( k, N) __lccrt_vec_f##k##_t_##N + +__lccrt_vec_typedef( int32_t, 2); +__lccrt_vec_typedef( int32_t, 16); +__lccrt_vec_typedef( int32_t, 32); + +__lccrt_vec_typedef( int8_t, 16); +__lccrt_vec_typedef( int16_t, 8); +__lccrt_vec_typedef( int32_t, 4); +__lccrt_vec_typedef( int64_t, 2); + +__lccrt_vec_typedef( int8_t, 32); +__lccrt_vec_typedef( int16_t, 16); +__lccrt_vec_typedef( int32_t, 8); +__lccrt_vec_typedef( int64_t, 4); + +__lccrt_vec_typedef( uint8_t, 16); +__lccrt_vec_typedef( uint16_t, 8); +__lccrt_vec_typedef( uint32_t, 4); +__lccrt_vec_typedef( uint64_t, 2); + +__lccrt_vec_typedef( uint8_t, 32); +__lccrt_vec_typedef( uint16_t, 16); +__lccrt_vec_typedef( uint32_t, 8); +__lccrt_vec_typedef( uint64_t, 4); + +__lccrt_vec_typedef( f32_t, 4); +__lccrt_vec_typedef( f64_t, 2); + +__lccrt_vec_typedef( f32_t, 8); +__lccrt_vec_typedef( f64_t, 4); + +typedef struct +{ + uint8_t value; + uint8_t is_overflow; +} __lccrt_overflow_8_t; + +typedef struct +{ + uint16_t value; + uint8_t is_overflow; +} __lccrt_overflow_16_t; + +typedef struct +{ + uint32_t value; + uint8_t is_overflow; +} __lccrt_overflow_32_t; + +typedef struct +{ + uint64_t value; + uint8_t is_overflow; +} __lccrt_overflow_64_t; + +typedef struct +{ + uint64_t lo; + uint64_t hi; +} __lccrt_uint128_t; + +typedef struct +{ + __lccrt_uint128_t value; + uint8_t is_overflow; +} __lccrt_overflow_128_t; + +typedef struct +{ + __lccrt_uint128_t lo; + __lccrt_uint128_t hi; +} __lccrt_uint256_t; + +typedef struct +{ + __lccrt_uint256_t value; + uint8_t is_overflow; +} __lccrt_overflow_256_t; + +extern __lccrt_overflow_8_t __lccrt_uadd_overflow_8( uint64_t a, uint64_t b); +extern __lccrt_overflow_8_t __lccrt_sadd_overflow_8( uint64_t a, uint64_t b); +extern __lccrt_overflow_16_t __lccrt_uadd_overflow_16( uint64_t a, uint64_t b); +extern __lccrt_overflow_16_t __lccrt_sadd_overflow_16( uint64_t a, uint64_t b); +extern __lccrt_overflow_32_t __lccrt_uadd_overflow_32( uint64_t a, uint64_t b); +extern __lccrt_overflow_32_t __lccrt_sadd_overflow_32( uint64_t a, uint64_t b); +extern __lccrt_overflow_64_t __lccrt_uadd_overflow_64( uint64_t a, uint64_t b); +extern __lccrt_overflow_64_t __lccrt_sadd_overflow_64( uint64_t a, uint64_t b); +extern __lccrt_overflow_128_t __lccrt_uadd_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b); +extern __lccrt_overflow_128_t __lccrt_sadd_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b); +extern __lccrt_overflow_256_t __lccrt_uadd_overflow_256( __lccrt_uint256_t a, __lccrt_uint256_t b); +extern __lccrt_overflow_256_t __lccrt_sadd_overflow_256( __lccrt_uint256_t a, __lccrt_uint256_t b); + +extern __lccrt_overflow_8_t __lccrt_usub_overflow_8( uint64_t a, uint64_t b); +extern __lccrt_overflow_8_t __lccrt_ssub_overflow_8( uint64_t a, uint64_t b); +extern __lccrt_overflow_16_t __lccrt_usub_overflow_16( uint64_t a, uint64_t b); +extern __lccrt_overflow_16_t __lccrt_ssub_overflow_16( uint64_t a, uint64_t b); +extern __lccrt_overflow_32_t __lccrt_usub_overflow_32( uint64_t a, uint64_t b); +extern __lccrt_overflow_32_t __lccrt_ssub_overflow_32( uint64_t a, uint64_t b); +extern __lccrt_overflow_64_t __lccrt_usub_overflow_64( uint64_t a, uint64_t b); +extern __lccrt_overflow_64_t __lccrt_ssub_overflow_64( uint64_t a, uint64_t b); +extern __lccrt_overflow_128_t __lccrt_usub_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b); +extern __lccrt_overflow_128_t __lccrt_ssub_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b); + +extern __lccrt_overflow_8_t __lccrt_umul_overflow_8( uint64_t a, uint64_t b); +extern __lccrt_overflow_8_t __lccrt_smul_overflow_8( uint64_t a, uint64_t b); +extern __lccrt_overflow_16_t __lccrt_umul_overflow_16( uint64_t a, uint64_t b); +extern __lccrt_overflow_16_t __lccrt_smul_overflow_16( uint64_t a, uint64_t b); +extern __lccrt_overflow_32_t __lccrt_umul_overflow_32( uint64_t a, uint64_t b); +extern __lccrt_overflow_32_t __lccrt_smul_overflow_32( uint64_t a, uint64_t b); +extern __lccrt_overflow_64_t __lccrt_umul_overflow_64( uint64_t a, uint64_t b); +extern __lccrt_overflow_64_t __lccrt_smul_overflow_64( uint64_t a, uint64_t b); +extern __lccrt_overflow_128_t __lccrt_umul_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b); +extern __lccrt_overflow_128_t __lccrt_smul_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b); + +extern uint8_t __lccrt_uadd_sat_8( uint8_t a, uint8_t b); +extern uint8_t __lccrt_sadd_sat_8( uint8_t a, uint8_t b); +extern uint16_t __lccrt_uadd_sat_16( uint16_t a, uint16_t b); +extern uint16_t __lccrt_sadd_sat_16( uint16_t a, uint16_t b); +extern uint32_t __lccrt_uadd_sat_32( uint32_t a, uint32_t b); +extern uint32_t __lccrt_sadd_sat_32( uint32_t a, uint32_t b); +extern uint64_t __lccrt_uadd_sat_64( uint64_t a, uint64_t b); +extern uint64_t __lccrt_sadd_sat_64( uint64_t a, uint64_t b); +extern __lccrt_uint128_t __lccrt_uadd_sat_128( __lccrt_uint128_t a, __lccrt_uint128_t b); +extern __lccrt_uint128_t __lccrt_sadd_sat_128( __lccrt_uint128_t a, __lccrt_uint128_t b); + +extern uint8_t __lccrt_usub_sat_8( uint8_t a, uint8_t b); +extern uint8_t __lccrt_ssub_sat_8( uint8_t a, uint8_t b); +extern uint16_t __lccrt_usub_sat_16( uint16_t a, uint16_t b); +extern uint16_t __lccrt_ssub_sat_16( uint16_t a, uint16_t b); +extern uint32_t __lccrt_usub_sat_32( uint32_t a, uint32_t b); +extern uint32_t __lccrt_ssub_sat_32( uint32_t a, uint32_t b); +extern uint64_t __lccrt_usub_sat_64( uint64_t a, uint64_t b); +extern uint64_t __lccrt_ssub_sat_64( uint64_t a, uint64_t b); +extern __lccrt_uint128_t __lccrt_usub_sat_128( __lccrt_uint128_t a, __lccrt_uint128_t b); +extern __lccrt_uint128_t __lccrt_ssub_sat_128( __lccrt_uint128_t a, __lccrt_uint128_t b); + +extern uint8_t __lccrt_umul_sat_8( uint8_t a, uint8_t b); +extern uint8_t __lccrt_smul_sat_8( uint8_t a, uint8_t b); +extern uint16_t __lccrt_umul_sat_16( uint16_t a, uint16_t b); +extern uint16_t __lccrt_smul_sat_16( uint16_t a, uint16_t b); +extern uint32_t __lccrt_umul_sat_32( uint32_t a, uint32_t b); +extern uint32_t __lccrt_smul_sat_32( uint32_t a, uint32_t b); +extern uint64_t __lccrt_umul_sat_64( uint64_t a, uint64_t b); +extern uint64_t __lccrt_smul_sat_64( uint64_t a, uint64_t b); +//extern uint8_t __lccrt_umul_sat_128( uint8_t a, uint8_t b); +//extern uint8_t __lccrt_smul_sat_128( uint8_t a, uint8_t b); + +extern uint8_t __lccrt_fshl_i8( uint8_t a, uint8_t b, uint8_t c); +extern uint16_t __lccrt_fshl_i16( uint16_t a, uint16_t b, uint16_t c); +extern uint32_t __lccrt_fshl_i32( uint32_t a, uint32_t b, uint32_t c); +extern uint64_t __lccrt_fshl_i64( uint64_t a, uint64_t b, uint64_t c); +extern uint8_t __lccrt_fshr_8( uint8_t a, uint8_t b, uint8_t c); +extern uint16_t __lccrt_fshr_16( uint16_t a, uint16_t b, uint16_t c); +extern uint32_t __lccrt_fshr_32( uint32_t a, uint32_t b, uint32_t c); +extern uint64_t __lccrt_fshr_64( uint64_t a, uint64_t b, uint64_t c); +extern __lccrt_uint128_t __lccrt_fshl_i128( __lccrt_uint128_t a, __lccrt_uint128_t b, __lccrt_uint128_t c); +extern __lccrt_uint128_t __lccrt_fshr_128( __lccrt_uint128_t a, __lccrt_uint128_t b, __lccrt_uint128_t c); + +extern void __lccrt_bitcast_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_select( uint32_t rbits, uint32_t abits, uint32_t bbits, uint32_t cbits, + uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c); +extern void __lccrt_abs_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_zext_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_sext_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_trunc_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_shl_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_shr_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_sar_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_fshl_n( __LCCRT_N_ARG3( rbits, abits, bbits, cbits, r, a, b, c)); +extern void __lccrt_and_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_or_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_xor_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_add_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_sub_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_mul_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_udiv_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_sdiv_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_umod_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_smod_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_fmod_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_minnum_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_maxnum_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_fneg_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_shuffle_n( uint32_t rbits, uint32_t abits, uint32_t bbits, uint32_t cbits, + uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t cn); +extern void __lccrt_fptofp_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_fptosi_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_fptoui_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_sitofp_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_uitofp_n( uint32_t rbits, uint32_t abits, uint8_t *r, uint8_t *a); +extern void __lccrt_uadd_sat_n( __LCCRT_N_ARG2( rbits, abits, bbits, r, a, b)); +extern void __lccrt_sadd_sat_n( __LCCRT_N_ARG2( rbits, abits, bbits, r, a, b)); +extern void __lccrt_usub_sat_n( __LCCRT_N_ARG2( rbits, abits, bbits, r, a, b)); +extern void __lccrt_ssub_sat_n( __LCCRT_N_ARG2( rbits, abits, bbits, r, a, b)); +extern void __lccrt_bswap_n( __LCCRT_N_ARG1( rbits, abits, r, a)); +extern void __lccrt_bitreverse_n( __LCCRT_N_ARG1( rbits, abits, r, a)); +extern void __lccrt_ctpop_n( __LCCRT_N_ARG1( rbits, abits, r, a)); + +extern void __lccrt_shl_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_shr_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_sar_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_fshl_v( __LCCRT_VEC_ARGS3( rb, ab, bb, cb, r, a, b, c, rn, an, bn, cn, reb, aeb, beb, ceb)); +extern void __lccrt_and_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_or_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_xor_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_add_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_sub_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_mul_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_udiv_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_sdiv_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_umod_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_smod_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_fadd_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_fsub_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_fmul_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_fmuladd_v( __LCCRT_VEC_ARGS3( rb, ab, bb, cb, r, a, b, c, rn, an, bn, cn, reb, aeb, beb, ceb)); +extern void __lccrt_fdiv_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_fmod_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_minnum_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_maxnum_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_abs_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_reduce_fmin_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_reduce_fmax_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_fneg_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_ptoi_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_itop_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_fptofp_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_fptosi_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_fptoui_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_sitofp_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_uitofp_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_trunc_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_uadd_sat_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_sadd_sat_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_usub_sat_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_ssub_sat_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_fabs_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_sqrt_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_exp2_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_log2_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_exp10_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_log10_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_exp_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_log_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_cos_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_sin_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_tan_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_acos_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_asin_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_pow_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_powi_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)); +extern void __lccrt_bswap_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_bitreverse_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_ctpop_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_fma_v( __LCCRT_VEC_ARGS3( rb, ab, bb, cb, r, a, b, c, rn, an, bn, cn, reb, aeb, beb, ceb)); +extern void __lccrt_floor_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_ceil_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_round_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_ftrunc_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); +extern void __lccrt_rint_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)); + +extern void __lccrt_cmp_n_eq_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_n_ne_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_n_lt_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_n_lt_u( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_n_le_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_n_le_u( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_n_gt_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_n_gt_u( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_n_ge_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_n_ge_u( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); + +extern void __lccrt_cmp_v_eq_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn); +extern void __lccrt_cmp_v_ne_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn); +extern void __lccrt_cmp_v_lt_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn); +extern void __lccrt_cmp_v_lt_u( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn); +extern void __lccrt_cmp_v_le_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn); +extern void __lccrt_cmp_v_le_u( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn); +extern void __lccrt_cmp_v_gt_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn); +extern void __lccrt_cmp_v_gt_u( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn); +extern void __lccrt_cmp_v_ge_i( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn); +extern void __lccrt_cmp_v_ge_u( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn); + +extern void __lccrt_cmp_fo( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_fu( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_eq_fu( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_ne_fu( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_lt_fu( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_le_fu( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_gt_fu( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); +extern void __lccrt_cmp_ge_fu( uint32_t rbits, uint32_t abits, uint32_t bbits, uint8_t *r, uint8_t *a, uint8_t *b); + +extern uint64_t __lccrt_ctlz_8( uint64_t a); +extern uint64_t __lccrt_ctlz_16( uint64_t a); +extern uint64_t __lccrt_ctlz_32( uint64_t a); +extern uint64_t __lccrt_ctlz_64( uint64_t a); +extern __lccrt_uint128_t __lccrt_ctlz_128( __lccrt_uint128_t a); +extern uint64_t __lccrt_cttz_8( uint64_t a); +extern uint64_t __lccrt_cttz_16( uint64_t a); +extern uint64_t __lccrt_cttz_32( uint64_t a); +extern uint64_t __lccrt_cttz_64( uint64_t a); +extern __lccrt_uint128_t __lccrt_cttz_128( __lccrt_uint128_t a); +extern uint64_t __lccrt_ctpop_i8( uint64_t a); +extern uint64_t __lccrt_ctpop_i16( uint64_t a); +extern uint64_t __lccrt_ctpop_i32( uint64_t a); +extern uint64_t __lccrt_ctpop_i64( uint64_t a); +extern __lccrt_uint128_t __lccrt_ctpop_i128( __lccrt_uint128_t a); +extern uint64_t __lccrt_bitreverse_8( uint64_t a); +extern uint64_t __lccrt_bitreverse_16( uint64_t a); +extern uint64_t __lccrt_bitreverse_32( uint64_t a); +extern uint64_t __lccrt_bitreverse_64( uint64_t a); +extern __lccrt_uint128_t __lccrt_bitreverse_128( __lccrt_uint128_t a); + +#if defined( __LCC__) && (__LCC__ <= 123) +extern __lccrt_complex_f32 __mulsc3( __lccrt_f32_t a, __lccrt_f32_t b, __lccrt_f32_t c, __lccrt_f32_t d); +extern __lccrt_complex_f64 __muldc3( __lccrt_f64_t a, __lccrt_f64_t b, __lccrt_f64_t c, __lccrt_f64_t d); +extern __lccrt_complex_f32 __divsc3( __lccrt_f32_t a, __lccrt_f32_t b, __lccrt_f32_t c, __lccrt_f32_t d); +extern __lccrt_complex_f64 __divdc3( __lccrt_f64_t a, __lccrt_f64_t b, __lccrt_f64_t c, __lccrt_f64_t d); +#endif /* __LCC__ <= 123 */ + +int8_t __atomic_fetch_max_1( int8_t *a, int8_t b); +int16_t __atomic_fetch_max_2( int16_t *a, int16_t b); +int32_t __atomic_fetch_max_4( int32_t *a, int32_t b); +int64_t __atomic_fetch_max_8( int64_t *a, int64_t b); +int8_t __atomic_fetch_min_1( int8_t *a, int8_t b); +int16_t __atomic_fetch_min_2( int16_t *a, int16_t b); +int32_t __atomic_fetch_min_4( int32_t *a, int32_t b); +int64_t __atomic_fetch_min_8( int64_t *a, int64_t b); +uint8_t __atomic_fetch_umax_1( uint8_t *a, uint8_t b); +uint16_t __atomic_fetch_umax_2( uint16_t *a, uint16_t b); +uint32_t __atomic_fetch_umax_4( uint32_t *a, uint32_t b); +uint64_t __atomic_fetch_umax_8( uint64_t *a, uint64_t b); +uint8_t __atomic_fetch_umin_1( uint8_t *a, uint8_t b); +uint16_t __atomic_fetch_umin_2( uint16_t *a, uint16_t b); +uint32_t __atomic_fetch_umin_4( uint32_t *a, uint32_t b); +uint64_t __atomic_fetch_umin_8( uint64_t *a, uint64_t b); + +extern __lccrt_vec_si( 8, 16) __lccopt_shuffle_v16i8( __lccrt_vec_si( 8, 16) x, __lccrt_vec_si( 8, 16) y, + __lccrt_vec_si( 32, 16) c); +extern __lccrt_vec_si( 16, 8) __lccopt_shuffle_v8i16( __lccrt_vec_si( 16, 8) x, __lccrt_vec_si( 16, 8) y, + __lccrt_vec_si( 32, 8) c); +extern __lccrt_vec_si( 32, 4) __lccopt_shuffle_v4i32( __lccrt_vec_si( 32, 4) x, __lccrt_vec_si( 32, 4) y, + __lccrt_vec_si( 32, 4) c); +extern __lccrt_vec_si( 64, 2) __lccopt_shuffle_v2i64( __lccrt_vec_si( 64, 2) x, __lccrt_vec_si( 64, 2) y, + __lccrt_vec_si( 32, 2) c); + +extern __lccrt_vec_si( 8, 32) __lccopt_shuffle_v32i8( __lccrt_vec_si( 8, 32) x, __lccrt_vec_si( 8, 32) y, + __lccrt_vec_si( 32, 32) c); +extern __lccrt_vec_si( 16, 16) __lccopt_shuffle_v16i16( __lccrt_vec_si( 16, 16) x, __lccrt_vec_si( 16, 16) y, + __lccrt_vec_si( 32, 16) c); +extern __lccrt_vec_si( 32, 8) __lccopt_shuffle_v8i32( __lccrt_vec_si( 32, 8) x, __lccrt_vec_si( 32, 8) y, + __lccrt_vec_si( 32, 8) c); +extern __lccrt_vec_si( 64, 4) __lccopt_shuffle_v4i64( __lccrt_vec_si( 64, 4) x, __lccrt_vec_si( 64, 4) y, + __lccrt_vec_si( 32, 4) c); + +extern __lccrt_vec_f( 32, 4) __lccopt_shuffle_v4f32( __lccrt_vec_f( 32, 4) x, __lccrt_vec_f( 32, 4) y, + __lccrt_vec_si( 32, 4) c); +extern __lccrt_vec_f( 64, 2) __lccopt_shuffle_v2f64( __lccrt_vec_f( 64, 2) x, __lccrt_vec_f( 64, 2) y, + __lccrt_vec_si( 32, 2) c); + +extern __lccrt_vec_f( 32, 8) __lccopt_shuffle_v8f32( __lccrt_vec_f( 32, 8) x, __lccrt_vec_f( 32, 8) y, + __lccrt_vec_si( 32, 8) c); +extern __lccrt_vec_f( 64, 4) __lccopt_shuffle_v4f64( __lccrt_vec_f( 64, 4) x, __lccrt_vec_f( 64, 4) y, + __lccrt_vec_si( 32, 4) c); + +extern __lccrt_uint128_t __lccrt_bswap_128( __lccrt_uint128_t v); + +extern int8_t __lccrt_fptosi_sat_i8f32( __lccrt_f32_t); +extern int8_t __lccrt_fptosi_sat_i8f64( __lccrt_f64_t); +extern int8_t __lccrt_fptosi_sat_i8f80( __lccrt_f80_t); +extern int16_t __lccrt_fptosi_sat_i16f32( __lccrt_f32_t); +extern int16_t __lccrt_fptosi_sat_i16f64( __lccrt_f64_t); +extern int16_t __lccrt_fptosi_sat_i16f80( __lccrt_f80_t); +extern int32_t __lccrt_fptosi_sat_i32f32( __lccrt_f32_t); +extern int32_t __lccrt_fptosi_sat_i32f64( __lccrt_f64_t); +extern int32_t __lccrt_fptosi_sat_i32f80( __lccrt_f80_t); +extern int64_t __lccrt_fptosi_sat_i64f32( __lccrt_f32_t); +extern int64_t __lccrt_fptosi_sat_i64f64( __lccrt_f64_t); +extern int64_t __lccrt_fptosi_sat_i64f80( __lccrt_f80_t); +extern __lccrt_uint128_t __lccrt_fptosi_sat_i128f32( __lccrt_f32_t); +extern __lccrt_uint128_t __lccrt_fptosi_sat_i128f64( __lccrt_f64_t); + +extern uint8_t __lccrt_fptoui_sat_i8f32( __lccrt_f32_t); +extern uint8_t __lccrt_fptoui_sat_i8f64( __lccrt_f64_t); +extern uint8_t __lccrt_fptoui_sat_i8f80( __lccrt_f80_t); +extern uint16_t __lccrt_fptoui_sat_i16f32( __lccrt_f32_t); +extern uint16_t __lccrt_fptoui_sat_i16f64( __lccrt_f64_t); +extern uint16_t __lccrt_fptoui_sat_i16f80( __lccrt_f80_t); +extern uint32_t __lccrt_fptoui_sat_i32f32( __lccrt_f32_t); +extern uint32_t __lccrt_fptoui_sat_i32f64( __lccrt_f64_t); +extern uint32_t __lccrt_fptoui_sat_i32f80( __lccrt_f80_t); +extern uint64_t __lccrt_fptoui_sat_i64f32( __lccrt_f32_t); +extern uint64_t __lccrt_fptoui_sat_i64f64( __lccrt_f64_t); +extern uint64_t __lccrt_fptoui_sat_i64f80( __lccrt_f80_t); +extern __lccrt_uint128_t __lccrt_fptoui_sat_i128f32( __lccrt_f32_t); +extern __lccrt_uint128_t __lccrt_fptoui_sat_i128f64( __lccrt_f64_t); + +extern __lccrt_nint96_t __lccrt_fshl_i96( __lccrt_nint96_t, __lccrt_nint96_t, __lccrt_nint96_t); + +extern uint8_t __lccrt_typetest_unsupported_yet( void); diff --git a/tools/lccrt_s/src/lccrt.c b/tools/lccrt_s/src/lccrt.c new file mode 100644 index 0000000..d7a1afa --- /dev/null +++ b/tools/lccrt_s/src/lccrt.c @@ -0,0 +1,203 @@ +/** + * 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 + */ + +#include "lccrt_s.h" + +#include + +uint64_t +__lccrt_ctlz_8( uint64_t a) +{ + uint64_t r = __builtin_clz( a & 0xff) - 24; + + return (r); +} /* __lccrt_ctlz_8 */ + +uint64_t +__lccrt_ctlz_16( uint64_t a) +{ + uint64_t r = __builtin_clz( a & 0xffff) - 16; + + return (r); +} /* __lccrt_ctlz_16 */ + +uint64_t +__lccrt_ctlz_32( uint64_t a) +{ + uint64_t r = __builtin_clz( a); + + return (r); +} /* __lccrt_ctlz_32 */ + +uint64_t +__lccrt_ctlz_64( uint64_t a) +{ + uint64_t r = __builtin_clzll( a); + + return (r); +} /* __lccrt_ctlz_64 */ + +uint64_t +__lccrt_cttz_8( uint64_t a) +{ + uint64_t r = __builtin_ctz( a | (1U << 8U)); + + return (r); +} /* __lccrt_cttz_8 */ + +uint64_t +__lccrt_cttz_16( uint64_t a) +{ + uint64_t r = __builtin_ctz( a | (1U << 16U)); + + return (r); +} /* __lccrt_cttz_16 */ + +uint64_t +__lccrt_cttz_32( uint64_t a) +{ + uint64_t r = __builtin_ctz( a); + + return (r); +} /* __lccrt_cttz_32 */ + +uint64_t +__lccrt_cttz_64( uint64_t a) +{ + uint64_t r = __builtin_ctzll( a); + + return (r); +} /* __lccrt_cttz_64 */ + +uint64_t +__lccrt_ctpop_i8( uint64_t a) +{ + uint64_t r = __builtin_popcount( a & 0xff); + + return (r); +} /* __lccrt_ctpop_i8 */ + +uint64_t +__lccrt_ctpop_i16( uint64_t a) +{ + uint64_t r = __builtin_popcount( a & 0xffff); + + return (r); +} /* __lccrt_ctpop_i16 */ + +uint64_t +__lccrt_ctpop_i32( uint64_t a) +{ + uint64_t r = __builtin_popcount( a); + + return (r); +} /* __lccrt_ctpop_i32 */ + +uint64_t +__lccrt_ctpop_i64( uint64_t a) +{ + uint64_t r = __builtin_popcountll( a); + + return (r); +} /* __lccrt_ctpop_i64 */ + +__lccrt_uint128_t +__lccrt_ctpop_i128( __lccrt_uint128_t a) +{ + __lccrt_uint128_t r = {0}; + + r.lo = __builtin_popcountll( a.hi) + __builtin_popcountll( a.lo); + + return (r); +} /* __lccrt_ctpop_i128 */ + +double __lccrt___lccrt_sqrt_f64( double) asm( "__lccrt_sqrt.f64"); + +double +__lccrt___lccrt_sqrt_f64( double a) +{ + assert( 0); +} + +void +__builtin_lccopt_mul_4_x_i8( void) +{ + assert( 0); +} + +void +__builtin_lccopt_shuffle_4_x_i8( void) +{ + assert( 0); +} + +#if defined( __LCC__) && (__LCC__ <= 123) +__lccrt_complex_f32 +__mulsc3( float a, float b, float c, float d) +{ + __lccrt_complex_f32 r = {a*c - b*d, a*d + b*c}; + + return (r); +} /* __mulsc3 */ +#endif /* __LCC__ <= 123 */ + +#if defined( __LCC__) && (__LCC__ <= 123) +__lccrt_complex_f64 +__muldc3( __lccrt_f64_t a, __lccrt_f64_t b, __lccrt_f64_t c, __lccrt_f64_t d) +{ + __lccrt_complex_f64 r = {a*c - b*d, a*d + b*c}; + + return (r); +} /* __muldc3 */ +#endif /* __LCC__ <= 123 */ + +#if defined( __LCC__) && (__LCC__ <= 123) +__lccrt_complex_f32 +__divsc3( float a, float b, float c, float d) +{ + float v2 = c*c + d*d; + __lccrt_complex_f32 r = {(a*c - b*d)/v2, (a*d + b*c)/v2}; + + return (r); +} /* __divsc3 */ +#endif /* __LCC__ <= 123 */ + +#if defined( __LCC__) && (__LCC__ <= 123) +__lccrt_complex_f64 +__divdc3( __lccrt_f64_t a, __lccrt_f64_t b, __lccrt_f64_t c, __lccrt_f64_t d) +{ + __lccrt_f64_t v2 = c*c + d*d; + __lccrt_complex_f64 r = {(a*c - b*d)/v2, (a*d + b*c)/v2}; + + return (r); +} /* __divdc3 */ +#endif /* __LCC__ <= 123 */ + +extern void __lccrt_lifetime_start( void) asm( "llvm.lifetime.start.p0i8"); +extern void __lccrt_lifetime_end( void) asm( "llvm.lifetime.end.p0i8"); +extern void *__lccrt_frameaddress( void) asm( "llvm.frameaddress.p0i8"); + +void __lccrt_lifetime_start( void) {} +void __lccrt_lifetime_end( void) {} +void *__lccrt_frameaddress() { return (0); } + +void __lccrt_stacksave( void) { assert( 0); } +void __lccrt_stackrestore( void) { assert( 0); } + +int8_t +__atomic_fetch_max_1( int8_t *a, int8_t b) +{ + assert( 0); + return (0); +} /* __atomic_fetch_max_1 */ + +uint8_t +__lccrt_typetest_unsupported_yet( void) +{ + assert( 0); + + return (0); +} /* __lccrt_typetest_unsupported_yet */ diff --git a/tools/lccrt_s/src/lccrt_n.c b/tools/lccrt_s/src/lccrt_n.c new file mode 100644 index 0000000..99eb236 --- /dev/null +++ b/tools/lccrt_s/src/lccrt_n.c @@ -0,0 +1,3754 @@ +/** + * 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 + */ + +#include "lccrt_s.h" + +#include +#include +#include +#include + +#define __LCCRT_SHIFT_LR( v, a) (((v) << (a)) >> (a)) +#define __LCCRT_SEXT( v, bits) __LCCRT_SHIFT_LR( ( int64_t)(v), 64LL - (bits)) +#define __LCCRT_ZEXT( v, bits) __LCCRT_SHIFT_LR( (uint64_t)(v), 64ULL - (bits)) +#define __LCCRT_CMP( a, b) (((a) < (b)) ? (-1) : (((a) == (b)) ? 0 : 1)) + +#define __LCCRT_NUM_DIGITS( a, b, c) (((__LCCRT_MAX( a, __LCCRT_MAX( b, c))) + 31) / 32) +#define __LCCRT_NUM_DIGITS4( a, b, c, d) (((__LCCRT_MAX( __LCCRT_MAX( a, b), __LCCRT_MAX( c, d))) + 31) / 32) + +#define __LCCRT_ALIGN_BITS_N( b) \ + ( \ + ((b) <= 8) ? 8 : (((b) <= 16) ? 16 : (((b) <= 32) ? 32 : (((b) + 63) & ~63ULL))) \ + ) + +#define __LCCRT_CONV( dst, dst_type, src) \ +{ \ + dst_type conv_value = (dst_type)src; \ + memcpy( dst, &conv_value, sizeof( conv_value)); \ +} + +#define __LCCRT_BIT_INDEX( bsize, aind, k) \ +( \ + ((bsize) == 8) \ + ? ((uint8_t *)aind)[k] \ + : (((bsize) == 16) \ + ? ((uint16_t *)aind)[k] \ + : (((bsize) == 32) \ + ? ((uint32_t *)aind)[k] \ + : ((uint64_t *)aind)[k])) \ +) + +typedef __lccrt_f32_t (*__lccrt_ffunc32_t)( __lccrt_f32_t, __lccrt_f32_t); +typedef __lccrt_f64_t (*__lccrt_ffunc64_t)( __lccrt_f64_t, __lccrt_f64_t); +typedef __lccrt_f80_t (*__lccrt_ffunc80_t)( __lccrt_f80_t, __lccrt_f80_t); + +typedef __lccrt_f32_t (*__lccrt_ffunc32_3_t)( __lccrt_f32_t, __lccrt_f32_t, __lccrt_f32_t); +typedef __lccrt_f64_t (*__lccrt_ffunc64_3_t)( __lccrt_f64_t, __lccrt_f64_t, __lccrt_f64_t); +typedef __lccrt_f80_t (*__lccrt_ffunc80_3_t)( __lccrt_f80_t, __lccrt_f80_t, __lccrt_f80_t); + +typedef enum +{ + A_LCCRT_CMP_EQ, + A_LCCRT_CMP_NE, + A_LCCRT_CMP_GT_I, + A_LCCRT_CMP_GE_I, + A_LCCRT_CMP_LT_I, + A_LCCRT_CMP_LE_I, + A_LCCRT_CMP_LT_U, + A_LCCRT_CMP_LE_U, + A_LCCRT_CMP_GT_U, + A_LCCRT_CMP_GE_U, + A_LCCRT_CMP_FO, + A_LCCRT_CMP_EQ_FO, + A_LCCRT_CMP_NE_FO, + A_LCCRT_CMP_LT_FO, + A_LCCRT_CMP_LE_FO, + A_LCCRT_CMP_GT_FO, + A_LCCRT_CMP_GE_FO, + A_LCCRT_CMP_FU, + A_LCCRT_CMP_EQ_FU, + A_LCCRT_CMP_NE_FU, + A_LCCRT_CMP_LT_FU, + A_LCCRT_CMP_LE_FU, + A_LCCRT_CMP_GT_FU, + A_LCCRT_CMP_GE_FU, +} __lccrt_cmp_type_t; + +#if 0 +static uint64_t +__lccrt_get_bits( uint64_t v, uint64_t lo, uint64_t hi) +{ + uint64_t up = 63ULL - hi; + uint64_t r = (v << up) >> (lo + up); + + return (r); +} /* __lccrt_get_bits */ + +static uint64_t +__lccrt_set_bits( uint64_t a, uint64_t lo, uint64_t hi, uint64_t v) +{ + uint64_t ml = __lccrt_get_bits( ~0ULL, lo, hi); + uint64_t mh = ml << lo; + uint64_t r = (a & ~mh) | ((v << lo) & mh); + + return (r); +} /* __lccrt_set_bits */ +#endif + +static void +__lccrt_zn_set_bits( uint32_t num_digits, int is_sign, uint32_t *za, uint32_t bb, uint8_t *b) +{ + uint8_t *a = (uint8_t *)za; + + if ( (bb == 0) ) + { + memset( a, 0, 4*num_digits); + + } else if ( (32*num_digits <= bb) ) + { + memcpy( a, b, 4*num_digits); + } else + { + uint8_t sn = 0; + int bytes = (bb + 7) / 8; + int digits = (bb + 31) / 32; + + memcpy( a, b, bytes); + if ( (bb % 32 != 0) ) + { + if ( is_sign ) + { + za[digits-1] = __LCCRT_SEXT( za[digits-1], bb % 32); + } else + { + za[digits-1] = __LCCRT_ZEXT( za[digits-1], bb % 32); + } + } + + if ( (digits < num_digits) ) + { + if ( is_sign ) + { + sn = (int32_t)za[digits-1] >> 31; + } + + memset( a + 4*digits, sn, 4*(num_digits - digits)); + } + } + + return; +} /* __lccrt_zn_set_bits */ + +static void +__lccrt_zn_get_bits( uint32_t num_digits, uint32_t *za, uint32_t bb, uint8_t *b) +{ + uint8_t *a = (uint8_t *)za; + uint32_t ab = __LCCRT_MIN( 32*num_digits, bb); + uint32_t abytes_part = ab / 8; + uint32_t abytes = (ab + 7) / 8; + uint32_t bbytes = (bb + 7) / 8; + + memcpy( b, a, abytes_part); + if ( (abytes_part < abytes) ) + { + b[abytes_part] = __LCCRT_ZEXT( a[abytes_part], ab - 8*abytes_part); + } + + if ( (abytes < bbytes) ) + { + memset( b + abytes, 0, bbytes - abytes); + } + + return; +} /* __lccrt_zn_get_bits */ + +static void +__lccrt_zn_abs( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, int *is_overflow) +{ + int i, j; + uint32_t zc[num_digits]; + + memset( zc, 0, num_digits*sizeof( zc[0])); + + if ( (num_digits == 1) ) + { + zc[0] = ((int32_t)za[0] >= (int32_t)0) ? (int32_t)za[0] : -(int32_t)za[0]; + + } else if ( (num_digits == 2) ) + { + uint64_t bits = 32; + uint64_t va = ((uint64_t)za[1] << bits) | za[0]; + uint64_t vc = ((int64_t)va >= (int64_t)0) ? (int64_t)va : -(int64_t)va; + + zc[0] = (uint32_t)vc; + zc[1] = vc >> bits; + } else + { + assert( 0); + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_abs */ + +static int +__lccrt_zn_cmp( uint32_t num_digits, uint32_t *za, uint32_t *zb) +{ + int i; + int r = 0; + + for ( i = num_digits - 1; (i >= 0) && (r == 0); --i ) + { + if ( (za[i] < zb[i]) ) + { + r = -1; + + } else if ( (za[i] > zb[i]) ) + { + r = 1; + } + } + + return (r); +} /* __lccrt_zn_cmp */ + +static int +__lccrt_zn_cmp_signed( uint32_t num_digits, uint32_t *za, uint32_t *zb) +{ + int i; + int r = 0; + + if ( (num_digits > 0) ) + { + int32_t va = za[num_digits - 1]; + int32_t vb = zb[num_digits - 1]; + + if ( (va < 0) && (vb >= 0) ) + { + r = -1; + + } else if ( (va >= 0) && (vb < 0) ) + { + r = 1; + } else + { + int q = __lccrt_zn_cmp( num_digits, za, zb); + + if ( (va < 0) && (vb < 0) ) + { + r = q; + + } else if ( (va >= 0) && (vb >= 0) ) + { + r = q; + } else + { + assert( 0); + } + } + } + + return (r); +} /* __lccrt_zn_cmp_signed */ + +static void +__lccrt_zn_sar( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb, int *is_overflow) +{ + int i; + uint32_t zc[num_digits]; + uint32_t w = zb[0]; + int is_long = 0; + int digit_bits = 8*sizeof( zc[0]); + uint32_t sn = (int32_t)za[num_digits - 1] >> (digit_bits - 1); + + for ( i = 1; i < num_digits; ++i ) + { + if ( zb[i] ) + { + is_long = 1; + break; + } + } + + if ( (w >= num_digits*8*sizeof( zr[0])) ) + { + is_long = 1; + } + + if ( is_long ) + { + /* Величина сдвига превышает или равна полному количеству битов, поэтому + просто заполняем все цифры знаком. */ + for ( i = 0; i < num_digits; ++i ) + { + zr[i] = sn; + } + } else + { + int digit_shift = w / digit_bits; + int lo_bits = w % digit_bits; + int hi_bits = digit_bits - lo_bits; + uint32_t lo = (lo_bits > 0) ? (sn << hi_bits) : 0; + + /* Сначала сдвигаем на остаток по модулю количества бит в цифре. */ + for ( i = num_digits-1; i >= 0; i-- ) + { + zc[i] = lo | (za[i] >> lo_bits); + lo = (lo_bits > 0) ? (za[i] << hi_bits) : 0; + } + + /* Теперь сдвигаем на оставшуюся часть, уже кратную количеству бит в цифре. */ + for ( i = 0; i + digit_shift < num_digits ; ++i ) + { + zr[i] = zc[i + digit_shift]; + } + + /* Заполняем старшие цифры знаком. */ + for ( i = num_digits - digit_shift; i < num_digits; ++i ) + { + zr[i] = sn; + } + } + + return; +} /* __lccrt_zn_sar */ + +static void +__lccrt_zn_shl( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb) +{ + int i; + uint32_t x, y; + uint32_t zc[num_digits]; + uint32_t num_bits = 32*num_digits; + uint32_t bit_shift = zb[0] % num_bits; + uint32_t shift0 = bit_shift % 32; + uint32_t dig_shift = bit_shift / 32; + + memset( zc, 0, 4*dig_shift); + memcpy( zc + dig_shift, za, 4*(num_digits - dig_shift)); + + if ( (shift0 > 0) ) + { + x = 0; + for ( i = dig_shift; i < num_digits; ++i ) + { + y = zc[i]; + zc[i] = (y << shift0) | x; + x = y >> (32 - shift0); + } + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_shl */ + +static void +__lccrt_zn_shr( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb) +{ + int i; + uint32_t x, y; + uint32_t zc[num_digits]; + uint32_t num_bits = 32*num_digits; + uint32_t bit_shift = zb[0] % num_bits; + uint32_t shift0 = bit_shift % 32; + uint32_t dig_shift = bit_shift / 32; + + memset( zc + (num_digits - dig_shift), 0, 4*dig_shift); + memcpy( zc, za + dig_shift, 4*(num_digits - dig_shift)); + + if ( (shift0 > 0) ) + { + x = 0; + for ( i = num_digits - 1; i >= (int)dig_shift; --i ) + { + y = zc[i]; + zc[i] = (y >> shift0) | x; + x = y << (32 - shift0); + } + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_shr */ + +static void +__lccrt_zn_ior( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb) +{ + int i; + uint32_t zc[num_digits]; + + for ( i = 0; i < num_digits; ++i ) + { + zc[i] = za[i] | zb[i]; + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_ior */ + +static void +__lccrt_zn_add( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb, int *is_overflow) +{ + int i; + uint32_t zc[num_digits]; + uint64_t carry = 0; + + for ( i = 0; i < num_digits; ++i ) + { + carry = (uint64_t)za[i] + (uint64_t)zb[i] + carry; + zc[i] = (uint32_t)carry; + carry = carry >> 32ULL; + } + + if ( is_overflow ) + { + is_overflow[0] = (carry != 0); + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_add */ + +static void +__lccrt_zn_sub( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb, int *is_overflow) +{ + int i; + uint32_t zc[num_digits]; + int flag = 0; + uint64_t carry = 1; + + for ( i = 0; i < num_digits; ++i ) + { + carry = (uint64_t)za[i] + (uint64_t)(zb[i] ^ 0xffffffff) + carry; + zc[i] = (uint32_t)carry; + carry = carry >> 32ULL; + } + + if ( is_overflow ) + { + is_overflow[0] = (__lccrt_zn_cmp( num_digits, za, zb) < 0); + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_sub */ + +static void +__lccrt_zn_mul( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb, int *is_overflow) +{ + int i, j; + uint32_t zc[num_digits]; + int flag = 0; + + memset( zc, 0, num_digits*sizeof( zc[0])); + + for ( j = 0; j < num_digits; ++j ) + { + uint64_t carry = 0; + + for ( i = 0; i < num_digits - j; ++i ) + { + carry = ((uint64_t)za[i] * (uint64_t)zb[j]) + (uint64_t)zc[j + i] + carry; + zc[j + i] = (uint32_t)carry; + carry = carry >> 32ULL; + } + + if ( carry ) + { + flag = 1; + } + } + + if ( is_overflow ) + { + for ( j = 1; (j < num_digits) && (flag == 0); ++j ) + { + if ( zb[j] ) + { + for ( i = num_digits - j; (i < num_digits) && (flag == 0); ++i ) + { + if ( za[i] ) + { + flag = 1; + } + } + } + } + + is_overflow[0] = flag; + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_mul */ + +static void +__lccrt_zn_udiv( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb, + int *is_overflow) +{ + int i, j; + uint32_t zc[num_digits]; + + memset( zc, 0, num_digits*sizeof( zc[0])); + + if ( (num_digits == 1) ) + { + zc[0] = za[0] / zb[0]; + + } else if ( (num_digits == 2) ) + { + uint64_t bits = 32; + uint64_t va = ((uint64_t)za[1] << bits) | za[0]; + uint64_t vb = ((uint64_t)zb[1] << bits) | zb[0]; + uint64_t vc = va / vb; + + zc[0] = (uint32_t)vc; + zc[1] = vc >> bits; + } else + { + assert( 0); + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_udiv */ + +static void +__lccrt_zn_sdiv( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb, + int *is_overflow) +{ + int i, j; + uint32_t zc[num_digits]; + + memset( zc, 0, num_digits*sizeof( zc[0])); + + if ( (num_digits == 1) ) + { + zc[0] = (int32_t)za[0] / (int32_t)zb[0]; + + } else if ( (num_digits == 2) ) + { + uint64_t bits = 32; + uint64_t va = ((uint64_t)za[1] << bits) | za[0]; + uint64_t vb = ((uint64_t)zb[1] << bits) | zb[0]; + uint64_t vc = (int64_t)va / (int64_t)vb; + + zc[0] = (uint32_t)vc; + zc[1] = vc >> bits; + } else + { + assert( 0); + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_sdiv */ + +static void +__lccrt_zn_umod( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb, + int *is_overflow) +{ + int i, j; + uint32_t zc[num_digits]; + + memset( zc, 0, num_digits*sizeof( zc[0])); + + if ( (num_digits == 1) ) + { + zc[0] = za[0] / zb[0]; + + } else if ( (num_digits == 2) ) + { + uint64_t bits = 32; + uint64_t va = ((uint64_t)za[1] << bits) | za[0]; + uint64_t vb = ((uint64_t)zb[1] << bits) | zb[0]; + uint64_t vc = va % vb; + + zc[0] = (uint32_t)vc; + zc[1] = vc >> bits; + } else + { + assert( 0); + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_umod */ + +static void +__lccrt_zn_smod( uint32_t num_digits, uint32_t *zr, uint32_t * __restrict za, uint32_t * __restrict zb, + int *is_overflow) +{ + int i, j; + uint32_t zc[num_digits]; + + memset( zc, 0, num_digits*sizeof( zc[0])); + + if ( (num_digits == 1) ) + { + zc[0] = (int32_t)za[0] / (int32_t)zb[0]; + + } else if ( (num_digits == 2) ) + { + uint64_t bits = 32; + uint64_t va = ((uint64_t)za[1] << bits) | za[0]; + uint64_t vb = ((uint64_t)zb[1] << bits) | zb[0]; + uint64_t vc = (int64_t)va % (int64_t)vb; + + zc[0] = (uint32_t)vc; + zc[1] = vc >> bits; + } else + { + assert( 0); + } + + memcpy( zr, zc, num_digits*sizeof( zc[0])); + + return; +} /* __lccrt_zn_smod */ + +static void +__lccrt_arith1_v( void (*func)( uint32_t, uint32_t, uint8_t *, uint8_t *), + uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + int i; + uint32_t reb_align = __LCCRT_ALIGN_BITS_N( reb); + uint32_t aeb_align = __LCCRT_ALIGN_BITS_N( aeb); + uint32_t rbytes_align = reb_align / 8; + uint32_t abytes_align = aeb_align / 8; + + assert( (rn == an)); + assert( rn*reb_align == rb); + assert( an*aeb_align == ab); + memset( r, 0, rn * rbytes_align); + for ( i = 0; i < rn; ++i ) + { + (*func)( reb, aeb, r + i*rbytes_align, a + i*abytes_align); + } + + return; +} /* __lccrt_arith1_v */ + +static void +__lccrt_arith2_v( void (*func)( uint32_t, uint32_t, uint32_t, uint8_t *, uint8_t *, uint8_t *), + uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + int i; + uint32_t reb_align = __LCCRT_ALIGN_BITS_N( reb); + uint32_t aeb_align = __LCCRT_ALIGN_BITS_N( aeb); + uint32_t beb_align = __LCCRT_ALIGN_BITS_N( beb); + uint32_t rbytes_align = reb_align / 8; + + assert( (rn == an) && (rn == bn) && (reb == aeb) && (reb == beb)); + assert( (rb == ab) && (rb == bb)); + assert( rn*reb_align == rb); + memset( r, 0, rn * rbytes_align); + for ( i = 0; i < rn; ++i ) + { + (*func)( reb, aeb, beb, r + i*rbytes_align, a + i*rbytes_align, b + i*rbytes_align); + } + + return; +} /* __lccrt_arith2_v */ + +static void +__lccrt_arith3_v( void (*func)( uint32_t, uint32_t, uint32_t, uint32_t, uint8_t *, uint8_t *, uint8_t *, uint8_t *), + uint32_t rb, uint32_t ab, uint32_t bb, uint32_t cb, + uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t cn, + uint32_t reb, uint32_t aeb, uint32_t beb, uint32_t ceb) +{ + int i; + uint32_t reb_align = __LCCRT_ALIGN_BITS_N( reb); + uint32_t rbytes_align = reb_align / 8; + + assert( (rb == ab) && (rb == bb) && (rb == cb)); + assert( (rn == an) && (rn == bn) && (rn == cn)); + assert( (reb == aeb) && (reb == beb) && (reb == ceb)); + assert( rn*reb_align == rb); + memset( r, 0, rn * rbytes_align); + for ( i = 0; i < rn; ++i ) + { + uint8_t *ri = r + i*rbytes_align; + uint8_t *ai = a + i*rbytes_align; + uint8_t *bi = b + i*rbytes_align; + uint8_t *ci = c + i*rbytes_align; + + (*func)( reb, aeb, beb, ceb, ri, ai, bi, ci); + } + + return; +} /* __lccrt_arith3_v */ + +static void +__lccrt_farith1_v( float (*f32)( float), double (*f64)( double), long double (*f80)( long double), + uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + int i; + int byte_elen = reb / 8; + + assert( (reb % 8 == 0)); + assert( (rn == an) && (reb == aeb) && (rn*reb == rb)); + for ( i = 0; i < rn; ++i ) + { + uint8_t *q0 = r + i*byte_elen; + uint8_t *p0 = a + i*byte_elen; + + if ( (reb == 32) ) + { + float z, x; + + memcpy( &x, p0, sizeof( x)); + z = (*f32)( x); + memcpy( q0, &z, sizeof( z)); + + } else if ( (reb == 64) ) + { + double z, x; + + memcpy( &x, p0, sizeof( x)); + z = (*f64)( x); + memcpy( q0, &z, sizeof( z)); + + } else if ( (reb == 80) ) + { + long double z, x; + + memcpy( &x, p0, sizeof( x)); + z = (*f80)( x); + memcpy( q0, &z, sizeof( z)); + } else + { + assert( 0); + } + } + + return; +} /* __lccrt_farith1_v */ + +static void +__lccrt_farith2_v( float (*f32)( float, float), double (*f64)( double, double), + long double (*f80)( long double, long double), + uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + int i; + int byte_elen = reb / 8; + + assert( (reb % 8 == 0)); + assert( (rn == an) && (rn == bn) && (reb == aeb) && (reb == beb) && (rn*reb == rb)); + for ( i = 0; i < rn; ++i ) + { + uint8_t *q0 = r + i*byte_elen; + uint8_t *p0 = a + i*byte_elen; + uint8_t *p1 = b + i*byte_elen; + + if ( (reb == 32) ) + { + float z, x, y; + + memcpy( &x, p0, sizeof( x)); + memcpy( &y, p1, sizeof( y)); + z = (*f32)( x, y); + memcpy( q0, &z, sizeof( z)); + + } else if ( (reb == 64) ) + { + double z, x, y; + + memcpy( &x, p0, sizeof( x)); + memcpy( &y, p1, sizeof( y)); + z = (*f64)( x, y); + memcpy( q0, &z, sizeof( z)); + + } else if ( (reb == 80) ) + { + long double z, x, y; + + memcpy( &x, p0, sizeof( x)); + memcpy( &y, p1, sizeof( y)); + z = (*f80)( x, y); + memcpy( q0, &z, sizeof( z)); + } else + { + assert( 0); + } + } + + return; +} /* __lccrt_farith2_v */ + +void +__lccrt_bitcast_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + int rlen = rb / 8; + int alen = ab / 8; + int rlen1 = (rb + 7) / 8; + int len = __LCCRT_MIN( alen, rlen1); + + memcpy( r, a, len); + memset( r + len, 0, rlen1 - len); + + if ( (8*alen < ab) + && (8*alen < rb) ) + { + int bits = __LCCRT_MIN( ab, rb); + + r[alen] = __LCCRT_ZEXT( a[alen], bits - 8*alen); + } + + if ( (rlen < rlen1) ) + { + r[rlen] = __LCCRT_ZEXT( r[rlen], rb - 8*rlen); + } + + return; +} /* __lccrt_bitcast_n */ + +void +__lccrt_select( uint32_t rb, uint32_t ab, uint32_t bb, uint32_t cb, + uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c) +{ + assert( ab == 8); + assert( rb == bb); + assert( rb == cb); + if ( a[0] ) + { + __lccrt_bitcast_n( rb, bb, r, b); + } else + { + __lccrt_bitcast_n( rb, cb, r, c); + } + + return; +} /* __lccrt_select */ + +void +__lccrt_select_v( uint32_t rb, uint32_t ab, uint32_t bb, uint32_t cb, + uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t cn) +{ + if ( (rn == an) + && (rn == bn) + && (rn == cn) + && (ab > 0) + && (rb == bb) + && (rb == cb) + && (rn > 0) + && (rb > 0) ) + { + int k; + uint32_t re = rb / rn; + uint32_t ae = ab / an; + uint32_t be = bb / bn; + uint32_t ce = bb / bn; + + if ( (ae == 8) + && (re > 0) + && (re == be) + && (re == ce) + && (rb % rn == 0) + && (ab % an == 0) + && (re % 8 == 0) ) + { + for ( k = 0; k < rn; ++k ) + { + __lccrt_select( re, ae, be, ce, r + k*(re/8), a + k*(ae/8), b + k*(be/8), c + k*(ce/8)); + } + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + return; +} /* __lccrt_select_v */ + +void +__lccrt_zext_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + assert( rb >= ab); + __lccrt_bitcast_n( rb, ab, r, a); + + return; +} /* __lccrt_zext_n */ + +void +__lccrt_trunc_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + assert( rb <= ab); + __lccrt_bitcast_n( rb, ab, r, a); + + return; +} /* __lccrt_trunc_n */ + +void +__lccrt_sext_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + int rlen = rb / 8; + int alen = ab / 8; + int rlen1 = (rb + 7) / 8; + int len = __LCCRT_MIN( alen, rlen); + + assert( rb >= ab); + if ( (ab == 0) ) + { + memset( r, 0, rlen1); + } else + { + int8_t va; + + memcpy( r, a, len); + + if ( (8*alen < ab) ) + { + len = alen + 1; + va = __LCCRT_SEXT( a[len - 1], ab - 8*alen); + r[alen] = va; + } else + { + len = alen; + va = a[len - 1]; + } + + va = va >> 7; + memset( r + len, va, rlen1 - len); + if ( (rlen < rlen1) ) + { + r[rlen] = __LCCRT_ZEXT( r[rlen], rb - 8*rlen); + } + } + + return; +} /* __lccrt_sext_n */ + +void +__lccrt_trunc_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, uint32_t rn, uint32_t an, + uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_trunc_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_trunc_v */ + +void +__lccrt_zext_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, uint32_t rn, uint32_t an, + uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_zext_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_zext_v */ + +void +__lccrt_sext_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, uint32_t rn, uint32_t an, + uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_sext_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_sext_v */ + +static int +__lccrt_cmp_lexic( int bits, uint8_t *a, uint8_t *b) +{ + int i; + int u = 0; + int n = bits / 8; + int n1 = (bits + 7) / 8; + + if ( (n < n1) ) + { + uint8_t ah = __LCCRT_ZEXT( a[n], bits - 8*n); + uint8_t bh = __LCCRT_ZEXT( b[n], bits - 8*n); + + u = (ah < bh) ? (-1) : ((ah == bh) ? 0 : 1); + } + + for ( i = n - 1; (i >= 0) && (u == 0); --i ) + { + if ( (a[i] != b[i]) ) + { + u = (a[i] < b[i]) ? (-1) : 1; + } + } + + return (u); +} /* __lccrt_cmp_lexic */ + +static int +__lccrt_cmp_lexic_sign( int bits, uint8_t *a, uint8_t *b) +{ + int u = 0; + int n = bits / 8; + int n1 = (bits + 7) / 8; + + if ( (n1 > 0) ) + { + int hl = bits % 8; + int8_t hs = (8 - hl) % 8; + int ha = ((int8_t)(((int8_t)a[n1-1]) << hs)) >> hs; + int hb = ((int8_t)(((int8_t)b[n1-1]) << hs)) >> hs; + + if ( (ha < hb) ) + { + u = -1; + + } else if ( (ha > hb) ) + { + u = 1; + + } else if ( (bits > 8) ) + { + u = __lccrt_cmp_lexic( 8*(n1 - 1), a, b); + } + } + + return (u); +} /* __lccrt_cmp_lexic_sign */ + +static int +__lccrt_fcmp( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t type) +{ + int v = 0; + + if ( (rb == 8) + && (ab == bb) ) + { + int u = 0; + + if ( (ab == 32) ) + { + float fa, fb; + + memcpy( &fa, a, sizeof( fa)); + memcpy( &fb, b, sizeof( fb)); + u = (fa <= fb) || (fa > fb); + + switch ( type ) + { + case A_LCCRT_CMP_FU: v = !u; break; + case A_LCCRT_CMP_FO: v = u; break; + case A_LCCRT_CMP_EQ_FU: v = (fa == fb) || !u; break; + case A_LCCRT_CMP_EQ_FO: v = (fa == fb) && u; break; + case A_LCCRT_CMP_NE_FU: v = (fa != fb) || !u; break; + case A_LCCRT_CMP_NE_FO: v = (fa != fb) && u; break; + case A_LCCRT_CMP_LT_FU: v = (fa < fb) || !u; break; + case A_LCCRT_CMP_LT_FO: v = (fa < fb) && u; break; + case A_LCCRT_CMP_LE_FU: v = (fa <= fb) || !u; break; + case A_LCCRT_CMP_LE_FO: v = (fa <= fb) && u; break; + case A_LCCRT_CMP_GT_FU: v = (fa > fb) || !u; break; + case A_LCCRT_CMP_GT_FO: v = (fa > fb) && u; break; + case A_LCCRT_CMP_GE_FU: v = (fa >= fb) || !u; break; + case A_LCCRT_CMP_GE_FO: v = (fa >= fb) && u; break; + default: assert( 0); break; + } + } else if ( (ab == 64) ) + { + double da, db; + + memcpy( &da, a, sizeof( da)); + memcpy( &db, b, sizeof( db)); + u = (da <= db) || (da > db); + + switch ( type ) + { + case A_LCCRT_CMP_FU: v = !u; break; + case A_LCCRT_CMP_FO: v = u; break; + case A_LCCRT_CMP_EQ_FU: v = (da == db) || !u; break; + case A_LCCRT_CMP_EQ_FO: v = (da == db) && u; break; + case A_LCCRT_CMP_NE_FU: v = (da != db) || !u; break; + case A_LCCRT_CMP_NE_FO: v = (da != db) && u; break; + case A_LCCRT_CMP_LT_FU: v = (da < db) || !u; break; + case A_LCCRT_CMP_LT_FO: v = (da < db) && u; break; + case A_LCCRT_CMP_LE_FU: v = (da <= db) || !u; break; + case A_LCCRT_CMP_LE_FO: v = (da <= db) && u; break; + case A_LCCRT_CMP_GT_FU: v = (da > db) || !u; break; + case A_LCCRT_CMP_GT_FO: v = (da > db) && u; break; + case A_LCCRT_CMP_GE_FU: v = (da >= db) || !u; break; + case A_LCCRT_CMP_GE_FO: v = (da >= db) && u; break; + default: assert( 0); break; + } + } else if ( (ab == 80) ) + { + long double la, lb; + + memcpy( &la, a, sizeof( la)); + memcpy( &lb, b, sizeof( lb)); + u = (la <= lb) || (la > lb); + + switch ( type ) + { + case A_LCCRT_CMP_FU: v = !u; break; + case A_LCCRT_CMP_FO: v = u; break; + case A_LCCRT_CMP_EQ_FU: v = (la == lb) || !u; break; + case A_LCCRT_CMP_EQ_FO: v = (la == lb) && u; break; + case A_LCCRT_CMP_NE_FU: v = (la != lb) || !u; break; + case A_LCCRT_CMP_NE_FO: v = (la != lb) && u; break; + case A_LCCRT_CMP_LT_FU: v = (la < lb) || !u; break; + case A_LCCRT_CMP_LT_FO: v = (la < lb) && u; break; + case A_LCCRT_CMP_LE_FU: v = (la <= lb) || !u; break; + case A_LCCRT_CMP_LE_FO: v = (la <= lb) && u; break; + case A_LCCRT_CMP_GT_FU: v = (la > lb) || !u; break; + case A_LCCRT_CMP_GT_FO: v = (la > lb) && u; break; + case A_LCCRT_CMP_GE_FU: v = (la >= lb) || !u; break; + case A_LCCRT_CMP_GE_FO: v = (la >= lb) && u; break; + default: assert( 0); break; + } + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + if ( r ) + { + r[0] = v; + } + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + return (v); +} /* __lccrt_fcmp */ + +static void +__lccrt_cmp_n( uint32_t type, uint32_t rb, uint32_t ab, uint32_t bb, + uint8_t *r, uint8_t *a, uint8_t *b) +{ + int i; + int alen = ab / 8; + int alen1 = (ab + 7) / 8; + + if ( (0 < rb) + && (rb <= 8) + && (ab == bb) + && (ab > 0) ) + { + int v = 0; + + switch ( type ) + { + case A_LCCRT_CMP_EQ: v = (__lccrt_cmp_lexic( ab, a, b) == 0); break; + case A_LCCRT_CMP_NE: v = (__lccrt_cmp_lexic( ab, a, b) != 0); break; + case A_LCCRT_CMP_LT_I: v = (__lccrt_cmp_lexic_sign( ab, a, b) == -1); break; + case A_LCCRT_CMP_LT_U: v = (__lccrt_cmp_lexic( ab, a, b) == -1); break; + case A_LCCRT_CMP_LE_I: v = (__lccrt_cmp_lexic_sign( ab, a, b) <= 0); break; + case A_LCCRT_CMP_LE_U: v = (__lccrt_cmp_lexic( ab, a, b) <= 0); break; + case A_LCCRT_CMP_GT_I: v = (__lccrt_cmp_lexic_sign( ab, a, b) == 1); break; + case A_LCCRT_CMP_GT_U: v = (__lccrt_cmp_lexic( ab, a, b) == 1); break; + case A_LCCRT_CMP_GE_I: v = (__lccrt_cmp_lexic_sign( ab, a, b) >= 0); break; + case A_LCCRT_CMP_GE_U: v = (__lccrt_cmp_lexic( ab, a, b) >= 0); break; + case A_LCCRT_CMP_FU: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_FO: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_EQ_FU: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_EQ_FO: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_NE_FU: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_NE_FO: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_LT_FU: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_LT_FO: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_LE_FU: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_LE_FO: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_GT_FU: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_GT_FO: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_GE_FU: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + case A_LCCRT_CMP_GE_FO: v = (__lccrt_fcmp( rb, ab, bb, 0, a, b, type)); break; + default: assert( 0); break; + } + + r[0] = v; + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + return; +} /* __lccrt_cmp_n */ + +void +__lccrt_cmp_n_eq_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_cmp_n( A_LCCRT_CMP_EQ, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_cmp_n_eq_i */ + +void +__lccrt_cmp_n_ne_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_cmp_n( A_LCCRT_CMP_NE, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_cmp_n_ne_i */ + +void +__lccrt_cmp_n_lt_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_cmp_n( A_LCCRT_CMP_LT_I, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_cmp_n_lt_i */ + +void +__lccrt_cmp_n_lt_u( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_cmp_n( A_LCCRT_CMP_LT_U, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_cmp_n_lt_u */ + +void +__lccrt_cmp_n_le_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_cmp_n( A_LCCRT_CMP_LE_I, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_cmp_n_le_i */ + +void +__lccrt_cmp_n_le_u( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_cmp_n( A_LCCRT_CMP_LE_U, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_cmp_n_le_u */ + +void +__lccrt_cmp_n_gt_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_cmp_n( A_LCCRT_CMP_GT_I, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_cmp_n_gt_i */ + +void +__lccrt_cmp_n_gt_u( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_cmp_n( A_LCCRT_CMP_GT_U, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_cmp_n_gt_u */ + +void +__lccrt_cmp_n_ge_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_cmp_n( A_LCCRT_CMP_GE_I, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_cmp_n_ge_i */ + +void +__lccrt_cmp_n_ge_u( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_cmp_n( A_LCCRT_CMP_GE_U, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_cmp_n_ge_u */ + +void +__lccrt_cmp_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_FO); + + return; +} /* __lccrt_cmp_fo */ + +void +__lccrt_cmp_eq_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_EQ_FO); + + return; +} /* __lccrt_cmp_eq_fo */ + +void +__lccrt_cmp_ne_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_NE_FO); + + return; +} /* __lccrt_cmp_ne_fo */ + +void +__lccrt_cmp_lt_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_LT_FO); + + return; +} /* __lccrt_cmp_lt_fo */ + +void +__lccrt_cmp_le_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_LE_FO); + + return; +} /* __lccrt_cmp_le_fo */ + +void +__lccrt_cmp_gt_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_GT_FO); + + return; +} /* __lccrt_cmp_gt_fo */ + +void +__lccrt_cmp_ge_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_GE_FO); + + return; +} /* __lccrt_cmp_ge_fo */ + +void +__lccrt_cmp_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_FU); + + return; +} /* __lccrt_cmp_fu */ + +void +__lccrt_cmp_eq_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_EQ_FU); + + return; +} /* __lccrt_cmp_eq_fu */ + +void +__lccrt_cmp_ne_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_NE_FU); + + return; +} /* __lccrt_cmp_ne_fu */ + +void +__lccrt_cmp_lt_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_LT_FU); + + return; +} /* __lccrt_cmp_lt_fu */ + +void +__lccrt_cmp_le_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_LE_FU); + + return; +} /* __lccrt_cmp_le_fu */ + +void +__lccrt_cmp_gt_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_GT_FU); + + return; +} /* __lccrt_cmp_gt_fu */ + +void +__lccrt_cmp_ge_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_fcmp( rb, ab, bb, r, a, b, A_LCCRT_CMP_GE_FU); + + return; +} /* __lccrt_cmp_ge_fu */ + +static void +__lccrt_cmp_v( uint32_t type, uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + if ( (rn == an) + && (an == bn) + && (ab == bb) + && (rn > 0) + && (rb > 0) + && (ab > 0) + && (bb > 0) ) + { + int k; + uint32_t re = rb / rn; + uint32_t ae = ab / an; + uint32_t be = bb / bn; + + if ( (re == 8) + && (ae == be) + && (rb % rn == 0) + && (ab % an == 0) + && (ae % 8 == 0) + && (be % 8 == 0) ) + { + for ( k = 0; k < rn; ++k ) + { + __lccrt_cmp_n( type, re, ae, be, r + k*(re/8), a + k*(ae/8), b + k*(be/8)); + } + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + return; +} /* __lccrt_cmp_v */ + +void +__lccrt_cmp_v_eq_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_EQ, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_eq_i */ + +void +__lccrt_cmp_v_ne_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_NE, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_ne_i */ + +void +__lccrt_cmp_v_lt_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_LT_I, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_lt_i */ + +void +__lccrt_cmp_v_lt_u( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_LT_U, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_lt_u */ + +void +__lccrt_cmp_v_le_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_LE_I, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_le_i */ + +void +__lccrt_cmp_v_le_u( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_LE_U, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_le_u */ + +void +__lccrt_cmp_v_gt_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_GT_I, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_gt_i */ + +void +__lccrt_cmp_v_gt_u( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_GT_U, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_gt_u */ + +void +__lccrt_cmp_v_ge_i( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_GE_I, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_ge_i */ + +void +__lccrt_cmp_v_ge_u( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_GE_U, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_ge_u */ + +void +__lccrt_cmp_v_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_FO, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_fo */ + +void +__lccrt_cmp_v_eq_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_EQ_FO, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_eq_fo */ + +void +__lccrt_cmp_v_ne_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_NE_FO, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_ne_fo */ + +void +__lccrt_cmp_v_lt_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_LT_FO, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_lt_fo */ + +void +__lccrt_cmp_v_le_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_LE_FO, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_le_fo */ + +void +__lccrt_cmp_v_gt_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_GT_FO, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_gt_fo */ + +void +__lccrt_cmp_v_ge_fo( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_GE_FO, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_ge_fo */ + +void +__lccrt_cmp_v_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_FU, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_fu */ + +void +__lccrt_cmp_v_eq_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_EQ_FU, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_eq_fu */ + +void +__lccrt_cmp_v_ne_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_NE_FU, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_ne_fu */ + +void +__lccrt_cmp_v_lt_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_LT_FU, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_lt_fu */ + +void +__lccrt_cmp_v_le_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_LE_FU, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_le_fu */ + +void +__lccrt_cmp_v_gt_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_GT_FU, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_gt_fu */ + +void +__lccrt_cmp_v_ge_fu( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn) +{ + __lccrt_cmp_v( A_LCCRT_CMP_GE_FU, rb, ab, bb, r, a, b, rn, an, bn); + + return; +} /* __lccrt_cmp_v_ge_fu */ + +void +__lccrt_abs_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, ab); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + + __lccrt_zn_set_bits( num_digits, 1, za, ab, a); + + if ( (ab > 0) + && (rb == ab) ) + { + __lccrt_zn_abs( num_digits, zr, za, 0); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, ab); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, ab, r); + + return; +} /* __lccrt_abs_n */ + +void +__lccrt_shl_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + int rlen = rb / 8; + int rlen1 = (rb + 7) / 8; + uint64_t vb = 0; + + assert( rb == ab); + assert( rb == bb); + if ( (rb > 0) ) + { + int64_t k; + + if ( (rlen < rlen1) ) + { + vb = __LCCRT_ZEXT( b[rlen], rb - 8*rlen); + } + + for ( k = rlen - 1; k >= 0; k-- ) + { + vb = 256*vb + b[k]; + if ( (vb > rb) ) + { + break; + } + } + + if ( (vb >= rb) ) + { + memset( r, 0, rlen1); + } else + { + int vbr = vb % 8; + int vbd = vb / 8; + + memset( r, 0, vbd); + if ( (vbr == 0) ) + { + memcpy( r + vbd, a, rlen1 - vbd); + } else + { + int k; + uint8_t lo = 0; + + for ( k = vbd; k < rlen1; ++k ) + { + uint8_t va = a[k - vbd]; + + r[k] = (va << vbr) | lo; + lo = va >> (8 - vbr); + } + } + + if ( (rlen < rlen1) ) + { + r[rlen] = __LCCRT_ZEXT( r[rlen], rb - 8*rlen); + } + } + } + + return; +} /* __lccrt_shl_n */ + +void +__lccrt_shr_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + int rlen = rb / 8; + int rlen1 = (rb + 7) / 8; + uint64_t vb = 0; + + assert( rb == ab); + assert( rb == bb); + if ( (rb > 0) ) + { + int64_t k; + + if ( (rlen < rlen1) ) + { + vb = __LCCRT_ZEXT( b[rlen], rb - 8*rlen); + } + + for ( k = rlen - 1; k >= 0; k-- ) + { + vb = 256*vb + b[k]; + if ( (vb > rb) ) + { + break; + } + } + + if ( (vb >= rb) ) + { + memset( r, 0, rlen1); + } else + { + int vbr = vb % 8; + int vbd = vb / 8; + + memset( r + rlen1 - vbd, 0, vbd); + if ( (vbr == 0) ) + { + memcpy( r, a + vbd, rlen1 - vbd); + } else + { + int k; + uint8_t hi = 0; + + for ( k = rlen1 - vbd - 1; k >= 0; --k ) + { + uint8_t va = a[k + vbd]; + + va = ((k == rlen1 - vbd - 1) && (rlen < rlen1)) ? __LCCRT_ZEXT( va, rb - 8*rlen) : va; + r[k] = hi | (va >> vbr); + hi = va << (8 - vbr); + } + } + + if ( (rlen < rlen1) ) + { + r[rlen1 - vbd - 1] = __LCCRT_ZEXT( r[rlen1 - vbd - 1], rb - 8*rlen); + } + } + } + + return; +} /* __lccrt_shr_n */ + +void +__lccrt_sar_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, bb); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + uint32_t zb[num_digits]; + + __lccrt_zn_set_bits( num_digits, 1, za, ab, a); + __lccrt_zn_set_bits( num_digits, 0, zb, bb, b); + + if ( (ab > 0) + && (ab == bb) + && (rb == ab) ) + { + __lccrt_zn_sar( num_digits, zr, za, zb, 0); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_sar_n */ + +void +__lccrt_fshl_n( uint32_t rb, uint32_t ab, uint32_t bb, uint32_t cb, uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS4( rb, ab, bb, cb); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + uint32_t zb[num_digits]; + uint32_t zc[num_digits]; + uint32_t zd[num_digits]; + uint32_t ze[num_digits]; + uint32_t zf[num_digits]; + + __lccrt_zn_set_bits( num_digits, 0, za, ab, a); + __lccrt_zn_set_bits( num_digits, 0, zb, bb, b); + __lccrt_zn_set_bits( num_digits, 0, zc, cb, c); + + if ( (ab > 0) + && (ab == bb) + && (ab == cb) + && (rb == ab) ) + { + memset( zf, 0, 4*num_digits); + zc[0] = zc[0] % ab; + zf[0] = (ab - zc[0]) % ab; + if ( (zc[0] == 0) ) + { + memcpy( zr, za, 4*num_digits); + } else + { + __lccrt_zn_shl( num_digits, zd, za, zc); + __lccrt_zn_shr( num_digits, ze, zb, zf); + __lccrt_zn_ior( num_digits, zr, zd, ze); + } + } else + { + __LCCRT_PRINT_BITS4( rb, ab, bb, cb); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_fshl_n */ + +void +__lccrt_and_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + int rlen = rb / 8; + int rlen1 = (rb + 7) / 8; + + assert( rb == ab); + assert( rb == bb); + if ( (rb > 0) ) + { + int64_t k; + + for ( k = 0; k < rlen; k++ ) + { + r[k] = a[k] & b[k]; + } + + if ( (rlen < rlen1) ) + { + uint8_t v = a[rlen] & b[rlen]; + + r[rlen] = __LCCRT_ZEXT( v, rb - 8*rlen); + } + } + + return; +} /* __lccrt_and_n */ + +void +__lccrt_or_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + int rlen = rb / 8; + int rlen1 = (rb + 7) / 8; + + assert( rb == ab); + assert( rb == bb); + if ( (rb > 0) ) + { + int64_t k; + + for ( k = 0; k < rlen; k++ ) + { + r[k] = a[k] | b[k]; + } + + if ( (rlen < rlen1) ) + { + uint8_t v = a[rlen] | b[rlen]; + + r[rlen] = __LCCRT_ZEXT( v, rb - 8*rlen); + } + } + + return; +} /* __lccrt_or_n */ + +void +__lccrt_xor_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + int rlen = rb / 8; + int rlen1 = (rb + 7) / 8; + + assert( rb == ab); + assert( rb == bb); + if ( (rb > 0) ) + { + int64_t k; + + for ( k = 0; k < rlen; k++ ) + { + r[k] = a[k] ^ b[k]; + } + + if ( (rlen < rlen1) ) + { + uint8_t v = a[rlen] ^ b[rlen]; + + r[rlen] = __LCCRT_ZEXT( v, rb - 8*rlen); + } + } + + return; +} /* __lccrt_xor_n */ + +void +__lccrt_add_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, bb); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + uint32_t zb[num_digits]; + + __lccrt_zn_set_bits( num_digits, 0, za, ab, a); + __lccrt_zn_set_bits( num_digits, 0, zb, bb, b); + + if ( (ab > 0) + && (ab == bb) + && (rb == ab) ) + { + __lccrt_zn_add( num_digits, zr, za, zb, 0); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_add_n */ + +void +__lccrt_sub_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, bb); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + uint32_t zb[num_digits]; + + __lccrt_zn_set_bits( num_digits, 0, za, ab, a); + __lccrt_zn_set_bits( num_digits, 0, zb, bb, b); + + if ( (ab > 0) + && (ab == bb) + && (rb == ab) ) + { + __lccrt_zn_sub( num_digits, zr, za, zb, 0); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_sub_n */ + +void +__lccrt_mul_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, bb); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + uint32_t zb[num_digits]; + + __lccrt_zn_set_bits( num_digits, 0, za, ab, a); + __lccrt_zn_set_bits( num_digits, 0, zb, bb, b); + + if ( (ab > 0) + && (ab == bb) + && (rb == ab) ) + { + __lccrt_zn_mul( num_digits, zr, za, zb, 0); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_mul_n */ + +void +__lccrt_udiv_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, bb); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + uint32_t zb[num_digits]; + + __lccrt_zn_set_bits( num_digits, 0, za, ab, a); + __lccrt_zn_set_bits( num_digits, 0, zb, bb, b); + + if ( (ab > 0) + && (ab == bb) + && (rb == ab) ) + { + __lccrt_zn_udiv( num_digits, zr, za, zb, 0); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_udiv_n */ + +void +__lccrt_sdiv_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, bb); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + uint32_t zb[num_digits]; + + __lccrt_zn_set_bits( num_digits, 1, za, ab, a); + __lccrt_zn_set_bits( num_digits, 1, zb, bb, b); + + if ( (ab > 0) + && (ab == bb) + && (rb == ab) ) + { + __lccrt_zn_sdiv( num_digits, zr, za, zb, 0); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_sdiv_n */ + +void +__lccrt_umod_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, bb); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + uint32_t zb[num_digits]; + + __lccrt_zn_set_bits( num_digits, 0, za, ab, a); + __lccrt_zn_set_bits( num_digits, 0, zb, bb, b); + + if ( (ab > 0) + && (ab == bb) + && (rb == ab) ) + { + __lccrt_zn_umod( num_digits, zr, za, zb, 0); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_umod_n */ + +void +__lccrt_smod_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, bb); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + uint32_t zb[num_digits]; + + __lccrt_zn_set_bits( num_digits, 1, za, ab, a); + __lccrt_zn_set_bits( num_digits, 1, zb, bb, b); + + if ( (ab > 0) + && (ab == bb) + && (rb == ab) ) + { + __lccrt_zn_smod( num_digits, zr, za, zb, 0); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_smod_n */ + +static void +__lccrt_ffunc_n( __lccrt_ffunc32_t f32, __lccrt_ffunc64_t f64, __lccrt_ffunc80_t f80, + uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + if ( (rb == ab) + && (ab == bb) + && (ab > 0) ) + { + if ( (rb == 32) ) + { + float v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = (*f32)( u0, u1); + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 64) ) + { + double v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = (*f64)( u0, u1); + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 80) ) + { + long double v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = (*f80)( u0, u1); + memcpy( r, &v, sizeof( v)); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + return; +} /* __lccrt_ffunc_n */ + +static void +__lccrt_ffunc3_n( __lccrt_ffunc32_3_t f32, __lccrt_ffunc64_3_t f64, __lccrt_ffunc80_3_t f80, + uint32_t rb, uint32_t ab, uint32_t bb, uint32_t cb, + uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c) +{ + if ( (rb == ab) + && (rb == bb) + && (rb == cb) + && (rb > 0) ) + { + if ( (rb == 32) ) + { + float v, u0, u1, u2; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + memcpy( &u2, c, sizeof( u2)); + v = (*f32)( u0, u1, u2); + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 64) ) + { + double v, u0, u1, u2; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + memcpy( &u2, c, sizeof( u2)); + v = (*f64)( u0, u1, u2); + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 80) ) + { + long double v, u0, u1, u2; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + memcpy( &u2, c, sizeof( u2)); + v = (*f80)( u0, u1, u2); + memcpy( r, &v, sizeof( v)); + } else + { + __LCCRT_PRINT_BITS4( rb, ab, bb, cb); + assert( 0); + } + } else + { + __LCCRT_PRINT_BITS4( rb, ab, bb, cb); + assert( 0); + } + + return; +} /* __lccrt_ffunc3_n */ + +static __lccrt_f32_t __lccrt_fadd32( __lccrt_f32_t x, __lccrt_f32_t y) { return (x + y); } +static __lccrt_f64_t __lccrt_fadd64( __lccrt_f64_t x, __lccrt_f64_t y) { return (x + y); } +static __lccrt_f80_t __lccrt_fadd80( __lccrt_f80_t x, __lccrt_f80_t y) { return (x + y); } + +void +__lccrt_fadd_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_ffunc_n( &__lccrt_fadd32, &__lccrt_fadd64, &__lccrt_fadd80, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_fadd_n */ + +static __lccrt_f32_t __lccrt_fsub32( __lccrt_f32_t x, __lccrt_f32_t y) { return (x - y); } +static __lccrt_f64_t __lccrt_fsub64( __lccrt_f64_t x, __lccrt_f64_t y) { return (x - y); } +static __lccrt_f80_t __lccrt_fsub80( __lccrt_f80_t x, __lccrt_f80_t y) { return (x - y); } + +void +__lccrt_fsub_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_ffunc_n( &__lccrt_fsub32, &__lccrt_fsub64, &__lccrt_fsub80, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_fsub_n */ + +static __lccrt_f32_t __lccrt_fmul32( __lccrt_f32_t x, __lccrt_f32_t y) { return (x * y); } +static __lccrt_f64_t __lccrt_fmul64( __lccrt_f64_t x, __lccrt_f64_t y) { return (x * y); } +static __lccrt_f80_t __lccrt_fmul80( __lccrt_f80_t x, __lccrt_f80_t y) { return (x * y); } + +void +__lccrt_fmul_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_ffunc_n( &__lccrt_fmul32, &__lccrt_fmul64, &__lccrt_fmul80, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_fmul_n */ + +static __lccrt_f32_t __lccrt_fmuladd32( __lccrt_f32_t x, __lccrt_f32_t y, __lccrt_f32_t z) { return (x*y + z); } +static __lccrt_f64_t __lccrt_fmuladd64( __lccrt_f64_t x, __lccrt_f64_t y, __lccrt_f64_t z) { return (x*y + z); } +static __lccrt_f80_t __lccrt_fmuladd80( __lccrt_f80_t x, __lccrt_f80_t y, __lccrt_f80_t z) { return (x*y + z); } + +void +__lccrt_fmuladd_n( uint32_t rb, uint32_t ab, uint32_t bb, uint32_t cb, uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c) +{ + __lccrt_ffunc3_n( &__lccrt_fmuladd32, &__lccrt_fmuladd64, &__lccrt_fmuladd80, rb, ab, bb, cb, r, a, b, c); + + return; +} /* __lccrt_fmuladd_n */ + +static __lccrt_f32_t __lccrt_fdiv32( __lccrt_f32_t x, __lccrt_f32_t y) { return (x / y); } +static __lccrt_f64_t __lccrt_fdiv64( __lccrt_f64_t x, __lccrt_f64_t y) { return (x / y); } +static __lccrt_f80_t __lccrt_fdiv80( __lccrt_f80_t x, __lccrt_f80_t y) { return (x / y); } + +void +__lccrt_fdiv_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + __lccrt_ffunc_n( &__lccrt_fdiv32, &__lccrt_fdiv64, &__lccrt_fdiv80, rb, ab, bb, r, a, b); + + return; +} /* __lccrt_fdiv_n */ + +void +__lccrt_fmod_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + if ( (rb == ab) + && (ab == bb) + && (ab > 0) ) + { + if ( (rb == 32) ) + { + float v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = fmodf( u0, u1); + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 64) ) + { + double v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = fmod( u0, u1); + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 80) ) + { + long double v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = fmodl( u0, u1); + memcpy( r, &v, sizeof( v)); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + return; +} /* __lccrt_fmod_n */ + +void +__lccrt_minnum_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + if ( (rb == ab) + && (ab == bb) + && (ab > 0) ) + { + if ( (rb == 32) ) + { + float v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = __builtin_fminf( u0, u1); + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 64) ) + { + double v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = __builtin_fmin( u0, u1); + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 80) ) + { + long double v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = __builtin_fminl( u0, u1); + memcpy( r, &v, sizeof( v)); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + return; +} /* __lccrt_minnum_n */ + +void +__lccrt_maxnum_n( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b) +{ + if ( (rb == ab) + && (ab == bb) + && (ab > 0) ) + { + if ( (rb == 32) ) + { + float v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = __builtin_fmaxf( u0, u1); + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 64) ) + { + double v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = __builtin_fmax( u0, u1); + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 80) ) + { + long double v, u0, u1; + + memcpy( &u0, a, sizeof( u0)); + memcpy( &u1, b, sizeof( u1)); + v = __builtin_fmaxl( u0, u1); + memcpy( r, &v, sizeof( v)); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + } else + { + __LCCRT_PRINT_BITS3( rb, ab, bb); + assert( 0); + } + + return; +} /* __lccrt_maxnum_n */ + +void +__lccrt_fneg_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + if ( (rb == ab) + && (ab > 0) ) + { + if ( (rb == 32) ) + { + float v, u0; + + memcpy( &u0, a, sizeof( u0)); + v = -u0; + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 64) ) + { + double v, u0; + + memcpy( &u0, a, sizeof( u0)); + v = -u0; + memcpy( r, &v, sizeof( v)); + + } else if ( (rb == 80) ) + { + long double v, u0; + + memcpy( &u0, a, sizeof( u0)); + v = -u0; + memcpy( r, &v, sizeof( v)); + } else + { + __LCCRT_PRINT_BITS2( rb, ab); + assert( 0); + } + } else + { + __LCCRT_PRINT_BITS2( rb, ab); + assert( 0); + } + + return; +} /* __lccrt_fneg_n */ + +void +__lccrt_fptofp_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + int is_conv = 0; + + if ( (ab == 32) ) + { + float u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + + } else if ( (ab == 64) ) + { + double u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + + } else if ( (ab == 80) ) + { + long double u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + } + + if ( !is_conv ) + { + __LCCRT_PRINT_BITS2( rb, ab); + assert( 0); + } + + return; +} /* __lccrt_fptofp_n */ + +void +__lccrt_fptosi_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + int is_conv = 0; + + if ( (ab == 32) ) + { + float u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 8) ) { is_conv = 1; __LCCRT_CONV( r, int8_t, u0); } + else if ( (rb == 16) ) { is_conv = 1; __LCCRT_CONV( r, int16_t, u0); } + else if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, int32_t, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, int64_t, u0); } + + } else if ( (ab == 64) ) + { + double u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 8) ) { is_conv = 1; __LCCRT_CONV( r, int8_t, u0); } + else if ( (rb == 16) ) { is_conv = 1; __LCCRT_CONV( r, int16_t, u0); } + else if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, int32_t, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, int64_t, u0); } + + } else if ( (ab == 80) ) + { + long double u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 8) ) { is_conv = 1; __LCCRT_CONV( r, int8_t, u0); } + else if ( (rb == 16) ) { is_conv = 1; __LCCRT_CONV( r, int16_t, u0); } + else if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, int32_t, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, int64_t, u0); } + } + + if ( !is_conv ) + { + __LCCRT_PRINT_BITS2( rb, ab); + assert( 0); + } + + return; +} /* __lccrt_fptosi_n */ + +void +__lccrt_fptoui_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + int is_conv = 0; + + if ( (ab == 32) ) + { + float u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 8) ) { is_conv = 1; __LCCRT_CONV( r, uint8_t, u0); } + else if ( (rb == 16) ) { is_conv = 1; __LCCRT_CONV( r, uint16_t, u0); } + else if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, uint32_t, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, uint64_t, u0); } + + } else if ( (ab == 64) ) + { + double u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 8) ) { is_conv = 1; __LCCRT_CONV( r, uint8_t, u0); } + else if ( (rb == 16) ) { is_conv = 1; __LCCRT_CONV( r, uint16_t, u0); } + else if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, uint32_t, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, uint64_t, u0); } + + } else if ( (ab == 80) ) + { + long double u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 8) ) { is_conv = 1; __LCCRT_CONV( r, uint8_t, u0); } + else if ( (rb == 16) ) { is_conv = 1; __LCCRT_CONV( r, uint16_t, u0); } + else if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, uint32_t, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, uint64_t, u0); } + } + + if ( !is_conv ) + { + __LCCRT_PRINT_BITS2( rb, ab); + assert( 0); + } + + return; +} /* __lccrt_fptoui_n */ + +void +__lccrt_sitofp_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + int is_conv = 0; + + if ( (ab == 8) ) + { + int8_t u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + + } else if ( (ab == 16) ) + { + int16_t u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + + } else if ( (ab == 32) ) + { + int32_t u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + + } else if ( (ab == 64) ) + { + int64_t u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + } + + if ( !is_conv ) + { + __LCCRT_PRINT_BITS2( rb, ab); + assert( 0); + } + + return; +} /* __lccrt_sitofp_n */ + +void +__lccrt_uitofp_n( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a) +{ + int is_conv = 0; + + if ( (ab == 8) ) + { + uint8_t u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + + } else if ( (ab == 16) ) + { + uint16_t u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + + } else if ( (ab == 32) ) + { + uint32_t u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + + } else if ( (ab == 64) ) + { + uint64_t u0; + + memcpy( &u0, a, sizeof( u0)); + if ( (rb == 32) ) { is_conv = 1; __LCCRT_CONV( r, float, u0); } + else if ( (rb == 64) ) { is_conv = 1; __LCCRT_CONV( r, double, u0); } + else if ( (rb == 80) ) { is_conv = 1; __LCCRT_CONV( r, long double, u0); } + } + + if ( !is_conv ) + { + __LCCRT_PRINT_BITS2( rb, ab); + assert( 0); + } + + return; +} /* __lccrt_uitofp_n */ + +void +__lccrt_func2_stdint_n( __LCCRT_N_ARG2( rb, ab, bb, r, a, b), + uint8_t (*f8)( uint8_t, uint8_t), + uint16_t (*f16)( uint16_t, uint16_t), + uint32_t (*f32)( uint32_t, uint32_t), + uint64_t (*f64)( uint64_t, uint64_t)) +{ + assert( (rb == ab) && (rb == bb)); + if ( (rb == 8) ) + { + uint8_t *x = (uint8_t *)a; + uint8_t *y = (uint8_t *)b; + uint8_t *z = (uint8_t *)r; + + z[0] = f8( x[0], y[0]); + + } else if ( (rb == 16) ) + { + uint16_t *x = (uint16_t *)a; + uint16_t *y = (uint16_t *)b; + uint16_t *z = (uint16_t *)r; + + z[0] = f16( x[0], y[0]); + + } else if ( (ab == 32) ) + { + uint32_t *x = (uint32_t *)a; + uint32_t *y = (uint32_t *)b; + uint32_t *z = (uint32_t *)r; + + z[0] = f32( x[0], y[0]); + + } else if ( (ab == 64) ) + { + uint64_t *x = (uint64_t *)a; + uint64_t *y = (uint64_t *)b; + uint64_t *z = (uint64_t *)r; + + z[0] = f64( x[0], y[0]); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, rb); + assert( 0); + } + + return; +} /* __lccrt_func2_stdint_n */ + +void +__lccrt_uadd_sat_n( __LCCRT_N_ARG2( rb, ab, bb, r, a, b)) +{ + __lccrt_func2_stdint_n( rb, ab, bb, r, a, b, + &__lccrt_uadd_sat_8, &__lccrt_uadd_sat_16, + &__lccrt_uadd_sat_32, &__lccrt_uadd_sat_64); + + return; +} /* __lccrt_uadd_sat_n */ + +void +__lccrt_sadd_sat_n( __LCCRT_N_ARG2( rb, ab, bb, r, a, b)) +{ + __lccrt_func2_stdint_n( rb, ab, bb, r, a, b, + &__lccrt_sadd_sat_8, &__lccrt_sadd_sat_16, + &__lccrt_sadd_sat_32, &__lccrt_sadd_sat_64); + + return; +} /* __lccrt_sadd_sat_n */ + +void +__lccrt_usub_sat_n( __LCCRT_N_ARG2( rb, ab, bb, r, a, b)) +{ + __lccrt_func2_stdint_n( rb, ab, bb, r, a, b, + &__lccrt_usub_sat_8, &__lccrt_usub_sat_16, + &__lccrt_usub_sat_32, &__lccrt_usub_sat_64); + + return; +} /* __lccrt_usub_sat_n */ + +void +__lccrt_ssub_sat_n( __LCCRT_N_ARG2( rb, ab, bb, r, a, b)) +{ + __lccrt_func2_stdint_n( rb, ab, bb, r, a, b, + &__lccrt_ssub_sat_8, &__lccrt_ssub_sat_16, + &__lccrt_ssub_sat_32, &__lccrt_ssub_sat_64); + + return; +} /* __lccrt_ssub_sat_n */ + +void +__lccrt_bswap_n( __LCCRT_N_ARG1( rb, ab, r, a)) +{ + int i; + int rlen = rb / 8; + + assert( (rb > 0) && (rb == ab) && (rb % 16 == 0)); + for ( i = 0; i < rlen; ++i ) + { + r[rlen - 1 - i] = a[i]; + } + + return; +} /* __lccrt_bswap_n */ + +void +__lccrt_bitreverse_n( __LCCRT_N_ARG1( rb, ab, r, a)) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, ab); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + uint32_t zb[num_digits]; + + __lccrt_zn_set_bits( num_digits, 0, za, ab, a); + + if ( (ab > 0) + && (rb == ab) ) + { + int i; + + for ( i = 0; i < num_digits; ++i ) + { + za[i] = __builtin_e2k_bitrevs( za[i]); + zb[i] = 0; + } + + for ( i = 0; i < num_digits/2; ++i ) + { + uint32_t v = za[i]; + int i0 = i; + int i1 = num_digits/2 - i; + + za[i0] = za[i1]; + za[i1] = v; + } + + zb[0] = 32*num_digits - ab; + __lccrt_zn_shr( num_digits, zr, za, zb); + } else + { + __LCCRT_PRINT_BITS3( rb, ab, ab); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_bitreverse_n */ + +void +__lccrt_ctpop_n( __LCCRT_N_ARG1( rb, ab, r, a)) +{ + uint32_t num_digits = __LCCRT_NUM_DIGITS( rb, ab, ab); + uint32_t zr[num_digits]; + uint32_t za[num_digits]; + + __lccrt_zn_set_bits( num_digits, 0, za, ab, a); + + if ( (ab > 0) + && (rb == ab) ) + { + int i; + int v = 0; + + for ( i = 0; i < num_digits; ++i ) + { + zr[i] = 0; + v += __builtin_popcount( za[i]); + } + + zr[0] = v; + } else + { + __LCCRT_PRINT_BITS3( rb, ab, ab); + assert( 0); + } + + __lccrt_zn_get_bits( num_digits, zr, rb, r); + + return; +} /* __lccrt_ctpop_n */ + +void +__lccrt_abs_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, uint32_t rn, uint32_t an, + uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_abs_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_abs_v */ + +void +__lccrt_shl_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_shl_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_shl_v */ + +void +__lccrt_shr_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_shr_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_shr_v */ + +void +__lccrt_sar_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_sar_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_sar_v */ + +void +__lccrt_fshl_v( uint32_t rb, uint32_t ab, uint32_t bb, uint32_t cb, + uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t cn, + uint32_t reb, uint32_t aeb, uint32_t beb, uint32_t ceb) +{ + __lccrt_arith3_v( &__lccrt_fshl_n, rb, ab, bb, cb, r, a, b, c, rn, an, bn, cn, reb, aeb, beb, ceb); + + return; +} /* __lccrt_fshl_v */ + +void +__lccrt_and_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_and_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_and_v */ + +void +__lccrt_or_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_or_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_or_v */ + +void +__lccrt_xor_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_xor_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_xor_v */ + +void +__lccrt_add_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_add_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_add_v */ + +void +__lccrt_sub_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_sub_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_sub_v */ + +void +__lccrt_mul_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_mul_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_mul_v */ + +void +__lccrt_udiv_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_udiv_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_udiv_v */ + +void +__lccrt_sdiv_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_sdiv_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_sdiv_v */ + +void +__lccrt_umod_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_umod_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_umod_v */ + +void +__lccrt_smod_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_smod_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_smod_v */ + +void +__lccrt_fadd_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_fadd_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_fadd_v */ + +void +__lccrt_fsub_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_fsub_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_fsub_v */ + +void +__lccrt_fmul_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_fmul_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_fmul_v */ + +void +__lccrt_fmuladd_v( uint32_t rb, uint32_t ab, uint32_t bb, uint32_t cb, + uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t cn, + uint32_t reb, uint32_t aeb, uint32_t beb, uint32_t ceb) +{ + __lccrt_arith3_v( &__lccrt_fmuladd_n, rb, ab, bb, cb, r, a, b, c, rn, an, bn, cn, reb, aeb, beb, ceb); + + return; +} /* __lccrt_fmuladd_v */ + +void +__lccrt_fdiv_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_fdiv_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_fdiv_v */ + +void +__lccrt_fmod_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_fmod_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_fmod_v */ + +void +__lccrt_minnum_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_minnum_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_minnum_v */ + +void +__lccrt_maxnum_v( uint32_t rb, uint32_t ab, uint32_t bb, uint8_t *r, uint8_t *a, uint8_t *b, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t reb, uint32_t aeb, uint32_t beb) +{ + __lccrt_arith2_v( &__lccrt_maxnum_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_maxnum_v */ + +void +__lccrt_fneg_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_fneg_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_fneg_v */ + +void +__lccrt_ptoi_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_bitcast_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_ptoi_v */ + +void +__lccrt_itop_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_bitcast_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_itop_v */ + +void +__lccrt_fptofp_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_fptofp_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_fptofp_v */ + +void +__lccrt_fptosi_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_fptosi_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_fptosi_v */ + +void +__lccrt_fptoui_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_fptoui_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_fptoui_v */ + +void +__lccrt_sitofp_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_sitofp_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_sitofp_v */ + +void +__lccrt_uitofp_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + __lccrt_arith1_v( &__lccrt_uitofp_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_uitofp_v */ + +void +__lccrt_uadd_sat_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)) +{ + __lccrt_arith2_v( &__lccrt_uadd_sat_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_uadd_sat_v */ + +void +__lccrt_sadd_sat_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)) +{ + __lccrt_arith2_v( &__lccrt_sadd_sat_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_sadd_sat_v */ + +void +__lccrt_usub_sat_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)) +{ + __lccrt_arith2_v( &__lccrt_usub_sat_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_usub_sat_v */ + +void +__lccrt_ssub_sat_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)) +{ + __lccrt_arith2_v( &__lccrt_ssub_sat_n, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_ssub_sat_v */ + +void +__lccrt_fabs_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &fabsf, &fabs, &fabsl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_fabs_v */ + +void +__lccrt_exp2_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &exp2f, &exp2, &exp2l, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_exp2_v */ + +void +__lccrt_exp10_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &exp10f, &exp10, &exp10l, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_exp10_v */ + +void +__lccrt_exp_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &expf, &exp, &expl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_exp_v */ + +void +__lccrt_pow_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)) +{ + __lccrt_farith2_v( &powf, &pow, &powl, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_pow_v */ + +void +__lccrt_powi_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)) +{ + int i; + int byte_elen = reb / 8; + + assert( (reb % 8 == 0) && (bn == 1) && (reb == 32)); + assert( (rn == an) && (reb == aeb) && (reb == beb) && (rn*reb == rb)); + for ( i = 0; i < rn; ++i ) + { + int y; + uint8_t *q0 = r + i*byte_elen; + uint8_t *p0 = a + i*byte_elen; + + memcpy( &y, b, sizeof( y)); + if ( (reb == 32) ) + { + float z, x; + + memcpy( &x, p0, sizeof( x)); + z = __builtin_powif( x, y); + memcpy( q0, &z, sizeof( z)); + + } else if ( (reb == 64) ) + { + double z, x; + + memcpy( &x, p0, sizeof( x)); + z = __builtin_powi( x, y); + memcpy( q0, &z, sizeof( z)); + + } else if ( (reb == 80) ) + { + long double z, x; + + memcpy( &x, p0, sizeof( x)); + z = __builtin_powil( x, y); + memcpy( q0, &z, sizeof( z)); + } else + { + assert( 0); + } + } + + return; +} /* __lccrt_powi_v */ + +void +__lccrt_fma_v( __LCCRT_VEC_ARGS3( rb, ab, bb, cb, r, a, b, c, rn, an, bn, cn, reb, aeb, beb, ceb)) +{ + int i; + int byte_elen = reb / 8; + + assert( (reb % 8 == 0)); + assert( (rn == an) && (rn == bn) && (rn == cn) && (rn*reb == rb)); + assert( (reb == aeb) && (reb == beb) && (reb == ceb)); + for ( i = 0; i < rn; ++i ) + { + uint8_t *q0 = r + i*byte_elen; + uint8_t *p0 = a + i*byte_elen; + uint8_t *p1 = b + i*byte_elen; + uint8_t *p2 = c + i*byte_elen; + + if ( (reb == 32) ) + { + float z, x, y, u; + + memcpy( &x, p0, sizeof( x)); + memcpy( &y, p1, sizeof( y)); + memcpy( &u, p2, sizeof( u)); + z = fmaf( x, y, u); + memcpy( q0, &z, sizeof( z)); + + } else if ( (reb == 64) ) + { + double z, x, y, u; + + memcpy( &x, p0, sizeof( x)); + memcpy( &y, p1, sizeof( y)); + memcpy( &u, p2, sizeof( u)); + z = fma( x, y, u); + memcpy( q0, &z, sizeof( z)); + + } else if ( (reb == 80) ) + { + long double z, x, y, u; + + memcpy( &x, p0, sizeof( x)); + memcpy( &y, p1, sizeof( y)); + memcpy( &u, p2, sizeof( u)); + z = fmal( x, y, u); + memcpy( q0, &z, sizeof( z)); + } else + { + assert( 0); + } + } + + return; +} /* __lccrt_fma_v */ + +void +__lccrt_minn_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)) +{ + __lccrt_farith2_v( &fminf, &fmin, &fminl, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_minn_v */ + +void +__lccrt_maxn_v( __LCCRT_VEC_ARGS2( rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb)) +{ + __lccrt_farith2_v( &fmaxf, &fmax, &fmaxl, rb, ab, bb, r, a, b, rn, an, bn, reb, aeb, beb); + + return; +} /* __lccrt_maxn_v */ + +void +__lccrt_sqrt_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &sqrtf, &sqrt, &sqrtl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_sqrt_v */ + +void +__lccrt_log2_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &log2f, &log2, &log2l, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_log2_v */ + +void +__lccrt_log10_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &log10f, &log10, &log10l, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_log10_v */ + +void +__lccrt_log_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &logf, &log, &logl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_log_v */ + +void +__lccrt_cos_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &cosf, &cos, &cosl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_cos_v */ + +void +__lccrt_sin_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &sinf, &sin, &sinl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_sin_v */ + +void +__lccrt_tan_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &tanf, &tan, &tanl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_tan_v */ + +void +__lccrt_acos_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &acosf, &acos, &acosl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_acos_v */ + +void +__lccrt_asin_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &asinf, &asin, &asinl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_asin_v */ + +void +__lccrt_floor_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &floorf, &floor, &floorl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_floor_v */ + +void +__lccrt_ceil_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &ceilf, &ceil, &ceill, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_ceil_v */ + +void +__lccrt_round_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &roundf, &round, &roundl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_round_v */ + +void +__lccrt_ftrunc_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &truncf, &trunc, &truncl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_ftrunc_v */ + +void +__lccrt_rint_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_farith1_v( &rintf, &rint, &rintl, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_rint_v */ + +void +__lccrt_bswap_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_arith1_v( &__lccrt_bswap_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_bswap_v */ + +void +__lccrt_bitreverse_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_arith1_v( &__lccrt_bitreverse_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_bitreverse_v */ + +void +__lccrt_ctpop_v( __LCCRT_VEC_ARGS1( rb, ab, r, a, rn, an, reb, aeb)) +{ + __lccrt_arith1_v( &__lccrt_ctpop_n, rb, ab, r, a, rn, an, reb, aeb); + + return; +} /* __lccrt_ctpop_v */ + +void +__lccrt_shuffle_n( uint32_t rb, uint32_t ab, uint32_t bb, uint32_t cb, + uint8_t *r, uint8_t *a, uint8_t *b, uint8_t *c, + uint32_t rn, uint32_t an, uint32_t bn, uint32_t cn) +{ + int i; + + if ( (rn == cn) + && (rn > 0) + && (an > 0) + && (bn > 0) + && (rb > 0) + && (ab > 0) + && (bb > 0) ) + { + int k; + uint32_t re = rb / rn; + uint32_t ae = ab / an; + uint32_t be = bb / bn; + uint32_t ce = cb / cn; + + if ( (re == ae) + && (re == be) + && (rb % rn == 0) + && (ab % an == 0) + && (bb % bn == 0) + && (cb % cn == 0) + && ((ce == 8) + || (ce == 16) + || (ce == 32) + || (ce == 64)) ) + { + if ( (re % 8 == 0) ) + { + for ( k = 0; k < rn; ++k ) + { + uint8_t *ps = 0; + uint64_t j = __LCCRT_BIT_INDEX( ce, c, k); + + assert( (0 <= j) && (j < an + bn)); + ps = (j < an) ? (a + j*(ae/8)) : (b + (j - an)*(be/8)); + memcpy( r + k*(re/8), ps, re/8); + } +#if 0 + } else if ( (re == 1) + || (re == 2) + || (re == 4) ) + { + memset( r, 0, rb/8); + for ( k = 0; k < rn; ++k ) + { + uint64_t j = __LCCRT_BIT_INDEX( ce, c, k); + uint64_t l0 = (j*re) / 8; + uint64_t l1 = (j*re) % 8; + uint64_t n0 = (k*re) / 8; + uint64_t n1 = (k*re) % 8; + uint8_t *p = (j < an) ? a : b; + uint8_t u = __lccrt_get_bits( p[l0], l1, l1 + re - 1); + + assert( (0 <= j) && (j < an + bn)); + r[n0] = __lccrt_set_bits( r[n0], n1, n1 + re - 1, u); + } +#endif + } else + { + __LCCRT_PRINT_BITS4( rb, ab, bb, cb); + __LCCRT_PRINT_BITS4( rn, an, bn, cn); + assert( 0); + } + } else + { + __LCCRT_PRINT_BITS4( rb, ab, bb, cb); + __LCCRT_PRINT_BITS4( rn, an, bn, cn); + assert( 0); + } + } else + { + __LCCRT_PRINT_BITS4( rb, ab, bb, cb); + __LCCRT_PRINT_BITS4( rn, an, bn, cn); + assert( 0); + } + + return; +} /* __lccrt_shuffle_n */ + +void +__lccrt_elemptr_v( int32_t res_len, uint8_t **res, int32_t num_inds, int32_t ptr_len, uint8_t **ptr, ...) +{ + va_list ap; + int i, j; + + //va_start( ap, ptr_len); + va_start( ap, ptr); + + assert( (res_len > 0) && (num_inds > 0)); + assert( (ptr_len == 1) || (ptr_len == res_len)); + for ( i = 0; i < res_len; ++i ) + { + res[i] = (ptr_len == 1) ? ptr[0] : ptr[i]; + } + + for ( i = 0; i < num_inds; ++i ) + { + int64_t ind_offset = va_arg( ap, int64_t); + int32_t ind_len = va_arg( ap, int32_t); + int32_t ind_bitsize = va_arg( ap, int32_t); + + assert( (ind_len > 0) && (ind_offset >= 0)); + assert( (ind_bitsize == 32) || (ind_bitsize == 64)); + if ( (ind_bitsize == 32) ) + { + int32_t *ind = va_arg( ap, int32_t *); + + for ( j = 0; j < res_len; ++j ) + { + res[j] += ind_offset * ((ind_len == 1) ? ind[0] : ind[j]); + } + } else + { + int64_t *ind = va_arg( ap, int64_t *); + + for ( j = 0; j < res_len; ++j ) + { + res[j] += ind_offset * ((ind_len == 1) ? ind[0] : ind[j]); + } + } + } + + va_end( ap); + + return; +} /* __lccrt_elemptr_v */ + +void +__lccrt_reduce_fmin_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + int i; + int byte_elen = reb / 8; + + assert( (reb % 8 == 0) && (rn == 1) && (reb == rb) && (an >= 1)); + assert( (reb == aeb) && (an*aeb == ab)); + if ( (reb == 32) ) + { + float x, y; + + memcpy( &x, a + 0*byte_elen, sizeof( x)); + for ( i = 1; i < an; ++i ) + { + memcpy( &y, a + i*byte_elen, sizeof( y)); + x = __builtin_fminf( x, y); + } + + memcpy( r, &x, sizeof( x)); + + } else if ( (reb == 64) ) + { + double x, y; + + memcpy( &x, a + 0*byte_elen, sizeof( x)); + for ( i = 1; i < an; ++i ) + { + memcpy( &y, a + i*byte_elen, sizeof( y)); + x = __builtin_fmin( x, y); + } + + memcpy( r, &x, sizeof( x)); + + } else if ( (reb == 80) ) + { + long double x, y; + + memcpy( &x, a + 0*byte_elen, sizeof( x)); + for ( i = 1; i < an; ++i ) + { + memcpy( &y, a + i*byte_elen, sizeof( y)); + x = __builtin_fminl( x, y); + } + + memcpy( r, &x, sizeof( x)); + } else + { + assert( 0); + } + + return; +} /* __lccrt_reduce_fmin_v */ + +void +__lccrt_reduce_fmax_v( uint32_t rb, uint32_t ab, uint8_t *r, uint8_t *a, + uint32_t rn, uint32_t an, uint32_t reb, uint32_t aeb) +{ + int i; + int byte_elen = reb / 8; + + assert( (reb % 8 == 0) && (rn == 1) && (reb == rb) && (an >= 1)); + assert( (reb == aeb) && (an*aeb == ab)); + if ( (reb == 32) ) + { + float x, y; + + memcpy( &x, a + 0*byte_elen, sizeof( x)); + for ( i = 1; i < an; ++i ) + { + memcpy( &y, a + i*byte_elen, sizeof( y)); + x = __builtin_fmaxf( x, y); + } + + memcpy( r, &x, sizeof( x)); + + } else if ( (reb == 64) ) + { + double x, y; + + memcpy( &x, a + 0*byte_elen, sizeof( x)); + for ( i = 1; i < an; ++i ) + { + memcpy( &y, a + i*byte_elen, sizeof( y)); + x = __builtin_fmax( x, y); + } + + memcpy( r, &x, sizeof( x)); + + } else if ( (reb == 80) ) + { + long double x, y; + + memcpy( &x, a + 0*byte_elen, sizeof( x)); + for ( i = 1; i < an; ++i ) + { + memcpy( &y, a + i*byte_elen, sizeof( y)); + x = __builtin_fmaxl( x, y); + } + + memcpy( r, &x, sizeof( x)); + } else + { + assert( 0); + } + + return; +} /* __lccrt_reduce_fmax_v */ + +__lccrt_uint128_t +__lccrt_bswap_128( __lccrt_uint128_t v) +{ + __lccrt_uint128_t r = {__builtin_bswap64( v.hi), __builtin_bswap64( v.lo)}; + + return (r); +} /* __lccrt_bswap_128 */ diff --git a/tools/lccrt_s/src/lccrt_overflow.c b/tools/lccrt_s/src/lccrt_overflow.c new file mode 100644 index 0000000..3b9de72 --- /dev/null +++ b/tools/lccrt_s/src/lccrt_overflow.c @@ -0,0 +1,1608 @@ +/** + * 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 + */ + +#include "lccrt_s.h" + +typedef union { + __lccrt_f32_t f; + uint32_t i; +} __lccrt_ce32_t; + +typedef union { + __lccrt_f64_t f; + uint64_t i; +} __lccrt_ce64_t; + +static __lccrt_ce32_t __lccrt_f32umax32 = {.i = 0x4f7fffff}; +static __lccrt_ce32_t __lccrt_f32smin32 = {.i = 0xcf000000}; +static __lccrt_ce32_t __lccrt_f32smax32 = {.i = 0x4effffff}; + +static __lccrt_ce32_t __lccrt_f32umax64 = {.i = 0x5f7fffff}; +static __lccrt_ce32_t __lccrt_f32smin64 = {.i = 0xdf000000}; +static __lccrt_ce32_t __lccrt_f32smax64 = {.i = 0x5effffff}; + +static __lccrt_ce32_t __lccrt_f32umax128 = {.i = 0x7f7fffff}; +static __lccrt_ce32_t __lccrt_f32smin128 = {.i = 0xff000000}; +static __lccrt_ce32_t __lccrt_f32smax128 = {.i = 0x7effffff}; + +static __lccrt_ce64_t __lccrt_f64umax64 = {.i = 0x43efffffffffffffUL}; +static __lccrt_ce64_t __lccrt_f64smin64 = {.i = 0xc3e0000000000000UL}; +static __lccrt_ce64_t __lccrt_f64smax64 = {.i = 0x43e0000000000000UL}; + +static __lccrt_ce64_t __lccrt_f64umax128 = {.i = 0x47dfffffffffffffUL}; +static __lccrt_ce64_t __lccrt_f64smin128 = {.i = 0xc7e0000000000000UL}; +static __lccrt_ce64_t __lccrt_f64smax128 = {.i = 0x47e0000000000000UL}; + +static int +__lccrt_cmp_eq_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + int r = 0; + + if ( (a.hi == b.hi) + && (a.lo == b.lo) ) + { + r = 1; + } + + return (r); +} /* __lccrt_cmp_eq_128 */ + +static int +__lccrt_cmp_uls_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + int r = 0; + + if ( (a.hi < b.hi) + || ((a.hi == b.hi) + && (a.lo < b.lo)) ) + { + r = 1; + } + + return (r); +} /* __lccrt_cmp_uls_128 */ + +static int +__lccrt_cmp_ule_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + int r = 0; + + if ( __lccrt_cmp_eq_128( a, b) + || __lccrt_cmp_uls_128( a, b) ) + { + r = 1; + } + + return (r); +} /* __lccrt_cmp_ule_128 */ + +static int +__lccrt_cmp_sls_128( __lccrt_uint128_t va, __lccrt_uint128_t vb) +{ + int r = 0; + int64_t ah = va.hi; + int64_t bh = vb.hi; + + if ( (ah < 0) && (0 <= bh) ) + { + r = 1; + + } else if ( (bh < 0) && (0 <= ah) ) + { + r = 0; + } else + { + if ( (ah >= 0) ) + { + r = __lccrt_cmp_uls_128( va, vb); + } else + { + r = !__lccrt_cmp_uls_128( va, vb); + } + } + + return (r); +} /* __lccrt_cmp_sls_128 */ + +#if 0 +static int +__lccrt_cmp_sle_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + int r = 0; + + if ( __lccrt_cmp_eq_128( a, b) + || __lccrt_cmp_sls_128( a, b) ) + { + r = 1; + } + + return (r); +} /* __lccrt_cmp_sle_128 */ +#endif + +static int +__lccrt_cmp_sgt_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + int r = __lccrt_cmp_sls_128( b, a); + + return (r); +} /* __lccrt_cmp_sgt_128 */ + +static int +__lccrt_cmp_eq_256( __lccrt_uint256_t a, __lccrt_uint256_t b) +{ + int r = 0; + + if ( __lccrt_cmp_eq_128( a.hi, b.hi) + && __lccrt_cmp_eq_128( a.lo, b.lo) ) + { + r = 1; + } + + return (r); +} /* __lccrt_cmp_eq_256 */ + +static __lccrt_uint128_t +__lccrt_inv_128( __lccrt_uint128_t a) +{ + __lccrt_uint128_t r = {.hi = ~a.hi, .lo = ~a.lo}; + + return (r); +} /* __lccrt_inv_128 */ + +static __lccrt_uint256_t +__lccrt_inv_256( __lccrt_uint256_t a) +{ + __lccrt_uint256_t r = {.hi = __lccrt_inv_128( a.hi), .lo = __lccrt_inv_128( a.lo)}; + + return (r); +} /* __lccrt_inv_256 */ + +static __lccrt_uint128_t +__lccrt_zext_128( uint64_t a) +{ + __lccrt_uint128_t r = {.hi = 0, .lo = a}; + + return (r); +} /* __lccrt_zext_128 */ + +static __lccrt_uint256_t +__lccrt_zext_256( __lccrt_uint128_t a) +{ + __lccrt_uint256_t r = {.hi = {0}, .lo = a}; + + return (r); +} /* __lccrt_zext_256 */ + +static __lccrt_uint128_t +__lccrt_sext_128( uint64_t a) +{ + uint64_t sign = ((int64_t)a) >> 63LL; + __lccrt_uint128_t r = {.hi = sign, .lo = a}; + + return (r); +} /* __lccrt_sext_128 */ + +static __lccrt_uint256_t +__lccrt_sext_256( __lccrt_uint128_t a) +{ + uint64_t sign = ((int64_t)a.hi) >> 63LL; + __lccrt_uint256_t r = {.hi = __lccrt_sext_128( sign), .lo = a}; + + return (r); +} /* __lccrt_sext_256 */ + +static __lccrt_uint128_t +__lccrt_shl_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t r = {}; + uint64_t l = b.lo % 128; + + if ( (l == 0) ) + { + r = a; + + } else if ( (l < 64) ) + { + r.lo = a.lo << l; + r.hi = (a.hi << l) | (a.lo >> (64 - l)); + } else + { + r.lo = 0; + r.hi = a.lo << (l - 64); + } + + return (r); +} /* __lccrt_shl_128 */ + +static __lccrt_uint128_t +__lccrt_shr_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t r = {}; + uint64_t l = b.lo % 128; + + if ( (l == 0) ) + { + r = a; + + } else if ( (l < 64) ) + { + r.lo = (a.hi << (64 - l)) | (a.lo >> l); + r.hi = a.hi >> l; + } else + { + r.lo = a.hi >> (l - 64); + r.hi = 0; + } + + return (r); +} /* __lccrt_shr_128 */ + +static __lccrt_uint128_t +__lccrt_uadd_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_overflow_128_t r = __lccrt_uadd_overflow_128( a, b); + + return (r.value); +} /* __lccrt_uadd_128 */ + +static __lccrt_uint256_t +__lccrt_uadd_256( __lccrt_uint256_t a, __lccrt_uint256_t b) +{ + __lccrt_overflow_256_t r = __lccrt_uadd_overflow_256( a, b); + + return (r.value); +} /* __lccrt_uadd_256 */ + +static __lccrt_uint128_t +__lccrt_usub_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t d = {.hi = 0, .lo = 1}; + __lccrt_uint128_t r = __lccrt_uadd_128( a, __lccrt_uadd_128( __lccrt_inv_128( b), d)); + + return (r); +} /* __lccrt_usub_128 */ + +static __lccrt_uint256_t +__lccrt_usub_256( __lccrt_uint256_t a, __lccrt_uint256_t b) +{ + __lccrt_uint256_t d = {.lo = {.lo = 1}}; + __lccrt_uint256_t r = __lccrt_uadd_256( a, __lccrt_uadd_256( __lccrt_inv_256( b), d)); + + return (r); +} /* __lccrt_usub_256 */ + +static __lccrt_uint128_t +__lccrt_umul_64x64_128( uint64_t a, uint64_t b) +{ + uint64_t a0 = a & 0xffffffff; + uint64_t b0 = b & 0xffffffff; + uint64_t a1 = a >> 32; + uint64_t b1 = b >> 32; + __lccrt_uint128_t c0 = {.hi = 0, .lo = (a0*b0)}; + __lccrt_uint128_t c1 = {.hi = (a0*b1) >> 32, .lo = (a0*b1) << 32}; + __lccrt_uint128_t c2 = {.hi = (a1*b0) >> 32, .lo = (a1*b0) << 32}; + __lccrt_uint128_t c3 = {.hi = (a1*b1), .lo = 0}; + __lccrt_uint128_t r = __lccrt_uadd_128( __lccrt_uadd_128( c0, c1), __lccrt_uadd_128( c2, c3)); + + return (r); +} /* __lccrt_umul_64x64_128 */ + +static __lccrt_uint256_t +__lccrt_umul_128x128_256( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t a0b0 = __lccrt_umul_64x64_128( a.lo, b.lo); + __lccrt_uint128_t a1b0 = __lccrt_umul_64x64_128( a.hi, b.lo); + __lccrt_uint128_t a0b1 = __lccrt_umul_64x64_128( a.lo, b.hi); + __lccrt_uint128_t a1b1 = __lccrt_umul_64x64_128( a.hi, b.hi); + __lccrt_uint256_t c0 = {.hi = {0}, .lo = a0b0}; + __lccrt_uint256_t c1 = {.hi = {.lo = a1b0.hi}, .lo = {.hi = a1b0.lo}}; + __lccrt_uint256_t c2 = {.hi = {.lo = a0b1.hi}, .lo = {.hi = a0b1.lo}}; + __lccrt_uint256_t c3 = {.hi = a1b1, .lo = 0}; + __lccrt_uint256_t r = __lccrt_uadd_256( __lccrt_uadd_256( c0, c1), __lccrt_uadd_256( c2, c3)); + + return (r); +} /* __lccrt_umul_128x128_256 */ + +static __lccrt_uint128_t +__lccrt_umul_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t a0b0 = __lccrt_umul_64x64_128( a.lo, b.lo); + __lccrt_uint128_t a1b0 = {.hi = a.hi*b.lo, .lo = 0}; + __lccrt_uint128_t a0b1 = {.hi = a.lo*b.hi, .lo = 0}; + __lccrt_uint128_t r = __lccrt_uadd_128( __lccrt_uadd_128( a0b0, a1b0), a0b1); + + return (r); +} /* __lccrt_umul_128 */ + +static __lccrt_uint256_t +__lccrt_umul_256( __lccrt_uint256_t a, __lccrt_uint256_t b) +{ + __lccrt_uint256_t a0b0 = __lccrt_umul_128x128_256( a.lo, b.lo); + __lccrt_uint256_t a1b0 = {.hi = __lccrt_umul_128( a.hi, b.lo), .lo = {0}}; + __lccrt_uint256_t a0b1 = {.hi = __lccrt_umul_128( a.lo, b.hi), .lo = {0}}; + __lccrt_uint256_t r = __lccrt_uadd_256( __lccrt_uadd_256( a0b0, a1b0), a0b1); + + return (r); +} /* __lccrt_umul_256 */ + +__lccrt_overflow_8_t +__lccrt_uadd_overflow_8( uint64_t a, uint64_t b) +{ + uint64_t c = ((uint64_t)(uint8_t)a) + ((uint64_t)(uint8_t)b); + __lccrt_overflow_8_t r = {.value=c, .is_overflow=(c != ((uint64_t)(uint8_t)c))}; + + return (r); +} /* __lccrt_uadd_overflow_8 */ + +__lccrt_overflow_8_t +__lccrt_sadd_overflow_8( uint64_t a, uint64_t b) +{ + uint64_t c = ((int64_t)(int8_t)a) + ((int64_t)(int8_t)b); + __lccrt_overflow_8_t r = {.value=c, .is_overflow=(c != ((int64_t)(int8_t)c))}; + + return (r); +} /* __lccrt_sadd_overflow_8 */ + +__lccrt_overflow_16_t +__lccrt_uadd_overflow_16( uint64_t a, uint64_t b) +{ + uint64_t c = ((uint64_t)(uint16_t)a) + ((uint64_t)(uint16_t)b); + __lccrt_overflow_16_t r = {.value=c, .is_overflow=(c != ((uint64_t)(uint16_t)c))}; + + return (r); +} /* __lccrt_uadd_overflow_16 */ + +__lccrt_overflow_16_t +__lccrt_sadd_overflow_16( uint64_t a, uint64_t b) +{ + uint64_t c = ((int64_t)(int16_t)a) + ((int64_t)(int16_t)b); + __lccrt_overflow_16_t r = {.value=c, .is_overflow=(c != ((int64_t)(int16_t)c))}; + + return (r); +} /* __lccrt_sadd_overflow_16 */ + +__lccrt_overflow_32_t +__lccrt_uadd_overflow_32( uint64_t a, uint64_t b) +{ + uint64_t c = ((uint64_t)(uint32_t)a) + ((uint64_t)(uint32_t)b); + __lccrt_overflow_32_t r = {.value=c, .is_overflow=(c != ((uint64_t)(uint32_t)c))}; + + return (r); +} /* __lccrt_uadd_overflow_32 */ + +__lccrt_overflow_32_t +__lccrt_sadd_overflow_32( uint64_t a, uint64_t b) +{ + uint64_t c = ((int64_t)(int32_t)a) + ((int64_t)(int32_t)b); + __lccrt_overflow_32_t r = {.value=c, .is_overflow=(c != ((int64_t)(int32_t)c))}; + + return (r); +} /* __lccrt_sadd_overflow_32 */ + +__lccrt_overflow_64_t +__lccrt_uadd_overflow_64( uint64_t a, uint64_t b) +{ + uint64_t c = a + b; + __lccrt_overflow_64_t r = {.value=c, .is_overflow=(__LCCRT_UMAX_U64 - a < b)}; + + return (r); +} /* __lccrt_uadd_overflow_64 */ + +__lccrt_overflow_64_t +__lccrt_sadd_overflow_64( uint64_t va, uint64_t vb) +{ + int64_t a = va; + int64_t b = vb; + uint64_t c = a + b; + int is_overflow = ((a > 0) && (__LCCRT_SMAX_S64 - a < b)) || ((a < 0) && (b < __LCCRT_SMIN_S64 - a)); + __lccrt_overflow_64_t r = {.value=c, .is_overflow=is_overflow}; + + return (r); +} /* __lccrt_sadd_overflow_64 */ + +__lccrt_overflow_128_t +__lccrt_uadd_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_overflow_128_t r; + __lccrt_overflow_64_t r0 = __lccrt_uadd_overflow_64( a.lo, b.lo); + __lccrt_overflow_64_t r1 = __lccrt_uadd_overflow_64( a.hi, r0.is_overflow); + __lccrt_overflow_64_t r2 = __lccrt_uadd_overflow_64( b.hi, r1.value); + + r.value.lo = r0.value; + r.value.hi = r2.value; + r.is_overflow = r1.is_overflow || r2.is_overflow; + + return (r); +} /* __lccrt_uadd_overflow_128 */ + +__lccrt_overflow_128_t +__lccrt_sadd_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_overflow_128_t r; + __lccrt_overflow_64_t r0 = __lccrt_uadd_overflow_64( a.lo, b.lo); + __lccrt_overflow_64_t r1 = __lccrt_sadd_overflow_64( a.hi, r0.is_overflow); + __lccrt_overflow_64_t r2 = __lccrt_sadd_overflow_64( b.hi, r1.value); + + r.value.lo = r0.value; + r.value.hi = r2.value; + r.is_overflow = r1.is_overflow || r2.is_overflow; + + return (r); +} /* __lccrt_sadd_overflow_128 */ + +__lccrt_overflow_256_t +__lccrt_uadd_overflow_256( __lccrt_uint256_t a, __lccrt_uint256_t b) +{ + __lccrt_overflow_256_t r; + __lccrt_overflow_128_t r0 = __lccrt_uadd_overflow_128( a.lo, b.lo); + __lccrt_overflow_128_t r1 = __lccrt_uadd_overflow_128( a.hi, __lccrt_zext_128( r0.is_overflow)); + __lccrt_overflow_128_t r2 = __lccrt_uadd_overflow_128( b.hi, r1.value); + + r.value.lo = r0.value; + r.value.hi = r2.value; + r.is_overflow = r1.is_overflow || r2.is_overflow; + + return (r); +} /* __lccrt_uadd_overflow_256 */ + +__lccrt_overflow_256_t +__lccrt_sadd_overflow_256( __lccrt_uint256_t a, __lccrt_uint256_t b) +{ + __lccrt_overflow_256_t r; + __lccrt_overflow_128_t r0 = __lccrt_uadd_overflow_128( a.lo, b.lo); + __lccrt_overflow_128_t r1 = __lccrt_sadd_overflow_128( a.hi, __lccrt_zext_128( r0.is_overflow)); + __lccrt_overflow_128_t r2 = __lccrt_sadd_overflow_128( b.hi, r1.value); + + r.value.lo = r0.value; + r.value.hi = r2.value; + r.is_overflow = r1.is_overflow || r2.is_overflow; + + return (r); +} /* __lccrt_sadd_overflow_256 */ + +__lccrt_overflow_8_t +__lccrt_usub_overflow_8( uint64_t a, uint64_t b) +{ + uint64_t c = ((uint64_t)(uint8_t)a) - ((uint64_t)(uint8_t)b); + __lccrt_overflow_8_t r = {.value=c, .is_overflow=(c != ((uint64_t)(uint8_t)c))}; + + return (r); +} /* __lccrt_usub_overflow_8 */ + +__lccrt_overflow_8_t +__lccrt_ssub_overflow_8( uint64_t a, uint64_t b) +{ + uint64_t c = ((int64_t)(int8_t)a) - ((int64_t)(int8_t)b); + __lccrt_overflow_8_t r = {.value=c, .is_overflow=(c != ((int64_t)(int8_t)c))}; + + return (r); +} /* __lccrt_ssub_overflow_8 */ + +__lccrt_overflow_16_t +__lccrt_usub_overflow_16( uint64_t a, uint64_t b) +{ + uint64_t c = ((uint64_t)(uint16_t)a) - ((uint64_t)(uint16_t)b); + __lccrt_overflow_16_t r = {.value=c, .is_overflow=(c != ((uint64_t)(uint16_t)c))}; + + return (r); +} /* __lccrt_usub_overflow_16 */ + +__lccrt_overflow_16_t +__lccrt_ssub_overflow_16( uint64_t a, uint64_t b) +{ + uint64_t c = ((int64_t)(int16_t)a) - ((int64_t)(int16_t)b); + __lccrt_overflow_16_t r = {.value=c, .is_overflow=(c != ((int64_t)(int16_t)c))}; + + return (r); +} /* __lccrt_ssub_overflow_16 */ + +__lccrt_overflow_32_t +__lccrt_usub_overflow_32( uint64_t a, uint64_t b) +{ + uint64_t c = ((uint64_t)(uint32_t)a) - ((uint64_t)(uint32_t)b); + __lccrt_overflow_32_t r = {.value=c, .is_overflow=(c != ((uint64_t)(uint32_t)c))}; + + return (r); +} /* __lccrt_usub_overflow_32 */ + +__lccrt_overflow_32_t +__lccrt_ssub_overflow_32( uint64_t a, uint64_t b) +{ + uint64_t c = ((int64_t)(int32_t)a) - ((int64_t)(int32_t)b); + __lccrt_overflow_32_t r = {.value=c, .is_overflow=(c != ((int64_t)(int32_t)c))}; + + return (r); +} /* __lccrt_ssub_overflow_32 */ + +__lccrt_overflow_64_t +__lccrt_usub_overflow_64( uint64_t a, uint64_t b) +{ + uint64_t c = a - b; + __lccrt_overflow_64_t r = {.value=c, .is_overflow=(a < b)}; + + return (r); +} /* __lccrt_usub_overflow_64 */ + +__lccrt_overflow_64_t +__lccrt_ssub_overflow_64( uint64_t va, uint64_t vb) +{ + int64_t a = va; + int64_t b = vb; + uint64_t c = a - b; + int is_overflow = 0; + __lccrt_overflow_64_t r = {.value=c}; + + if ( ((a >= 0) + && ((b == __LCCRT_SMIN_S64) + || (__LCCRT_SMAX_S64 - a < -b))) + || ((a < 0) + && (b != __LCCRT_SMIN_S64) + && (-b < __LCCRT_SMIN_S64 - a)) ) + { + is_overflow = 1; + } + + r.is_overflow = is_overflow; + + return (r); +} /* __lccrt_ssub_overflow_64 */ + +__lccrt_overflow_128_t +__lccrt_usub_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t c = __lccrt_inv_128( b); + __lccrt_uint128_t d = {.hi = 0, .lo = 1}; + __lccrt_overflow_128_t r = {0}; + + c = __lccrt_uadd_overflow_128( c, d).value; + r = __lccrt_uadd_overflow_128( a, c); + r.is_overflow = (a.hi < b.hi) || ((a.hi == b.hi) && (a.lo < b.lo)); + + return (r); +} /* __lccrt_usub_overflow_128 */ + +__lccrt_overflow_128_t +__lccrt_ssub_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t c = __lccrt_usub_128( a, b); + __lccrt_uint256_t qc = __lccrt_sext_256( c); + __lccrt_uint256_t qd = __lccrt_usub_256( __lccrt_sext_256( a), __lccrt_sext_256( b)); + __lccrt_overflow_128_t r = {.value = c, .is_overflow = !__lccrt_cmp_eq_256( qc, qd)}; + + return (r); +} /* __lccrt_ssub_overflow_128 */ + +__lccrt_overflow_8_t +__lccrt_umul_overflow_8( uint64_t a, uint64_t b) +{ + uint64_t c = ((uint64_t)(uint8_t)a) * ((uint64_t)(uint8_t)b); + __lccrt_overflow_8_t r = {.value=c, .is_overflow=(c != ((uint64_t)(uint8_t)c))}; + + return (r); +} /* __lccrt_umul_overflow_8 */ + +__lccrt_overflow_8_t +__lccrt_smul_overflow_8( uint64_t a, uint64_t b) +{ + uint64_t c = ((int64_t)(int8_t)a) * ((int64_t)(int8_t)b); + __lccrt_overflow_8_t r = {.value=c, .is_overflow=(c != ((int64_t)(int8_t)c))}; + + return (r); +} /* __lccrt_smul_overflow_8 */ + +__lccrt_overflow_16_t +__lccrt_umul_overflow_16( uint64_t a, uint64_t b) +{ + uint64_t c = ((uint64_t)(uint16_t)a) * ((uint64_t)(uint16_t)b); + __lccrt_overflow_16_t r = {.value=c, .is_overflow=(c != ((uint64_t)(uint16_t)c))}; + + return (r); +} /* __lccrt_umul_overflow_16 */ + +__lccrt_overflow_16_t +__lccrt_smul_overflow_16( uint64_t a, uint64_t b) +{ + uint64_t c = ((int64_t)(int16_t)a) * ((int64_t)(int16_t)b); + __lccrt_overflow_16_t r = {.value=c, .is_overflow=(c != ((int64_t)(int16_t)c))}; + + return (r); +} /* __lccrt_smul_overflow_16 */ + +__lccrt_overflow_32_t +__lccrt_umul_overflow_32( uint64_t a, uint64_t b) +{ + uint64_t c = ((uint64_t)(uint32_t)a) * ((uint64_t)(uint32_t)b); + __lccrt_overflow_32_t r = {.value=c, .is_overflow=(c != ((uint64_t)(uint32_t)c))}; + + return (r); +} /* __lccrt_umul_overflow_32 */ + +__lccrt_overflow_32_t +__lccrt_smul_overflow_32( uint64_t a, uint64_t b) +{ + uint64_t c = ((int64_t)(int32_t)a) * ((int64_t)(int32_t)b); + __lccrt_overflow_32_t r = {.value=c, .is_overflow=(c != ((int64_t)(int32_t)c))}; + + return (r); +} /* __lccrt_smul_overflow_32 */ + +__lccrt_overflow_64_t +__lccrt_umul_overflow_64( uint64_t a, uint64_t b) +{ + uint64_t c = a * b; + __lccrt_overflow_64_t r = {.value=c, .is_overflow=((a > 0) && ((__LCCRT_UMAX_U64 / a) < b))}; + + return (r); +} /* __lccrt_umul_overflow_64 */ + +__lccrt_overflow_64_t +__lccrt_smul_overflow_64( uint64_t va, uint64_t vb) +{ + int64_t a = va; + int64_t b = vb; + uint64_t c = a * b; + int is_overflow = 0; + __lccrt_overflow_64_t r = {.value = c}; + + if ( (a == 0) + || (b == 0) ) + { + is_overflow = 0; + + } else if ( (a == __LCCRT_SMIN_S64) ) + { + is_overflow = (b != 1); + + } else if ( (b == __LCCRT_SMIN_S64) ) + { + is_overflow = (a != 1); + } else + { + uint64_t ap = (a > 0) ? a : -a; + uint64_t bp = (b > 0) ? b : -b; + + if ( ((a > 0) == (b > 0)) ) + { + is_overflow = ((__LCCRT_SMAX_U64 / ap) < bp); + } else + { + is_overflow = ((__LCCRT_SMIN_U64 / ap) < bp); + } + } + + r.is_overflow = is_overflow; + + return (r); +} /* __lccrt_smul_overflow_64 */ + +__lccrt_overflow_128_t +__lccrt_umul_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_overflow_128_t r; + int is_overflow = 0; + __lccrt_uint128_t a0b0 = __lccrt_umul_64x64_128( a.lo, b.lo); + __lccrt_overflow_64_t ra0b1 = __lccrt_umul_overflow_64( a.lo, b.hi); + __lccrt_overflow_64_t ra1b0 = __lccrt_umul_overflow_64( a.hi, b.lo); + __lccrt_uint128_t a0b1 = {.hi = ra0b1.value, .lo = 0}; + __lccrt_uint128_t a1b0 = {.hi = ra1b0.value, .lo = 0}; + __lccrt_overflow_128_t r0 = __lccrt_uadd_overflow_128( a0b0, a0b1); + __lccrt_overflow_128_t r1 = __lccrt_uadd_overflow_128( r0.value, a1b0); + + if ( (a.hi + && b.hi) + || ra0b1.is_overflow + || ra1b0.is_overflow + || r0.is_overflow + || r1.is_overflow ) + { + is_overflow = 1; + } + + r.value = r1.value; + r.is_overflow = is_overflow; + + return (r); +} /* __lccrt_umul_overflow_128 */ + +__lccrt_overflow_128_t +__lccrt_smul_overflow_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t c = __lccrt_umul_128( a, b); + __lccrt_uint256_t qc = __lccrt_sext_256( c); + __lccrt_uint256_t qd = __lccrt_umul_256( __lccrt_sext_256( a), __lccrt_sext_256( b)); + __lccrt_overflow_128_t r = {.value = c, .is_overflow = !__lccrt_cmp_eq_256( qc, qd)}; + + return (r); +} /* __lccrt_smul_overflow_128 */ + +static uint64_t +__lccrt_uadd_sat( uint64_t a, uint64_t b, uint64_t umax) +{ + uint64_t c = a + b; + uint64_t r = (a > (umax - b)) ? umax : c; + + return (r); +} /* __lccrt_uadd_sat */ + +static int64_t +__lccrt_sadd_sat( int64_t a, int64_t b, int64_t smin, int64_t smax) +{ + int64_t c = a + b; + int64_t r = (b < 0) ? ((a < (smin - b)) ? smin : c) : ((a > (smax - b)) ? smax : c); + + return (r); +} /* __lccrt_sadd_sat */ + +static uint64_t +__lccrt_usub_sat( uint64_t a, uint64_t b) +{ + return (a < b) ? 0 : (a - b); +} /* __lccrt_usub_sat */ + +static int64_t +__lccrt_ssub_sat( int64_t a, int64_t b, int64_t smin, int64_t smax) +{ + int64_t c = a - b; + int64_t r = (b > 0) ? ((a < (smin + b)) ? smin : c) : ((a > (smax + b)) ? smax : c); + + return (r); +} /* __lccrt_ssub_sat */ + +uint8_t +__lccrt_uadd_sat_8( uint8_t a, uint8_t b) +{ + return __lccrt_uadd_sat( a, b, 0xff); +} /* __lccrt_uadd_sat_8 */ + +uint16_t +__lccrt_uadd_sat_16( uint16_t a, uint16_t b) +{ + return __lccrt_uadd_sat( a, b, 0xffff); +} /* __lccrt_uadd_sat_16 */ + +uint32_t +__lccrt_uadd_sat_32( uint32_t a, uint32_t b) +{ + return __lccrt_uadd_sat( a, b, __LCCRT_UMAX_U32); +} /* __lccrt_uadd_sat_32 */ + +uint64_t +__lccrt_uadd_sat_64( uint64_t a, uint64_t b) +{ + return __lccrt_uadd_sat( a, b, __LCCRT_UMAX_U64); +} /* __lccrt_uadd_sat_64 */ + +uint8_t +__lccrt_sadd_sat_8( uint8_t a, uint8_t b) +{ + return __lccrt_sadd_sat( (int8_t)a, (int8_t)b, (int8_t)0x80, (int8_t)0x7f); +} /* __lccrt_sadd_sat_8 */ + +uint16_t +__lccrt_sadd_sat_16( uint16_t a, uint16_t b) +{ + return __lccrt_sadd_sat( (int16_t)a, (int16_t)b, (int16_t)0x8000, (int16_t)0x7fff); +} /* __lccrt_sadd_sat_16 */ + +uint32_t +__lccrt_sadd_sat_32( uint32_t a, uint32_t b) +{ + return __lccrt_sadd_sat( (int32_t)a, (int32_t)b, (int32_t)__LCCRT_SMIN_S32, (int32_t)__LCCRT_SMAX_S32); +} /* __lccrt_sadd_sat_32 */ + +uint64_t +__lccrt_sadd_sat_64( uint64_t a, uint64_t b) +{ + return __lccrt_sadd_sat( (int64_t)a, (int64_t)b, (int64_t)__LCCRT_SMIN_S64, (int64_t)__LCCRT_SMAX_S64); +} /* __lccrt_sadd_sat_64 */ + +uint8_t +__lccrt_usub_sat_8( uint8_t a, uint8_t b) +{ + return __lccrt_usub_sat( a, b); +} /* __lccrt_usub_sat_8 */ + +uint16_t +__lccrt_usub_sat_16( uint16_t a, uint16_t b) +{ + return __lccrt_usub_sat( a, b); +} /* __lccrt_usub_sat_16 */ + +uint32_t +__lccrt_usub_sat_32( uint32_t a, uint32_t b) +{ + return __lccrt_usub_sat( a, b); +} /* __lccrt_usub_sat_32 */ + +uint64_t +__lccrt_usub_sat_64( uint64_t a, uint64_t b) +{ + return __lccrt_usub_sat( a, b); +} /* __lccrt_usub_sat_64 */ + +uint8_t +__lccrt_ssub_sat_8( uint8_t a, uint8_t b) +{ + return __lccrt_ssub_sat( (int8_t)a, (int8_t)b, (int8_t)0x80, (int8_t)0x7f); +} /* __lccrt_ssub_sat_8 */ + +uint16_t +__lccrt_ssub_sat_16( uint16_t a, uint16_t b) +{ + return __lccrt_ssub_sat( (int16_t)a, (int16_t)b, (int16_t)0x8000, (int16_t)0x7fff); +} /* __lccrt_ssub_sat_16 */ + +uint32_t +__lccrt_ssub_sat_32( uint32_t a, uint32_t b) +{ + return __lccrt_ssub_sat( (int32_t)a, (int32_t)b, (int32_t)__LCCRT_SMIN_S32, (int32_t)__LCCRT_SMAX_S32); +} /* __lccrt_ssub_sat_32 */ + +uint64_t +__lccrt_ssub_sat_64( uint64_t a, uint64_t b) +{ + return __lccrt_ssub_sat( (int64_t)a, (int64_t)b, (int64_t)__LCCRT_SMIN_S64, (int64_t)__LCCRT_SMAX_S64); +} /* __lccrt_ssub_sat_64 */ + +__lccrt_uint128_t +__lccrt_uadd_sat_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t r; + __lccrt_uint128_t umax = {.lo = ~0ULL, .hi = ~0ULL}; + + if ( __lccrt_cmp_ule_128( a, __lccrt_usub_128( umax, b)) ) + { + r = __lccrt_uadd_128( a, b); + } else + { + r = umax; + } + + return (r); +} /* __lccrt_uadd_sat_128 */ + +__lccrt_uint128_t +__lccrt_sadd_sat_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t r; + __lccrt_uint128_t s0 = {}; + __lccrt_uint128_t smax = {.lo = ~0ULL, .hi = ~0ULL >> 1}; + __lccrt_uint128_t smin = {.lo = 0, .hi = 1ULL << 63ULL}; + + if ( __lccrt_cmp_sls_128( b, s0) ) + { + if ( __lccrt_cmp_sls_128( a, __lccrt_usub_128( smin, b)) ) + { + r = smin; + } else + { + r = __lccrt_uadd_128( a, b); + } + } else + { + if ( __lccrt_cmp_sgt_128( a, __lccrt_usub_128( smax, b)) ) + { + r = smax; + } else + { + r = __lccrt_uadd_128( a, b); + } + } + + return (r); +} /* __lccrt_sadd_sat_128 */ + +__lccrt_uint128_t +__lccrt_usub_sat_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t r; + __lccrt_uint128_t u0 = {}; + + if ( __lccrt_cmp_uls_128( a, b) ) + { + r = u0; + } else + { + r = __lccrt_usub_128( a, b); + } + + return (r); +} /* __lccrt_usub_sat_128 */ + +__lccrt_uint128_t +__lccrt_ssub_sat_128( __lccrt_uint128_t a, __lccrt_uint128_t b) +{ + __lccrt_uint128_t r; + __lccrt_uint128_t s0 = {}; + __lccrt_uint128_t smax = {.lo = ~0ULL, .hi = ~0ULL >> 1}; + __lccrt_uint128_t smin = {.lo = 0, .hi = 1ULL << 63ULL}; + + if ( __lccrt_cmp_sgt_128( b, s0) ) + { + if ( __lccrt_cmp_sls_128( a, __lccrt_uadd_128( smin, b)) ) + { + r = smin; + } else + { + r = __lccrt_usub_128( a, b); + } + } else + { + if ( __lccrt_cmp_sgt_128( a, __lccrt_uadd_128( smax, b)) ) + { + r = smax; + } else + { + r = __lccrt_usub_128( a, b); + } + } + + return (r); +} /* __lccrt_ssub_sat_128 */ + +static uint64_t +__lccrt_fshl( uint64_t a, uint64_t b, uint64_t c, uint64_t l) +{ + uint64_t r; + uint64_t m = ~0ULL >> (64 - l); + + a = a & m; + b = b & m; + c = c % l; + a = (a << c); + b = (b >> (l - c)); + r = c ? (a | b) : a; + r = r & m; + + return (r); +} /* __lccrt_fshl */ + +static uint64_t +__lccrt_fshr( uint64_t a, uint64_t b, uint64_t c, uint64_t l) +{ + uint64_t r; + uint64_t m = ~0ULL >> (64 - l); + + a = a & m; + b = b & m; + c = c % l; + a = (a << (l - c)); + b = (b >> c); + r = c ? (a | b) : b; + r = r & m; + + return (r); +} /* __lccrt_fshr */ + +uint8_t __lccrt_fshl_i8( uint8_t a, uint8_t b, uint8_t c) { return __lccrt_fshl( a, b, c, 8); } +uint16_t __lccrt_fshl_i16( uint16_t a, uint16_t b, uint16_t c) { return __lccrt_fshl( a, b, c, 16); } +uint32_t __lccrt_fshl_i32( uint32_t a, uint32_t b, uint32_t c) { return __lccrt_fshl( a, b, c, 32); } +uint64_t __lccrt_fshl_i64( uint64_t a, uint64_t b, uint64_t c) { return __lccrt_fshl( a, b, c, 64); } +uint8_t __lccrt_fshr_8( uint8_t a, uint8_t b, uint8_t c) { return __lccrt_fshr( a, b, c, 8); } +uint16_t __lccrt_fshr_16( uint16_t a, uint16_t b, uint16_t c) { return __lccrt_fshr( a, b, c, 16); } +uint32_t __lccrt_fshr_32( uint32_t a, uint32_t b, uint32_t c) { return __lccrt_fshr( a, b, c, 32); } +uint64_t __lccrt_fshr_64( uint64_t a, uint64_t b, uint64_t c) { return __lccrt_fshr( a, b, c, 64); } + +__lccrt_uint128_t +__lccrt_fshl_i128( __lccrt_uint128_t a, __lccrt_uint128_t b, __lccrt_uint128_t c) +{ + __lccrt_uint128_t r = {}; + uint64_t l = c.lo % 128; + + if ( (l == 0) ) + { + r = a; + } else + { + __lccrt_uint128_t la = {.lo = l, .hi = 0}; + __lccrt_uint128_t lb = {.lo = 128 - l, .hi = 0}; + __lccrt_uint128_t a1 = __lccrt_shl_128( a, la); + __lccrt_uint128_t b1 = __lccrt_shr_128( b, lb); + + r.lo = a1.lo | b1.lo; + r.hi = a1.hi | b1.hi; + } + + return (r); +} /* __lccrt_fshl_i128 */ + +__lccrt_uint128_t +__lccrt_fshr_128( __lccrt_uint128_t a, __lccrt_uint128_t b, __lccrt_uint128_t c) +{ + __lccrt_uint128_t r = {}; + uint64_t l = c.lo % 128; + + if ( (l == 0) ) + { + r = b; + } else + { + __lccrt_uint128_t la = {.lo = 128 - l, .hi = 0}; + __lccrt_uint128_t lb = {.lo = l, .hi = 0}; + __lccrt_uint128_t a1 = __lccrt_shl_128( a, la); + __lccrt_uint128_t b1 = __lccrt_shr_128( b, lb); + + r.lo = a1.lo | b1.lo; + r.hi = a1.hi | b1.hi; + } + + return (r); +} /* __lccrt_fshr_128 */ + +static uint64_t +__lccrt_clz64( uint64_t a) +{ + uint64_t r = (sizeof( long) == 4) ? __builtin_clzll( a) : __builtin_clzl( a); + + return (r); +} /* __lccrt_clz64 */ + +static uint64_t +__lccrt_ctz64( uint64_t a) +{ + uint64_t r = (sizeof( long) == 4) ? __builtin_ctzll( a) : __builtin_ctzl( a); + + return (r); +} /* __lccrt_ctz64 */ + +__lccrt_uint128_t +__lccrt_ctlz_128( __lccrt_uint128_t a) +{ + __lccrt_uint128_t r = {0}; + + if ( (a.hi != 0) ) + { + r.lo = __lccrt_clz64( a.hi); + } else + { + r.lo = (a.lo != 0) ? (64 + __lccrt_clz64( a.lo)) : 128; + } + + return (r); +} /* __lccrt_ctlz_128 */ + +__lccrt_uint128_t +__lccrt_cttz_128( __lccrt_uint128_t a) +{ + __lccrt_uint128_t r = {0}; + + if ( (a.lo != 0) ) + { + r.lo = __lccrt_ctz64( a.lo); + } else + { + r.lo = (a.hi != 0) ? (64 + __lccrt_ctz64( a.hi)) : 128; + } + + return (r); +} /* __lccrt_cttz_128 */ + +uint64_t +__lccrt_bitreverse_8( uint64_t a) +{ + int i; + uint64_t r = 0; + uint64_t b = 0; + + for ( i = 0; i < 8; ++i ) + { + b = (b << 1) | ((a >> i) & 0x1); + } + + r |= (((b >> 0*8) & 0xff) << 0*8); + + return (r); +} /* __lccrt_bitreverse_8 */ + +uint64_t +__lccrt_bitreverse_16( uint64_t a) +{ + int i; + uint64_t r = 0; + uint64_t b = 0; + + for ( i = 0; i < 8; ++i ) + { + b = (b << 1) | ((a >> i) & 0x0101); + } + + r |= (((b >> 1*8) & 0xff) << 0*8); + r |= (((b >> 0*8) & 0xff) << 1*8); + + return (r); +} /* __lccrt_bitreverse_16 */ + +uint64_t +__lccrt_bitreverse_32( uint64_t a) +{ + int i; + uint64_t r = 0; + uint64_t b = 0; + + for ( i = 0; i < 8; ++i ) + { + b = (b << 1) | ((a >> i) & 0x01010101); + } + + r |= (((b >> 3*8) & 0xff) << 0*8); + r |= (((b >> 2*8) & 0xff) << 1*8); + r |= (((b >> 1*8) & 0xff) << 2*8); + r |= (((b >> 0*8) & 0xff) << 3*8); + + return (r); +} /* __lccrt_bitreverse_32 */ + +uint64_t +__lccrt_bitreverse_64( uint64_t a) +{ + int i; + uint64_t r = 0; + uint64_t b = 0; + + for ( i = 0; i < 8; ++i ) + { + b = (b << 1) | ((a >> i) & 0x0101010101010101ULL); + } + + r |= (((b >> 7*8) & 0xff) << 0*8); + r |= (((b >> 6*8) & 0xff) << 1*8); + r |= (((b >> 5*8) & 0xff) << 2*8); + r |= (((b >> 4*8) & 0xff) << 3*8); + r |= (((b >> 3*8) & 0xff) << 4*8); + r |= (((b >> 2*8) & 0xff) << 5*8); + r |= (((b >> 1*8) & 0xff) << 6*8); + r |= (((b >> 0*8) & 0xff) << 7*8); + + return (r); +} /* __lccrt_bitreverse_64 */ + +__lccrt_uint128_t +__lccrt_bitreverse_128( __lccrt_uint128_t a) +{ + __lccrt_uint128_t r = {0}; + + r.lo = __lccrt_bitreverse_64( a.hi); + r.hi = __lccrt_bitreverse_64( a.lo); + + return (r); +} /* __lccrt_bitreverse_128 */ + +int8_t +__lccrt_fptosi_sat_i8f32( __lccrt_f32_t x) +{ + __lccrt_f32_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, -128); + y = __LCCRT_MIN( y, +127); + + return (y); +} /* __lccrt_fptosi_sat_i8f32 */ + +int8_t +__lccrt_fptosi_sat_i8f64( __lccrt_f64_t x) +{ + __lccrt_f64_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, -128); + y = __LCCRT_MIN( y, +127); + + return (y); +} /* __lccrt_fptosi_sat_i8f64 */ + +int8_t +__lccrt_fptosi_sat_i8f80( __lccrt_f80_t x) +{ + __lccrt_f80_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, -128); + y = __LCCRT_MIN( y, +127); + + return (y); +} /* __lccrt_fptosi_sat_i8f80 */ + +int16_t +__lccrt_fptosi_sat_i16f32( __lccrt_f32_t x) +{ + __lccrt_f32_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, -32768); + y = __LCCRT_MIN( y, +32767); + + return (y); +} /* __lccrt_fptosi_sat_i16f32 */ + +int16_t +__lccrt_fptosi_sat_i16f64( __lccrt_f64_t x) +{ + __lccrt_f64_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, -32768); + y = __LCCRT_MIN( y, +32767); + + return (y); +} /* __lccrt_fptosi_sat_i16f64 */ + +int16_t +__lccrt_fptosi_sat_i16f80( __lccrt_f80_t x) +{ + __lccrt_f80_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, -32768); + y = __LCCRT_MIN( y, +32767); + + return (y); +} /* __lccrt_fptosi_sat_i16f80 */ + +int32_t +__lccrt_fptosi_sat_i32f32( __lccrt_f32_t x) +{ + int32_t r = 0; + + if ( isnan( x) ) + { + } else if ( x < __lccrt_f32smin32.f ) + { + r = 0x80000000ULL; + + } else if ( x > __lccrt_f32smax32.f ) + { + r = 0x7fffffffULL; + } else + { + r = x; + } + + return (r); + +} /* __lccrt_fptosi_sat_i32f32 */ + +int32_t +__lccrt_fptosi_sat_i32f64( __lccrt_f64_t x) +{ + __lccrt_f64_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, -2147483648); + y = __LCCRT_MIN( y, +2147483647); + + return (y); +} /* __lccrt_fptosi_sat_i32f64 */ + +int32_t +__lccrt_fptosi_sat_i32f80( __lccrt_f80_t x) +{ + __lccrt_f80_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, -2147483648); + y = __LCCRT_MIN( y, +2147483647); + + return (y); +} /* __lccrt_fptosi_sat_i32f80 */ + +int64_t +__lccrt_fptosi_sat_i64f32( __lccrt_f32_t x) +{ + int64_t r = 0; + + if ( isnan( x) ) + { + } else if ( x < __lccrt_f32smin64.f ) + { + r = 0x8000000000000000ULL; + + } else if ( x > __lccrt_f32smax64.f ) + { + r = 0x7fffffffffffffffULL; + } else + { + r = x; + } + + return (r); +} /* __lccrt_fptosi_sat_i64f32 */ + +int64_t +__lccrt_fptosi_sat_i64f64( __lccrt_f64_t x) +{ + int64_t r = 0; + + if ( isnan( x) ) + { + } else if ( x <= __lccrt_f64smin64.f ) + { + r = 0x8000000000000000ULL; + + } else if ( x >= __lccrt_f64smax64.f ) + { + r = 0x7fffffffffffffffULL; + } else + { + r = x; + } + + return (r); +} /* __lccrt_fptosi_sat_i64f64 */ + +__lccrt_uint128_t +__lccrt_fptosi_sat_i128f32( __lccrt_f32_t x) +{ + __lccrt_uint128_t r = {0}; + + if ( isnan( x) ) + { + } else if ( x <= __lccrt_f32smin128.f ) + { + r.hi = 0x8000000000000000ULL; + r.lo = 0; + + } else if ( x >= __lccrt_f32smax128.f ) + { + r.hi = 0x7fffffffffffffffULL; + r.lo = 0xffffffffffffffffULL; + } else + { + __int128 a = x; + + r.lo = a; + r.hi = a >> 64ULL; + } + + return (r); +} /* __lccrt_fptosi_sat_i128f32 */ + +__lccrt_uint128_t +__lccrt_fptosi_sat_i128f64( __lccrt_f64_t x) +{ + __lccrt_uint128_t r = {0}; + + if ( isnan( x) ) + { + } else if ( x <= __lccrt_f64smin128.f ) + { + r.hi = 0x8000000000000000ULL; + r.lo = 0; + + } else if ( x >= __lccrt_f64smax128.f ) + { + r.hi = 0x7fffffffffffffffULL; + r.lo = 0xffffffffffffffffULL; + } else + { + __int128 a = x; + + r.lo = a; + r.hi = a >> 64ULL; + } + + return (r); +} /* __lccrt_fptosi_sat_i128f64 */ + +//int64_t __lccrt_fptosi_sat_i64f80( __lccrt_f80_t); + +uint8_t +__lccrt_fptoui_sat_i8f32( __lccrt_f32_t x) +{ + __lccrt_f32_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, 0); + y = __LCCRT_MIN( y, +255); + + return (y); +} /* __lccrt_fptosi_sat_i8f32 */ + +uint8_t +__lccrt_fptoui_sat_i8f64( __lccrt_f64_t x) +{ + __lccrt_f64_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, 0); + y = __LCCRT_MIN( y, +255); + + return (y); +} /* __lccrt_fptosi_sat_i8f64 */ + +uint8_t +__lccrt_fptoui_sat_i8f80( __lccrt_f80_t x) +{ + __lccrt_f80_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, 0); + y = __LCCRT_MIN( y, +255); + + return (y); +} /* __lccrt_fptosi_sat_i8f80 */ + +uint16_t +__lccrt_fptoui_sat_i16f32( __lccrt_f32_t x) +{ + __lccrt_f32_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, 0); + y = __LCCRT_MIN( y, +65535); + + return (y); +} /* __lccrt_fptosi_sat_i16f32 */ + +uint16_t +__lccrt_fptoui_sat_i16f64( __lccrt_f64_t x) +{ + __lccrt_f64_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, 0); + y = __LCCRT_MIN( y, +65535); + + return (y); +} /* __lccrt_fptosi_sat_i16f64 */ + +uint16_t +__lccrt_fptoui_sat_i16f80( __lccrt_f80_t x) +{ + __lccrt_f80_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, 0); + y = __LCCRT_MIN( y, +65535); + + return (y); +} /* __lccrt_fptosi_sat_i16f80 */ + +uint32_t +__lccrt_fptoui_sat_i32f32( __lccrt_f32_t x) +{ + uint32_t r = 0; + + if ( isnan( x) + || (x <= 0) ) + { + r = 0; + + } else if ( x > __lccrt_f32umax32.f ) + { + r = 0xffffffffULL; + } else + { + r = x; + } + + return (r); +} /* __lccrt_fptoui_sat_i32f32 */ + +uint32_t +__lccrt_fptoui_sat_i32f64( __lccrt_f64_t x) +{ + __lccrt_f64_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, 0); + y = __LCCRT_MIN( y, +4294967295); + + return (y); +} /* __lccrt_fptoui_sat_i32f64 */ + +uint32_t +__lccrt_fptoui_sat_i32f80( __lccrt_f80_t x) +{ + __lccrt_f80_t y = isnan( x) ? 0 : x; + y = __LCCRT_MAX( y, 0); + y = __LCCRT_MIN( y, +4294967295); + + return (y); +} /* __lccrt_fptoui_sat_i32f80 */ + +uint64_t +__lccrt_fptoui_sat_i64f32( __lccrt_f32_t x) +{ + uint64_t r = 0; + + if ( isnan( x) + || (x <= 0) ) + { + r = 0; + + } else if ( x > __lccrt_f32umax64.f ) + { + r = 0xffffffffffffffffULL; + } else + { + r = x; + } + + return (r); +} /* __lccrt_fptoui_sat_i64f32 */ + +uint64_t +__lccrt_fptoui_sat_i64f64( __lccrt_f64_t x) +{ + uint64_t r = 0; + + if ( isnan( x) + || (x <= 0) ) + { + r = 0; + + } else if ( x > __lccrt_f64umax64.f ) + { + r = 0xffffffffffffffffULL; + } else + { + r = x; + } + + return (r); +} /* __lccrt_fptoui_sat_i64f64 */ + +//uint64_t __lccrt_fptoui_sat_i64f80( __lccrt_f80_t); + +__lccrt_uint128_t +__lccrt_fptoui_sat_i128f32( __lccrt_f32_t x) +{ + __lccrt_uint128_t r = {0}; + + if ( isnan( x) ) + { + } else if ( x <= 0 ) + { + r.hi = 0; + r.lo = 0; + + } else if ( x > __lccrt_f32umax128.f ) + { + r.hi = 0xffffffffffffffffULL; + r.lo = 0xffffffffffffffffULL; + } else + { + __int128 a = x; + + r.lo = a; + r.hi = a >> 64ULL; + } + + return (r); +} /* __lccrt_fptoui_sat_i128f32 */ + +__lccrt_uint128_t +__lccrt_fptoui_sat_i128f64( __lccrt_f64_t x) +{ + __lccrt_uint128_t r = {0}; + + if ( isnan( x) ) + { + } else if ( x <= 0 ) + { + r.hi = 0; + r.lo = 0; + + } else if ( x > __lccrt_f64umax128.f ) + { + r.hi = 0xffffffffffffffffULL; + r.lo = 0xffffffffffffffffULL; + } else + { + __int128 a = x; + + r.lo = a; + r.hi = a >> 64ULL; + } + + return (r); +} /* __lccrt_fptoui_sat_i128f64 */ + +__lccrt_nint96_t +__lccrt_fshl_i96( __lccrt_nint96_t a, __lccrt_nint96_t b, __lccrt_nint96_t c) +{ + int i; + __lccrt_nint96_t d; + int s = c.a[0] % 96; + int sl = s / 8; + int sm = s - 8*sl; + int l = 96 / 8; + + // Сдвигаем влево на целое количество байт. + for ( i = l - 1; i >= 0; --i ) + { + d.a[i] = (i >= sl) ? a.a[i - sl] : b.a[l - sl + i]; + } + + // Досдвигаем влево на битовый остаток. + if ( sm > 0 ) + { + uint8_t tm = 8 - sm; + uint8_t f = b.a[l - sl - 1] >> tm; + + for ( i = 0; i < l; ++i ) + { + uint8_t g = d.a[i]; + + d.a[i] = (g << sm) | f; + f = g >> tm; + } + } + + return (d); +} /* __lccrt_fshl_i96 */ diff --git a/tools/lccrt_s/src/lccrt_vec.c b/tools/lccrt_s/src/lccrt_vec.c new file mode 100644 index 0000000..8c4da0e --- /dev/null +++ b/tools/lccrt_s/src/lccrt_vec.c @@ -0,0 +1,103 @@ +/** + * 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 + */ + +#include "lccrt_s.h" + +#include +#include +#include + +#define __lccrt_shuffle_get( n, k, x, y) (((k) < (n)) ? (x).a[k] : (y).a[(k) - (n)]) + +#define __lccopt_vec_shuffle( suffix, arg_type, ind_type, len) \ +arg_type \ +__lccopt_shuffle_##suffix( arg_type x, arg_type y, ind_type c) \ +{ \ + int i; \ + arg_type r; \ +\ + for ( i = 0; i < len; ++i ) \ + { \ + r.a[i] = __lccrt_shuffle_get( len, c.a[i], x, y); \ + } \ +\ + return (r); \ +} /* __builtin_lccopt_shuffle_##suffix */ + +__lccopt_vec_shuffle( v16i8, __lccrt_vec_si( 8, 16), __lccrt_vec_si( 32, 16), 16) +__lccopt_vec_shuffle( v8i16, __lccrt_vec_si( 16, 8), __lccrt_vec_si( 32, 8), 8) +__lccopt_vec_shuffle( v4i32, __lccrt_vec_si( 32, 4), __lccrt_vec_si( 32, 4), 4) +__lccopt_vec_shuffle( v2i64, __lccrt_vec_si( 64, 2), __lccrt_vec_si( 32, 2), 2) + +__lccopt_vec_shuffle( v32i8, __lccrt_vec_si( 8, 32), __lccrt_vec_si( 32, 32), 32) +__lccopt_vec_shuffle( v16i16, __lccrt_vec_si( 16, 16), __lccrt_vec_si( 32, 16), 16) +__lccopt_vec_shuffle( v8i32, __lccrt_vec_si( 32, 8), __lccrt_vec_si( 32, 8), 8) +__lccopt_vec_shuffle( v4i64, __lccrt_vec_si( 64, 4), __lccrt_vec_si( 32, 4), 4) + +__lccopt_vec_shuffle( v4f32, __lccrt_vec_f( 32, 4), __lccrt_vec_si( 32, 4), 4) +__lccopt_vec_shuffle( v2f64, __lccrt_vec_f( 64, 2), __lccrt_vec_si( 32, 2), 2) + +__lccopt_vec_shuffle( v8f32, __lccrt_vec_f( 32, 8), __lccrt_vec_si( 32, 8), 8) +__lccopt_vec_shuffle( v4f64, __lccrt_vec_f( 64, 4), __lccrt_vec_si( 32, 4), 4) + +__lccrt_vec_si( 32, 4) +__lccrt_mul_v4i32( __lccrt_vec_si( 32, 4) a, __lccrt_vec_si( 32, 4) b) +{ + int i; + __lccrt_vec_si( 32, 4) r; + + for ( i = 0; i < 4; ++i ) r.a[i] = a.a[i] * b.a[i]; + + return (r); +} + +__lccrt_vec_f( 32, 4) +__lccrt_fdiv_v4f32( __lccrt_vec_f( 32, 4) a, __lccrt_vec_f( 32, 4) b) +{ + int i; + __lccrt_vec_f( 32, 4) r; + + for ( i = 0; i < 4; ++i ) r.a[i] = a.a[i] / b.a[i]; + + return (r); +} + +__lccrt_vec_si( 32, 4) +__lccrt_select_v4i32_t( __lccrt_vec_si( 32, 4) a, + __lccrt_vec_si( 32, 4) b, + __lccrt_vec_si( 32, 4) c) +{ + int i; + __lccrt_vec_si( 32, 4) r; + + for ( i = 0; i < 4; ++i ) r.a[i] = a.a[i] ? b.a[i] : c.a[i]; + + return (r); +} + +__lccrt_vec_f( 32, 4) +__lccrt_select_v4f32_t( __lccrt_vec_si( 32, 4) a, + __lccrt_vec_f( 32, 4) b, + __lccrt_vec_f( 32, 4) c) +{ + int i; + __lccrt_vec_f( 32, 4) r; + + for ( i = 0; i < 4; ++i ) r.a[i] = a.a[i] ? b.a[i] : c.a[i]; + + return (r); +} + +__lccrt_vec_f( 32, 4) +__lccrt_sqrt_v4f32( __lccrt_vec_f( 32, 4) a) +{ + int i; + __lccrt_vec_f( 32, 4) r; + + for ( i = 0; i < 4; ++i ) r.a[i] = __builtin_sqrtf( a.a[i]); + + return (r); +}