diff --git a/CMakeLists.txt b/CMakeLists.txt index d1d52ab..7dc03b4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,21 +5,14 @@ project(Ravi VERSION 1.0.4 LANGUAGES C CXX) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") option(LLVM_JIT "Controls whether LLVM JIT compilation will be enabled, default is OFF" OFF) -option(OMR_JIT "Controls whether NanoJIT compilation will be enabled, default is OFF" OFF) option(NO_JIT "Controls whether JIT should be disabled, default is OFF" OFF) option(STATIC_BUILD "Build static version of Ravi, default is OFF" OFF) option(COMPUTED_GOTO "Controls whether the interpreter switch will use computed gotos on gcc/clang, default is ON" ON) option(LTESTS "Controls whether ltests are enabled in Debug mode; note requires Debug build" ON) -if (LLVM_JIT AND OMR_JIT) - message(FATAL_ERROR - "LLVM_JIT and OMR_JIT cannot be set to ON at the same time") -endif () - # By default on X86_64 non-Windows platforms we enable MIR JIT if (NOT WIN32 AND NOT LLVM_JIT - AND NOT OMR_JIT AND NOT NO_JIT AND CMAKE_SYSTEM_PROCESSOR MATCHES "(x86)|(X86)|(amd64)|(AMD64)") set(MIR_JIT ON) @@ -33,7 +26,6 @@ if (MIR_JIT) message(FATAL_ERROR "MIR_JIT is only supported on X86-64 platforms") endif () set(LLVM_JIT OFF) - set(OMR_JIT OFF) set(STATIC_BUILD OFF) # Because we need to expose the symbols in the library endif () @@ -72,24 +64,9 @@ set(MIR_HEADERS mir/mir.h mir/mir-gen.h mir/mir-varr.h mir/mir-dlist.h mir/mir-h mir/mir-hash.h mir/mir-bitmap.h) set(MIR_SRCS mir/mir.c mir/mir-gen.c) set(C2MIR_SRCS mir/c2mir/c2mir.c) -# OMR code gen -set(OMR_JIT_SRCS src/ravi_omrjit.c src/ravi_omrjitapi.c) # MIR code gen set(MIR_JIT_SRCS src/ravi_mirjit.c) set(NO_JIT_SRCS src/ravi_nojit.c) -# Common stuff we need even if we don't use dmrC. -set(DMR_C_HEADERS_COMMON dmr_c/src/allocate.h dmr_c/src/port.h dmr_c/src/ptrlist.h) -set(DMR_C_SRCS_COMMON dmr_c/src/allocate.c dmr_c/src/ptrlist.c) -# dmrC Optional sources -set(RAVI_C_SYMBOL_PARSER src/ravi_dmrc_parsesymbols.c) -set(DMR_C_SRCS_OPT dmr_c/src/builtin.c dmr_c/src/char.c dmr_c/src/expression.c dmr_c/src/evaluate.c - dmr_c/src/expand.c dmr_c/src/inline.c dmr_c/src/lib.c dmr_c/src/linearize.c - dmr_c/src/liveness.c dmr_c/src/parse.c dmr_c/src/target.c dmr_c/src/tokenize.c - dmr_c/src/pre-process.c dmr_c/src/scope.c dmr_c/src/show-parse.c dmr_c/src/symbol.c - dmr_c/src/walksymbol.c) -set(DMR_C_HEADERS_OPT dmr_c/src/char.h dmr_c/src/expression.h dmr_c/src/flow.h dmr_c/src/ident-list.h - dmr_c/src/linearize.h dmr_c/src/lib.h dmr_c/src/parse.h dmr_c/src/scope.h dmr_c/src/symbol.h - dmr_c/src/target.h dmr_c/src/token.h dmr_c/src/walksymbol.h) set(LUA_CMD_SRCS src/lua.c) file(GLOB RAVI_HEADERS "${PROJECT_SOURCE_DIR}/include/*.h") @@ -116,7 +93,6 @@ if (COMPILER_OPT_NO_STACK_PROTECTOR_SUPPORTED AND NOT CMAKE_C_FLAGS MATCHES "-fn endif() -set(EMBEDDED_DMRC ON) if (LLVM_JIT) find_package(LLVM REQUIRED CONFIG) message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") @@ -135,63 +111,12 @@ if (LLVM_JIT) APPEND PROPERTY INCLUDE_DIRECTORIES ${LLVM_INCLUDE_DIRS} ) - set(DMR_C_JIT_SRCS - dmr_c/llvm-backend/sparse-llvm.c - ) - set(DMR_C_JIT_HEADERS - dmr_c/llvm-backend/dmr_c.h - ) - set(DMR_C_HEADERS ${DMR_C_HEADERS_OPT} ${DMR_C_HEADERS_COMMON}) - set(DMR_C_SRCS ${DMR_C_SRCS_OPT} ${DMR_C_SRCS_COMMON} ${RAVI_C_SYMBOL_PARSER}) - - set_property(SOURCE ${DMR_C_JIT_SRCS} src/ravi_llvmcodegen.cpp ${RAVI_C_SYMBOL_PARSER} - APPEND - PROPERTY INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/dmr_c/llvm-backend") - set_property(SOURCE ${DMR_C_SRCS} ${DMR_C_JIT_SRCS} - APPEND - PROPERTY INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/dmr_c/src") - set_property( - SOURCE ${RAVI_C_SYMBOL_PARSER} ${DMR_C_JIT_SRCS} - APPEND - PROPERTY INCLUDE_DIRECTORIES ${LLVM_INCLUDE_DIRS}) # FIXME get rid of this dependency set_property( SOURCE ${LUA_CMD_SRCS} APPEND PROPERTY INCLUDE_DIRECTORIES ${LLVM_INCLUDE_DIRS}) -elseif (OMR_JIT) - find_package(OMRJIT REQUIRED) - message(STATUS "OMRJIT enabled") - set(JIT_SRCS ${OMR_JIT_SRCS}) - set(DMR_C_JIT_SRCS - dmr_c/omrjit-backend/sparse-omrjit.c - ) - set(DMR_C_JIT_HEADERS - dmr_c/omrjit-backend/dmr_c.h - ) - set(DMR_C_HEADERS ${DMR_C_HEADERS_OPT} ${DMR_C_HEADERS_COMMON}) - set(DMR_C_SRCS ${DMR_C_SRCS_OPT} ${DMR_C_SRCS_COMMON} ${RAVI_C_SYMBOL_PARSER}) - - set_property(SOURCE ${DMR_C_JIT_SRCS} ${RAVI_C_SYMBOL_PARSER} ${OMR_JIT_SRCS} - APPEND - PROPERTY INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/dmr_c/omrjit-backend") - set_property(SOURCE ${DMR_C_SRCS} ${DMR_C_JIT_SRCS} - APPEND - PROPERTY INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/dmr_c/src") - set_property(SOURCE ${DMR_C_JIT_SRCS} ${OMR_JIT_SRCS} ${RAVI_C_SYMBOL_PARSER} - APPEND - PROPERTY INCLUDE_DIRECTORIES "${OMRJIT_INCLUDE_DIRS}" - ) else () - # Omit all dmrC stuff except for what we need for the parser - set(DMR_C_HEADERS ${DMR_C_HEADERS_COMMON}) - set(DMR_C_SRCS ${DMR_C_SRCS_COMMON}) - set(EMBEDDED_DMRC OFF) - - set_property(SOURCE ${DMR_C_SRCS_COMMON} - APPEND - PROPERTY INCLUDE_DIRECTORIES "${PROJECT_SOURCE_DIR}/dmr_c/src") - if (MIR_JIT) message(STATUS "MIRJIT enabled") set(JIT_SRCS ${MIR_SRCS} ${C2MIR_SRCS} ${MIR_JIT_SRCS}) @@ -206,23 +131,8 @@ else () endif () endif () -# Additional stuff for dmrC -if (CMAKE_COMPILER_IS_GNUCC AND EMBEDDED_DMRC) - execute_process(COMMAND ${CMAKE_C_COMPILER} --print-file-name= - OUTPUT_VARIABLE GCC_BASE OUTPUT_STRIP_TRAILING_WHITESPACE) - execute_process(COMMAND ${CMAKE_C_COMPILER} -print-multiarch - OUTPUT_VARIABLE MULTIARCH_TRIPLET ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) - - set_source_files_properties(dmr_c/src/lib.c PROPERTIES COMPILE_FLAGS "-DGCC_BASE=${GCC_BASE} -DMULTIARCH_TRIPLET=${MULTIARCH_TRIPLET}") - - message(STATUS "GCC_BASE_DIR : " ${GCC_BASE}) - message(STATUS "MULTIARCH_TRIPLET : " ${MULTIARCH_TRIPLET}) -endif () - # IDE stuff if (MSVC OR APPLE) - source_group("dmrC Headers" FILES ${DMR_C_HEADERS} ${DMR_C_JIT_HEADERS}) - source_group("dmrC Source Files" FILES ${DMR_C_SRCS} ${DMR_C_JIT_SRCS}) source_group("Ravi Headers" FILES ${RAVI_HEADERS}) source_group("Ravi Source Files" FILES ${LUA_CORE_SRCS} ${LUA_LIB_SRCS} ${JIT_SRCS}) endif () @@ -303,11 +213,8 @@ add_library(${LIBRAVI_NAME} ${LIBRAVI_BUILD_TYPE} ${RAVI_HEADERS} ${LUA_LIB_SRCS} ${LUA_CORE_SRCS} - ${JIT_SRCS} - ${DMR_C_HEADERS} - ${DMR_C_SRCS} - ${DMR_C_JIT_SRCS}) -target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${OMRJIT_LIBRARIES} ${MIRJIT_LIBRARIES}) + ${JIT_SRCS}) +target_link_libraries(${LIBRAVI_NAME} ${EXTRA_LIBRARIES} ${LLVM_LIBS} ${MIRJIT_LIBRARIES}) # Main Ravi executable add_executable(ravi ${LUA_CMD_SRCS}) @@ -318,9 +225,6 @@ set(NOJIT_RAVI_SRCS ${RAVI_HEADERS} ${LUA_LIB_SRCS} ${LUA_CORE_SRCS} - ${DMR_C_HEADERS} - ${DMR_C_SRCS} - ${DMR_C_JIT_SRCS} ${NO_JIT_SRCS}) set(RAVI_STATICEXEC_TARGET ravi_s) @@ -353,12 +257,6 @@ if (LLVM_JIT) APPEND PROPERTY COMPILE_DEFINITIONS "USE_LLVM=1") set(USE_LLVM 1) -elseif (OMR_JIT) - set_property( - TARGET ${LIBRAVI_NAME} ravi - APPEND - PROPERTY COMPILE_DEFINITIONS "USE_OMRJIT=1") - set(USE_OMRJIT 1) elseif (MIR_JIT) set_property( TARGET ${LIBRAVI_NAME} ravi @@ -379,12 +277,6 @@ if (NOT STATIC_BUILD) else () set_target_properties(${LIBRAVI_NAME} PROPERTIES PREFIX "") endif () -if (EMBEDDED_DMRC) - set_property( - TARGET ${LIBRAVI_NAME} ravi - APPEND - PROPERTY COMPILE_DEFINITIONS "USE_DMR_C=1") -endif () if (APPLE) set_property( TARGET ${LIBRAVI_NAME} libravinojit_static diff --git a/README.rst b/README.rst index 28e4b5a..b52a869 100644 --- a/README.rst +++ b/README.rst @@ -5,8 +5,8 @@ Ravi Programming Language :target: https://travis-ci.org/dibyendumajumdar/ravi Ravi is a derivative/dialect of `Lua 5.3 `_ with limited optional static typing and -features `MIR `_, `LLVM `_ and `Eclipse OMR `_ -powered JIT compilers. The name Ravi comes from the Sanskrit word for the Sun. +features `MIR `_ and `LLVM `_ powered JIT compilers. +The name Ravi comes from the Sanskrit word for the Sun. Interestingly a precursor to Lua was `Sol `_ which had support for static types; Sol means the Sun in Portugese. @@ -35,14 +35,12 @@ Features * Compatibility with Lua 5.3 (see Compatibility section below) * New! JIT backend `MIR `_; only Linux and x86-64 supported for now. * `LLVM `_ powered JIT compiler -* `Eclipse OMR `_ powered JIT compiler * A `distribution with batteries `_. Documentation ============= * For the Lua extensions in Ravi see the `Reference Manual `_. * `MIR JIT Build instructions `_. -* `OMR JIT Build instructions `_. * `LLVM JIT Build instructions `_. * Also see `Ravi Documentation `_. * and the slides I presented at the `Lua 2015 Workshop `_. @@ -90,10 +88,10 @@ History * 2016 - Implemented debugger for Ravi and Lua 5.3 for `Visual Studio Code `_ * 2017 - - Embedded C compiler using dmrC project (C JIT compiler) + - Embedded C compiler using dmrC project (C JIT compiler) (now discontinued) - Additional type-annotations * 2018 - - Implemented Eclipse OMR JIT backend + - Implemented Eclipse OMR JIT backend (now discontinued) - Created `Ravi with batteries `_. * 2019 - New language feature - `defer` statement diff --git a/dmr_c/.clang-format b/dmr_c/.clang-format deleted file mode 100644 index 04bafc9..0000000 --- a/dmr_c/.clang-format +++ /dev/null @@ -1,7 +0,0 @@ -BasedOnStyle: LLVM -IndentWidth: 8 -UseTab: Always -BreakBeforeBraces: Linux -AllowShortIfStatementsOnASingleLine: false -IndentCaseLabels: false -ColumnLimit: 120 \ No newline at end of file diff --git a/dmr_c/README.md b/dmr_c/README.md deleted file mode 100644 index 5e32972..0000000 --- a/dmr_c/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# dmr_C is a C Parser and JIT compiler - -Ravi includes a copy of the [dmr_C](https://github.com/dibyendumajumdar/dmr_c) project. See the project for more details regarding dmr_C. - -## Goals - -* Use dmr_C to translate code to JIT backend such as OMR JIT, NanoJIT or LLVM. -* Expose dmr_C features such as C parser, and compiler to users so that they can also compile chunks of C code when necessary diff --git a/dmr_c/llvm-backend/dmr_c.h b/dmr_c/llvm-backend/dmr_c.h deleted file mode 100644 index e483731..0000000 --- a/dmr_c/llvm-backend/dmr_c.h +++ /dev/null @@ -1,44 +0,0 @@ -/** - * This is a backend code generator for dmr_C that uses - * the LLVM JIT engine. - * - * Copyright (C) 2017 Dibyendu Majumdar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef DMR_C_H -#define DMR_C_H - -#include - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -extern bool dmrC_llvmcompile(int argc, char **argv, LLVMModuleRef module, - const char *inputbuffer); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/dmr_c/llvm-backend/sparse-llvm.c b/dmr_c/llvm-backend/sparse-llvm.c deleted file mode 100644 index 074b54f..0000000 --- a/dmr_c/llvm-backend/sparse-llvm.c +++ /dev/null @@ -1,2095 +0,0 @@ -/** -* Sparse LLVM backend -* -* Original copyrights: Pekka Enberg and Jeff Garzik (https://lwn.net/Articles/456709/) -* Additional copyrights: Dibyendu Majumdar and Luc Van Oostenryck -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -struct function { - LLVMBuilderRef builder; - LLVMTypeRef type; - LLVMValueRef fn; - LLVMModuleRef module; - LLVMTypeRef return_type; -}; - -static LLVMTypeRef type_to_llvmtype(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym, struct symbol *sym_node); -static LLVMValueRef constant_value(struct dmr_C *C, LLVMModuleRef module, unsigned long long val, LLVMTypeRef dtype); - -static const char *get_llvmtypekind_name(LLVMTypeKind kind) { - switch (kind) { - case LLVMVoidTypeKind: return "VoidType"; /**< type with no size */ - case LLVMHalfTypeKind: return "HalfFloatType"; /**< 16 bit floating point type */ - case LLVMFloatTypeKind: return "FloatType"; /**< 32 bit floating point type */ - case LLVMDoubleTypeKind: return "DoubleType"; /**< 64 bit floating point type */ - case LLVMX86_FP80TypeKind: return "LongDoubleType"; /**< 80 bit floating point type (X87) */ - case LLVMFP128TypeKind: return "128BitDoubleType"; /**< 128 bit floating point type (112-bit mantissa)*/ - case LLVMPPC_FP128TypeKind: return "128BitPPCDoubleType"; /**< 128 bit floating point type (two 64-bits) */ - case LLVMLabelTypeKind: return "LabelType"; /**< Labels */ - case LLVMIntegerTypeKind: return "IntegerType"; /**< Arbitrary bit width integers */ - case LLVMFunctionTypeKind: return "FunctionType"; /**< Functions */ - case LLVMStructTypeKind: return "StructType"; /**< Structures */ - case LLVMArrayTypeKind: return "ArrayType"; /**< Arrays */ - case LLVMPointerTypeKind: return "PointerType"; /**< Pointers */ - case LLVMVectorTypeKind: return "VectorType"; /**< SIMD 'packed' format, or other vector type */ - case LLVMMetadataTypeKind: return "MetadataType"; /**< Metadata */ - case LLVMX86_MMXTypeKind: return "MMXType"; /**< X86 MMX */ - case LLVMTokenTypeKind: return "TokenType"; /**< Tokens */ - default: assert(0); - } - return ""; -} - -static LLVMTypeRef get_symnode_type(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym) -{ - assert(sym->type == SYM_NODE); - return type_to_llvmtype(C, module, sym->ctype.base_type, sym); -} - -static LLVMTypeRef get_symnode_or_basetype(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym) -{ - if (sym->type == SYM_NODE) { - assert(sym->ctype.base_type->type != SYM_NODE); - return type_to_llvmtype(C, module, sym->ctype.base_type, sym); - } - return type_to_llvmtype(C, module, sym, NULL); -} - - -static LLVMTypeRef func_return_type(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym, struct symbol *sym_node) -{ - return type_to_llvmtype(C, module, sym->ctype.base_type, sym_node); -} - -static LLVMTypeRef sym_func_type(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym, struct symbol *sym_node) -{ - LLVMTypeRef *arg_type; - LLVMTypeRef func_type; - LLVMTypeRef ret_type; - struct symbol *arg; - int n_arg = 0; - - /* to avoid strangeness with varargs [for now], we build - * the function and type anew, for each call. This - * is probably wrong. We should look up the - * symbol declaration info. - */ - - ret_type = func_return_type(C, module, sym, sym_node); - if (!ret_type) - return NULL; - - /* count args, build argument type information */ - FOR_EACH_PTR(sym->arguments, arg) { - n_arg++; - } END_FOR_EACH_PTR(arg); - - arg_type = alloca(n_arg * sizeof(LLVMTypeRef)); - - int idx = 0; - FOR_EACH_PTR(sym->arguments, arg) { - struct symbol *arg_sym = arg; - - arg_type[idx] = get_symnode_type(C, module, arg_sym); - if (!arg_type[idx]) - return NULL; - idx++; - } END_FOR_EACH_PTR(arg); - func_type = LLVMFunctionType(ret_type, arg_type, n_arg, - sym->variadic); - - return func_type; -} - -static LLVMTypeRef sym_array_type(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym, struct symbol *sym_node) -{ - LLVMTypeRef elem_type; - struct symbol *base_type; - - base_type = sym->ctype.base_type; - /* empty struct is undefined [6.7.2.1(8)] */ - unsigned int array_bit_size = sym->bit_size; - if (array_bit_size == 0 || (int)array_bit_size == -1) { - if (sym_node != NULL) - array_bit_size = sym_node->bit_size; - } - if (base_type->bit_size == 0 || base_type->bit_size == -1 || array_bit_size == 0 || (int)array_bit_size == -1) { - fprintf(stderr, "array size can not be determined\n"); - return NULL; - } - elem_type = type_to_llvmtype(C, module, base_type, sym_node); - if (!elem_type) - return NULL; - - return LLVMArrayType(elem_type, array_bit_size / base_type->bit_size); -} - -#define MAX_STRUCT_MEMBERS 256 - -static LLVMTypeRef sym_struct_type(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym, struct symbol *sym_node) -{ - LLVMTypeRef elem_types[MAX_STRUCT_MEMBERS]; - struct symbol *member; - char buffer[256]; - LLVMTypeRef ret; - unsigned nr = 0; - (void)sym_node; - snprintf(buffer, sizeof(buffer), "struct.%s", sym->ident ? sym->ident->name : "anno"); - ret = LLVMStructCreateNamed(LLVMGetModuleContext(module), buffer); - /* set ->aux to avoid recursion */ - sym->aux = ret; - - FOR_EACH_PTR(sym->symbol_list, member) { - LLVMTypeRef member_type; - - if (nr >= MAX_STRUCT_MEMBERS) { - // TODO error message - return NULL; - } - - member_type = get_symnode_type(C, module, member); - if (!member_type) - return NULL; - - elem_types[nr++] = member_type; - } END_FOR_EACH_PTR(member); - - LLVMStructSetBody(ret, elem_types, nr, 0 /* packed? */); - return ret; -} - -static LLVMTypeRef sym_union_type(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym, struct symbol *sym_node) -{ - LLVMTypeRef elem_types[1]; - char buffer[256]; - LLVMTypeRef type; - (void)C; (void)sym_node; - snprintf(buffer, sizeof(buffer), "union.%s", sym->ident ? sym->ident->name : "anno"); - type = LLVMStructCreateNamed(LLVMGetModuleContext(module), buffer); - /* set ->aux to avoid recursion */ - sym->aux = type; - - unsigned union_size; - - if (sym->bit_size > 0 && sym->bit_size != -1) { - /* - * There's no union support in the LLVM API so we treat unions as - * opaque structs. The downside is that we lose type information on the - * members but as LLVM doesn't care, neither do we. - */ - union_size = sym->bit_size / 8; - if (union_size > 0) { - elem_types[0] = LLVMArrayType(LLVMInt8TypeInContext(LLVMGetModuleContext(module)), union_size); - - LLVMStructSetBody(type, elem_types, 1, 0 /* packed? */); - } - } - return type; -} - -static LLVMTypeRef sym_ptr_type(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym, struct symbol *sym_node) -{ - LLVMTypeRef type; - - /* 'void *' is treated like 'char *' */ - if (dmrC_is_void_type(C->S, sym->ctype.base_type)) - type = LLVMInt8TypeInContext(LLVMGetModuleContext(module)); - else { - type = type_to_llvmtype(C, module, sym->ctype.base_type, sym_node); - if (!type) - return NULL; - } - return LLVMPointerType(type, 0); -} - -static LLVMTypeRef int_type_by_size(LLVMModuleRef module, int size) -{ - LLVMTypeRef ret = NULL; - switch (size) { - case 1: - ret = LLVMInt1TypeInContext(LLVMGetModuleContext(module)); - break; - case 8: - ret = LLVMInt8TypeInContext(LLVMGetModuleContext(module)); - break; - case 16: - ret = LLVMInt16TypeInContext(LLVMGetModuleContext(module)); - break; - case 32: - ret = LLVMInt32TypeInContext(LLVMGetModuleContext(module)); - break; - case 64: - ret = LLVMInt64TypeInContext(LLVMGetModuleContext(module)); - break; - default: - fprintf(stderr, "invalid bit size %d\n", size); - } - return ret; -} - -static LLVMTypeRef sym_basetype_type(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym, struct symbol *sym_node) -{ - LLVMTypeRef ret = NULL; - (void)sym_node; - if (dmrC_is_float_type(C->S, sym)) { - switch (sym->bit_size) { - case 32: - ret = LLVMFloatTypeInContext(LLVMGetModuleContext(module)); - break; - case 64: - ret = LLVMDoubleTypeInContext(LLVMGetModuleContext(module)); - break; - case 80: - ret = LLVMX86FP80TypeInContext(LLVMGetModuleContext(module)); - break; - default: - fprintf(stderr, "invalid bit size %d for type %d\n", sym->bit_size, sym->type); - return NULL; - } - } - else { - if (sym->bit_size == -1) - ret = LLVMVoidTypeInContext(LLVMGetModuleContext(module)); - else - ret = int_type_by_size(module, sym->bit_size); - } - - return ret; -} - -static int is_aggregate_type(struct symbol *sym) -{ - if (sym->type == SYM_NODE) - return is_aggregate_type(sym->ctype.base_type); - switch (sym->type) { - case SYM_UNION: - case SYM_STRUCT: - case SYM_ARRAY: - return true; - default: - return false; - } -} - -static LLVMTypeRef type_to_llvmtype(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym, struct symbol *sym_node) -{ - LLVMTypeRef ret = NULL; - - assert(sym->type != SYM_NODE); - assert(sym_node == NULL || sym_node->type == SYM_NODE); - if (sym->aux) - return sym->aux; - - switch (sym->type) { - case SYM_BITFIELD: - ret = LLVMIntTypeInContext(LLVMGetModuleContext(module), sym->bit_size); - break; - case SYM_RESTRICT: - case SYM_ENUM: - ret = type_to_llvmtype(C, module, sym->ctype.base_type, sym_node); - break; - case SYM_BASETYPE: - ret = sym_basetype_type(C, module, sym, sym_node); - break; - case SYM_PTR: - ret = sym_ptr_type(C, module, sym, sym_node); - break; - case SYM_UNION: - ret = sym_union_type(C, module, sym, sym_node); - break; - case SYM_STRUCT: - ret = sym_struct_type(C, module, sym, sym_node); - break; - case SYM_ARRAY: - ret = sym_array_type(C, module, sym, sym_node); - break; - case SYM_FN: - ret = sym_func_type(C, module, sym, sym_node); - break; - default: - return NULL; - } - - /* cache the result */ - sym->aux = ret; - return ret; -} - -static LLVMTypeRef insn_symbol_type(struct dmr_C *C, LLVMModuleRef module, struct instruction *insn) -{ - if (insn->type) { - //printf("insn %s sym type %s\n", dmrC_show_instruction(C, insn), dmrC_get_type_name(insn->type->type)); - return get_symnode_or_basetype(C, module, insn->type); - } - LLVMTypeRef ret = int_type_by_size(module, insn->size); - if (!ret) { - dmrC_sparse_error(C, insn->pos, "invalid bit size %d", insn->size); - } - return ret; -} - -static LLVMLinkage data_linkage(struct dmr_C *C, struct symbol *sym) -{ - (void)C; - if (sym->ctype.modifiers & MOD_STATIC) - return LLVMPrivateLinkage; - return LLVMExternalLinkage; -} - -static LLVMLinkage function_linkage(struct dmr_C *C, struct symbol *sym) -{ - (void)C; - if (sym->ctype.modifiers & MOD_STATIC) - return LLVMInternalLinkage; - return LLVMExternalLinkage; -} - -static LLVMValueRef build_cast(struct dmr_C *C, struct function *fn, LLVMValueRef val, LLVMTypeRef dtype, const char *target_name, int unsigned_cast) -{ - LLVMTypeRef valtype = LLVMTypeOf(val); - LLVMTypeKind valkind = LLVMGetTypeKind(valtype); - LLVMTypeKind dkind = LLVMGetTypeKind(dtype); - LLVMOpcode op; - (void)C; - switch (dkind) { - case LLVMIntegerTypeKind: { - switch (valkind) { - case LLVMPointerTypeKind: - op = LLVMPtrToInt; - break; - case LLVMIntegerTypeKind: { - unsigned val_width = LLVMGetIntTypeWidth(valtype); - unsigned target_width = LLVMGetIntTypeWidth(dtype); - if (target_width < val_width) - op = LLVMTrunc; - else if (target_width == val_width) - op = LLVMBitCast; - else - op = unsigned_cast ? LLVMZExt : LLVMSExt; - break; - } - case LLVMFloatTypeKind: - case LLVMDoubleTypeKind: - op = LLVMFPToSI; - break; - default: - fprintf(stderr, "unsupported value type %s in cast to integer value\n", get_llvmtypekind_name(valkind)); - return NULL; - } - break; - } - case LLVMPointerTypeKind: { - switch (valkind) { - case LLVMPointerTypeKind: - op = LLVMBitCast; - break; - case LLVMIntegerTypeKind: - op = LLVMIntToPtr; - break; - default: - fprintf(stderr, "unsupported value type %s in cast to ptr\n", get_llvmtypekind_name(valkind)); - return NULL; - } - break; - } - case LLVMFloatTypeKind: - case LLVMDoubleTypeKind: { - switch (valkind) { - case LLVMIntegerTypeKind: - op = unsigned_cast ? LLVMUIToFP : LLVMSIToFP; - break; - case LLVMFloatTypeKind: { - if (dkind == LLVMFloatTypeKind) - op = LLVMBitCast; - else - op = LLVMFPExt; - break; - } - case LLVMDoubleTypeKind: { - if (dkind == LLVMFloatTypeKind) - op = LLVMFPTrunc; - else - op = LLVMBitCast; - break; - } - default: - fprintf(stderr, "unsupported value type %s in cast to floating point value\n", get_llvmtypekind_name(valkind)); - return NULL; - } - break; - } - default: - if (dkind == valkind) - op = LLVMBitCast; - else { - fprintf(stderr, "unsupported target type %s in cast from value kind %s\n", get_llvmtypekind_name(dkind), get_llvmtypekind_name(valkind)); - return NULL; - } - } - return LLVMBuildCast(fn->builder, op, val, dtype, target_name); -} - - -#define MAX_PSEUDO_NAME 64 - -static const char * pseudo_name(struct dmr_C *C, pseudo_t pseudo, char *buf, size_t len) -{ - (void)C; - buf[0] = '\0'; - switch (pseudo->type) { - case PSEUDO_REG: - snprintf(buf, len, "R%d", pseudo->nr); - break; - case PSEUDO_PHI: - snprintf(buf, len, "PHI%d", pseudo->nr); - break; - case PSEUDO_SYM: - case PSEUDO_VAL: - case PSEUDO_ARG: - case PSEUDO_VOID: - break; - default: - assert(0); - } - - return buf; -} - -static LLVMValueRef build_local(struct dmr_C *C, struct function *fn, struct symbol *sym) -{ - const char *name = dmrC_show_ident(C, sym->ident); - LLVMTypeRef type = get_symnode_type(C, fn->module, sym); - LLVMValueRef result; - char localname[256] = { 0 }; - snprintf(localname, sizeof localname, "%s_%p.", name, sym); - if (dmrC_is_static(sym) || dmrC_is_extern(sym) || dmrC_is_toplevel(sym)) { - result = LLVMGetNamedGlobal(fn->module, localname); - if (!result) { - result = LLVMAddGlobal(fn->module, type, localname); - if (!dmrC_is_extern(sym)) - LLVMSetLinkage(result, LLVMInternalLinkage); - else - LLVMSetLinkage(result, LLVMExternalLinkage); - } - } - else { - /* insert alloca into entry block */ - /* LLVM requires allocas to be at the start */ - LLVMBasicBlockRef entrybbr = LLVMGetEntryBasicBlock(fn->fn); - /* Use temporary Builder as we don't want to mess the function builder */ - LLVMBuilderRef tmp_builder = LLVMCreateBuilderInContext(LLVMGetModuleContext(fn->module)); - LLVMValueRef firstins = LLVMGetFirstInstruction(entrybbr); - if (firstins) - LLVMPositionBuilderBefore(tmp_builder, firstins); - else - LLVMPositionBuilderAtEnd(tmp_builder, entrybbr); - /* Since multiple locals may have same name but in different scopes we - append the symbol's address to make each variable unique */ - result = LLVMBuildAlloca(tmp_builder, type, localname); - if (sym->initialized && is_aggregate_type(sym)) { - LLVMValueRef memsetfunc = LLVMGetNamedFunction(fn->module, "llvm.memset.p0i8.i32"); - assert(memsetfunc); - LLVMValueRef resulti8 = LLVMBuildBitCast(fn->builder, result, LLVMPointerType(LLVMInt8TypeInContext(LLVMGetModuleContext(fn->module)), 0), LLVMGetValueName(result)); - LLVMValueRef args[5]; - args[0] = resulti8; - args[1] = LLVMConstInt(LLVMInt8TypeInContext(LLVMGetModuleContext(fn->module)), 0, 0); - args[2] = LLVMConstInt(LLVMInt32TypeInContext(LLVMGetModuleContext(fn->module)), sym->bit_size / C->target->bits_in_char, 0); - args[3] = LLVMConstInt(LLVMInt32TypeInContext(LLVMGetModuleContext(fn->module)), sym->ctype.alignment, 0); - args[4] = LLVMConstInt(LLVMInt1TypeInContext(LLVMGetModuleContext(fn->module)), 0, 0); - LLVMBuildCall(fn->builder, memsetfunc, args, 5, ""); - } - LLVMDisposeBuilder(tmp_builder); - } - sym->priv = result; - return result; -} - -static LLVMValueRef get_sym_value(struct dmr_C *C, struct function *fn, pseudo_t pseudo) -{ - LLVMValueRef result = NULL; - struct symbol *sym = pseudo->sym; - struct expression *expr; - - result = (LLVMValueRef)sym->priv; - if (result) - return result; - - assert(sym->bb_target == NULL); - - expr = sym->initializer; - if (expr && - (!sym->ident || - (sym->ident && (expr->type == EXPR_VALUE || expr->type == EXPR_FVALUE)))) { - switch (expr->type) { - case EXPR_STRING: { - const char *s = expr->string->data; - LLVMValueRef indices[] = { LLVMConstInt(LLVMInt64TypeInContext(LLVMGetModuleContext(fn->module)), 0, 0), - LLVMConstInt(LLVMInt64TypeInContext(LLVMGetModuleContext(fn->module)), 0, 0) }; - LLVMValueRef data; - - data = LLVMAddGlobal(fn->module, LLVMArrayType(LLVMInt8TypeInContext(LLVMGetModuleContext(fn->module)), strlen(s) + 1), ".str"); - LLVMSetLinkage(data, LLVMPrivateLinkage); - LLVMSetGlobalConstant(data, 1); - char *scopy = dmrC_allocator_allocate(&C->byte_allocator, strlen(s) + 1); - strcpy(scopy, s); - LLVMSetInitializer(data, LLVMConstStringInContext(LLVMGetModuleContext(fn->module), scopy, strlen(scopy) + 1, true)); - - result = LLVMConstGEP(data, indices, ARRAY_SIZE(indices)); - sym->priv = result; - break; - } - case EXPR_SYMBOL: { - dmrC_sparse_error(C, expr->pos, "unresolved symbol reference in initializer\n"); - dmrC_show_expression(C, expr); - return NULL; - break; - } - case EXPR_VALUE: { - LLVMTypeRef symtype = get_symnode_type(C, fn->module, sym); - if (symtype == NULL) { - dmrC_sparse_error(C, expr->pos, "invalid symbol type\n"); - dmrC_show_expression(C, expr); - return NULL; - } - result = build_local(C, fn, sym); - if (!result) - return result; - LLVMValueRef value = constant_value(C, fn->module, expr->value, symtype); - if (dmrC_is_static(sym)) - LLVMSetInitializer(result, value); - else - LLVMBuildStore(fn->builder, value, result); - sym->priv = result; - break; - } - case EXPR_FVALUE: { - LLVMTypeRef symtype = get_symnode_type(C, fn->module, sym); - if (symtype == NULL) { - dmrC_sparse_error(C, expr->pos, "invalid symbol type\n"); - dmrC_show_expression(C, expr); - return NULL; - } - result = build_local(C, fn, sym); - if (!result) - return result; - if (dmrC_is_static(sym)) - LLVMSetInitializer(result, LLVMConstReal(symtype, expr->fvalue)); - else - LLVMBuildStore(fn->builder, LLVMConstReal(symtype, expr->fvalue), result); - sym->priv = result; - break; - } - default: - dmrC_sparse_error(C, expr->pos, "unsupported expr type in initializer: %d\n", expr->type); - dmrC_show_expression(C, expr); - return NULL; - } - } - else { - const char *name = dmrC_show_ident(C, sym->ident); - LLVMTypeRef type = get_symnode_type(C, fn->module, sym); - if (LLVMGetTypeKind(type) == LLVMFunctionTypeKind) { - result = LLVMGetNamedFunction(fn->module, name); - if (!result) - result = LLVMAddFunction(fn->module, name, type); - sym->priv = result; - } - else if (dmrC_is_extern(sym) || dmrC_is_toplevel(sym)) { - result = LLVMGetNamedGlobal(fn->module, name); - if (!result) { - result = LLVMAddGlobal(fn->module, type, name); - if (dmrC_is_extern(sym)) - LLVMSetLinkage(result, LLVMExternalLinkage); - } - sym->priv = result; - } - else { - if (dmrC_is_static(sym) && sym->initializer) { - dmrC_sparse_error(C, sym->initializer->pos, "unsupported initializer for local static variable\n"); - dmrC_show_expression(C, sym->initializer); - return NULL; - } - result = build_local(C, fn, sym); - if (!result) - return result; - if (dmrC_is_static(sym)) { - LLVMSetInitializer(result, LLVMConstNull(type)); - } - sym->priv = result; - } - } - return result; -} - -static LLVMValueRef constant_value(struct dmr_C *C, LLVMModuleRef module, unsigned long long val, LLVMTypeRef dtype) -{ - LLVMTypeRef itype; - LLVMValueRef result; - - LLVMTypeKind kind = LLVMGetTypeKind(dtype); - switch (kind) { - case LLVMPointerTypeKind: - itype = LLVMIntTypeInContext(LLVMGetModuleContext(module), C->target->bits_in_pointer); - result = LLVMConstInt(itype, val, 0); - result = LLVMConstIntToPtr(result, dtype); - break; - case LLVMIntegerTypeKind: - result = LLVMConstInt(dtype, val, 0); - break; - case LLVMFloatTypeKind: - case LLVMDoubleTypeKind: - result = LLVMConstReal(dtype, (double)(long long)val); - break; - default: - fprintf(stderr, "unsupported pseudo value kind %s\n", get_llvmtypekind_name(kind)); - return NULL; - } - return result; -} - -static LLVMValueRef val_to_value(struct dmr_C *C, struct function *fn, unsigned long long val, struct symbol *ctype) -{ - LLVMTypeRef dtype; - - if (!ctype) - return NULL; - dtype = get_symnode_or_basetype(C, fn->module, ctype); - if (!dtype) - return NULL; - return constant_value(C, fn->module, val, dtype); -} - -static LLVMValueRef pseudo_to_value(struct dmr_C *C, struct function *fn, struct symbol *ctype, pseudo_t pseudo) -{ - LLVMValueRef result = NULL; - - switch (pseudo->type) { - case PSEUDO_REG: - result = pseudo->priv; - break; - case PSEUDO_SYM: - result = get_sym_value(C, fn, pseudo); - break; - case PSEUDO_VAL: - result = val_to_value(C, fn, pseudo->value, ctype); - break; - case PSEUDO_ARG: - result = LLVMGetParam(fn->fn, pseudo->nr - 1); - break; - case PSEUDO_PHI: - result = pseudo->priv; - break; - case PSEUDO_VOID: - result = NULL; - break; - default: - break; - } - if (!result) { - fprintf(stderr, "error: no result for pseudo\n"); - return NULL; - } - return result; -} - -static LLVMValueRef ptr_toint(struct dmr_C *C, struct function *fn, LLVMValueRef val) -{ - if (LLVMGetTypeKind(LLVMTypeOf(val)) == LLVMPointerTypeKind) { - LLVMTypeRef dtype = LLVMIntTypeInContext(LLVMGetModuleContext(fn->module), C->target->bits_in_pointer); - val = LLVMBuildPtrToInt(fn->builder, val, dtype, LLVMGetValueName(val)); - } - return val; -} - -#if 0 - -static LLVMValueRef calc_gep(struct dmr_C *C, struct function *fn, LLVMBuilderRef builder, LLVMValueRef base, LLVMValueRef off) -{ - LLVMTypeRef type = LLVMTypeOf(base); - unsigned int as = LLVMGetPointerAddressSpace(type); - LLVMTypeRef bytep = LLVMPointerType(LLVMInt8TypeInContext(LLVMGetModuleContext(fn->module)), as); - LLVMValueRef addr; - - /* convert base to char* type */ - base = LLVMBuildPointerCast(builder, base, bytep, ""); - /* addr = base + off */ - addr = LLVMBuildInBoundsGEP(builder, base, &off, 1, ""); - /* convert back to the actual pointer type */ - addr = LLVMBuildPointerCast(builder, addr, type, ""); - return addr; -} - -#endif - -static LLVMRealPredicate translate_fop(int opcode) -{ - static const LLVMRealPredicate trans_tbl[] = { - [OP_SET_EQ] = LLVMRealOEQ, - [OP_SET_NE] = LLVMRealUNE, - [OP_SET_LE] = LLVMRealOLE, - [OP_SET_GE] = LLVMRealOGE, - [OP_SET_LT] = LLVMRealOLT, - [OP_SET_GT] = LLVMRealOGT, - /* Are these used with FP? */ - [OP_SET_B] = LLVMRealOLT, - [OP_SET_A] = LLVMRealOGT, - [OP_SET_BE] = LLVMRealOLE, - [OP_SET_AE] = LLVMRealOGE, - }; - - return trans_tbl[opcode]; -} - -static LLVMIntPredicate translate_op(int opcode) -{ - static const LLVMIntPredicate trans_tbl[] = { - [OP_SET_EQ] = LLVMIntEQ, - [OP_SET_NE] = LLVMIntNE, - [OP_SET_LE] = LLVMIntSLE, - [OP_SET_GE] = LLVMIntSGE, - [OP_SET_LT] = LLVMIntSLT, - [OP_SET_GT] = LLVMIntSGT, - [OP_SET_B] = LLVMIntULT, - [OP_SET_A] = LLVMIntUGT, - [OP_SET_BE] = LLVMIntULE, - [OP_SET_AE] = LLVMIntUGE, - }; - - return trans_tbl[opcode]; -} - -/** -* Convert the pseudo to a value, and cast it to the expected type of the -* instruction. If ptrtoint is true then convert pointer values to integers. -*/ -static LLVMValueRef get_operand(struct dmr_C *C, struct function *fn, struct symbol *ctype, pseudo_t pseudo, bool ptrtoint, bool unsigned_cast) -{ - LLVMValueRef target; - - LLVMTypeRef instruction_type = get_symnode_or_basetype(C, fn->module, ctype); - if (instruction_type == NULL) - return NULL; - target = pseudo_to_value(C, fn, ctype, pseudo); - if (!target) - return NULL; - if (ptrtoint && dmrC_is_ptr_type(ctype)) - target = ptr_toint(C, fn, target); - else - target = build_cast(C, fn, target, instruction_type, LLVMGetValueName(target), unsigned_cast); - return target; -} - -static LLVMValueRef output_op_binary(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef lhs, rhs, target; - char target_name[64]; - - LLVMTypeRef instruction_type = get_symnode_or_basetype(C, fn->module, insn->type); - - lhs = get_operand(C, fn, insn->type, insn->src1, 1, 0); - if (!lhs) - return NULL; - - rhs = get_operand(C, fn, insn->type, insn->src2, 1, 0); - if (!rhs) - return NULL; - - pseudo_name(C, insn->target, target_name, sizeof target_name); - - switch (insn->opcode) { - /* Binary */ - case OP_ADD: - if (dmrC_is_float_type(C->S, insn->type)) - target = LLVMBuildFAdd(fn->builder, lhs, rhs, target_name); - else - target = LLVMBuildAdd(fn->builder, lhs, rhs, target_name); - break; - case OP_SUB: - if (dmrC_is_float_type(C->S, insn->type)) - target = LLVMBuildFSub(fn->builder, lhs, rhs, target_name); - else - target = LLVMBuildSub(fn->builder, lhs, rhs, target_name); - break; - case OP_MULU: - if (dmrC_is_float_type(C->S, insn->type)) - target = LLVMBuildFMul(fn->builder, lhs, rhs, target_name); - else - target = LLVMBuildMul(fn->builder, lhs, rhs, target_name); - break; - case OP_MULS: - assert(!dmrC_is_float_type(C->S, insn->type)); - target = LLVMBuildMul(fn->builder, lhs, rhs, target_name); - break; - case OP_DIVU: - if (dmrC_is_float_type(C->S, insn->type)) - target = LLVMBuildFDiv(fn->builder, lhs, rhs, target_name); - else - target = LLVMBuildUDiv(fn->builder, lhs, rhs, target_name); - break; - case OP_DIVS: - assert(!dmrC_is_float_type(C->S, insn->type)); - target = LLVMBuildSDiv(fn->builder, lhs, rhs, target_name); - break; - case OP_MODU: - assert(!dmrC_is_float_type(C->S, insn->type)); - target = LLVMBuildURem(fn->builder, lhs, rhs, target_name); - break; - case OP_MODS: - assert(!dmrC_is_float_type(C->S, insn->type)); - target = LLVMBuildSRem(fn->builder, lhs, rhs, target_name); - break; - case OP_SHL: - assert(!dmrC_is_float_type(C->S, insn->type)); - target = LLVMBuildShl(fn->builder, lhs, rhs, target_name); - break; - case OP_LSR: - assert(!dmrC_is_float_type(C->S, insn->type)); - target = LLVMBuildLShr(fn->builder, lhs, rhs, target_name); - break; - case OP_ASR: - assert(!dmrC_is_float_type(C->S, insn->type)); - target = LLVMBuildAShr(fn->builder, lhs, rhs, target_name); - break; - - /* Logical */ - case OP_AND: - assert(!dmrC_is_float_type(C->S, insn->type)); - target = LLVMBuildAnd(fn->builder, lhs, rhs, target_name); - break; - case OP_OR: - assert(!dmrC_is_float_type(C->S, insn->type)); - target = LLVMBuildOr(fn->builder, lhs, rhs, target_name); - break; - case OP_XOR: - assert(!dmrC_is_float_type(C->S, insn->type)); - target = LLVMBuildXor(fn->builder, lhs, rhs, target_name); - break; - case OP_AND_BOOL: { - LLVMValueRef lhs_nz, rhs_nz; - LLVMTypeRef dst_type; - - lhs_nz = LLVMBuildIsNotNull(fn->builder, lhs, ""); - rhs_nz = LLVMBuildIsNotNull(fn->builder, rhs, ""); - target = LLVMBuildAnd(fn->builder, lhs_nz, rhs_nz, target_name); - - dst_type = insn_symbol_type(C, fn->module, insn); - if (!dst_type) - return NULL; - target = LLVMBuildZExt(fn->builder, target, dst_type, target_name); - break; - } - case OP_OR_BOOL: { - LLVMValueRef lhs_nz, rhs_nz; - LLVMTypeRef dst_type; - - lhs_nz = LLVMBuildIsNotNull(fn->builder, lhs, ""); - rhs_nz = LLVMBuildIsNotNull(fn->builder, rhs, ""); - target = LLVMBuildOr(fn->builder, lhs_nz, rhs_nz, target_name); - - dst_type = insn_symbol_type(C, fn->module, insn); - if (!dst_type) - return NULL; - target = LLVMBuildZExt(fn->builder, target, dst_type, target_name); - break; - } - - default: - assert(0); - return NULL; - } - - target = build_cast(C, fn, target, instruction_type, target_name, 0); - insn->target->priv = target; - - return target; -} - -static inline struct symbol *pseudo_type(struct dmr_C *C, pseudo_t pseudo) -{ - switch (pseudo->type) { - case PSEUDO_SYM: - case PSEUDO_ARG: - return pseudo->sym; - case PSEUDO_REG: - case PSEUDO_PHI: - return pseudo->def->type; - case PSEUDO_VAL: - return C->target->size_t_ctype; - case PSEUDO_VOID: - default: - return &C->S->void_ctype; - } -} - -static LLVMValueRef output_op_compare(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef lhs, rhs, target; - char target_name[64]; - - if (insn->src1->type == PSEUDO_VAL) - lhs = val_to_value(C, fn, insn->src1->value, pseudo_type(C, insn->src2)); - else - lhs = pseudo_to_value(C, fn, insn->type, insn->src1); - if (!lhs) - return NULL; - if (insn->src2->type == PSEUDO_VAL) - rhs = val_to_value(C, fn, insn->src2->value, pseudo_type(C, insn->src1)); - else - rhs = pseudo_to_value(C, fn, insn->type, insn->src2); - if (!rhs) - return NULL; - - pseudo_name(C, insn->target, target_name, sizeof target_name); - - LLVMTypeRef dst_type = insn_symbol_type(C, fn->module, insn); - if (!dst_type) - return NULL; - - switch (LLVMGetTypeKind(LLVMTypeOf(lhs))) { - case LLVMPointerTypeKind: { - lhs = LLVMBuildPtrToInt(fn->builder, lhs, LLVMIntTypeInContext(LLVMGetModuleContext(fn->module), C->target->bits_in_pointer), ""); - if (LLVMGetTypeKind(LLVMTypeOf(rhs)) == LLVMPointerTypeKind) { - rhs = LLVMBuildPtrToInt(fn->builder, rhs, LLVMIntTypeInContext(LLVMGetModuleContext(fn->module), C->target->bits_in_pointer), ""); - } - LLVMIntPredicate op = translate_op(insn->opcode); - target = LLVMBuildICmp(fn->builder, op, lhs, rhs, target_name); - break; - } - - case LLVMIntegerTypeKind: { - LLVMIntPredicate op = translate_op(insn->opcode); - target = LLVMBuildICmp(fn->builder, op, lhs, rhs, target_name); - break; - } - - case LLVMHalfTypeKind: - case LLVMFloatTypeKind: - case LLVMDoubleTypeKind: - case LLVMX86_FP80TypeKind: - case LLVMFP128TypeKind: - case LLVMPPC_FP128TypeKind: { - LLVMRealPredicate op = translate_fop(insn->opcode); - - target = LLVMBuildFCmp(fn->builder, op, lhs, rhs, target_name); - break; - } - default: - assert(0); - return NULL; - } - - target = LLVMBuildZExt(fn->builder, target, dst_type, target_name); - - insn->target->priv = target; - - return target; -} - -static LLVMValueRef output_op_ret(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - pseudo_t pseudo = insn->src; - - if (pseudo && pseudo != VOID_PSEUDO(C) && LLVMGetTypeKind(fn->return_type) != LLVMVoidTypeKind) { - LLVMValueRef result = get_operand(C, fn, insn->type, pseudo, 0, 0); - if (!result) - return NULL; - return LLVMBuildRet(fn->builder, result); - } - else - return LLVMBuildRetVoid(fn->builder); -} - -static LLVMValueRef calc_memop_addr(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMTypeRef int_type, addr_type; - LLVMValueRef src, off, addr; - unsigned int as; - - /* int type large enough to hold a pointer */ - int_type = LLVMIntTypeInContext(LLVMGetModuleContext(fn->module), C->target->bits_in_pointer); - off = LLVMConstInt(int_type, (int)insn->offset, 0); - - /* convert src to the effective pointer type */ - src = pseudo_to_value(C, fn, insn->type, insn->src); - if (!src) - return NULL; - as = LLVMGetPointerAddressSpace(LLVMTypeOf(src)); - LLVMTypeRef symtype = insn_symbol_type(C, fn->module, insn); - if (!symtype) - return NULL; - addr_type = LLVMPointerType(symtype, as); -#if 1 - src = ptr_toint(C, fn, src); - addr = LLVMBuildAdd(fn->builder, src, off, ""); - addr = LLVMBuildIntToPtr(fn->builder, addr, addr_type, ""); -#else - src = LLVMBuildPointerCast(fn->builder, src, addr_type, ""); - - /* addr = src + off */ - addr = calc_gep(C, fn->builder, src, off); -#endif - return addr; -} - - -static LLVMValueRef output_op_load(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef addr, target; - char name[MAX_PSEUDO_NAME]; - - addr = calc_memop_addr(C, fn, insn); - if (!addr) - return NULL; - - /* perform load */ - pseudo_name(C, insn->target, name, sizeof name); - target = LLVMBuildLoad(fn->builder, addr, name); - - insn->target->priv = target; - return target; -} - -static LLVMValueRef output_op_store(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef addr, target_in; - LLVMTypeRef desttype; - - if (is_aggregate_type(insn->type)) { - dmrC_sparse_error(C, insn->pos, "store to aggregate type is not yet supported, failure at insn %s\n", dmrC_show_instruction(C, insn)); - return NULL; - } - - addr = calc_memop_addr(C, fn, insn); - if (!addr) - return NULL; - - target_in = pseudo_to_value(C, fn, insn->type, insn->target); - if (!target_in) - return NULL; - - desttype = insn_symbol_type(C, fn->module, insn); - if (!desttype) - return NULL; - - /* Cast to the right type - to resolve issue with union types */ - target_in = build_cast(C, fn, target_in, desttype, LLVMGetValueName(target_in), 0); - if (!target_in) - return NULL; - - /* perform store */ - return LLVMBuildStore(fn->builder, target_in, addr); -} - -static LLVMValueRef bool_value(struct dmr_C *C, struct function *fn, LLVMValueRef value) -{ - (void)C; - LLVMTypeRef type = LLVMTypeOf(value); - if (type != LLVMInt1TypeInContext(LLVMGetModuleContext(fn->module))) { - LLVMTypeKind kind = LLVMGetTypeKind(type); - switch (kind) { - case LLVMPointerTypeKind: - case LLVMIntegerTypeKind: - value = LLVMBuildIsNotNull(fn->builder, value, "cond"); - break; - case LLVMFloatTypeKind: - case LLVMDoubleTypeKind: - value = LLVMBuildFCmp(fn->builder, LLVMRealUNE, value, LLVMConstReal(type, 0.0), "cond"); - break; - default: - return NULL; - } - } - return value; -} - -static LLVMValueRef output_op_cbr(struct dmr_C *C, struct function *fn, struct instruction *br) -{ - // FIXME - NEW_SSA changes appear to result in cond being PSEUDO_VAL in some cases - // This is a workaround for VALUE PSEUDO appearing in cond - struct symbol *ctype = br->type; - if (!ctype && br->cond->type == PSEUDO_VAL) - ctype = &C->S->llong_ctype; - LLVMValueRef cond = pseudo_to_value(C, fn, ctype, br->cond); - if (cond) - cond = bool_value(C, fn, cond); - if (!cond) { - dmrC_sparse_error(C, br->pos, "failure at insn %s\n", dmrC_show_instruction(C, br)); - return NULL; - } - return LLVMBuildCondBr(fn->builder, cond, - br->bb_true->priv, - br->bb_false->priv); -} - -static LLVMValueRef output_op_br(struct dmr_C *C, struct function *fn, struct instruction *br) -{ - (void)C; - return LLVMBuildBr(fn->builder, br->bb_true->priv); -} - - -static LLVMValueRef output_op_sel(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef target, src1, src2, src3; - LLVMTypeRef desttype = insn_symbol_type(C, fn->module, insn); - if (!desttype) - return NULL; - - src1 = pseudo_to_value(C, fn, insn->type, insn->src1); - if (!src1) - return NULL; - src1 = bool_value(C, fn, src1); - if (!src1) - return NULL; - - src2 = get_operand(C, fn, insn->type, insn->src2, 0, 0); - if (!src2) - return NULL; - src3 = get_operand(C, fn, insn->type, insn->src3, 0, 0); - if (!src3) - return NULL; - - target = LLVMBuildSelect(fn->builder, src1, src2, src3, "select"); - - insn->target->priv = target; - return target; -} - -static LLVMValueRef output_op_switch(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef sw_val, target; - struct basic_block *def = NULL; - struct multijmp *jmp; - int n_jmp = 0; - - FOR_EACH_PTR(insn->multijmp_list, jmp) { - if (jmp->begin <= jmp->end) { /* case M..N */ - n_jmp += (jmp->end - jmp->begin) + 1; - } - else /* default case */ - def = jmp->target; - } END_FOR_EACH_PTR(jmp); - - sw_val = pseudo_to_value(C, fn, insn->type, insn->target); - if (!sw_val) - return NULL; - target = LLVMBuildSwitch(fn->builder, sw_val, - def ? def->priv : NULL, n_jmp); - - FOR_EACH_PTR(insn->multijmp_list, jmp) { - long long val; - for (val = jmp->begin; val <= jmp->end; val++) { - LLVMValueRef value = LLVMConstInt(LLVMTypeOf(sw_val), val, 0); - LLVMAddCase(target, value, jmp->target->priv); - } - } END_FOR_EACH_PTR(jmp); - - return target; -} - -static struct symbol *get_function_basetype(struct symbol *type) -{ - if (type->type == SYM_PTR) - type = type->ctype.base_type; - assert(type->type == SYM_FN); - return type; -} - -static LLVMValueRef output_op_call(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef target, func; - int n_arg = 0, i; - struct pseudo *arg; - LLVMValueRef *args; - char name[64]; - - n_arg = ptrlist_size((struct ptr_list *)insn->arguments); - args = alloca(n_arg * sizeof(LLVMValueRef)); - struct symbol *ftype = get_function_basetype(insn->fntype); - - i = 0; - FOR_EACH_PTR(insn->arguments, arg) { - LLVMValueRef value; - struct symbol *atype; - - atype = dmrC_get_nth_symbol(ftype->arguments, i); - value = NULL; - if (arg->type == PSEUDO_VAL) { - /* Value pseudos do not have type information. */ - /* Use the function prototype to get the type. */ - if (atype) - value = val_to_value(C, fn, arg->value, atype); - else { - LLVMTypeRef type = int_type_by_size(fn->module, arg->size); - if (!type) { - dmrC_sparse_error(C, insn->pos, "pseudo value argument[%d] = %lld has invalid size %d\n", i+1, arg->value, arg->size); - } - else { - value = constant_value(C, fn->module, arg->value, type); - } - } - } - else { - value = pseudo_to_value(C, fn, atype, arg); - } - if (!value) - return NULL; - if (atype) { - LLVMTypeRef argtype = get_symnode_type(C, fn->module, atype); - if (!argtype) - return NULL; - value = build_cast(C, fn, value, argtype, LLVMGetValueName(value), 0); - if (!value) - return NULL; - } - args[i++] = value; - } END_FOR_EACH_PTR(arg); - - func = pseudo_to_value(C, fn, insn->type, insn->func); - if (!func) - return NULL; - pseudo_name(C, insn->target, name, sizeof name); - LLVMTypeRef function_type = type_to_llvmtype(C, fn->module, ftype, NULL); - if (!function_type) - return NULL; - LLVMTypeRef fptr_type = LLVMPointerType(function_type, 0); - LLVMTypeRef bytep = LLVMPointerType(LLVMInt8TypeInContext(LLVMGetModuleContext(fn->module)), 0); - - target = LLVMBuildBitCast(fn->builder, func, bytep, name); - target = LLVMBuildBitCast(fn->builder, target, fptr_type, name); - target = LLVMBuildCall(fn->builder, target, args, n_arg, name); - - insn->target->priv = target; - - return target; -} - -static LLVMValueRef output_op_phisrc(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef v; - struct instruction *phi; - - assert(insn->target->priv == NULL); - - /* target = src */ - v = get_operand(C, fn, insn->type, insn->phi_src, 0, 0); - if (!v) - return NULL; - - FOR_EACH_PTR(insn->phi_users, phi) { - LLVMValueRef load, ptr; - - assert(phi->opcode == OP_PHI); - /* phi must be load from alloca */ - load = phi->target->priv; - assert(load); - if (!load) - return NULL; - assert(LLVMGetInstructionOpcode(load) == LLVMLoad); - ptr = LLVMGetOperand(load, 0); - /* store v to alloca */ - LLVMTypeRef phi_type = insn_symbol_type(C, fn->module, phi); - if (!phi_type) - return NULL; - v = build_cast(C, fn, v, phi_type, "", 0); - if (!v) - return NULL; - v = LLVMBuildStore(fn->builder, v, ptr); - } END_FOR_EACH_PTR(phi); - return v; -} - -static LLVMValueRef output_op_phi(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef load = insn->target->priv; - (void)C; - assert(load); - if (!load) - return NULL; - - /* forward load */ - assert(LLVMGetInstructionOpcode(load) == LLVMLoad); - /* forward load has no parent block */ - assert(!LLVMGetInstructionParent(load)); - /* finalize load in current block */ - LLVMInsertIntoBuilder(fn->builder, load); - return load; -} - -static LLVMValueRef output_op_ptrcast(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef src, target; - LLVMTypeRef dtype; - struct symbol *otype = insn->orig_type; - char target_name[64]; - - assert(dmrC_is_ptr_type(insn->type)); - - src = insn->src->priv; - if (!src) - src = get_operand(C, fn, otype, insn->src, 1, 0); - if (!src) - return NULL; - - pseudo_name(C, insn->target, target_name, sizeof target_name); - - dtype = insn_symbol_type(C, fn->module, insn); - if (!dtype) - return NULL; - - target = build_cast(C, fn, src, dtype, target_name, 0); - insn->target->priv = target; - - return target; -} - -static LLVMValueRef output_op_cast(struct dmr_C *C, struct function *fn, struct instruction *insn, LLVMOpcode op) -{ - LLVMValueRef src, target; - LLVMTypeRef dtype; - struct symbol *otype = insn->orig_type; - char target_name[64]; - - if (dmrC_is_ptr_type(insn->type)) { - return output_op_ptrcast(C, fn, insn); - } - - src = insn->src->priv; - if (!src) - src = pseudo_to_value(C, fn, insn->type, insn->src); - if (dmrC_is_int_type(C->S, otype)) { - LLVMTypeRef stype = get_symnode_or_basetype(C, fn->module, otype); - src = build_cast(C, fn, src, stype, LLVMGetValueName(src), op == LLVMZExt); - } - if (!src) - return NULL; - - pseudo_name(C, insn->target, target_name, sizeof target_name); - - assert(!dmrC_is_float_type(C->S, insn->type)); - - dtype = insn_symbol_type(C, fn->module, insn); - if (!dtype) - return NULL; - target = build_cast(C, fn, src, dtype, target_name, op == LLVMZExt); - insn->target->priv = target; - - return target; -} - -static LLVMValueRef output_op_fpcast(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef src, target; - char target_name[64]; - LLVMTypeRef dtype; - struct symbol *otype = insn->orig_type; - - src = insn->src->priv; - if (!src) - src = pseudo_to_value(C, fn, insn->type, insn->src); - if (!src) - return NULL; - - pseudo_name(C, insn->target, target_name, sizeof target_name); - - dtype = insn_symbol_type(C, fn->module, insn); - if (!dtype) - return NULL; - - target = build_cast(C, fn, src, dtype, target_name, !dmrC_is_signed_type(otype)); - insn->target->priv = target; - - return target; -} - - -static LLVMValueRef output_op_copy(struct dmr_C *C, struct function *fn, struct instruction *insn, - pseudo_t pseudo) -{ - LLVMValueRef src, target; - LLVMTypeRef const_type; - char target_name[64]; - - pseudo_name(C, insn->target, target_name, sizeof target_name); - src = pseudo_to_value(C, fn, insn->type, pseudo); - if (!src) - return NULL; - - const_type = insn_symbol_type(C, fn->module, insn); - if (!const_type) - return NULL; - - /* - * This is nothing more than 'target = src' - * - * TODO: find a better way to provide an identity function, - * than using "X + 0" simply to produce a new LLVM pseudo - */ - - if (dmrC_is_float_type(C->S, insn->type)) - target = LLVMBuildFAdd(fn->builder, src, - LLVMConstReal(const_type, 0.0), target_name); - else - target = LLVMBuildAdd(fn->builder, src, - LLVMConstInt(const_type, 0, 0), target_name); - - insn->target->priv = target; - return target; -} - -static LLVMValueRef output_op_setval(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - struct expression *expr = insn->val; - char target_name[64]; - LLVMTypeRef const_type; - LLVMValueRef target = NULL; - - if (!expr) - return NULL; - - pseudo_name(C, insn->target, target_name, sizeof target_name); - const_type = insn_symbol_type(C, fn->module, insn); - if (!const_type) - return NULL; - - switch (expr->type) { - case EXPR_FVALUE: - target = LLVMConstReal(const_type, expr->fvalue); - break; - case EXPR_LABEL: - target = LLVMBlockAddress(fn->fn, expr->symbol->bb_target->priv); - break; - default: - dmrC_sparse_error(C, insn->pos, "unsupported expression type %d in setval\n", expr->type); - dmrC_show_expression(C, expr); - return NULL; - } - - insn->target->priv = target; - - return target; -} - -static LLVMValueRef output_op_symaddr(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef res, src; - LLVMTypeRef dtype; - char name[64]; - - src = pseudo_to_value(C, fn, insn->type, insn->symbol); - if (!src) - return NULL; - - dtype = get_symnode_or_basetype(C, fn->module, insn->type); - if (!dtype) - return NULL; - - pseudo_name(C, insn->target, name, sizeof name); - res = LLVMBuildBitCast(fn->builder, src, dtype, name); - insn->target->priv = res; - - return res; -} - -static LLVMValueRef output_op_not(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef src, target; - char target_name[64]; - - src = pseudo_to_value(C, fn, insn->type, insn->src); - if (!src) - return NULL; - - pseudo_name(C, insn->target, target_name, sizeof target_name); - - target = LLVMBuildNot(fn->builder, src, target_name); - - insn->target->priv = target; - - return target; -} - -static LLVMValueRef output_op_neg(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef src, target; - char target_name[64]; - - src = pseudo_to_value(C, fn, insn->type, insn->src); - if (!src) - return NULL; - - pseudo_name(C, insn->target, target_name, sizeof target_name); - - if (dmrC_is_float_type(C->S, insn->type)) - target = LLVMBuildFNeg(fn->builder, src, target_name); - else - target = LLVMBuildNeg(fn->builder, src, target_name); - - insn->target->priv = target; - - return target; -} - -/* return 1 on success, 0 on failure */ -static int output_insn(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - LLVMValueRef v = NULL; - switch (insn->opcode) { - case OP_RET: - v = output_op_ret(C, fn, insn); - break; - case OP_CBR: - v = output_op_cbr(C, fn, insn); - break; - case OP_BR: - v = output_op_br(C, fn, insn); - break; - case OP_SYMADDR: - v = output_op_symaddr(C, fn, insn); - break; - case OP_SETVAL: - v = output_op_setval(C, fn, insn); - break; - case OP_SWITCH: - v = output_op_switch(C, fn, insn); - break; - case OP_COMPUTEDGOTO: - dmrC_sparse_error(C, insn->pos, "computed goto not yet supported\n"); - return 0; - case OP_PHISOURCE: - v = output_op_phisrc(C, fn, insn); - break; - case OP_PHI: - v = output_op_phi(C, fn, insn); - break; - case OP_LOAD: - v = output_op_load(C, fn, insn); - break; - case OP_LNOP: - dmrC_sparse_error(C, insn->pos, "lnop not yet supported\n"); - return 0; - case OP_STORE: - v = output_op_store(C, fn, insn); - break; - case OP_SNOP: - dmrC_sparse_error(C, insn->pos, "snop not yet supported\n"); - return 0; - case OP_CALL: - v = output_op_call(C, fn, insn); - break; - case OP_CAST: - v = output_op_cast(C, fn, insn, LLVMZExt); - break; - case OP_SCAST: - v = output_op_cast(C, fn, insn, LLVMSExt); - break; - case OP_FPCAST: - v = output_op_fpcast(C, fn, insn); - break; - case OP_PTRCAST: - v = output_op_ptrcast(C, fn, insn); - break; - case OP_ADD: - case OP_SUB: - case OP_MULU: - case OP_MULS: - case OP_DIVU: - case OP_DIVS: - case OP_MODU: - case OP_MODS: - case OP_SHL: - case OP_LSR: - case OP_ASR: - case OP_AND: - case OP_OR: - case OP_XOR: - case OP_AND_BOOL: - case OP_OR_BOOL: - v = output_op_binary(C, fn, insn); - break; - case OP_SET_EQ: - case OP_SET_NE: - case OP_SET_LE: - case OP_SET_GE: - case OP_SET_LT: - case OP_SET_GT: - case OP_SET_B: - case OP_SET_A: - case OP_SET_BE: - case OP_SET_AE: - v = output_op_compare(C, fn, insn); - break; - case OP_SEL: - v = output_op_sel(C, fn, insn); - break; - case OP_SLICE: - dmrC_sparse_error(C, insn->pos, "slice not yet supported\n"); - return 0; - case OP_NOT: - v = output_op_not(C, fn, insn); - break; - case OP_NEG: - v = output_op_neg(C, fn, insn); - break; - case OP_CONTEXT: - dmrC_sparse_error(C, insn->pos, "context not yet supported\n"); - return 0; - case OP_RANGE: - dmrC_sparse_error(C, insn->pos, "range not yet supported\n"); - return 0; - case OP_NOP: - dmrC_sparse_error(C, insn->pos, "nop not yet supported\n"); - return 0; - case OP_DEATHNOTE: - return 1; - case OP_ASM: - dmrC_sparse_error(C, insn->pos, "asm not yet supported\n"); - return 0; - case OP_COPY: - v = output_op_copy(C, fn, insn, insn->src); - break; - default: - return 1; - } - - if (v == NULL) - dmrC_sparse_error(C, insn->pos, "failed to output instruction %s\n", dmrC_show_instruction(C, insn)); - return v != NULL; -} - -/* return 1 on success, 0 on failure */ -static int output_bb(struct dmr_C *C, struct function *fn, struct basic_block *bb) -{ - struct instruction *insn; - - FOR_EACH_PTR(bb->insns, insn) { - if (!insn->bb) - continue; - - if (!output_insn(C, fn, insn)) { - dmrC_sparse_error(C, insn->pos, "failed to output %s\n", dmrC_show_instruction(C, insn)); - return 0; - } - } - END_FOR_EACH_PTR(insn); - return 1; -} - -#define MAX_ARGS 64 - -static LLVMValueRef output_fn(struct dmr_C *C, LLVMModuleRef module, struct entrypoint *ep) -{ - struct symbol *sym = ep->name; - struct symbol *base_type = sym->ctype.base_type; - struct symbol *ret_type = sym->ctype.base_type->ctype.base_type; - LLVMTypeRef arg_types[MAX_ARGS]; - LLVMTypeRef return_type; - struct function function = { .module = module }; - struct basic_block *bb; - struct symbol *arg; - const char *name; - int nr_args = 0; - - FOR_EACH_PTR(base_type->arguments, arg) { - if (nr_args >= MAX_ARGS) - return NULL; - arg_types[nr_args] = get_symnode_type(C, module, arg); - if (!arg_types[nr_args]) - return NULL; - nr_args++; - } END_FOR_EACH_PTR(arg); - - name = dmrC_show_ident(C, sym->ident); - - return_type = type_to_llvmtype(C, module, ret_type, NULL); - if (!return_type) - return NULL; - - function.return_type = return_type; - function.fn = LLVMGetNamedFunction(module, name); - if (!function.fn) { - function.type = LLVMFunctionType(return_type, arg_types, nr_args, base_type->variadic); - function.fn = LLVMAddFunction(module, name, function.type); - LLVMSetLinkage(function.fn, function_linkage(C, sym)); - sym->priv = function.fn; - } - else { - function.type = LLVMTypeOf(function.fn); - } - - LLVMSetFunctionCallConv(function.fn, LLVMCCallConv); - - function.builder = LLVMCreateBuilderInContext(LLVMGetModuleContext(module)); - - /* give a name to each argument */ - for (int i = 0; i < nr_args; i++) { - char name[MAX_PSEUDO_NAME]; - LLVMValueRef arg; - - arg = LLVMGetParam(function.fn, i); - snprintf(name, sizeof name, "ARG%d", i + 1); - LLVMSetValueName(arg, name); - } - - /* create the BBs */ - FOR_EACH_PTR(ep->bbs, bb) { - static int nr_bb; - LLVMBasicBlockRef bbr; - char bbname[32]; - struct instruction *insn; - - sprintf(bbname, "L%d", nr_bb++); - bbr = LLVMAppendBasicBlockInContext(LLVMGetModuleContext(module), function.fn, bbname); - - bb->priv = bbr; - - /* allocate alloca for each phi */ - FOR_EACH_PTR(bb->insns, insn) { - LLVMBasicBlockRef entrybbr; - LLVMTypeRef phi_type; - LLVMValueRef ptr; - - if (!insn->bb || insn->opcode != OP_PHI) - continue; - /* insert alloca into entry block */ - entrybbr = LLVMGetEntryBasicBlock(function.fn); - LLVMPositionBuilderAtEnd(function.builder, entrybbr); - phi_type = insn_symbol_type(C, module, insn); - if (!phi_type) { - LLVMDisposeBuilder(function.builder); - return NULL; - } - ptr = LLVMBuildAlloca(function.builder, phi_type, ""); - /* emit forward load for phi */ - LLVMClearInsertionPosition(function.builder); - insn->target->priv = LLVMBuildLoad(function.builder, ptr, "phi"); - } END_FOR_EACH_PTR(insn); - } - END_FOR_EACH_PTR(bb); - - FOR_EACH_PTR(ep->bbs, bb) { - LLVMPositionBuilderAtEnd(function.builder, bb->priv); - - if (!output_bb(C, &function, bb)) { - LLVMDisposeBuilder(function.builder); - return NULL; - } - } - END_FOR_EACH_PTR(bb); - - LLVMDisposeBuilder(function.builder); - - return function.fn; -} - -/* returns NULL on failure */ -static LLVMValueRef output_data(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym) -{ - struct expression *initializer = sym->initializer; - LLVMValueRef initial_value = NULL; - LLVMValueRef data = NULL; - const char *name; - - if (initializer) { - switch (initializer->type) { - case EXPR_VALUE: - initial_value = constant_value(C, module, initializer->value, get_symnode_type(C, module, sym)); - break; - case EXPR_FVALUE: - initial_value = LLVMConstReal(get_symnode_type(C, module, sym), initializer->fvalue); - break; - case EXPR_SYMBOL: { - struct symbol *sym = initializer->symbol; - if (sym->ident) - initial_value = LLVMGetNamedGlobal(module, dmrC_show_ident(C, sym->ident)); - if (!initial_value) - initial_value = output_data(C, module, sym); - break; - } - case EXPR_STRING: { - const char *s = initializer->string->data; - char *scopy = dmrC_allocator_allocate(&C->byte_allocator, strlen(s) + 1); - strcpy(scopy, s); - initial_value = LLVMConstStringInContext(LLVMGetModuleContext(module), scopy, strlen(scopy) + 1, true); - break; - } - default: - dmrC_sparse_error(C, initializer->pos, "unsupported expr type in global data initializer: %d\n", initializer->type); - dmrC_show_expression(C, initializer); - } - if (!initial_value) - return NULL; - } - else { - LLVMTypeRef type = get_symnode_type(C, module, sym); - if (type == NULL) - return NULL; - initial_value = LLVMConstNull(type); - } - - name = dmrC_show_ident(C, sym->ident); - - if (!sym->priv) { - if (sym->ident) - data = LLVMGetNamedGlobal(module, name); - if (!data) - data = LLVMAddGlobal(module, LLVMTypeOf(initial_value), name); - - LLVMSetLinkage(data, data_linkage(C, sym)); - if (sym->ctype.modifiers & MOD_CONST) - LLVMSetGlobalConstant(data, 1); - if (sym->ctype.modifiers & MOD_TLS) - LLVMSetThreadLocal(data, 1); - if (sym->ctype.alignment) - LLVMSetAlignment(data, sym->ctype.alignment); - - if (!(sym->ctype.modifiers & MOD_EXTERN)) - LLVMSetInitializer(data, initial_value); - - sym->priv = data; - } - else { - data = sym->priv; - if (!(sym->ctype.modifiers & MOD_EXTERN)) - LLVMSetInitializer(data, initial_value); - } - return data; -} - -static LLVMValueRef output_prototype(struct dmr_C *C, LLVMModuleRef module, struct symbol *sym) -{ - const char *name = dmrC_show_ident(C, sym->ident); - struct symbol *base_type = sym; - if (sym->type == SYM_NODE) - base_type = sym->ctype.base_type; - LLVMTypeRef ftype = sym_func_type(C, module, base_type, sym->type == SYM_NODE ? sym : NULL); - if (!ftype) - return NULL; - LLVMValueRef result = LLVMGetNamedFunction(module, name); - if (!result) { - result = LLVMAddFunction(module, name, ftype); - LLVMSetLinkage(result, function_linkage(C, sym)); - //LLVMSetFunctionCallConv(result, LLVMCCallConv); - } - sym->priv = result; - return result; -} - -/* returns 1 on success, 0 on failure */ -static int compile(struct dmr_C *C, LLVMModuleRef module, struct symbol_list *list) -{ - struct symbol *sym; - - FOR_EACH_PTR(list, sym) { - struct entrypoint *ep; - dmrC_expand_symbol(C, sym); - - if (dmrC_is_prototype(sym)) { - if (!output_prototype(C, module, sym)) - return 0; - continue; - } - - ep = dmrC_linearize_symbol(C, sym); - LLVMValueRef result = NULL; - if (ep) - result = output_fn(C, module, ep); - else - result = output_data(C, module, sym); - if (!result) - return 0; - } - END_FOR_EACH_PTR(sym); - - return 1; -} - -#if 0 - -#ifndef LLVM_DEFAULT_TARGET_TRIPLE -#define LLVM_DEFAULT_TARGET_TRIPLE LLVM_HOSTTRIPLE -#endif - -#define X86_LINUX_LAYOUT \ - "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" \ - "i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-" \ - "a0:0:64-f80:32:32-n8:16:32-S128" - -#define X86_64_LINUX_LAYOUT \ - "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-" \ - "i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-" \ - "a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" - -static void set_target(struct dmr_C *C, LLVMModuleRef module) -{ - char target[] = LLVM_DEFAULT_TARGET_TRIPLE; - const char *arch, *vendor, *os, *env, *layout = NULL; - char triple[256]; - - arch = strtok(target, "-"); - vendor = strtok(NULL, "-"); - os = strtok(NULL, "-"); - env = strtok(NULL, "-"); - - if (!os) - return; - if (!env) - env = "unknown"; - - if (!strcmp(arch, "x86_64") && !strcmp(os, "linux")) { - if (C->arch_m64) { - layout = X86_64_LINUX_LAYOUT; - } - else { - arch = "i386"; - layout = X86_LINUX_LAYOUT; - } - } - - /* unsupported target */ - if (!layout) - return; - - snprintf(triple, sizeof(triple), "%s-%s-%s-%s", arch, vendor, os, env); - // FIXME - what do we do here? - //LLVMSetTarget(module, triple); - //LLVMSetDataLayout(module, layout); -} - -#endif - -static void add_intrinsics(LLVMModuleRef module) -{ - LLVMTypeRef param_types[] = { LLVMPointerType(LLVMInt8TypeInContext(LLVMGetModuleContext(module)), 0), - LLVMInt8TypeInContext(LLVMGetModuleContext(module)), - LLVMInt32TypeInContext(LLVMGetModuleContext(module)), - LLVMInt32TypeInContext(LLVMGetModuleContext(module)), - LLVMInt1TypeInContext(LLVMGetModuleContext(module)) }; - LLVMTypeRef fn_type = LLVMFunctionType(LLVMVoidTypeInContext(LLVMGetModuleContext(module)), param_types, 5, false); - LLVMAddFunction(module, "llvm.memset.p0i8.i32", fn_type); -} - -bool dmrC_llvmcompile(int argc, char **argv, LLVMModuleRef module, - const char *inputbuffer) -{ - struct string_list *filelist = NULL; - struct symbol_list *symlist; - char *file; - - struct dmr_C *C = new_dmr_C(); - C->codegen = 1; /* disables macros related to vararg processing */ - - symlist = dmrC_sparse_initialize(C, argc, argv, &filelist); - // set_target(C, module); - add_intrinsics(module); - - int rc = 0; /* 0 means OK, non-zero means error */ - if (!setjmp(C->jmpbuf)) { - if (compile(C, module, symlist)) { - /* need ->phi_users */ - /* This flag enables call to dmrC_track_pseudo_death() in - linearize.c which sets - phi_users list on PHISOURCE instructions */ - C->dbg_dead = 1; - FOR_EACH_PTR(filelist, file) - { - symlist = dmrC_sparse(C, file); - if (C->die_if_error || !symlist) { - rc = 1; - break; - } - if (!compile(C, module, symlist)) { - rc = 1; - break; - } - } - END_FOR_EACH_PTR(file); - - if (inputbuffer && rc == 0) { - char *buffer = strdup(inputbuffer); - if (!buffer) - rc = 1; - else { - symlist = dmrC_sparse_buffer(C, "buffer", buffer, 0); - free(buffer); - if (C->die_if_error || !symlist) { - rc = 1; - } - else if (!compile(C, module, symlist)) { - rc = 1; - } - } - } - } - else - rc = 1; - } - else { - rc = 1; - } - char *error_message = NULL; - int dump_module = 0; - if (rc == 1) { - fprintf(stderr, "Failed to compile given inputs\n"); - } - if (rc == 0 && - LLVMVerifyModule(module, LLVMPrintMessageAction, &error_message)) { - dump_module = 1; - rc = 1; - } - if (error_message) { - if (strlen(error_message) > 0) - fprintf(stderr, "%s\n\n", error_message); - LLVMDisposeMessage(error_message); - } - if (rc == 0) { - const char *filename = "out.bc"; - if (C->output_file_name[0]) - filename = C->output_file_name; - LLVMWriteBitcodeToFile(module, filename); - } - else { - if (dump_module) - /* we only dump the LLVM module if verification fails */ - LLVMDumpModule(module); - } - destroy_dmr_C(C); - - return rc == 0; -} diff --git a/dmr_c/null-backend/dmr_c.h b/dmr_c/null-backend/dmr_c.h deleted file mode 100644 index eb5f23e..0000000 --- a/dmr_c/null-backend/dmr_c.h +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This header is used when no backend is used - * - * Copyright (C) 2017 Dibyendu Majumdar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef DMR_C_H -#define DMR_C_H - -#endif diff --git a/dmr_c/omrjit-backend/dmr_c.h b/dmr_c/omrjit-backend/dmr_c.h deleted file mode 100644 index 1a8e1b5..0000000 --- a/dmr_c/omrjit-backend/dmr_c.h +++ /dev/null @@ -1,42 +0,0 @@ -/** - * This is a backend code generator for dmr_C that uses - * the JIT engine OMR JIT (https://github.com/dibyendumajumdar/nj). - * - * Copyright (C) 2018 Dibyendu Majumdar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ -#ifndef DMR_C_H -#define DMR_C_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -bool dmrC_omrcompile(int argc, char **argv, JIT_ContextRef context, - const char *inputbuffer); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/dmr_c/omrjit-backend/sparse-omrjit.c b/dmr_c/omrjit-backend/sparse-omrjit.c deleted file mode 100644 index d101fde..0000000 --- a/dmr_c/omrjit-backend/sparse-omrjit.c +++ /dev/null @@ -1,2299 +0,0 @@ -/** - * This is a backend code generator for dmr_C that uses - * the JIT engine OMRJIT (https://github.com/dibyendumajumdar/nj). - * - * Copyright (C) 2018 Dibyendu Majumdar - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* -Define environment variable -TR_Options=traceIlGen,traceFull,traceAliases,log=trtrace.log -To obtain a nice trace of codegen -*/ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -/* -Some Implementation Notes -========================= - -1. Local aggregate variables are modelled as byte strings - the load/store ops - take care of extracting / storing the right type of value - -2. Local primitives are modelled as temporaries. - -3. Phi values are modelled as temporaries - phisrc is implemented as store - to temporary while phi is a load from temporary. - -4. We create all the blocks at the beginning based upon the blocks in - Sparse IR - but we have to add an extra block for every CBR instruction - as conditional branches in OMR fall through to the next block - -5. Local SymRefs are stored in Sparse Symbol->priv field. - -6. Pseudo SymRefs are stored in pseudo->priv2, whereas corresponding load - is stored in pseudo->priv. - -7. If address of a local temporary is taken we need to let the compiler - backend know this as otherwise the backend may not realize that the - locals could change through the pointers. Strictly speaking this is a - problem if the pointers escape (e.g. are passed to a function call) - but we don't optimize for that yet. -*/ - -/* -OMR has additional vector types which we do not support -*/ -enum OMRTypeKind { - RT_UNSUPPORTED = 0, - RT_VOID = 1, - RT_INT = 2, /* Sometimes Sparse IR contains int values with odd bit - sizes; this type is used in that case */ - RT_INT8 = 3, - RT_INT16 = 4, - RT_INT32 = 5, - RT_INT64 = 6, - RT_FLOAT = 7, - RT_DOUBLE = 8, - RT_PTR = 9, - RT_AGGREGATE = 10, - RT_FUNCTION = 11 -}; - -struct OMRType { - enum OMRTypeKind type; - struct OMRType *return_type; - uint32_t bit_size; -}; - -static struct OMRType VoidType = {.type = RT_VOID, .return_type = NULL, .bit_size = 0}; -static struct OMRType Int8Type = {.type = RT_INT8, .return_type = NULL, .bit_size = sizeof(int8_t) * 8}; -static struct OMRType Int16Type = {.type = RT_INT16, .return_type = NULL, .bit_size = sizeof(int16_t) * 8}; -static struct OMRType Int32Type = {.type = RT_INT32, .return_type = NULL, .bit_size = sizeof(int32_t) * 8}; -static struct OMRType Int64Type = {.type = RT_INT64, .return_type = NULL, .bit_size = sizeof(int64_t) * 8}; -static struct OMRType FloatType = {.type = RT_FLOAT, .return_type = NULL, .bit_size = sizeof(float) * 8}; -static struct OMRType DoubleType = {.type = RT_DOUBLE, .return_type = NULL, .bit_size = sizeof(double) * 8}; -static struct OMRType PtrType = {.type = RT_PTR, .return_type = NULL, .bit_size = sizeof(void *) * 8}; -// static struct OMRType PtrIntType = { -// .type = RT_INT64,.return_type = NULL,.bit_size = sizeof(intptr_t) * 8 }; -static struct OMRType BadType = {.type = RT_UNSUPPORTED, .return_type = NULL, .bit_size = 0}; - -struct function { - struct dmr_C *C; - JIT_ILInjectorRef injector; - JIT_FunctionBuilderRef builder; - JIT_ContextRef context; - struct entrypoint *ep; - struct allocator type_allocator; - struct OMRType *return_type; -}; - -/* Arbitrary limit ... FIXME */ -#define JIT_MaxArgs 16 - -static struct OMRType *alloc_OMRtype(struct function *fn, enum OMRTypeKind kind, unsigned int bit_size) -{ - struct OMRType *type = dmrC_allocator_allocate(&fn->type_allocator, 0); - type->type = kind; - type->bit_size = bit_size; - type->return_type = NULL; - return type; -} - -static struct OMRType *int_type_by_size(struct function *fn, int size) -{ - switch (size) { - case -1: - return NULL; - case 8: - return &Int8Type; - case 16: - return &Int16Type; - case 32: - return &Int32Type; - case 64: - return &Int64Type; - default: - /* Sometimes Sparse IR has non-standard bit sizes espcially in - * bitwise ops */ - return alloc_OMRtype(fn, RT_INT, size); - } -} - -static struct OMRType *sym_basetype_type(struct dmr_C *C, struct function *fn, struct symbol *sym, - struct symbol *sym_node) -{ - (void)sym_node; - if (dmrC_is_float_type(C->S, sym)) { - switch (sym->bit_size) { - case 32: - return &FloatType; - case 64: - return &DoubleType; - default: - fprintf(stderr, "invalid bit size %d for type %d\n", sym->bit_size, sym->type); - return &BadType; - } - } else { - switch (sym->bit_size) { - case -1: - return &VoidType; - default: - return int_type_by_size(fn, sym->bit_size); - } - } -} - -static int is_aggregate_type(struct symbol *sym) -{ - if (sym->type == SYM_NODE) - return is_aggregate_type(sym->ctype.base_type); - switch (sym->type) { - case SYM_UNION: - case SYM_STRUCT: - case SYM_ARRAY: - return true; - default: - return false; - } -} - -static struct OMRType *type_to_OMRtype(struct dmr_C *C, struct function *fn, struct symbol *sym, - struct symbol *sym_node); - -static struct OMRType *get_symnode_type(struct dmr_C *C, struct function *fn, struct symbol *sym) -{ - assert(sym->type == SYM_NODE); - return type_to_OMRtype(C, fn, sym->ctype.base_type, sym); -} - -static struct OMRType *get_symnode_or_basetype(struct dmr_C *C, struct function *fn, struct symbol *sym) -{ - if (sym->type == SYM_NODE) { - assert(sym->ctype.base_type->type != SYM_NODE); - return type_to_OMRtype(C, fn, sym->ctype.base_type, sym); - } - return type_to_OMRtype(C, fn, sym, NULL); -} - -static struct OMRType *func_return_type(struct dmr_C *C, struct function *fn, struct symbol *sym, - struct symbol *sym_node) -{ - return type_to_OMRtype(C, fn, sym->ctype.base_type, sym_node); -} - -static struct OMRType *sym_func_type(struct dmr_C *C, struct function *fn, struct symbol *sym, struct symbol *sym_node) -{ - struct OMRType *ret_type; - - // TODO we probably need a better way to encode function type - - ret_type = func_return_type(C, fn, sym, sym_node); - struct OMRType *type = alloc_OMRtype(fn, RT_FUNCTION, 0); - type->return_type = ret_type; - return type; -} - -static struct OMRType *sym_array_type(struct dmr_C *C, struct function *fn, struct symbol *sym, struct symbol *sym_node) -{ - struct symbol *base_type; - - (void)C; - base_type = sym->ctype.base_type; - /* empty struct is undefined [6.7.2.1(8)] */ - int array_bit_size = sym->bit_size; - if (array_bit_size == 0 || array_bit_size == -1) { - if (sym_node != NULL) - array_bit_size = sym_node->bit_size; - } - if (base_type->bit_size == 0 || base_type->bit_size == -1 || array_bit_size == 0 || array_bit_size == -1) { - fprintf(stderr, "array size cannot be determined\n"); - return &BadType; - } - return alloc_OMRtype(fn, RT_AGGREGATE, array_bit_size); -} - -static struct OMRType *sym_struct_type(struct dmr_C *C, struct function *fn, struct symbol *sym, - struct symbol *sym_node) -{ - (void)C; - (void)sym_node; - unsigned int bit_size = 0; - if (sym->bit_size > 0 && sym->bit_size != -1) { - bit_size = sym->bit_size; - } - return alloc_OMRtype(fn, RT_AGGREGATE, bit_size); -} - -static struct OMRType *sym_ptr_type(struct dmr_C *C, struct function *fn, struct symbol *sym, struct symbol *sym_node) -{ - (void)C; - (void)fn; - (void)sym_node; - (void)sym; - return &PtrType; -} - -static struct OMRType *type_to_OMRtype(struct dmr_C *C, struct function *fn, struct symbol *sym, - struct symbol *sym_node) -{ - assert(sym->type != SYM_NODE); - assert(sym_node == NULL || sym_node->type == SYM_NODE); - switch (sym->type) { - case SYM_BITFIELD: { - return alloc_OMRtype(fn, RT_INT, sym->bit_size); - } - case SYM_RESTRICT: - case SYM_ENUM: - return type_to_OMRtype(C, fn, sym->ctype.base_type, sym_node); - case SYM_BASETYPE: - return sym_basetype_type(C, fn, sym, sym_node); - case SYM_PTR: - return sym_ptr_type(C, fn, sym, sym_node); - case SYM_UNION: - case SYM_STRUCT: - return sym_struct_type(C, fn, sym, sym_node); - case SYM_ARRAY: - return sym_array_type(C, fn, sym, sym_node); - case SYM_FN: - return sym_func_type(C, fn, sym, sym_node); - default: - return &BadType; - } -} - -/* -If the instruction has a type uses that to determine the OMR type -else returns an OMR int type that matches the instruction size. -*/ -static struct OMRType *insn_symbol_type(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - if (insn->type) { - return get_symnode_or_basetype(C, fn, insn->type); - } - return int_type_by_size(fn, insn->size); -} - -static JIT_Type check_supported_argtype(struct dmr_C *C, struct symbol *sym) -{ - if (dmrC_is_ptr_type(sym)) - return JIT_Address; - if (dmrC_is_int_type(C->S, sym)) { - switch (sym->bit_size) { - case 8: - return JIT_Int8; - case 16: - return JIT_Int16; - case 32: - return JIT_Int32; - case 64: - return JIT_Int64; - default: - fprintf(stderr, "Unsupported type in function argument\n"); - return JIT_NoType; - } - } else { - // TODO assert float type - switch (sym->bit_size) { - case 32: - return JIT_Float; - case 64: - return JIT_Double; - default: - fprintf(stderr, "Unsupported type in function argument\n"); - return JIT_NoType; - } - } - return 0; -} - -static struct OMRType *check_supported_returntype(struct dmr_C *C, struct OMRType *type) -{ - (void)C; - if (type->type == RT_AGGREGATE || type->type == RT_FUNCTION || type->type == RT_INT || - type->type == RT_UNSUPPORTED) - return &BadType; - return type; -} - -static int32_t instruction_size_in_bytes(struct dmr_C *C, struct instruction *insn) -{ - return insn->size / C->target->bits_in_char; -} - -static JIT_Type map_OMRtype(struct OMRType *type) -{ - switch (type->type) { - case RT_DOUBLE: - return JIT_Double; - case RT_FLOAT: - return JIT_Float; - case RT_INT8: - return JIT_Int8; - case RT_INT16: - return JIT_Int16; - case RT_INT32: - return JIT_Int32; - case RT_INT64: - return JIT_Int64; - case RT_PTR: - return JIT_Address; - case RT_AGGREGATE: - return JIT_Aggregate; - default: - return JIT_NoType; - } -} - -static JIT_SymbolRef OMR_alloca(struct function *fn, struct OMRType *type, int32_t size, bool reg) -{ - (void)reg; - JIT_Type omr_type = map_OMRtype(type); - // In OMR there is no explicit alloca IL I believe - // Instead we create a local symbol of appropriate size - // We treat all locals as byte arrays - the load/store - // is done at specific offsets as required - if (omr_type == JIT_Aggregate) - return JIT_CreateLocalByteArray(fn->injector, (uint32_t)size); - else - // phi nodes get created as temporaries - return JIT_CreateTemporary(fn->injector, omr_type); -} - -static JIT_NodeRef constant_value(struct dmr_C *C, struct function *fn, unsigned long long val, struct OMRType *dtype) -{ - JIT_NodeRef result = NULL; - - (void)C; - (void)fn; - - switch (dtype->type) { - case RT_INT8: - result = JIT_ConstInt8((int8_t)val); - break; - case RT_INT16: - result = JIT_ConstInt16((int16_t)val); - break; - case RT_INT: - case RT_INT32: - assert(dtype->bit_size <= Int32Type.bit_size); - result = JIT_ConstInt32((int32_t)val); - break; - case RT_INT64: - result = JIT_ConstInt64(val); - break; - case RT_PTR: - result = JIT_ConstAddress((void *)val); - break; - case RT_DOUBLE: - result = JIT_ConstDouble((double)(long long)val); - break; - case RT_FLOAT: - result = JIT_ConstFloat((float)(long long)val); - break; - default: - fprintf(stderr, "unsupported pseudo value kind %d\n", dtype->type); - break; - } - return result; -} - -static JIT_NodeRef constant_fvalue(struct dmr_C *C, struct function *fn, double val, struct OMRType *dtype) -{ - JIT_NodeRef result = NULL; - - (void)C; - (void)fn; - if (dtype->type == RT_DOUBLE) { - result = JIT_ConstDouble(val); - } else if (dtype->type == RT_FLOAT) { - result = JIT_ConstFloat((float)val); - } else { - fprintf(stderr, "unsupported pseudo value kind %d\n", dtype->type); - return NULL; - } - return result; -} - -/* - * We do not support globals or aggregate locals with initializers - */ -static JIT_SymbolRef build_local(struct dmr_C *C, struct function *fn, struct symbol *sym) -{ - const char *name = dmrC_show_ident(C, sym->ident); - struct OMRType *type = get_symnode_type(C, fn, sym); - char localname[256] = {0}; - snprintf(localname, sizeof localname, "%s_%p.", name, sym); - if (dmrC_is_static(sym) || dmrC_is_extern(sym) || dmrC_is_toplevel(sym)) { - return NULL; - } else { - if (sym->initialized && is_aggregate_type(sym)) { - return NULL; - } - JIT_SymbolRef result = OMR_alloca(fn, type, type->bit_size / C->target->bits_in_char, false); - sym->priv = result; - return result; - } -} - -static void build_store(struct dmr_C *C, struct function *fn, JIT_NodeRef v, JIT_SymbolRef symbol) -{ - (void)C; - - if (JIT_IsTemporary(fn->injector, symbol)) { - JIT_StoreToTemporary(fn->injector, symbol, v); - } else { - assert(false); - JIT_ArrayStoreAt(fn->injector, 0, JIT_LoadAddress(fn->injector, symbol), 0, v); - } -} - -static JIT_SymbolRef get_sym_value(struct dmr_C *C, struct function *fn, pseudo_t pseudo, bool do_init) -{ - JIT_SymbolRef result = NULL; - struct symbol *sym = pseudo->sym; - struct expression *expr; - - result = (JIT_SymbolRef)sym->priv; - if (result) - return result; - - assert(sym->bb_target == NULL); - - expr = sym->initializer; - if (expr && (!sym->ident || (sym->ident && (expr->type == EXPR_VALUE || expr->type == EXPR_FVALUE)))) { - switch (expr->type) { - case EXPR_STRING: { - dmrC_sparse_error(C, expr->pos, "unsupported string reference in initializer\n"); - dmrC_show_expression(C, expr); - return NULL; - break; - } - case EXPR_SYMBOL: { - dmrC_sparse_error(C, expr->pos, "unresolved symbol reference in initializer\n"); - dmrC_show_expression(C, expr); - return NULL; - break; - } - case EXPR_VALUE: { - if (dmrC_is_static(sym)) { - dmrC_sparse_error(C, expr->pos, "unsupported symbol reference\n"); - dmrC_show_expression(C, expr); - return NULL; - } - struct OMRType *symtype = get_symnode_type(C, fn, sym); - if (symtype == NULL) { - dmrC_sparse_error(C, expr->pos, "invalid symbol type\n"); - dmrC_show_expression(C, expr); - return NULL; - } - result = build_local(C, fn, sym); - if (!result) - return result; - if (do_init) { - JIT_NodeRef value = constant_value(C, fn, expr->value, symtype); - build_store(C, fn, value, result); - } - sym->priv = result; - break; - } - case EXPR_FVALUE: { - if (dmrC_is_static(sym)) { - dmrC_sparse_error(C, expr->pos, "unsupported symbol reference\n"); - dmrC_show_expression(C, expr); - return NULL; - } - struct OMRType *symtype = get_symnode_type(C, fn, sym); - if (symtype == NULL) { - dmrC_sparse_error(C, expr->pos, "invalid symbol type\n"); - dmrC_show_expression(C, expr); - return NULL; - } - result = build_local(C, fn, sym); - if (!result) - return result; - if (do_init) { - JIT_NodeRef value = constant_fvalue(C, fn, expr->fvalue, symtype); - build_store(C, fn, value, result); - } - sym->priv = result; - break; - } - default: - dmrC_sparse_error(C, expr->pos, "unsupported expr type in initializer: %d\n", expr->type); - dmrC_show_expression(C, expr); - return NULL; - } - } else { - const char *name = dmrC_show_ident(C, sym->ident); - struct OMRType *type = get_symnode_type(C, fn, sym); - if (type->type == RT_FUNCTION) { - result = JIT_GetFunctionSymbol(fn->injector, name); - if (!result) { - dmrC_sparse_error(C, sym->pos, "unsupported symbol reference for '%s'\n", name); - dmrC_debug_symbol(C, sym); - return NULL; - } - } else if (dmrC_is_extern(sym) || dmrC_is_toplevel(sym)) { - dmrC_sparse_error(C, sym->pos, "unsupported symbol reference for '%s'\n", name); - dmrC_debug_symbol(C, sym); - return NULL; - } else { - if (dmrC_is_static(sym)) { - dmrC_sparse_error(C, sym->pos, "unsupported symbol reference for '%s'\n", name); - dmrC_debug_symbol(C, sym); - return NULL; - } - if (dmrC_is_static(sym) && sym->initializer) { - dmrC_sparse_error(C, sym->initializer->pos, - "unsupported initializer for " - "local static variable\n"); - dmrC_show_expression(C, sym->initializer); - return NULL; - } - result = build_local(C, fn, sym); - if (!result) { - dmrC_sparse_error(C, sym->initializer->pos, - "unsupported initializer for " - "local variable because zero initialization is not yet done\n"); - dmrC_show_expression(C, sym->initializer); - return result; - } - sym->priv = result; - } - } - return result; -} - -static JIT_NodeRef val_to_value(struct dmr_C *C, struct function *fn, long long value, struct symbol *ctype) -{ - (void)C; - (void)fn; - - switch (ctype->bit_size) { - case 8: - return JIT_ConstInt8((int8_t)value); - case 16: - return JIT_ConstInt16((int16_t)value); - case 32: - return JIT_ConstInt32((int32_t)value); - case 64: - return JIT_ConstInt64((int64_t)value); - } - fprintf(stderr, "Cannot create a constant of size %d\n", ctype->bit_size); - return NULL; -} - -static JIT_NodeRef pseudo_to_value(struct dmr_C *C, struct function *fn, struct symbol *ctype, pseudo_t pseudo) -{ - JIT_NodeRef result = NULL; - - switch (pseudo->type) { - case PSEUDO_REG: - result = pseudo->priv; - break; - case PSEUDO_SYM: { - JIT_SymbolRef sym = get_sym_value(C, fn, pseudo, true); - if (!sym) - return NULL; - return JIT_LoadAddress(fn->injector, sym); - } - case PSEUDO_VAL: - result = val_to_value(C, fn, pseudo->value, ctype); - break; - case PSEUDO_ARG: - result = JIT_LoadParameter(fn->injector, pseudo->nr - 1); - break; - case PSEUDO_PHI: - result = pseudo->priv; - break; - case PSEUDO_VOID: - result = NULL; - break; - } - if (!result) { - fprintf(stderr, "error: no result for pseudo\n"); - return NULL; - } else if (JIT_GetNodeType(result) == JIT_NoType) { - fprintf(stderr, "error: no result for pseudo\n"); - return NULL; - } - return result; -} - -static JIT_NodeRef truncate_intvalue(struct dmr_C *C, struct function *fn, JIT_NodeRef val, struct OMRType *dtype, - int unsigned_cast) -{ - (void)C; - (void)fn; - (void)unsigned_cast; - - if (JIT_GetNodeType(val) == JIT_Int64 && dtype->bit_size <= 64) { - if (dtype->bit_size == 64) - return val; - uint64_t mask = (1ULL << dtype->bit_size) - 1; - return JIT_CreateNode2C(OP_land, val, JIT_ConstUInt64(mask)); - } else if (JIT_GetNodeType(val) == JIT_Int32 && dtype->bit_size <= 32) { - if (dtype->bit_size == 32) - return val; - uint32_t mask = (1U << dtype->bit_size) - 1; - return JIT_CreateNode2C(OP_iand, val, JIT_ConstUInt32(mask)); - } else { - return NULL; - } -} - -static JIT_NodeRef convert_to(struct function *fn, JIT_NodeRef val, JIT_Type target_type, int unsigned_cast) -{ - if (target_type == JIT_NoType) - return NULL; - JIT_NodeRef node = JIT_ConvertTo(fn->injector, val, target_type, unsigned_cast); - if (JIT_GetNodeType(node) == JIT_NoType) - return NULL; - return node; -} - -static JIT_NodeRef build_cast(struct dmr_C *C, struct function *fn, JIT_NodeRef val, struct OMRType *dtype, - int unsigned_cast) -{ - if (dtype->type == RT_INT) - return truncate_intvalue(C, fn, val, dtype, unsigned_cast); - - JIT_Type target_type = map_OMRtype(dtype); - return convert_to(fn, val, target_type, unsigned_cast); -} - -static JIT_NodeRef output_op_phi(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_SymbolRef ptr = insn->target->priv2; - (void)C; - - if (!ptr) - return NULL; - - // Unlike LLVM version which creates the Load instruction - // early on and inserts it into the IR stream here, we - // create the Load instruction here. - JIT_NodeRef load = NULL; - // Model phi values as temporaries - load = JIT_LoadTemporary(fn->injector, ptr); - if (load == NULL) - return NULL; - assert(JIT_GetNodeType(load) != JIT_NoType); - insn->target->priv = load; - return load; -} - -static JIT_NodeRef output_op_load(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef ptr = pseudo_to_value(C, fn, insn->type, insn->src); - JIT_NodeRef load = NULL; - - if (!ptr) - return NULL; - - if (insn->orig_type && dmrC_is_simple_type(C->S, insn->orig_type) && !dmrC_is_ptr_type(insn->orig_type)) { - JIT_SymbolRef symref = insn->orig_type->priv; - if (symref && JIT_IsTemporary(fn->injector, symref)) - load = JIT_LoadTemporary(fn->injector, symref); - } - - if (!load) { - // JIT_SymbolRef symref = NULL; - uint64_t symref = (uint64_t)insn->orig_type; - - // JIT_NodeRef index = JIT_ConstInt64((int64_t)insn->offset); - int64_t index = (int64_t)insn->offset; - switch (insn->size) { - case 8: - // TODO do we need to do unsigned here? - load = JIT_ArrayLoadAt(fn->injector, symref, ptr, index, JIT_Int8); - break; - case 16: - // TODO do we need to do unsigned here? - load = JIT_ArrayLoadAt(fn->injector, symref, ptr, index, JIT_Int16); - break; - case 32: - if (dmrC_is_float_type(C->S, insn->type)) - load = JIT_ArrayLoadAt(fn->injector, symref, ptr, index, JIT_Float); - else - load = JIT_ArrayLoadAt(fn->injector, symref, ptr, index, JIT_Int32); - break; - case 64: - if (dmrC_is_float_type(C->S, insn->type)) - load = JIT_ArrayLoadAt(fn->injector, symref, ptr, index, JIT_Double); - else if (dmrC_is_ptr_type(insn->type)) - load = JIT_ArrayLoadAt(fn->injector, symref, ptr, index, JIT_Address); - else - load = JIT_ArrayLoadAt(fn->injector, symref, ptr, index, JIT_Int64); - break; - } - } - if (load == NULL) - return NULL; - assert(JIT_GetNodeType(load) != JIT_NoType); - insn->target->priv = load; - return load; -} - -static JIT_NodeRef output_op_store(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef ptr, target_in; - - if (is_aggregate_type(insn->type)) { - dmrC_sparse_error(C, insn->pos, - "store to aggregate type is " - "not yet supported, failure at " - "insn %s\n", - dmrC_show_instruction(C, insn)); - return NULL; - } - - target_in = pseudo_to_value(C, fn, insn->type, insn->target); - if (!target_in) - return NULL; - - if (insn->orig_type && dmrC_is_simple_type(C->S, insn->orig_type) && !dmrC_is_ptr_type(insn->orig_type)) { - JIT_SymbolRef symref = insn->orig_type->priv; - if (symref && JIT_IsTemporary(fn->injector, symref)) { - JIT_StoreToTemporary(fn->injector, symref, target_in); - return target_in; - } - } - - /* Following causes test failures -- To be investgated */ - //if (insn->src->type == PSEUDO_SYM) { - // JIT_SymbolRef symref = get_sym_value(C, fn, insn->src, true); - // if (symref && JIT_IsTemporary(fn->injector, symref)) { - // JIT_StoreToTemporary(fn->injector, symref, target_in); - // return target_in; - // } - //} - - ptr = pseudo_to_value(C, fn, insn->type, insn->src); - if (!ptr) - return NULL; - ptr = build_cast(C, fn, ptr, &PtrType, 0); - int64_t index = (int64_t)insn->offset; - assert(JIT_GetNodeType(ptr) == JIT_Address); - uint64_t symref = (uint64_t)insn->orig_type; - JIT_ArrayStoreAt(fn->injector, symref, ptr, index, target_in); - return target_in; -} - -static JIT_NodeRef output_op_phisrc(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef v; - struct instruction *phi; - - assert(insn->target->priv == NULL); - - /* target = src */ - v = pseudo_to_value(C, fn, insn->type, insn->phi_src); - if (!v) - return NULL; - - FOR_EACH_PTR(insn->phi_users, phi) - { - JIT_SymbolRef symref; - - assert(phi->opcode == OP_PHI); - /* phi must be load from alloca */ - symref = phi->target->priv2; - if (!symref) - return NULL; - /* We do the convert below because Sparse treats pointers and - integers as interchangeable - but OMR doesn't - so saving to a - pointer can fail due to type mismatch */ - JIT_StoreToTemporary(fn->injector, symref, convert_to(fn, v, JIT_GetSymbolType(symref), true)); - } - END_FOR_EACH_PTR(phi); - return v; -} - -/** - * Convert the pseudo to a value, and cast it to the expected type of the - * instruction. If ptrtoint is true then convert pointer values to integers. - */ -static JIT_NodeRef get_operand(struct dmr_C *C, struct function *fn, struct symbol *ctype, pseudo_t pseudo, - bool ptrtoint, bool unsigned_cast) -{ - JIT_NodeRef target; - struct OMRType *instruction_type = get_symnode_or_basetype(C, fn, ctype); - (void)ptrtoint; - (void)unsigned_cast; - if (instruction_type == NULL) - return NULL; - target = pseudo_to_value(C, fn, ctype, pseudo); - if (!target) - return NULL; - return target; -} - -static struct symbol *pseudo_type(struct dmr_C *C, pseudo_t pseudo) -{ - switch (pseudo->type) { - case PSEUDO_SYM: - case PSEUDO_ARG: - return pseudo->sym; - case PSEUDO_REG: - case PSEUDO_PHI: - return pseudo->def->type; - case PSEUDO_VAL: - return C->target->size_t_ctype; - case PSEUDO_VOID: - default: - return &C->S->void_ctype; - } -} - -static JIT_NodeRef output_op_cbr(struct dmr_C *C, struct function *fn, struct instruction *br) -{ - JIT_NodeRef value = pseudo_to_value(C, fn, br->type, br->cond); - if (!value) - return NULL; - // JIT_GenerateTreeTop(fn->injector, value); - JIT_BlockRef true_block = JIT_GetBlock(fn->injector, br->bb_true->nr); - JIT_BlockRef false_block = JIT_GetBlock(fn->injector, br->bb_false->nr); - JIT_NodeRef if_node = JIT_IfNotZeroValue(fn->injector, value, true_block); - // OMR expects the code to fall through to next block here - // which is assumed to be the else block - // But we want to handle false block explicitly - // During the initial scan we already accounted for extra block here - int fallthrough_blocknum = br->bb->nr + 1; // Next block is meant to be a fallthrough block - JIT_BlockRef fallthrough_block = JIT_GetBlock(fn->injector, fallthrough_blocknum); - // Add an edge from current block to fallthrough block - JIT_CFGAddEdge(fn->injector, JIT_BlockAsCFGNode(JIT_GetCurrentBlock(fn->injector)), - JIT_BlockAsCFGNode(fallthrough_block)); - // Switch to fallthrough block - JIT_SetCurrentBlock(fn->injector, fallthrough_blocknum); - // In the fallthrough block we only need a goto - JIT_Goto(fn->injector, false_block); - return if_node; -} - -static JIT_NodeRef is_neq_zero(struct dmr_C *C, struct function *fn, JIT_NodeRef value) -{ - JIT_NodeRef cond = NULL; - JIT_Type value_type = JIT_GetNodeType(value); - (void)C; - switch (value_type) { - case JIT_Int32: - cond = JIT_CreateNode2C(OP_icmpne, value, JIT_ZeroValue(fn->injector, JIT_Int32)); - break; - - case JIT_Int64: - cond = JIT_CreateNode2C(OP_lcmpne, value, JIT_ZeroValue(fn->injector, JIT_Int64)); - break; - - case JIT_Int16: - cond = JIT_CreateNode2C(OP_scmpne, value, JIT_ZeroValue(fn->injector, JIT_Int16)); - break; - - case JIT_Int8: - cond = JIT_CreateNode2C(OP_bcmpne, value, JIT_ZeroValue(fn->injector, JIT_Int8)); - break; - - case JIT_Address: - cond = JIT_CreateNode2C(OP_acmpne, value, JIT_ZeroValue(fn->injector, JIT_Address)); - break; - - case JIT_Double: - cond = JIT_CreateNode2C(OP_dcmpneu, value, JIT_ZeroValue(fn->injector, JIT_Double)); - break; - - case JIT_Float: - cond = JIT_CreateNode2C(OP_fcmpneu, value, JIT_ZeroValue(fn->injector, JIT_Float)); - break; - default: - fprintf(stderr, "Cannot construct a zero object of JIT type %d\n", value_type); - break; - } - return cond; -} - -static JIT_NodeRef output_op_compare(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef lhs, rhs, target = NULL; - - if (insn->src1->type == PSEUDO_VAL) - lhs = val_to_value(C, fn, insn->src1->value, pseudo_type(C, insn->src2)); - else - lhs = pseudo_to_value(C, fn, insn->type, insn->src1); - if (!lhs) - return NULL; - if (insn->src2->type == PSEUDO_VAL) - rhs = val_to_value(C, fn, insn->src2->value, pseudo_type(C, insn->src1)); - else - rhs = pseudo_to_value(C, fn, insn->type, insn->src2); - if (!rhs) - return NULL; - - struct OMRType *dst_type = insn_symbol_type(C, fn, insn); - if (!dst_type) - return NULL; - - JIT_Type op_type = JIT_GetNodeType(lhs); - - switch (insn->opcode) { - case OP_SET_LT: - if (op_type == JIT_Double) - target = JIT_CreateNode2C(OP_dcmplt, lhs, rhs); - else if (op_type == JIT_Float) - target = JIT_CreateNode2C(OP_fcmplt, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_lcmplt, lhs, rhs); - else if (op_type == JIT_Int32) - target = JIT_CreateNode2C(OP_icmplt, lhs, rhs); - else if (op_type == JIT_Int16) - target = JIT_CreateNode2C(OP_scmplt, lhs, rhs); - else if (op_type == JIT_Int8) - target = JIT_CreateNode2C(OP_bcmplt, lhs, rhs); - else if (op_type == JIT_Address) - target = JIT_CreateNode2C(OP_acmplt, convert_to(fn, lhs, JIT_Address, true), - convert_to(fn, rhs, JIT_Address, true)); - break; - case OP_SET_B: - if (op_type == JIT_Double) - target = JIT_CreateNode2C(OP_dcmplt, lhs, rhs); - else if (op_type == JIT_Float) - target = JIT_CreateNode2C(OP_fcmplt, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_lucmplt, lhs, rhs); - else if (op_type == JIT_Int32) - target = JIT_CreateNode2C(OP_iucmplt, lhs, rhs); - else if (op_type == JIT_Int16) - target = JIT_CreateNode2C(OP_sucmplt, lhs, rhs); - else if (op_type == JIT_Int8) - target = JIT_CreateNode2C(OP_bucmplt, lhs, rhs); - else if (op_type == JIT_Address) - target = JIT_CreateNode2C(OP_acmplt, convert_to(fn, lhs, JIT_Address, true), - convert_to(fn, rhs, JIT_Address, true)); - break; - case OP_SET_LE: - if (op_type == JIT_Double) - target = JIT_CreateNode2C(OP_dcmple, lhs, rhs); - else if (op_type == JIT_Float) - target = JIT_CreateNode2C(OP_fcmple, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_lcmple, lhs, rhs); - else if (op_type == JIT_Int32) - target = JIT_CreateNode2C(OP_icmple, lhs, rhs); - else if (op_type == JIT_Int16) - target = JIT_CreateNode2C(OP_scmple, lhs, rhs); - else if (op_type == JIT_Int8) - target = JIT_CreateNode2C(OP_bcmple, lhs, rhs); - else if (op_type == JIT_Address) - target = JIT_CreateNode2C(OP_acmple, convert_to(fn, lhs, JIT_Address, true), - convert_to(fn, rhs, JIT_Address, true)); - break; - case OP_SET_BE: - if (op_type == JIT_Double) - target = JIT_CreateNode2C(OP_dcmple, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_fcmple, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_lucmple, lhs, rhs); - else if (op_type == JIT_Int32) - target = JIT_CreateNode2C(OP_iucmple, lhs, rhs); - else if (op_type == JIT_Int16) - target = JIT_CreateNode2C(OP_sucmple, lhs, rhs); - else if (op_type == JIT_Int8) - target = JIT_CreateNode2C(OP_bucmple, lhs, rhs); - else if (op_type == JIT_Address) - target = JIT_CreateNode2C(OP_acmple, convert_to(fn, lhs, JIT_Address, true), - convert_to(fn, rhs, JIT_Address, true)); - break; - case OP_SET_GT: - if (op_type == JIT_Double) - target = JIT_CreateNode2C(OP_dcmpgt, lhs, rhs); - else if (op_type == JIT_Float) - target = JIT_CreateNode2C(OP_fcmpgt, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_lcmpgt, lhs, rhs); - else if (op_type == JIT_Int32) - target = JIT_CreateNode2C(OP_icmpgt, lhs, rhs); - else if (op_type == JIT_Int16) - target = JIT_CreateNode2C(OP_scmpgt, lhs, rhs); - else if (op_type == JIT_Int8) - target = JIT_CreateNode2C(OP_bcmpgt, lhs, rhs); - else if (op_type == JIT_Address) - target = JIT_CreateNode2C(OP_acmpgt, convert_to(fn, lhs, JIT_Address, true), - convert_to(fn, rhs, JIT_Address, true)); - break; - case OP_SET_A: - if (op_type == JIT_Double) - target = JIT_CreateNode2C(OP_dcmpgt, lhs, rhs); - else if (op_type == JIT_Float) - target = JIT_CreateNode2C(OP_fcmpgt, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_lucmpgt, lhs, rhs); - else if (op_type == JIT_Int32) - target = JIT_CreateNode2C(OP_iucmpgt, lhs, rhs); - else if (op_type == JIT_Int16) - target = JIT_CreateNode2C(OP_sucmpgt, lhs, rhs); - else if (op_type == JIT_Int8) - target = JIT_CreateNode2C(OP_bucmpgt, lhs, rhs); - else if (op_type == JIT_Address) - target = JIT_CreateNode2C(OP_acmpgt, convert_to(fn, lhs, JIT_Address, true), - convert_to(fn, rhs, JIT_Address, true)); - break; - case OP_SET_GE: - if (op_type == JIT_Double) - target = JIT_CreateNode2C(OP_dcmpge, lhs, rhs); - else if (op_type == JIT_Float) - target = JIT_CreateNode2C(OP_fcmpge, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_lcmpge, lhs, rhs); - else if (op_type == JIT_Int32) - target = JIT_CreateNode2C(OP_icmpge, lhs, rhs); - else if (op_type == JIT_Int16) - target = JIT_CreateNode2C(OP_scmpge, lhs, rhs); - else if (op_type == JIT_Int8) - target = JIT_CreateNode2C(OP_bcmpge, lhs, rhs); - else if (op_type == JIT_Address) - target = JIT_CreateNode2C(OP_acmpge, convert_to(fn, lhs, JIT_Address, true), - convert_to(fn, rhs, JIT_Address, true)); - break; - case OP_SET_AE: - if (op_type == JIT_Double) - target = JIT_CreateNode2C(OP_dcmpge, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_fcmpge, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_lucmpge, lhs, rhs); - else if (op_type == JIT_Int32) - target = JIT_CreateNode2C(OP_iucmpge, lhs, rhs); - else if (op_type == JIT_Int16) - target = JIT_CreateNode2C(OP_sucmpge, lhs, rhs); - else if (op_type == JIT_Int8) - target = JIT_CreateNode2C(OP_bucmpge, lhs, rhs); - else if (op_type == JIT_Address) - target = JIT_CreateNode2C(OP_acmpge, convert_to(fn, lhs, JIT_Address, true), - convert_to(fn, rhs, JIT_Address, true)); - break; - case OP_SET_EQ: - if (op_type == JIT_Double) - target = JIT_CreateNode2C(OP_dcmpeq, lhs, rhs); - else if (op_type == JIT_Float) - target = JIT_CreateNode2C(OP_fcmpeq, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_lcmpeq, lhs, rhs); - else if (op_type == JIT_Int32) - target = JIT_CreateNode2C(OP_icmpeq, lhs, rhs); - else if (op_type == JIT_Int16) - target = JIT_CreateNode2C(OP_scmpeq, lhs, rhs); - else if (op_type == JIT_Int8) - target = JIT_CreateNode2C(OP_bcmpeq, lhs, rhs); - else if (op_type == JIT_Address) - target = JIT_CreateNode2C(OP_acmpeq, convert_to(fn, lhs, JIT_Address, true), - convert_to(fn, rhs, JIT_Address, true)); - break; - case OP_SET_NE: - if (op_type == JIT_Double) - target = JIT_CreateNode2C(OP_dcmpneu, lhs, rhs); - else if (op_type == JIT_Float) - target = JIT_CreateNode2C(OP_fcmpneu, lhs, rhs); - else if (op_type == JIT_Int64) - target = JIT_CreateNode2C(OP_lcmpne, lhs, rhs); - else if (op_type == JIT_Int32) - target = JIT_CreateNode2C(OP_icmpne, lhs, rhs); - else if (op_type == JIT_Int16) - target = JIT_CreateNode2C(OP_scmpne, lhs, rhs); - else if (op_type == JIT_Int8) - target = JIT_CreateNode2C(OP_bcmpne, lhs, rhs); - else if (op_type == JIT_Address) - target = JIT_CreateNode2C(OP_acmpne, convert_to(fn, lhs, JIT_Address, true), - convert_to(fn, rhs, JIT_Address, true)); - break; - default: - break; - } - assert(JIT_GetNodeType(target) != JIT_NoType); - insn->target->priv = target; - return target; -} - -static JIT_NodeRef output_op_binary(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef lhs, rhs, target = NULL; - - // TODO is this enough or do we need special unsigned opcodes? - bool unsigned_op = insn->opcode == OP_MULU || insn->opcode == OP_DIVU || insn->opcode == OP_MODU; - - lhs = get_operand(C, fn, insn->type, insn->src1, 1, unsigned_op); - if (!lhs) - return NULL; - - rhs = get_operand(C, fn, insn->type, insn->src2, 1, unsigned_op); - if (!rhs) - return NULL; - - switch (insn->opcode) { - /* Binary */ - case OP_ADD: - switch (insn->size) { - case 64: - if (dmrC_is_float_type(C->S, insn->type)) - target = JIT_CreateNode2C(OP_dadd, lhs, rhs); - else { - if (JIT_GetNodeType(lhs) == JIT_Address) { - if (JIT_GetNodeType(rhs) == JIT_Int64) { - target = JIT_CreateNode2C(OP_aladd, lhs, rhs); - } else if (JIT_GetNodeType(rhs) == JIT_Int32) { - target = JIT_CreateNode2C(OP_aiadd, lhs, rhs); - } else { - dmrC_sparse_error(C, insn->pos, - "The add operand for a " - "pointer value must be " - "int64 or int32\n"); - } - } else if (JIT_GetNodeType(rhs) == JIT_Address) { - if (JIT_GetNodeType(lhs) == JIT_Int64) { - target = JIT_CreateNode2C(OP_aladd, rhs, lhs); - } else if (JIT_GetNodeType(lhs) == JIT_Int32) { - target = JIT_CreateNode2C(OP_aiadd, rhs, lhs); - } else { - dmrC_sparse_error(C, insn->pos, - "The add operand for a " - "pointer value must be " - "int64 or int32\n"); - } - } else - target = JIT_CreateNode2C(OP_ladd, lhs, rhs); - } - break; - case 32: - if (dmrC_is_float_type(C->S, insn->type)) - target = JIT_CreateNode2C(OP_fadd, lhs, rhs); - else - target = JIT_CreateNode2C(OP_iadd, lhs, rhs); - break; - } - break; - case OP_SUB: - switch (insn->size) { - case 64: - if (dmrC_is_float_type(C->S, insn->type)) - target = JIT_CreateNode2C(OP_dsub, lhs, rhs); - else { - if (JIT_GetNodeType(lhs) == JIT_Address && JIT_GetNodeType(rhs) == JIT_Address) { - // target = JIT_CreateNode2C(OP_asub, - // lhs, rhs); - // For some reason above is returning - // NoType? - target = - JIT_CreateNode2C(OP_lsub, JIT_ConvertTo(fn->injector, lhs, JIT_Int64, true), - JIT_ConvertTo(fn->injector, rhs, JIT_Int64, true)); - assert(JIT_GetNodeType(target) != JIT_NoType); - } - /* Since OMR only supports adding integer to a - pointer, but C allows integer subtraction as - well - we convert the op to an pointer add with - negative offset. C allows the - address to lhs or rhs - meaning is the same */ - else if (JIT_GetNodeType(lhs) == JIT_Address) { - if (JIT_GetNodeType(rhs) == JIT_Int64) { - target = - JIT_CreateNode2C(OP_aladd, lhs, JIT_CreateNode1C(OP_lneg, rhs)); - assert(JIT_GetNodeType(target) != JIT_NoType); - } else if (JIT_GetNodeType(rhs) == JIT_Int32) { - target = - JIT_CreateNode2C(OP_aiadd, lhs, JIT_CreateNode1C(OP_ineg, rhs)); - assert(JIT_GetNodeType(target) != JIT_NoType); - } else { - dmrC_sparse_error(C, insn->pos, - "The add operand for a " - "pointer value must be " - "int64 or int32\n"); - } - } else if (JIT_GetNodeType(rhs) == JIT_Address) { - if (JIT_GetNodeType(lhs) == JIT_Int64) { - target = - JIT_CreateNode2C(OP_aladd, rhs, JIT_CreateNode1C(OP_lneg, lhs)); - assert(JIT_GetNodeType(target) != JIT_NoType); - } else if (JIT_GetNodeType(lhs) == JIT_Int32) { - target = - JIT_CreateNode2C(OP_aiadd, rhs, JIT_CreateNode1C(OP_ineg, lhs)); - assert(JIT_GetNodeType(target) != JIT_NoType); - } else { - dmrC_sparse_error(C, insn->pos, - "The add operand for a " - "pointer value must be " - "int64 or int32\n"); - } - } else { - target = JIT_CreateNode2C(OP_lsub, lhs, rhs); - assert(JIT_GetNodeType(target) != JIT_NoType); - } - } - break; - case 32: - if (dmrC_is_float_type(C->S, insn->type)) - target = JIT_CreateNode2C(OP_fsub, lhs, rhs); - else - target = JIT_CreateNode2C(OP_isub, lhs, rhs); - break; - } - break; - case OP_MULU: - assert(JIT_GetNodeType(lhs) != JIT_Address && JIT_GetNodeType(rhs) != JIT_Address); - switch (insn->size) { - case 64: - if (dmrC_is_float_type(C->S, insn->type)) - target = JIT_CreateNode2C(OP_dmul, lhs, rhs); - else - target = JIT_CreateNode2C(OP_lmul, lhs, rhs); - break; - case 32: - if (dmrC_is_float_type(C->S, insn->type)) - target = JIT_CreateNode2C(OP_fmul, lhs, rhs); - else - target = JIT_CreateNode2C(OP_iumul, lhs, rhs); - break; - } - break; - case OP_MULS: - assert(JIT_GetNodeType(lhs) != JIT_Address && JIT_GetNodeType(rhs) != JIT_Address); - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_lmul, lhs, rhs); - break; - case 32: - target = JIT_CreateNode2C(OP_imul, lhs, rhs); - break; - } - break; - case OP_DIVU: - assert(JIT_GetNodeType(lhs) != JIT_Address && JIT_GetNodeType(rhs) != JIT_Address); - switch (insn->size) { - case 64: - if (dmrC_is_float_type(C->S, insn->type)) - target = JIT_CreateNode2C(OP_ddiv, lhs, rhs); - else - target = JIT_CreateNode2C(OP_ludiv, lhs, rhs); - break; - case 32: - if (dmrC_is_float_type(C->S, insn->type)) - target = JIT_CreateNode2C(OP_fdiv, lhs, rhs); - else - target = JIT_CreateNode2C(OP_iudiv, lhs, rhs); - break; - } - break; - case OP_DIVS: - assert(JIT_GetNodeType(lhs) != JIT_Address && JIT_GetNodeType(rhs) != JIT_Address); - switch (insn->size) { - case 64: - if (JIT_GetNodeType(lhs) != JIT_Int64 || JIT_GetNodeType(rhs) != JIT_Int64) { - target = NULL; - } else - target = JIT_CreateNode2C(OP_ldiv, lhs, rhs); - break; - case 32: - target = JIT_CreateNode2C(OP_idiv, lhs, rhs); - break; - } - break; - - case OP_MODS: - case OP_MODU: - assert(!dmrC_is_float_type(C->S, insn->type)); - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_lrem, lhs, rhs); - break; - case 32: - target = JIT_CreateNode2C(OP_irem, lhs, rhs); - break; - } - break; - case OP_SHL: - assert(!dmrC_is_float_type(C->S, insn->type)); - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_lshl, lhs, rhs); - break; - case 32: - target = JIT_CreateNode2C(OP_ishl, lhs, rhs); - break; - } - break; - case OP_LSR: - assert(!dmrC_is_float_type(C->S, insn->type)); - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_lshr, lhs, rhs); - break; - case 32: - target = JIT_CreateNode2C(OP_ishr, lhs, rhs); - break; - } - break; - case OP_ASR: - assert(!dmrC_is_float_type(C->S, insn->type)); - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_lshr, lhs, rhs); - break; - case 32: - target = JIT_CreateNode2C(OP_ishr, lhs, rhs); - break; - } - break; - - /* Logical */ - case OP_AND: - assert(!dmrC_is_float_type(C->S, insn->type)); - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_land, lhs, rhs); - break; - case 32: - target = JIT_CreateNode2C(OP_iand, lhs, rhs); - break; - } - break; - case OP_OR: - assert(!dmrC_is_float_type(C->S, insn->type)); - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_lor, lhs, rhs); - break; - case 32: - target = JIT_CreateNode2C(OP_ior, lhs, rhs); - break; - } - break; - case OP_XOR: - assert(!dmrC_is_float_type(C->S, insn->type)); - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_lxor, lhs, rhs); - break; - case 32: - target = JIT_CreateNode2C(OP_ixor, lhs, rhs); - break; - } - break; - case OP_AND_BOOL: { - JIT_NodeRef lhs_nz, rhs_nz; - struct OMRType *dst_type; - - lhs_nz = is_neq_zero(C, fn, lhs); - rhs_nz = is_neq_zero(C, fn, rhs); - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_land, lhs_nz, rhs_nz); - break; - case 1: - case 32: - target = JIT_CreateNode2C(OP_iand, lhs_nz, rhs_nz); - break; - } - if (!target) - return NULL; - dst_type = insn_symbol_type(C, fn, insn); - if (!dst_type) - return NULL; - target = build_cast(C, fn, target, dst_type, 1); - break; - } - case OP_OR_BOOL: { - JIT_NodeRef lhs_nz, rhs_nz; - struct OMRType *dst_type; - - lhs_nz = is_neq_zero(C, fn, lhs); - rhs_nz = is_neq_zero(C, fn, rhs); - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_lor, lhs_nz, rhs_nz); - break; - case 1: - case 32: - target = JIT_CreateNode2C(OP_ior, lhs_nz, rhs_nz); - break; - } - if (!target) - return NULL; - dst_type = insn_symbol_type(C, fn, insn); - if (!dst_type) - return NULL; - target = build_cast(C, fn, target, dst_type, 1); - break; - } - } - assert(JIT_GetNodeType(target) != JIT_NoType); - insn->target->priv = target; - - return target; -} - -static JIT_NodeRef output_op_setval(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - struct expression *expr = insn->val; - struct OMRType *const_type; - JIT_NodeRef target = NULL; - - if (!expr) - return NULL; - - const_type = insn_symbol_type(C, fn, insn); - if (!const_type) - return NULL; - - switch (expr->type) { - case EXPR_FVALUE: - target = constant_fvalue(C, fn, expr->fvalue, const_type); - break; - default: - dmrC_sparse_error(C, insn->pos, "unsupported expression type %d in setval\n", expr->type); - dmrC_show_expression(C, expr); - return NULL; - } - assert(JIT_GetNodeType(target) != JIT_NoType); - insn->target->priv = target; - - return target; -} - -static JIT_NodeRef output_op_symaddr(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef res, src; - struct OMRType *dtype; - JIT_SymbolRef sym; - - src = pseudo_to_value(C, fn, insn->type, insn->symbol); - if (!src) - return NULL; - - /* We need to tell the backend if a local var has had its - address taken */ - if (insn->symbol->type == PSEUDO_SYM) { - sym = get_sym_value(C, fn, insn->symbol, true); - if (sym) - JIT_SetAutoAddressTaken(fn->injector, sym); - } - - dtype = get_symnode_or_basetype(C, fn, insn->type); - if (!dtype) - return NULL; - - res = build_cast(C, fn, src, dtype, 0); - assert(JIT_GetNodeType(res) != JIT_NoType); - insn->target->priv = res; - - return res; -} - -static struct symbol *get_function_basetype(struct symbol *type) -{ - if (type->type == SYM_PTR) - type = type->ctype.base_type; - assert(type->type == SYM_FN); - return type; -} - -static JIT_NodeRef output_op_call(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef target; - int n_arg = 0, i; - struct pseudo *arg; - JIT_NodeRef *args; - - n_arg = ptrlist_size((struct ptr_list *)insn->arguments); - args = alloca(n_arg * sizeof(JIT_NodeRef)); - struct symbol *ftype = get_function_basetype(insn->fntype); - - i = 0; - FOR_EACH_PTR(insn->arguments, arg) - { - JIT_NodeRef value; - struct symbol *atype; - - atype = dmrC_get_nth_symbol(ftype->arguments, i); - value = NULL; - if (arg->type == PSEUDO_VAL) { - /* Value pseudos do not have type information. */ - /* Use the function prototype to get the type. */ - if (atype) - value = val_to_value(C, fn, arg->value, atype); - else { - struct OMRType *type = int_type_by_size(fn, arg->size); - if (!type) { - dmrC_sparse_error(C, insn->pos, - "pseudo value argument[%d] = %lld " - "has invalid size %d\n", - i + 1, arg->value, arg->size); - } else { - value = constant_value(C, fn, arg->value, type); - } - } - } else { - value = pseudo_to_value(C, fn, atype, arg); - } - if (!value) - return NULL; - if (atype) { - struct OMRType *argtype = get_symnode_type(C, fn, atype); - if (!argtype) - return NULL; - value = build_cast(C, fn, value, argtype, 0); - if (!value) - return NULL; - } - args[i++] = value; - } - END_FOR_EACH_PTR(arg); - - if (insn->func->type == PSEUDO_SYM) { - struct symbol *sym = insn->func->sym; - const char *name = dmrC_show_ident(C, sym->ident); - struct OMRType *type = get_symnode_type(C, fn, sym); - if (type->type != RT_FUNCTION) { - return NULL; - } - target = JIT_Call(fn->injector, name, i, args); - } - else { - JIT_NodeRef funcptr = pseudo_to_value(C, fn, insn->type, insn->func); - if (funcptr == NULL || JIT_GetNodeType(funcptr) != JIT_Address) { - return NULL; - } - struct OMRType *function_type = type_to_OMRtype(C, fn, ftype, NULL); - JIT_Type jit_return_type = map_OMRtype(function_type->return_type); - target = JIT_IndirectCall(fn->injector, funcptr, jit_return_type, i, args); - } - if (JIT_GetNodeType(target) != JIT_NoType) - insn->target->priv = target; - return target; -} - -static JIT_NodeRef output_op_not(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef src, target; - - src = pseudo_to_value(C, fn, insn->type, insn->src); - if (!src) - return NULL; - - switch (insn->size) { - case 64: - target = JIT_CreateNode2C(OP_lxor, src, JIT_ConstInt64(0xFFFFFFFFFFFFFFFFLL)); - break; - case 32: - target = JIT_CreateNode2C(OP_ixor, src, JIT_ConstInt32(0xFFFFFFFF)); - break; - case 16: - target = JIT_CreateNode2C(OP_sxor, src, JIT_ConstInt16(0xFFFF)); - break; - case 8: - target = JIT_CreateNode2C(OP_bxor, src, JIT_ConstInt8(0xFF)); - break; - } - assert(JIT_GetNodeType(target) != JIT_NoType); - insn->target->priv = target; - - return target; -} - -static JIT_NodeRef output_op_neg(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef src, target; - - src = pseudo_to_value(C, fn, insn->type, insn->src); - if (!src) - return NULL; - - target = NULL; - if (dmrC_is_float_type(C->S, insn->type)) { - switch (insn->size) { - case 64: - target = JIT_CreateNode1C(OP_dneg, src); - break; - case 32: - target = JIT_CreateNode1C(OP_fneg, src); - break; - } - } else { - switch (insn->size) { - case 64: - target = JIT_CreateNode1C(OP_lneg, src); - break; - case 32: - target = JIT_CreateNode1C(OP_ineg, src); - break; - case 16: - target = JIT_CreateNode1C(OP_sneg, src); - break; - case 8: - target = JIT_CreateNode1C(OP_bneg, src); - break; - } - } - assert(JIT_GetNodeType(target) != JIT_NoType); - insn->target->priv = target; - - return target; -} - -static JIT_NodeRef output_op_sel(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef target, src1, src2, src3; - - src1 = pseudo_to_value(C, fn, insn->type, insn->src1); - if (!src1) - return NULL; - - src1 = is_neq_zero(C, fn, src1); - if (!src1) - return NULL; - - src2 = get_operand(C, fn, insn->type, insn->src2, 0, 0); - if (!src2) - return NULL; - src3 = get_operand(C, fn, insn->type, insn->src3, 0, 0); - if (!src3) - return NULL; - - struct OMRType *insntype = insn_symbol_type(C, fn, insn); - JIT_Type target_type = map_OMRtype(insntype); - JIT_NodeOpCode op_code; - switch (target_type) { - case JIT_Int32: - op_code = OP_iternary; - break; - case JIT_Int64: - op_code = OP_lternary; - break; - case JIT_Int16: - op_code = OP_sternary; - break; - case JIT_Int8: - op_code = OP_bternary; - break; - case JIT_Address: - op_code = OP_aternary; - break; - case JIT_Float: - op_code = OP_fternary; - break; - case JIT_Double: - op_code = OP_dternary; - break; - default: - // TODO error message - return NULL; - } - target = JIT_CreateNode3C(op_code, src1, src2, src3); - assert(JIT_GetNodeType(target) != JIT_NoType); - insn->target->priv = target; - return target; -} - -static JIT_NodeRef output_op_fpcast(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef src, target; - struct OMRType *dtype; - struct symbol *otype = insn->orig_type; - - src = insn->src->priv; - if (!src) - src = pseudo_to_value(C, fn, insn->type, insn->src); - if (!src) - return NULL; - - dtype = insn_symbol_type(C, fn, insn); - if (!dtype) - return NULL; - - target = build_cast(C, fn, src, dtype, !dmrC_is_signed_type(otype)); - assert(JIT_GetNodeType(target) != JIT_NoType); - insn->target->priv = target; - - return target; -} - -static JIT_NodeRef output_op_switch(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef switch_value; - struct basic_block *default_bb = NULL; - struct multijmp *jmp; - int n_jmp = 0; - - FOR_EACH_PTR(insn->multijmp_list, jmp) - { - if (jmp->begin <= jmp->end) { /* case M..N */ - n_jmp += (int)(jmp->end - jmp->begin) + 1; - } else /* default case */ - default_bb = jmp->target; - } - END_FOR_EACH_PTR(jmp); - - if (!default_bb) - return NULL; - - switch_value = pseudo_to_value(C, fn, insn->type, insn->target); - if (!switch_value) - return NULL; - - int32_t *values = alloca(n_jmp * sizeof(int32_t)); - JIT_BlockRef *blocks = alloca(n_jmp * sizeof(JIT_BlockRef)); - - int i = 0; - FOR_EACH_PTR(insn->multijmp_list, jmp) - { - long long val; - for (val = jmp->begin; val <= jmp->end; val++) { - if (val < INT_MIN || val > INT_MAX) - return NULL; - - values[i] = (int32_t)val; - blocks[i] = JIT_GetBlock(fn->injector, jmp->target->nr); - i++; - } - } - END_FOR_EACH_PTR(jmp); - - return JIT_Switch(fn->injector, switch_value, JIT_GetBlock(fn->injector, default_bb->nr), n_jmp, blocks, - values); -} - -static JIT_NodeRef output_op_ptrcast(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef src, target; - struct OMRType *dtype; - struct symbol *otype = insn->orig_type; - - assert(dmrC_is_ptr_type(insn->type)); - - src = insn->src->priv; - if (!src) - src = get_operand(C, fn, otype, insn->src, 1, 0); - if (!src) - return NULL; - - dtype = insn_symbol_type(C, fn, insn); - if (!dtype) - return NULL; - - target = build_cast(C, fn, src, dtype, false); - assert(JIT_GetNodeType(target) != JIT_NoType); - insn->target->priv = target; - - return target; -} - -static JIT_NodeRef output_op_cast(struct dmr_C *C, struct function *fn, struct instruction *insn, bool unsignedcast) -{ - JIT_NodeRef src, target; - struct OMRType *dtype; - struct symbol *otype = insn->orig_type; - - if (dmrC_is_ptr_type(insn->type)) { - return output_op_ptrcast(C, fn, insn); - } - - src = insn->src->priv; - if (!src) - src = pseudo_to_value(C, fn, insn->type, insn->src); - if (dmrC_is_int_type(C->S, otype)) { - struct OMRType *stype = get_symnode_or_basetype(C, fn, otype); - src = build_cast(C, fn, src, stype, unsignedcast); - } - if (!src) - return NULL; - - assert(!dmrC_is_float_type(C->S, insn->type)); - - dtype = insn_symbol_type(C, fn, insn); - if (!dtype) - return NULL; - target = build_cast(C, fn, src, dtype, unsignedcast); - assert(JIT_GetNodeType(target) != JIT_NoType); - insn->target->priv = target; - - return target; -} - -static JIT_NodeRef output_op_ret(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - pseudo_t pseudo = insn->src; - - if (pseudo && pseudo != VOID_PSEUDO(C)) { - JIT_NodeRef result = pseudo_to_value(C, fn, insn->type, pseudo); - if (!result) - return NULL; - return JIT_ReturnValue(fn->injector, result); - } else - return JIT_ReturnNoValue(fn->injector); -} - -static JIT_NodeRef output_op_br(struct dmr_C *C, struct function *fn, struct instruction *br) -{ - (void)C; - JIT_BlockRef target_block = JIT_GetBlock(fn->injector, br->bb_true->nr); - return JIT_Goto(fn->injector, target_block); -} - -/* return 1 on success, 0 on failure */ -static int output_insn(struct dmr_C *C, struct function *fn, struct instruction *insn) -{ - JIT_NodeRef v = NULL; - switch (insn->opcode) { - case OP_RET: - v = output_op_ret(C, fn, insn); - break; - case OP_BR: - v = output_op_br(C, fn, insn); - break; - case OP_CBR: - v = output_op_cbr(C, fn, insn); - break; - case OP_PHISOURCE: - v = output_op_phisrc(C, fn, insn); - break; - case OP_PHI: - v = output_op_phi(C, fn, insn); - break; - case OP_LOAD: - v = output_op_load(C, fn, insn); - break; - case OP_SYMADDR: - v = output_op_symaddr(C, fn, insn); - break; - case OP_SETVAL: - v = output_op_setval(C, fn, insn); - break; - - case OP_SWITCH: - v = output_op_switch(C, fn, insn); - break; - - case OP_COMPUTEDGOTO: - dmrC_sparse_error(C, insn->pos, "computed goto is not supported\n"); - return 0; - - case OP_LNOP: - return 0; - - case OP_STORE: - v = output_op_store(C, fn, insn); - break; - - case OP_SNOP: - return 0; - - case OP_CALL: - v = output_op_call(C, fn, insn); - break; - case OP_CAST: - v = output_op_cast(C, fn, insn, true); - break; - case OP_SCAST: - v = output_op_cast(C, fn, insn, false); - break; - case OP_FPCAST: - v = output_op_fpcast(C, fn, insn); - break; - case OP_PTRCAST: - v = output_op_ptrcast(C, fn, insn); - break; - - case OP_ADD: - case OP_SUB: - case OP_MULU: - case OP_MULS: - case OP_DIVU: - case OP_DIVS: - case OP_MODU: - case OP_MODS: - case OP_SHL: - case OP_LSR: - case OP_ASR: - case OP_AND: - case OP_OR: - case OP_XOR: - case OP_AND_BOOL: - case OP_OR_BOOL: - v = output_op_binary(C, fn, insn); - break; - - case OP_SET_EQ: - case OP_SET_NE: - case OP_SET_LE: - case OP_SET_GE: - case OP_SET_LT: - case OP_SET_GT: - case OP_SET_B: - case OP_SET_A: - case OP_SET_BE: - case OP_SET_AE: - v = output_op_compare(C, fn, insn); - break; - - case OP_SEL: - v = output_op_sel(C, fn, insn); - break; - - case OP_SLICE: - return 0; - - case OP_NOT: - v = output_op_not(C, fn, insn); - break; - - case OP_NEG: - v = output_op_neg(C, fn, insn); - break; - - case OP_CONTEXT: - case OP_RANGE: - case OP_NOP: - case OP_ASM: - return 0; - - default: - return 1; - } - - if (v == NULL) - dmrC_sparse_error(C, insn->pos, "failed to output instruction %s\n", dmrC_show_instruction(C, insn)); - return v != NULL; -} - -/* return 1 on success, 0 on failure */ -static int output_bb(struct dmr_C *C, struct function *fn, struct basic_block *bb) -{ - struct instruction *insn; - - JIT_SetCurrentBlock(fn->injector, bb->nr); - FOR_EACH_PTR(bb->insns, insn) - { - if (!insn->bb) - continue; - - // Useful for debugging - // fprintf(stderr, "Instruction %s\n", - // dmrC_show_instruction(C, insn)); - - if (!output_insn(C, fn, insn)) { - dmrC_sparse_error(C, insn->pos, "failed to output %s\n", dmrC_show_instruction(C, insn)); - return 0; - } - } - END_FOR_EACH_PTR(insn); - - return 1; -} - -static bool JIT_ILBuilderImpl(JIT_ILInjectorRef injector, void *userdata) -{ - struct function *fn = (struct function *)userdata; - struct entrypoint *ep = fn->ep; - struct dmr_C *C = fn->C; - struct basic_block *bb; - pseudo_t pseudo; - - fn->injector = injector; - - /* - Count and number the basic blocks. - Whenever a basic block ends with CBR instruction we will - need an extra block in OMR so we count such blocks as 2. - The block numbers will be directly used to access corresponding - OMR blocks. - */ - unsigned int bbnr = 0; - FOR_EACH_PTR(ep->bbs, bb) - { - bool saw_cbr = false; - struct instruction *insn; - FOR_EACH_PTR(bb->insns, insn) - { - if (!insn->bb || insn->opcode != OP_CBR) - continue; - saw_cbr = true; - break; - } - END_FOR_EACH_PTR(insn); - /* The bb->nr field is not used by the - frontend anymore so we can use it to - decide which the order of basic blocks. - */ - bb->nr = bbnr++; - if (saw_cbr) - bbnr++; /* Allow an extra block here because of the way - OMR does conditional branching (see CBR - codegen) */ - } - END_FOR_EACH_PTR(bb); - - /* Number of basic blocks we need - complicated by how OMRJIT handles - * branching */ - JIT_CreateBlocks(fn->injector, bbnr); - /* At this point we are at block 0 */ - FOR_EACH_PTR(ep->bbs, bb) - { - struct instruction *insn; - /* allocate stack storage for each phi */ - FOR_EACH_PTR(bb->insns, insn) - { - if (!insn->bb || insn->opcode != OP_PHI) - continue; - - /* insert alloca into entry block */ - JIT_SymbolRef symref = OMR_alloca(fn, insn_symbol_type(fn->C, fn, insn), - instruction_size_in_bytes(fn->C, insn), true); - if (!symref) - goto Efailed; - - // Unlike the Sparse LLVM version we - // save the symbol reference here and perform the load - // when we encounter the PHI instructions - // NOTE therefore priv2 is always a JIT_SymbolRef - insn->target->priv2 = symref; - insn->target->priv = NULL; - } - END_FOR_EACH_PTR(insn); - } - END_FOR_EACH_PTR(bb); - - /* Try to do allocas for all declared local symbols up front */ - FOR_EACH_PTR(ep->accesses, pseudo) - { - if (pseudo->type == PSEUDO_SYM) { - if (dmrC_is_extern(pseudo->sym) || dmrC_is_static(pseudo->sym) || dmrC_is_toplevel(pseudo->sym)) - continue; - if (!get_sym_value(C, fn, pseudo, false)) - goto Efailed; - } - } - END_FOR_EACH_PTR(arg); - - /* - Now generate IL for each block - */ - FOR_EACH_PTR(ep->bbs, bb) - { - if (!output_bb(C, fn, bb)) { - goto Efailed; - } - } - END_FOR_EACH_PTR(bb); - - // The following flag triggers loop optimizations at O2 - JIT_SetMayHaveLoops(fn->injector); - - return true; - -Efailed: - return false; -} - -static bool output_fn(struct dmr_C *C, JIT_ContextRef module, struct entrypoint *ep) -{ - bool success = false; - struct symbol *sym = ep->name; - struct symbol *base_type = sym->ctype.base_type; - struct symbol *ret_type = sym->ctype.base_type->ctype.base_type; - struct function function; - const char *name; - struct symbol *arg; - int nr_args = 0; - - memset(&function, 0, sizeof function); - function.C = C; - function.context = module; - function.ep = ep; - if (base_type->variadic) { - fprintf(stderr, "Variadic functions are not supported\n"); - return false; - } - - dmrC_allocator_init(&function.type_allocator, "OMRtypes", sizeof(struct OMRType), __alignof__(struct OMRType), - CHUNK); - - JIT_Type argtypes[JIT_MaxArgs]; - - FOR_EACH_PTR(base_type->arguments, arg) - { - struct symbol *arg_base_type = arg->ctype.base_type; - if (nr_args >= JIT_MaxArgs) { - fprintf(stderr, "Only upto %d arguments supported\n", JIT_MaxArgs); - goto Ereturn; - } - argtypes[nr_args] = check_supported_argtype(C, arg_base_type); - if (argtypes[nr_args] == JIT_NoType) // Unsupported - goto Ereturn; - nr_args++; - } - END_FOR_EACH_PTR(arg); - - name = dmrC_show_ident(C, sym->ident); - char function_name[128]; - snprintf(function_name, sizeof function_name, "%s", name); - - struct OMRType *function_type = type_to_OMRtype(C, &function, ret_type, NULL); - function.return_type = check_supported_returntype(C, function_type); - if (function.return_type == &BadType) { - fprintf(stderr, "Function '%s' has unsupported return type\n", name); - goto Ereturn; - } - - JIT_Type freturn = map_OMRtype(function.return_type); - - function.builder = - JIT_CreateFunctionBuilder(module, function_name, freturn, nr_args, argtypes, JIT_ILBuilderImpl, &function); - - void *p = JIT_Compile(function.builder, C->optimize); - if (p) - success = true; - - JIT_DestroyFunctionBuilder(function.builder); - -Ereturn: - dmrC_allocator_destroy(&function.type_allocator); - - return success; -} - -static int is_prototype(struct symbol *sym) -{ - if (sym->type == SYM_NODE) - sym = sym->ctype.base_type; - return sym && sym->type == SYM_FN && !sym->stmt; -} - -/* returns 1 on success, 0 on failure */ -static int compile(struct dmr_C *C, JIT_ContextRef module, struct symbol_list *list) -{ - struct symbol *sym; - - FOR_EACH_PTR(list, sym) - { - struct entrypoint *ep; - dmrC_expand_symbol(C, sym); - - if (is_prototype(sym)) { - continue; - } - - ep = dmrC_linearize_symbol(C, sym); - if (ep) { - if (!output_fn(C, module, ep)) - return 0; - } else { - fprintf(stderr, "Global data is not supported\n"); - return 0; - } - } - END_FOR_EACH_PTR(sym); - - return 1; -} - -char *safe_strdup(const char *in) { - size_t len = strlen(in); - char *buf = calloc(1, len+1); - if (buf == NULL) { - fprintf(stderr, "Out of memory\n"); - exit(1); - } - strncpy(buf, in, len+1); - buf[len] = 0; - return buf; -} - - -bool dmrC_omrcompile(int argc, char **argv, JIT_ContextRef module, const char *inputbuffer) -{ - struct string_list *filelist = NULL; - struct symbol_list *symlist; - char *file; - - struct dmr_C *C = new_dmr_C(); - C->optimize = 1; /* Default */ - C->codegen = 1; /* Disables macros related to vararg processing */ - C->Wdecl = 0; - - int rc = 0; - char *buffer = NULL; - if (!setjmp(C->jmpbuf)) { - symlist = dmrC_sparse_initialize(C, argc, argv, &filelist); - if (compile(C, module, symlist)) { - /* We need ->phi_users */ - /* This flag enables call to dmrC_track_pseudo_death() in - linearize.c which sets - phi_users list on PHISOURCE instructions */ - C->dbg_dead = 1; - FOR_EACH_PTR(filelist, file) - { - symlist = dmrC_sparse(C, file); - if (C->die_if_error || !symlist) { - rc = 1; - break; - } - if (!compile(C, module, symlist)) { - rc = 1; - break; - } - } - END_FOR_EACH_PTR(file); - if (inputbuffer && rc == 0) { - buffer = safe_strdup(inputbuffer); - if (!buffer) - rc = 1; - else { - symlist = dmrC_sparse_buffer(C, "buffer", buffer, 0); - if (C->die_if_error || !symlist) { - rc = 1; - } else if (!compile(C, module, symlist)) { - rc = 1; - } - } - } - } else - rc = 1; - } - else { - rc = 1; - } - if (rc == 1) { - fprintf(stderr, "Failed to compile given inputs\n"); - } - if (buffer != NULL) free(buffer); - destroy_dmr_C(C); - - return rc == 0; -} diff --git a/dmr_c/src/README.md b/dmr_c/src/README.md deleted file mode 100644 index 82391ef..0000000 --- a/dmr_c/src/README.md +++ /dev/null @@ -1,67 +0,0 @@ -The code is organised as follows: - - -## Pointer Linked List - -This is implemented in: - -* ptrlist.h -* ptrlist.c - -## Memory allocation - -* allocate.h -* allocate.c - -## Tokenizer - -This is implemented in: - -* token.h -* tokenize.c - -The tokenizer depends on declarations in symbol.h and target.h - -## Parser - -The C parser parses code as well as evaluates constant expressions and as far as I can tell it will also perform -inlining of functions. The evaluation code is reused by the pre-processor so the C parser is lower level than the -pre-processor. - -The parser implementation is in following: - -* symbol.h -* symbol.c -* scope.h -* scope.c -* parse.h -* parse.c -* char.c -* char.h -* expression.h -* expression.c -* expand.c -* evaluate.c -* inline.c -* ident-list.h -* show-parse.c - -## Pre-processor - -The pre-processor depends upon the parser functions to evaluate expressions. It is implemented in: - -* pre-process.c - -## Linearizer - -This component transforms the parsed representation to a linear form (SSA I believe). The implementation is in: - -* linearize.h -* linearize.c -* flow.h -* flow.c -* cse.c -* liveness.c -* memops.c -* simplify.c -* unssa.c diff --git a/dmr_c/src/allocate.c b/dmr_c/src/allocate.c deleted file mode 100644 index 803a7ba..0000000 --- a/dmr_c/src/allocate.c +++ /dev/null @@ -1,215 +0,0 @@ -/* -* allocate.c - simple space-efficient blob allocator. -* -* Copyright (C) 2003 Transmeta Corp. -* 2003-2004 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -* Simple allocator for data that doesn't get partially free'd. -* The tokenizer and parser allocate a _lot_ of small data structures -* (often just two-three bytes for things like small integers), -* and since they all depend on each other you can't free them -* individually _anyway_. So do something that is very space- -* efficient: allocate larger "blobs", and give out individual -* small bits and pieces of it with no maintenance overhead. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#include - -#include -#include -#include -#include - -void *dmrC_blob_alloc(size_t size) { - void *ptr; - ptr = malloc(size); - if (ptr != NULL) - memset(ptr, 0, size); - return ptr; -} - -void dmrC_blob_free(void *addr, size_t size) { - (void)size; - free(addr); -} - -void dmrC_allocator_init(struct allocator *A, const char *name, size_t size, - unsigned int alignment, unsigned int chunking) { - A->name_ = name; - A->blobs_ = NULL; - A->size_ = size; - A->alignment_ = alignment; - A->chunking_ = chunking; - A->freelist_ = NULL; - A->allocations = 0; - A->total_bytes = 0; - A->useful_bytes = 0; -} - -void *dmrC_allocator_allocate(struct allocator *A, size_t extra) { - size_t size = extra + A->size_; - size_t alignment = A->alignment_; - struct allocation_blob *blob = A->blobs_; - void *retval; - - assert(size <= A->chunking_); - /* - * NOTE! The freelist only works with things that are - * (a) sufficiently aligned - * (b) use a constant size - * Don't try to free allocators that don't follow - * these rules. - */ - if (A->freelist_) { - void **p = (void **)A->freelist_; - retval = p; - A->freelist_ = *p; - memset(retval, 0, size); - return retval; - } - - A->allocations++; - A->useful_bytes += size; - size = (size + alignment - 1) & ~(alignment - 1); - if (!blob || blob->left < size) { - size_t offset, chunking = A->chunking_; - struct allocation_blob *newblob = - (struct allocation_blob *)dmrC_blob_alloc(chunking); - if (!newblob) { - fprintf(stderr, "out of memory\n"); - abort(); - } - A->total_bytes += chunking; - newblob->next = blob; - blob = newblob; - A->blobs_ = newblob; - offset = offsetof(struct allocation_blob, data); - offset = (offset + alignment - 1) & ~(alignment - 1); - blob->left = chunking - offset; - blob->offset = offset - offsetof(struct allocation_blob, data); - } - retval = blob->data + blob->offset; - blob->offset += size; - blob->left -= size; - return retval; -} - -void dmrC_allocator_free(struct allocator *A, void *entry) { - void **p = (void **)entry; - *p = A->freelist_; - A->freelist_ = p; -} -void dmrC_allocator_show_allocations(struct allocator *A) { - fprintf(stderr, "%s: %d allocations, %d bytes (%d total bytes, " - "%6.2f%% usage, %6.2f average size)\n", - A->name_, (int)A->allocations, (int)A->useful_bytes, - (int)A->total_bytes, 100 * (double)A->useful_bytes / A->total_bytes, - (double)A->useful_bytes / A->allocations); -} -void dmrC_allocator_drop_all_allocations(struct allocator *A) { - struct allocation_blob *blob = A->blobs_; - A->blobs_ = NULL; - A->allocations = 0; - A->total_bytes = 0; - A->useful_bytes = 0; - A->freelist_ = NULL; - while (blob) { - struct allocation_blob *next = blob->next; - dmrC_blob_free(blob, A->chunking_); - blob = next; - } -} -void dmrC_allocator_destroy(struct allocator *A) { - dmrC_allocator_drop_all_allocations(A); - A->blobs_ = NULL; - A->allocations = 0; - A->total_bytes = 0; - A->useful_bytes = 0; - A->freelist_ = NULL; -} -void dmrC_allocator_transfer(struct allocator *A, struct allocator *transfer_to) { - assert(transfer_to->blobs_ == NULL); - assert(transfer_to->freelist_ == NULL); - transfer_to->blobs_ = A->blobs_; - transfer_to->allocations = A->allocations; - transfer_to->total_bytes = A->total_bytes; - transfer_to->useful_bytes = A->useful_bytes; - transfer_to->freelist_ = A->freelist_; - transfer_to->alignment_ = A->alignment_; - transfer_to->chunking_ = A->chunking_; - transfer_to->size_ = A->size_; - A->blobs_ = NULL; - A->allocations = 0; - A->total_bytes = 0; - A->useful_bytes = 0; - A->freelist_ = NULL; -} - -struct foo { - int a, b; -}; - -int dmrC_test_allocator() { - struct allocator alloc; - dmrC_allocator_init(&alloc, "foo", sizeof(struct foo), __alignof__(struct foo), - sizeof(struct allocation_blob) + sizeof(struct foo) * 2); - struct foo *t1 = (struct foo *)dmrC_allocator_allocate(&alloc, 0); - if (t1 == NULL) - return 1; - if (alloc.alignment_ != __alignof__(struct foo)) - return 1; - if (alloc.allocations != 1) - return 1; - if (alloc.freelist_ != NULL) - return 1; - struct foo *t2 = (struct foo *)dmrC_allocator_allocate(&alloc, 0); - if (t2 != t1 + 1) - return 1; - //dmrC_allocator_show_allocations(&alloc); - dmrC_allocator_free(&alloc, t1); - dmrC_allocator_free(&alloc, t2); - struct foo *t3 = (struct foo *)dmrC_allocator_allocate(&alloc, 0); - if (t3 != t2) - return 1; - struct foo *t4 = (struct foo *)dmrC_allocator_allocate(&alloc, 0); - if (t4 != t1) - return 1; - struct foo *t5 = (struct foo *)dmrC_allocator_allocate(&alloc, 0); - (void)t5; - if (alloc.total_bytes != - (sizeof(struct allocation_blob) + sizeof(struct foo) * 2) * 2) - return 1; - struct allocator alloc2; - memset(&alloc2, 0, sizeof alloc2); - struct allocation_blob *saved = alloc.blobs_; - dmrC_allocator_transfer(&alloc, &alloc2); - if (alloc.blobs_ != NULL) - return 1; - if (alloc2.blobs_ != saved) - return 1; - dmrC_allocator_destroy(&alloc2); - printf("allocator tests okay\n"); - return 0; -} diff --git a/dmr_c/src/allocate.h b/dmr_c/src/allocate.h deleted file mode 100644 index 0709535..0000000 --- a/dmr_c/src/allocate.h +++ /dev/null @@ -1,100 +0,0 @@ -#ifndef DMR_C_ALLOCATOR_H -#define DMR_C_ALLOCATOR_H - -/* -* allocate.c - simple space-efficient blob allocator. -* -* Copyright (C) 2003 Transmeta Corp. -* 2003-2004 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -* Simple allocator for data that doesn't get partially free'd. -* The tokenizer and parser allocate a _lot_ of small data structures -* (often just two-three bytes for things like small integers), -* and since they all depend on each other you can't free them -* individually _anyway_. So do something that is very space- -* efficient: allocate larger "blobs", and give out individual -* small bits and pieces of it with no maintenance overhead. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#include - -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -struct allocation_blob { - struct allocation_blob *next; - size_t left, offset; - unsigned char data[]; -}; - -/* -* Our "blob" allocator works on chunks that are multiples -* of this size (the underlying allocator may be a mmap that -* cannot handle smaller chunks, for example, so trying to -* allocate blobs that aren't aligned is not going to work). -*/ -#define CHUNK 32768 - -struct allocator { - const char *name_; - struct allocation_blob *blobs_; - size_t size_; - unsigned int alignment_; - unsigned int chunking_; - void *freelist_; - size_t allocations, total_bytes, useful_bytes; -}; - -extern void dmrC_allocator_init(struct allocator *A, const char *name, size_t size, - unsigned int alignment, unsigned int chunking); - -extern void *dmrC_allocator_allocate(struct allocator *A, size_t extra); - -extern void dmrC_allocator_free(struct allocator *A, void *entry); - -extern void dmrC_allocator_show_allocations(struct allocator *A); - -extern void dmrC_allocator_drop_all_allocations(struct allocator *A); - -extern void dmrC_allocator_destroy(struct allocator *A); - -extern void dmrC_allocator_transfer(struct allocator *A, - struct allocator *transfer_to); - -extern int dmrC_test_allocator(); - -#ifdef __cplusplus -} -#endif - - -#endif \ No newline at end of file diff --git a/dmr_c/src/builtin.c b/dmr_c/src/builtin.c deleted file mode 100644 index a0568c1..0000000 --- a/dmr_c/src/builtin.c +++ /dev/null @@ -1,249 +0,0 @@ -/* - * builtin evaluation & expansion. - * - * Copyright (C) 2003 Transmeta Corp. - * 2003-2004 Linus Torvalds - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#include -#include -#include -#include -#include - -static int evaluate_to_integer(struct dmr_C *C, struct expression *expr) -{ - expr->ctype = &C->S->int_ctype; - return 1; -} - -static int evaluate_expect(struct dmr_C *C, struct expression *expr) -{ - /* Should we evaluate it to return the type of the first argument? */ - expr->ctype = &C->S->int_ctype; - return 1; -} - -static int arguments_choose(struct dmr_C *C, struct expression *expr) -{ - struct expression_list *arglist = expr->args; - struct expression *arg; - int i = 0; - - FOR_EACH_PTR (arglist, arg) { - if (!dmrC_evaluate_expression(C, arg)) - return 0; - i++; - } END_FOR_EACH_PTR(arg); - if (i < 3) { - dmrC_sparse_error(C, expr->pos, - "not enough arguments for __builtin_choose_expr"); - return 0; - } if (i > 3) { - dmrC_sparse_error(C, expr->pos, - "too many arguments for __builtin_choose_expr"); - return 0; - } - return 1; -} - -static int evaluate_choose(struct dmr_C *C, struct expression *expr) -{ - struct expression_list *list = expr->args; - struct expression *arg, *args[3]; - int n = 0; - - /* there will be exactly 3; we'd already verified that */ - FOR_EACH_PTR(list, arg) { - args[n++] = arg; - } END_FOR_EACH_PTR(arg); - - *expr = dmrC_get_expression_value(C, args[0]) ? *args[1] : *args[2]; - - return 1; -} - -static int expand_expect(struct dmr_C *C, struct expression *expr, int cost) -{ - struct expression *arg = dmrC_first_expression(expr->args); - (void)C; - (void)cost; - - if (arg) - *expr = *arg; - return 0; -} - -/* - * __builtin_warning() has type "int" and always returns 1, - * so that you can use it in conditionals or whatever - */ -static int expand_warning(struct dmr_C *C, struct expression *expr, int cost) -{ - struct expression *arg; - struct expression_list *arglist = expr->args; - (void)cost; - - FOR_EACH_PTR (arglist, arg) { - /* - * Constant strings get printed out as a warning. By the - * time we get here, the EXPR_STRING has been fully - * evaluated, so by now it's an anonymous symbol with a - * string initializer. - * - * Just for the heck of it, allow any constant string - * symbol. - */ - if (arg->type == EXPR_SYMBOL) { - struct symbol *sym = arg->symbol; - if (sym->initializer && sym->initializer->type == EXPR_STRING) { - struct string *string = sym->initializer->string; - dmrC_warning(C, expr->pos, "%*s", string->length-1, string->data); - } - continue; - } - - /* - * Any other argument is a conditional. If it's - * non-constant, or it is false, we exit and do - * not print any warning. - */ - if (arg->type != EXPR_VALUE) - goto out; - if (!arg->value) - goto out; - } END_FOR_EACH_PTR(arg); -out: - expr->type = EXPR_VALUE; - expr->value = 1; - expr->taint = 0; - return 0; -} - -/* The arguments are constant if the cost of all of them is zero */ -static int expand_constant_p(struct dmr_C *C, struct expression *expr, int cost) -{ - (void) C; - expr->type = EXPR_VALUE; - expr->value = !cost; - expr->taint = 0; - return 0; -} - -/* The arguments are safe, if their cost is less than SIDE_EFFECTS */ -static int expand_safe_p(struct dmr_C *C, struct expression *expr, int cost) -{ - (void) C; - expr->type = EXPR_VALUE; - expr->value = (cost < SIDE_EFFECTS); - expr->taint = 0; - return 0; -} - -static struct symbol_op constant_p_op = { - .evaluate = evaluate_to_integer, - .expand = expand_constant_p -}; - -static struct symbol_op safe_p_op = { - .evaluate = evaluate_to_integer, - .expand = expand_safe_p -}; - -static struct symbol_op warning_op = { - .evaluate = evaluate_to_integer, - .expand = expand_warning -}; - -static struct symbol_op expect_op = { - .evaluate = evaluate_expect, - .expand = expand_expect -}; - -static struct symbol_op choose_op = { - .evaluate = evaluate_choose, - .args = arguments_choose, -}; - -/* The argument is constant and valid if the cost is zero */ -static int expand_bswap(struct dmr_C *C, struct expression *expr, int cost) -{ - struct expression *arg; - long long val; - - if (cost) - return cost; - - /* the arguments number & type have already been checked */ - arg = dmrC_first_expression(expr->args); - val = dmrC_get_expression_value_silent(C, arg); - switch (expr->ctype->bit_size) { - case 16: expr->value = __builtin_bswap16((uint16_t)val); break; - case 32: expr->value = __builtin_bswap32((uint32_t)val); break; - case 64: expr->value = __builtin_bswap64(val); break; - default: /* impossible error */ - return SIDE_EFFECTS; - } - - expr->type = EXPR_VALUE; - expr->taint = 0; - return 0; -} - -static struct symbol_op bswap_op = { - .expand = expand_bswap, -}; - - -/* - * Builtin functions - */ -static struct symbol builtin_fn_type = { .type = SYM_FN /* , .variadic =1 */ }; -static struct sym_init { - const char *name; - struct symbol *base_type; - unsigned int modifiers; - struct symbol_op *op; -} builtins_table[] = { - { "__builtin_constant_p", &builtin_fn_type, MOD_TOPLEVEL, &constant_p_op }, - { "__builtin_safe_p", &builtin_fn_type, MOD_TOPLEVEL, &safe_p_op }, - { "__builtin_warning", &builtin_fn_type, MOD_TOPLEVEL, &warning_op }, - { "__builtin_expect", &builtin_fn_type, MOD_TOPLEVEL, &expect_op }, - { "__builtin_choose_expr", &builtin_fn_type, MOD_TOPLEVEL, &choose_op }, - { "__builtin_bswap16", NULL, MOD_TOPLEVEL, &bswap_op }, - { "__builtin_bswap32", NULL, MOD_TOPLEVEL, &bswap_op }, - { "__builtin_bswap64", NULL, MOD_TOPLEVEL, &bswap_op }, - { NULL, NULL, 0, NULL } -}; - -void dmrC_init_builtins(struct dmr_C *C, int stream) -{ - struct sym_init *ptr; - - builtin_fn_type.variadic = 1; - for (ptr = builtins_table; ptr->name; ptr++) { - struct symbol *sym; - sym = dmrC_create_symbol(C->S, stream, ptr->name, SYM_NODE, NS_SYMBOL); - sym->ctype.base_type = ptr->base_type; - sym->ctype.modifiers = ptr->modifiers; - sym->op = ptr->op; - } -} diff --git a/dmr_c/src/char.c b/dmr_c/src/char.c deleted file mode 100644 index a5111ad..0000000 --- a/dmr_c/src/char.c +++ /dev/null @@ -1,181 +0,0 @@ -/* -* sparse/char.c -* -* Copyright (C) 2003 Transmeta Corp. -* 2003-2004 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ -#include - -#include -#include -#include -#include -#include -#include - -static const char *parse_escape(struct dmr_C *C, const char *p, unsigned *val, const char *end, int bits, struct position pos) -{ - unsigned c = *p++; - unsigned d; - if (c != '\\') { - *val = c; - return p; - } - - c = *p++; - switch (c) { - case 'a': c = '\a'; break; - case 'b': c = '\b'; break; - case 't': c = '\t'; break; - case 'n': c = '\n'; break; - case 'v': c = '\v'; break; - case 'f': c = '\f'; break; - case 'r': c = '\r'; break; -#ifndef _MSC_VER - case 'e': c = '\e'; break; -#endif - case 'x': { - unsigned mask = -(1U << (bits - 4)); - for (c = 0; p < end; c = (c << 4) + d) { - d = dmrC_hexval(*p); - if (d > 16) - break; - p++; - if (c & mask) { - dmrC_warning(C, pos, - "hex escape sequence out of range"); - mask = 0; - } - } - break; - } - case '0':case '1': case '2': case '3': case '4': case '5': - case '6': case '7': { - if (p + 2 < end) - end = p + 2; - c -= '0'; - while (p < end && (d = *p - '0') < 8) { - c = (c << 3) + d; - p++; - } - if ((c & 0400) && bits < 9) - dmrC_warning(C, pos, - "octal escape sequence out of range"); - break; - } - default: /* everything else is left as is */ - dmrC_warning(C, pos, "unknown escape sequence: '\\%c'", c); - break; - case '\\': - case '\'': - case '"': - case '?': - break; /* those are legal, so no warnings */ - } - *val = c & ~((~0U << (bits - 1)) << 1); - return p; -} - -void dmrC_get_char_constant(struct dmr_C *C, struct token *token, unsigned long long *val) -{ - const char *p = token->embedded, *end; - unsigned v; - int type = dmrC_token_type(token); - switch (type) { - case TOKEN_CHAR: - case TOKEN_WIDE_CHAR: - p = token->string->data; - end = p + token->string->length - 1; - break; - case TOKEN_CHAR_EMBEDDED_0: - case TOKEN_CHAR_EMBEDDED_1: - case TOKEN_CHAR_EMBEDDED_2: - case TOKEN_CHAR_EMBEDDED_3: - end = p + type - TOKEN_CHAR; - break; - default: - end = p + type - TOKEN_WIDE_CHAR; - } - p = parse_escape(C, p, &v, end, - type < TOKEN_WIDE_CHAR ? C->target->bits_in_char : C->target->bits_in_wchar, token->pos); - if (p != end) - dmrC_warning(C, token->pos, - "multi-character character constant"); - *val = v; -} - -struct token *dmrC_get_string_constant(struct dmr_C *C, struct token *token, struct expression *expr) -{ - struct string *string = token->string; - struct token *next = token->next, *done = NULL; - int stringtype = dmrC_token_type(token); - int is_wide = stringtype == TOKEN_WIDE_STRING; - char buffer[MAX_STRING]; - int len = 0; - int bits; - int esc_count = 0; - - while (!done) { - switch (dmrC_token_type(next)) { - case TOKEN_WIDE_STRING: - is_wide = 1; - case TOKEN_STRING: - next = next->next; - break; - default: - done = next; - } - } - bits = is_wide ? C->target->bits_in_wchar : C->target->bits_in_char; - while (token != done) { - unsigned v; - const char *p = token->string->data; - const char *end = p + token->string->length - 1; - while (p < end) { - if (*p == '\\') - esc_count++; - p = parse_escape(C, p, &v, end, bits, token->pos); - if (len < MAX_STRING) - buffer[len] = v; - len++; - } - token = token->next; - } - if (len > MAX_STRING) { - dmrC_warning(C, token->pos, "trying to concatenate %d-character string (%d bytes max)", len, MAX_STRING); - len = MAX_STRING; - } - - if (esc_count || len >= (int)string->length) { - if (string->immutable || len >= string->length) /* can't cannibalize */ - string = (struct string *)dmrC_allocator_allocate(&C->string_allocator, len+1); - string->length = len+1; - memcpy(string->data, buffer, len); - string->data[len] = '\0'; - } - expr->string = string; - expr->wide = is_wide; - return token; -} diff --git a/dmr_c/src/char.h b/dmr_c/src/char.h deleted file mode 100644 index 2092127..0000000 --- a/dmr_c/src/char.h +++ /dev/null @@ -1,25 +0,0 @@ -/* -* sparse/char.h -* -* Copyright (C) 2003 Transmeta Corp. -* 2003 Linus Torvalds -* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ -#ifndef DMR_C_CHAR_H -#define DMR_C_CHAR_H - -#ifdef __cplusplus -extern "C" { -#endif - -extern void dmrC_get_char_constant(struct dmr_C *C, struct token *, unsigned long long *); -extern struct token *dmrC_get_string_constant(struct dmr_C *C, struct token *, struct expression *); - -#ifdef __cplusplus -} -#endif - - -#endif \ No newline at end of file diff --git a/dmr_c/src/cse.c b/dmr_c/src/cse.c deleted file mode 100644 index 5b3ae68..0000000 --- a/dmr_c/src/cse.c +++ /dev/null @@ -1,393 +0,0 @@ -/* - * CSE - walk the linearized instruction flow, and - * see if we can simplify it and apply CSE on it. - * - * Copyright (C) 2004 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static int phi_compare(pseudo_t phi1, pseudo_t phi2) -{ - const struct instruction *def1 = phi1->def; - const struct instruction *def2 = phi2->def; - - if (def1->src1 != def2->src1) - return def1->src1 < def2->src1 ? -1 : 1; - if (def1->bb != def2->bb) - return def1->bb < def2->bb ? -1 : 1; - return 0; -} - - -static void clean_up_one_instruction(struct dmr_C *C, struct basic_block *bb, struct instruction *insn) -{ - unsigned long hash; - - if (!insn->bb) - return; - assert(insn->bb == bb); - C->L->repeat_phase |= dmrC_simplify_instruction(C, insn); - if (!insn->bb) - return; - hash = (insn->opcode << 3) + (insn->size >> 3); - switch (insn->opcode) { - case OP_SEL: - hash += dmrC_hashval(insn->src3); - /* Fall through */ - - /* Binary arithmetic */ - case OP_ADD: case OP_SUB: - case OP_MULU: case OP_MULS: - case OP_DIVU: case OP_DIVS: - case OP_MODU: case OP_MODS: - case OP_SHL: - case OP_LSR: case OP_ASR: - case OP_AND: case OP_OR: - - /* Binary logical */ - case OP_XOR: case OP_AND_BOOL: - case OP_OR_BOOL: - - /* Binary comparison */ - case OP_SET_EQ: case OP_SET_NE: - case OP_SET_LE: case OP_SET_GE: - case OP_SET_LT: case OP_SET_GT: - case OP_SET_B: case OP_SET_A: - case OP_SET_BE: case OP_SET_AE: - hash += dmrC_hashval(insn->src2); - /* Fall through */ - - /* Unary */ - case OP_NOT: case OP_NEG: - hash += dmrC_hashval(insn->src1); - break; - - case OP_SETVAL: - hash += dmrC_hashval(insn->val); - break; - - case OP_SYMADDR: - hash += dmrC_hashval(insn->symbol); - break; - - case OP_CAST: - case OP_SCAST: - case OP_PTRCAST: - /* - * This is crap! Many "orig_types" are the - * same as far as casts go, we should generate - * some kind of "type hash" that is identical - * for identical casts - */ - hash += dmrC_hashval(insn->orig_type); - hash += dmrC_hashval(insn->src); - break; - - /* Other */ - case OP_PHI: { - pseudo_t phi; - FOR_EACH_PTR(insn->phi_list, phi) { - struct instruction *def; - if (phi == VOID_PSEUDO(C) || !phi->def) - continue; - def = phi->def; - hash += dmrC_hashval(def->src1); - hash += dmrC_hashval(def->bb); - } END_FOR_EACH_PTR(phi); - break; - } - - default: - /* - * Nothing to do, don't even bother hashing them, - * we're not going to try to CSE them - */ - return; - } - hash += hash >> 16; - hash &= INSN_HASH_SIZE-1; - dmrC_add_instruction(C, C->L->insn_hash_table + hash, insn); -} - -static void clean_up_insns(struct dmr_C *C, struct entrypoint *ep) -{ - struct basic_block *bb; - - FOR_EACH_PTR(ep->bbs, bb) { - struct instruction *insn; - FOR_EACH_PTR(bb->insns, insn) { - clean_up_one_instruction(C, bb, insn); - } END_FOR_EACH_PTR(insn); - } END_FOR_EACH_PTR(bb); -} - -/* Compare two (sorted) phi-lists */ -static int phi_list_compare(struct dmr_C *C, struct pseudo_list *l1, struct pseudo_list *l2) -{ - pseudo_t phi1, phi2; - - PREPARE_PTR_LIST(l1, phi1); - PREPARE_PTR_LIST(l2, phi2); - for (;;) { - int cmp; - - while (phi1 && (phi1 == VOID_PSEUDO(C) || !phi1->def)) - NEXT_PTR_LIST(phi1); - while (phi2 && (phi2 == VOID_PSEUDO(C) || !phi2->def)) - NEXT_PTR_LIST(phi2); - - if (!phi1) - return phi2 ? -1 : 0; - if (!phi2) - return phi1 ? 1 : 0; - cmp = phi_compare(phi1, phi2); - if (cmp) - return cmp; - NEXT_PTR_LIST(phi1); - NEXT_PTR_LIST(phi2); - } - /* Not reached, but we need to make the nesting come out right */ - FINISH_PTR_LIST(phi2); - FINISH_PTR_LIST(phi1); -} - -static int insn_compare(void *ud, const void *_i1, const void *_i2) -{ - struct dmr_C *C = (struct dmr_C *) ud; - const struct instruction *i1 = _i1; - const struct instruction *i2 = _i2; - - if (i1->opcode != i2->opcode) - return i1->opcode < i2->opcode ? -1 : 1; - - switch (i1->opcode) { - /* commutative binop */ - case OP_ADD: - case OP_MULU: case OP_MULS: - case OP_AND_BOOL: case OP_OR_BOOL: - case OP_AND: case OP_OR: - case OP_XOR: - case OP_SET_EQ: case OP_SET_NE: - if (i1->src1 == i2->src2 && i1->src2 == i2->src1) - return 0; - goto case_binops; - - case OP_SEL: - if (i1->src3 != i2->src3) - return i1->src3 < i2->src3 ? -1 : 1; - /* Fall-through to binops */ - - /* Binary arithmetic */ - case OP_SUB: - case OP_DIVU: case OP_DIVS: - case OP_MODU: case OP_MODS: - case OP_SHL: - case OP_LSR: case OP_ASR: - - /* Binary comparison */ - case OP_SET_LE: case OP_SET_GE: - case OP_SET_LT: case OP_SET_GT: - case OP_SET_B: case OP_SET_A: - case OP_SET_BE: case OP_SET_AE: - case_binops: - if (i1->src2 != i2->src2) - return i1->src2 < i2->src2 ? -1 : 1; - /* Fall through to unops */ - - /* Unary */ - case OP_NOT: case OP_NEG: - if (i1->src1 != i2->src1) - return i1->src1 < i2->src1 ? -1 : 1; - break; - - case OP_SYMADDR: - if (i1->symbol != i2->symbol) - return i1->symbol < i2->symbol ? -1 : 1; - break; - - case OP_SETVAL: - if (i1->val != i2->val) - return i1->val < i2->val ? -1 : 1; - break; - - /* Other */ - case OP_PHI: - return phi_list_compare(C, i1->phi_list, i2->phi_list); - - case OP_CAST: - case OP_SCAST: - case OP_PTRCAST: - /* - * This is crap! See the comments on hashing. - */ - if (i1->orig_type != i2->orig_type) - return i1->orig_type < i2->orig_type ? -1 : 1; - if (i1->src != i2->src) - return i1->src < i2->src ? -1 : 1; - break; - - default: - dmrC_warning(C, i1->pos, "bad instruction on hash chain"); - } - if (i1->size != i2->size) - return i1->size < i2->size ? -1 : 1; - return 0; -} - -static void sort_instruction_list(struct dmr_C *C, struct instruction_list **list) -{ - ptrlist_sort((struct ptr_list **)list, C, insn_compare); -} - -static struct instruction * cse_one_instruction(struct dmr_C *C, struct instruction *insn, struct instruction *def) -{ - dmrC_convert_instruction_target(C, insn, def->target); - - dmrC_kill_instruction(C, insn); - C->L->repeat_phase |= REPEAT_CSE; - return def; -} - -/* - * Does "bb1" dominate "bb2"? - */ -static int bb_dominates(struct entrypoint *ep, struct basic_block *bb1, struct basic_block *bb2, unsigned long generation) -{ - struct basic_block *parent; - - /* Nothing dominates the entrypoint.. */ - if (bb2 == ep->entry->bb) - return 0; - FOR_EACH_PTR(bb2->parents, parent) { - if (parent == bb1) - continue; - if (parent->generation == generation) - continue; - parent->generation = generation; - if (!bb_dominates(ep, bb1, parent, generation)) - return 0; - } END_FOR_EACH_PTR(parent); - return 1; -} - -static struct basic_block *trivial_common_parent(struct basic_block *bb1, struct basic_block *bb2) -{ - struct basic_block *parent; - - if (dmrC_bb_list_size(bb1->parents) != 1) - return NULL; - parent = dmrC_first_basic_block(bb1->parents); - if (dmrC_bb_list_size(bb2->parents) != 1) - return NULL; - if (dmrC_first_basic_block(bb2->parents) != parent) - return NULL; - return parent; -} - -static inline void remove_instruction(struct instruction_list **list, struct instruction *insn, int count) -{ - ptrlist_remove((struct ptr_list **)list, insn, count); -} - -static void add_instruction_to_end(struct dmr_C *C, struct instruction *insn, struct basic_block *bb) -{ - struct instruction *br = dmrC_delete_last_instruction(&bb->insns); - insn->bb = bb; - dmrC_add_instruction(C, &bb->insns, insn); - dmrC_add_instruction(C, &bb->insns, br); -} - -static struct instruction * try_to_cse(struct dmr_C *C, struct entrypoint *ep, struct instruction *i1, struct instruction *i2) -{ - struct basic_block *b1, *b2, *common; - - /* - * OK, i1 and i2 are the same instruction, modulo "target". - * We should now see if we can combine them. - */ - b1 = i1->bb; - b2 = i2->bb; - - /* - * Currently we only handle the uninteresting degenerate case where - * the CSE is inside one basic-block. - */ - if (b1 == b2) { - struct instruction *insn; - FOR_EACH_PTR(b1->insns, insn) { - if (insn == i1) - return cse_one_instruction(C, i2, i1); - if (insn == i2) - return cse_one_instruction(C, i1, i2); - } END_FOR_EACH_PTR(insn); - dmrC_warning(C, b1->pos, "Whaa? unable to find CSE instructions"); - return i1; - } - if (bb_dominates(ep, b1, b2, ++C->L->bb_generation)) - return cse_one_instruction(C, i2, i1); - - if (bb_dominates(ep, b2, b1, ++C->L->bb_generation)) - return cse_one_instruction(C, i1, i2); - - /* No direct dominance - but we could try to find a common ancestor.. */ - common = trivial_common_parent(b1, b2); - if (common) { - i1 = cse_one_instruction(C, i2, i1); - remove_instruction(&b1->insns, i1, 1); - add_instruction_to_end(C, i1, common); - } - - return i1; -} - -void dmrC_cleanup_and_cse(struct dmr_C *C, struct entrypoint *ep) -{ - int i; - - dmrC_simplify_memops(C, ep); -repeat: - C->L->repeat_phase = 0; - clean_up_insns(C, ep); - if (C->L->repeat_phase & REPEAT_CFG_CLEANUP) - dmrC_kill_unreachable_bbs(C, ep); - for (i = 0; i < INSN_HASH_SIZE; i++) { - struct instruction_list **list = C->L->insn_hash_table + i; - if (*list) { - if (dmrC_instruction_list_size(*list) > 1) { - struct instruction *insn, *last; - - sort_instruction_list(C, list); - - last = NULL; - FOR_EACH_PTR(*list, insn) { - if (!insn->bb) - continue; - if (last) { - if (!insn_compare(C, last, insn)) - insn = try_to_cse(C, ep, last, insn); - } - last = insn; - } END_FOR_EACH_PTR(insn); - } - ptrlist_remove_all((struct ptr_list **)list); - } - } - - if (C->L->repeat_phase & REPEAT_SYMBOL_CLEANUP) - dmrC_simplify_memops(C, ep); - - if (C->L->repeat_phase & REPEAT_CSE) - goto repeat; -} diff --git a/dmr_c/src/evaluate.c b/dmr_c/src/evaluate.c deleted file mode 100644 index 51b340d..0000000 --- a/dmr_c/src/evaluate.c +++ /dev/null @@ -1,3579 +0,0 @@ -/* - * sparse/evaluate.c - * - * Copyright (C) 2003 Transmeta Corp. - * 2003-2004 Linus Torvalds - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * Evaluate constant expressions. - */ - /* - * This version is part of the dmr_c project. - * Copyright (C) 2017 Dibyendu Majumdar - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct symbol *degenerate(struct dmr_C *C, struct expression *expr); -static struct symbol *evaluate_symbol(struct dmr_C *C, struct symbol *sym); -static void examine_fn_arguments(struct dmr_C *C, struct symbol *fn); -static struct symbol *cast_to_bool(struct dmr_C *C, struct expression *expr); - -static struct symbol *evaluate_symbol_expression(struct dmr_C *C, struct expression *expr) -{ - struct expression *addr; - struct symbol *sym = expr->symbol; - struct symbol *base_type; - - if (!sym) { - dmrC_expression_error(C, expr, "undefined identifier '%s'", dmrC_show_ident(C, expr->symbol_name)); - return NULL; - } - - dmrC_examine_symbol_type(C->S, sym); - - base_type = dmrC_get_base_type(C->S, sym); - if (!base_type) { - dmrC_expression_error(C, expr, "identifier '%s' has no type", dmrC_show_ident(C, expr->symbol_name)); - return NULL; - } - - addr = dmrC_alloc_expression(C, expr->pos, EXPR_SYMBOL); - addr->symbol = sym; - addr->symbol_name = expr->symbol_name; - addr->ctype = &C->S->lazy_ptr_ctype; /* Lazy evaluation: we need to do a proper job if somebody does &sym */ - expr->type = EXPR_PREOP; - expr->op = '*'; - expr->unop = addr; - - /* The type of a symbol is the symbol itself! */ - expr->ctype = sym; - return sym; -} - -static struct symbol *evaluate_string(struct dmr_C *C, struct expression *expr) -{ - struct symbol *sym = dmrC_alloc_symbol(C->S, expr->pos, SYM_NODE); - struct symbol *array = dmrC_alloc_symbol(C->S, expr->pos, SYM_ARRAY); - struct expression *addr = dmrC_alloc_expression(C, expr->pos, EXPR_SYMBOL); - struct expression *initstr = dmrC_alloc_expression(C, expr->pos, EXPR_STRING); - unsigned int length = expr->string->length; - - sym->array_size = dmrC_alloc_const_expression(C, expr->pos, length); - sym->bit_size = dmrC_bytes_to_bits(C->target, length); - sym->ctype.alignment = 1; - sym->string = 1; - sym->ctype.modifiers = MOD_STATIC; - sym->ctype.base_type = array; - sym->initializer = initstr; - - initstr->ctype = sym; - initstr->string = expr->string; - - array->array_size = sym->array_size; - array->bit_size = dmrC_bytes_to_bits(C->target, length); - array->ctype.alignment = 1; - array->ctype.modifiers = MOD_STATIC; - array->ctype.base_type = &C->S->char_ctype; - - addr->symbol = sym; - addr->ctype = &C->S->lazy_ptr_ctype; - - expr->type = EXPR_PREOP; - expr->op = '*'; - expr->unop = addr; - expr->ctype = sym; - return sym; -} - -/* type has come from classify_type and is an integer type */ -static inline struct symbol *integer_promotion(struct dmr_C *C, struct symbol *type) -{ - unsigned long mod = type->ctype.modifiers; - int width = type->bit_size; - - /* - * Bitfields always promote to the base type, - * even if the bitfield might be bigger than - * an "int". - */ - if (type->type == SYM_BITFIELD) { - type = type->ctype.base_type; - } - mod = type->ctype.modifiers; - if (width < C->target->bits_in_int) - return &C->S->int_ctype; - - /* If char/short has as many bits as int, it still gets "promoted" */ - if (mod & (MOD_CHAR | MOD_SHORT)) { - if (mod & MOD_UNSIGNED) - return &C->S->uint_ctype; - return &C->S->int_ctype; - } - return type; -} - -/* - * integer part of usual arithmetic conversions: - * integer promotions are applied - * if left and right are identical, we are done - * if signedness is the same, convert one with lower rank - * unless unsigned argument has rank lower than signed one, convert the - * signed one. - * if signed argument is bigger than unsigned one, convert the unsigned. - * otherwise, convert signed. - * - * Leaving aside the integer promotions, that is equivalent to - * if identical, don't convert - * if left is bigger than right, convert right - * if right is bigger than left, convert right - * otherwise, if signedness is the same, convert one with lower rank - * otherwise convert the signed one. - */ -static struct symbol *bigger_int_type(struct dmr_C *C, struct symbol *left, struct symbol *right) -{ - unsigned long lmod, rmod; - - left = integer_promotion(C, left); - right = integer_promotion(C, right); - - if (left == right) - goto left; - - if (left->bit_size > right->bit_size) - goto left; - - if (right->bit_size > left->bit_size) - goto right; - - lmod = left->ctype.modifiers; - rmod = right->ctype.modifiers; - if ((lmod ^ rmod) & MOD_UNSIGNED) { - if (lmod & MOD_UNSIGNED) - goto left; - } else if ((lmod & ~rmod) & (MOD_LONG_ALL)) - goto left; -right: - left = right; -left: - return left; -} - -static int same_cast_type(struct dmr_C *C, struct symbol *orig, struct symbol *news) -{ - (void)C; - return orig->bit_size == news->bit_size && - orig->bit_offset == news->bit_offset; -} - -static struct symbol *base_type(struct symbol *node, unsigned long *modp, unsigned long *asp) -{ - unsigned long mod, as; - - mod = 0; as = 0; - while (node) { - mod |= node->ctype.modifiers; - as |= node->ctype.as; - if (node->type == SYM_NODE) { - node = node->ctype.base_type; - continue; - } - break; - } - *modp = mod & ~MOD_IGNORE; - *asp = as; - return node; -} - -static int is_same_type(struct dmr_C *C, struct expression *expr, struct symbol *news) -{ - struct symbol *old = expr->ctype; - unsigned long oldmod, newmod, oldas, newas; - - old = base_type(old, &oldmod, &oldas); - news = base_type(news, &newmod, &newas); - - /* Same base type, same address space? */ - if (old == news && oldas == newas) { - unsigned long difmod; - - /* Check the modifier bits. */ - difmod = (oldmod ^ newmod) & ~MOD_NOCAST; - - /* Exact same type? */ - if (!difmod) - return 1; - - /* - * Not the same type, but differs only in "const". - * Don't warn about MOD_NOCAST. - */ - if (difmod == MOD_CONST) - return 0; - } - if ((oldmod | newmod) & MOD_NOCAST) { - const char *tofrom = "to/from"; - if (!(newmod & MOD_NOCAST)) - tofrom = "from"; - if (!(oldmod & MOD_NOCAST)) - tofrom = "to"; - dmrC_warning(C, expr->pos, "implicit cast %s nocast type", tofrom); - } - return 0; -} - -static void -warn_for_different_enum_types (struct dmr_C *C, struct position pos, - struct symbol *typea, - struct symbol *typeb) -{ - if (!C->Wenum_mismatch) - return; - if (typea->type == SYM_NODE) - typea = typea->ctype.base_type; - if (typeb->type == SYM_NODE) - typeb = typeb->ctype.base_type; - - if (typea == typeb) - return; - - if (typea->type == SYM_ENUM && typeb->type == SYM_ENUM) { - dmrC_warning(C, pos, "mixing different enum types"); - dmrC_info(C, pos, " %s versus", dmrC_show_typename(C, typea)); - dmrC_info(C, pos, " %s", dmrC_show_typename(C, typeb)); - } -} - -/* - * This gets called for implicit casts in assignments and - * integer promotion. We often want to try to move the - * cast down, because the ops involved may have been - * implicitly cast up, and we can get rid of the casts - * early. - */ -static struct expression * cast_to(struct dmr_C *C, struct expression *old, struct symbol *type) -{ - struct expression *expr; - - warn_for_different_enum_types (C, old->pos, old->ctype, type); - - if (old->ctype != &C->S->null_ctype && is_same_type(C, old, type)) - return old; - - /* - * See if we can simplify the op. Move the cast down. - */ - switch (old->type) { - case EXPR_PREOP: - if (old->ctype->bit_size < type->bit_size) - break; - if (old->op == '~') { - old->ctype = type; - old->unop = cast_to(C, old->unop, type); - return old; - } - break; - - case EXPR_IMPLIED_CAST: - warn_for_different_enum_types(C, old->pos, old->ctype, type); - - if (old->ctype->bit_size >= type->bit_size) { - struct expression *orig = old->cast_expression; - if (same_cast_type(C, orig->ctype, type)) - return orig; - if (old->ctype->bit_offset == type->bit_offset) { - old->ctype = type; - old->cast_type = type; - return old; - } - } - break; - - default: - /* nothing */; - } - - expr = dmrC_alloc_expression(C, old->pos, EXPR_IMPLIED_CAST); - expr->flags = old->flags; - expr->ctype = type; - expr->cast_type = type; - expr->cast_expression = old; - - if (dmrC_is_bool_type(C->S, type)) - cast_to_bool(C, expr); - - return expr; -} - -enum { - TYPE_NUM = 1, - TYPE_BITFIELD = 2, - TYPE_RESTRICT = 4, - TYPE_FLOAT = 8, - TYPE_PTR = 16, - TYPE_COMPOUND = 32, - TYPE_FOULED = 64, - TYPE_FN = 128, -}; - -static inline int classify_type(struct dmr_C *C, struct symbol *type, struct symbol **base) -{ - static int type_class[SYM_BAD + 1] = { - [SYM_PTR] = TYPE_PTR, - [SYM_FN] = TYPE_PTR | TYPE_FN, - [SYM_ARRAY] = TYPE_PTR | TYPE_COMPOUND, - [SYM_STRUCT] = TYPE_COMPOUND, - [SYM_UNION] = TYPE_COMPOUND, - [SYM_BITFIELD] = TYPE_NUM | TYPE_BITFIELD, - [SYM_RESTRICT] = TYPE_NUM | TYPE_RESTRICT, - [SYM_FOULED] = TYPE_NUM | TYPE_RESTRICT | TYPE_FOULED, - }; - if (type->type == SYM_NODE) - type = type->ctype.base_type; - if (type->type == SYM_TYPEOF) { - type = dmrC_evaluate_expression(C, type->initializer); - if (!type) - type = &C->S->bad_ctype; - else if (type->type == SYM_NODE) - type = type->ctype.base_type; - } - if (type->type == SYM_ENUM) - type = type->ctype.base_type; - *base = type; - if (type->type == SYM_BASETYPE) { - if (type->ctype.base_type == &C->S->int_type) - return TYPE_NUM; - if (type->ctype.base_type == &C->S->fp_type) - return TYPE_NUM | TYPE_FLOAT; - } - return type_class[type->type]; -} - -#define is_int(klass) ((klass & (TYPE_NUM | TYPE_FLOAT)) == TYPE_NUM) - -static inline int is_string_type(struct dmr_C *C, struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - return type->type == SYM_ARRAY && dmrC_is_byte_type(C->target, type->ctype.base_type); -} - -static struct symbol *bad_expr_type(struct dmr_C *C, struct expression *expr) -{ - dmrC_sparse_error(C, expr->pos, "incompatible types for operation (%s)", dmrC_show_special(C, expr->op)); - switch (expr->type) { - case EXPR_BINOP: - case EXPR_COMPARE: - dmrC_info(C, expr->pos, " left side has type %s", dmrC_show_typename(C, expr->left->ctype)); - dmrC_info(C, expr->pos, " right side has type %s", dmrC_show_typename(C, expr->right->ctype)); - break; - case EXPR_PREOP: - case EXPR_POSTOP: - dmrC_info(C, expr->pos, " argument has type %s", dmrC_show_typename(C, expr->unop->ctype)); - break; - default: - break; - } - - expr->flags = 0; - return expr->ctype = &C->S->bad_ctype; -} - -static int restricted_value(struct expression *v, struct symbol *type) -{ - (void)type; - if (v->type != EXPR_VALUE) - return 1; - if (v->value != 0) - return 1; - return 0; -} - -static int restricted_binop(int op) -{ - switch (op) { - case '&': - case '=': - case SPECIAL_AND_ASSIGN: - case SPECIAL_OR_ASSIGN: - case SPECIAL_XOR_ASSIGN: - return 1; /* unfoul */ - case '|': - case '^': - case '?': - return 2; /* keep fouled */ - case SPECIAL_EQUAL: - case SPECIAL_NOTEQUAL: - return 3; /* warn if fouled */ - default: - return 0; /* warn */ - } -} - -static int restricted_unop(struct dmr_C *C, int op, struct symbol **type) -{ - if (op == '~') { - if ((*type)->bit_size < C->target->bits_in_int) - *type = dmrC_befoul(C->S, *type); - return 0; - } if (op == '+') - return 0; - return 1; -} - -/* type should be SYM_FOULED */ -static inline struct symbol *unfoul(struct symbol *type) -{ - return type->ctype.base_type; -} - -static struct symbol *restricted_binop_type(struct dmr_C *C, int op, - struct expression *left, - struct expression *right, - int lclass, int rclass, - struct symbol *ltype, - struct symbol *rtype) -{ - (void) C; - struct symbol *ctype = NULL; - if (lclass & TYPE_RESTRICT) { - if (rclass & TYPE_RESTRICT) { - if (ltype == rtype) { - ctype = ltype; - } else if (lclass & TYPE_FOULED) { - if (unfoul(ltype) == rtype) - ctype = ltype; - } else if (rclass & TYPE_FOULED) { - if (unfoul(rtype) == ltype) - ctype = rtype; - } - } else { - if (!restricted_value(right, ltype)) - ctype = ltype; - } - } else if (!restricted_value(left, rtype)) - ctype = rtype; - - if (ctype) { - switch (restricted_binop(op)) { - case 1: - if ((lclass ^ rclass) & TYPE_FOULED) - ctype = unfoul(ctype); - break; - case 3: - if (!(lclass & rclass & TYPE_FOULED)) - break; - case 0: - ctype = NULL; - default: - break; - } - } - - return ctype; -} - -static inline void unrestrict(struct dmr_C *C, struct expression *expr, - int klass, struct symbol **ctype) -{ - if (klass & TYPE_RESTRICT) { - if (klass & TYPE_FOULED) - *ctype = unfoul(*ctype); - dmrC_warning(C, expr->pos, "%s degrades to integer", - dmrC_show_typename(C, *ctype)); - *ctype = (*ctype)->ctype.base_type; /* get to arithmetic type */ - } -} - -static struct symbol *usual_conversions(struct dmr_C *C, int op, - struct expression *left, - struct expression *right, - int lclass, int rclass, - struct symbol *ltype, - struct symbol *rtype) -{ - struct symbol *ctype; - - warn_for_different_enum_types(C, right->pos, left->ctype, right->ctype); - - if ((lclass | rclass) & TYPE_RESTRICT) - goto Restr; - -Normal: - if (!(lclass & TYPE_FLOAT)) { - if (!(rclass & TYPE_FLOAT)) - return bigger_int_type(C, ltype, rtype); - else - return rtype; - } else if (rclass & TYPE_FLOAT) { - unsigned long lmod = ltype->ctype.modifiers; - unsigned long rmod = rtype->ctype.modifiers; - if (rmod & ~lmod & (MOD_LONG_ALL)) - return rtype; - else - return ltype; - } else - return ltype; - -Restr: - ctype = restricted_binop_type(C, op, left, right, - lclass, rclass, ltype, rtype); - if (ctype) - return ctype; - - unrestrict(C, left, lclass, <ype); - unrestrict(C, right, rclass, &rtype); - - goto Normal; -} - -static inline int lvalue_expression(struct dmr_C *C, struct expression *expr) -{ - (void) C; - return expr->type == EXPR_PREOP && expr->op == '*'; -} - -static struct symbol *evaluate_ptr_add(struct dmr_C *C, struct expression *expr, struct symbol *itype) -{ - struct expression *index = expr->right; - struct symbol *ctype, *base; - int multiply; - - classify_type(C, degenerate(C, expr->left), &ctype); - base = dmrC_examine_pointer_target(C->S, ctype); - - if (!base) { - dmrC_expression_error(C, expr, "missing type information"); - return NULL; - } - if (dmrC_is_function(base)) { - dmrC_expression_error(C, expr, "arithmetics on pointers to functions"); - return NULL; - } - - /* Get the size of whatever the pointer points to */ - multiply = dmrC_is_void_type(C->S, base) ? 1 : dmrC_bits_to_bytes(C->target, base->bit_size); - - if (ctype == &C->S->null_ctype) - ctype = &C->S->ptr_ctype; - expr->ctype = ctype; - - if (multiply == 1 && itype->bit_size >= C->target->bits_in_pointer) - return ctype; - - if (index->type == EXPR_VALUE) { - struct expression *val = dmrC_alloc_expression(C, expr->pos, EXPR_VALUE); - unsigned long long v = index->value, mask; - mask = 1ULL << (itype->bit_size - 1); - if (v & mask) - v |= -mask; - else - v &= mask - 1; - v *= multiply; - mask = 1ULL << (C->target->bits_in_pointer - 1); - v &= mask | (mask - 1); - val->value = v; - val->ctype = C->target->ssize_t_ctype; - expr->right = val; - return ctype; - } - - if (itype->bit_size < C->target->bits_in_pointer) - index = cast_to(C, index, C->target->ssize_t_ctype); - - if (multiply > 1) { - struct expression *val = dmrC_alloc_expression(C, expr->pos, EXPR_VALUE); - struct expression *mul = dmrC_alloc_expression(C, expr->pos, EXPR_BINOP); - - val->ctype = C->target->ssize_t_ctype; - val->value = multiply; - - mul->op = '*'; - mul->ctype = C->target->ssize_t_ctype; - mul->left = index; - mul->right = val; - index = mul; - } - - expr->right = index; - return ctype; -} - - -#define MOD_IGN (MOD_VOLATILE | MOD_CONST | MOD_PURE) - -const char *dmrC_type_difference(struct dmr_C *C, struct ctype *c1, struct ctype *c2, - unsigned long mod1, unsigned long mod2) -{ - unsigned long as1 = c1->as, as2 = c2->as; - struct symbol *t1 = c1->base_type; - struct symbol *t2 = c2->base_type; - int move1 = 1, move2 = 1; - mod1 |= c1->modifiers; - mod2 |= c2->modifiers; - for (;;) { - unsigned long diff; - int type; - struct symbol *base1 = t1->ctype.base_type; - struct symbol *base2 = t2->ctype.base_type; - - /* - * FIXME! Collect alignment and context too here! - */ - if (move1) { - if (t1 && t1->type != SYM_PTR) { - mod1 |= t1->ctype.modifiers; - as1 |= t1->ctype.as; - } - move1 = 0; - } - - if (move2) { - if (t2 && t2->type != SYM_PTR) { - mod2 |= t2->ctype.modifiers; - as2 |= t2->ctype.as; - } - move2 = 0; - } - - if (t1 == t2) - break; - if (!t1 || !t2) - return "different types"; - - if (t1->type == SYM_NODE || t1->type == SYM_ENUM) { - t1 = base1; - move1 = 1; - if (!t1) - return "bad types"; - continue; - } - - if (t2->type == SYM_NODE || t2->type == SYM_ENUM) { - t2 = base2; - move2 = 1; - if (!t2) - return "bad types"; - continue; - } - - move1 = move2 = 1; - type = t1->type; - if (type != t2->type) - return "different base types"; - - switch (type) { - default: - dmrC_sparse_error(C, t1->pos, - "internal error: bad type in derived(%d)", - type); - return "bad types"; - case SYM_RESTRICT: - return "different base types"; - case SYM_UNION: - case SYM_STRUCT: - /* allow definition of incomplete structs and unions */ - if (t1->ident == t2->ident) - return NULL; - return "different base types"; - case SYM_ARRAY: - /* XXX: we ought to compare sizes */ - break; - case SYM_PTR: - if (as1 != as2) - return "different address spaces"; - /* MOD_SPECIFIER is due to idiocy in parse.c */ - if ((mod1 ^ mod2) & ~MOD_IGNORE & ~MOD_SPECIFIER) - return "different modifiers"; - /* we could be lazier here */ - base1 = dmrC_examine_pointer_target(C->S, t1); - base2 = dmrC_examine_pointer_target(C->S, t2); - mod1 = t1->ctype.modifiers; - as1 = t1->ctype.as; - mod2 = t2->ctype.modifiers; - as2 = t2->ctype.as; - break; - case SYM_FN: { - struct symbol *arg1, *arg2; - int i; - - if (as1 != as2) - return "different address spaces"; - if ((mod1 ^ mod2) & ~MOD_IGNORE & ~MOD_SIGNEDNESS) - return "different modifiers"; - mod1 = t1->ctype.modifiers; - as1 = t1->ctype.as; - mod2 = t2->ctype.modifiers; - as2 = t2->ctype.as; - - if (t1->variadic != t2->variadic) - return "incompatible variadic arguments"; - examine_fn_arguments(C, t1); - examine_fn_arguments(C, t2); - PREPARE_PTR_LIST(t1->arguments, arg1); - PREPARE_PTR_LIST(t2->arguments, arg2); - i = 1; - for (;;) { - const char *diffstr; - if (!arg1 && !arg2) - break; - if (!arg1 || !arg2) - return "different argument counts"; - diffstr = dmrC_type_difference(C, &arg1->ctype, - &arg2->ctype, - MOD_IGN, MOD_IGN); - if (diffstr) { - ////// FIXME - static char argdiff[80]; - sprintf(argdiff, "incompatible argument %d (%s)", i, diffstr); - return argdiff; - } - NEXT_PTR_LIST(arg1); - NEXT_PTR_LIST(arg2); - i++; - } - FINISH_PTR_LIST(arg2); - FINISH_PTR_LIST(arg1); - break; - } - case SYM_BASETYPE: - if (as1 != as2) - return "different address spaces"; - if (base1 != base2) - return "different base types"; - diff = (mod1 ^ mod2) & ~MOD_IGNORE; - if (!diff) - return NULL; - if (diff & MOD_SIZE) - return "different type sizes"; - else if (diff & ~MOD_SIGNEDNESS) - return "different modifiers"; - else - return "different signedness"; - } - t1 = base1; - t2 = base2; - } - if (as1 != as2) - return "different address spaces"; - if ((mod1 ^ mod2) & ~MOD_IGNORE & ~MOD_SIGNEDNESS) - return "different modifiers"; - return NULL; -} - -static void bad_null(struct dmr_C *C, struct expression *expr) -{ - if (C->Wnon_pointer_null) - dmrC_warning(C, expr->pos, "Using plain integer as NULL pointer"); -} - -static unsigned long target_qualifiers(struct dmr_C *C, struct symbol *type) -{ - (void) C; - unsigned long mod = type->ctype.modifiers & MOD_IGN; - if (type->ctype.base_type && type->ctype.base_type->type == SYM_ARRAY) - mod = 0; - return mod; -} - -static struct symbol *evaluate_ptr_sub(struct dmr_C *C, struct expression *expr) -{ - const char *typediff; - struct symbol *ltype, *rtype; - struct expression *l = expr->left; - struct expression *r = expr->right; - struct symbol *lbase; - - classify_type(C, degenerate(C, l), <ype); - classify_type(C, degenerate(C, r), &rtype); - - lbase = dmrC_examine_pointer_target(C->S, ltype); - dmrC_examine_pointer_target(C->S, rtype); - typediff = dmrC_type_difference(C, <ype->ctype, &rtype->ctype, - target_qualifiers(C, rtype), - target_qualifiers(C, ltype)); - if (typediff) - dmrC_expression_error(C, expr, "subtraction of different types can't work (%s)", typediff); - - if (dmrC_is_function(lbase)) { - dmrC_expression_error(C, expr, "subtraction of functions? Share your drugs"); - return NULL; - } - - expr->ctype = C->target->ssize_t_ctype; - if (lbase->bit_size > C->target->bits_in_char) { - struct expression *sub = dmrC_alloc_expression(C, expr->pos, EXPR_BINOP); - struct expression *div = expr; - struct expression *val = dmrC_alloc_expression(C, expr->pos, EXPR_VALUE); - unsigned long value = dmrC_bits_to_bytes(C->target, lbase->bit_size); - - val->ctype = C->target->size_t_ctype; - val->value = value; - - if (value & (value-1)) { - if (C->Wptr_subtraction_blows) - dmrC_warning(C, expr->pos, "potentially expensive pointer subtraction"); - } - - sub->op = '-'; - sub->ctype = C->target->ssize_t_ctype; - sub->left = l; - sub->right = r; - - div->op = '/'; - div->left = sub; - div->right = val; - } - - return C->target->ssize_t_ctype; -} - -#define is_safe_type(type) ((type)->ctype.modifiers & MOD_SAFE) - -static struct symbol *evaluate_conditional(struct dmr_C *C, struct expression *expr, int iterator) -{ - struct symbol *ctype; - - if (!expr) - return NULL; - - if (!iterator && expr->type == EXPR_ASSIGNMENT && expr->op == '=') - dmrC_warning(C, expr->pos, "assignment expression in conditional"); - - ctype = dmrC_evaluate_expression(C, expr); - if (ctype) { - if (is_safe_type(ctype)) - dmrC_warning(C, expr->pos, "testing a 'safe expression'"); - if (dmrC_is_func_type(ctype)) { - if (C->Waddress) - dmrC_warning(C, expr->pos, "the address of %s will always evaluate as true", "a function"); - } - else if (dmrC_is_array_type(ctype)) { - if (C->Waddress) - dmrC_warning(C, expr->pos, "the address of %s will always evaluate as true", "an array"); - } - else if (!dmrC_is_scalar_type(C->S, ctype)) { - dmrC_sparse_error(C, expr->pos, "incorrect type in conditional"); - dmrC_info(C, expr->pos, " got %s", dmrC_show_typename(C, ctype)); - ctype = NULL; - } - } - ctype = degenerate(C, expr); - - return ctype; -} - -static struct symbol *evaluate_logical(struct dmr_C *C, struct expression *expr) -{ - if (!evaluate_conditional(C, expr->left, 0)) - return NULL; - if (!evaluate_conditional(C, expr->right, 0)) - return NULL; - - /* the result is int [6.5.13(3), 6.5.14(3)] */ - expr->ctype = &C->S->int_ctype; - if (expr->flags) { - if (!(expr->left->flags & expr->right->flags & Int_const_expr)) - expr->flags = 0; - } - return &C->S->int_ctype; -} - -static struct symbol *evaluate_binop(struct dmr_C *C, struct expression *expr) -{ - struct symbol *ltype, *rtype, *ctype; - int lclass = classify_type(C, expr->left->ctype, <ype); - int rclass = classify_type(C, expr->right->ctype, &rtype); - int op = expr->op; - - if (expr->flags) { - if (!(expr->left->flags & expr->right->flags & Int_const_expr)) - expr->flags = 0; - } - - /* number op number */ - if (lclass & rclass & TYPE_NUM) { - if ((lclass | rclass) & TYPE_FLOAT) { - switch (op) { - case '+': case '-': case '*': case '/': - break; - default: - return bad_expr_type(C, expr); - } - } - - if (op == SPECIAL_LEFTSHIFT || op == SPECIAL_RIGHTSHIFT) { - // shifts do integer promotions, but that's it. - unrestrict(C, expr->left, lclass, <ype); - unrestrict(C, expr->right, rclass, &rtype); - ctype = ltype = integer_promotion(C, ltype); - rtype = integer_promotion(C, rtype); - } else { - // The rest do usual conversions - const unsigned left_not = expr->left->type == EXPR_PREOP - && expr->left->op == '!'; - const unsigned right_not = expr->right->type == EXPR_PREOP - && expr->right->op == '!'; - if ((op == '&' || op == '|') && (left_not || right_not)) - dmrC_warning(C, expr->pos, "dubious: %sx %c %sy", - left_not ? "!" : "", - op, - right_not ? "!" : ""); - - ltype = usual_conversions(C, op, expr->left, expr->right, - lclass, rclass, ltype, rtype); - ctype = rtype = ltype; - } - - expr->left = cast_to(C, expr->left, ltype); - expr->right = cast_to(C, expr->right, rtype); - expr->ctype = ctype; - return ctype; - } - - /* pointer (+|-) integer */ - if (lclass & TYPE_PTR && is_int(rclass) && (op == '+' || op == '-')) { - unrestrict(C, expr->right, rclass, &rtype); - return evaluate_ptr_add(C, expr, rtype); - } - - /* integer + pointer */ - if (rclass & TYPE_PTR && is_int(lclass) && op == '+') { - struct expression *index = expr->left; - unrestrict(C, index, lclass, <ype); - expr->left = expr->right; - expr->right = index; - return evaluate_ptr_add(C, expr, ltype); - } - - /* pointer - pointer */ - if (lclass & rclass & TYPE_PTR && expr->op == '-') - return evaluate_ptr_sub(C, expr); - - return bad_expr_type(C, expr); -} - -static struct symbol *evaluate_comma(struct dmr_C *C, struct expression *expr) -{ - expr->ctype = degenerate(C, expr->right); - if (expr->ctype == &C->S->null_ctype) - expr->ctype = &C->S->ptr_ctype; - expr->flags &= expr->left->flags & expr->right->flags; - return expr->ctype; -} - -static int modify_for_unsigned(struct dmr_C *C, int op) -{ - (void) C; - if (op == '<') - op = SPECIAL_UNSIGNED_LT; - else if (op == '>') - op = SPECIAL_UNSIGNED_GT; - else if (op == SPECIAL_LTE) - op = SPECIAL_UNSIGNED_LTE; - else if (op == SPECIAL_GTE) - op = SPECIAL_UNSIGNED_GTE; - return op; -} - -static inline int is_null_pointer_constant(struct dmr_C *C, struct expression *e) -{ - if (e->ctype == &C->S->null_ctype) - return 1; - if (!(e->flags & Int_const_expr)) - return 0; - return dmrC_is_zero_constant(C, e) ? 2 : 0; -} - -static struct symbol *evaluate_compare(struct dmr_C *C, struct expression *expr) -{ - struct expression *left = expr->left, *right = expr->right; - struct symbol *ltype, *rtype, *lbase, *rbase; - int lclass = classify_type(C, degenerate(C, left), <ype); - int rclass = classify_type(C, degenerate(C, right), &rtype); - struct symbol *ctype; - const char *typediff; - - if (expr->flags) { - if (!(expr->left->flags & expr->right->flags & Int_const_expr)) - expr->flags = 0; - } - - /* Type types? */ - if (dmrC_is_type_type(ltype) && dmrC_is_type_type(rtype)) - goto OK; - - if (is_safe_type(left->ctype) || is_safe_type(right->ctype)) - dmrC_warning(C, expr->pos, "testing a 'safe expression'"); - - /* number on number */ - if (lclass & rclass & TYPE_NUM) { - ctype = usual_conversions(C, expr->op, expr->left, expr->right, - lclass, rclass, ltype, rtype); - expr->left = cast_to(C, expr->left, ctype); - expr->right = cast_to(C, expr->right, ctype); - if (ctype->ctype.modifiers & MOD_UNSIGNED) - expr->op = modify_for_unsigned(C, expr->op); - goto OK; - } - - /* at least one must be a pointer */ - if (!((lclass | rclass) & TYPE_PTR)) - return bad_expr_type(C, expr); - - /* equality comparisons can be with null pointer constants */ - if (expr->op == SPECIAL_EQUAL || expr->op == SPECIAL_NOTEQUAL) { - int is_null1 = is_null_pointer_constant(C, left); - int is_null2 = is_null_pointer_constant(C, right); - if (is_null1 == 2) - bad_null(C, left); - if (is_null2 == 2) - bad_null(C, right); - if (is_null1 && is_null2) { - int positive = expr->op == SPECIAL_EQUAL; - expr->type = EXPR_VALUE; - expr->value = positive; - goto OK; - } - if (is_null1 && (rclass & TYPE_PTR)) { - left = cast_to(C, left, rtype); - goto OK; - } - if (is_null2 && (lclass & TYPE_PTR)) { - right = cast_to(C, right, ltype); - goto OK; - } - } - /* both should be pointers */ - if (!(lclass & rclass & TYPE_PTR)) - return bad_expr_type(C, expr); - expr->op = modify_for_unsigned(C, expr->op); - - lbase = dmrC_examine_pointer_target(C->S, ltype); - rbase = dmrC_examine_pointer_target(C->S, rtype); - - /* they also have special treatment for pointers to void */ - if (expr->op == SPECIAL_EQUAL || expr->op == SPECIAL_NOTEQUAL) { - if (ltype->ctype.as == rtype->ctype.as) { - if (lbase == &C->S->void_ctype) { - right = cast_to(C, right, ltype); - goto OK; - } - if (rbase == &C->S->void_ctype) { - left = cast_to(C, left, rtype); - goto OK; - } - } - } - - typediff = dmrC_type_difference(C, <ype->ctype, &rtype->ctype, - target_qualifiers(C, rtype), - target_qualifiers(C, ltype)); - if (!typediff) - goto OK; - - dmrC_expression_error(C, expr, "incompatible types in comparison expression (%s)", typediff); - return NULL; - -OK: - /* the result is int [6.5.8(6), 6.5.9(3)]*/ - expr->ctype = &C->S->int_ctype; - return &C->S->int_ctype; -} - -/* - * NOTE! The degenerate case of "x ? : y", where we don't - * have a true case, this will possibly promote "x" to the - * same type as "y", and thus _change_ the conditional - * test in the expression. But since promotion is "safe" - * for testing, that's OK. - */ -static struct symbol *evaluate_conditional_expression(struct dmr_C *C, struct expression *expr) -{ - struct expression **truee; - struct symbol *ctype, *ltype, *rtype, *lbase, *rbase; - int lclass, rclass; - const char * typediff; - int qual; - - if (!evaluate_conditional(C, expr->conditional, 0)) - return NULL; - if (!dmrC_evaluate_expression(C, expr->cond_false)) - return NULL; - - ctype = degenerate(C, expr->conditional); - rtype = degenerate(C, expr->cond_false); - - truee = &expr->conditional; - ltype = ctype; - if (expr->cond_true) { - if (!dmrC_evaluate_expression(C, expr->cond_true)) - return NULL; - ltype = degenerate(C, expr->cond_true); - truee = &expr->cond_true; - } - - if (expr->flags) { - int flags = expr->conditional->flags & Int_const_expr; - flags &= (*truee)->flags & expr->cond_false->flags; - if (!flags) - expr->flags = 0; - } - - lclass = classify_type(C, ltype, <ype); - rclass = classify_type(C, rtype, &rtype); - if (lclass & rclass & TYPE_NUM) { - ctype = usual_conversions(C, '?', *truee, expr->cond_false, - lclass, rclass, ltype, rtype); - *truee = cast_to(C, *truee, ctype); - expr->cond_false = cast_to(C, expr->cond_false, ctype); - goto out; - } - - if ((lclass | rclass) & TYPE_PTR) { - int is_null1 = is_null_pointer_constant(C, *truee); - int is_null2 = is_null_pointer_constant(C, expr->cond_false); - - if (is_null1 && is_null2) { - *truee = cast_to(C, *truee, &C->S->ptr_ctype); - expr->cond_false = cast_to(C, expr->cond_false, &C->S->ptr_ctype); - ctype = &C->S->ptr_ctype; - goto out; - } - if (is_null1 && (rclass & TYPE_PTR)) { - if (is_null1 == 2) - bad_null(C, *truee); - *truee = cast_to(C, *truee, rtype); - ctype = rtype; - goto out; - } - if (is_null2 && (lclass & TYPE_PTR)) { - if (is_null2 == 2) - bad_null(C, expr->cond_false); - expr->cond_false = cast_to(C, expr->cond_false, ltype); - ctype = ltype; - goto out; - } - if (!(lclass & rclass & TYPE_PTR)) { - typediff = "different types"; - goto Err; - } - /* OK, it's pointer on pointer */ - if (ltype->ctype.as != rtype->ctype.as) { - typediff = "different address spaces"; - goto Err; - } - - /* need to be lazier here */ - lbase = dmrC_examine_pointer_target(C->S, ltype); - rbase = dmrC_examine_pointer_target(C->S, rtype); - qual = target_qualifiers(C, ltype) | target_qualifiers(C, rtype); - - if (lbase == &C->S->void_ctype) { - /* XXX: pointers to function should warn here */ - ctype = ltype; - goto Qual; - - } - if (rbase == &C->S->void_ctype) { - /* XXX: pointers to function should warn here */ - ctype = rtype; - goto Qual; - } - /* XXX: that should be pointer to composite */ - ctype = ltype; - typediff = dmrC_type_difference(C, <ype->ctype, &rtype->ctype, - qual, qual); - if (!typediff) - goto Qual; - goto Err; - } - - /* void on void, struct on same struct, union on same union */ - if (ltype == rtype) { - ctype = ltype; - goto out; - } - typediff = "different base types"; - -Err: - dmrC_expression_error(C, expr, "incompatible types in conditional expression (%s)", typediff); - /* - * if the condition is constant, the type is in fact known - * so use it, as gcc & clang do. - */ - switch (dmrC_expr_truth_value(C, expr->conditional)) { - case 1: expr->ctype = ltype; - break; - case 0: expr->ctype = rtype; - break; - default: - break; - } - return NULL; - -out: - expr->ctype = ctype; - return ctype; - -Qual: - if (qual & ~ctype->ctype.modifiers) { - struct symbol *sym = dmrC_alloc_symbol(C->S, ctype->pos, SYM_PTR); - *sym = *ctype; - sym->ctype.modifiers |= qual; - ctype = sym; - } - *truee = cast_to(C, *truee, ctype); - expr->cond_false = cast_to(C, expr->cond_false, ctype); - goto out; -} - -/* FP assignments can not do modulo or bit operations */ -static int compatible_float_op(int op) -{ - return op == SPECIAL_ADD_ASSIGN || - op == SPECIAL_SUB_ASSIGN || - op == SPECIAL_MUL_ASSIGN || - op == SPECIAL_DIV_ASSIGN; -} - -static int evaluate_assign_op(struct dmr_C *C, struct expression *expr) -{ - struct symbol *target = expr->left->ctype; - struct symbol *source = expr->right->ctype; - struct symbol *t, *s; - int tclass = classify_type(C, target, &t); - int sclass = classify_type(C, source, &s); - int op = expr->op; - - if (tclass & sclass & TYPE_NUM) { - if (tclass & TYPE_FLOAT && !compatible_float_op(op)) { - dmrC_expression_error(C, expr, "invalid assignment"); - return 0; - } - if (tclass & TYPE_RESTRICT) { - if (!restricted_binop(op)) { - dmrC_warning(C, expr->pos, "bad assignment (%s) to %s", - dmrC_show_special(C, op), dmrC_show_typename(C, t)); - expr->right = cast_to(C, expr->right, target); - return 0; - } - /* allowed assignments unfoul */ - if (sclass & TYPE_FOULED && unfoul(s) == t) - goto Cast; - if (!restricted_value(expr->right, t)) - return 1; - } else if (!(sclass & TYPE_RESTRICT)) - goto usual; - /* source and target would better be identical restricted */ - if (t == s) - return 1; - dmrC_warning(C, expr->pos, "invalid assignment: %s", dmrC_show_special(C, op)); - dmrC_info(C, expr->pos, " left side has type %s", dmrC_show_typename(C, t)); - dmrC_info(C, expr->pos, " right side has type %s", dmrC_show_typename(C, s)); - expr->right = cast_to(C, expr->right, target); - return 0; - } - if (tclass == TYPE_PTR && is_int(sclass)) { - if (op == SPECIAL_ADD_ASSIGN || op == SPECIAL_SUB_ASSIGN) { - unrestrict(C, expr->right, sclass, &s); - evaluate_ptr_add(C, expr, s); - return 1; - } - dmrC_expression_error(C, expr, "invalid pointer assignment"); - return 0; - } - - dmrC_expression_error(C, expr, "invalid assignment"); - return 0; - -usual: - target = usual_conversions(C, op, expr->left, expr->right, - tclass, sclass, target, source); -Cast: - expr->right = cast_to(C, expr->right, target); - return 1; -} - -static int whitelist_pointers(struct dmr_C *C, struct symbol *t1, struct symbol *t2) -{ - if (t1 == t2) - return 0; /* yes, 0 - we don't want a cast_to here */ - if (t1 == &C->S->void_ctype) - return 1; - if (t2 == &C->S->void_ctype) - return 1; - if (classify_type(C, t1, &t1) != TYPE_NUM) - return 0; - if (classify_type(C, t2, &t2) != TYPE_NUM) - return 0; - if (t1 == t2) - return 1; - if (t1->ctype.modifiers & t2->ctype.modifiers & MOD_CHAR) - return 1; - if ((t1->ctype.modifiers ^ t2->ctype.modifiers) & MOD_SIZE) - return 0; - return !C->Wtypesign; -} - -static int check_assignment_types(struct dmr_C *C, struct symbol *target, struct expression **rp, - const char **typediff) -{ - struct symbol *source = degenerate(C, *rp); - struct symbol *t, *s; - int tclass = classify_type(C, target, &t); - int sclass = classify_type(C, source, &s); - - if (tclass & sclass & TYPE_NUM) { - if (tclass & TYPE_RESTRICT) { - /* allowed assignments unfoul */ - if (sclass & TYPE_FOULED && unfoul(s) == t) - goto Cast; - if (!restricted_value(*rp, target)) - return 1; - if (s == t) - return 1; - } else if (!(sclass & TYPE_RESTRICT)) - goto Cast; - if (t == &C->S->bool_ctype) { - if (dmrC_is_fouled_type(s)) - dmrC_warning(C, (*rp)->pos, "%s degrades to integer", - dmrC_show_typename(C, s->ctype.base_type)); - goto Cast; - } - *typediff = "different base types"; - return 0; - } - - if (tclass == TYPE_PTR) { - unsigned long mod1, mod2; - struct symbol *b1, *b2; - // NULL pointer is always OK - int is_null = is_null_pointer_constant(C, *rp); - if (is_null) { - if (is_null == 2) - bad_null(C, *rp); - goto Cast; - } - if (!(sclass & TYPE_PTR)) { - *typediff = "different base types"; - return 0; - } - b1 = dmrC_examine_pointer_target(C->S, t); - b2 = dmrC_examine_pointer_target(C->S, s); - mod1 = target_qualifiers(C, t); - mod2 = target_qualifiers(C, s); - if (whitelist_pointers(C, b1, b2)) { - /* - * assignments to/from void * are OK, provided that - * we do not remove qualifiers from pointed to [C] - * or mix address spaces [sparse]. - */ - if (t->ctype.as != s->ctype.as) { - *typediff = "different address spaces"; - return 0; - } - /* - * If this is a function pointer assignment, it is - * actually fine to assign a pointer to const data to - * it, as a function pointer points to const data - * implicitly, i.e., dereferencing it does not produce - * an lvalue. - */ - if (b1->type == SYM_FN) - mod1 |= MOD_CONST; - if (mod2 & ~mod1) { - *typediff = "different modifiers"; - return 0; - } - goto Cast; - } - /* It's OK if the target is more volatile or const than the source */ - *typediff = dmrC_type_difference(C, &t->ctype, &s->ctype, 0, mod1); - if (*typediff) - return 0; - return 1; - } - - if ((tclass & TYPE_COMPOUND) && s == t) - return 1; - - if (tclass & TYPE_NUM) { - /* XXX: need to turn into comparison with NULL */ - if (t == &C->S->bool_ctype && (sclass & TYPE_PTR)) - goto Cast; - *typediff = "different base types"; - return 0; - } - *typediff = "invalid types"; - return 0; -Cast: - *rp = cast_to(C, *rp, target); - return 1; -} - -static int compatible_assignment_types(struct dmr_C *C, struct expression *expr, struct symbol *target, - struct expression **rp, const char *where) -{ - const char *typediff; - struct symbol *source = degenerate(C, *rp); - - if (!check_assignment_types(C, target, rp, &typediff)) { - dmrC_warning(C, expr->pos, "incorrect type in %s (%s)", where, typediff); - dmrC_info(C, expr->pos, " expected %s", dmrC_show_typename(C, target)); - dmrC_info(C, expr->pos, " got %s", dmrC_show_typename(C, source)); - *rp = cast_to(C, *rp, target); - return 0; - } - - return 1; -} - -static int compatible_transparent_union(struct dmr_C *C, struct symbol *target, - struct expression **rp) -{ - struct symbol *t, *member; - classify_type(C, target, &t); - if (t->type != SYM_UNION || !t->transparent_union) - return 0; - - FOR_EACH_PTR(t->symbol_list, member) { - const char *typediff; - if (check_assignment_types(C, member, rp, &typediff)) - return 1; - } END_FOR_EACH_PTR(member); - - return 0; -} - -static int compatible_argument_type(struct dmr_C *C, struct expression *expr, struct symbol *target, - struct expression **rp, const char *where) -{ - if (compatible_transparent_union(C, target, rp)) - return 1; - - return compatible_assignment_types(C, expr, target, rp, where); -} -static void mark_assigned(struct dmr_C *C, struct expression *expr) -{ - struct symbol *sym; - - if (!expr) - return; - switch (expr->type) { - case EXPR_SYMBOL: - sym = expr->symbol; - if (!sym) - return; - if (sym->type != SYM_NODE) - return; - sym->ctype.modifiers |= MOD_ASSIGNED; - return; - - case EXPR_BINOP: - mark_assigned(C, expr->left); - mark_assigned(C, expr->right); - return; - case EXPR_CAST: - case EXPR_FORCE_CAST: - mark_assigned(C, expr->cast_expression); - return; - case EXPR_SLICE: - mark_assigned(C, expr->base); - return; - default: - /* Hmm? */ - return; - } -} - -static void evaluate_assign_to(struct dmr_C *C, struct expression *left, struct symbol *type) -{ - if (type->ctype.modifiers & MOD_CONST) - dmrC_expression_error(C, left, "assignment to const expression"); - - /* We know left is an lvalue, so it's a "preop-*" */ - mark_assigned(C, left->unop); -} - -static struct symbol *evaluate_assignment(struct dmr_C *C, struct expression *expr) -{ - struct expression *left = expr->left; - struct expression *where = expr; - struct symbol *ltype; - - if (!lvalue_expression(C, left)) { - dmrC_expression_error(C, expr, "not an lvalue"); - return NULL; - } - - ltype = left->ctype; - - if (expr->op != '=') { - if (!evaluate_assign_op(C, expr)) - return NULL; - } else { - if (!compatible_assignment_types(C, where, ltype, &expr->right, "assignment")) - return NULL; - } - - evaluate_assign_to(C, left, ltype); - - expr->ctype = ltype; - return ltype; -} - -static void examine_fn_arguments(struct dmr_C *C, struct symbol *fn) -{ - struct symbol *s; - - FOR_EACH_PTR(fn->arguments, s) { - struct symbol *arg = evaluate_symbol(C, s); - /* Array/function arguments silently degenerate into pointers */ - if (arg) { - struct symbol *ptr; - switch(arg->type) { - case SYM_ARRAY: - case SYM_FN: - ptr = dmrC_alloc_symbol(C->S, s->pos, SYM_PTR); - if (arg->type == SYM_ARRAY) - ptr->ctype = arg->ctype; - else - ptr->ctype.base_type = arg; - ptr->ctype.as |= s->ctype.as; - ptr->ctype.modifiers |= s->ctype.modifiers & MOD_PTRINHERIT; - - s->ctype.base_type = ptr; - s->ctype.as = 0; - s->ctype.modifiers &= ~MOD_PTRINHERIT; - s->bit_size = 0; - s->examined = 0; - dmrC_examine_symbol_type(C->S, s); - break; - default: - /* nothing */ - break; - } - } - } END_FOR_EACH_PTR(s); -} - -static struct symbol *convert_to_as_mod(struct dmr_C *C, struct symbol *sym, int as, int mod) -{ - /* Take the modifiers of the pointer, and apply them to the member */ - mod |= sym->ctype.modifiers; - if ((int)(sym->ctype.as) != as || (int)(sym->ctype.modifiers) != mod) { - struct symbol *newsym = dmrC_alloc_symbol(C->S, sym->pos, SYM_NODE); - *newsym = *sym; - newsym->ctype.as = as; - newsym->ctype.modifiers = mod; - sym = newsym; - } - return sym; -} - -static struct symbol *create_pointer(struct dmr_C *C, struct expression *expr, struct symbol *sym, int degenerate) -{ - struct symbol *node = dmrC_alloc_symbol(C->S, expr->pos, SYM_NODE); - struct symbol *ptr = dmrC_alloc_symbol(C->S, expr->pos, SYM_PTR); - - node->ctype.base_type = ptr; - ptr->bit_size = C->target->bits_in_pointer; - ptr->ctype.alignment = C->target->pointer_alignment; - - node->bit_size = C->target->bits_in_pointer; - node->ctype.alignment = C->target->pointer_alignment; - - dmrC_access_symbol(C->S, sym); - if (sym->ctype.modifiers & MOD_REGISTER) { - dmrC_warning(C, expr->pos, "taking address of 'register' variable '%s'", dmrC_show_ident(C, sym->ident)); - sym->ctype.modifiers &= ~MOD_REGISTER; - } - if (sym->type == SYM_NODE) { - ptr->ctype.as |= sym->ctype.as; - ptr->ctype.modifiers |= sym->ctype.modifiers & MOD_PTRINHERIT; - sym = sym->ctype.base_type; - } - if (degenerate && sym->type == SYM_ARRAY) { - ptr->ctype.as |= sym->ctype.as; - ptr->ctype.modifiers |= sym->ctype.modifiers & MOD_PTRINHERIT; - sym = sym->ctype.base_type; - } - ptr->ctype.base_type = sym; - - return node; -} - -/* Arrays degenerate into pointers on pointer arithmetic */ -static struct symbol *degenerate(struct dmr_C *C, struct expression *expr) -{ - struct symbol *ctype, *base; - - if (!expr) - return NULL; - ctype = expr->ctype; - if (!ctype) - return NULL; - base = dmrC_examine_symbol_type(C->S, ctype); - if (ctype->type == SYM_NODE) - base = ctype->ctype.base_type; - /* - * Arrays degenerate into pointers to the entries, while - * functions degenerate into pointers to themselves. - * If array was part of non-lvalue compound, we create a copy - * of that compound first and then act as if we were dealing with - * the corresponding field in there. - */ - switch (base->type) { - case SYM_ARRAY: - if (expr->type == EXPR_SLICE) { - struct symbol *a = dmrC_alloc_symbol(C->S, expr->pos, SYM_NODE); - struct expression *e0, *e1, *e2, *e3, *e4; - - a->ctype.base_type = expr->base->ctype; - a->bit_size = expr->base->ctype->bit_size; - a->array_size = expr->base->ctype->array_size; - - e0 = dmrC_alloc_expression(C, expr->pos, EXPR_SYMBOL); - e0->symbol = a; - e0->ctype = &C->S->lazy_ptr_ctype; - - e1 = dmrC_alloc_expression(C, expr->pos, EXPR_PREOP); - e1->unop = e0; - e1->op = '*'; - e1->ctype = expr->base->ctype; /* XXX */ - - e2 = dmrC_alloc_expression(C, expr->pos, EXPR_ASSIGNMENT); - e2->left = e1; - e2->right = expr->base; - e2->op = '='; - e2->ctype = expr->base->ctype; - - if (expr->r_bitpos) { - e3 = dmrC_alloc_expression(C, expr->pos, EXPR_BINOP); - e3->op = '+'; - e3->left = e0; - e3->right = dmrC_alloc_const_expression(C, expr->pos, - dmrC_bits_to_bytes(C->target, expr->r_bitpos)); - e3->ctype = &C->S->lazy_ptr_ctype; - } else { - e3 = e0; - } - - e4 = dmrC_alloc_expression(C, expr->pos, EXPR_COMMA); - e4->left = e2; - e4->right = e3; - e4->ctype = &C->S->lazy_ptr_ctype; - - expr->unop = e4; - expr->type = EXPR_PREOP; - expr->op = '*'; - } - case SYM_FN: - if (expr->op != '*' || expr->type != EXPR_PREOP) { - dmrC_expression_error(C, expr, "strange non-value function or array"); - return &C->S->bad_ctype; - } - *expr = *expr->unop; - ctype = create_pointer(C, expr, ctype, 1); - expr->ctype = ctype; - default: - /* nothing */; - } - return ctype; -} - -static struct symbol *evaluate_addressof(struct dmr_C *C, struct expression *expr) -{ - struct expression *op = expr->unop; - struct symbol *ctype; - - if (op->op != '*' || op->type != EXPR_PREOP) { - dmrC_expression_error(C, expr, "not addressable"); - return NULL; - } - ctype = op->ctype; - *expr = *op->unop; - expr->flags = 0; - - if (expr->type == EXPR_SYMBOL) { - struct symbol *sym = expr->symbol; - sym->ctype.modifiers |= MOD_ADDRESSABLE; - } - - /* - * symbol expression evaluation is lazy about the type - * of the sub-expression, so we may have to generate - * the type here if so.. - */ - if (expr->ctype == &C->S->lazy_ptr_ctype) { - ctype = create_pointer(C, expr, ctype, 0); - expr->ctype = ctype; - } - return expr->ctype; -} - - -static struct symbol *evaluate_dereference(struct dmr_C *C, struct expression *expr) -{ - struct expression *op = expr->unop; - struct symbol *ctype = op->ctype, *node, *target; - - /* Simplify: *&(expr) => (expr) */ - if (op->type == EXPR_PREOP && op->op == '&') { - *expr = *op->unop; - expr->flags = 0; - return expr->ctype; - } - - dmrC_examine_symbol_type(C->S, ctype); - - /* Dereferencing a node drops all the node information. */ - if (ctype->type == SYM_NODE) - ctype = ctype->ctype.base_type; - - node = dmrC_alloc_symbol(C->S, expr->pos, SYM_NODE); - target = ctype->ctype.base_type; - - switch (ctype->type) { - default: - dmrC_expression_error(C, expr, "cannot dereference this type"); - return NULL; - case SYM_PTR: - node->ctype.modifiers = target->ctype.modifiers & MOD_SPECIFIER; - dmrC_merge_type(node, ctype); - break; - - case SYM_ARRAY: - if (!lvalue_expression(C, op)) { - dmrC_expression_error(C, op, "non-lvalue array??"); - return NULL; - } - - /* Do the implied "addressof" on the array */ - *op = *op->unop; - - /* - * When an array is dereferenced, we need to pick - * up the attributes of the original node too.. - */ - dmrC_merge_type(node, op->ctype); - dmrC_merge_type(node, ctype); - break; - } - - node->bit_size = target->bit_size; - node->array_size = target->array_size; - - expr->ctype = node; - return node; -} - -/* - * Unary post-ops: x++ and x-- - */ -static struct symbol *evaluate_postop(struct dmr_C *C, struct expression *expr) -{ - struct expression *op = expr->unop; - struct symbol *ctype = op->ctype; - int klass = classify_type(C, ctype, &ctype); - int multiply = 0; - - if (!klass || klass & TYPE_COMPOUND) { - dmrC_expression_error(C, expr, "need scalar for ++/--"); - return NULL; - } - if (!lvalue_expression(C, expr->unop)) { - dmrC_expression_error(C, expr, "need lvalue expression for ++/--"); - return NULL; - } - - if ((klass & TYPE_RESTRICT) && restricted_unop(C, expr->op, &ctype)) - unrestrict(C, expr, klass, &ctype); - - if (klass & TYPE_NUM) { - multiply = 1; - } else if (klass == TYPE_PTR) { - struct symbol *target = dmrC_examine_pointer_target(C->S, ctype); - if (!dmrC_is_function(target)) - multiply = dmrC_bits_to_bytes(C->target, target->bit_size); - } - - if (multiply) { - evaluate_assign_to(C, op, op->ctype); - expr->op_value = multiply; - expr->ctype = ctype; - return ctype; - } - - dmrC_expression_error(C, expr, "bad argument type for ++/--"); - return NULL; -} - -static struct symbol *evaluate_sign(struct dmr_C *C, struct expression *expr) -{ - struct symbol *ctype = expr->unop->ctype; - int klass = classify_type(C, ctype, &ctype); - if (expr->flags && !(expr->unop->flags & Int_const_expr)) - expr->flags = 0; - /* should be an arithmetic type */ - if (!(klass & TYPE_NUM)) - return bad_expr_type(C, expr); - if (klass & TYPE_RESTRICT) - goto Restr; -Normal: - if (!(klass & TYPE_FLOAT)) { - ctype = integer_promotion(C, ctype); - expr->unop = cast_to(C, expr->unop, ctype); - } else if (expr->op != '~') { - /* no conversions needed */ - } else { - return bad_expr_type(C, expr); - } - if (expr->op == '+') - *expr = *expr->unop; - expr->ctype = ctype; - return ctype; -Restr: - if (restricted_unop(C, expr->op, &ctype)) - unrestrict(C, expr, klass, &ctype); - goto Normal; -} - -static struct symbol *evaluate_preop(struct dmr_C *C, struct expression *expr) -{ - struct symbol *ctype = expr->unop->ctype; - - switch (expr->op) { - case '(': - *expr = *expr->unop; - return ctype; - - case '+': - case '-': - case '~': - return evaluate_sign(C, expr); - - case '*': - return evaluate_dereference(C, expr); - - case '&': - return evaluate_addressof(C, expr); - - case SPECIAL_INCREMENT: - case SPECIAL_DECREMENT: - /* - * From a type evaluation standpoint the preops are - * the same as the postops - */ - return evaluate_postop(C, expr); - - case '!': - if (expr->flags && !(expr->unop->flags & Int_const_expr)) - expr->flags = 0; - if (is_safe_type(ctype)) - dmrC_warning(C, expr->pos, "testing a 'safe expression'"); - if (dmrC_is_float_type(C->S, ctype)) { - struct expression *arg = expr->unop; - expr->type = EXPR_COMPARE; - expr->op = SPECIAL_EQUAL; - expr->left = arg; - expr->right = dmrC_alloc_expression(C, expr->pos, EXPR_FVALUE); - expr->right->ctype = ctype; - expr->right->fvalue = 0; - } else if (dmrC_is_fouled_type(ctype)) { - dmrC_warning(C, expr->pos, "%s degrades to integer", - dmrC_show_typename(C, ctype->ctype.base_type)); - } - /* the result is int [6.5.3.3(5)]*/ - ctype = &C->S->int_ctype; - break; - - default: - break; - } - expr->ctype = ctype; - return ctype; -} - -static struct symbol *find_identifier(struct dmr_C *C, struct ident *ident, struct symbol_list *_list, int *offset) -{ - struct ptr_list *head = (struct ptr_list *)_list; - struct ptr_list *list = head; - - if (!head) - return NULL; - do { - int i; - for (i = 0; i < list->nr_; i++) { - struct symbol *sym = (struct symbol *) list->list_[i]; - if (sym->ident) { - if (sym->ident != ident) - continue; - *offset = sym->offset; - return sym; - } else { - struct symbol *ctype = sym->ctype.base_type; - struct symbol *sub; - if (!ctype) - continue; - if (ctype->type != SYM_UNION && ctype->type != SYM_STRUCT) - continue; - sub = find_identifier(C, ident, ctype->symbol_list, offset); - if (!sub) - continue; - *offset += sym->offset; - return sub; - } - } - } while ((list = list->next_) != head); - return NULL; -} - -static struct expression *evaluate_offset(struct dmr_C *C, struct expression *expr, unsigned long offset) -{ - struct expression *add; - - /* - * Create a new add-expression - * - * NOTE! Even if we just add zero, we need a new node - * for the member pointer, since it has a different - * type than the original pointer. We could make that - * be just a cast, but the fact is, a node is a node, - * so we might as well just do the "add zero" here. - */ - add = dmrC_alloc_expression(C, expr->pos, EXPR_BINOP); - add->op = '+'; - add->left = expr; - add->right = dmrC_alloc_expression(C, expr->pos, EXPR_VALUE); - add->right->ctype = &C->S->int_ctype; - add->right->value = offset; - - /* - * The ctype of the pointer will be lazily evaluated if - * we ever take the address of this member dereference.. - */ - add->ctype = &C->S->lazy_ptr_ctype; - return add; -} - -/* structure/union dereference */ -static struct symbol *evaluate_member_dereference(struct dmr_C *C, struct expression *expr) -{ - int offset; - struct symbol *ctype, *member; - struct expression *deref = expr->deref, *add; - struct ident *ident = expr->member; - unsigned int mod; - int address_space; - - if (!dmrC_evaluate_expression(C, deref)) - return NULL; - if (!ident) { - dmrC_expression_error(C, expr, "bad member name"); - return NULL; - } - - ctype = deref->ctype; - dmrC_examine_symbol_type(C->S, ctype); - address_space = ctype->ctype.as; - mod = ctype->ctype.modifiers; - if (ctype->type == SYM_NODE) { - ctype = ctype->ctype.base_type; - address_space |= ctype->ctype.as; - mod |= ctype->ctype.modifiers; - } - if (!ctype || (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION)) { - dmrC_expression_error(C, expr, "expected structure or union"); - return NULL; - } - offset = 0; - member = find_identifier(C, ident, ctype->symbol_list, &offset); - if (!member) { - const char *type = ctype->type == SYM_STRUCT ? "struct" : "union"; - const char *name = ""; - int namelen = 9; - if (ctype->ident) { - name = ctype->ident->name; - namelen = ctype->ident->len; - } - if (ctype->symbol_list) - dmrC_expression_error(C, expr, "no member '%s' in %s %.*s", - dmrC_show_ident(C, ident), type, namelen, name); - else - dmrC_expression_error(C, expr, "using member '%s' in " - "incomplete %s %.*s", dmrC_show_ident(C, ident), - type, namelen, name); - return NULL; - } - - /* - * The member needs to take on the address space and modifiers of - * the "parent" type. - */ - member = convert_to_as_mod(C, member, address_space, mod); - ctype = dmrC_get_base_type(C->S, member); - - if (!lvalue_expression(C, deref)) { - if (deref->type != EXPR_SLICE) { - expr->base = deref; - expr->r_bitpos = 0; - } else { - expr->base = deref->base; - expr->r_bitpos = deref->r_bitpos; - } - expr->r_bitpos += dmrC_bytes_to_bits(C->target, offset); - expr->type = EXPR_SLICE; - expr->r_nrbits = member->bit_size; - expr->r_bitpos += member->bit_offset; - expr->ctype = member; - return member; - } - - deref = deref->unop; - expr->deref = deref; - - add = evaluate_offset(C, deref, offset); - expr->type = EXPR_PREOP; - expr->op = '*'; - expr->unop = add; - - expr->ctype = member; - return member; -} - -static int is_promoted(struct dmr_C *C, struct expression *expr) -{ - (void) C; - while (1) { - switch (expr->type) { - case EXPR_BINOP: - case EXPR_SELECT: - case EXPR_CONDITIONAL: - return 1; - case EXPR_COMMA: - expr = expr->right; - continue; - case EXPR_PREOP: - switch (expr->op) { - case '(': - expr = expr->unop; - continue; - case '+': - case '-': - case '~': - return 1; - default: - return 0; - } - default: - return 0; - } - } -} - - -static struct symbol *evaluate_cast(struct dmr_C *C, struct expression *); - -static struct symbol *evaluate_type_information(struct dmr_C *C, struct expression *expr) -{ - struct symbol *sym = expr->cast_type; - if (!sym) { - sym = dmrC_evaluate_expression(C, expr->cast_expression); - if (!sym) - return NULL; - /* - * Expressions of restricted types will possibly get - * promoted - check that here - */ - if (dmrC_is_restricted_type(sym)) { - if (sym->bit_size < C->target->bits_in_int && is_promoted(C, expr)) - sym = &C->S->int_ctype; - } else if (dmrC_is_fouled_type(sym)) { - sym = &C->S->int_ctype; - } - } - dmrC_examine_symbol_type(C->S, sym); - if (dmrC_is_bitfield_type(sym)) { - dmrC_expression_error(C, expr, "trying to examine bitfield type"); - return NULL; - } - return sym; -} - -static struct symbol *evaluate_sizeof(struct dmr_C *C, struct expression *expr) -{ - struct symbol *type; - int size; - - type = evaluate_type_information(C, expr); - if (!type) - return NULL; - - size = type->bit_size; - - if (size < 0 && dmrC_is_void_type(C->S, type)) { - dmrC_warning(C, expr->pos, "expression using sizeof(void)"); - size = C->target->bits_in_char; - } - - if (size == 1 && dmrC_is_bool_type(C->S, type)) { - if (C->Wsizeof_bool) - dmrC_warning(C, expr->pos, "expression using sizeof bool"); - size = C->target->bits_in_char; - } - - if (dmrC_is_function(type->ctype.base_type)) { - dmrC_warning(C, expr->pos, "expression using sizeof on a function"); - size = C->target->bits_in_char; - } - - if ((size < 0) || (size & (C->target->bits_in_char - 1))) - dmrC_expression_error(C, expr, "cannot size expression"); - - expr->type = EXPR_VALUE; - expr->value = dmrC_bits_to_bytes(C->target, size); - expr->taint = 0; - expr->ctype = C->target->size_t_ctype; - return C->target->size_t_ctype; -} - -static struct symbol *evaluate_ptrsizeof(struct dmr_C *C, struct expression *expr) -{ - struct symbol *type; - int size; - - type = evaluate_type_information(C, expr); - if (!type) - return NULL; - - if (type->type == SYM_NODE) - type = type->ctype.base_type; - if (!type) - return NULL; - switch (type->type) { - case SYM_ARRAY: - break; - case SYM_PTR: - type = dmrC_get_base_type(C->S, type); - if (type) - break; - default: - dmrC_expression_error(C, expr, "expected pointer expression"); - return NULL; - } - size = type->bit_size; - if (size & (C->target->bits_in_char-1)) - size = 0; - expr->type = EXPR_VALUE; - expr->value = dmrC_bits_to_bytes(C->target, size); - expr->taint = 0; - expr->ctype = C->target->size_t_ctype; - return C->target->size_t_ctype; -} - -static struct symbol *evaluate_alignof(struct dmr_C *C, struct expression *expr) -{ - struct symbol *type; - - type = evaluate_type_information(C, expr); - if (!type) - return NULL; - - expr->type = EXPR_VALUE; - expr->value = type->ctype.alignment; - expr->taint = 0; - expr->ctype = C->target->size_t_ctype; - return C->target->size_t_ctype; -} - -static int evaluate_arguments(struct dmr_C *C, struct symbol *fn, struct expression_list *head) -{ - struct expression *expr; - struct symbol_list *argument_types = fn->arguments; - struct symbol *argtype; - int i = 1; - - PREPARE_PTR_LIST(argument_types, argtype); - FOR_EACH_PTR (head, expr) { - struct expression **p = THIS_ADDRESS(struct expression*, expr); - struct symbol *ctype, *target; - ctype = dmrC_evaluate_expression(C, expr); - - if (!ctype) - return 0; - - target = argtype; - if (!target) { - struct symbol *type; - int klass = classify_type(C, ctype, &type); - if (is_int(klass)) { - *p = cast_to(C, expr, integer_promotion(C, type)); - } else if (klass & TYPE_FLOAT) { - unsigned long mod = type->ctype.modifiers; - if (!(mod & (MOD_LONG_ALL))) - *p = cast_to(C, expr, &C->S->double_ctype); - } else if (klass & TYPE_PTR) { - if (expr->ctype == &C->S->null_ctype) - *p = cast_to(C, expr, &C->S->ptr_ctype); - else - degenerate(C, expr); - } - } else if (!target->forced_arg){ - /// FIXME - static char where[30]; - dmrC_examine_symbol_type(C->S, target); - sprintf(where, "argument %d", i); - compatible_argument_type(C, expr, target, p, where); - } - - i++; - NEXT_PTR_LIST(argtype); - } END_FOR_EACH_PTR(expr); - FINISH_PTR_LIST(argtype); - return 1; -} - -static void convert_index(struct dmr_C *C, struct expression *e) -{ - struct expression *child = e->idx_expression; - unsigned from = e->idx_from; - unsigned to = e->idx_to + 1; - e->type = EXPR_POS; - e->init_offset = from * dmrC_bits_to_bytes(C->target, e->ctype->bit_size); - e->init_nr = to - from; - e->init_expr = child; -} - -static void convert_ident(struct dmr_C *C, struct expression *e) -{ - (void) C; - struct expression *child = e->ident_expression; - int offset = e->offset; - - e->type = EXPR_POS; - e->init_offset = offset; - e->init_nr = 1; - e->init_expr = child; -} - -static void convert_designators(struct dmr_C *C, struct expression *e) -{ - while (e) { - if (e->type == EXPR_INDEX) - convert_index(C, e); - else if (e->type == EXPR_IDENTIFIER) - convert_ident(C, e); - else - break; - e = e->init_expr; - } -} - -static void excess(struct dmr_C *C, struct expression *e, const char *s) -{ - dmrC_warning(C, e->pos, "excessive elements in %s initializer", s); -} - -/* - * implicit designator for the first element - */ -static struct expression *first_subobject(struct dmr_C *C, struct symbol *ctype, int klass, - struct expression **v) -{ - struct expression *e = *v, *newe; - - if (ctype->type == SYM_NODE) - ctype = ctype->ctype.base_type; - - if (klass & TYPE_PTR) { /* array */ - if (!ctype->bit_size) - return NULL; - newe = dmrC_alloc_expression(C, e->pos, EXPR_INDEX); - newe->idx_expression = e; - newe->ctype = ctype->ctype.base_type; - } else { - struct symbol *field, *p; - PREPARE_PTR_LIST(ctype->symbol_list, p); - while (p && !p->ident && dmrC_is_bitfield_type(p)) - NEXT_PTR_LIST(p); - field = p; - FINISH_PTR_LIST(p); - if (!field) - return NULL; - newe = dmrC_alloc_expression(C, e->pos, EXPR_IDENTIFIER); - newe->ident_expression = e; - newe->field = newe->ctype = field; - newe->offset = field->offset; - } - *v = newe; - return newe; -} - -/* - * sanity-check explicit designators; return the innermost one or NULL - * in case of error. Assign types. - */ -static struct expression *check_designators(struct dmr_C *C, struct expression *e, - struct symbol *ctype) -{ - struct expression *last = NULL; - const char *err; - while (1) { - if (ctype->type == SYM_NODE) - ctype = ctype->ctype.base_type; - if (e->type == EXPR_INDEX) { - struct symbol *type; - if (ctype->type != SYM_ARRAY) { - err = "array index in non-array"; - break; - } - type = ctype->ctype.base_type; - if (ctype->bit_size >= 0 && type->bit_size >= 0) { - unsigned offset = (unsigned) dmrC_array_element_offset(C->target, type->bit_size, e->idx_to); - if (offset >= (unsigned) (ctype->bit_size)) { - err = "index out of bounds in"; - break; - } - } - e->ctype = ctype = type; - ctype = type; - last = e; - if (!e->idx_expression) { - err = "invalid"; - break; - } - e = e->idx_expression; - } else if (e->type == EXPR_IDENTIFIER) { - int offset = 0; - if (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION) { - err = "field name not in struct or union"; - break; - } - ctype = find_identifier(C, e->expr_ident, ctype->symbol_list, &offset); - if (!ctype) { - err = "unknown field name in"; - break; - } - e->offset = offset; - e->field = e->ctype = ctype; - last = e; - if (!e->ident_expression) { - err = "invalid"; - break; - } - e = e->ident_expression; - } else if (e->type == EXPR_POS) { - err = "internal front-end error: EXPR_POS in"; - break; - } else - return last; - } - dmrC_expression_error(C, e, "%s initializer", err); - return NULL; -} - -/* - * choose the next subobject to initialize. - * - * Get designators for next element, switch old ones to EXPR_POS. - * Return the resulting expression or NULL if we'd run out of subobjects. - * The innermost designator is returned in *v. Designators in old - * are assumed to be already sanity-checked. - */ -static struct expression *next_designators(struct dmr_C *C, struct expression *old, - struct symbol *ctype, - struct expression *e, struct expression **v) -{ - struct expression *newe = NULL; - - if (!old) - return NULL; - if (old->type == EXPR_INDEX) { - struct expression *copy; - unsigned n; - - copy = next_designators(C, old->idx_expression, - old->ctype, e, v); - if (!copy) { - n = old->idx_to + 1; - if ((int)dmrC_array_element_offset(C->target, old->ctype->bit_size, n) == ctype->bit_size) { - convert_index(C, old); - return NULL; - } - copy = e; - *v = newe = dmrC_alloc_expression(C, e->pos, EXPR_INDEX); - } else { - n = old->idx_to; - newe = dmrC_alloc_expression(C, e->pos, EXPR_INDEX); - } - - newe->idx_from = newe->idx_to = n; - newe->idx_expression = copy; - newe->ctype = old->ctype; - convert_index(C, old); - } else if (old->type == EXPR_IDENTIFIER) { - struct expression *copy; - struct symbol *field; - int offset = 0; - - copy = next_designators(C, old->ident_expression, - old->ctype, e, v); - if (!copy) { - field = old->field->next_subobject; - if (!field) { - convert_ident(C, old); - return NULL; - } - copy = e; - *v = newe = dmrC_alloc_expression(C, e->pos, EXPR_IDENTIFIER); - /* - * We can't necessarily trust "field->offset", - * because the field might be in an anonymous - * union, and the field offset is then the offset - * within that union. - * - * The "old->offset - old->field->offset" - * would be the offset of such an anonymous - * union. - */ - offset = old->offset - old->field->offset; - } else { - field = old->field; - newe = dmrC_alloc_expression(C, e->pos, EXPR_IDENTIFIER); - } - - newe->field = field; - newe->expr_ident = field->ident; - newe->ident_expression = copy; - newe->ctype = field; - newe->offset = field->offset + offset; - convert_ident(C, old); - } - return newe; -} - -static int handle_simple_initializer(struct dmr_C *C, struct expression **ep, int nested, - int klass, struct symbol *ctype); - -/* - * deal with traversing subobjects [6.7.8(17,18,20)] - */ -static void handle_list_initializer(struct dmr_C *C, struct expression *expr, - int klass, struct symbol *ctype) -{ - struct expression *e, *last = NULL, *top = NULL, *next; - int jumped = 0; - - FOR_EACH_PTR(expr->expr_list, e) { - struct expression **v; - struct symbol *type; - int lclass; - - if (e->type != EXPR_INDEX && e->type != EXPR_IDENTIFIER) { - struct symbol *struct_sym; - if (!top) { - top = e; - last = first_subobject(C, ctype, klass, &top); - } else { - last = next_designators(C, last, ctype, e, &top); - } - if (!last) { - excess(C, e, klass & TYPE_PTR ? "array" : - "struct or union"); - DELETE_CURRENT_PTR(e); - continue; - } - struct_sym = ctype->type == SYM_NODE ? ctype->ctype.base_type : ctype; - if (C->Wdesignated_init && struct_sym->designated_init) - dmrC_warning(C, e->pos, "%s%.*s%spositional init of field in %s %s, declared with attribute designated_init", - ctype->ident ? "in initializer for " : "", - ctype->ident ? ctype->ident->len : 0, - ctype->ident ? ctype->ident->name : "", - ctype->ident ? ": " : "", - dmrC_get_type_name(struct_sym->type), - dmrC_show_ident(C, struct_sym->ident)); - if (jumped) { - dmrC_warning(C, e->pos, "advancing past deep designator"); - jumped = 0; - } - REPLACE_CURRENT_PTR(struct expression *, e, last); - } else { - next = check_designators(C, e, ctype); - if (!next) { - DELETE_CURRENT_PTR(e); - continue; - } - top = next; - /* deeper than one designator? */ - jumped = top != e; - convert_designators(C, last); - last = e; - } - -found: - lclass = classify_type(C, top->ctype, &type); - if (top->type == EXPR_INDEX) - v = &top->idx_expression; - else - v = &top->ident_expression; - - if (handle_simple_initializer(C, v, 1, lclass, top->ctype)) - continue; - - if (!(lclass & TYPE_COMPOUND)) { - dmrC_warning(C, e->pos, "bogus scalar initializer"); - DELETE_CURRENT_PTR(e); - continue; - } - - next = first_subobject(C, type, lclass, v); - if (next) { - dmrC_warning(C, e->pos, "missing braces around initializer"); - top = next; - goto found; - } - - DELETE_CURRENT_PTR(e); - excess(C, e, lclass & TYPE_PTR ? "array" : "struct or union"); - - } END_FOR_EACH_PTR(e); - - convert_designators(C, last); - expr->ctype = ctype; -} - -static int is_string_literal(struct dmr_C *C, struct expression **v) -{ - struct expression *e = *v; - while (e && e->type == EXPR_PREOP && e->op == '(') - e = e->unop; - if (!e || e->type != EXPR_STRING) - return 0; - if (e != *v && C->Wparen_string) - dmrC_warning(C, e->pos, - "array initialized from parenthesized string constant"); - *v = e; - return 1; -} - -/* - * We want a normal expression, possibly in one layer of braces. Warn - * if the latter happens inside a list (it's legal, but likely to be - * an effect of screwup). In case of anything not legal, we are definitely - * having an effect of screwup, so just fail and let the caller warn. - */ -static struct expression *handle_scalar(struct dmr_C *C, struct expression *e, int nested) -{ - struct expression *v = NULL, *p; - int count = 0; - - /* normal case */ - if (e->type != EXPR_INITIALIZER) - return e; - - FOR_EACH_PTR(e->expr_list, p) { - if (!v) - v = p; - count++; - } END_FOR_EACH_PTR(p); - if (count != 1) - return NULL; - switch(v->type) { - case EXPR_INITIALIZER: - case EXPR_INDEX: - case EXPR_IDENTIFIER: - return NULL; - default: - break; - } - if (nested) - dmrC_warning(C, e->pos, "braces around scalar initializer"); - return v; -} - -/* - * deal with the cases that don't care about subobjects: - * scalar <- assignment expression, possibly in braces [6.7.8(11)] - * character array <- string literal, possibly in braces [6.7.8(14)] - * struct or union <- assignment expression of compatible type [6.7.8(13)] - * compound type <- initializer list in braces [6.7.8(16)] - * The last one punts to handle_list_initializer() which, in turn will call - * us for individual elements of the list. - * - * We do not handle 6.7.8(15) (wide char array <- wide string literal) for - * the lack of support of wide char stuff in general. - * - * One note: we need to take care not to evaluate a string literal until - * we know that we *will* handle it right here. Otherwise we would screw - * the cases like struct { struct {char s[10]; ...} ...} initialized with - * { "string", ...} - we need to preserve that string literal recognizable - * until we dig into the inner struct. - */ -static int handle_simple_initializer(struct dmr_C *C, struct expression **ep, int nested, - int klass, struct symbol *ctype) -{ - int is_string = is_string_type(C, ctype); - struct expression *e = *ep, *p; - struct symbol *type; - - if (!e) - return 0; - - /* scalar */ - if (!(klass & TYPE_COMPOUND)) { - e = handle_scalar(C, e, nested); - if (!e) - return 0; - *ep = e; - if (!dmrC_evaluate_expression(C, e)) - return 1; - compatible_assignment_types(C, e, ctype, ep, "initializer"); - return 1; - } - - /* - * sublist; either a string, or we dig in; the latter will deal with - * pathologies, so we don't need anything fancy here. - */ - if (e->type == EXPR_INITIALIZER) { - if (is_string) { - struct expression *v = NULL; - int count = 0; - - FOR_EACH_PTR(e->expr_list, p) { - if (!v) - v = p; - count++; - } END_FOR_EACH_PTR(p); - if (count == 1 && is_string_literal(C, &v)) { - *ep = e = v; - goto String; - } - } - handle_list_initializer(C, e, klass, ctype); - return 1; - } - - /* string */ - if (is_string_literal(C, &e)) { - /* either we are doing array of char, or we'll have to dig in */ - if (is_string) { - *ep = e; - goto String; - } - return 0; - } - /* struct or union can be initialized by compatible */ - if (klass != TYPE_COMPOUND) - return 0; - type = dmrC_evaluate_expression(C, e); - if (!type) - return 0; - if (ctype->type == SYM_NODE) - ctype = ctype->ctype.base_type; - if (type->type == SYM_NODE) - type = type->ctype.base_type; - if (ctype == type) - return 1; - return 0; - -String: - p = dmrC_alloc_expression(C, e->pos, EXPR_STRING); - *p = *e; - type = dmrC_evaluate_expression(C, p); - if (ctype->bit_size != -1) { - if (ctype->bit_size + C->target->bits_in_char < type->bit_size) - dmrC_warning(C, e->pos, - "too long initializer-string for array of char"); - else if (C->Winit_cstring && ctype->bit_size + C->target->bits_in_char == type->bit_size) { - dmrC_warning(C, e->pos, - "too long initializer-string for array of char(no space for nul char)"); - } - } - *ep = p; - return 1; -} - -static void evaluate_initializer(struct dmr_C *C, struct symbol *ctype, struct expression **ep) -{ - struct symbol *type; - int klass = classify_type(C, ctype, &type); - if (!handle_simple_initializer(C, ep, 0, klass, ctype)) - dmrC_expression_error(C, *ep, "invalid initializer"); -} - -static struct symbol *cast_to_bool(struct dmr_C *C, struct expression *expr) -{ - struct expression *old = expr->cast_expression; - struct expression *zero; - struct symbol *otype; - int oclass = classify_type(C, degenerate(C, old), &otype); - struct symbol *ctype; - - if (oclass & TYPE_COMPOUND) - return NULL; - - zero = dmrC_alloc_const_expression(C, expr->pos, 0); - expr->op = SPECIAL_NOTEQUAL; - ctype = usual_conversions(C, expr->op, old, zero, - oclass, TYPE_NUM, otype, zero->ctype); - expr->type = EXPR_COMPARE; - expr->left = cast_to(C, old, ctype); - expr->right = cast_to(C, zero, ctype); - - return expr->ctype; -} -static struct symbol *evaluate_cast(struct dmr_C *C, struct expression *expr) -{ - struct expression *target = expr->cast_expression; - struct symbol *ctype; - struct symbol *t1, *t2; - int class1, class2; - int as1 = 0, as2 = 0; - - if (!target) - return NULL; - - /* - * Special case: a cast can be followed by an - * initializer, in which case we need to pass - * the type value down to that initializer rather - * than trying to evaluate it as an expression - * - * A more complex case is when the initializer is - * dereferenced as part of a post-fix expression. - * We need to produce an expression that can be dereferenced. - */ - if (target->type == EXPR_INITIALIZER) { - struct symbol *sym = expr->cast_type; - struct expression *addr = dmrC_alloc_expression(C, expr->pos, EXPR_SYMBOL); - - sym->initializer = target; - evaluate_symbol(C, sym); - - addr->ctype = &C->S->lazy_ptr_ctype; /* Lazy eval */ - addr->symbol = sym; - - expr->type = EXPR_PREOP; - expr->op = '*'; - expr->unop = addr; - expr->ctype = sym; - - return sym; - } - - ctype = dmrC_examine_symbol_type(C->S, expr->cast_type); - expr->ctype = ctype; - expr->cast_type = ctype; - - dmrC_evaluate_expression(C, target); - degenerate(C, target); - - class1 = classify_type(C, ctype, &t1); - - /* cast to non-integer type -> not an integer constant expression */ - if (!is_int(class1)) - expr->flags = 0; - /* if argument turns out to be not an integer constant expression *and* - it was not a floating literal to start with -> too bad */ - else if (expr->flags == Int_const_expr && - !(target->flags & Int_const_expr)) - expr->flags = 0; - /* - * You can always throw a value away by casting to - * "void" - that's an implicit "force". Note that - * the same is _not_ true of "void *". - */ - if (t1 == &C->S->void_ctype) - goto out; - - if (class1 & (TYPE_COMPOUND | TYPE_FN)) - dmrC_warning(C, expr->pos, "cast to non-scalar"); - - t2 = target->ctype; - if (!t2) { - dmrC_expression_error(C, expr, "cast from unknown type"); - goto out; - } - class2 = classify_type(C, t2, &t2); - - if (class2 & TYPE_COMPOUND) - dmrC_warning(C, expr->pos, "cast from non-scalar"); - - if (expr->type == EXPR_FORCE_CAST) - goto out; - - /* allowed cast unfouls */ - if (class2 & TYPE_FOULED) - t2 = unfoul(t2); - - if (t1 != t2) { - if ((class1 & TYPE_RESTRICT) && restricted_value(target, t1)) - dmrC_warning(C, expr->pos, "cast to %s", - dmrC_show_typename(C, t1)); - if (class2 & TYPE_RESTRICT) { - if (t1 == &C->S->bool_ctype) { - if (class2 & TYPE_FOULED) - dmrC_warning(C, expr->pos, "%s degrades to integer", - dmrC_show_typename(C, t2)); - } - else { - dmrC_warning(C, expr->pos, "cast from %s", - dmrC_show_typename(C, t2)); - } - } - } - - if (t1 == &C->S->ulong_ctype) - as1 = -1; - else if (class1 == TYPE_PTR) { - dmrC_examine_pointer_target(C->S, t1); - as1 = t1->ctype.as; - } - - if (t2 == &C->S->ulong_ctype) - as2 = -1; - else if (class2 == TYPE_PTR) { - dmrC_examine_pointer_target(C->S, t2); - as2 = t2->ctype.as; - } - - if (!as1 && as2 > 0) - dmrC_warning(C, expr->pos, "cast removes address space of expression"); - if (as1 > 0 && as2 > 0 && as1 != as2) - dmrC_warning(C, expr->pos, "cast between address spaces (->)", as2, as1); - if (as1 > 0 && !as2 && - !is_null_pointer_constant(C, target) && C->Wcast_to_as) - dmrC_warning(C, expr->pos, - "cast adds address space to expression ()", as1); - - if (!(t1->ctype.modifiers & MOD_PTRINHERIT) && class1 == TYPE_PTR && - !as1 && (target->flags & Int_const_expr)) { - if (t1->ctype.base_type == &C->S->void_ctype) { - if (dmrC_is_zero_constant(C, target)) { - /* NULL */ - expr->type = EXPR_VALUE; - expr->ctype = &C->S->null_ctype; - expr->value = 0; - return expr->ctype; - } - } - } - - if (t1 == &C->S->bool_ctype) - cast_to_bool(C, expr); - -out: - return ctype; -} - -/* - * Evaluate a call expression with a symbol. This - * should expand inline functions, and evaluate - * builtins. - */ -static int evaluate_symbol_call(struct dmr_C *C, struct expression *expr) -{ - struct expression *fn = expr->fn; - struct symbol *ctype = fn->ctype; - - if (fn->type != EXPR_PREOP) - return 0; - - if (ctype->op && ctype->op->evaluate) - return ctype->op->evaluate(C, expr); - - if (ctype->ctype.modifiers & MOD_INLINE) { - int ret; - struct symbol *curr = C->current_fn; - - if (ctype->definition) - ctype = ctype->definition; - - C->current_fn = ctype->ctype.base_type; - - ret = dmrC_inline_function(C, expr, ctype); - - /* restore the old function */ - C->current_fn = curr; - return ret; - } - - return 0; -} - -static struct symbol *evaluate_call(struct dmr_C *C, struct expression *expr) -{ - int args, fnargs; - struct symbol *ctype, *sym; - struct expression *fn = expr->fn; - struct expression_list *arglist = expr->args; - - if (!dmrC_evaluate_expression(C, fn)) - return NULL; - sym = ctype = fn->ctype; - if (ctype->type == SYM_NODE) - ctype = ctype->ctype.base_type; - if (ctype->type == SYM_PTR) - ctype = dmrC_get_base_type(C->S, ctype); - - if (ctype->type != SYM_FN) { - struct expression *arg; - dmrC_expression_error(C, expr, "not a function %s", - dmrC_show_ident(C, sym->ident)); - /* do typechecking in arguments */ - FOR_EACH_PTR (arglist, arg) { - dmrC_evaluate_expression(C, arg); - } END_FOR_EACH_PTR(arg); - return NULL; - } - - examine_fn_arguments(C, ctype); - if (sym->type == SYM_NODE && fn->type == EXPR_PREOP && - sym->op && sym->op->args) { - if (!sym->op->args(C, expr)) - return NULL; - } else { - if (!evaluate_arguments(C, ctype, arglist)) - return NULL; - args = dmrC_expression_list_size(expr->args); - fnargs = dmrC_symbol_list_size(ctype->arguments); - if (args < fnargs) - dmrC_expression_error(C, expr, - "not enough arguments for function %s", - dmrC_show_ident(C, sym->ident)); - if (args > fnargs && !ctype->variadic) - dmrC_expression_error(C, expr, - "too many arguments for function %s", - dmrC_show_ident(C, sym->ident)); - } - if (sym->type == SYM_NODE) { - if (evaluate_symbol_call(C, expr)) - return expr->ctype; - } - expr->ctype = ctype->ctype.base_type; - return expr->ctype; -} - -static struct symbol *evaluate_offsetof(struct dmr_C *C, struct expression *expr) -{ - struct expression *e = expr->down; - struct symbol *ctype = expr->in; - int klass; - - if (expr->op == '.') { - struct symbol *field; - int offset = 0; - if (!ctype) { - dmrC_expression_error(C, expr, "expected structure or union"); - return NULL; - } - dmrC_examine_symbol_type(C->S, ctype); - klass = classify_type(C, ctype, &ctype); - if (klass != TYPE_COMPOUND) { - dmrC_expression_error(C, expr, "expected structure or union"); - return NULL; - } - - field = find_identifier(C, expr->ident, ctype->symbol_list, &offset); - if (!field) { - dmrC_expression_error(C, expr, "unknown member"); - return NULL; - } - ctype = field; - expr->type = EXPR_VALUE; - expr->flags = Int_const_expr; - expr->value = offset; - expr->taint = 0; - expr->ctype = C->target->size_t_ctype; - } else { - if (!ctype) { - dmrC_expression_error(C, expr, "expected structure or union"); - return NULL; - } - dmrC_examine_symbol_type(C->S, ctype); - klass = classify_type(C, ctype, &ctype); - if (klass != (TYPE_COMPOUND | TYPE_PTR)) { - dmrC_expression_error(C, expr, "expected array"); - return NULL; - } - ctype = ctype->ctype.base_type; - if (!expr->index) { - expr->type = EXPR_VALUE; - expr->flags = Int_const_expr; - expr->value = 0; - expr->taint = 0; - expr->ctype = C->target->size_t_ctype; - } else { - struct expression *idx = expr->index, *m; - struct symbol *i_type = dmrC_evaluate_expression(C, idx); - int i_class = classify_type(C, i_type, &i_type); - if (!is_int(i_class)) { - dmrC_expression_error(C, expr, "non-integer index"); - return NULL; - } - unrestrict(C, idx, i_class, &i_type); - idx = cast_to(C, idx, C->target->size_t_ctype); - m = dmrC_alloc_const_expression(C, expr->pos, - dmrC_bits_to_bytes(C->target, ctype->bit_size)); - m->ctype = C->target->size_t_ctype; - m->flags = Int_const_expr; - expr->type = EXPR_BINOP; - expr->left = idx; - expr->right = m; - expr->op = '*'; - expr->ctype = C->target->size_t_ctype; - expr->flags = m->flags & idx->flags & Int_const_expr; - } - } - if (e) { - struct expression *copy = (struct expression *)dmrC_allocator_allocate(&C->expression_allocator, 0); - *copy = *expr; - if (e->type == EXPR_OFFSETOF) - e->in = ctype; - if (!dmrC_evaluate_expression(C, e)) - return NULL; - expr->type = EXPR_BINOP; - expr->flags = e->flags & copy->flags & Int_const_expr; - expr->op = '+'; - expr->ctype = C->target->size_t_ctype; - expr->left = copy; - expr->right = e; - } - return C->target->size_t_ctype; -} - -struct symbol *dmrC_evaluate_expression(struct dmr_C *C, struct expression *expr) -{ - if (!expr) - return NULL; - if (expr->ctype) - return expr->ctype; - - switch (expr->type) { - case EXPR_VALUE: - case EXPR_FVALUE: - dmrC_expression_error(C, expr, "value expression without a type"); - return NULL; - case EXPR_STRING: - return evaluate_string(C, expr); - case EXPR_SYMBOL: - return evaluate_symbol_expression(C, expr); - case EXPR_BINOP: - if (!dmrC_evaluate_expression(C, expr->left)) - return NULL; - if (!dmrC_evaluate_expression(C, expr->right)) - return NULL; - return evaluate_binop(C, expr); - case EXPR_LOGICAL: - return evaluate_logical(C, expr); - case EXPR_COMMA: - dmrC_evaluate_expression(C, expr->left); - if (!dmrC_evaluate_expression(C, expr->right)) - return NULL; - return evaluate_comma(C, expr); - case EXPR_COMPARE: - if (!dmrC_evaluate_expression(C, expr->left)) - return NULL; - if (!dmrC_evaluate_expression(C, expr->right)) - return NULL; - return evaluate_compare(C, expr); - case EXPR_ASSIGNMENT: - if (!dmrC_evaluate_expression(C, expr->left)) - return NULL; - if (!dmrC_evaluate_expression(C, expr->right)) - return NULL; - return evaluate_assignment(C, expr); - case EXPR_PREOP: - if (!dmrC_evaluate_expression(C, expr->unop)) - return NULL; - return evaluate_preop(C, expr); - case EXPR_POSTOP: - if (!dmrC_evaluate_expression(C, expr->unop)) - return NULL; - return evaluate_postop(C, expr); - case EXPR_CAST: - case EXPR_FORCE_CAST: - case EXPR_IMPLIED_CAST: - return evaluate_cast(C, expr); - case EXPR_SIZEOF: - return evaluate_sizeof(C, expr); - case EXPR_PTRSIZEOF: - return evaluate_ptrsizeof(C, expr); - case EXPR_ALIGNOF: - return evaluate_alignof(C, expr); - case EXPR_DEREF: - return evaluate_member_dereference(C, expr); - case EXPR_CALL: - return evaluate_call(C, expr); - case EXPR_SELECT: - case EXPR_CONDITIONAL: - return evaluate_conditional_expression(C, expr); - case EXPR_STATEMENT: - expr->ctype = dmrC_evaluate_statement(C, expr->statement); - return expr->ctype; - - case EXPR_LABEL: - expr->ctype = &C->S->ptr_ctype; - return &C->S->ptr_ctype; - - case EXPR_TYPE: - /* Evaluate the type of the symbol .. */ - evaluate_symbol(C, expr->symbol); - /* .. but the type of the _expression_ is a "type" */ - expr->ctype = &C->S->type_ctype; - return &C->S->type_ctype; - - case EXPR_OFFSETOF: - return evaluate_offsetof(C, expr); - - /* These can not exist as stand-alone expressions */ - case EXPR_INITIALIZER: - case EXPR_IDENTIFIER: - case EXPR_INDEX: - case EXPR_POS: - dmrC_expression_error(C, expr, "internal front-end error: initializer in expression"); - return NULL; - case EXPR_SLICE: - dmrC_expression_error(C, expr, "internal front-end error: SLICE re-evaluated"); - return NULL; - } - return NULL; -} - -static void check_duplicates(struct dmr_C *C, struct symbol *sym) -{ - int declared = 0; - struct symbol *next = sym; - int initialized = sym->initializer != NULL; - - while ((next = next->same_symbol) != NULL) { - const char *typediff; - evaluate_symbol(C, next); - if (initialized && next->initializer) { - dmrC_sparse_error(C, sym->pos, "symbol '%s' has multiple initializers (originally initialized at %s:%d)", - dmrC_show_ident(C, sym->ident), - dmrC_stream_name(C, next->pos.stream), next->pos.line); - /* Only warn once */ - initialized = 0; - } - declared++; - typediff = dmrC_type_difference(C, &sym->ctype, &next->ctype, 0, 0); - if (typediff) { - dmrC_sparse_error(C, sym->pos, "symbol '%s' redeclared with different type (originally declared at %s:%d) - %s", - dmrC_show_ident(C, sym->ident), - dmrC_stream_name(C, next->pos.stream), next->pos.line, typediff); - return; - } - } - if (!declared) { - unsigned long mod = sym->ctype.modifiers; - if (mod & (MOD_STATIC | MOD_REGISTER)) - return; - if (!(mod & MOD_TOPLEVEL)) - return; - if (!C->Wdecl) - return; - if (sym->ident == C->S->main_ident) - return; - dmrC_warning(C, sym->pos, "symbol '%s' was not declared. Should it be static?", dmrC_show_ident(C, sym->ident)); - } -} - -static struct symbol *evaluate_symbol(struct dmr_C *C, struct symbol *sym) -{ - struct symbol *base_type; - - if (!sym) - return sym; - if (sym->evaluated) - return sym; - sym->evaluated = 1; - - sym = dmrC_examine_symbol_type(C->S, sym); - base_type = dmrC_get_base_type(C->S, sym); - if (!base_type) - return NULL; - - /* Evaluate the initializers */ - if (sym->initializer) - evaluate_initializer(C, sym, &sym->initializer); - - /* And finally, evaluate the body of the symbol too */ - if (base_type->type == SYM_FN) { - struct symbol *curr = C->current_fn; - - if (sym->definition && sym->definition != sym) - return evaluate_symbol(C, sym->definition); - - C->current_fn = base_type; - - examine_fn_arguments(C, base_type); - if (!base_type->stmt && base_type->inline_stmt) - dmrC_uninline(C, sym); - if (base_type->stmt) - dmrC_evaluate_statement(C, base_type->stmt); - - C->current_fn = curr; - } - - return base_type; -} - -void dmrC_evaluate_symbol_list(struct dmr_C *C, struct symbol_list *list) -{ - struct symbol *sym; - - FOR_EACH_PTR(list, sym) { - C->has_error &= ~ERROR_CURR_PHASE; - evaluate_symbol(C, sym); - check_duplicates(C, sym); - } END_FOR_EACH_PTR(sym); -} - -static struct symbol *evaluate_return_expression(struct dmr_C *C, struct statement *stmt) -{ - struct expression *expr = stmt->expression; - struct symbol *fntype; - - dmrC_evaluate_expression(C, expr); - fntype = C->current_fn->ctype.base_type; - if (!fntype || fntype == &C->S->void_ctype) { - if (expr && expr->ctype != &C->S->void_ctype) - dmrC_expression_error(C, expr, "return expression in %s function", fntype?"void":"typeless"); - if (expr && C->Wreturn_void) - dmrC_warning(C, stmt->pos, "returning void-valued expression"); - return NULL; - } - - if (!expr) { - dmrC_sparse_error(C, stmt->pos, "return with no return value"); - return NULL; - } - if (!expr->ctype) - return NULL; - compatible_assignment_types(C, expr, fntype, &stmt->expression, "return expression"); - return NULL; -} - -static void evaluate_if_statement(struct dmr_C *C, struct statement *stmt) -{ - if (!stmt->if_conditional) - return; - - evaluate_conditional(C, stmt->if_conditional, 0); - dmrC_evaluate_statement(C, stmt->if_true); - dmrC_evaluate_statement(C, stmt->if_false); -} - -static void evaluate_iterator(struct dmr_C *C, struct statement *stmt) -{ - dmrC_evaluate_symbol_list(C, stmt->iterator_syms); - evaluate_conditional(C, stmt->iterator_pre_condition, 1); - evaluate_conditional(C, stmt->iterator_post_condition,1); - dmrC_evaluate_statement(C, stmt->iterator_pre_statement); - dmrC_evaluate_statement(C, stmt->iterator_statement); - dmrC_evaluate_statement(C, stmt->iterator_post_statement); -} - -static void verify_output_constraint(struct dmr_C *C, struct expression *expr, const char *constraint) -{ - switch (*constraint) { - case '=': /* Assignment */ - case '+': /* Update */ - break; - default: - dmrC_expression_error(C, expr, "output constraint is not an assignment constraint (\"%s\")", constraint); - } -} - -static void verify_input_constraint(struct dmr_C *C, struct expression *expr, const char *constraint) -{ - switch (*constraint) { - case '=': /* Assignment */ - case '+': /* Update */ - dmrC_expression_error(C, expr, "input constraint with assignment (\"%s\")", constraint); - } -} - -static void evaluate_asm_statement(struct dmr_C *C, struct statement *stmt) -{ - struct expression *expr; - struct symbol *sym; - int state; - - expr = stmt->asm_string; - if (!expr || expr->type != EXPR_STRING) { - dmrC_sparse_error(C, stmt->pos, "need constant string for inline asm"); - return; - } - - state = 0; - FOR_EACH_PTR(stmt->asm_outputs, expr) { - switch (state) { - case 0: /* Identifier */ - state = 1; - continue; - - case 1: /* Constraint */ - state = 2; - if (!expr || expr->type != EXPR_STRING) { - dmrC_sparse_error(C, expr ? expr->pos : stmt->pos, "asm output constraint is not a string"); - *THIS_ADDRESS(struct expression *, expr) = NULL; - continue; - } - verify_output_constraint(C, expr, expr->string->data); - continue; - - case 2: /* Expression */ - state = 0; - if (!dmrC_evaluate_expression(C, expr)) - return; - if (!lvalue_expression(C, expr)) - dmrC_warning(C, expr->pos, "asm output is not an lvalue"); - evaluate_assign_to(C, expr, expr->ctype); - continue; - } - } END_FOR_EACH_PTR(expr); - - state = 0; - FOR_EACH_PTR(stmt->asm_inputs, expr) { - switch (state) { - case 0: /* Identifier */ - state = 1; - continue; - - case 1: /* Constraint */ - state = 2; - if (!expr || expr->type != EXPR_STRING) { - dmrC_sparse_error(C, expr ? expr->pos : stmt->pos, "asm input constraint is not a string"); - *THIS_ADDRESS(struct expression *, expr) = NULL; - continue; - } - verify_input_constraint(C, expr, expr->string->data); - continue; - - case 2: /* Expression */ - state = 0; - if (!dmrC_evaluate_expression(C, expr)) - return; - continue; - } - } END_FOR_EACH_PTR(expr); - - FOR_EACH_PTR(stmt->asm_clobbers, expr) { - if (!expr) { - dmrC_sparse_error(C, stmt->pos, "bad asm clobbers"); - return; - } - if (expr->type == EXPR_STRING) - continue; - dmrC_expression_error(C, expr, "asm clobber is not a string"); - } END_FOR_EACH_PTR(expr); - - - FOR_EACH_PTR(stmt->asm_labels, sym) { - if (!sym || sym->type != SYM_LABEL) { - dmrC_sparse_error(C, stmt->pos, "bad asm label"); - return; - } - } END_FOR_EACH_PTR(sym); -} - -static void evaluate_case_statement(struct dmr_C *C, struct statement *stmt) -{ - dmrC_evaluate_expression(C, stmt->case_expression); - dmrC_evaluate_expression(C, stmt->case_to); - dmrC_evaluate_statement(C, stmt->case_statement); -} - -static void check_case_type(struct dmr_C *C, struct expression *switch_expr, - struct expression *case_expr, - struct expression **enumcase) -{ - struct symbol *switch_type, *case_type; - int sclass, cclass; - - if (!case_expr) - return; - - switch_type = switch_expr->ctype; - case_type = dmrC_evaluate_expression(C, case_expr); - - if (!switch_type || !case_type) - goto Bad; - if (enumcase) { - if (*enumcase) - warn_for_different_enum_types(C, case_expr->pos, case_type, (*enumcase)->ctype); - else if (dmrC_is_enum_type(case_type)) - *enumcase = case_expr; - } - - sclass = classify_type(C, switch_type, &switch_type); - cclass = classify_type(C, case_type, &case_type); - - /* both should be arithmetic */ - if (!(sclass & cclass & TYPE_NUM)) - goto Bad; - - /* neither should be floating */ - if ((sclass | cclass) & TYPE_FLOAT) - goto Bad; - - /* if neither is restricted, we are OK */ - if (!((sclass | cclass) & TYPE_RESTRICT)) - return; - - if (!restricted_binop_type(C, SPECIAL_EQUAL, case_expr, switch_expr, - cclass, sclass, case_type, switch_type)) { - unrestrict(C, case_expr, cclass, &case_type); - unrestrict(C, switch_expr, sclass, &switch_type); - } - return; - -Bad: - dmrC_expression_error(C, case_expr, "incompatible types for 'case' statement"); -} - -static void evaluate_switch_statement(struct dmr_C *C, struct statement *stmt) -{ - struct symbol *sym; - struct expression *enumcase = NULL; - struct expression **enumcase_holder = &enumcase; - struct expression *sel = stmt->switch_expression; - - dmrC_evaluate_expression(C, sel); - dmrC_evaluate_statement(C, stmt->switch_statement); - if (!sel) - return; - if (sel->ctype && dmrC_is_enum_type(sel->ctype)) - enumcase_holder = NULL; /* Only check cases against switch */ - - FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) { - struct statement *case_stmt = sym->stmt; - check_case_type(C, sel, case_stmt->case_expression, enumcase_holder); - check_case_type(C, sel, case_stmt->case_to, enumcase_holder); - } END_FOR_EACH_PTR(sym); -} - -static void evaluate_goto_statement(struct dmr_C *C, struct statement *stmt) -{ - struct symbol *label = stmt->goto_label; - - if (label && !label->stmt && !dmrC_lookup_keyword(label->ident, NS_KEYWORD)) - dmrC_sparse_error(C, stmt->pos, "label '%s' was not declared", dmrC_show_ident(C, label->ident)); - - dmrC_evaluate_expression(C, stmt->goto_expression); -} - -struct symbol *dmrC_evaluate_statement(struct dmr_C *C, struct statement *stmt) -{ - if (!stmt) - return NULL; - - switch (stmt->type) { - case STMT_DECLARATION: { - struct symbol *s; - FOR_EACH_PTR(stmt->declaration, s) { - evaluate_symbol(C, s); - } END_FOR_EACH_PTR(s); - return NULL; - } - - case STMT_RETURN: - return evaluate_return_expression(C, stmt); - - case STMT_EXPRESSION: - if (!dmrC_evaluate_expression(C, stmt->expression)) - return NULL; - if (stmt->expression->ctype == &C->S->null_ctype) - stmt->expression = cast_to(C, stmt->expression, &C->S->ptr_ctype); - return degenerate(C, stmt->expression); - - case STMT_COMPOUND: { - struct statement *s; - struct symbol *type = NULL; - - /* Evaluate the return symbol in the compound statement */ - evaluate_symbol(C, stmt->ret); - - /* - * Then, evaluate each statement, making the type of the - * compound statement be the type of the last statement - */ - type = dmrC_evaluate_statement(C, stmt->args); - FOR_EACH_PTR(stmt->stmts, s) { - type = dmrC_evaluate_statement(C, s); - } END_FOR_EACH_PTR(s); - if (!type) - type = &C->S->void_ctype; - return type; - } - case STMT_IF: - evaluate_if_statement(C, stmt); - return NULL; - case STMT_ITERATOR: - evaluate_iterator(C, stmt); - return NULL; - case STMT_SWITCH: - evaluate_switch_statement(C, stmt); - return NULL; - case STMT_CASE: - evaluate_case_statement(C, stmt); - return NULL; - case STMT_LABEL: - return dmrC_evaluate_statement(C, stmt->label_statement); - case STMT_GOTO: - evaluate_goto_statement(C, stmt); - return NULL; - case STMT_NONE: - break; - case STMT_ASM: - evaluate_asm_statement(C, stmt); - return NULL; - case STMT_CONTEXT: - dmrC_evaluate_expression(C, stmt->expression); - return NULL; - case STMT_RANGE: - dmrC_evaluate_expression(C, stmt->range_expression); - dmrC_evaluate_expression(C, stmt->range_low); - dmrC_evaluate_expression(C, stmt->range_high); - return NULL; - } - return NULL; -} diff --git a/dmr_c/src/expand.c b/dmr_c/src/expand.c deleted file mode 100644 index 7f86df4..0000000 --- a/dmr_c/src/expand.c +++ /dev/null @@ -1,1347 +0,0 @@ -/* - * sparse/expand.c - * - * Copyright (C) 2003 Transmeta Corp. - * 2003-2004 Linus Torvalds - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * expand constant expressions. - */ - /* - * This version is part of the dmr_c project. - * Copyright (C) 2017 Dibyendu Majumdar - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int expand_expression(struct dmr_C *C, struct expression *); -static int expand_statement(struct dmr_C *C, struct statement *); -static int conservative; - -static int expand_symbol_expression(struct dmr_C *C, struct expression *expr) -{ - struct symbol *sym = expr->symbol; - - if (sym == &C->S->zero_int) { - if (C->Wundef) - dmrC_warning(C, expr->pos, "undefined preprocessor identifier '%s'", dmrC_show_ident(C, expr->symbol_name)); - expr->type = EXPR_VALUE; - expr->value = 0; - expr->taint = 0; - return 0; - } - /* The cost of a symbol expression is lower for on-stack symbols */ - return (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN)) ? 2 : 1; -} - -static long long get_longlong(struct dmr_C *C, struct expression *expr) -{ - int no_expand = expr->ctype->ctype.modifiers & MOD_UNSIGNED; - long long mask = 1ULL << (expr->ctype->bit_size - 1); - long long value = expr->value; - long long ormask, andmask; - (void)C; - - if (!(value & mask)) - no_expand = 1; - andmask = mask | (mask-1); - ormask = ~andmask; - if (no_expand) - ormask = 0; - return (value & andmask) | ormask; -} - -void dmrC_cast_value(struct dmr_C *C, struct expression *expr, struct symbol *newtype, - struct expression *old, struct symbol *oldtype) -{ - int old_size = oldtype->bit_size; - int new_size = newtype->bit_size; - long long value, mask, signmask; - long long oldmask, oldsignmask, dropped; - - if (dmrC_is_float_type(C->S, newtype) || - dmrC_is_float_type(C->S, oldtype)) - goto Float; - - // For pointers and integers, we can just move the value around - expr->type = EXPR_VALUE; - expr->taint = old->taint; - if (old_size == new_size) { - expr->value = old->value; - return; - } - - // expand it to the full "long long" value - value = get_longlong(C, old); - -Int: - // _Bool requires a zero test rather than truncation. - if (dmrC_is_bool_type(C->S, newtype)) { - expr->value = !!value; - if (!conservative && value != 0 && value != 1) - dmrC_warning(C, old->pos, "odd constant _Bool cast (%llx becomes 1)", value); - return; - } - - // Truncate it to the new size - signmask = 1ULL << (new_size-1); - mask = signmask | (signmask-1); - expr->value = value & mask; - - // Stop here unless checking for truncation - if (!C->Wcast_truncate || conservative) - return; - - // Check if we dropped any bits.. - oldsignmask = 1ULL << (old_size-1); - oldmask = oldsignmask | (oldsignmask-1); - dropped = oldmask & ~mask; - - // OK if the bits were (and still are) purely sign bits - if (value & dropped) { - if (!(value & oldsignmask) || !(value & signmask) || (value & dropped) != dropped) - dmrC_warning(C, old->pos, "cast truncates bits from constant value (%llx becomes %llx)", - value & oldmask, - value & mask); - } - return; - -Float: - if (!dmrC_is_float_type(C->S, newtype)) { - value = (long long)old->fvalue; - expr->type = EXPR_VALUE; - expr->taint = 0; - goto Int; - } - - if (!dmrC_is_float_type(C->S, oldtype)) - expr->fvalue = (long double)get_longlong(C, old); - else - expr->fvalue = old->fvalue; - - if (!(newtype->ctype.modifiers & MOD_LONGLONG) && \ - !(newtype->ctype.modifiers & MOD_LONGLONGLONG)) { - if ((newtype->ctype.modifiers & MOD_LONG)) - expr->fvalue = (double)expr->fvalue; - else - expr->fvalue = (float)expr->fvalue; - } - expr->type = EXPR_FVALUE; -} - -static int check_shift_count(struct dmr_C *C, struct expression *expr, struct symbol *ctype, unsigned int count) -{ - dmrC_warning(C, expr->pos, "shift too big (%u) for type %s", count, dmrC_show_typename(C, ctype)); - count &= ctype->bit_size-1; - return count; -} - -/* - * CAREFUL! We need to get the size and sign of the - * result right! - */ -#define CONVERT(op,s) (((op)<<1)+(s)) -#define SIGNED(op) CONVERT(op, 1) -#define UNSIGNED(op) CONVERT(op, 0) -static int simplify_int_binop(struct dmr_C *C, struct expression *expr, struct symbol *ctype) -{ - struct expression *left = expr->left, *right = expr->right; - unsigned long long v, l, r, mask; - signed long long sl, sr; - int is_signed; - - if (right->type != EXPR_VALUE) - return 0; - r = right->value; - if (expr->op == SPECIAL_LEFTSHIFT || expr->op == SPECIAL_RIGHTSHIFT) { - if ((int)r >= ctype->bit_size) { - if (conservative) - return 0; - r = check_shift_count(C, expr, ctype, (unsigned int)r); - right->value = r; - } - } - if (left->type != EXPR_VALUE) - return 0; - l = left->value; r = right->value; - is_signed = !(ctype->ctype.modifiers & MOD_UNSIGNED); - mask = 1ULL << (ctype->bit_size-1); - sl = l; sr = r; - if (is_signed && (sl & mask)) - sl |= ~(mask-1); - if (is_signed && (sr & mask)) - sr |= ~(mask-1); - - switch (CONVERT(expr->op,is_signed)) { - case SIGNED('+'): - case UNSIGNED('+'): - v = l + r; - break; - - case SIGNED('-'): - case UNSIGNED('-'): - v = l - r; - break; - - case SIGNED('&'): - case UNSIGNED('&'): - v = l & r; - break; - - case SIGNED('|'): - case UNSIGNED('|'): - v = l | r; - break; - - case SIGNED('^'): - case UNSIGNED('^'): - v = l ^ r; - break; - - case SIGNED('*'): - v = sl * sr; - break; - - case UNSIGNED('*'): - v = l * r; - break; - - case SIGNED('/'): - if (!r) - goto Div; - if (l == mask && sr == -1) - goto Overflow; - v = sl / sr; - break; - - case UNSIGNED('/'): - if (!r) goto Div; - v = l / r; - break; - - case SIGNED('%'): - if (!r) - goto Div; - if (l == mask && sr == -1) - goto Overflow; - v = sl % sr; - break; - - case UNSIGNED('%'): - if (!r) goto Div; - v = l % r; - break; - - case SIGNED(SPECIAL_LEFTSHIFT): - case UNSIGNED(SPECIAL_LEFTSHIFT): - v = l << r; - break; - - case SIGNED(SPECIAL_RIGHTSHIFT): - v = sl >> r; - break; - - case UNSIGNED(SPECIAL_RIGHTSHIFT): - v = l >> r; - break; - - default: - return 0; - } - mask = mask | (mask-1); - expr->value = v & mask; - expr->type = EXPR_VALUE; - expr->taint = left->taint | right->taint; - return 1; -Div: - if (!conservative) - dmrC_warning(C, expr->pos, "division by zero"); - return 0; -Overflow: - if (!conservative) - dmrC_warning(C, expr->pos, "constant integer operation overflow"); - return 0; -} - -static int simplify_cmp_binop(struct dmr_C *C, struct expression *expr, struct symbol *ctype) -{ - struct expression *left = expr->left, *right = expr->right; - unsigned long long l, r, mask; - signed long long sl, sr; - - (void) C; - if (left->type != EXPR_VALUE || right->type != EXPR_VALUE) - return 0; - l = left->value; r = right->value; - mask = 1ULL << (ctype->bit_size-1); - sl = l; sr = r; - if (sl & mask) - sl |= ~(mask-1); - if (sr & mask) - sr |= ~(mask-1); - switch (expr->op) { - case '<': expr->value = sl < sr; break; - case '>': expr->value = sl > sr; break; - case SPECIAL_LTE: expr->value = sl <= sr; break; - case SPECIAL_GTE: expr->value = sl >= sr; break; - case SPECIAL_EQUAL: expr->value = l == r; break; - case SPECIAL_NOTEQUAL: expr->value = l != r; break; - case SPECIAL_UNSIGNED_LT:expr->value = l < r; break; - case SPECIAL_UNSIGNED_GT:expr->value = l > r; break; - case SPECIAL_UNSIGNED_LTE:expr->value = l <= r; break; - case SPECIAL_UNSIGNED_GTE:expr->value = l >= r; break; - } - expr->type = EXPR_VALUE; - expr->taint = left->taint | right->taint; - return 1; -} - -static int simplify_float_binop(struct dmr_C *C, struct expression *expr) -{ - struct expression *left = expr->left, *right = expr->right; - unsigned long mod = expr->ctype->ctype.modifiers; - long double l, r, res; - - if (left->type != EXPR_FVALUE || right->type != EXPR_FVALUE) - return 0; - - l = left->fvalue; - r = right->fvalue; - - if (mod & MOD_LONGLONG) { - switch (expr->op) { - case '+': res = l + r; break; - case '-': res = l - r; break; - case '*': res = l * r; break; - case '/': if (!r) goto Div; - res = l / r; break; - default: return 0; - } - } else if (mod & MOD_LONG) { - switch (expr->op) { - case '+': res = (double) l + (double) r; break; - case '-': res = (double) l - (double) r; break; - case '*': res = (double) l * (double) r; break; - case '/': if (!r) goto Div; - res = (double) l / (double) r; break; - default: return 0; - } - } else { - switch (expr->op) { - case '+': res = (float)l + (float)r; break; - case '-': res = (float)l - (float)r; break; - case '*': res = (float)l * (float)r; break; - case '/': if (!r) goto Div; - res = (float)l / (float)r; break; - default: return 0; - } - } - expr->type = EXPR_FVALUE; - expr->fvalue = res; - return 1; -Div: - if (!conservative) - dmrC_warning(C, expr->pos, "division by zero"); - return 0; -} - -static int simplify_float_cmp(struct dmr_C *C, struct expression *expr, struct symbol *ctype) -{ - (void) C; - (void)ctype; - struct expression *left = expr->left, *right = expr->right; - long double l, r; - - if (left->type != EXPR_FVALUE || right->type != EXPR_FVALUE) - return 0; - - l = left->fvalue; - r = right->fvalue; - switch (expr->op) { - case '<': expr->value = l < r; break; - case '>': expr->value = l > r; break; - case SPECIAL_LTE: expr->value = l <= r; break; - case SPECIAL_GTE: expr->value = l >= r; break; - case SPECIAL_EQUAL: expr->value = l == r; break; - case SPECIAL_NOTEQUAL: expr->value = l != r; break; - } - expr->type = EXPR_VALUE; - expr->taint = 0; - return 1; -} - -static int expand_binop(struct dmr_C *C, struct expression *expr) -{ - int cost; - - cost = expand_expression(C, expr->left); - cost += expand_expression(C, expr->right); - if (simplify_int_binop(C, expr, expr->ctype)) - return 0; - if (simplify_float_binop(C, expr)) - return 0; - return cost + 1; -} - -static int expand_logical(struct dmr_C *C, struct expression *expr) -{ - struct expression *left = expr->left; - struct expression *right; - int cost, rcost; - - /* Do immediate short-circuiting ... */ - cost = expand_expression(C, left); - if (left->type == EXPR_VALUE) { - if (expr->op == SPECIAL_LOGICAL_AND) { - if (!left->value) { - expr->type = EXPR_VALUE; - expr->value = 0; - expr->taint = left->taint; - return 0; - } - } else { - if (left->value) { - expr->type = EXPR_VALUE; - expr->value = 1; - expr->taint = left->taint; - return 0; - } - } - } - - right = expr->right; - rcost = expand_expression(C, right); - if (left->type == EXPR_VALUE && right->type == EXPR_VALUE) { - /* - * We know the left value doesn't matter, since - * otherwise we would have short-circuited it.. - */ - expr->type = EXPR_VALUE; - expr->value = right->value != 0; - expr->taint = left->taint | right->taint; - return 0; - } - - /* - * If the right side is safe and cheaper than a branch, - * just avoid the branch and turn it into a regular binop - * style SAFELOGICAL. - */ - if (rcost < BRANCH_COST) { - expr->type = EXPR_BINOP; - rcost -= BRANCH_COST - 1; - } - - return cost + BRANCH_COST + rcost; -} - -static int expand_comma(struct dmr_C *C, struct expression *expr) -{ - int cost; - - cost = expand_expression(C, expr->left); - cost += expand_expression(C, expr->right); - if (expr->left->type == EXPR_VALUE || expr->left->type == EXPR_FVALUE) { - unsigned flags = expr->flags; - unsigned taint; - taint = expr->left->type == EXPR_VALUE ? expr->left->taint : 0; - *expr = *expr->right; - expr->flags = flags; - if (expr->type == EXPR_VALUE) - expr->taint |= Taint_comma | taint; - } - return cost; -} - -#define MOD_IGN (MOD_VOLATILE | MOD_CONST) - -static int compare_types(struct dmr_C *C, int op, struct symbol *left, struct symbol *right) -{ - struct ctype c1 = {.base_type = left}; - struct ctype c2 = {.base_type = right}; - switch (op) { - case SPECIAL_EQUAL: - return !dmrC_type_difference(C, &c1, &c2, MOD_IGN, MOD_IGN); - case SPECIAL_NOTEQUAL: - return dmrC_type_difference(C, &c1, &c2, MOD_IGN, MOD_IGN) != NULL; - case '<': - return left->bit_size < right->bit_size; - case '>': - return left->bit_size > right->bit_size; - case SPECIAL_LTE: - return left->bit_size <= right->bit_size; - case SPECIAL_GTE: - return left->bit_size >= right->bit_size; - } - return 0; -} - -static int expand_compare(struct dmr_C *C, struct expression *expr) -{ - struct expression *left = expr->left, *right = expr->right; - int cost; - - cost = expand_expression(C, left); - cost += expand_expression(C, right); - - if (left && right) { - /* Type comparison? */ - if (left->type == EXPR_TYPE && right->type == EXPR_TYPE) { - int op = expr->op; - expr->type = EXPR_VALUE; - expr->value = compare_types(C, op, left->symbol, right->symbol); - expr->taint = 0; - return 0; - } - if (simplify_cmp_binop(C, expr, left->ctype)) - return 0; - if (simplify_float_cmp(C, expr, left->ctype)) - return 0; - } - return cost + 1; -} - -static int expand_conditional(struct dmr_C *C, struct expression *expr) -{ - struct expression *cond = expr->conditional; - struct expression *truee = expr->cond_true; - struct expression *falsee = expr->cond_false; - int cost, cond_cost; - - cond_cost = expand_expression(C, cond); - if (cond->type == EXPR_VALUE) { - unsigned flags = expr->flags; - if (!cond->value) - truee = falsee; - if (!truee) - truee = cond; - cost = expand_expression(C, truee); - *expr = *truee; - expr->flags = flags; - if (expr->type == EXPR_VALUE) - expr->taint |= cond->taint; - return cost; - } - - cost = expand_expression(C, truee); - cost += expand_expression(C, falsee); - - if (cost < SELECT_COST) { - expr->type = EXPR_SELECT; - cost -= BRANCH_COST - 1; - } - - return cost + cond_cost + BRANCH_COST; -} - -static int expand_assignment(struct dmr_C *C, struct expression *expr) -{ - expand_expression(C, expr->left); - expand_expression(C, expr->right); - return SIDE_EFFECTS; -} - -static int expand_addressof(struct dmr_C *C, struct expression *expr) -{ - return expand_expression(C, expr->unop); -} - -/* - * Look up a trustable initializer value at the requested offset. - * - * Return NULL if no such value can be found or statically trusted. - * - * FIXME!! We should check that the size is right! - */ -static struct expression *constant_symbol_value(struct dmr_C *C, struct symbol *sym, int offset) -{ - struct expression *value; - (void)C; - - if (sym->ctype.modifiers & (MOD_ASSIGNED | MOD_ADDRESSABLE)) - return NULL; - value = sym->initializer; - if (!value) - return NULL; - if (value->type == EXPR_INITIALIZER) { - struct expression *entry; - FOR_EACH_PTR(value->expr_list, entry) { - if (entry->type != EXPR_POS) { - if (offset) - continue; - return entry; - } - if ((int) entry->init_offset < offset) - continue; - if ((int) entry->init_offset > offset) - return NULL; - return entry->init_expr; - } END_FOR_EACH_PTR(entry); - return NULL; - } - return value; -} - -static int expand_dereference(struct dmr_C *C, struct expression *expr) -{ - struct expression *unop = expr->unop; - unsigned int offset; - - expand_expression(C, unop); - - /* - * NOTE! We get a bogus warning right now for some special - * cases: apparently I've screwed up the optimization of - * a zero-offset dereference, and the ctype is wrong. - * - * Leave the warning in anyway, since this is also a good - * test for me to get the type evaluation right.. - */ - if (expr->ctype->ctype.modifiers & MOD_NODEREF) - dmrC_warning(C, unop->pos, "dereference of noderef expression"); - - /* - * Is it "symbol" or "symbol + offset"? - */ - offset = 0; - if (unop->type == EXPR_BINOP && unop->op == '+') { - struct expression *right = unop->right; - if (right->type == EXPR_VALUE) { - offset = (unsigned int) right->value; - unop = unop->left; - } - } - - if (unop->type == EXPR_SYMBOL) { - struct symbol *sym = unop->symbol; - struct expression *value = constant_symbol_value(C, sym, offset); - - /* Const symbol with a constant initializer? */ - if (value) { - /* FIXME! We should check that the size is right! */ - if (value->type == EXPR_VALUE) { - /* - During the expansion of a dereference, it's if the initializer - which corrrespond to the offset we're interested is a constant. - In which case this dereference can be avoided and the value - given in the initializer can be used instead. - - However, it's not enough to check for the offset since for bitfields - several are placed at the same offset. - Hence refuse such expansion if the constant value correspond - to a bitfield. - */ - if (dmrC_is_bitfield_type(value->ctype)) - return UNSAFE; - expr->type = EXPR_VALUE; - expr->value = value->value; - expr->taint = 0; - return 0; - } else if (value->type == EXPR_FVALUE) { - expr->type = EXPR_FVALUE; - expr->fvalue = value->fvalue; - return 0; - } - } - - /* Direct symbol dereference? Cheap and safe */ - return (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN)) ? 2 : 1; - } - - return UNSAFE; -} - -static int simplify_preop(struct dmr_C *C, struct expression *expr) -{ - struct expression *op = expr->unop; - unsigned long long v, mask; - - if (op->type != EXPR_VALUE) - return 0; - - mask = 1ULL << (expr->ctype->bit_size-1); - v = op->value; - switch (expr->op) { - case '+': break; - case '-': - if (v == mask && !(expr->ctype->ctype.modifiers & MOD_UNSIGNED)) - goto Overflow; - v = -v; - break; - case '!': v = !v; break; - case '~': v = ~v; break; - default: return 0; - } - mask = mask | (mask-1); - expr->value = v & mask; - expr->type = EXPR_VALUE; - expr->taint = op->taint; - return 1; - -Overflow: - if (!conservative) - dmrC_warning(C, expr->pos, "constant integer operation overflow"); - return 0; -} - -static int simplify_float_preop(struct dmr_C *C, struct expression *expr) -{ - (void) C; - struct expression *op = expr->unop; - long double v; - - if (op->type != EXPR_FVALUE) - return 0; - v = op->fvalue; - switch (expr->op) { - case '+': break; - case '-': v = -v; break; - default: return 0; - } - expr->fvalue = v; - expr->type = EXPR_FVALUE; - return 1; -} - -/* - * Unary post-ops: x++ and x-- - */ -static int expand_postop(struct dmr_C *C, struct expression *expr) -{ - expand_expression(C, expr->unop); - return SIDE_EFFECTS; -} - -static int expand_preop(struct dmr_C *C, struct expression *expr) -{ - int cost; - - switch (expr->op) { - case '*': - return expand_dereference(C, expr); - - case '&': - return expand_addressof(C, expr); - - case SPECIAL_INCREMENT: - case SPECIAL_DECREMENT: - /* - * From a type evaluation standpoint the preops are - * the same as the postops - */ - return expand_postop(C, expr); - - default: - break; - } - cost = expand_expression(C, expr->unop); - - if (simplify_preop(C, expr)) - return 0; - if (simplify_float_preop(C, expr)) - return 0; - return cost + 1; -} - -static int expand_arguments(struct dmr_C *C, struct expression_list *head) -{ - int cost = 0; - struct expression *expr; - - FOR_EACH_PTR (head, expr) { - cost += expand_expression(C, expr); - } END_FOR_EACH_PTR(expr); - return cost; -} - -static int expand_cast(struct dmr_C *C, struct expression *expr) -{ - int cost; - struct expression *target = expr->cast_expression; - - cost = expand_expression(C, target); - - /* Simplify normal integer casts.. */ - if (target->type == EXPR_VALUE || target->type == EXPR_FVALUE) { - dmrC_cast_value(C, expr, expr->ctype, target, target->ctype); - return 0; - } - return cost + 1; -} - -/* - * expand a call expression with a symbol. This - * should expand builtins. - */ -static int expand_symbol_call(struct dmr_C *C, struct expression *expr, int cost) -{ - struct expression *fn = expr->fn; - struct symbol *ctype = fn->ctype; - - if (fn->type != EXPR_PREOP) - return SIDE_EFFECTS; - - if (ctype->op && ctype->op->expand) - return ctype->op->expand(C, expr, cost); - - if (ctype->ctype.modifiers & MOD_PURE) - return cost + 1; - - return SIDE_EFFECTS; -} - -static int expand_call(struct dmr_C *C, struct expression *expr) -{ - int cost; - struct symbol *sym; - struct expression *fn = expr->fn; - - cost = expand_arguments(C, expr->args); - sym = fn->ctype; - if (!sym) { - dmrC_expression_error(C, expr, "function has no type"); - return SIDE_EFFECTS; - } - if (sym->type == SYM_NODE) - return expand_symbol_call(C, expr, cost); - - return SIDE_EFFECTS; -} - -static int expand_expression_list(struct dmr_C *C, struct expression_list *list) -{ - int cost = 0; - struct expression *expr; - - FOR_EACH_PTR(list, expr) { - cost += expand_expression(C, expr); - } END_FOR_EACH_PTR(expr); - return cost; -} - -/* - * We can simplify nested position expressions if - * this is a simple (single) positional expression. - */ -static int expand_pos_expression(struct dmr_C *C, struct expression *expr) -{ - struct expression *nested = expr->init_expr; - unsigned long offset = expr->init_offset; - int nr = expr->init_nr; - - if (nr == 1) { - switch (nested->type) { - case EXPR_POS: - offset += nested->init_offset; - *expr = *nested; - expr->init_offset = offset; - nested = expr; - break; - - case EXPR_INITIALIZER: { - struct expression *reuse = nested, *entry; - *expr = *nested; - FOR_EACH_PTR(expr->expr_list, entry) { - if (entry->type == EXPR_POS) { - entry->init_offset += offset; - } else { - if (!reuse) { - /* - * This happens rarely, but it can happen - * with bitfields that are all at offset - * zero.. - */ - reuse = dmrC_alloc_expression(C, entry->pos, EXPR_POS); - } - reuse->type = EXPR_POS; - reuse->ctype = entry->ctype; - reuse->init_offset = offset; - reuse->init_nr = 1; - reuse->init_expr = entry; - REPLACE_CURRENT_PTR(struct expression *, entry, reuse); - reuse = NULL; - } - } END_FOR_EACH_PTR(entry); - nested = expr; - break; - } - - default: - break; - } - } - return expand_expression(C, nested); -} - -static unsigned long bit_offset(struct dmr_C *C, const struct expression *expr) -{ - unsigned long offset = 0; - while (expr->type == EXPR_POS) { - offset += dmrC_bytes_to_bits(C->target, expr->init_offset); - expr = expr->init_expr; - } - if (expr && expr->ctype) - offset += expr->ctype->bit_offset; - return offset; -} - -static unsigned long bit_range(const struct expression *expr) -{ - unsigned long range = 0; - unsigned long size = 0; - while (expr->type == EXPR_POS) { - unsigned long nr = expr->init_nr; - size = expr->ctype->bit_size; - range += (nr - 1) * size; - expr = expr->init_expr; - } - range += size; - return range; -} - -static int compare_expressions(void *userdata, const void *_a, const void *_b) -{ - struct dmr_C *C = (struct dmr_C *) userdata; - const struct expression *a = (const struct expression *)_a; - const struct expression *b = (const struct expression *)_b; - unsigned long a_pos = bit_offset(C, a); - unsigned long b_pos = bit_offset(C, b); - - return (a_pos < b_pos) ? -1 : (a_pos == b_pos) ? 0 : 1; -} - -static void sort_expression_list(struct dmr_C *C, struct expression_list **list) -{ - ptrlist_sort((struct ptr_list **)list, C, compare_expressions); -} - -static void verify_nonoverlapping(struct dmr_C *C, struct expression_list **list, struct expression *expr) -{ - struct expression *a = NULL; - unsigned long max = 0; - unsigned long whole = expr->ctype->bit_size; - struct expression *b; - - if (!C->Woverride_init) - return; - - FOR_EACH_PTR(*list, b) { - unsigned long off, end; - if (!b->ctype || !b->ctype->bit_size) - continue; - off = bit_offset(C, b); - if (a && off < max) { - dmrC_warning(C, a->pos, "Initializer entry defined twice"); - dmrC_info(C, b->pos, " also defined here"); - if (!C->Woverride_init_all) - return; - } - end = off + bit_range(b); - if (!a && !C->Woverride_init_whole_range) { - // If first entry is the whole range, do not let - // any warning about it (this allow to initialize - // an array with some default value and then override - // some specific entries). - if (off == 0 && end == whole) - continue; - } - if (end > max) { - max = end; - a = b; - } - } END_FOR_EACH_PTR(b); -} - -static int expand_expression(struct dmr_C *C, struct expression *expr) -{ - if (!expr) - return 0; - if (!expr->ctype || expr->ctype == &C->S->bad_ctype) - return UNSAFE; - - switch (expr->type) { - case EXPR_VALUE: - case EXPR_FVALUE: - case EXPR_STRING: - return 0; - case EXPR_TYPE: - case EXPR_SYMBOL: - return expand_symbol_expression(C, expr); - case EXPR_BINOP: - return expand_binop(C, expr); - - case EXPR_LOGICAL: - return expand_logical(C, expr); - - case EXPR_COMMA: - return expand_comma(C, expr); - - case EXPR_COMPARE: - return expand_compare(C, expr); - - case EXPR_ASSIGNMENT: - return expand_assignment(C, expr); - - case EXPR_PREOP: - return expand_preop(C, expr); - - case EXPR_POSTOP: - return expand_postop(C, expr); - - case EXPR_CAST: - case EXPR_FORCE_CAST: - case EXPR_IMPLIED_CAST: - return expand_cast(C, expr); - - case EXPR_CALL: - return expand_call(C, expr); - - case EXPR_DEREF: - dmrC_warning(C, expr->pos, "we should not have an EXPR_DEREF left at expansion time"); - return UNSAFE; - - case EXPR_SELECT: - case EXPR_CONDITIONAL: - return expand_conditional(C, expr); - - case EXPR_STATEMENT: { - struct statement *stmt = expr->statement; - int cost = expand_statement(C, stmt); - - if (stmt->type == STMT_EXPRESSION && stmt->expression) - *expr = *stmt->expression; - return cost; - } - - case EXPR_LABEL: - return 0; - - case EXPR_INITIALIZER: - sort_expression_list(C, &expr->expr_list); - verify_nonoverlapping(C, &expr->expr_list, expr); - return expand_expression_list(C, expr->expr_list); - - case EXPR_IDENTIFIER: - return UNSAFE; - - case EXPR_INDEX: - return UNSAFE; - - case EXPR_SLICE: - return expand_expression(C, expr->base) + 1; - - case EXPR_POS: - return expand_pos_expression(C, expr); - - case EXPR_SIZEOF: - case EXPR_PTRSIZEOF: - case EXPR_ALIGNOF: - case EXPR_OFFSETOF: - dmrC_expression_error(C, expr, "internal front-end error: sizeof in expansion?"); - return UNSAFE; - } - return SIDE_EFFECTS; -} - -static void expand_const_expression(struct dmr_C *C, struct expression *expr, const char *where) -{ - if (expr) { - expand_expression(C, expr); - if (expr->type != EXPR_VALUE) - dmrC_expression_error(C, expr, "Expected constant expression in %s", where); - } -} - -int dmrC_expand_symbol(struct dmr_C *C, struct symbol *sym) -{ - int retval; - struct symbol *base_type; - - if (!sym) - return 0; - base_type = sym->ctype.base_type; - if (!base_type) - return 0; - - retval = expand_expression(C, sym->initializer); - /* expand the body of the symbol */ - if (base_type->type == SYM_FN) { - if (base_type->stmt) - expand_statement(C, base_type->stmt); - } - return retval; -} - -static void expand_return_expression(struct dmr_C *C, struct statement *stmt) -{ - expand_expression(C, stmt->expression); -} - -static int expand_if_statement(struct dmr_C *C, struct statement *stmt) -{ - struct expression *expr = stmt->if_conditional; - - if (!expr || !expr->ctype || expr->ctype == &C->S->bad_ctype) - return UNSAFE; - - expand_expression(C, expr); - -/* This is only valid if nobody jumps into the "dead" side */ -#if 0 - /* Simplify constant conditionals without even evaluating the false side */ - if (expr->type == EXPR_VALUE) { - struct statement *simple; - simple = expr->value ? stmt->if_true : stmt->if_false; - - /* Nothing? */ - if (!simple) { - stmt->type = STMT_NONE; - return 0; - } - expand_statement(simple); - *stmt = *simple; - return SIDE_EFFECTS; - } -#endif - expand_statement(C, stmt->if_true); - expand_statement(C, stmt->if_false); - return SIDE_EFFECTS; -} - -/* - * Expanding a compound statement is really just - * about adding up the costs of each individual - * statement. - * - * We also collapse a simple compound statement: - * this would trigger for simple inline functions, - * except we would have to check the "return" - * symbol usage. Next time. - */ -static int expand_compound(struct dmr_C *C, struct statement *stmt) -{ - struct statement *s, *last; - int cost, statements; - - if (stmt->ret) - dmrC_expand_symbol(C, stmt->ret); - - last = stmt->args; - cost = expand_statement(C, last); - statements = last != NULL; - FOR_EACH_PTR(stmt->stmts, s) { - statements++; - last = s; - cost += expand_statement(C, s); - } END_FOR_EACH_PTR(s); - - if (statements == 1 && !stmt->ret) - *stmt = *last; - - return cost; -} - -static int expand_statement(struct dmr_C *C, struct statement *stmt) -{ - if (!stmt) - return 0; - - switch (stmt->type) { - case STMT_DECLARATION: { - struct symbol *sym; - FOR_EACH_PTR(stmt->declaration, sym) { - dmrC_expand_symbol(C, sym); - } END_FOR_EACH_PTR(sym); - return SIDE_EFFECTS; - } - - case STMT_RETURN: - expand_return_expression(C, stmt); - return SIDE_EFFECTS; - - case STMT_EXPRESSION: - return expand_expression(C, stmt->expression); - - case STMT_COMPOUND: - return expand_compound(C, stmt); - - case STMT_IF: - return expand_if_statement(C, stmt); - - case STMT_ITERATOR: - expand_expression(C, stmt->iterator_pre_condition); - expand_expression(C, stmt->iterator_post_condition); - expand_statement(C, stmt->iterator_pre_statement); - expand_statement(C, stmt->iterator_statement); - expand_statement(C, stmt->iterator_post_statement); - return SIDE_EFFECTS; - - case STMT_SWITCH: - expand_expression(C, stmt->switch_expression); - expand_statement(C, stmt->switch_statement); - return SIDE_EFFECTS; - - case STMT_CASE: - expand_const_expression(C, stmt->case_expression, "case statement"); - expand_const_expression(C, stmt->case_to, "case statement"); - expand_statement(C, stmt->case_statement); - return SIDE_EFFECTS; - - case STMT_LABEL: - expand_statement(C, stmt->label_statement); - return SIDE_EFFECTS; - - case STMT_GOTO: - expand_expression(C, stmt->goto_expression); - return SIDE_EFFECTS; - - case STMT_NONE: - break; - case STMT_ASM: - /* FIXME! Do the asm parameter evaluation! */ - break; - case STMT_CONTEXT: - expand_expression(C, stmt->expression); - break; - case STMT_RANGE: - expand_expression(C, stmt->range_expression); - expand_expression(C, stmt->range_low); - expand_expression(C, stmt->range_high); - break; - } - return SIDE_EFFECTS; -} - -static inline int bad_integer_constant_expression(struct dmr_C *C, struct expression *expr) -{ - (void) C; - if (!(expr->flags & Int_const_expr)) - return 1; - if (expr->taint & Taint_comma) - return 1; - return 0; -} - -static long long __get_expression_value(struct dmr_C *C, struct expression *expr, int strict) -{ - long long value, mask; - struct symbol *ctype; - - if (!expr) - return 0; - ctype = dmrC_evaluate_expression(C, expr); - if (!ctype) { - dmrC_expression_error(C, expr, "bad constant expression type"); - return 0; - } - expand_expression(C, expr); - if (expr->type != EXPR_VALUE) { - if (strict != 2) - dmrC_expression_error(C, expr, "bad constant expression"); - return 0; - } - if ((strict == 1) && bad_integer_constant_expression(C, expr)) { - dmrC_expression_error(C, expr, "bad integer constant expression"); - return 0; - } - - value = expr->value; - mask = 1ULL << (ctype->bit_size-1); - - if (value & mask) { - while (ctype->type != SYM_BASETYPE) - ctype = ctype->ctype.base_type; - if (!(ctype->ctype.modifiers & MOD_UNSIGNED)) - value = value | mask | ~(mask-1); - } - return value; -} - -long long dmrC_get_expression_value(struct dmr_C *C, struct expression *expr) -{ - return __get_expression_value(C, expr, 0); -} - -long long dmrC_const_expression_value(struct dmr_C *C, struct expression *expr) -{ - return __get_expression_value(C, expr, 1); -} - -long long dmrC_get_expression_value_silent(struct dmr_C *C, struct expression *expr) -{ - - return __get_expression_value(C, expr, 2); -} - -int dmrC_expr_truth_value(struct dmr_C *C, struct expression *expr) -{ - const int saved = conservative; - struct symbol *ctype; - - if (!expr) - return 0; - - ctype = dmrC_evaluate_expression(C, expr); - if (!ctype) - return -1; - - conservative = 1; - expand_expression(C, expr); - conservative = saved; - -redo: - switch (expr->type) { - case EXPR_COMMA: - expr = expr->right; - goto redo; - case EXPR_VALUE: - return expr->value != 0; - case EXPR_FVALUE: - return expr->fvalue != 0; - default: - return -1; - } -} - -int dmrC_is_zero_constant(struct dmr_C *C, struct expression *expr) -{ - const int saved = conservative; - conservative = 1; - expand_expression(C, expr); - conservative = saved; - return expr->type == EXPR_VALUE && !expr->value; -} diff --git a/dmr_c/src/expand.h b/dmr_c/src/expand.h deleted file mode 100644 index 27e10c0..0000000 --- a/dmr_c/src/expand.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef EXPAND_H -#define EXPAND_H -/* - * sparse/expand.h - * - * Copyright (C) 2003 Transmeta Corp. - * 2003 Linus Torvalds - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* Random cost numbers */ -#define SIDE_EFFECTS 10000 /* The expression has side effects */ -#define UNSAFE 100 /* The expression may be "infinitely costly" due to exceptions */ -#define SELECT_COST 20 /* Cut-off for turning a conditional into a select */ -#define BRANCH_COST 10 /* Cost of a conditional branch */ - -#endif diff --git a/dmr_c/src/expression.c b/dmr_c/src/expression.c deleted file mode 100644 index 08636f2..0000000 --- a/dmr_c/src/expression.c +++ /dev/null @@ -1,930 +0,0 @@ -/* - * sparse/expression.c - * - * Copyright (C) 2003 Transmeta Corp. - * 2003-2004 Linus Torvalds - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * This is the expression parsing part of parsing C. - */ - /* - * This version is part of the dmr_c project. - * Copyright (C) 2017 Dibyendu Majumdar - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int match_oplist(int op, ...) -{ - va_list args; - int nextop; - - va_start(args, op); - do { - nextop = va_arg(args, int); - } while (nextop != 0 && nextop != op); - va_end(args); - - return nextop != 0; -} - -static struct token *comma_expression(struct dmr_C *C, struct token *, struct expression **); - -struct token *dmrC_parens_expression(struct dmr_C *C, struct token *token, struct expression **expr, const char *where) -{ - token = dmrC_expect_token(C, token, '(', where); - if (dmrC_match_op(token, '{')) { - struct expression *e = dmrC_alloc_expression(C, token->pos, EXPR_STATEMENT); - struct statement *stmt = dmrC_alloc_statement(C, token->pos, STMT_COMPOUND); - *expr = e; - e->statement = stmt; - dmrC_start_symbol_scope(C); - token = dmrC_compound_statement(C, token->next, stmt); - dmrC_end_symbol_scope(C); - token = dmrC_expect_token(C, token, '}', "at end of statement expression"); - } else - token = dmrC_parse_expression(C, token, expr); - return dmrC_expect_token(C, token, ')', where); -} - -/* - * Handle __func__, __FUNCTION__ and __PRETTY_FUNCTION__ token - * conversion - */ -static struct symbol *handle_func(struct dmr_C *C, struct token *token) -{ - struct ident *ident = token->ident; - struct symbol *decl, *array; - struct string *string; - int len; - - if (ident != C->S->__func___ident && - ident != C->S->__FUNCTION___ident && - ident != C->S->__PRETTY_FUNCTION___ident) - return NULL; - - if (!C->current_fn || !C->current_fn->ident) - return NULL; - - /* OK, it's one of ours */ - array = dmrC_alloc_symbol(C->S, token->pos, SYM_ARRAY); - array->ctype.base_type = &C->S->char_ctype; - array->ctype.alignment = 1; - array->endpos = token->pos; - decl = dmrC_alloc_symbol(C->S, token->pos, SYM_NODE); - decl->ctype.base_type = array; - decl->ctype.alignment = 1; - decl->ctype.modifiers = MOD_STATIC; - decl->endpos = token->pos; - - /* function-scope, but in NS_SYMBOL */ - dmrC_bind_symbol(C->S, decl, ident, NS_LABEL); - decl->ns = NS_SYMBOL; - - len = C->current_fn->ident->len; - string = (struct string *)dmrC_allocator_allocate(&C->string_allocator, len + 1); - memcpy(string->data, C->current_fn->ident->name, len); - string->data[len] = 0; - string->length = len + 1; - - decl->initializer = dmrC_alloc_expression(C, token->pos, EXPR_STRING); - decl->initializer->string = string; - decl->initializer->ctype = decl; - decl->array_size = dmrC_alloc_const_expression(C, token->pos, len + 1); - array->array_size = decl->array_size; - decl->bit_size = array->bit_size = dmrC_bytes_to_bits(C->target, len + 1); - - return decl; -} - -static struct token *parse_type(struct dmr_C *C, struct token *token, struct expression **tree) -{ - struct symbol *sym; - *tree = dmrC_alloc_expression(C, token->pos, EXPR_TYPE); - (*tree)->flags = Int_const_expr; /* sic */ - token = dmrC_typename(C, token, &sym, NULL); - if (sym->ident) - dmrC_sparse_error(C, token->pos, - "type expression should not include identifier " - "\"%s\"", sym->ident->name); - (*tree)->symbol = sym; - return token; -} - -static struct token *builtin_types_compatible_p_expr(struct dmr_C *C, struct token *token, - struct expression **tree) -{ - struct expression *expr = dmrC_alloc_expression( - C, token->pos, EXPR_COMPARE); - expr->flags = Int_const_expr; - expr->op = SPECIAL_EQUAL; - token = token->next; - if (!dmrC_match_op(token, '(')) - return dmrC_expect_token(C, token, '(', - "after __builtin_types_compatible_p"); - token = token->next; - token = parse_type(C, token, &expr->left); - if (!dmrC_match_op(token, ',')) - return dmrC_expect_token(C, token, ',', - "in __builtin_types_compatible_p"); - token = token->next; - token = parse_type(C, token, &expr->right); - if (!dmrC_match_op(token, ')')) - return dmrC_expect_token(C, token, ')', - "at end of __builtin_types_compatible_p"); - token = token->next; - - *tree = expr; - return token; -} - -static struct token *builtin_offsetof_expr(struct dmr_C *C, struct token *token, - struct expression **tree) -{ - struct expression *expr = NULL; - struct expression **p = &expr; - struct symbol *sym; - int op = '.'; - - token = token->next; - if (!dmrC_match_op(token, '(')) - return dmrC_expect_token(C, token, '(', "after __builtin_offset"); - - token = token->next; - token = dmrC_typename(C, token, &sym, NULL); - if (sym->ident) - dmrC_sparse_error(C, token->pos, - "type expression should not include identifier " - "\"%s\"", sym->ident->name); - - if (!dmrC_match_op(token, ',')) - return dmrC_expect_token(C, token, ',', "in __builtin_offset"); - - while (1) { - struct expression *e; - switch (op) { - case ')': - expr->in = sym; - *tree = expr; - default: - return dmrC_expect_token(C, token, ')', "at end of __builtin_offset"); - case SPECIAL_DEREFERENCE: - e = dmrC_alloc_expression(C, token->pos, EXPR_OFFSETOF); - e->flags = Int_const_expr; - e->op = '['; - *p = e; - p = &e->down; - /* fall through */ - case '.': - token = token->next; - e = dmrC_alloc_expression(C, token->pos, EXPR_OFFSETOF); - e->flags = Int_const_expr; - e->op = '.'; - if (dmrC_token_type(token) != TOKEN_IDENT) { - dmrC_sparse_error(C, token->pos, "Expected member name"); - return token; - } - e->ident = token->ident; - token = token->next; - break; - case '[': - token = token->next; - e = dmrC_alloc_expression(C, token->pos, EXPR_OFFSETOF); - e->flags = Int_const_expr; - e->op = '['; - token = dmrC_parse_expression(C, token, &e->index); - token = dmrC_expect_token(C, token, ']', - "at end of array dereference"); - if (!e->index) - return token; - } - *p = e; - p = &e->down; - op = dmrC_token_type(token) == TOKEN_SPECIAL ? token->special : 0; - } -} - -#ifndef ULLONG_MAX -#define ULLONG_MAX (~0ULL) -#endif - -static unsigned long long parse_num(const char *nptr, char **end) -{ - if (nptr[0] == '0' && tolower((unsigned char)nptr[1]) == 'b') - return strtoull(&nptr[2], end, 2); - return strtoull(nptr, end, 0); -} - -static void get_number_value(struct dmr_C *C, struct expression *expr, struct token *token) -{ - const char *str = token->number; - unsigned long long value; - char *end; - int size = 0, want_unsigned = 0; - int overflow = 0, do_warn = 0; - int try_unsigned = 1; - int bits; - - errno = 0; - value = parse_num(str, &end); - if (end == str) - goto Float; - if (value == ULLONG_MAX && errno == ERANGE) - overflow = 1; - while (1) { - char c = *end++; - if (!c) { - break; - } else if (c == 'u' || c == 'U') { - if (want_unsigned) - goto Enoint; - want_unsigned = 1; - } else if (c == 'l' || c == 'L') { - if (size) - goto Enoint; - size = 1; - if (*end == c) { - size = 2; - end++; - } - } else - goto Float; - } - if (overflow) - goto Eoverflow; - /* OK, it's a valid integer */ - /* decimals can be unsigned only if directly specified as such */ - if (str[0] != '0' && !want_unsigned) - try_unsigned = 0; - if (!size) { - bits = C->target->bits_in_int - 1; - if (!(value & (~1ULL << bits))) { - if (!(value & (1ULL << bits))) { - goto got_it; - } else if (try_unsigned) { - want_unsigned = 1; - goto got_it; - } - } - size = 1; - do_warn = 1; - } - if (size < 2) { - bits = C->target->bits_in_long - 1; - if (!(value & (~1ULL << bits))) { - if (!(value & (1ULL << bits))) { - goto got_it; - } else if (try_unsigned) { - want_unsigned = 1; - goto got_it; - } - do_warn |= 2; - } - size = 2; - do_warn |= 1; - } - bits = C->target->bits_in_longlong - 1; - if (value & (~1ULL << bits)) - goto Eoverflow; - if (!(value & (1ULL << bits))) - goto got_it; - if (!try_unsigned) - dmrC_warning(C, expr->pos, "decimal constant %s is too big for long long", - dmrC_show_token(C, token)); - want_unsigned = 1; -got_it: - if (do_warn) - dmrC_warning(C, expr->pos, "constant %s is so big it is%s%s%s", - dmrC_show_token(C, token), - want_unsigned ? " unsigned":"", - size > 0 ? " long":"", - size > 1 ? " long":""); - if (do_warn & 2) - dmrC_warning(C, expr->pos, - "decimal constant %s is between LONG_MAX and ULONG_MAX." - " For C99 that means long long, C90 compilers are very " - "likely to produce unsigned long (and a warning) here", - dmrC_show_token(C, token)); - expr->type = EXPR_VALUE; - expr->flags = Int_const_expr; - expr->ctype = dmrC_ctype_integer(C, size, want_unsigned); - expr->value = value; - return; -Eoverflow: - dmrC_error_die(C, expr->pos, "constant %s is too big even for unsigned long long", - dmrC_show_token(C, token)); - return; -Float: - expr->fvalue = dmrC_string_to_ld(str, &end); - if (str == end) - goto Enoint; - - if (*end && end[1]) - goto Enoint; - - if (*end == 'f' || *end == 'F') - expr->ctype = &C->S->float_ctype; - else if (*end == 'l' || *end == 'L') - expr->ctype = &C->S->ldouble_ctype; - else if (!*end) - expr->ctype = &C->S->double_ctype; - else - goto Enoint; - - expr->flags = Float_literal; - expr->type = EXPR_FVALUE; - return; - -Enoint: - dmrC_error_die(C, expr->pos, "constant %s is not a valid number", dmrC_show_token(C, token)); -} - -struct token *dmrC_primary_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - struct expression *expr = NULL; - - switch (dmrC_token_type(token)) { - case TOKEN_CHAR: - case TOKEN_CHAR_EMBEDDED_0: - case TOKEN_CHAR_EMBEDDED_1: - case TOKEN_CHAR_EMBEDDED_2: - case TOKEN_CHAR_EMBEDDED_3: - case TOKEN_WIDE_CHAR: - case TOKEN_WIDE_CHAR_EMBEDDED_0: - case TOKEN_WIDE_CHAR_EMBEDDED_1: - case TOKEN_WIDE_CHAR_EMBEDDED_2: - case TOKEN_WIDE_CHAR_EMBEDDED_3: - expr = dmrC_alloc_expression(C, token->pos, EXPR_VALUE); - expr->flags = Int_const_expr; - expr->ctype = dmrC_token_type(token) < TOKEN_WIDE_CHAR ? &C->S->int_ctype : &C->S->long_ctype; - dmrC_get_char_constant(C, token, &expr->value); - token = token->next; - break; - - case TOKEN_NUMBER: - expr = dmrC_alloc_expression(C, token->pos, EXPR_VALUE); - get_number_value(C, expr, token); /* will see if it's an integer */ - token = token->next; - break; - - case TOKEN_ZERO_IDENT: { - expr = dmrC_alloc_expression(C, token->pos, EXPR_SYMBOL); - expr->flags = Int_const_expr; - expr->ctype = &C->S->int_ctype; - expr->symbol = &C->S->zero_int; - expr->symbol_name = token->ident; - token = token->next; - break; - } - - case TOKEN_IDENT: { - struct symbol *sym = dmrC_lookup_symbol(token->ident, NS_SYMBOL | NS_TYPEDEF); - struct token *next = token->next; - - if (!sym) { - sym = handle_func(C, token); - if (token->ident == C->S->__builtin_types_compatible_p_ident) { - token = builtin_types_compatible_p_expr(C, token, &expr); - break; - } - if (token->ident == C->S->__builtin_offsetof_ident) { - token = builtin_offsetof_expr(C, token, &expr); - break; - } - } else if (sym->enum_member) { - expr = dmrC_alloc_expression(C, token->pos, EXPR_VALUE); - *expr = *sym->initializer; - /* we want the right position reported, thus the copy */ - expr->pos = token->pos; - expr->flags = Int_const_expr; - token = next; - break; - } - - expr = dmrC_alloc_expression(C, token->pos, EXPR_SYMBOL); - - /* - * We support types as real first-class citizens, with type - * comparisons etc: - * - * if (typeof(a) == int) .. - */ - if (sym && sym->ns == NS_TYPEDEF) { - dmrC_sparse_error(C, token->pos, "typename in expression"); - sym = NULL; - } - expr->symbol_name = token->ident; - expr->symbol = sym; - token = next; - break; - } - - case TOKEN_STRING: - case TOKEN_WIDE_STRING: - expr = dmrC_alloc_expression(C, token->pos, EXPR_STRING); - token = dmrC_get_string_constant(C, token, expr); - break; - - case TOKEN_SPECIAL: - if (token->special == '(') { - expr = dmrC_alloc_expression(C, token->pos, EXPR_PREOP); - expr->op = '('; - token = dmrC_parens_expression(C, token, &expr->unop, "in expression"); - if (expr->unop) - expr->flags = expr->unop->flags; - break; - } - if (token->special == '[' && dmrC_lookup_type(token->next)) { - expr = dmrC_alloc_expression(C, token->pos, EXPR_TYPE); - expr->flags = Int_const_expr; /* sic */ - token = dmrC_typename(C, token->next, &expr->symbol, NULL); - token = dmrC_expect_token(C, token, ']', "in type expression"); - break; - } - - default: - ; - } - *tree = expr; - return token; -} - -static struct token *expression_list(struct dmr_C *C, struct token *token, struct expression_list **list) -{ - while (!dmrC_match_op(token, ')')) { - struct expression *expr = NULL; - token = dmrC_assignment_expression(C, token, &expr); - if (!expr) - break; - dmrC_add_expression(C, list, expr); - if (!dmrC_match_op(token, ',')) - break; - token = token->next; - } - return token; -} - -/* - * extend to deal with the ambiguous C grammar for parsing - * a cast expressions followed by an initializer. - */ -static struct token *postfix_expression(struct dmr_C *C, struct token *token, struct expression **tree, struct expression *cast_init_expr) -{ - struct expression *expr = cast_init_expr; - - if (!expr) - token = dmrC_primary_expression(C, token, &expr); - - while (expr && dmrC_token_type(token) == TOKEN_SPECIAL) { - switch (token->special) { - case '[': { /* Array dereference */ - struct expression *deref = dmrC_alloc_expression(C, token->pos, EXPR_PREOP); - struct expression *add = dmrC_alloc_expression(C, token->pos, EXPR_BINOP); - - deref->op = '*'; - deref->unop = add; - - add->op = '+'; - add->left = expr; - token = dmrC_parse_expression(C, token->next, &add->right); - token = dmrC_expect_token(C, token, ']', "at end of array dereference"); - expr = deref; - continue; - } - case SPECIAL_INCREMENT: /* Post-increment */ - case SPECIAL_DECREMENT: { /* Post-decrement */ - struct expression *post = dmrC_alloc_expression(C, token->pos, EXPR_POSTOP); - post->op = token->special; - post->unop = expr; - expr = post; - token = token->next; - continue; - } - case SPECIAL_DEREFERENCE: { /* Structure pointer member dereference */ - /* "x->y" is just shorthand for "(*x).y" */ - struct expression *inner = dmrC_alloc_expression(C, token->pos, EXPR_PREOP); - inner->op = '*'; - inner->unop = expr; - expr = inner; - } - /* Fall through!! */ - case '.': { /* Structure member dereference */ - struct expression *deref = dmrC_alloc_expression(C, token->pos, EXPR_DEREF); - deref->op = '.'; - deref->deref = expr; - token = token->next; - if (dmrC_token_type(token) != TOKEN_IDENT) { - dmrC_sparse_error(C, token->pos, "Expected member name"); - break; - } - deref->member = token->ident; - token = token->next; - expr = deref; - continue; - } - - case '(': { /* Function call */ - struct expression *call = dmrC_alloc_expression(C, token->pos, EXPR_CALL); - call->op = '('; - call->fn = expr; - token = expression_list(C, token->next, &call->args); - token = dmrC_expect_token(C, token, ')', "in function call"); - expr = call; - continue; - } - - default: - break; - } - break; - } - *tree = expr; - return token; -} - -static struct token *cast_expression(struct dmr_C *C, struct token *token, struct expression **tree); -static struct token *unary_expression(struct dmr_C *C, struct token *token, struct expression **tree); - -static struct token *type_info_expression(struct dmr_C *C, struct token *token, - struct expression **tree, int type) -{ - struct expression *expr = dmrC_alloc_expression(C, token->pos, type); - struct token *p; - - *tree = expr; - expr->flags = Int_const_expr; /* XXX: VLA support will need that changed */ - token = token->next; - if (!dmrC_match_op(token, '(') || !dmrC_lookup_type(token->next)) - return unary_expression(C, token, &expr->cast_expression); - p = token; - token = dmrC_typename(C, token->next, &expr->cast_type, NULL); - - if (!dmrC_match_op(token, ')')) { - static const char * error[] = { - [EXPR_SIZEOF] = "at end of sizeof", - [EXPR_ALIGNOF] = "at end of __alignof__", - [EXPR_PTRSIZEOF] = "at end of __sizeof_ptr__" - }; - return dmrC_expect_token(C, token, ')', error[type]); - } - - token = token->next; - /* - * C99 ambiguity: the typename might have been the beginning - * of a typed initializer expression.. - */ - if (dmrC_match_op(token, '{')) { - struct expression *cast = dmrC_alloc_expression(C, p->pos, EXPR_CAST); - cast->cast_type = expr->cast_type; - expr->cast_type = NULL; - expr->cast_expression = cast; - token = dmrC_initializer(C, &cast->cast_expression, token); - token = postfix_expression(C, token, &expr->cast_expression, cast); - } - return token; -} - -static struct token *unary_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - if (dmrC_token_type(token) == TOKEN_IDENT) { - struct ident *ident = token->ident; - if (ident->reserved) { - const struct { - struct ident *id; - int type; - } type_information[] = { - { C->S->sizeof_ident, EXPR_SIZEOF }, - { C->S->__alignof___ident, EXPR_ALIGNOF }, - { C->S->__alignof_ident, EXPR_ALIGNOF }, - { C->S->_Alignof_ident, EXPR_ALIGNOF }, - { C->S->__sizeof_ptr___ident, EXPR_PTRSIZEOF }, - }; - int i; - for (i = 0; i < (int)ARRAY_SIZE(type_information); i++) { - if (ident == type_information[i].id) - return type_info_expression(C, token, tree, type_information[i].type); - } - } - } - - if (dmrC_token_type(token) == TOKEN_SPECIAL) { - if (match_oplist(token->special, - SPECIAL_INCREMENT, SPECIAL_DECREMENT, - '&', '*', 0)) { - struct expression *unop; - struct expression *unary; - struct token *next; - - next = cast_expression(C, token->next, &unop); - if (!unop) { - dmrC_sparse_error(C, token->pos, "Syntax error in unary expression"); - *tree = NULL; - return next; - } - unary = dmrC_alloc_expression(C, token->pos, EXPR_PREOP); - unary->op = token->special; - unary->unop = unop; - *tree = unary; - return next; - } - /* possibly constant ones */ - if (match_oplist(token->special, '+', '-', '~', '!', 0)) { - struct expression *unop; - struct expression *unary; - struct token *next; - - next = cast_expression(C, token->next, &unop); - if (!unop) { - dmrC_sparse_error(C, token->pos, "Syntax error in unary expression"); - *tree = NULL; - return next; - } - unary = dmrC_alloc_expression(C, token->pos, EXPR_PREOP); - unary->op = token->special; - unary->unop = unop; - unary->flags = unop->flags & Int_const_expr; - *tree = unary; - return next; - } - /* Gcc extension: &&label gives the address of a label */ - if (dmrC_match_op(token, SPECIAL_LOGICAL_AND) && - dmrC_token_type(token->next) == TOKEN_IDENT) { - struct expression *label = dmrC_alloc_expression(C, token->pos, EXPR_LABEL); - struct symbol *sym = dmrC_label_symbol(C, token->next); - if (!(sym->ctype.modifiers & MOD_ADDRESSABLE)) { - sym->ctype.modifiers |= MOD_ADDRESSABLE; - dmrC_add_symbol(C, &C->P->function_computed_target_list, sym); - } - label->label_symbol = sym; - *tree = label; - return token->next->next; - } - - } - - return postfix_expression(C, token, tree, NULL); -} - -/* - * Ambiguity: a '(' can be either a cast-expression or - * a primary-expression depending on whether it is followed - * by a type or not. - * - * additional ambiguity: a "cast expression" followed by - * an initializer is really a postfix-expression. - */ -static struct token *cast_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - if (dmrC_match_op(token, '(')) { - struct token *next = token->next; - if (dmrC_lookup_type(next)) { - struct expression *cast = dmrC_alloc_expression(C, next->pos, EXPR_CAST); - struct expression *v; - struct symbol *sym; - int is_force; - - token = dmrC_typename(C, next, &sym, &is_force); - cast->cast_type = sym; - token = dmrC_expect_token(C, token, ')', "at end of cast operator"); - if (dmrC_match_op(token, '{')) { - if (is_force) - dmrC_warning(C, sym->pos, - "[force] in compound literal"); - token = dmrC_initializer(C, &cast->cast_expression, token); - return postfix_expression(C, token, tree, cast); - } - *tree = cast; - if (is_force) - cast->type = EXPR_FORCE_CAST; - token = cast_expression(C, token, &v); - if (!v) - return token; - cast->cast_expression = v; - if (v->flags & Int_const_expr) - cast->flags = Int_const_expr; - else if (v->flags & Float_literal) /* and _not_ int */ - cast->flags = Int_const_expr | Float_literal; - return token; - } - } - return unary_expression(C, token, tree); -} - -/* - * Generic left-to-right binop parsing - * - * This _really_ needs to be inlined, because that makes the inner - * function call statically deterministic rather than a totally - * unpredictable indirect call. But gcc-3 is so "clever" that it - * doesn't do so by default even when you tell it to inline it. - * - * Making it a macro avoids the inlining problem, and also means - * that we can pass in the op-comparison as an expression rather - * than create a data structure for it. - */ - -#define LR_BINOP_EXPRESSION(C, __token, tree, type, inner, compare) \ - struct expression *left = NULL; \ - struct token * next = inner(C, __token, &left); \ - \ - if (left) { \ - while (dmrC_token_type(next) == TOKEN_SPECIAL) { \ - struct expression *top, *right = NULL; \ - int op = next->special; \ - \ - if (!(compare)) \ - goto out; \ - top = dmrC_alloc_expression(C, next->pos, type); \ - next = inner(C, next->next, &right); \ - if (!right) { \ - dmrC_sparse_error(C, next->pos, "No right hand side of '%s'-expression", dmrC_show_special(C, op)); \ - break; \ - } \ - top->flags = left->flags & right->flags \ - & Int_const_expr; \ - top->op = op; \ - top->left = left; \ - top->right = right; \ - left = top; \ - } \ - } \ -out: \ - *tree = left; \ - return next; \ - -static struct token *multiplicative_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_BINOP, cast_expression, - (op == '*') || (op == '/') || (op == '%') - ); -} - -static struct token *additive_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_BINOP, multiplicative_expression, - (op == '+') || (op == '-') - ); -} - -static struct token *shift_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_BINOP, additive_expression, - (op == SPECIAL_LEFTSHIFT) || (op == SPECIAL_RIGHTSHIFT) - ); -} - -static struct token *relational_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_COMPARE, shift_expression, - (op == '<') || (op == '>') || - (op == SPECIAL_LTE) || (op == SPECIAL_GTE) - ); -} - -static struct token *equality_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_COMPARE, relational_expression, - (op == SPECIAL_EQUAL) || (op == SPECIAL_NOTEQUAL) - ); -} - -static struct token *bitwise_and_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_BINOP, equality_expression, - (op == '&') - ); -} - -static struct token *bitwise_xor_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_BINOP, bitwise_and_expression, - (op == '^') - ); -} - -static struct token *bitwise_or_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_BINOP, bitwise_xor_expression, - (op == '|') - ); -} - -static struct token *logical_and_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_LOGICAL, bitwise_or_expression, - (op == SPECIAL_LOGICAL_AND) - ); -} - -static struct token *logical_or_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_LOGICAL, logical_and_expression, - (op == SPECIAL_LOGICAL_OR) - ); -} - -struct token *dmrC_conditional_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - token = logical_or_expression(C, token, tree); - if (*tree && dmrC_match_op(token, '?')) { - struct expression *expr = dmrC_alloc_expression(C, token->pos, EXPR_CONDITIONAL); - expr->op = token->special; - expr->left = *tree; - *tree = expr; - token = dmrC_parse_expression(C, token->next, &expr->cond_true); - token = dmrC_expect_token(C, token, ':', "in conditional expression"); - token = dmrC_conditional_expression(C, token, &expr->cond_false); - if (expr->left && expr->cond_false) { - int is_const = expr->left->flags & - expr->cond_false->flags & - Int_const_expr; - if (expr->cond_true) - is_const &= expr->cond_true->flags; - expr->flags = is_const; - } - } - return token; -} - -struct token *dmrC_assignment_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - token = dmrC_conditional_expression(C, token, tree); - if (*tree && dmrC_token_type(token) == TOKEN_SPECIAL) { - static const int assignments[] = { - '=', - SPECIAL_ADD_ASSIGN, SPECIAL_SUB_ASSIGN, - SPECIAL_MUL_ASSIGN, SPECIAL_DIV_ASSIGN, - SPECIAL_MOD_ASSIGN, SPECIAL_SHL_ASSIGN, - SPECIAL_SHR_ASSIGN, SPECIAL_AND_ASSIGN, - SPECIAL_OR_ASSIGN, SPECIAL_XOR_ASSIGN }; - int i, op = token->special; - for (i = 0; i < (int)ARRAY_SIZE(assignments); i++) - if (assignments[i] == op) { - struct expression * expr = dmrC_alloc_expression(C, token->pos, EXPR_ASSIGNMENT); - expr->left = *tree; - expr->op = op; - *tree = expr; - return dmrC_assignment_expression(C, token->next, &expr->right); - } - } - return token; -} - -static struct token *comma_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - LR_BINOP_EXPRESSION(C, - token, tree, EXPR_COMMA, dmrC_assignment_expression, - (op == ',') - ); -} - -struct token *dmrC_parse_expression(struct dmr_C *C, struct token *token, struct expression **tree) -{ - return comma_expression(C, token,tree); -} - - diff --git a/dmr_c/src/expression.h b/dmr_c/src/expression.h deleted file mode 100644 index e59c658..0000000 --- a/dmr_c/src/expression.h +++ /dev/null @@ -1,265 +0,0 @@ -#ifndef DMR_C_EXPRESSION_H -#define DMR_C_EXPRESSION_H -/* -* sparse/expression.h -* -* Copyright (C) 2003 Transmeta Corp. -* 2003 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -* -* Declarations and helper functions for expression parsing. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - - -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -enum expression_type { - EXPR_VALUE = 1, - EXPR_STRING, - EXPR_SYMBOL, - EXPR_TYPE, - EXPR_BINOP, - EXPR_ASSIGNMENT, - EXPR_LOGICAL, - EXPR_DEREF, - EXPR_PREOP, - EXPR_POSTOP, - EXPR_CAST, - EXPR_FORCE_CAST, - EXPR_IMPLIED_CAST, - EXPR_SIZEOF, - EXPR_ALIGNOF, - EXPR_PTRSIZEOF, - EXPR_CONDITIONAL, - EXPR_SELECT, // a "safe" conditional expression - EXPR_STATEMENT, - EXPR_CALL, - EXPR_COMMA, - EXPR_COMPARE, - EXPR_LABEL, - EXPR_INITIALIZER, // initializer list - EXPR_IDENTIFIER, // identifier in initializer - EXPR_INDEX, // index in initializer - EXPR_POS, // position in initializer - EXPR_FVALUE, - EXPR_SLICE, - EXPR_OFFSETOF, -}; - -enum { - Int_const_expr = 1, - Float_literal = 2, -}; /* for expr->flags */ - -enum { - Taint_comma = 1, -}; /* for expr->taint */ - -DECLARE_PTR_LIST(expression_list, struct expression); - -struct expression { - enum expression_type type:8; - unsigned flags:8; - int op; - struct position pos; - struct symbol *ctype; - union { - // EXPR_VALUE - struct { - unsigned long long value; - unsigned taint; - }; - - // EXPR_FVALUE - long double fvalue; - - // EXPR_STRING - struct { - int wide; - struct string *string; - }; - - // EXPR_UNOP, EXPR_PREOP and EXPR_POSTOP - struct /* unop */ { - struct expression *unop; - unsigned long op_value; - }; - - // EXPR_SYMBOL, EXPR_TYPE - struct /* symbol_arg */ { - struct symbol *symbol; - struct ident *symbol_name; - }; - - // EXPR_STATEMENT - struct statement *statement; - - // EXPR_BINOP, EXPR_COMMA, EXPR_COMPARE, EXPR_LOGICAL and EXPR_ASSIGNMENT - struct /* binop_arg */ { - struct expression *left, *right; - }; - // EXPR_DEREF - struct /* deref_arg */ { - struct expression *deref; - struct ident *member; - }; - // EXPR_SLICE - struct /* slice */ { - struct expression *base; - unsigned r_bitpos, r_nrbits; - }; - // EXPR_CAST and EXPR_SIZEOF - struct /* cast_arg */ { - struct symbol *cast_type; - struct expression *cast_expression; - }; - // EXPR_CONDITIONAL - // EXPR_SELECT - struct /* conditional_expr */ { - struct expression *conditional, *cond_true, *cond_false; - }; - // EXPR_CALL - struct /* call_expr */ { - struct expression *fn; - struct expression_list *args; - }; - // EXPR_LABEL - struct /* label_expr */ { - struct symbol *label_symbol; - }; - // EXPR_INITIALIZER - struct expression_list *expr_list; - // EXPR_IDENTIFIER - struct /* ident_expr */ { - int offset; - struct ident *expr_ident; - struct symbol *field; - struct expression *ident_expression; - }; - // EXPR_INDEX - struct /* index_expr */ { - unsigned int idx_from, idx_to; - struct expression *idx_expression; - }; - // EXPR_POS - struct /* initpos_expr */ { - unsigned int init_offset, init_nr; - struct expression *init_expr; - }; - // EXPR_OFFSETOF - struct { - struct symbol *in; - struct expression *down; - union { - struct ident *ident; - struct expression *index; - }; - }; - }; -}; - -long long dmrC_get_expression_value_silent(struct dmr_C *C, struct expression *expr); -extern struct symbol *dmrC_evaluate_expression(struct dmr_C *C, struct expression *); -long long dmrC_get_expression_value(struct dmr_C *C, struct expression *); - -/* Constant expression values */ -int dmrC_is_zero_constant(struct dmr_C *C, struct expression *); -int dmrC_expr_truth_value(struct dmr_C *C, struct expression *expr); -long long dmrC_const_expression_value(struct dmr_C *C, struct expression *); - -/* Expression parsing */ -struct token *dmrC_conditional_expression(struct dmr_C *C, struct token *token, - struct expression **tree); -struct token *dmrC_primary_expression(struct dmr_C *C, struct token *token, struct expression **tree); -struct token *dmrC_parens_expression(struct dmr_C *C, struct token *token, struct expression **expr, - const char *where); -struct token *dmrC_assignment_expression(struct dmr_C *C, struct token *token, - struct expression **tree); - -extern void dmrC_evaluate_symbol_list(struct dmr_C *C, struct symbol_list *list); -extern struct symbol *dmrC_evaluate_statement(struct dmr_C *C, struct statement *stmt); - -extern int dmrC_expand_symbol(struct dmr_C *C, struct symbol *); - -static inline struct expression *dmrC_alloc_expression(struct dmr_C *C, struct position pos, int type) -{ - struct expression *expr = (struct expression *)dmrC_allocator_allocate(&C->expression_allocator, 0); - expr->type = (enum expression_type)type; - expr->pos = pos; - return expr; -} - -static inline struct expression *dmrC_alloc_const_expression(struct dmr_C *C, struct position pos, - int value) -{ - struct expression *expr = (struct expression *)dmrC_allocator_allocate(&C->expression_allocator, 0); - expr->type = EXPR_VALUE; - expr->pos = pos; - expr->value = value; - expr->ctype = &C->S->int_ctype; - return expr; -} - -/* Type name parsing */ -struct token *dmrC_typename(struct dmr_C *C, struct token *, struct symbol **, int *); - -static inline int dmrC_lookup_type(struct token *token) -{ - if (token->pos.type == TOKEN_IDENT) { - struct symbol *sym = dmrC_lookup_symbol( - token->ident, - (enum namespace_type)(NS_SYMBOL | NS_TYPEDEF)); - return sym && (sym->ns & NS_TYPEDEF); - } - return 0; -} - -/* Statement parsing */ -struct statement *dmrC_alloc_statement(struct dmr_C *C, struct position pos, int type); -struct token *dmrC_initializer(struct dmr_C *C, struct expression **tree, struct token *token); -struct token *dmrC_compound_statement(struct dmr_C *C, struct token *, struct statement *); - -/* The preprocessor calls this 'dmrC_constant_expression()' */ -#define dmrC_constant_expression(C, token, tree) dmrC_conditional_expression(C, token, tree) - -/* Cast folding of constant values.. */ -void dmrC_cast_value(struct dmr_C *C, struct expression *expr, struct symbol *newtype, - struct expression *old, struct symbol *oldtype); - -static inline struct expression *dmrC_first_expression(struct expression_list *head) -{ - return (struct expression *) ptrlist_first((struct ptr_list *)head); -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/dmr_c/src/flow.c b/dmr_c/src/flow.c deleted file mode 100644 index 3419112..0000000 --- a/dmr_c/src/flow.c +++ /dev/null @@ -1,1008 +0,0 @@ -/* - * Flow - walk the linearized flowgraph, simplifying it as we - * go along. - * - * Copyright (C) 2004 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -/* - * Dammit, if we have a phi-node followed by a conditional - * branch on that phi-node, we should damn well be able to - * do something about the source. Maybe. - */ -static int rewrite_branch(struct dmr_C *C, struct basic_block *bb, - struct basic_block **ptr, - struct basic_block *old, - struct basic_block *new) -{ - if (*ptr != old || new == old || !bb->ep) - return 0; - - /* We might find new if-conversions or non-dominating CSEs */ - /* we may also create new dead cycles */ - C->L->repeat_phase |= REPEAT_CSE | REPEAT_CFG_CLEANUP; - *ptr = new; - dmrC_replace_bb_in_list(&bb->children, old, new, 1); - dmrC_remove_bb_from_list(&old->parents, bb, 1); - dmrC_add_bb(C, &new->parents, bb); - return 1; -} - -/* - * Return the known truth value of a pseudo, or -1 if - * it's not known. - */ -static int pseudo_truth_value(pseudo_t pseudo) -{ - switch (pseudo->type) { - case PSEUDO_VAL: - return !!pseudo->value; - - case PSEUDO_REG: { - struct instruction *insn = pseudo->def; - - /* A symbol address is always considered true.. */ - if (insn->opcode == OP_SYMADDR && insn->target == pseudo) - return 1; - } - /* Fall through */ - default: - return -1; - } -} - -/* - * Does a basic block depend on the pseudos that "src" defines? - */ -static int bb_depends_on(struct basic_block *target, struct basic_block *src) -{ - pseudo_t pseudo; - - FOR_EACH_PTR(src->defines, pseudo) { - if (dmrC_pseudo_in_list(target->needs, pseudo)) - return 1; - } END_FOR_EACH_PTR(pseudo); - return 0; -} - -/* - * This really should be handled by bb_depends_on() - * which efficiently check the dependence using the - * defines - needs liveness info. Problem is that - * there is no liveness done on OP_PHI & OP_PHISRC. - * - * This function add the missing dependency checks. - */ -static int bb_depends_on_phi(struct basic_block *target, struct basic_block *src) -{ - struct instruction *insn; - FOR_EACH_PTR(src->insns, insn) { - if (!insn->bb) - continue; - if (insn->opcode != OP_PHI) - continue; - if (dmrC_pseudo_in_list(target->needs, insn->target)) - return 1; - } END_FOR_EACH_PTR(insn); - return 0; -} -/* - * When we reach here, we have: - * - a basic block that ends in a conditional branch and - * that has no side effects apart from the pseudos it - * may change. - * - the phi-node that the conditional branch depends on - * - full pseudo liveness information - * - * We need to check if any of the _sources_ of the phi-node - * may be constant, and not actually need this block at all. - */ -static int try_to_simplify_bb(struct dmr_C *C, struct basic_block *bb, struct instruction *first, struct instruction *second) -{ - int changed = 0; - pseudo_t phi; - int bogus; - - /* - * This a due to improper dominance tracking during - * simplify_symbol_usage()/conversion to SSA form. - * No sane simplification can be done when we have this. - */ - bogus = dmrC_bb_list_size(bb->parents) != dmrC_pseudo_list_size(first->phi_list); - - FOR_EACH_PTR(first->phi_list, phi) { - struct instruction *def = phi->def; - struct basic_block *source, *target; - pseudo_t pseudo; - struct instruction *br; - int true; - - if (!def) - continue; - source = def->bb; - pseudo = def->src1; - if (!pseudo || !source) - continue; - br = dmrC_last_instruction(source->insns); - if (!br) - continue; - if (br->opcode != OP_CBR && br->opcode != OP_BR) - continue; - true = pseudo_truth_value(pseudo); - if (true < 0) - continue; - target = true ? second->bb_true : second->bb_false; - if (bb_depends_on(target, bb)) - continue; - if (bb_depends_on_phi(target, bb)) - continue; - changed |= rewrite_branch(C, source, &br->bb_true, bb, target); - changed |= rewrite_branch(C, source, &br->bb_false, bb, target); - if (changed && !bogus) - dmrC_kill_use(C, THIS_ADDRESS(pseudo_t, phi)); - } END_FOR_EACH_PTR(phi); - return changed; -} - -static int bb_has_side_effects(struct basic_block *bb) -{ - struct instruction *insn; - FOR_EACH_PTR(bb->insns, insn) { - switch (insn->opcode) { - case OP_CALL: - /* FIXME! This should take "const" etc into account */ - return 1; - - case OP_STORE: - case OP_CONTEXT: - return 1; - - case OP_ASM: - /* FIXME! This should take "volatile" etc into account */ - return 1; - - default: - continue; - } - } END_FOR_EACH_PTR(insn); - return 0; -} - -static int simplify_phi_branch(struct dmr_C *C, struct basic_block *bb, struct instruction *br) -{ - pseudo_t cond = br->cond; - struct instruction *def; - - if (cond->type != PSEUDO_REG) - return 0; - def = cond->def; - if (def->bb != bb || def->opcode != OP_PHI) - return 0; - if (bb_has_side_effects(bb)) - return 0; - return try_to_simplify_bb(C, bb, def, br); -} - -static int simplify_branch_branch(struct dmr_C *C, struct basic_block *bb, struct instruction *br, - struct basic_block **target_p, int true) -{ - struct basic_block *target = *target_p, *final; - struct instruction *insn; - int retval; - - if (target == bb) - return 0; - insn = dmrC_last_instruction(target->insns); - if (!insn || insn->opcode != OP_CBR || insn->cond != br->cond) - return 0; - /* - * Ahhah! We've found a branch to a branch on the same conditional! - * Now we just need to see if we can rewrite the branch.. - */ - retval = 0; - final = true ? insn->bb_true : insn->bb_false; - if (bb_has_side_effects(target)) - goto try_to_rewrite_target; - if (bb_depends_on(final, target)) - goto try_to_rewrite_target; - if (bb_depends_on_phi(final, target)) - return 0; - return rewrite_branch(C, bb, target_p, target, final); - -try_to_rewrite_target: - /* - * If we're the only parent, at least we can rewrite the - * now-known second branch. - */ - if (dmrC_bb_list_size(target->parents) != 1) - return retval; - dmrC_insert_branch(C, target, insn, final); - return 1; -} - -static int simplify_one_branch(struct dmr_C *C, struct basic_block *bb, struct instruction *br) -{ - if (simplify_phi_branch(C, bb, br)) - return 1; - return simplify_branch_branch(C, bb, br, &br->bb_true, 1) | - simplify_branch_branch(C, bb, br, &br->bb_false, 0); -} - -static int simplify_branch_nodes(struct dmr_C *C, struct entrypoint *ep) -{ - int changed = 0; - struct basic_block *bb; - - FOR_EACH_PTR(ep->bbs, bb) { - struct instruction *br = dmrC_last_instruction(bb->insns); - - if (!br || br->opcode != OP_CBR) - continue; - changed |= simplify_one_branch(C, bb, br); - } END_FOR_EACH_PTR(bb); - return changed; -} - -/* - * This is called late - when we have intra-bb liveness information.. - */ -int dmrC_simplify_flow(struct dmr_C *C, struct entrypoint *ep) -{ - return simplify_branch_nodes(C, ep); -} - - -void dmrC_convert_load_instruction(struct dmr_C *C, struct instruction *insn, pseudo_t src) -{ - dmrC_convert_instruction_target(C, insn, src); - /* Turn the load into a no-op */ - insn->opcode = OP_LNOP; - insn->bb = NULL; -} - -static int overlapping_memop(struct dmr_C *C, struct instruction *a, struct instruction *b) -{ - unsigned int a_start = dmrC_bytes_to_bits(C->target, a->offset); - unsigned int b_start = dmrC_bytes_to_bits(C->target, b->offset); - unsigned int a_size = a->size; - unsigned int b_size = b->size; - - if (a_size + a_start <= b_start) - return 0; - if (b_size + b_start <= a_start) - return 0; - return 1; -} - -static inline int same_memop(struct instruction *a, struct instruction *b) -{ - return a->offset == b->offset && a->size == b->size; -} - -static inline int distinct_symbols(pseudo_t a, pseudo_t b) -{ - if (a->type != PSEUDO_SYM) - return 0; - if (b->type != PSEUDO_SYM) - return 0; - return a->sym != b->sym; -} -/* - * Return 1 if "dom" dominates the access to "pseudo" - * in "insn". - * - * Return 0 if it doesn't, and -1 if you don't know. - */ -int dmrC_dominates(struct dmr_C *C, pseudo_t pseudo, struct instruction *insn, struct instruction *dom, int local) -{ - int opcode = dom->opcode; - - if (opcode == OP_CALL || opcode == OP_ENTRY) - return local ? 0 : -1; - if (opcode != OP_LOAD && opcode != OP_STORE) - return 0; - if (dom->src != pseudo) { - if (local) - return 0; - /* We don't think two explicitly different symbols ever alias */ - if (distinct_symbols(insn->src, dom->src)) - return 0; - /* We could try to do some alias analysis here */ - return -1; - } - if (!same_memop(insn, dom)) { - // TODO I think I changed this to fix some simplification issue - // http://marc.info/?l=linux-sparse&m=148966371314267&w=2 - if (dom->opcode == OP_LOAD) - return -1; - if (!overlapping_memop(C, insn, dom)) - return 0; - return -1; - } - return 1; -} - -static int phisrc_in_bb(struct pseudo_list *list, struct basic_block *bb) -{ - pseudo_t p; - FOR_EACH_PTR(list, p) { - if (p->def->bb == bb) - return 1; - } END_FOR_EACH_PTR(p); - - return 0; -} -static int find_dominating_parents(struct dmr_C *C, pseudo_t pseudo, struct instruction *insn, - struct basic_block *bb, unsigned long generation, struct pseudo_list **dominators, - int local) -{ - struct basic_block *parent; - - if (!bb->parents) - return !!local; - - FOR_EACH_PTR(bb->parents, parent) { - struct instruction *one; - struct instruction *br; - pseudo_t phi; - - FOR_EACH_PTR_REVERSE(parent->insns, one) { - int dominance; - if (one == insn) - goto no_dominance; - dominance = dmrC_dominates(C, pseudo, insn, one, local); - if (dominance < 0) { - if (one->opcode == OP_LOAD) - continue; - return 0; - } - if (!dominance) - continue; - goto found_dominator; - } END_FOR_EACH_PTR_REVERSE(one); -no_dominance: - if (parent->generation == generation) - continue; - parent->generation = generation; - - if (!find_dominating_parents(C, pseudo, insn, parent, generation, dominators, local)) - return 0; - continue; - -found_dominator: - if (dominators && phisrc_in_bb(*dominators, parent)) - continue; - br = dmrC_delete_last_instruction(&parent->insns); - phi = dmrC_alloc_phi(C, parent, one->target, one->type); - phi->ident = phi->ident ? phi->ident : pseudo->ident; - dmrC_add_instruction(C, &parent->insns, br); - dmrC_use_pseudo(C, insn, phi, dmrC_add_pseudo(C, dominators, phi)); - } END_FOR_EACH_PTR(parent); - return 1; -} - -/* - * We should probably sort the phi list just to make it easier to compare - * later for equality. - */ -void dmrC_rewrite_load_instruction(struct dmr_C *C, struct instruction *insn, struct pseudo_list *dominators) -{ - pseudo_t new, phi; - - /* - * Check for somewhat common case of duplicate - * phi nodes. - */ - new = dmrC_first_pseudo(dominators)->def->src1; - FOR_EACH_PTR(dominators, phi) { - if (new != phi->def->src1) - goto complex_phi; - new->ident = new->ident ? new->ident : phi->ident; - } END_FOR_EACH_PTR(phi); - - /* - * All the same pseudo - mark the phi-nodes unused - * and convert the load into a LNOP and replace the - * pseudo. - */ - FOR_EACH_PTR(dominators, phi) { - dmrC_kill_instruction(C, phi->def); - } END_FOR_EACH_PTR(phi); - dmrC_convert_load_instruction(C, insn, new); - return; - -complex_phi: - /* We leave symbol pseudos with a bogus usage list here */ - if (insn->src->type != PSEUDO_SYM) - dmrC_kill_use(C, &insn->src); - insn->opcode = OP_PHI; - insn->phi_list = dominators; -} - -static int find_dominating_stores(struct dmr_C *C, pseudo_t pseudo, struct instruction *insn, - unsigned long generation, int local) -{ - struct basic_block *bb = insn->bb; - struct instruction *one, *dom = NULL; - struct pseudo_list *dominators; - int partial; - - /* Unreachable load? Undo it */ - if (!bb) { - insn->opcode = OP_LNOP; - return 1; - } - - partial = 0; - FOR_EACH_PTR(bb->insns, one) { - int dominance; - if (one == insn) - goto found; - dominance = dmrC_dominates(C, pseudo, insn, one, local); - if (dominance < 0) { - /* Ignore partial load dominators */ - if (one->opcode == OP_LOAD) - continue; - dom = NULL; - partial = 1; - continue; - } - if (!dominance) - continue; - dom = one; - partial = 0; - } END_FOR_EACH_PTR(one); - /* Whaa? */ - dmrC_warning(C, pseudo->sym->pos, "unable to find symbol read"); - return 0; -found: - if (partial) - return 0; - - if (dom) { - dmrC_convert_load_instruction(C, insn, dom->target); - return 1; - } - - /* OK, go find the parents */ - bb->generation = generation; - - dominators = NULL; - if (!find_dominating_parents(C, pseudo, insn, bb, generation, &dominators, local)) - return 0; - - /* This happens with initial assignments to structures etc.. */ - if (!dominators) { - if (!local) - return 0; - dmrC_check_access(C, insn); - dmrC_convert_load_instruction(C, insn, dmrC_value_pseudo(C, insn->type, 0)); - return 1; - } - - /* - * If we find just one dominating instruction, we - * can turn it into a direct thing. Otherwise we'll - * have to turn the load into a phi-node of the - * dominators. - */ - dmrC_rewrite_load_instruction(C, insn, dominators); - return 1; -} - -static void kill_store(struct dmr_C *C, struct instruction *insn) -{ - if (insn) { - insn->bb = NULL; - insn->opcode = OP_SNOP; - dmrC_kill_use(C, &insn->target); - } -} - -/* Kill a pseudo that is dead on exit from the bb */ -static void kill_dead_stores(struct dmr_C *C, pseudo_t pseudo, unsigned long generation, struct basic_block *bb, int local) -{ - struct instruction *insn; - struct basic_block *parent; - - if (bb->generation == generation) - return; - bb->generation = generation; - FOR_EACH_PTR_REVERSE(bb->insns, insn) { - int opcode = insn->opcode; - - if (opcode != OP_LOAD && opcode != OP_STORE) { - if (local) - continue; - if (opcode == OP_CALL) - return; - continue; - } - if (insn->src == pseudo) { - if (opcode == OP_LOAD) - return; - kill_store(C, insn); - continue; - } - if (local) - continue; - if (insn->src->type != PSEUDO_SYM) - return; - } END_FOR_EACH_PTR_REVERSE(insn); - - FOR_EACH_PTR(bb->parents, parent) { - struct basic_block *child; - FOR_EACH_PTR(parent->children, child) { - if (child && child != bb) - return; - } END_FOR_EACH_PTR(child); - kill_dead_stores(C, pseudo, generation, parent, local); - } END_FOR_EACH_PTR(parent); -} - -/* - * This should see if the "insn" trivially dominates some previous store, and kill the - * store if unnecessary. - */ -static void kill_dominated_stores(struct dmr_C *C, pseudo_t pseudo, struct instruction *insn, - unsigned long generation, struct basic_block *bb, int local, int found) -{ - struct instruction *one; - struct basic_block *parent; - - /* Unreachable store? Undo it */ - if (!bb) { - kill_store(C, insn); - return; - } - if (bb->generation == generation) - return; - bb->generation = generation; - FOR_EACH_PTR_REVERSE(bb->insns, one) { - int dominance; - if (!found) { - if (one != insn) - continue; - found = 1; - continue; - } - dominance = dmrC_dominates(C, pseudo, insn, one, local); - if (!dominance) - continue; - if (dominance < 0) - return; - if (one->opcode == OP_LOAD) - return; - kill_store(C, one); - } END_FOR_EACH_PTR_REVERSE(one); - - if (!found) { - dmrC_warning(C, bb->pos, "Unable to find instruction"); - return; - } - - FOR_EACH_PTR(bb->parents, parent) { - struct basic_block *child; - FOR_EACH_PTR(parent->children, child) { - if (child && child != bb) - return; - } END_FOR_EACH_PTR(child); - kill_dominated_stores(C, pseudo, insn, generation, parent, local, found); - } END_FOR_EACH_PTR(parent); -} - -void dmrC_check_access(struct dmr_C *C, struct instruction *insn) -{ - pseudo_t pseudo = insn->src; - - if (insn->bb && pseudo->type == PSEUDO_SYM) { - int offset = insn->offset, bit = dmrC_bytes_to_bits(C->target, offset) + insn->size; - struct symbol *sym = pseudo->sym; - - if (sym->bit_size > 0 && (offset < 0 || bit > sym->bit_size)) - dmrC_warning(C, insn->pos, "invalid access %s '%s' (%d %d)", - offset < 0 ? "below" : "past the end of", - dmrC_show_ident(C, sym->ident), offset, - dmrC_bits_to_bytes(C->target, sym->bit_size)); - } -} - -static void simplify_one_symbol(struct dmr_C *C, struct entrypoint *ep, struct symbol *sym) -{ -#if SINGLE_STORE_SHORTCUT - pseudo_t pseudo, src; - struct instruction *def; -#else - pseudo_t pseudo; -#endif - struct pseudo_user *pu; - unsigned long mod; -#if SINGLE_STORE_SHORTCUT - int all, stores, complex; -#else - int all; -#endif - - /* Never used as a symbol? */ - pseudo = sym->pseudo; - if (!pseudo) - return; - - /* We don't do coverage analysis of volatiles.. */ - if (sym->ctype.modifiers & MOD_VOLATILE) - return; - - /* ..and symbols with external visibility need more care */ - mod = sym->ctype.modifiers & (MOD_NONLOCAL | MOD_STATIC | MOD_ADDRESSABLE); - if (mod) - goto external_visibility; - -#if SINGLE_STORE_SHORTCUT - def = NULL; - stores = 0; - complex = 0; -#endif - FOR_EACH_PTR(pseudo->users, pu) { - /* We know that the symbol-pseudo use is the "src" in the instruction */ - struct instruction *insn = pu->insn; - - switch (insn->opcode) { - case OP_STORE: -#if SINGLE_STORE_SHORTCUT - stores++; - def = insn; -#endif - break; - case OP_LOAD: - break; - case OP_SYMADDR: - if (!insn->bb) - continue; - mod |= MOD_ADDRESSABLE; - goto external_visibility; - case OP_NOP: - case OP_SNOP: - case OP_LNOP: - case OP_PHI: - continue; - default: - dmrC_warning(C, sym->pos, "symbol '%s' pseudo used in unexpected way", dmrC_show_ident(C, sym->ident)); - } -#if SINGLE_STORE_SHORTCUT - complex |= insn->offset; -#endif - } END_FOR_EACH_PTR(pu); - -#if SINGLE_STORE_SHORTCUT - if (complex) - goto complex_def; - if (stores > 1) - goto multi_def; - - /* - * Goodie, we have a single store (if even that) in the whole - * thing. Replace all loads with moves from the pseudo, - * replace the store with a def. - */ - src = VOID_PSEUDO(C); - if (def) - src = def->target; - - //printf("simply one symbol pre convert load\n"); - //dmrC_show_entry(C, ep); - - FOR_EACH_PTR(pseudo->users, pu) { - struct instruction *insn = pu->insn; - if (insn->opcode == OP_LOAD) { - dmrC_check_access(C, insn); - dmrC_convert_load_instruction(C, insn, src); - } - } END_FOR_EACH_PTR(pu); - - /* Turn the store into a no-op */ - kill_store(C, def); - - //printf("simply one symbol post kill store\n"); - //dmrC_show_entry(C, ep); - - return; - -multi_def: -complex_def: -#endif - -external_visibility: - all = 1; - FOR_EACH_PTR_REVERSE(pseudo->users, pu) { - struct instruction *insn = pu->insn; - if (insn->opcode == OP_LOAD) - all &= find_dominating_stores(C, pseudo, insn, ++C->L->bb_generation, !mod); - } END_FOR_EACH_PTR_REVERSE(pu); - - //printf("simply one symbol post find dominating stores\n"); - //dmrC_show_entry(C, ep); - - /* If we converted all the loads, remove the stores. They are dead */ - if (all && !mod) { - FOR_EACH_PTR(pseudo->users, pu) { - struct instruction *insn = pu->insn; - if (insn->opcode == OP_STORE) - kill_store(C, insn); - } END_FOR_EACH_PTR(pu); - } else { - /* - * If we couldn't take the shortcut, see if we can at least kill some - * of them.. - */ - - FOR_EACH_PTR(pseudo->users, pu) { - struct instruction *insn = pu->insn; - - //printf("simply one symbol pre kill dominated stores ins %s\n", dmrC_show_instruction(C, insn)); - //dmrC_show_entry(C, ep); - - if (insn->opcode == OP_STORE) - kill_dominated_stores(C, pseudo, insn, ++C->L->bb_generation, insn->bb, !mod, 0); - } END_FOR_EACH_PTR(pu); - - //printf("simply one symbol pre kill dead stores\n"); - //dmrC_show_entry(C, ep); - - if (!(mod & (MOD_NONLOCAL | MOD_STATIC))) { - struct basic_block *bb; - FOR_EACH_PTR(ep->bbs, bb) { - if (!bb->children) - kill_dead_stores(C, pseudo, ++C->L->bb_generation, bb, !mod); - } END_FOR_EACH_PTR(bb); - } - } - - return; -} - -void dmrC_simplify_symbol_usage(struct dmr_C *C, struct entrypoint *ep) -{ - pseudo_t pseudo; - - FOR_EACH_PTR(ep->accesses, pseudo) { - simplify_one_symbol(C, ep, pseudo->sym); - } END_FOR_EACH_PTR(pseudo); -} - - -static int rewrite_parent_branch(struct dmr_C *C, struct basic_block *bb, struct basic_block *old, struct basic_block *new) -{ - int changed = 0; - struct instruction *insn = dmrC_last_instruction(bb->insns); - - if (!insn) - return 0; - - /* Infinite loops: let's not "optimize" them.. */ - if (old == new) - return 0; - - switch (insn->opcode) { - case OP_CBR: - changed |= rewrite_branch(C, bb, &insn->bb_false, old, new); - /* fall through */ - case OP_BR: - changed |= rewrite_branch(C, bb, &insn->bb_true, old, new); - assert(changed); - return changed; - case OP_SWITCH: { - struct multijmp *jmp; - FOR_EACH_PTR(insn->multijmp_list, jmp) { - changed |= rewrite_branch(C, bb, &jmp->target, old, new); - } END_FOR_EACH_PTR(jmp); - assert(changed); - return changed; - } - default: - return 0; - } -} - -static struct basic_block * rewrite_branch_bb(struct dmr_C *C, struct basic_block *bb, struct instruction *br) -{ - struct basic_block *parent; - struct basic_block *target = br->bb_true; - struct basic_block *false = br->bb_false; - - if (br->opcode == OP_CBR) { - pseudo_t cond = br->cond; - if (cond->type != PSEUDO_VAL) - return NULL; - target = cond->value ? target : false; - } - - /* - * We can't do FOR_EACH_PTR() here, because the parent list - * may change when we rewrite the parent. - */ - while ((parent = dmrC_first_basic_block(bb->parents)) != NULL) { - if (!rewrite_parent_branch(C, parent, bb, target)) - return NULL; - } - return target; -} - -static void vrfy_bb_in_list(struct basic_block *bb, struct basic_block_list *list) -{ - if (bb) { - struct basic_block *tmp; - int no_bb_in_list = 0; - - FOR_EACH_PTR(list, tmp) { - if (bb == tmp) - return; - } END_FOR_EACH_PTR(tmp); - assert(no_bb_in_list); - } -} - -static void vrfy_parents(struct basic_block *bb) -{ - struct basic_block *tmp; - FOR_EACH_PTR(bb->parents, tmp) { - vrfy_bb_in_list(bb, tmp->children); - } END_FOR_EACH_PTR(tmp); -} - -static void vrfy_children(struct basic_block *bb) -{ - struct basic_block *tmp; - struct instruction *br = dmrC_last_instruction(bb->insns); - - if (!br) { - assert(!bb->children); - return; - } - switch (br->opcode) { - struct multijmp *jmp; - case OP_CBR: - vrfy_bb_in_list(br->bb_false, bb->children); - /* fall through */ - case OP_BR: - vrfy_bb_in_list(br->bb_true, bb->children); - break; - case OP_SWITCH: - case OP_COMPUTEDGOTO: - FOR_EACH_PTR(br->multijmp_list, jmp) { - vrfy_bb_in_list(jmp->target, bb->children); - } END_FOR_EACH_PTR(jmp); - break; - default: - break; - } - - FOR_EACH_PTR(bb->children, tmp) { - vrfy_bb_in_list(bb, tmp->parents); - } END_FOR_EACH_PTR(tmp); -} - -static void vrfy_bb_flow(struct basic_block *bb) -{ - vrfy_children(bb); - vrfy_parents(bb); -} - -void dmrC_vrfy_flow(struct entrypoint *ep) -{ - struct basic_block *bb; - struct basic_block *entry = ep->entry->bb; - - FOR_EACH_PTR(ep->bbs, bb) { - if (bb == entry) - entry = NULL; - vrfy_bb_flow(bb); - } END_FOR_EACH_PTR(bb); - assert(!entry); -} - -void dmrC_pack_basic_blocks(struct dmr_C *C, struct entrypoint *ep) -{ - struct basic_block *bb; - - /* See if we can merge a bb into another one.. */ - FOR_EACH_PTR(ep->bbs, bb) { - struct instruction *first, *insn; - struct basic_block *parent, *child, *last; - - if (!dmrC_bb_reachable(bb)) - continue; - - /* - * Just a branch? - */ - FOR_EACH_PTR(bb->insns, first) { - if (!first->bb) - continue; - switch (first->opcode) { - case OP_NOP: case OP_LNOP: case OP_SNOP: - case OP_INLINED_CALL: - continue; - case OP_CBR: - case OP_BR: { - struct basic_block *replace; - replace = rewrite_branch_bb(C, bb, first); - if (replace) { - dmrC_kill_bb(C, bb); - goto no_merge; - } - } - /* fallthrough */ - default: - goto out; - } - } END_FOR_EACH_PTR(first); - -out: - /* - * See if we only have one parent.. - */ - last = NULL; - FOR_EACH_PTR(bb->parents, parent) { - if (last) { - if (last != parent) - goto no_merge; - continue; - } - last = parent; - } END_FOR_EACH_PTR(parent); - - parent = last; - if (!parent || parent == bb) - continue; - - /* - * Goodie. See if the parent can merge.. - */ - FOR_EACH_PTR(parent->children, child) { - if (child != bb) - goto no_merge; - } END_FOR_EACH_PTR(child); - - /* - * Merge the two. - */ - C->L->repeat_phase |= REPEAT_CSE; - - parent->children = bb->children; - bb->children = NULL; - bb->parents = NULL; - - FOR_EACH_PTR(parent->children, child) { - dmrC_replace_bb_in_list(&child->parents, bb, parent, 0); - } END_FOR_EACH_PTR(child); - - dmrC_kill_instruction(C, dmrC_delete_last_instruction(&parent->insns)); - FOR_EACH_PTR(bb->insns, insn) { - if (insn->bb) { - assert(insn->bb == bb); - insn->bb = parent; - } - dmrC_add_instruction(C, &parent->insns, insn); - } END_FOR_EACH_PTR(insn); - bb->insns = NULL; - - no_merge: - /* nothing to do */; - } END_FOR_EACH_PTR(bb); -} - - diff --git a/dmr_c/src/flow.h b/dmr_c/src/flow.h deleted file mode 100644 index 018f962..0000000 --- a/dmr_c/src/flow.h +++ /dev/null @@ -1,46 +0,0 @@ -#ifndef DMR_C_FLOW_H -#define DMR_C_FLOW_H - -/* -* Flow - walk the linearized flowgraph, simplifying it as we -* go along. -* -* Copyright (C) 2004 Linus Torvalds -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -struct entrypoint; -struct instruction; - -extern int dmrC_simplify_flow(struct dmr_C *C, struct entrypoint *ep); - -extern void dmrC_simplify_symbol_usage(struct dmr_C *C, struct entrypoint *ep); -extern void dmrC_simplify_memops(struct dmr_C *C, struct entrypoint *ep); -extern void dmrC_pack_basic_blocks(struct dmr_C *C, struct entrypoint *ep); - -extern void dmrC_cleanup_and_cse(struct dmr_C *C, struct entrypoint *ep); -extern int dmrC_simplify_instruction(struct dmr_C *C, struct instruction *); - -extern void dmrC_kill_use(struct dmr_C *C, pseudo_t *usep); -extern void dmrC_remove_use(struct dmr_C *C, pseudo_t *); - -void dmrC_check_access(struct dmr_C *C, struct instruction *insn); -void dmrC_convert_load_instruction(struct dmr_C *C, struct instruction *, pseudo_t); -void dmrC_rewrite_load_instruction(struct dmr_C *C, struct instruction *, struct pseudo_list *); -int dmrC_dominates(struct dmr_C *C, pseudo_t pseudo, struct instruction *insn, struct instruction *dom, int local); - -extern void dmrC_vrfy_flow(struct entrypoint *ep); -extern int dmrC_pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/dmr_c/src/gcc-attr-list.h b/dmr_c/src/gcc-attr-list.h deleted file mode 100644 index 9aa2980..0000000 --- a/dmr_c/src/gcc-attr-list.h +++ /dev/null @@ -1,207 +0,0 @@ -GCC_ATTR(BELOW100) -GCC_ATTR(OS_Task) -GCC_ATTR(OS_main) -GCC_ATTR(OS_task) -GCC_ATTR(abi_tag) -GCC_ATTR(absdata) -GCC_ATTR(address) -GCC_ATTR(alias) -GCC_ATTR(aligned) -GCC_ATTR(alloc_align) -GCC_ATTR(alloc_size) -GCC_ATTR(altivec) -GCC_ATTR(always_inline) -GCC_ATTR(artificial) -GCC_ATTR(assume_aligned) -GCC_ATTR(bank_switch) -GCC_ATTR(based) -GCC_ATTR(below100) -GCC_ATTR(bnd_instrument) -GCC_ATTR(bnd_legacy) -GCC_ATTR(bnd_variable_size) -GCC_ATTR(break_handler) -GCC_ATTR(brk_interrupt) -GCC_ATTR(callee_pop_aggregate_return) -GCC_ATTR(cb) -GCC_ATTR(cdecl) -GCC_ATTR(cleanup) -GCC_ATTR(cmse_nonsecure_call) -GCC_ATTR(cmse_nonsecure_entry) -GCC_ATTR(cold) -GCC_ATTR(common) -GCC_ATTR(common_object) -GCC_ATTR(const) -GCC_ATTR(constructor) -GCC_ATTR(critical) -GCC_ATTR(default) -GCC_ATTR(deprecated) -GCC_ATTR(designated_init) -GCC_ATTR(destructor) -GCC_ATTR(disinterrupt) -GCC_ATTR(dllexport) -GCC_ATTR(dllimport) -GCC_ATTR(eightbit_data) -GCC_ATTR(either) -GCC_ATTR(error) -GCC_ATTR(exception) -GCC_ATTR(exception_handler) -GCC_ATTR(externally_visible) -GCC_ATTR(fallthrough) -GCC_ATTR(far) -GCC_ATTR(fast_interrupt) -GCC_ATTR(fastcall) -GCC_ATTR(flatten) -GCC_ATTR(force_align_arg_pointer) -GCC_ATTR(format) -GCC_ATTR(format_arg) -GCC_ATTR(forwarder_section) -GCC_ATTR(function_vector) -GCC_ATTR(gcc_struct) -GCC_ATTR(gnu_inline) -GCC_ATTR(hidden) -GCC_ATTR(hot) -GCC_ATTR(hotpatch) -GCC_ATTR(ifunc) -GCC_ATTR(init_priority) -GCC_ATTR(interfacearm) -GCC_ATTR(internal) -GCC_ATTR(interrupt) -GCC_ATTR(interrupt_handler) -GCC_ATTR(interrupt_thread) -GCC_ATTR(io) -GCC_ATTR(io_low) -GCC_ATTR(isr) -GCC_ATTR(keep_interrupts_masked) -GCC_ATTR(kernel) -GCC_ATTR(kspisusp) -GCC_ATTR(l1_data) -GCC_ATTR(l1_data_A) -GCC_ATTR(l1_data_B) -GCC_ATTR(l1_text) -GCC_ATTR(l2) -GCC_ATTR(leaf) -GCC_ATTR(long_call) -GCC_ATTR(longcall) -GCC_ATTR(lower) -GCC_ATTR(malloc) -GCC_ATTR(may_alias) -GCC_ATTR(maybe_unused) -GCC_ATTR(medium_call) -GCC_ATTR(micromips) -GCC_ATTR(mips16) -GCC_ATTR(mode) -GCC_ATTR(model) -GCC_ATTR(monitor) -GCC_ATTR(ms_abi) -GCC_ATTR(ms_hook_prologue) -GCC_ATTR(ms_struct) -GCC_ATTR(naked) -GCC_ATTR(near) -GCC_ATTR(nested) -GCC_ATTR(nested_ready) -GCC_ATTR(nesting) -GCC_ATTR(nmi) -GCC_ATTR(nmi_handler) -GCC_ATTR(no_address_safety_analysis) -GCC_ATTR(no_caller_saved_registers) -GCC_ATTR(no_gccisr) -GCC_ATTR(no_icf) -GCC_ATTR(no_instrument_function) -GCC_ATTR(no_profile_instrument_function) -GCC_ATTR(no_reorder) -GCC_ATTR(no_sanitize) -GCC_ATTR(no_sanitize_address) -GCC_ATTR(no_sanitize_thread) -GCC_ATTR(no_sanitize_undefined) -GCC_ATTR(no_split_stack) -GCC_ATTR(no_stack_limit) -GCC_ATTR(noclone) -GCC_ATTR(nocommon) -GCC_ATTR(nocompression) -GCC_ATTR(nodiscard) -GCC_ATTR(noinit) -GCC_ATTR(noinline) -GCC_ATTR(noipa) -GCC_ATTR(nomicromips) -GCC_ATTR(nomips16) -GCC_ATTR(nonnull) -GCC_ATTR(noplt) -GCC_ATTR(noreturn) -GCC_ATTR(nosave_low_regs) -GCC_ATTR(not_nested) -GCC_ATTR(nothrow) -GCC_ATTR(notshared) -GCC_ATTR(optimize) -GCC_ATTR(packed) -GCC_ATTR(partial_save) -GCC_ATTR(patchable_function_entry) -GCC_ATTR(pcs) -GCC_ATTR(persistent) -GCC_ATTR(progmem) -GCC_ATTR(protected) -GCC_ATTR(pure) -GCC_ATTR(reentrant) -GCC_ATTR(regparm) -GCC_ATTR(renesas) -GCC_ATTR(resbank) -GCC_ATTR(reset) -GCC_ATTR(returns_nonnull) -GCC_ATTR(returns_twice) -GCC_ATTR(s390_vector_bool) -GCC_ATTR(saddr) -GCC_ATTR(save_all) -GCC_ATTR(save_volatiles) -GCC_ATTR(saveall) -GCC_ATTR(scalar_storage_order) -GCC_ATTR(sda) -GCC_ATTR(section) -GCC_ATTR(selectany) -GCC_ATTR(sentinel) -GCC_ATTR(shared) -GCC_ATTR(short_call) -GCC_ATTR(shortcall) -GCC_ATTR(signal) -GCC_ATTR(simd) -GCC_ATTR(sp_switch) -GCC_ATTR(spu_vector) -GCC_ATTR(sseregparm) -GCC_ATTR(stack_protect) -GCC_ATTR(stdcall) -GCC_ATTR(syscall_linkage) -GCC_ATTR(sysv_abi) -GCC_ATTR(target) -GCC_ATTR(target_clones) -GCC_ATTR(tda) -GCC_ATTR(thiscall) -GCC_ATTR(tiny) -GCC_ATTR(tiny_data) -GCC_ATTR(tls_model) -GCC_ATTR(transaction_callable) -GCC_ATTR(transaction_may_cancel_outer) -GCC_ATTR(transaction_pure) -GCC_ATTR(transaction_safe) -GCC_ATTR(transaction_safe_dynamic) -GCC_ATTR(transaction_unsafe) -GCC_ATTR(transaction_wrap) -GCC_ATTR(transparent_union) -GCC_ATTR(trap_exit) -GCC_ATTR(trapa_handler) -GCC_ATTR(unused) -GCC_ATTR(upper) -GCC_ATTR(use_debug_exception_return) -GCC_ATTR(use_shadow_register_set) -GCC_ATTR(used) -GCC_ATTR(vector) -GCC_ATTR(vector_size) -GCC_ATTR(version_id) -GCC_ATTR(visibility) -GCC_ATTR(vliw) -GCC_ATTR(volatile) -GCC_ATTR(wakeup) -GCC_ATTR(warm) -GCC_ATTR(warn_unused) -GCC_ATTR(warn_unused_result) -GCC_ATTR(warning) -GCC_ATTR(weak) -GCC_ATTR(weakref) -GCC_ATTR(zda) diff --git a/dmr_c/src/ident-list.h b/dmr_c/src/ident-list.h deleted file mode 100644 index 709ffce..0000000 --- a/dmr_c/src/ident-list.h +++ /dev/null @@ -1,140 +0,0 @@ - -#define IDENT(n) __IDENT(n## _ident, #n, 0) -#define IDENT_RESERVED(n) __IDENT(n## _ident, #n, 1) - -/* Basic C reserved words.. */ -IDENT_RESERVED(sizeof); -IDENT_RESERVED(if); -IDENT_RESERVED(else); -IDENT_RESERVED(return); -IDENT_RESERVED(switch); -IDENT_RESERVED(case); -IDENT_RESERVED(default); -IDENT_RESERVED(break); -IDENT_RESERVED(continue); -IDENT_RESERVED(for); -IDENT_RESERVED(while); -IDENT_RESERVED(do); -IDENT_RESERVED(goto); - -/* C typenames. They get marked as reserved when initialized */ -IDENT(struct); -IDENT(union); -IDENT(enum); -IDENT(__attribute); IDENT(__attribute__); -IDENT(volatile); IDENT(__volatile); IDENT(__volatile__); -IDENT(double); - -/* C storage classes. They get marked as reserved when initialized */ -IDENT(static); - -/* C99 keywords */ -IDENT(restrict); IDENT(__restrict); IDENT(__restrict__); -IDENT(_Bool); -IDENT_RESERVED(_Complex); -IDENT_RESERVED(_Imaginary); - -/* C11 keywords */ -IDENT(_Alignas); -IDENT_RESERVED(_Alignof); -IDENT_RESERVED(_Atomic); -IDENT_RESERVED(_Generic); -IDENT(_Noreturn); -IDENT_RESERVED(_Static_assert); -IDENT(_Thread_local); - -/* Special case for L'\t' */ -IDENT(L); - -/* Extended gcc identifiers */ -IDENT(asm); IDENT_RESERVED(__asm); IDENT_RESERVED(__asm__); -IDENT(alignof); IDENT_RESERVED(__alignof); IDENT_RESERVED(__alignof__); -IDENT_RESERVED(__sizeof_ptr__); -IDENT_RESERVED(__builtin_types_compatible_p); -IDENT_RESERVED(__builtin_offsetof); -IDENT_RESERVED(__label__); - -/* Attribute names */ -IDENT(packed); IDENT(__packed__); -IDENT(aligned); IDENT(__aligned__); -IDENT(nocast); -IDENT(noderef); -IDENT(safe); -IDENT(force); -IDENT(address_space); -IDENT(context); -IDENT(mode); IDENT(__mode__); -IDENT(QI); IDENT(__QI__); -IDENT(HI); IDENT(__HI__); -IDENT(SI); IDENT(__SI__); -IDENT(DI); IDENT(__DI__); -IDENT(word); IDENT(__word__); -IDENT(format); IDENT(__format__); -IDENT(section); IDENT(__section__); -IDENT(unused); IDENT(__unused__); -IDENT(const); IDENT(__const); IDENT(__const__); -IDENT(used); IDENT(__used__); -IDENT(warn_unused_result); IDENT(__warn_unused_result__); -IDENT(noinline); IDENT(__noinline__); -IDENT(deprecated); IDENT(__deprecated__); -IDENT(noreturn); IDENT(__noreturn__); -IDENT(regparm); IDENT(__regparm__); -IDENT(weak); IDENT(__weak__); -IDENT(no_instrument_function); IDENT(__no_instrument_function__); -IDENT(sentinel); IDENT(__sentinel__); -IDENT(alias); IDENT(__alias__); -IDENT(pure); IDENT(__pure__); -IDENT(always_inline); IDENT(__always_inline__); -IDENT(syscall_linkage); IDENT(__syscall_linkage__); -IDENT(visibility); IDENT(__visibility__); -IDENT(bitwise); IDENT(__bitwise__); -IDENT(model); IDENT(__model__); -IDENT(format_arg); IDENT(__format_arg__); -IDENT(nothrow); IDENT(__nothrow); IDENT(__nothrow__); -IDENT(__transparent_union__); -IDENT(malloc); -IDENT(__malloc__); -IDENT(nonnull); IDENT(__nonnull); IDENT(__nonnull__); -IDENT(constructor); IDENT(__constructor__); -IDENT(destructor); IDENT(__destructor__); -IDENT(cold); IDENT(__cold__); -IDENT(hot); IDENT(__hot__); -IDENT(cdecl); IDENT(__cdecl__); -IDENT(stdcall); IDENT(__stdcall__); -IDENT(fastcall); IDENT(__fastcall__); -IDENT(dllimport); IDENT(__dllimport__); -IDENT(dllexport); IDENT(__dllexport__); -IDENT(artificial); IDENT(__artificial__); -IDENT(leaf); IDENT(__leaf__); -IDENT(vector_size); IDENT(__vector_size__); -IDENT(error); IDENT(__error__); - - -/* Preprocessor idents. Direct use of __IDENT avoids mentioning the keyword - * itself by name, preventing these tokens from expanding when compiling - * sparse. */ -IDENT(defined); -IDENT(once); -__IDENT(pragma_ident, "__pragma__", 0); -__IDENT(__VA_ARGS___ident, "__VA_ARGS__", 0); -__IDENT(__LINE___ident, "__LINE__", 0); -__IDENT(__FILE___ident, "__FILE__", 0); -__IDENT(__DATE___ident, "__DATE__", 0); -__IDENT(__TIME___ident, "__TIME__", 0); -__IDENT(__func___ident, "__func__", 0); -__IDENT(__FUNCTION___ident, "__FUNCTION__", 0); -__IDENT(__PRETTY_FUNCTION___ident, "__PRETTY_FUNCTION__", 0); -__IDENT(__COUNTER___ident, "__COUNTER__", 0); - -/* Sparse commands */ -IDENT_RESERVED(__context__); -IDENT_RESERVED(__range__); - -/* Magic function names we recognize */ -IDENT(memset); IDENT(memcpy); -IDENT(copy_to_user); IDENT(copy_from_user); -IDENT(main); - -#undef __IDENT -#undef IDENT -#undef IDENT_RESERVED diff --git a/dmr_c/src/inline.c b/dmr_c/src/inline.c deleted file mode 100644 index 6f8b281..0000000 --- a/dmr_c/src/inline.c +++ /dev/null @@ -1,590 +0,0 @@ -/* - * Sparse - a semantic source parser. - * - * Copyright (C) 2003 Transmeta Corp. - * 2003-2004 Linus Torvalds - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - /* - * This version is part of the dmr_c project. - * Copyright (C) 2017 Dibyendu Majumdar - */ - -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -static struct expression * dup_expression(struct dmr_C *C, struct expression *expr) -{ - struct expression *dup = dmrC_alloc_expression(C, expr->pos, expr->type); - *dup = *expr; - return dup; -} - -static struct statement * dup_statement(struct dmr_C *C, struct statement *stmt) -{ - struct statement *dup = dmrC_alloc_statement(C, stmt->pos, stmt->type); - *dup = *stmt; - return dup; -} - -static struct symbol *copy_symbol(struct dmr_C *C, struct position pos, struct symbol *sym) -{ - if (!sym) - return sym; - if (sym->ctype.modifiers & (MOD_STATIC | MOD_EXTERN | MOD_TOPLEVEL | MOD_INLINE)) - return sym; - if (!sym->replace) { - dmrC_warning(C, pos, "unreplaced symbol '%s'", dmrC_show_ident(C, sym->ident)); - return sym; - } - return sym->replace; -} - -static struct symbol_list *copy_symbol_list(struct dmr_C *C, struct symbol_list *src) -{ - struct symbol_list *dst = NULL; - struct symbol *sym; - - FOR_EACH_PTR(src, sym) { - struct symbol *newsym = copy_symbol(C, sym->pos, sym); - dmrC_add_symbol(C, &dst, newsym); - } END_FOR_EACH_PTR(sym); - return dst; -} - -static struct expression * copy_expression(struct dmr_C *C, struct expression *expr) -{ - if (!expr) - return NULL; - - switch (expr->type) { - /* - * EXPR_SYMBOL is the interesting case, we may need to replace the - * symbol to the new copy. - */ - case EXPR_SYMBOL: { - struct symbol *sym = copy_symbol(C, expr->pos, expr->symbol); - if (sym == expr->symbol) - break; - expr = dup_expression(C, expr); - expr->symbol = sym; - break; - } - - /* Atomics, never change, just return the expression directly */ - case EXPR_VALUE: - case EXPR_STRING: - case EXPR_FVALUE: - case EXPR_TYPE: - break; - - /* Unops: check if the subexpression is unique */ - case EXPR_PREOP: - case EXPR_POSTOP: { - struct expression *unop = copy_expression(C, expr->unop); - if (expr->unop == unop) - break; - expr = dup_expression(C, expr); - expr->unop = unop; - break; - } - - case EXPR_SLICE: { - struct expression *base = copy_expression(C, expr->base); - expr = dup_expression(C, expr); - expr->base = base; - break; - } - - /* Binops: copy left/right expressions */ - case EXPR_BINOP: - case EXPR_COMMA: - case EXPR_COMPARE: - case EXPR_LOGICAL: { - struct expression *left = copy_expression(C, expr->left); - struct expression *right = copy_expression(C, expr->right); - if (left == expr->left && right == expr->right) - break; - expr = dup_expression(C, expr); - expr->left = left; - expr->right = right; - break; - } - - case EXPR_ASSIGNMENT: { - struct expression *left = copy_expression(C, expr->left); - struct expression *right = copy_expression(C, expr->right); - if (expr->op == '=' && left == expr->left && right == expr->right) - break; - expr = dup_expression(C, expr); - expr->left = left; - expr->right = right; - break; - } - - /* Dereference */ - case EXPR_DEREF: { - struct expression *deref = copy_expression(C, expr->deref); - expr = dup_expression(C, expr); - expr->deref = deref; - break; - } - - /* Cast/sizeof/__alignof__ */ - case EXPR_CAST: - if (expr->cast_expression->type == EXPR_INITIALIZER) { - struct expression *cast = expr->cast_expression; - struct symbol *sym = expr->cast_type; - expr = dup_expression(C, expr); - expr->cast_expression = copy_expression(C, cast); - expr->cast_type = dmrC_alloc_symbol(C->S, sym->pos, sym->type); - *expr->cast_type = *sym; - break; - } - case EXPR_FORCE_CAST: - case EXPR_IMPLIED_CAST: - case EXPR_SIZEOF: - case EXPR_PTRSIZEOF: - case EXPR_ALIGNOF: { - struct expression *cast = copy_expression(C, expr->cast_expression); - if (cast == expr->cast_expression) - break; - expr = dup_expression(C, expr); - expr->cast_expression = cast; - break; - } - - /* Conditional expression */ - case EXPR_SELECT: - case EXPR_CONDITIONAL: { - struct expression *cond = copy_expression(C, expr->conditional); - struct expression *truee = copy_expression(C, expr->cond_true); - struct expression *falsee = copy_expression(C, expr->cond_false); - if (cond == expr->conditional && truee == expr->cond_true && falsee == expr->cond_false) - break; - expr = dup_expression(C, expr); - expr->conditional = cond; - expr->cond_true = truee; - expr->cond_false = falsee; - break; - } - - /* Statement expression */ - case EXPR_STATEMENT: { - struct statement *stmt = dmrC_alloc_statement(C, expr->pos, STMT_COMPOUND); - dmrC_copy_statement(C, expr->statement, stmt); - expr = dup_expression(C, expr); - expr->statement = stmt; - break; - } - - /* Call expression */ - case EXPR_CALL: { - struct expression *fn = copy_expression(C, expr->fn); - struct expression_list *list = expr->args; - struct expression *arg; - - expr = dup_expression(C, expr); - expr->fn = fn; - expr->args = NULL; - FOR_EACH_PTR(list, arg) { - dmrC_add_expression(C, &expr->args, copy_expression(C, arg)); - } END_FOR_EACH_PTR(arg); - break; - } - - /* Initializer list statement */ - case EXPR_INITIALIZER: { - struct expression_list *list = expr->expr_list; - struct expression *entry; - expr = dup_expression(C, expr); - expr->expr_list = NULL; - FOR_EACH_PTR(list, entry) { - dmrC_add_expression(C, &expr->expr_list, copy_expression(C, entry)); - } END_FOR_EACH_PTR(entry); - break; - } - - /* Label in inline function - hmm. */ - case EXPR_LABEL: { - struct symbol *label_symbol = copy_symbol(C, expr->pos, expr->label_symbol); - expr = dup_expression(C, expr); - expr->label_symbol = label_symbol; - break; - } - - case EXPR_INDEX: { - struct expression *sub_expr = copy_expression(C, expr->idx_expression); - expr = dup_expression(C, expr); - expr->idx_expression = sub_expr; - break; - } - - case EXPR_IDENTIFIER: { - struct expression *sub_expr = copy_expression(C, expr->ident_expression); - expr = dup_expression(C, expr); - expr->ident_expression = sub_expr; - break; - } - - /* Position in initializer.. */ - case EXPR_POS: { - struct expression *val = copy_expression(C, expr->init_expr); - expr = dup_expression(C, expr); - expr->init_expr = val; - break; - } - case EXPR_OFFSETOF: { - struct expression *val = copy_expression(C, expr->down); - if (expr->op == '.') { - if (expr->down != val) { - expr = dup_expression(C, expr); - expr->down = val; - } - } else { - struct expression *idx = copy_expression(C, expr->index); - if (expr->down != val || expr->index != idx) { - expr = dup_expression(C, expr); - expr->down = val; - expr->index = idx; - } - } - break; - } - default: - dmrC_warning(C, expr->pos, "trying to copy expression type %d", expr->type); - } - return expr; -} - -static struct expression_list *copy_asm_constraints(struct dmr_C *C, struct expression_list *in) -{ - struct expression_list *out = NULL; - struct expression *expr; - int state = 0; - - FOR_EACH_PTR(in, expr) { - switch (state) { - case 0: /* identifier */ - case 1: /* constraint */ - state++; - dmrC_add_expression(C, &out, expr); - continue; - case 2: /* expression */ - state = 0; - dmrC_add_expression(C, &out, copy_expression(C, expr)); - continue; - } - } END_FOR_EACH_PTR(expr); - return out; -} - -static void set_replace(struct symbol *old, struct symbol *news) -{ - news->replace = old; - old->replace = news; -} - -static void unset_replace(struct dmr_C *C, struct symbol *sym) -{ - struct symbol *r = sym->replace; - if (!r) { - dmrC_warning(C, sym->pos, "symbol '%s' not replaced?", dmrC_show_ident(C, sym->ident)); - return; - } - r->replace = NULL; - sym->replace = NULL; -} - -static void unset_replace_list(struct dmr_C *C, struct symbol_list *list) -{ - struct symbol *sym; - FOR_EACH_PTR(list, sym) { - unset_replace(C, sym); - } END_FOR_EACH_PTR(sym); -} - -static struct statement *copy_one_statement(struct dmr_C *C, struct statement *stmt) -{ - if (!stmt) - return NULL; - switch(stmt->type) { - case STMT_NONE: - break; - case STMT_DECLARATION: { - struct symbol *sym; - struct statement *newstmt = dup_statement(C, stmt); - newstmt->declaration = NULL; - FOR_EACH_PTR(stmt->declaration, sym) { - struct symbol *newsym = copy_symbol(C, stmt->pos, sym); - if (newsym != sym) - newsym->initializer = copy_expression(C, sym->initializer); - dmrC_add_symbol(C, &newstmt->declaration, newsym); - } END_FOR_EACH_PTR(sym); - stmt = newstmt; - break; - } - case STMT_CONTEXT: - case STMT_EXPRESSION: { - struct expression *expr = copy_expression(C, stmt->expression); - if (expr == stmt->expression) - break; - stmt = dup_statement(C, stmt); - stmt->expression = expr; - break; - } - case STMT_RANGE: { - struct expression *expr = copy_expression(C, stmt->range_expression); - if (expr == stmt->expression) - break; - stmt = dup_statement(C, stmt); - stmt->range_expression = expr; - break; - } - case STMT_COMPOUND: { - struct statement *newst = dmrC_alloc_statement(C, stmt->pos, STMT_COMPOUND); - dmrC_copy_statement(C, stmt, newst); - stmt = newst; - break; - } - case STMT_IF: { - struct expression *cond = stmt->if_conditional; - struct statement *trues = stmt->if_true; - struct statement *falses = stmt->if_false; - - cond = copy_expression(C, cond); - trues = copy_one_statement(C, trues); - falses = copy_one_statement(C, falses); - if (stmt->if_conditional == cond && - stmt->if_true == trues && - stmt->if_false == falses) - break; - stmt = dup_statement(C, stmt); - stmt->if_conditional = cond; - stmt->if_true = trues; - stmt->if_false = falses; - break; - } - case STMT_RETURN: { - struct expression *retval = copy_expression(C, stmt->ret_value); - struct symbol *sym = copy_symbol(C, stmt->pos, stmt->ret_target); - - stmt = dup_statement(C, stmt); - stmt->ret_value = retval; - stmt->ret_target = sym; - break; - } - case STMT_CASE: { - stmt = dup_statement(C, stmt); - stmt->case_label = copy_symbol(C, stmt->pos, stmt->case_label); - stmt->case_label->stmt = stmt; - stmt->case_expression = copy_expression(C, stmt->case_expression); - stmt->case_to = copy_expression(C, stmt->case_to); - stmt->case_statement = copy_one_statement(C, stmt->case_statement); - break; - } - case STMT_SWITCH: { - struct symbol *switch_break = copy_symbol(C, stmt->pos, stmt->switch_break); - struct symbol *switch_case = copy_symbol(C, stmt->pos, stmt->switch_case); - struct expression *expr = copy_expression(C, stmt->switch_expression); - struct statement *switch_stmt = copy_one_statement(C, stmt->switch_statement); - - stmt = dup_statement(C, stmt); - switch_case->symbol_list = copy_symbol_list(C, switch_case->symbol_list); - stmt->switch_break = switch_break; - stmt->switch_case = switch_case; - stmt->switch_expression = expr; - stmt->switch_statement = switch_stmt; - break; - } - case STMT_ITERATOR: { - stmt = dup_statement(C, stmt); - stmt->iterator_break = copy_symbol(C, stmt->pos, stmt->iterator_break); - stmt->iterator_continue = copy_symbol(C, stmt->pos, stmt->iterator_continue); - stmt->iterator_syms = copy_symbol_list(C, stmt->iterator_syms); - - stmt->iterator_pre_statement = copy_one_statement(C, stmt->iterator_pre_statement); - stmt->iterator_pre_condition = copy_expression(C, stmt->iterator_pre_condition); - - stmt->iterator_statement = copy_one_statement(C, stmt->iterator_statement); - - stmt->iterator_post_statement = copy_one_statement(C, stmt->iterator_post_statement); - stmt->iterator_post_condition = copy_expression(C, stmt->iterator_post_condition); - break; - } - case STMT_LABEL: { - stmt = dup_statement(C, stmt); - stmt->label_identifier = copy_symbol(C, stmt->pos, stmt->label_identifier); - stmt->label_statement = copy_one_statement(C, stmt->label_statement); - break; - } - case STMT_GOTO: { - stmt = dup_statement(C, stmt); - stmt->goto_label = copy_symbol(C, stmt->pos, stmt->goto_label); - stmt->goto_expression = copy_expression(C, stmt->goto_expression); - stmt->target_list = copy_symbol_list(C, stmt->target_list); - break; - } - case STMT_ASM: { - stmt = dup_statement(C, stmt); - stmt->asm_inputs = copy_asm_constraints(C, stmt->asm_inputs); - stmt->asm_outputs = copy_asm_constraints(C, stmt->asm_outputs); - /* no need to dup "clobbers", since they are all constant strings */ - break; - } - default: - dmrC_warning(C, stmt->pos, "trying to copy statement type %d", stmt->type); - break; - } - return stmt; -} - -/* - * Copy a statement tree from 'src' to 'dst', where both - * source and destination are of type STMT_COMPOUND. - * - * We do this for the tree-level inliner. - * - * This doesn't do the symbol replacement right: it's not - * re-entrant. - */ -void dmrC_copy_statement(struct dmr_C *C, struct statement *src, struct statement *dst) -{ - struct statement *stmt; - - FOR_EACH_PTR(src->stmts, stmt) { - dmrC_add_statement(C, &dst->stmts, copy_one_statement(C, stmt)); - } END_FOR_EACH_PTR(stmt); - dst->args = copy_one_statement(C, src->args); - dst->ret = copy_symbol(C, src->pos, src->ret); - dst->inline_fn = src->inline_fn; -} - -static struct symbol *create_copy_symbol(struct dmr_C *C, struct symbol *orig) -{ - struct symbol *sym = orig; - if (orig) { - sym = dmrC_alloc_symbol(C->S, orig->pos, orig->type); - *sym = *orig; - sym->bb_target = NULL; - sym->pseudo = NULL; - set_replace(orig, sym); - orig = sym; - } - return orig; -} - -static struct symbol_list *create_symbol_list(struct dmr_C *C, struct symbol_list *src) -{ - struct symbol_list *dst = NULL; - struct symbol *sym; - - FOR_EACH_PTR(src, sym) { - struct symbol *newsym = create_copy_symbol(C, sym); - dmrC_add_symbol(C, &dst, newsym); - } END_FOR_EACH_PTR(sym); - return dst; -} - -int dmrC_inline_function(struct dmr_C *C, struct expression *expr, struct symbol *sym) -{ - struct symbol_list * fn_symbol_list; - struct symbol *fn = sym->ctype.base_type; - struct expression_list *arg_list = expr->args; - struct statement *stmt = dmrC_alloc_statement(C, expr->pos, STMT_COMPOUND); - struct symbol_list *name_list, *arg_decl; - struct symbol *name; - struct expression *arg; - - if (!fn->inline_stmt) { - dmrC_sparse_error(C, fn->pos, "marked inline, but without a definition"); - return 0; - } - if (fn->expanding) - return 0; - - fn->expanding = 1; - - name_list = fn->arguments; - - expr->type = EXPR_STATEMENT; - expr->statement = stmt; - expr->ctype = fn->ctype.base_type; - - fn_symbol_list = create_symbol_list(C, sym->inline_symbol_list); - - arg_decl = NULL; - PREPARE_PTR_LIST(name_list, name); - FOR_EACH_PTR(arg_list, arg) { - struct symbol *a = dmrC_alloc_symbol(C->S, arg->pos, SYM_NODE); - - a->ctype.base_type = arg->ctype; - if (name) { - *a = *name; - set_replace(name, a); - dmrC_add_symbol(C, &fn_symbol_list, a); - } - a->initializer = arg; - dmrC_add_symbol(C, &arg_decl, a); - - NEXT_PTR_LIST(name); - } END_FOR_EACH_PTR(arg); - FINISH_PTR_LIST(name); - - dmrC_copy_statement(C, fn->inline_stmt, stmt); - - if (arg_decl) { - struct statement *decl = dmrC_alloc_statement(C, expr->pos, STMT_DECLARATION); - decl->declaration = arg_decl; - stmt->args = decl; - } - stmt->inline_fn = sym; - - unset_replace_list(C, fn_symbol_list); - - dmrC_evaluate_statement(C, stmt); - - fn->expanding = 0; - return 1; -} - -void dmrC_uninline(struct dmr_C *C, struct symbol *sym) -{ - struct symbol *fn = sym->ctype.base_type; - struct symbol_list *arg_list = fn->arguments; - struct symbol *p; - - sym->symbol_list = create_symbol_list(C, sym->inline_symbol_list); - FOR_EACH_PTR(arg_list, p) { - p->replace = p; - } END_FOR_EACH_PTR(p); - fn->stmt = dmrC_alloc_statement(C, fn->pos, STMT_COMPOUND); - dmrC_copy_statement(C, fn->inline_stmt, fn->stmt); - unset_replace_list(C, sym->symbol_list); - unset_replace_list(C, arg_list); -} diff --git a/dmr_c/src/lib.c b/dmr_c/src/lib.c deleted file mode 100644 index f36a33c..0000000 --- a/dmr_c/src/lib.c +++ /dev/null @@ -1,1493 +0,0 @@ -/* -* 'sparse' library helper routines. -* -* Copyright (C) 2003 Transmeta Corp. -* 2003-2004 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define SPARSE_VERSION "0.5" -#ifndef __GNUC__ -# define __GNUC__ 2 -# define __GNUC_MINOR__ 95 -# define __GNUC_PATCHLEVEL__ 0 -#endif - -int gcc_major = __GNUC__; -int gcc_minor = __GNUC_MINOR__; -int gcc_patchlevel = __GNUC_PATCHLEVEL__; - -long double dmrC_string_to_ld(const char *nptr, char **endptr) -{ - return strtod(nptr, endptr); -} - -struct token *dmrC_skip_to_token(struct token *token, int op) -{ - while (!dmrC_match_op(token, op) && !dmrC_eof_token(token)) - token = token->next; - return token; -} - -struct token *dmrC_expect_token(struct dmr_C *C, struct token *token, int op, const char *where) -{ - if (!dmrC_match_op(token, op)) { - static struct token bad_token; - if (token != &bad_token) { - bad_token.next = token; - dmrC_sparse_error(C, token->pos, "Expected %s %s", dmrC_show_special(C, op), where); - dmrC_sparse_error(C, token->pos, "got %s", dmrC_show_token(C, token)); - } - if (op == ';') - return dmrC_skip_to_token(token, op); - return &bad_token; - } - return token->next; -} - -unsigned int dmrC_hexval(unsigned int c) -{ - int retval = 256; - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - retval = c - '0'; - break; - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - retval = c - 'a' + 10; - break; - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - retval = c - 'A' + 10; - break; - } - return retval; -} - -static void do_warn(struct dmr_C *C, const char *type, struct position pos, - const char *fmt, va_list args) -{ - static char buffer[512]; - const char *name; - - vsprintf(buffer, fmt, args); - name = dmrC_stream_name(C, pos.stream); - - fprintf(stderr, "%s:%d:%d: %s%s\n", name, pos.line, pos.pos, type, - buffer); -} - -void dmrC_info(struct dmr_C *C, struct position pos, const char *fmt, ...) -{ - va_list args; - - if (!C->show_info) - return; - va_start(args, fmt); - do_warn(C, "", pos, fmt, args); - va_end(args); -} - -static void do_error(struct dmr_C *C, struct position pos, const char *fmt, - va_list args) -{ - C->die_if_error = 1; - C->show_info = 1; - /* Shut up warnings after an error */ - C->has_error |= ERROR_CURR_PHASE; - C->max_warnings = 0; - if (C->errors > 100) { - C->show_info = 0; - if (C->once) - return; - fmt = "too many errors"; - C->once = 1; - } - - do_warn(C, "error: ", pos, fmt, args); - C->errors++; -} - - -void dmrC_warning(struct dmr_C *C, struct position pos, const char *fmt, ...) -{ - va_list args; - - if (C->Wsparse_error) { - va_start(args, fmt); - do_error(C, pos, fmt, args); - va_end(args); - return; - } - if (!C->max_warnings || C->has_error) { - C->show_info = 0; - return; - } - - if (!--C->max_warnings) { - C->show_info = 0; - fmt = "too many warnings"; - } - - va_start(args, fmt); - do_warn(C, "warning: ", pos, fmt, args); - va_end(args); -} - - -void dmrC_sparse_error(struct dmr_C *C, struct position pos, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - do_error(C, pos, fmt, args); - va_end(args); -} - -void dmrC_expression_error(struct dmr_C *C, struct expression *expr, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - do_error(C, expr->pos, fmt, args); - va_end(args); - expr->ctype = &C->S->bad_ctype; -} - -void dmrC_error_die(struct dmr_C *C, struct position pos, const char *fmt, ...) -{ - va_list args; - va_start(args, fmt); - do_warn(C, "error: ", pos, fmt, args); - va_end(args); - longjmp(C->jmpbuf, 1); -} - -void dmrC_die(struct dmr_C *C, const char *fmt, ...) -{ - va_list args; - static char buffer[512]; - - (void)C; - va_start(args, fmt); - vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); - - fprintf(stderr, "%s\n", buffer); - longjmp(C->jmpbuf, 1); -} - -#define ARCH_LP32 0 -#define ARCH_LP64 1 -#define ARCH_LLP64 2 - -#if _WIN32 || _WIN64 -#if _WIN64 -#define ARCH_M64_DEFAULT ARCH_LLP64 -#else -#define ARCH_M64_DEFAULT ARCH_LP32 -#endif -#elif __GNUC__ -#ifdef __x86_64__ -#define ARCH_M64_DEFAULT ARCH_LP64 -#else -#define ARCH_M64_DEFAULT ARCH_LP32 -#endif -#else -#error Unsupported compiler -#endif - -#ifdef __BIG_ENDIAN__ -#define ARCH_BIG_ENDIAN 1 -#else -#define ARCH_BIG_ENDIAN 0 -#endif - -#define xstr(s) str(s) -#define str(s) #s - -struct dmr_C *new_dmr_C() -{ - struct dmr_C *C = (struct dmr_C *)calloc(1, sizeof(struct dmr_C)); - C->standard = STANDARD_GNU89; - C->arch_m64 = ARCH_M64_DEFAULT; - C->arch_msize_long = 0; - C->arch_big_endian = ARCH_BIG_ENDIAN; -#ifdef GCC_BASE - C->gcc_base_dir = xstr(GCC_BASE); -#else - C->gcc_base_dir = NULL; -#endif -#ifdef MULTIARCH_TRIPLET - C->multiarch_dir = xstr(MULTIARCH_TRIPLET); -#else - C->multiarch_dir = NULL; -#endif - - C->Waddress_space = 1; - C->Wcast_truncate = 1; - C->Wcontext = 1; - C->Wdecl = 1; - C->Wdeclarationafterstatement = -1; - C->Wdesignated_init = 1; - C->Wenum_mismatch = 1; - C->Wnon_pointer_null = 1; - C->Wold_initializer = 1; - C->Wone_bit_signed_bitfield = 1; - C->Wuninitialized = 1; - C->Wunknown_attribute = 1; - C->Wvla = 1; - C->Woverride_init = 1; - C->Wbitwise = 1; - C->Wmemcpy_max_count = 1; - - C->max_warnings = 100; - C->show_info = 1; - C->fmemcpy_max_count = 100000; - - dmrC_allocator_init(&C->ptrlist_allocator, "ptrlist_nodes", sizeof(struct ptr_list), - __alignof__(struct ptr_list), CHUNK); - dmrC_allocator_init(&C->byte_allocator, "bytes", sizeof(char), - __alignof__(char), CHUNK); - dmrC_allocator_init(&C->ident_allocator, "identifiers", sizeof(struct ident), - __alignof__(struct ident), CHUNK); - dmrC_allocator_init(&C->string_allocator, "strings", sizeof(struct string), - __alignof__(struct string), CHUNK); - dmrC_allocator_init(&C->token_allocator, "tokens", sizeof(struct token), - __alignof__(struct token), CHUNK); - dmrC_allocator_init(&C->scope_allocator, "scopes", sizeof(struct scope), - __alignof__(struct scope), CHUNK); - dmrC_allocator_init(&C->expression_allocator, "expressions", sizeof(struct expression), - __alignof__(struct expression), CHUNK); - dmrC_allocator_init(&C->statement_allocator, "statements", sizeof(struct statement), - __alignof__(struct statement), CHUNK); - - C->warnings[0].name = "address-space"; C->warnings[0].flag = &C->Waddress_space; - C->warnings[1].name = "bitwise"; C->warnings[1].flag = &C->Wbitwise; - C->warnings[2].name = "cast-to-as"; C->warnings[2].flag = &C->Wcast_to_as; - C->warnings[3].name = "cast-truncate"; C->warnings[3].flag = &C->Wcast_truncate; - C->warnings[4].name = "context"; C->warnings[4].flag = &C->Wcontext; - C->warnings[5].name = "decl"; C->warnings[5].flag = &C->Wdecl; - C->warnings[6].name = "declaration-after-statement"; C->warnings[6].flag = &C->Wdeclarationafterstatement; - C->warnings[7].name = "default-bitfield-sign"; C->warnings[7].flag = &C->Wdefault_bitfield_sign; - C->warnings[8].name = "designated-init"; C->warnings[8].flag = &C->Wdesignated_init; - C->warnings[9].name = "do-while"; C->warnings[9].flag = &C->Wdo_while; - C->warnings[10].name = "enum-mismatch"; C->warnings[10].flag = &C->Wenum_mismatch; - C->warnings[11].name = "sparse-error"; C->warnings[11].flag = &C->Wsparse_error; - C->warnings[12].name = "init-cstring"; C->warnings[12].flag = &C->Winit_cstring; - C->warnings[13].name = "non-pointer-null"; C->warnings[13].flag = &C->Wnon_pointer_null; - C->warnings[14].name = "old-initializer"; C->warnings[14].flag = &C->Wold_initializer; - C->warnings[15].name = "one-bit-signed-bitfield"; C->warnings[15].flag = &C->Wone_bit_signed_bitfield; - C->warnings[16].name = "paren-string"; C->warnings[16].flag = &C->Wparen_string; - C->warnings[17].name = "ptr-subtraction-blows"; C->warnings[17].flag = &C->Wptr_subtraction_blows; - C->warnings[18].name = "return-void"; C->warnings[18].flag = &C->Wreturn_void; - C->warnings[19].name = "shadow"; C->warnings[19].flag = &C->Wshadow; - C->warnings[20].name = "sizeof-bool"; C->warnings[20].flag = &C->Wsizeof_bool; - C->warnings[21].name = "tautological-compare"; C->warnings[21].flag = &C->Wtautological_compare; - C->warnings[22].name = "transparent-union"; C->warnings[22].flag = &C->Wtransparent_union; - C->warnings[23].name = "typesign"; C->warnings[23].flag = &C->Wtypesign; - C->warnings[24].name = "undef"; C->warnings[24].flag = &C->Wundef; - C->warnings[25].name = "uninitialized"; C->warnings[25].flag = &C->Wuninitialized; - C->warnings[26].name = "unknown-attribute"; C->warnings[26].flag = &C->Wunknown_attribute; - C->warnings[27].name = "vla"; C->warnings[27].flag = &C->Wvla; - C->warnings[28].name = "address"; C->warnings[28].flag = &C->Waddress; - C->warnings[29].name = "memcpy-max-count"; C->warnings[29].flag = &C->Wmemcpy_max_count; - C->warnings[30].name = "override-init"; C->warnings[30].flag = &C->Woverride_init; - C->warnings[31].name = "override-init-all"; C->warnings[31].flag = &C->Woverride_init_all; - - C->debugs[0].name = "entry"; C->debugs[0].flag = &C->dbg_entry; - C->debugs[1].name = "dead"; C->debugs[1].flag = &C->dbg_dead; - - C->dumps[0].name = "D"; C->dumps[0].flag = &C->dump_macro_defs; - - dmrC_init_target(C); - dmrC_init_tokenizer(C); - dmrC_init_preprocessor_state(C); - dmrC_init_scope(C); - dmrC_init_symbols(C); - dmrC_init_ctype(C); -#if !defined(PARSER_ONLY) - dmrC_init_linearizer(C); -#endif - return C; -} - -void destroy_dmr_C(struct dmr_C *C) -{ - dmrC_destroy_all_scopes(C); - dmrC_destroy_tokenizer(C); - dmrC_destroy_target(C); - dmrC_destroy_symbols(C); -#if !defined(PARSER_ONLY) - dmrC_destroy_linearizer(C); -#endif - dmrC_allocator_destroy(&C->token_allocator); - dmrC_allocator_destroy(&C->protected_token_allocator); - dmrC_allocator_destroy(&C->string_allocator); - dmrC_allocator_destroy(&C->ident_allocator); - dmrC_allocator_destroy(&C->byte_allocator); - dmrC_allocator_destroy(&C->scope_allocator); - dmrC_allocator_destroy(&C->expression_allocator); - dmrC_allocator_destroy(&C->statement_allocator); - dmrC_allocator_destroy(&C->ptrlist_allocator); - free(C); -} - -void dmrC_add_pre_buffer(struct dmr_C *C, const char *fmt, ...) -{ - va_list args; - unsigned int size; - struct token *begin, *end; - char buffer[4096]; - - va_start(args, fmt); - size = vsnprintf(buffer, sizeof(buffer), fmt, args); - va_end(args); - begin = dmrC_tokenize_buffer(C, (unsigned char *)buffer, size, &end); - if (!C->pre_buffer_begin) - C->pre_buffer_begin = begin; - if (C->pre_buffer_end) - C->pre_buffer_end->next = begin; - C->pre_buffer_end = end; -} - -static char **handle_switch_D(struct dmr_C *C, char *arg, char **next) -{ - const char *name = arg + 1; - const char *value = "1"; - - if (!*name || isspace((unsigned char)*name)) - dmrC_die(C, "argument to `-D' is missing"); - - for (;;) { - char c; - c = *++arg; - if (!c) - break; - if (isspace((unsigned char)c) || c == '=') { - *arg = '\0'; - value = arg + 1; - break; - } - } - dmrC_add_pre_buffer(C, "#define %s %s\n", name, value); - return next; -} - -static char **handle_switch_E(struct dmr_C *C, char *arg, char **next) -{ - if (arg[1] == '\0') - C->preprocess_only = 1; - return next; -} - -static char **handle_switch_I(struct dmr_C *C, char *arg, char **next) -{ - char *path = arg + 1; - - switch (arg[1]) { - case '-': - dmrC_add_pre_buffer(C, "#split_include\n"); - break; - - case '\0': /* Plain "-I" */ - path = *++next; - if (!path) - dmrC_die(C, "missing argument for -I option"); - /* Fall through */ - default: - dmrC_add_pre_buffer(C, "#add_include \"%s/\"\n", path); - } - return next; -} - -static void add_cmdline_include(struct dmr_C *C, char *filename) -{ - if (C->cmdline_include_nr >= CMDLINE_INCLUDE) - dmrC_die(C, "too many include files for %s\n", filename); - C->cmdline_include[C->cmdline_include_nr++] = filename; -} - -static char **handle_switch_i(struct dmr_C *C, char *arg, char **next) -{ - if (*next && !strcmp(arg, "include")) - add_cmdline_include(C, *++next); - else if (*next && !strcmp(arg, "imacros")) - add_cmdline_include(C, *++next); - else if (*next && !strcmp(arg, "isystem")) { - char *path = *++next; - if (!path) - dmrC_die(C, "missing argument for -isystem option"); - dmrC_add_pre_buffer(C, "#add_isystem \"%s/\"\n", path); - } - else if (*next && !strcmp(arg, "idirafter")) { - char *path = *++next; - if (!path) - dmrC_die(C, "missing argument for -idirafter option"); - dmrC_add_pre_buffer(C, "#add_dirafter \"%s/\"\n", path); - } - return next; -} - -static char **handle_switch_M(struct dmr_C *C, char *arg, char **next) -{ - if (!strcmp(arg, "MF") || !strcmp(arg, "MQ") || !strcmp(arg, "MT")) { - if (!*next) - dmrC_die(C, "missing argument for -%s option", arg); - return next + 1; - } - return next; -} - -static char **handle_multiarch_dir(struct dmr_C *C, char *arg, char **next) -{ - (void)arg; - C->multiarch_dir = *++next; - if (!C->multiarch_dir) - dmrC_die(C, "missing argument for -multiarch-dir option"); - return next; -} -static char **handle_switch_m(struct dmr_C *C, char *arg, char **next) -{ - if (!strcmp(arg, "m64")) { - C->arch_m64 = ARCH_LP64; - } else if (!strcmp(arg, "m32")) { - C->arch_m64 = ARCH_LP32; - } else if (!strcmp(arg, "msize-llp64")) { - C->arch_m64 = ARCH_LLP64; - } else if (!strcmp(arg, "msize-long")) { - C->arch_msize_long = 1; - } else if (!strcmp(arg, "multiarch-dir")) { - return handle_multiarch_dir(C, arg, next); - } else if (!strcmp(arg, "mbig-endian")) { - C->arch_big_endian = 1; - } else if (!strcmp(arg, "mlittle-endian")) { - C->arch_big_endian = 0; - } - return next; -} - -static void handle_arch_m64_finalize(struct dmr_C *C) -{ - switch (C->arch_m64) { - case ARCH_LP32: - C->target->bits_in_long = 32; - C->target->max_int_alignment = 4; - C->target->bits_in_pointer = 32; - C->target->pointer_alignment = 4; - break; - case ARCH_LP64: - C->target->bits_in_long = 64; - C->target->max_int_alignment = 8; - C->target->size_t_ctype = &C->S->ulong_ctype; - C->target->ssize_t_ctype = &C->S->long_ctype; - dmrC_add_pre_buffer(C, "#weak_define __LP64__ 1\n"); - dmrC_add_pre_buffer(C, "#weak_define _LP64 1\n"); - goto case_64bit_common; - case ARCH_LLP64: - C->target->bits_in_long = 32; - C->target->max_int_alignment = 4; - C->target->size_t_ctype = &C->S->ullong_ctype; - C->target->ssize_t_ctype = &C->S->llong_ctype; - dmrC_add_pre_buffer(C, "#weak_define __LLP64__ 1\n"); - goto case_64bit_common; - case_64bit_common: - C->target->bits_in_pointer = 64; - C->target->pointer_alignment = 8; -#ifdef __x86_64__ - dmrC_add_pre_buffer(C, "#weak_define __x86_64__ 1\n"); -#endif - break; - } -} - -static void handle_arch_msize_long_finalize(struct dmr_C *C) -{ - if (C->arch_msize_long) { - C->target->size_t_ctype = &C->S->ulong_ctype; - C->target->ssize_t_ctype = &C->S->long_ctype; - } -} - -static void handle_arch_finalize(struct dmr_C *C) -{ - handle_arch_m64_finalize(C); - handle_arch_msize_long_finalize(C); -} - - -static int handle_simple_switch(const char *arg, const char *name, int *flag) -{ - int val = 1; - - // Prefixe "no-" mean to turn flag off. - if (strncmp(arg, "no-", 3) == 0) { - arg += 3; - val = 0; - } - - if (strcmp(arg, name) == 0) { - *flag = val; - return 1; - } - - // not handled - return 0; -} - -static char **handle_switch_o(struct dmr_C *C, char *arg, char **next) -{ - if (!strcmp(arg, "o")) { // "-o foo" - if (!*++next) - dmrC_die(C, "argument to '-o' is missing"); - } - snprintf(C->output_file_name, sizeof C->output_file_name, "%s", *next); - return next; -} - - -static char **handle_onoff_switch(struct dmr_C *C, char *arg, char **next, const struct warning warnings[], int n) -{ - int flag = WARNING_ON; - char *p = arg + 1; - int i; - - if (strcmp(p, "sparse-all") == 0) { - for (i = 0; i < n; i++) { - if (*warnings[i].flag != WARNING_FORCE_OFF && warnings[i].flag != &C->Wsparse_error) - *warnings[i].flag = WARNING_ON; - } - } - - // Prefixes "no" and "no-" mean to turn warning off. - if (p[0] == 'n' && p[1] == 'o') { - p += 2; - if (p[0] == '-') - p++; - flag = WARNING_FORCE_OFF; - } - - for (i = 0; i < n; i++) { - if (!strcmp(p, warnings[i].name)) { - *warnings[i].flag = flag; - return next; - } - } - - // Unknown. - return NULL; -} - -static char **handle_switch_W(struct dmr_C *C, char *arg, char **next) -{ - char ** ret = handle_onoff_switch(C, arg, next, C->warnings, 32); - if (ret) - return ret; - - // Unknown. - return next; -} - -static char **handle_switch_v(struct dmr_C *C, char *arg, char **next) -{ - char ** ret = handle_onoff_switch(C, arg, next, C->debugs, 2); - if (ret) - return ret; - - // Unknown. - do { - C->verbose++; - } while (*++arg == 'v'); - return next; -} - -static char **handle_switch_d(struct dmr_C *C, char *arg, char **next) -{ - char ** ret = handle_onoff_switch(C, arg, next, C->dumps, 1); - if (ret) - return ret; - - return next; -} - - -static void handle_onoff_switch_finalize(const struct warning warnings[], int n) -{ - int i; - - for (i = 0; i < n; i++) { - if (*warnings[i].flag == WARNING_FORCE_OFF) - *warnings[i].flag = WARNING_OFF; - } -} - -static void handle_switch_W_finalize(struct dmr_C *C) -{ - handle_onoff_switch_finalize(C->warnings, 32); - - /* default Wdeclarationafterstatement based on the C dialect */ - if (-1 == C->Wdeclarationafterstatement) - { - switch (C->standard) - { - case STANDARD_C89: - case STANDARD_C94: - C->Wdeclarationafterstatement = 1; - break; - - case STANDARD_C99: - case STANDARD_GNU89: - case STANDARD_GNU99: - case STANDARD_C11: - case STANDARD_GNU11: - C->Wdeclarationafterstatement = 0; - break; - - default: - assert(0); - } - - } -} - -static void handle_switch_v_finalize(struct dmr_C *C) -{ - handle_onoff_switch_finalize(C->debugs, 2); -} - -static char **handle_switch_U(struct dmr_C *C, char *arg, char **next) -{ - const char *name = arg + 1; - dmrC_add_pre_buffer(C, "#undef %s\n", name); - return next; -} - -static char **handle_switch_O(struct dmr_C *C, char *arg, char **next) -{ - int level = 1; - if (arg[1] >= '0' && arg[1] <= '9') - level = arg[1] - '0'; - C->optimize = level; - C->optimize_size = arg[1] == 's'; - return next; -} - -static char **handle_switch_fmemcpy_max_count(struct dmr_C *C, char *arg, char **next) -{ - unsigned long long val; - char *end; - - val = strtoull(arg, &end, 0); - if (*end != '\0' || end == arg) - dmrC_die(C, "error: missing argument to \"-fmemcpy-max-count=\""); - - if (val == 0) - val = ~0ULL; - C->fmemcpy_max_count = val; - return next; -} - -static char **handle_switch_ftabstop(struct dmr_C *C, char *arg, char **next) -{ - char *end; - unsigned long val; - - if (*arg == '\0') - dmrC_die(C, "error: missing argument to \"-ftabstop=\""); - - /* we silently ignore silly values */ - val = strtoul(arg, &end, 10); - if (*end == '\0' && 1 <= val && val <= 100) - C->T->tabstop = val; - - return next; -} - -static char **handle_switch_fdump(struct dmr_C *C, char *arg, char **next) -{ - if (!strncmp(arg, "linearize", 9)) { - arg += 9; - if (*arg == '\0') - C->fdump_linearize = 1; - else if (!strcmp(arg, "=only")) - C->fdump_linearize = 2; - } - - /* ignore others flags */ - return next; -} - -static char **handle_switch_f(struct dmr_C *C, char *arg, char **next) -{ - arg++; - - if (!strncmp(arg, "tabstop=", 8)) - return handle_switch_ftabstop(C, arg + 8, next); - if (!strncmp(arg, "dump-", 5)) - return handle_switch_fdump(C, arg + 5, next); - if (!strncmp(arg, "memcpy-max-count=", 17)) - return handle_switch_fmemcpy_max_count(C, arg + 17, next); - - /* handle switches w/ arguments above, boolean and only boolean below */ - if (handle_simple_switch(arg, "mem-report", &C->fmem_report)) - return next; - - return next; -} - -static char **handle_switch_G(struct dmr_C *C, char *arg, char **next) -{ - (void) C; - if (!strcmp(arg, "G") && *next) - return next + 1; // "-G 0" - else - return next; // "-G0" or (bogus) terminal "-G" -} - -static char **handle_switch_a(struct dmr_C *C, char *arg, char **next) -{ - if (!strcmp(arg, "ansi")) - C->standard = STANDARD_C89; - - return next; -} - -static char **handle_switch_s(struct dmr_C *C, char *arg, char **next) -{ - if (!strncmp(arg, "std=", 4)) - { - arg += 4; - - if (!strcmp(arg, "c89") || - !strcmp(arg, "iso9899:1990")) - C->standard = STANDARD_C89; - - else if (!strcmp(arg, "iso9899:199409")) - C->standard = STANDARD_C94; - - else if (!strcmp(arg, "c99") || - !strcmp(arg, "c9x") || - !strcmp(arg, "iso9899:1999") || - !strcmp(arg, "iso9899:199x")) - C->standard = STANDARD_C99; - - else if (!strcmp(arg, "gnu89")) - C->standard = STANDARD_GNU89; - - else if (!strcmp(arg, "gnu99") || !strcmp(arg, "gnu9x")) - C->standard = STANDARD_GNU99; - - else if (!strcmp(arg, "c11") || - !strcmp(arg, "c1x") || - !strcmp(arg, "iso9899:2011")) - C->standard = STANDARD_C11; - - else if (!strcmp(arg, "gnu11")) - C->standard = STANDARD_GNU11; - - else - dmrC_die(C, "Unsupported C dialect"); - } - - return next; -} - -static char **handle_nostdinc(struct dmr_C *C, char *arg, char **next) -{ - (void)arg; - dmrC_add_pre_buffer(C, "#nostdinc\n"); - return next; -} - -static char **handle_switch_n(struct dmr_C *C, char *arg, char **next) -{ - if (!strcmp (arg, "nostdinc")) - return handle_nostdinc(C, arg, next); - - return next; -} -static char **handle_base_dir(struct dmr_C *C, char *arg, char **next) -{ - (void)arg; - C->gcc_base_dir = *++next; - if (!C->gcc_base_dir) - dmrC_die(C, "missing argument for -gcc-base-dir option"); - return next; -} - -static char **handle_switch_g(struct dmr_C *C, char *arg, char **next) -{ - if (!strcmp (arg, "gcc-base-dir")) - return handle_base_dir(C, arg, next); - - return next; -} -static char **handle_version(struct dmr_C *C, char *arg, char **next) -{ - (void)C; - (void)arg; - (void)next; - printf("%s\n", SPARSE_VERSION); - exit(0); -} - -static char **handle_param(struct dmr_C *C, char *arg, char **next) -{ - char *value = NULL; - - /* For now just skip any '--param=*' or '--param *' */ - if (*arg == '\0') { - value = *++next; - } else if (isspace((unsigned char)*arg) || *arg == '=') { - value = ++arg; - } - - if (!value) - dmrC_die(C, "missing argument for --param option"); - - return next; -} -struct switches { - const char *name; - char **(*fn)(struct dmr_C *, char *, char **); - unsigned int prefix:1; -}; - -static char **handle_long_options(struct dmr_C *C, char *arg, char **next) -{ - static struct switches cmd[] = { - { "param", handle_param, 1 }, - { "version", handle_version , 0}, - { NULL, NULL, 0 } - }; - struct switches *s = cmd; - - while (s->name) { - int optlen = (int) strlen(s->name); - if (!strncmp(s->name, arg, optlen + !s->prefix)) - return s->fn(C, arg + optlen, next); - s++; - } - return next; - -} - -static char **handle_switch(struct dmr_C *C, char *arg, char **next) -{ - switch (*arg) { - case 'a': return handle_switch_a(C, arg, next); - case 'D': return handle_switch_D(C, arg, next); - case 'd': return handle_switch_d(C, arg, next); - case 'E': return handle_switch_E(C, arg, next); - case 'f': return handle_switch_f(C, arg, next); - case 'g': return handle_switch_g(C, arg, next); - case 'G': return handle_switch_G(C, arg, next); - case 'I': return handle_switch_I(C, arg, next); - case 'i': return handle_switch_i(C, arg, next); - case 'M': return handle_switch_M(C, arg, next); - case 'm': return handle_switch_m(C, arg, next); - case 'n': return handle_switch_n(C, arg, next); - case 'o': return handle_switch_o(C, arg, next); - case 'O': return handle_switch_O(C, arg, next); - case 's': return handle_switch_s(C, arg, next); - case 'U': return handle_switch_U(C, arg, next); - case 'v': return handle_switch_v(C, arg, next); - case 'W': return handle_switch_W(C, arg, next); - case '-': return handle_long_options(C, arg + 1, next); - - default: - break; - } - - /* - * Ignore unknown command line options: - * they're probably gcc switches - */ - return next; -} - -static void predefined_sizeof(struct dmr_C *C, const char *name, unsigned bits) -{ - dmrC_add_pre_buffer(C, "#weak_define __SIZEOF_%s__ %d\n", name, bits/8); -} - -static void predefined_max(struct dmr_C *C, const char *name, const char *suffix, unsigned bits) -{ - unsigned long long max = (1ULL << (bits - 1)) - 1; - - dmrC_add_pre_buffer(C, "#weak_define __%s_MAX__ %#llx%s\n", name, max, suffix); -} - -static void predefined_type_size(struct dmr_C *C, const char *name, const char *suffix, unsigned bits) -{ - predefined_max(C, name, suffix, bits); - - predefined_sizeof(C, name, bits); -} - -static void predefined_macros(struct dmr_C *C) -{ -#if LLVM_JIT - dmrC_add_pre_buffer(C, "#define __LLVM_BACKEND__ 1\n"); -#elif NANO_JIT - dmrC_add_pre_buffer(C, "#define __NANOJIT_BACKEND__ 1\n"); -#elif OMR_JIT - dmrC_add_pre_buffer(C, "#define __OMR_BACKEND__ 1\n"); -#endif - dmrC_add_pre_buffer(C, "#define __CHECKER__ 1\n"); - - predefined_sizeof(C, "SHORT", C->target->bits_in_short); - predefined_max(C, "SHRT", "", C->target->bits_in_short); - predefined_max(C, "SCHAR", "", C->target->bits_in_char); - predefined_max(C, "WCHAR", "", C->target->bits_in_wchar); - dmrC_add_pre_buffer(C, "#weak_define __CHAR_BIT__ %d\n", C->target->bits_in_char); - - predefined_type_size(C, "INT", "", C->target->bits_in_int); - predefined_type_size(C, "LONG", "L", C->target->bits_in_long); - predefined_type_size(C, "LONG_LONG", "LL", C->target->bits_in_longlong); - - predefined_sizeof(C, "INT128", 128); - - predefined_sizeof(C, "SIZE_T", C->target->bits_in_pointer); - predefined_sizeof(C, "PTRDIFF_T", C->target->bits_in_pointer); - predefined_sizeof(C, "POINTER", C->target->bits_in_pointer); - - predefined_sizeof(C, "FLOAT", C->target->bits_in_float); - predefined_sizeof(C, "DOUBLE", C->target->bits_in_double); - predefined_sizeof(C, "LONG_DOUBLE", C->target->bits_in_longdouble); - dmrC_add_pre_buffer(C, "#weak_define __%s_ENDIAN__ 1\n", - C->arch_big_endian ? "BIG" : "LITTLE"); - - dmrC_add_pre_buffer(C, "#weak_define __ORDER_LITTLE_ENDIAN__ 1234\n"); - dmrC_add_pre_buffer(C, "#weak_define __ORDER_BIG_ENDIAN__ 4321\n"); - dmrC_add_pre_buffer(C, "#weak_define __ORDER_PDP_ENDIAN__ 3412\n"); - dmrC_add_pre_buffer(C, "#weak_define __BYTE_ORDER__ __ORDER_%s_ENDIAN__\n", - C->arch_big_endian ? "BIG" : "LITTLE"); -} - -void dmrC_declare_builtin_functions(struct dmr_C *C) -{ - /* Gaah. gcc knows tons of builtin functions */ - dmrC_add_pre_buffer(C, "extern void *__builtin_memchr(const void *, int, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void *__builtin_memcpy(void *, const void *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void *__builtin_mempcpy(void *, const void *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void *__builtin_memmove(void *, const void *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void *__builtin_memset(void *, int, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_memcmp(const void *, const void *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strcat(char *, const char *);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strncat(char *, const char *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_strcmp(const char *, const char *);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_strncmp(const char *, const char *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_strcasecmp(const char *, const char *);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_strncasecmp(const char *, const char *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strchr(const char *, int);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strrchr(const char *, int);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strcpy(char *, const char *);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strncpy(char *, const char *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strdup(const char *);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strndup(const char *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern __SIZE_TYPE__ __builtin_strspn(const char *, const char *);\n"); - dmrC_add_pre_buffer(C, "extern __SIZE_TYPE__ __builtin_strcspn(const char *, const char *);\n"); - dmrC_add_pre_buffer(C, "extern char * __builtin_strpbrk(const char *, const char *);\n"); - dmrC_add_pre_buffer(C, "extern char* __builtin_stpcpy(const char *, const char*);\n"); - dmrC_add_pre_buffer(C, "extern char* __builtin_stpncpy(const char *, const char*, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern __SIZE_TYPE__ __builtin_strlen(const char *);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strstr(const char *, const char *);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strcasestr(const char *, const char *);\n"); - dmrC_add_pre_buffer(C, "extern char *__builtin_strnstr(const char *, const char *, __SIZE_TYPE__);\n"); - - /* And even some from */ - dmrC_add_pre_buffer(C, "extern int __builtin_bcmp(const void *, const void *, __SIZE_TYPE_);\n"); - dmrC_add_pre_buffer(C, "extern void __builtin_bcopy(const void *, void *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void __builtin_bzero(void *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern char*__builtin_index(const char *, int);\n"); - dmrC_add_pre_buffer(C, "extern char*__builtin_rindex(const char *, int);\n"); - - /* And bitwise operations.. */ - dmrC_add_pre_buffer(C, "extern int __builtin_clrsb(int);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_clrsbl(long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_clrsbll(long long);\n"); - - /* And bitwise operations.. */ - dmrC_add_pre_buffer(C, "extern int __builtin_clz(int);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_clzl(long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_clzll(long long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_ctz(int);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_ctzl(long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_ctzll(long long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_ffs(int);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_ffsl(long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_ffsll(long long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_parity(unsigned int);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_parityl(unsigned long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_parityll(unsigned long long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_popcount(unsigned int);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_popcountl(unsigned long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_popcountll(unsigned long long);\n"); - - /* And byte swaps.. */ - dmrC_add_pre_buffer(C, "extern unsigned short __builtin_bswap16(unsigned short);\n"); - dmrC_add_pre_buffer(C, "extern unsigned int __builtin_bswap32(unsigned int);\n"); - dmrC_add_pre_buffer(C, "extern unsigned long long __builtin_bswap64(unsigned long long);\n"); - - /* And atomic memory access functions.. */ - dmrC_add_pre_buffer(C, "extern int __sync_fetch_and_add(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_fetch_and_sub(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_fetch_and_or(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_fetch_and_and(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_fetch_and_xor(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_fetch_and_nand(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_add_and_fetch(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_sub_and_fetch(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_or_and_fetch(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_and_and_fetch(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_xor_and_fetch(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_nand_and_fetch(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_bool_compare_and_swap(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __sync_val_compare_and_swap(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern void __sync_synchronize();\n"); - dmrC_add_pre_buffer(C, "extern int __sync_lock_test_and_set(void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern void __sync_lock_release(void *, ...);\n"); - - /* And some random ones.. */ - dmrC_add_pre_buffer(C, "extern void *__builtin_return_address(unsigned int);\n"); - dmrC_add_pre_buffer(C, "extern void *__builtin_extract_return_addr(void *);\n"); - dmrC_add_pre_buffer(C, "extern void *__builtin_frame_address(unsigned int);\n"); - dmrC_add_pre_buffer(C, "extern void __builtin_trap(void);\n"); - dmrC_add_pre_buffer(C, "extern void *__builtin_alloca(__SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void __builtin_prefetch (const void *, ...);\n"); - dmrC_add_pre_buffer(C, "extern long __builtin_alpha_extbl(long, long);\n"); - dmrC_add_pre_buffer(C, "extern long __builtin_alpha_extwl(long, long);\n"); - dmrC_add_pre_buffer(C, "extern long __builtin_alpha_insbl(long, long);\n"); - dmrC_add_pre_buffer(C, "extern long __builtin_alpha_inswl(long, long);\n"); - dmrC_add_pre_buffer(C, "extern long __builtin_alpha_insql(long, long);\n"); - dmrC_add_pre_buffer(C, "extern long __builtin_alpha_inslh(long, long);\n"); - dmrC_add_pre_buffer(C, "extern long __builtin_alpha_cmpbge(long, long);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_abs(int);\n"); - dmrC_add_pre_buffer(C, "extern long __builtin_labs(long);\n"); - dmrC_add_pre_buffer(C, "extern long long __builtin_llabs(long long);\n"); - dmrC_add_pre_buffer(C, "extern double __builtin_fabs(double);\n"); - dmrC_add_pre_buffer(C, "extern __SIZE_TYPE__ __builtin_va_arg_pack_len(void);\n"); - - /* Add Blackfin-specific stuff */ - dmrC_add_pre_buffer(C, - "#ifdef __bfin__\n" - "extern void __builtin_bfin_csync(void);\n" - "extern void __builtin_bfin_ssync(void);\n" - "extern int __builtin_bfin_norm_fr1x32(int);\n" - "#endif\n" - ); - - /* And some floating point stuff.. */ - dmrC_add_pre_buffer(C, "extern int __builtin_isgreater(float, float);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_isgreaterequal(float, float);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_isless(float, float);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_islessequal(float, float);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_islessgreater(float, float);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_isunordered(float, float);\n"); - - /* And some INFINITY / NAN stuff.. */ - dmrC_add_pre_buffer(C, "extern double __builtin_huge_val(void);\n"); - dmrC_add_pre_buffer(C, "extern float __builtin_huge_valf(void);\n"); - dmrC_add_pre_buffer(C, "extern long double __builtin_huge_vall(void);\n"); - dmrC_add_pre_buffer(C, "extern double __builtin_inf(void);\n"); - dmrC_add_pre_buffer(C, "extern float __builtin_inff(void);\n"); - dmrC_add_pre_buffer(C, "extern long double __builtin_infl(void);\n"); - dmrC_add_pre_buffer(C, "extern double __builtin_nan(const char *);\n"); - dmrC_add_pre_buffer(C, "extern float __builtin_nanf(const char *);\n"); - dmrC_add_pre_buffer(C, "extern long double __builtin_nanl(const char *);\n"); - - /* And some __FORTIFY_SOURCE ones.. */ - dmrC_add_pre_buffer(C, "extern __SIZE_TYPE__ __builtin_object_size(void *, int);\n"); - dmrC_add_pre_buffer(C, "extern void * __builtin___memcpy_chk(void *, const void *, __SIZE_TYPE__, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void * __builtin___memmove_chk(void *, const void *, __SIZE_TYPE__, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void * __builtin___mempcpy_chk(void *, const void *, __SIZE_TYPE__, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void * __builtin___memset_chk(void *, int, __SIZE_TYPE__, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin___sprintf_chk(char *, int, __SIZE_TYPE__, const char *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin___snprintf_chk(char *, __SIZE_TYPE__, int , __SIZE_TYPE__, const char *, ...);\n"); - dmrC_add_pre_buffer(C, "extern char * __builtin___stpcpy_chk(char *, const char *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern char * __builtin___strcat_chk(char *, const char *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern char * __builtin___strcpy_chk(char *, const char *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern char * __builtin___strncat_chk(char *, const char *, __SIZE_TYPE__, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern char * __builtin___strncpy_chk(char *, const char *, __SIZE_TYPE__, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin___vsprintf_chk(char *, int, __SIZE_TYPE__, const char *, __builtin_va_list);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin___vsnprintf_chk(char *, __SIZE_TYPE__, int, __SIZE_TYPE__, const char *, __builtin_va_list ap);\n"); - dmrC_add_pre_buffer(C, "extern void __builtin_unreachable(void);\n"); - - /* And some from */ - dmrC_add_pre_buffer(C, "extern void __builtin_abort(void);\n"); - dmrC_add_pre_buffer(C, "extern void *__builtin_calloc(__SIZE_TYPE__, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void __builtin_exit(int);\n"); - dmrC_add_pre_buffer(C, "extern void *__builtin_malloc(__SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void *__builtin_realloc(void *, __SIZE_TYPE__);\n"); - dmrC_add_pre_buffer(C, "extern void __builtin_free(void *);\n"); - - /* And some from */ - dmrC_add_pre_buffer(C, "extern int __builtin_printf(const char *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_sprintf(char *, const char *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_snprintf(char *, __SIZE_TYPE__, const char *, ...);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_puts(const char *);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_vprintf(const char *, __builtin_va_list);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_vsprintf(char *, const char *, __builtin_va_list);\n"); - dmrC_add_pre_buffer(C, "extern int __builtin_vsnprintf(char *, __SIZE_TYPE__, const char *, __builtin_va_list ap);\n"); -} - -void dmrC_create_builtin_stream(struct dmr_C *C) -{ - dmrC_add_pre_buffer(C, "#define __DMR_C__ 1\n"); - - dmrC_add_pre_buffer(C, "#weak_define __GNUC__ %d\n", gcc_major); - dmrC_add_pre_buffer(C, "#weak_define __GNUC_MINOR__ %d\n", gcc_minor); - dmrC_add_pre_buffer(C, "#weak_define __GNUC_PATCHLEVEL__ %d\n", gcc_patchlevel); - - /* add the multiarch include directories, if any */ - if (C->multiarch_dir && *C->multiarch_dir) { - dmrC_add_pre_buffer(C, "#add_system \"/usr/include/%s\"\n", C->multiarch_dir); - dmrC_add_pre_buffer(C, "#add_system \"/usr/local/include/%s\"\n", C->multiarch_dir); - } - - /* We add compiler headers path here because we have to parse - * the arguments to get it, falling back to default. */ - if (C->gcc_base_dir && *C->gcc_base_dir) { - dmrC_add_pre_buffer(C, "#add_system \"%s/include\"\n", C->gcc_base_dir); - dmrC_add_pre_buffer(C, "#add_system \"%s/include-fixed\"\n", C->gcc_base_dir); - } - - dmrC_add_pre_buffer(C, "#define __extension__\n"); - dmrC_add_pre_buffer(C, "#define __pragma__\n"); - dmrC_add_pre_buffer(C, "#define _Pragma(x)\n"); - - - // gcc defines __SIZE_TYPE__ to be size_t. For linux/i86 and - // solaris/sparc that is really "unsigned int" and for linux/x86_64 - // it is "long unsigned int". In either case we can probably - // get away with this. We need the #weak_define as cgcc will define - // the right __SIZE_TYPE__. - if (C->target->size_t_ctype == &C->S->ullong_ctype) - dmrC_add_pre_buffer(C, "#weak_define __SIZE_TYPE__ unsigned long long int\n"); - else if (C->target->size_t_ctype == &C->S->ulong_ctype) - dmrC_add_pre_buffer(C, "#weak_define __SIZE_TYPE__ unsigned long int\n"); - else - dmrC_add_pre_buffer(C, "#weak_define __SIZE_TYPE__ unsigned int\n"); - dmrC_add_pre_buffer(C, "#weak_define __STDC__ 1\n"); - - switch (C->standard) - { - case STANDARD_C89: - dmrC_add_pre_buffer(C, "#weak_define __STRICT_ANSI__\n"); - break; - - case STANDARD_C94: - dmrC_add_pre_buffer(C, "#weak_define __STDC_VERSION__ 199409L\n"); - dmrC_add_pre_buffer(C, "#weak_define __STRICT_ANSI__\n"); - break; - - case STANDARD_C99: - dmrC_add_pre_buffer(C, "#weak_define __STDC_VERSION__ 199901L\n"); - dmrC_add_pre_buffer(C, "#weak_define __STRICT_ANSI__\n"); - break; - - case STANDARD_GNU89: - break; - - case STANDARD_GNU99: - dmrC_add_pre_buffer(C, "#weak_define __STDC_VERSION__ 199901L\n"); - break; - - case STANDARD_C11: - dmrC_add_pre_buffer(C, "#weak_define __STRICT_ANSI__ 1\n"); - - case STANDARD_GNU11: - dmrC_add_pre_buffer(C, "#weak_define __STDC_NO_ATOMICS__ 1\n"); - dmrC_add_pre_buffer(C, "#weak_define __STDC_NO_COMPLEX__ 1\n"); - dmrC_add_pre_buffer(C, "#weak_define __STDC_NO_THREADS__ 1\n"); - dmrC_add_pre_buffer(C, "#weak_define __STDC_VERSION__ 201112L\n"); - break; - - default: - assert(0); - } - - if (!C->codegen) { - /* Do not output these macros when we are generating code e.g. via LLVM as these macros are not correct */ - dmrC_add_pre_buffer(C, "#define __builtin_stdarg_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n"); - dmrC_add_pre_buffer(C, "#define __builtin_va_start(a,b) ((a) = (__builtin_va_list)(&(b)))\n"); - dmrC_add_pre_buffer(C, "#define __builtin_ms_va_start(a,b) ((a) = (__builtin_ms_va_list)(&(b)))\n"); - dmrC_add_pre_buffer(C, "#define __builtin_va_arg(arg,type) ({ type __va_arg_ret = *(type *)(arg); arg += sizeof(type); __va_arg_ret; })\n"); - dmrC_add_pre_buffer(C, "#define __builtin_va_alist (*(void *)0)\n"); - dmrC_add_pre_buffer(C, "#define __builtin_va_arg_incr(x) ((x) + 1)\n"); - dmrC_add_pre_buffer(C, "#define __builtin_va_copy(dest, src) ({ dest = src; (void)0; })\n"); - dmrC_add_pre_buffer(C, "#define __builtin_ms_va_copy(dest, src) ({ dest = src; (void)0; })\n"); - dmrC_add_pre_buffer(C, "#define __builtin_va_end(arg)\n"); - dmrC_add_pre_buffer(C, "#define __builtin_ms_va_end(arg)\n"); - dmrC_add_pre_buffer(C, "#define __builtin_va_arg_pack()\n"); - } - - /* FIXME! We need to do these as special magic macros at expansion time! */ - dmrC_add_pre_buffer(C, "#define __BASE_FILE__ \"base_file.c\"\n"); - - if (C->optimize) - dmrC_add_pre_buffer(C, "#define __OPTIMIZE__ 1\n"); - if (C->optimize_size) - dmrC_add_pre_buffer(C, "#define __OPTIMIZE_SIZE__ 1\n"); - -} - -static struct symbol_list *sparse_tokenstream(struct dmr_C *C, struct token *token) -{ - int builtin = token && !token->pos.stream; - - // Preprocess the stream - token = dmrC_preprocess(C, token); - if (C->die_if_error) - return NULL; - - if (C->dump_macro_defs && !builtin) - dmrC_dump_macro_definitions(C); - - if (C->preprocess_only) { - while (!dmrC_eof_token(token)) { - int prec = 1; - struct token *next = token->next; - const char *separator = ""; - if (next->pos.whitespace) - separator = " "; - if (next->pos.newline) { - separator = "\n\t\t\t\t\t"; - prec = next->pos.pos; - if (prec > 4) - prec = 4; - } - printf("%s%.*s", dmrC_show_token(C, token), prec, separator); - token = next; - } - putchar('\n'); - - return NULL; - } - - // Parse the resulting C code - while (!dmrC_eof_token(token)) - token = dmrC_external_declaration(C, token, &C->S->translation_unit_used_list, NULL); - return C->S->translation_unit_used_list; -} - -static struct symbol_list *sparse_file(struct dmr_C *C, const char *filename) -{ - int fd; - struct token *token; - - if (strcmp(filename, "-") == 0) { - fd = 0; - } else { - fd = open(filename, O_RDONLY); - if (fd < 0) - dmrC_die(C, "No such file: %s", filename); - } - - // Tokenize the input stream - token = dmrC_tokenize(C, filename, fd, NULL, C->T->includepath); - close(fd); - - return sparse_tokenstream(C, token); -} - -/* -* This handles the "-include" directive etc: we're in global -* scope, and all types/macros etc will affect all the following -* files. -* -* NOTE NOTE NOTE! "#undef" of anything in this stage will -* affect all subsequent files too, i.e. we can have non-local -* behaviour between files! -*/ -static struct symbol_list *sparse_initial(struct dmr_C *C) -{ - int i; - - // Prepend any "include" file to the stream. - // We're in global scope, it will affect all files! - for (i = 0; i < C->cmdline_include_nr; i++) - dmrC_add_pre_buffer(C, "#argv_include \"%s\"\n", C->cmdline_include[i]); - - return sparse_tokenstream(C, C->pre_buffer_begin); -} - -static void protect_token_alloc(struct dmr_C *C) { - /* prevent tokens from being deallocated ? */ - dmrC_allocator_transfer(&C->token_allocator, &C->protected_token_allocator); -} - -static void clear_token_alloc(struct dmr_C *C) { - /* prevent tokens from being deallocated ? */ - dmrC_allocator_drop_all_allocations(&C->token_allocator); -} - -struct symbol_list *dmrC_sparse_initialize(struct dmr_C *C, int argc, char **argv, struct string_list **filelist) -{ - char **args; - struct symbol_list *list; - - args = argv; - for (; args < argv + argc;) { - char *arg = *++args; - if (!arg) - break; - - if (arg[0] == '-' && arg[1]) { - args = handle_switch(C, arg + 1, args); - continue; - } - ptrlist_add((struct ptr_list **)filelist, arg, &C->ptrlist_allocator); - } - handle_switch_W_finalize(C); - handle_switch_v_finalize(C); - - handle_arch_finalize(C); - - list = NULL; - //if (!ptr_list_empty(filelist)) { - - dmrC_create_builtin_stream(C); - predefined_macros(C); - if (!C->preprocess_only) - dmrC_declare_builtin_functions(C); - - list = sparse_initial(C); - - /* - * Protect the initial token allocations, since - * they need to survive all the others - */ - protect_token_alloc(C); - //} - return list; -} - -struct symbol_list * dmrC_sparse_keep_tokens(struct dmr_C *C, char *filename) -{ - struct symbol_list *res; - - /* Clear previous symbol list */ - C->S->translation_unit_used_list = NULL; - - dmrC_new_file_scope(C); - res = sparse_file(C, filename); - - /* And return it */ - return res; -} - - -struct symbol_list * dmrC__sparse(struct dmr_C *C, char *filename) -{ - struct symbol_list *res; - - res = dmrC_sparse_keep_tokens(C, filename); - - /* Drop the tokens for this file after parsing */ - clear_token_alloc(C); - - /* And return it */ - return res; -} - -struct symbol_list * dmrC_sparse(struct dmr_C *C, char *filename) -{ - struct symbol_list *res = dmrC__sparse(C, filename); - - if (C->has_error & ERROR_CURR_PHASE) - C->has_error = ERROR_PREV_PHASE; - - /* Evaluate the complete symbol list */ - if (res) - dmrC_evaluate_symbol_list(C, res); - - return res; -} - -struct symbol_list *dmrC_sparse_buffer(struct dmr_C *C, const char *name, char *buffer, int keep_tokens) -{ - struct symbol_list *res; - - /* Clear previous symbol list */ - C->S->translation_unit_used_list = NULL; - dmrC_new_file_scope(C); - - struct token *start; - struct token *end; - start = dmrC_tokenize_buffer_stream(C, name, (unsigned char *)buffer, - (unsigned long)strlen(buffer), &end); - - res = sparse_tokenstream(C, start); - - if (!keep_tokens) { - /* Drop the tokens for this file after parsing */ - clear_token_alloc(C); - } - - /* Evaluate the complete symbol list */ - if (res) - dmrC_evaluate_symbol_list(C, res); - - /* And return it */ - return res; -} diff --git a/dmr_c/src/lib.h b/dmr_c/src/lib.h deleted file mode 100644 index 5db8948..0000000 --- a/dmr_c/src/lib.h +++ /dev/null @@ -1,302 +0,0 @@ -#ifndef DMR_LIB_H -#define DMR_LIB_H - -/* This file is derived from lib.h in sparse */ - -#include -#include -#include -#include - -/* -* Basic helper routine descriptions for 'sparse'. -* -* Copyright (C) 2003 Transmeta Corp. -* 2003 Linus Torvalds -* 2004 Christopher Li -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -// Build options -#define NEW_SSA 0 -#define SINGLE_STORE_SHORTCUT 1 - - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define DO_STRINGIFY(x) #x -#define STRINGIFY(x) DO_STRINGIFY(x) - -#ifndef ARRAY_SIZE -#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) -#endif - -#define MAX_STRING 8191 - -extern unsigned int dmrC_hexval(unsigned int c); - -struct position { - unsigned int type : 6, - stream : 14, - newline : 1, - whitespace : 1, - pos : 10; - unsigned int line : 31, - noexpand : 1; -}; - -struct ident; -struct token; -struct symbol; -struct statement; -struct expression; -struct basic_block; -struct entrypoint; -struct instruction; -struct multijmp; -struct pseudo; -struct string; -typedef struct pseudo *pseudo_t; - -struct target_t; -struct global_symbols_t; -struct tokenizer_state_t; -struct linearizer_state_t; - -struct warning { - const char *name; - int *flag; -}; - -enum standard { - STANDARD_C89, - STANDARD_C94, - STANDARD_C99, - STANDARD_C11, - STANDARD_GNU11, - STANDARD_GNU89, - STANDARD_GNU99, -}; - -enum { - WARNING_OFF, - WARNING_ON, - WARNING_FORCE_OFF -}; - -struct symbol_list; -struct statement_list; -struct expression_list; -struct basic_block_list; -struct instruction_list; -struct multijmp_list; -struct pseudo_list; -struct phi_map; - -DECLARE_PTR_LIST(string_list, char); - -#define ERROR_CURR_PHASE (1 << 0) -#define ERROR_PREV_PHASE (1 << 1) - -struct dmr_C { - struct target_t *target; - struct global_symbols_t *S; - struct tokenizer_state_t *T; - struct parse_state_t *P; - struct linearizer_state_t *L; - - void *User_data; - - // memory allocators - struct allocator ptrlist_allocator; - struct allocator token_allocator; - struct allocator protected_token_allocator; - struct allocator byte_allocator; - struct allocator string_allocator; - struct allocator ident_allocator; - struct allocator scope_allocator; - struct allocator expression_allocator; - struct allocator statement_allocator; - - int max_warnings; - int show_info; - int errors; - int die_if_error; - int once; - int preprocess_only; - int codegen; - int has_error; - - jmp_buf jmpbuf; - - const char *gcc_base_dir; - const char *multiarch_dir; - - int verbose, optimize, optimize_size, preprocessing; - - enum standard standard; - struct token *pre_buffer_begin; - struct token *pre_buffer_end; - - int Waddress; // TODO - int Waddress_space; - int Wbitwise; - int Wcast_to_as; - int Wcast_truncate; - int Wcontext; - int Wdecl; - int Wdeclarationafterstatement; - int Wdefault_bitfield_sign; - int Wdesignated_init; - int Wdo_while; - int Wenum_mismatch; - int Wsparse_error; - int Winit_cstring; - int Wmemcpy_max_count; // TODO - int Wnon_pointer_null; - int Wold_initializer; - int Wone_bit_signed_bitfield; - int Woverride_init; //TODO - int Woverride_init_all; //TODO - int Woverride_init_whole_range; //TODO - int Wparen_string; - int Wptr_subtraction_blows; - int Wreturn_void; - int Wshadow; - int Wsizeof_bool; - int Wtautological_compare; - int Wtransparent_union; - int Wtypesign; - int Wundef; - int Wuninitialized; - int Wunknown_attribute; - int Wvla; - struct warning warnings[32]; - struct warning debugs[2]; - struct warning dumps[1]; - -#define CMDLINE_INCLUDE 20 - int cmdline_include_nr; - char *cmdline_include[CMDLINE_INCLUDE]; - - int dump_macro_defs; // TODO - - int dbg_entry; - int dbg_dead; - int fmem_report; // TODO - int fdump_linearize; // TODO - unsigned long long fmemcpy_max_count; - - int arch_m64; - int arch_msize_long; - int arch_big_endian; // TODO - /* TODO is this the right place? */ - struct scope *block_scope, *function_scope, *file_scope, *global_scope; - struct scope *builtin_scope; - - /* Current parsing/evaluation function */ - struct symbol *current_fn; - - char modifier_string_buffer[100]; - char typename_array[200]; - - struct ident_list *macros; // only needed for -dD - int false_nesting; - int counter_macro; // __COUNTER__ expansion - -#define INCLUDEPATHS 300 - const char *includepath[INCLUDEPATHS + 1]; - - const char **quote_includepath; - const char **angle_includepath; - const char **isys_includepath; - const char **sys_includepath; - const char **dirafter_includepath; - - char date_buffer[12]; /* __DATE__: 3 + ' ' + 2 + ' ' + 4 + '\0' */ - char preprocessor_buffer[MAX_STRING]; - char preprocessor_mergebuffer[512]; - char preprocessor_tokenseqbuffer[256]; - time_t t; - char fullname[1024]; - - char output_file_name[1024]; -}; - -/* -* Creates a new instance of dmr_C. Due to the way the parser and compiler works -* at present it is recommended that each dmr_C instance be used to process one set -* of inputs only. Destroy the dmr_C instance after use. This way all resources will -* be released. -*/ -extern struct dmr_C *new_dmr_C(); -extern void destroy_dmr_C(struct dmr_C *C); - -/* -* Appends the provided formatted string to the "pre buffer" that is processed by -* dmrC_sparse_initialize(). The input is tokenized immediately and added to the "pre buffer" -* token stream. -*/ -extern void dmrC_add_pre_buffer(struct dmr_C *, const char *fmt, ...) FORMAT_ATTR(2); - -/* -* Declares a bunch of gcc built-ins into a "pre buffer" which is processed in -* dmrC_sparse_initialize(). The dmrC_add_pre_buffer() function is used to add input into the -* pre buffer. -*/ -extern void dmrC_declare_builtin_functions(struct dmr_C *C); -extern void dmrC_create_builtin_stream(struct dmr_C *C); -extern void dmrC_dump_macro_definitions(struct dmr_C *C); -extern struct symbol_list * dmrC_sparse_initialize(struct dmr_C *C, int argc, char **argv, struct string_list **filelist); -extern struct symbol_list * dmrC_sparse_keep_tokens(struct dmr_C *C, char *filename); -extern struct symbol_list * dmrC_sparse(struct dmr_C *C, char *filename); -extern struct symbol_list * dmrC__sparse(struct dmr_C *C, char *filename); -extern struct symbol_list * dmrC_sparse_buffer(struct dmr_C *C, const char *name, char *buffer, int keep_tokens); - -struct token *dmrC_skip_to_token(struct token *, int); -struct token *dmrC_expect_token(struct dmr_C *C, struct token *token, int op, const char *where); - -extern void dmrC_die(struct dmr_C *, const char *, ...) FORMAT_ATTR(2) NORETURN_ATTR; -extern void dmrC_info(struct dmr_C *, struct position, const char *, ...) - FORMAT_ATTR(3); -extern void dmrC_warning(struct dmr_C *, struct position, const char *, ...) - FORMAT_ATTR(3); -extern void dmrC_sparse_error(struct dmr_C *, struct position, const char *, ...) - FORMAT_ATTR(3); -extern void dmrC_error_die(struct dmr_C *, struct position, const char *, ...) - FORMAT_ATTR(3) NORETURN_ATTR; -extern void dmrC_expression_error(struct dmr_C *, struct expression *, const char *, - ...) FORMAT_ATTR(3); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/dmr_c/src/linearize.c b/dmr_c/src/linearize.c deleted file mode 100644 index a5c96d3..0000000 --- a/dmr_c/src/linearize.c +++ /dev/null @@ -1,2741 +0,0 @@ -/* - * Linearize - walk the parse tree and generate a linear version - * of it and the basic blocks. - * - * Copyright (C) 2004 Linus Torvalds - * Copyright (C) 2004 Christopher Li - */ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#if 0 -#include -#endif -#include - -static pseudo_t linearize_statement(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt); -static pseudo_t linearize_expression(struct dmr_C *C, struct entrypoint *ep, struct expression *expr); - -static pseudo_t add_binary_op(struct dmr_C *C, struct entrypoint *ep, struct symbol *ctype, int op, pseudo_t left, pseudo_t right); -static pseudo_t add_setval(struct dmr_C *C, struct entrypoint *ep, struct symbol *ctype, struct expression *val); -static pseudo_t linearize_one_symbol(struct dmr_C *C, struct entrypoint *ep, struct symbol *sym); - -struct access_data; -static pseudo_t add_load(struct dmr_C *C, struct entrypoint *ep, struct access_data *); -static pseudo_t linearize_initializer(struct dmr_C *C, struct entrypoint *ep, struct expression *initializer, struct access_data *); -static pseudo_t cast_pseudo(struct dmr_C *C, struct entrypoint *ep, pseudo_t src, struct symbol *from, struct symbol *to); - - -static struct instruction *alloc_instruction(struct dmr_C *C, int opcode, int size) -{ - struct instruction * insn = (struct instruction *) dmrC_allocator_allocate(&C->L->instruction_allocator, 0); - insn->opcode = opcode; - insn->size = size; - insn->pos = C->L->current_pos; - return insn; -} - -static inline int type_size(struct symbol *type) -{ - return type ? type->bit_size > 0 ? type->bit_size : 0 : 0; -} - -static struct instruction *alloc_typed_instruction(struct dmr_C *C, int opcode, struct symbol *type) -{ - struct instruction *insn = alloc_instruction(C, opcode, type_size(type)); - insn->type = type; - return insn; -} - -static struct entrypoint *alloc_entrypoint(struct dmr_C *C) -{ - return (struct entrypoint *) dmrC_allocator_allocate(&C->L->entrypoint_allocator, 0); -} - -static struct basic_block *alloc_basic_block(struct dmr_C *C, struct entrypoint *ep, struct position pos) -{ - struct basic_block *bb = (struct basic_block *) dmrC_allocator_allocate(&C->L->basic_block_allocator, 0); - bb->context = -1; - bb->pos = pos; - bb->ep = ep; - bb->nr = C->L->bb_nr++; - return bb; -} - -static struct multijmp *alloc_multijmp(struct dmr_C *C, struct basic_block *target, long long begin, long long end) -{ - struct multijmp *multijmp = (struct multijmp *)dmrC_allocator_allocate(&C->L->multijmp_allocator, 0); - multijmp->target = target; - multijmp->begin = begin; - multijmp->end = end; - return multijmp; -} - -#if 0 -static inline int regno(pseudo_t n) -{ - int retval = -1; - if (n && n->type == PSEUDO_REG) - retval = n->nr; - return retval; -} -#endif - -const char *dmrC_show_pseudo(struct dmr_C *C, pseudo_t pseudo) -{ - char *buf; - int i; - - if (!pseudo) - return "no pseudo"; - if (pseudo == VOID_PSEUDO(C)) - return "VOID"; - buf = C->L->pseudo_buffer[3 & ++C->L->n]; - switch(pseudo->type) { - case PSEUDO_SYM: { - struct symbol *sym = pseudo->sym; - struct expression *expr; - - if (sym->bb_target) { - snprintf(buf, 64, ".L%u", sym->bb_target->nr); - break; - } - if (sym->ident) { - snprintf(buf, 64, "%s", dmrC_show_ident(C, sym->ident)); - break; - } - expr = sym->initializer; - snprintf(buf, 64, "", sym); - if (expr) { - switch (expr->type) { - case EXPR_VALUE: - snprintf(buf, 64, "", expr->value); - break; - case EXPR_STRING: - return dmrC_show_string(C, expr->string); - default: - break; - } - } - break; - } - case PSEUDO_REG: - i = snprintf(buf, 64, "%%r%d", pseudo->nr); - if (pseudo->ident) - sprintf(buf+i, "(%s)", dmrC_show_ident(C, pseudo->ident)); - break; - case PSEUDO_VAL: { - long long value = pseudo->value; - if (value > 1000 || value < -1000) - snprintf(buf, 64, "$%#llx", value); - else - snprintf(buf, 64, "$%lld", value); - break; - } - case PSEUDO_ARG: - snprintf(buf, 64, "%%arg%d", pseudo->nr); - break; - case PSEUDO_PHI: - i = snprintf(buf, 64, "%%phi%d", pseudo->nr); - if (pseudo->ident) - sprintf(buf+i, "(%s)", dmrC_show_ident(C, pseudo->ident)); - break; - default: - snprintf(buf, 64, "", pseudo->type); - } - return buf; -} - -static const char *opcodes[] = { - [OP_BADOP] = "bad_op", - - /* Fn entrypoint */ - [OP_ENTRY] = "", - - /* Terminator */ - [OP_RET] = "ret", - [OP_BR] = "br", - [OP_CBR] = "cbr", - [OP_SWITCH] = "switch", - [OP_INVOKE] = "invoke", - [OP_COMPUTEDGOTO] = "jmp *", - [OP_UNWIND] = "unwind", - - /* Binary */ - [OP_ADD] = "add", - [OP_SUB] = "sub", - [OP_MULU] = "mulu", - [OP_MULS] = "muls", - [OP_DIVU] = "divu", - [OP_DIVS] = "divs", - [OP_MODU] = "modu", - [OP_MODS] = "mods", - [OP_SHL] = "shl", - [OP_LSR] = "lsr", - [OP_ASR] = "asr", - - /* Logical */ - [OP_AND] = "and", - [OP_OR] = "or", - [OP_XOR] = "xor", - [OP_AND_BOOL] = "and-bool", - [OP_OR_BOOL] = "or-bool", - - /* Binary comparison */ - [OP_SET_EQ] = "seteq", - [OP_SET_NE] = "setne", - [OP_SET_LE] = "setle", - [OP_SET_GE] = "setge", - [OP_SET_LT] = "setlt", - [OP_SET_GT] = "setgt", - [OP_SET_B] = "setb", - [OP_SET_A] = "seta", - [OP_SET_BE] = "setbe", - [OP_SET_AE] = "setae", - - /* Uni */ - [OP_NOT] = "not", - [OP_NEG] = "neg", - - /* Special three-input */ - [OP_SEL] = "select", - - /* Memory */ - [OP_MALLOC] = "malloc", - [OP_FREE] = "free", - [OP_ALLOCA] = "alloca", - [OP_LOAD] = "load", - [OP_STORE] = "store", - [OP_SETVAL] = "set", - [OP_SYMADDR] = "symaddr", - [OP_GET_ELEMENT_PTR] = "getelem", - - /* Other */ - [OP_PHI] = "phi", - [OP_PHISOURCE] = "phisrc", - [OP_CAST] = "cast", - [OP_SCAST] = "scast", - [OP_FPCAST] = "fpcast", - [OP_PTRCAST] = "ptrcast", - [OP_INLINED_CALL] = "# call", - [OP_CALL] = "call", - [OP_VANEXT] = "va_next", - [OP_VAARG] = "va_arg", - [OP_SLICE] = "slice", - [OP_SNOP] = "snop", - [OP_LNOP] = "lnop", - [OP_NOP] = "nop", - [OP_DEATHNOTE] = "dead", - [OP_ASM] = "asm", - - /* Sparse tagging (line numbers, context, whatever) */ - [OP_CONTEXT] = "context", - [OP_RANGE] = "range-check", - - [OP_COPY] = "copy", -}; - -static char *show_asm_constraints(struct dmr_C *C, char *buf, const char *sep, struct asm_constraint_list *list) -{ - struct asm_constraint *entry; - - FOR_EACH_PTR(list, entry) { - buf += sprintf(buf, "%s\"%s\"", sep, entry->constraint); - if (entry->pseudo) - buf += sprintf(buf, " (%s)", dmrC_show_pseudo(C, entry->pseudo)); - if (entry->ident) - buf += sprintf(buf, " [%s]", dmrC_show_ident(C, entry->ident)); - sep = ", "; - } END_FOR_EACH_PTR(entry); - return buf; -} - -static char *show_asm(struct dmr_C *C, char *buf, struct instruction *insn) -{ - struct asm_rules *rules = insn->asm_rules; - - buf += sprintf(buf, "\"%s\"", insn->string); - buf = show_asm_constraints(C, buf, "\n\t\tout: ", rules->outputs); - buf = show_asm_constraints(C, buf, "\n\t\tin: ", rules->inputs); - buf = show_asm_constraints(C, buf, "\n\t\tclobber: ", rules->clobbers); - return buf; -} - -const char *dmrC_show_instruction(struct dmr_C *C, struct instruction *insn) -{ - int opcode = insn->opcode; - char *buf; - - buf = C->L->buffer; - if (!insn->bb) - buf += sprintf(buf, "# "); - - if (opcode < (int)ARRAY_SIZE(opcodes)) { - const char *op = opcodes[opcode]; - if (!op) - buf += sprintf(buf, "opcode:%d", opcode); - else - buf += sprintf(buf, "%s", op); - if (insn->type && dmrC_is_float_type(C->S, insn->type)) - buf += sprintf(buf, ".f%d", insn->size); - else if (insn->size) - buf += sprintf(buf, ".%d", insn->size); - if (insn->type) { - if (dmrC_is_ptr_type(insn->type)) - buf += sprintf(buf, "*"); - } - - memset(buf, ' ', 20); - buf++; - } - - if (buf < C->L->buffer + 12) - buf = C->L->buffer + 12; - switch (opcode) { - case OP_RET: - if (insn->src && insn->src != VOID_PSEUDO(C)) - buf += sprintf(buf, "%s", dmrC_show_pseudo(C, insn->src)); - break; - case OP_CBR: - buf += sprintf(buf, "%s, .L%u, .L%u", dmrC_show_pseudo(C, insn->cond), insn->bb_true->nr, insn->bb_false->nr); - break; - - case OP_BR: - buf += sprintf(buf, ".L%u", insn->bb_true->nr); - break; - - case OP_SYMADDR: { - struct symbol *sym = insn->symbol->sym; - buf += sprintf(buf, "%s <- ", dmrC_show_pseudo(C, insn->target)); - - if (!insn->bb && !sym) - break; - if (sym->bb_target) { - buf += sprintf(buf, ".L%u", sym->bb_target->nr); - break; - } - if (sym->ident) { - buf += sprintf(buf, "%s", dmrC_show_ident(C, sym->ident)); - break; - } - buf += sprintf(buf, "", sym); - break; - } - - case OP_SETVAL: { - struct expression *expr = insn->val; - struct symbol *sym; - buf += sprintf(buf, "%s <- ", dmrC_show_pseudo(C, insn->target)); - - if (!expr) { - buf += sprintf(buf, "%s", ""); - break; - } - - switch (expr->type) { - case EXPR_VALUE: - buf += sprintf(buf, "%lld", expr->value); - break; - case EXPR_FVALUE: - buf += sprintf(buf, "%Lf", expr->fvalue); - break; - case EXPR_STRING: - buf += sprintf(buf, "%.40s", dmrC_show_string(C, expr->string)); - break; - case EXPR_SYMBOL: - buf += sprintf(buf, "%s", dmrC_show_ident(C, expr->symbol->ident)); - break; - case EXPR_LABEL: - sym = expr->symbol; - if (sym->bb_target) - buf += sprintf(buf, ".L%u", sym->bb_target->nr); - break; - default: - buf += sprintf(buf, "SETVAL EXPR TYPE %d", expr->type); - } - break; - } - case OP_SWITCH: { - struct multijmp *jmp; - buf += sprintf(buf, "%s", dmrC_show_pseudo(C, insn->cond)); - FOR_EACH_PTR(insn->multijmp_list, jmp) { - if (jmp->begin == jmp->end) - buf += sprintf(buf, ", %lld -> .L%u", jmp->begin, jmp->target->nr); - else if (jmp->begin < jmp->end) - buf += sprintf(buf, ", %lld ... %lld -> .L%u", jmp->begin, jmp->end, jmp->target->nr); - else - buf += sprintf(buf, ", default -> .L%u", jmp->target->nr); - } END_FOR_EACH_PTR(jmp); - break; - } - case OP_COMPUTEDGOTO: { - struct multijmp *jmp; - buf += sprintf(buf, "%s", dmrC_show_pseudo(C, insn->target)); - FOR_EACH_PTR(insn->multijmp_list, jmp) { - buf += sprintf(buf, ", .L%u", jmp->target->nr); - } END_FOR_EACH_PTR(jmp); - break; - } - - case OP_PHISOURCE: { - struct instruction *phi; - buf += sprintf(buf, "%s <- %s ", dmrC_show_pseudo(C, insn->target), dmrC_show_pseudo(C, insn->phi_src)); - FOR_EACH_PTR(insn->phi_users, phi) { - buf += sprintf(buf, " (%s)", dmrC_show_pseudo(C, phi->target)); - } END_FOR_EACH_PTR(phi); - break; - } - - case OP_PHI: { - pseudo_t phi; - const char *s = " <-"; - buf += sprintf(buf, "%s", dmrC_show_pseudo(C, insn->target)); - FOR_EACH_PTR(insn->phi_list, phi) { - buf += sprintf(buf, "%s %s", s, dmrC_show_pseudo(C, phi)); - s = ","; - } END_FOR_EACH_PTR(phi); - break; - } - case OP_LOAD: case OP_LNOP: - buf += sprintf(buf, "%s <- %d[%s]", dmrC_show_pseudo(C, insn->target), insn->offset, dmrC_show_pseudo(C, insn->src)); - if (insn->orig_type) { - struct symbol *sym = insn->orig_type; - if (sym->ident) { - buf += sprintf(buf, "; %s", dmrC_show_ident(C, sym->ident)); - } - else { - buf += sprintf(buf, "; ", sym); - } - } - break; - case OP_STORE: case OP_SNOP: - buf += sprintf(buf, "%s -> %d[%s]", dmrC_show_pseudo(C, insn->target), insn->offset, dmrC_show_pseudo(C, insn->src)); - if (insn->orig_type) { - struct symbol *sym = insn->orig_type; - if (sym->ident) { - buf += sprintf(buf, "; %s", dmrC_show_ident(C, sym->ident)); - } - else { - buf += sprintf(buf, "; ", sym); - } - } - break; - case OP_INLINED_CALL: - case OP_CALL: { - if (insn->target && insn->target != VOID_PSEUDO(C)) - buf += sprintf(buf, "%s <- ", dmrC_show_pseudo(C, insn->target)); - buf += sprintf(buf, "%s", dmrC_show_pseudo(C, insn->func)); - { - struct pseudo *arg; - FOR_EACH_PTR(insn->arguments, arg) { - buf += sprintf(buf, ", %s", dmrC_show_pseudo(C, arg)); - } END_FOR_EACH_PTR(arg); - } - break; - } - case OP_CAST: - case OP_SCAST: - case OP_FPCAST: - case OP_PTRCAST: - buf += sprintf(buf, "%s <- (%d) %s", - dmrC_show_pseudo(C, insn->target), - type_size(insn->orig_type), - dmrC_show_pseudo(C, insn->src)); - break; - case OP_ADD: - case OP_SUB: - case OP_MULU: - case OP_MULS: - case OP_DIVU: - case OP_DIVS: - case OP_MODU: - case OP_MODS: - case OP_SHL: - case OP_LSR: - case OP_ASR: - case OP_AND: - case OP_OR: - case OP_XOR: - case OP_AND_BOOL: - case OP_OR_BOOL: - case OP_SET_EQ: - case OP_SET_NE: - case OP_SET_LE: - case OP_SET_GE: - case OP_SET_LT: - case OP_SET_GT: - case OP_SET_B: - case OP_SET_A: - case OP_SET_BE: - case OP_SET_AE: - - buf += sprintf(buf, "%s <- %s, %s", dmrC_show_pseudo(C, insn->target), dmrC_show_pseudo(C, insn->src1), dmrC_show_pseudo(C, insn->src2)); - break; - - case OP_SEL: - buf += sprintf(buf, "%s <- %s, %s, %s", dmrC_show_pseudo(C, insn->target), - dmrC_show_pseudo(C, insn->src1), dmrC_show_pseudo(C, insn->src2), dmrC_show_pseudo(C, insn->src3)); - break; - - case OP_SLICE: - buf += sprintf(buf, "%s <- %s, %d, %d", dmrC_show_pseudo(C, insn->target), dmrC_show_pseudo(C, insn->base), insn->from, insn->len); - break; - - case OP_NOT: case OP_NEG: - buf += sprintf(buf, "%s <- %s", dmrC_show_pseudo(C, insn->target), dmrC_show_pseudo(C, insn->src1)); - break; - - case OP_CONTEXT: - buf += sprintf(buf, "%s%d", insn->check ? "check: " : "", insn->increment); - break; - case OP_RANGE: - buf += sprintf(buf, "%s between %s..%s", dmrC_show_pseudo(C, insn->src1), dmrC_show_pseudo(C, insn->src2), dmrC_show_pseudo(C, insn->src3)); - break; - case OP_NOP: - buf += sprintf(buf, "%s <- %s", dmrC_show_pseudo(C, insn->target), dmrC_show_pseudo(C, insn->src1)); - break; - case OP_DEATHNOTE: - buf += sprintf(buf, "%s", dmrC_show_pseudo(C, insn->target)); - break; - case OP_ASM: - buf = show_asm(C, buf, insn); - break; - case OP_COPY: - buf += sprintf(buf, "%s <- %s", dmrC_show_pseudo(C, insn->target), dmrC_show_pseudo(C, insn->src)); - break; - default: - break; - } - - if (buf >= C->L->buffer + sizeof(C->L->buffer)) - dmrC_die(C, "instruction buffer overflowed %td\n", buf - C->L->buffer); - do { --buf; } while (*buf == ' '); - *++buf = 0; - return C->L->buffer; -} - -void dmrC_show_bb(struct dmr_C *C, struct basic_block *bb) -{ - struct instruction *insn; - - printf(".L%u:\n", bb->nr); - if (C->verbose) { - pseudo_t needs, defines; - printf("%s:%d\n", dmrC_stream_name(C, bb->pos.stream), bb->pos.line); - - FOR_EACH_PTR(bb->needs, needs) { - struct instruction *def = needs->def; - if (def->opcode != OP_PHI) { - printf(" **uses %s (from .L%u)**\n", dmrC_show_pseudo(C, needs), def->bb->nr); - } else { - pseudo_t phi; - const char *sep = " "; - printf(" **uses %s (from", dmrC_show_pseudo(C, needs)); - FOR_EACH_PTR(def->phi_list, phi) { - if (phi == VOID_PSEUDO(C)) - continue; - printf("%s(%s:.L%u)", sep, dmrC_show_pseudo(C, phi), phi->def->bb->nr); - sep = ", "; - } END_FOR_EACH_PTR(phi); - printf(")**\n"); - } - } END_FOR_EACH_PTR(needs); - - FOR_EACH_PTR(bb->defines, defines) { - printf(" **defines %s **\n", dmrC_show_pseudo(C, defines)); - } END_FOR_EACH_PTR(defines); - - if (bb->parents) { - struct basic_block *from; - FOR_EACH_PTR(bb->parents, from) { - printf(" **from .L%u (%s:%d:%d)**\n", from->nr, - dmrC_stream_name(C, from->pos.stream), from->pos.line, from->pos.pos); - } END_FOR_EACH_PTR(from); - } - - if (bb->children) { - struct basic_block *to; - FOR_EACH_PTR(bb->children, to) { - printf(" **to .L%u (%s:%d:%d)**\n", to->nr, - dmrC_stream_name(C, to->pos.stream), to->pos.line, to->pos.pos); - } END_FOR_EACH_PTR(to); - } - } - - FOR_EACH_PTR(bb->insns, insn) { - if (!insn->bb && C->verbose < 2) - continue; - printf("\t%s\n", dmrC_show_instruction(C, insn)); - } END_FOR_EACH_PTR(insn); - if (!dmrC_bb_terminated(bb)) - printf("\tEND\n"); -} - -static void show_symbol_usage(struct dmr_C *C, pseudo_t pseudo) -{ - struct pseudo_user *pu; - - if (pseudo) { - FOR_EACH_PTR(pseudo->users, pu) { - printf("\t%s\n", dmrC_show_instruction(C, pu->insn)); - } END_FOR_EACH_PTR(pu); - } -} - -void dmrC_show_entry(struct dmr_C *C, struct entrypoint *ep) -{ - struct symbol *sym; - struct basic_block *bb; - - printf("%s:\n", dmrC_show_ident(C, ep->name->ident)); - - if (C->verbose) { - printf("ep %p: %s\n", ep, dmrC_show_ident(C, ep->name->ident)); - - FOR_EACH_PTR(ep->syms, sym) { - if (!sym->pseudo) - continue; - if (!sym->pseudo->users) - continue; - printf(" sym: %p %s\n", sym, dmrC_show_ident(C, sym->ident)); - if (sym->ctype.modifiers & (MOD_EXTERN | MOD_STATIC | MOD_ADDRESSABLE)) - printf("\texternal visibility\n"); - show_symbol_usage(C, sym->pseudo); - } END_FOR_EACH_PTR(sym); - - printf("\n"); - } - - FOR_EACH_PTR(ep->bbs, bb) { - if (!bb) - continue; - if (!bb->parents && !bb->children && !bb->insns && C->verbose < 2) - continue; - dmrC_show_bb(C, bb); - printf("\n"); - } END_FOR_EACH_PTR(bb); - - printf("\n"); -} - -static void bind_label(struct dmr_C *C, struct symbol *label, struct basic_block *bb, struct position pos) -{ - if (label->bb_target) - dmrC_warning(C, pos, "label '%s' already bound", dmrC_show_ident(C, label->ident)); - label->bb_target = bb; -} - -static struct basic_block * get_bound_block(struct dmr_C *C, struct entrypoint *ep, struct symbol *label) -{ - struct basic_block *bb = label->bb_target; - - if (!bb) { - bb = alloc_basic_block(C, ep, label->pos); - label->bb_target = bb; - } - return bb; -} - -static void finish_block(struct entrypoint *ep) -{ - struct basic_block *src = ep->active; - if (dmrC_bb_reachable(src)) - ep->active = NULL; -} - -static void add_goto(struct dmr_C *C, struct entrypoint *ep, struct basic_block *dst) -{ - struct basic_block *src = ep->active; - if (dmrC_bb_reachable(src)) { - struct instruction *br = alloc_instruction(C, OP_BR, 0); - br->bb_true = dst; - dmrC_add_bb(C, &dst->parents, src); - dmrC_add_bb(C, &src->children, dst); - br->bb = src; - dmrC_add_instruction(C, &src->insns, br); - ep->active = NULL; - } -} - -static void add_one_insn(struct dmr_C *C, struct entrypoint *ep, struct instruction *insn) -{ - struct basic_block *bb = ep->active; - - if (dmrC_bb_reachable(bb)) { - insn->bb = bb; - dmrC_add_instruction(C, &bb->insns, insn); - } -} - -static void set_activeblock(struct dmr_C *C, struct entrypoint *ep, struct basic_block *bb) -{ - if (!dmrC_bb_terminated(ep->active)) - add_goto(C, ep, bb); - - ep->active = bb; - if (dmrC_bb_reachable(bb)) - dmrC_add_bb(C, &ep->bbs, bb); -} - -static void remove_parent(struct dmr_C *C, struct basic_block *child, struct basic_block *parent) -{ - dmrC_remove_bb_from_list(&child->parents, parent, 1); - if (!child->parents) - C->L->repeat_phase |= REPEAT_CFG_CLEANUP; -} - -/* Change a "switch" into a branch */ -void dmrC_insert_branch(struct dmr_C *C, struct basic_block *bb, struct instruction *jmp, struct basic_block *target) -{ - struct instruction *br, *old; - struct basic_block *child; - - /* Remove the switch */ - old = dmrC_delete_last_instruction(&bb->insns); - assert(old == jmp); - dmrC_kill_instruction(C, old); - - br = alloc_instruction(C, OP_BR, 0); - br->bb = bb; - br->bb_true = target; - dmrC_add_instruction(C, &bb->insns, br); - - FOR_EACH_PTR(bb->children, child) { - if (child == target) { - target = NULL; /* Trigger just once */ - continue; - } - DELETE_CURRENT_PTR(child); - remove_parent(C, child, bb); - } END_FOR_EACH_PTR(child); - ptrlist_pack((struct ptr_list **)&bb->children); -} - - -void dmrC_insert_select(struct dmr_C *C, struct basic_block *bb, struct instruction *br, struct instruction *phi_node, pseudo_t if_true, pseudo_t if_false) -{ - pseudo_t target; - struct instruction *select; - - /* Remove the 'br' */ - dmrC_delete_last_instruction(&bb->insns); - - select = alloc_typed_instruction(C, OP_SEL, phi_node->type); - select->bb = bb; - - assert(br->cond); - dmrC_use_pseudo(C, select, br->cond, &select->src1); - - target = phi_node->target; - assert(target->def == phi_node); - select->target = target; - target->def = select; - - dmrC_use_pseudo(C, select, if_true, &select->src2); - dmrC_use_pseudo(C, select, if_false, &select->src3); - - dmrC_add_instruction(C, &bb->insns, select); - dmrC_add_instruction(C, &bb->insns, br); -} - -static inline int bb_empty(struct basic_block *bb) -{ - return !bb->insns; -} - -/* Add a label to the currently active block, return new active block */ -static struct basic_block * add_label(struct dmr_C *C, struct entrypoint *ep, struct symbol *label) -{ - struct basic_block *bb = label->bb_target; - - if (bb) { - set_activeblock(C, ep, bb); - return bb; - } - bb = ep->active; - if (!dmrC_bb_reachable(bb) || !bb_empty(bb)) { - bb = alloc_basic_block(C, ep, label->pos); - set_activeblock(C, ep, bb); - } - label->bb_target = bb; - return bb; -} - -static void add_branch(struct dmr_C *C, struct entrypoint *ep, struct expression *expr, pseudo_t cond, struct basic_block *bb_true, struct basic_block *bb_false) -{ - (void)expr; - struct basic_block *bb = ep->active; - struct instruction *br; - - if (dmrC_bb_reachable(bb)) { - br = alloc_instruction(C, OP_CBR, 0); - dmrC_use_pseudo(C, br, cond, &br->cond); - br->bb_true = bb_true; - br->bb_false = bb_false; - dmrC_add_bb(C, &bb_true->parents, bb); - dmrC_add_bb(C, &bb_false->parents, bb); - dmrC_add_bb(C, &bb->children, bb_true); - dmrC_add_bb(C, &bb->children, bb_false); - add_one_insn(C, ep, br); - } -} - -/* Dummy pseudo allocator */ -pseudo_t dmrC_alloc_pseudo(struct dmr_C *C, struct instruction *def) -{ - struct pseudo * pseudo = (pseudo_t)dmrC_allocator_allocate(&C->L->pseudo_allocator, 0); - pseudo->type = PSEUDO_REG; - pseudo->nr = ++C->L->nr; - pseudo->def = def; - return pseudo; -} - -static pseudo_t symbol_pseudo(struct dmr_C *C, struct entrypoint *ep, struct symbol *sym) -{ - pseudo_t pseudo; - - if (!sym) - return VOID_PSEUDO(C); - - pseudo = sym->pseudo; - if (!pseudo) { - pseudo = (pseudo_t)dmrC_allocator_allocate(&C->L->pseudo_allocator, 0); - pseudo->nr = -1; - pseudo->type = PSEUDO_SYM; - pseudo->sym = sym; - pseudo->ident = sym->ident; - sym->pseudo = pseudo; - dmrC_add_pseudo(C, &ep->accesses, pseudo); - } - /* Symbol pseudos have neither nr, usage nor def */ - return pseudo; -} - -unsigned int dmrC_value_size(long long value) -{ - value >>= 8; - if (!value) - return 8; - value >>= 8; - if (!value) - return 16; - value >>= 16; - if (!value) - return 32; - return 64; -} - -pseudo_t dmrC_value_pseudo(struct dmr_C *C, struct symbol *type, long long val) -{ - int hash = val & (MAX_VAL_HASH-1); - struct pseudo_list **list = C->L->prev + hash; - int size = type ? type->bit_size : dmrC_value_size(val); - pseudo_t pseudo; - - assert(size == -1 || size <= (int)(sizeof(long long) * 8)); - - FOR_EACH_PTR(*list, pseudo) { - if (pseudo->value == val && pseudo->size == size) - return pseudo; - } END_FOR_EACH_PTR(pseudo); - - pseudo = (pseudo_t)dmrC_allocator_allocate(&C->L->pseudo_allocator, 0); - pseudo->type = PSEUDO_VAL; - pseudo->value = val; - pseudo->size = size; - dmrC_add_pseudo(C, list, pseudo); - - /* Value pseudos have neither nr, usage nor def */ - return pseudo; -} - -static pseudo_t argument_pseudo(struct dmr_C *C, struct entrypoint *ep, int nr, struct symbol *arg) -{ - pseudo_t pseudo = (pseudo_t)dmrC_allocator_allocate(&C->L->pseudo_allocator, 0); - struct instruction *entry = ep->entry; - - pseudo->type = PSEUDO_ARG; - pseudo->nr = nr; - pseudo->sym = arg; - dmrC_add_pseudo(C, &entry->arg_list, pseudo); - - /* Argument pseudos have neither usage nor def */ - return pseudo; -} - -// From Luc: sssa-mini -struct instruction *dmrC_alloc_phisrc(struct dmr_C *C, pseudo_t pseudo, struct symbol *type) -{ - struct instruction *insn = alloc_typed_instruction(C, OP_PHISOURCE, type); - pseudo_t phi = (pseudo_t)dmrC_allocator_allocate(&C->L->pseudo_allocator, 0); - static int nr = 0; - - phi->type = PSEUDO_PHI; - phi->nr = ++nr; - phi->def = insn; - - dmrC_use_pseudo(C, insn, pseudo, &insn->phi_src); - insn->target = phi; - return insn; -} - -// From Luc: sssa-mini -pseudo_t dmrC_alloc_phi(struct dmr_C *C, struct basic_block *source, pseudo_t pseudo, struct symbol *type) -{ - struct instruction *insn; - - if (!source) - return VOID_PSEUDO(C); - - insn = dmrC_alloc_phisrc(C, pseudo, type); - insn->bb = source; - dmrC_add_instruction(C, &source->insns, insn); - return insn->target; -} - -// From Luc: sssa-mini -pseudo_t dmrC_insert_phi_node(struct dmr_C *C, struct basic_block *bb, struct symbol *type) -{ - struct instruction *phi_node = alloc_typed_instruction(C, OP_PHI, type); - struct instruction *insn; - pseudo_t phi; - - phi = dmrC_alloc_pseudo(C, phi_node); - phi_node->target = phi; - phi_node->bb = bb; - - FOR_EACH_PTR(bb->insns, insn) { - enum opcode op = insn->opcode; - if (op == OP_ENTRY || op == OP_PHI) - continue; - INSERT_CURRENT(phi_node, insn); - return phi; - } END_FOR_EACH_PTR(insn); - - dmrC_add_instruction(C, &bb->insns, phi_node); - return phi; -} - -/* - * We carry the "access_data" structure around for any accesses, - * which simplifies things a lot. It contains all the access - * information in one place. - */ -struct access_data { - struct symbol *result_type; // result ctype - struct symbol *source_type; // source ctype - pseudo_t address; // pseudo containing address .. - unsigned int offset; // byte offset - struct position pos; -}; - -static void finish_address_gen(struct entrypoint *ep, struct access_data *ad) -{ - (void)ep; - (void)ad; -} - -static int linearize_simple_address(struct dmr_C *C, struct entrypoint *ep, - struct expression *addr, - struct access_data *ad) -{ - if (addr->type == EXPR_SYMBOL) { - linearize_one_symbol(C, ep, addr->symbol); - ad->address = symbol_pseudo(C, ep, addr->symbol); - return 1; - } - if (addr->type == EXPR_BINOP) { - if (addr->right->type == EXPR_VALUE) { - if (addr->op == '+') { - ad->offset += (unsigned int) dmrC_get_expression_value(C, addr->right); - return linearize_simple_address(C, ep, addr->left, ad); - } - } - } - ad->address = linearize_expression(C, ep, addr); - return 1; -} - -static struct symbol *base_type(struct dmr_C *C, struct symbol *sym) -{ - (void)C; - struct symbol *base = sym; - - if (sym) { - if (sym->type == SYM_NODE) - base = base->ctype.base_type; - if (base->type == SYM_BITFIELD) - return base->ctype.base_type; - } - return sym; -} - -static int linearize_address_gen(struct dmr_C *C, struct entrypoint *ep, - struct expression *expr, - struct access_data *ad) -{ - struct symbol *ctype = expr->ctype; - - if (!ctype) - return 0; - ad->pos = expr->pos; - ad->result_type = ctype; - ad->source_type = base_type(C, ctype); - if (expr->type == EXPR_PREOP && expr->op == '*') - return linearize_simple_address(C, ep, expr->unop, ad); - - dmrC_warning(C, expr->pos, "generating address of non-lvalue (%d)", expr->type); - return 0; -} - -/* Try to get the actual struct type associated with a load or store */ -static struct symbol *get_base_symbol_type(struct dmr_C *C, struct access_data *ad) { - (void) C; - struct symbol *orig_type = NULL; - if (ad->address->type == PSEUDO_SYM) { - orig_type = ad->address->sym; - } - else if (ad->address->type == PSEUDO_REG) { - if (ad->address->def->opcode == OP_LOAD) { - orig_type = ad->address->def->orig_type; - } - } - if (orig_type) { - if (orig_type->type == SYM_NODE) - orig_type = orig_type->ctype.base_type; - if (orig_type->type == SYM_PTR) - orig_type = orig_type->ctype.base_type; - //dmrC_show_type(C, orig_type); - } - return orig_type; -} - -static pseudo_t add_load(struct dmr_C *C, struct entrypoint *ep, struct access_data *ad) -{ - struct instruction *insn; - pseudo_t new; - - insn = alloc_typed_instruction(C, OP_LOAD, ad->source_type); - /* save the address symbol so that backend can see what symbol we are accessing */ - insn->orig_type = get_base_symbol_type(C, ad); - new = dmrC_alloc_pseudo(C, insn); - - insn->target = new; - insn->offset = ad->offset; - dmrC_use_pseudo(C, insn, ad->address, &insn->src); - add_one_insn(C, ep, insn); - return new; -} - -static void add_store(struct dmr_C *C, struct entrypoint *ep, struct access_data *ad, pseudo_t value) -{ - struct basic_block *bb = ep->active; - if (dmrC_bb_reachable(bb)) { - struct instruction *store = alloc_typed_instruction(C, OP_STORE, ad->source_type); - store->offset = ad->offset; - /* save the address symbol so that backend can see what symbol we are accessing */ - store->orig_type = get_base_symbol_type(C, ad); - dmrC_use_pseudo(C, store, value, &store->target); - dmrC_use_pseudo(C, store, ad->address, &store->src); - add_one_insn(C, ep, store); - } -} - -static pseudo_t linearize_store_gen(struct dmr_C *C, struct entrypoint *ep, - pseudo_t value, - struct access_data *ad) -{ - pseudo_t store = value; - - if (type_size(ad->source_type) != type_size(ad->result_type)) { - struct symbol *ctype = ad->result_type; - unsigned int shift = ctype->bit_offset; - unsigned int size = ctype->bit_size; - pseudo_t orig = add_load(C, ep, ad); - unsigned long long mask = (1ULL << size) - 1; - - if (shift) { - store = add_binary_op(C, ep, ad->source_type, OP_SHL, value, dmrC_value_pseudo(C, ctype, shift)); - mask <<= shift; - } - orig = add_binary_op(C, ep, ad->source_type, OP_AND, orig, dmrC_value_pseudo(C, ctype, ~mask)); - store = add_binary_op(C, ep, ad->source_type, OP_OR, orig, store); - } - add_store(C, ep, ad, store); - return value; -} - -static pseudo_t add_binary_op(struct dmr_C *C, struct entrypoint *ep, struct symbol *ctype, int op, pseudo_t left, pseudo_t right) -{ - struct instruction *insn = alloc_typed_instruction(C, op, ctype); - pseudo_t target = dmrC_alloc_pseudo(C, insn); - insn->target = target; - dmrC_use_pseudo(C, insn, left, &insn->src1); - dmrC_use_pseudo(C, insn, right, &insn->src2); - add_one_insn(C, ep, insn); - return target; -} - -static pseudo_t add_setval(struct dmr_C *C, struct entrypoint *ep, struct symbol *ctype, struct expression *val) -{ - struct instruction *insn = alloc_typed_instruction(C, OP_SETVAL, ctype); - pseudo_t target = dmrC_alloc_pseudo(C, insn); - insn->target = target; - insn->val = val; - add_one_insn(C, ep, insn); - return target; -} - -static pseudo_t add_symbol_address(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - struct instruction *insn = alloc_typed_instruction(C, OP_SYMADDR, expr->ctype); - struct symbol *sym = expr->symbol; - pseudo_t target = dmrC_alloc_pseudo(C, insn); - - insn->target = target; - dmrC_use_pseudo(C, insn, symbol_pseudo(C, ep, sym), &insn->symbol); - add_one_insn(C, ep, insn); - return target; -} - -static pseudo_t linearize_load_gen(struct dmr_C *C, struct entrypoint *ep, struct access_data *ad) -{ - struct symbol *ctype = ad->result_type; - pseudo_t new = add_load(C, ep, ad); - - if (ctype->bit_offset) { - pseudo_t shift = dmrC_value_pseudo(C, ctype, ctype->bit_offset); - pseudo_t newval = add_binary_op(C, ep, ad->source_type, OP_LSR, new, shift); - new = newval; - } - - if (ctype->bit_size != type_size(ad->source_type)) - new = cast_pseudo(C, ep, new, ad->source_type, ad->result_type); - return new; -} - -static pseudo_t linearize_access(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - struct access_data ad; - pseudo_t value; - - memset(&ad, 0, sizeof ad); - if (!linearize_address_gen(C, ep, expr, &ad)) - return VOID_PSEUDO(C); - value = linearize_load_gen(C, ep, &ad); - finish_address_gen(ep, &ad); - return value; -} - -/* FIXME: FP */ -static pseudo_t linearize_inc_dec(struct dmr_C *C, struct entrypoint *ep, struct expression *expr, int postop) -{ - struct access_data ad; - pseudo_t old, new, one; - - memset(&ad, 0, sizeof ad); - int op = expr->op == SPECIAL_INCREMENT ? OP_ADD : OP_SUB; - - if (!linearize_address_gen(C, ep, expr->unop, &ad)) - return VOID_PSEUDO(C); - - old = linearize_load_gen(C, ep, &ad); - one = dmrC_value_pseudo(C, expr->ctype, expr->op_value); - new = add_binary_op(C, ep, expr->ctype, op, old, one); - linearize_store_gen(C, ep, new, &ad); - finish_address_gen(ep, &ad); - return postop ? old : new; -} - -static pseudo_t add_uniop(struct dmr_C *C, struct entrypoint *ep, struct expression *expr, int op, pseudo_t src) -{ - struct instruction *insn = alloc_typed_instruction(C, op, expr->ctype); - pseudo_t new = dmrC_alloc_pseudo(C, insn); - - insn->target = new; - dmrC_use_pseudo(C, insn, src, &insn->src1); - add_one_insn(C, ep, insn); - return new; -} - -static pseudo_t linearize_slice(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - pseudo_t pre = linearize_expression(C, ep, expr->base); - struct instruction *insn = alloc_typed_instruction(C, OP_SLICE, expr->ctype); - pseudo_t new = dmrC_alloc_pseudo(C, insn); - - insn->target = new; - insn->from = expr->r_bitpos; - insn->len = expr->r_nrbits; - dmrC_use_pseudo(C, insn, pre, &insn->base); - add_one_insn(C, ep, insn); - return new; -} - -static pseudo_t linearize_regular_preop(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - pseudo_t pre = linearize_expression(C, ep, expr->unop); - switch (expr->op) { - case '+': - return pre; - case '!': { - pseudo_t zero = dmrC_value_pseudo(C, expr->ctype, 0); - return add_binary_op(C, ep, expr->ctype, OP_SET_EQ, pre, zero); - } - case '~': - return add_uniop(C, ep, expr, OP_NOT, pre); - case '-': - return add_uniop(C, ep, expr, OP_NEG, pre); - } - return VOID_PSEUDO(C); -} - -static pseudo_t linearize_preop(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - /* - * '*' is an lvalue access, and is fundamentally different - * from an arithmetic operation. Maybe it should have an - * expression type of its own.. - */ - if (expr->op == '*') - return linearize_access(C, ep, expr); - if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT) - return linearize_inc_dec(C, ep, expr, 0); - return linearize_regular_preop(C, ep, expr); -} - -static pseudo_t linearize_postop(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - return linearize_inc_dec(C, ep, expr, 1); -} - -/* - * Casts to pointers are "less safe" than other casts, since - * they imply type-unsafe accesses. "void *" is a special - * case, since you can't access through it anyway without another - * cast. - */ -static struct instruction *alloc_cast_instruction(struct dmr_C *C, struct symbol *src, struct symbol *ctype) -{ - int opcode = OP_CAST; - // https://patchwork.kernel.org/patch/9516077/ - struct symbol *base = ctype; - - if (src->ctype.modifiers & MOD_SIGNED) - opcode = OP_SCAST; - if (base->type == SYM_NODE) - base = base->ctype.base_type; - if (base->type == SYM_PTR) { - base = base->ctype.base_type; - if (base != &C->S->void_ctype) - opcode = OP_PTRCAST; - } else if (base->ctype.base_type == &C->S->fp_type) - opcode = OP_FPCAST; - return alloc_typed_instruction(C, opcode, ctype); -} - -static pseudo_t cast_pseudo(struct dmr_C *C, struct entrypoint *ep, pseudo_t src, struct symbol *from, struct symbol *to) -{ - pseudo_t result; - struct instruction *insn; - - if (src == VOID_PSEUDO(C)) - return VOID_PSEUDO(C); - if (!from || !to) - return VOID_PSEUDO(C); - if (from->bit_size < 0 || to->bit_size < 0) - return VOID_PSEUDO(C); - insn = alloc_cast_instruction(C, from, to); - result = dmrC_alloc_pseudo(C, insn); - insn->target = result; - insn->orig_type = from; - dmrC_use_pseudo(C, insn, src, &insn->src); - add_one_insn(C, ep, insn); - return result; -} - -static int opcode_sign(struct dmr_C *C, int opcode, struct symbol *ctype) -{ - (void)C; - if (ctype && (ctype->ctype.modifiers & MOD_SIGNED)) { - switch(opcode) { - case OP_MULU: case OP_DIVU: case OP_MODU: case OP_LSR: - opcode++; - } - } - return opcode; -} - -static inline pseudo_t add_convert_to_bool(struct dmr_C *C, struct entrypoint *ep, pseudo_t src, struct symbol *type) -{ - pseudo_t zero; - int op; - - if (dmrC_is_bool_type(C->S, type)) - return src; - zero = dmrC_value_pseudo(C, type, 0); - op = OP_SET_NE; - return add_binary_op(C, ep, &C->S->bool_ctype, op, src, zero); -} - -static pseudo_t linearize_expression_to_bool(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - pseudo_t dst; - dst = linearize_expression(C, ep, expr); - dst = add_convert_to_bool(C, ep, dst, expr->ctype); - return dst; -} -static pseudo_t linearize_assignment(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - struct access_data ad; - struct expression *target = expr->left; - struct expression *src = expr->right; - struct symbol *ctype; - pseudo_t value; - - memset(&ad, 0, sizeof ad); - value = linearize_expression(C, ep, src); - if (!target || !linearize_address_gen(C, ep, target, &ad)) - return value; - if (expr->op != '=') { - pseudo_t oldvalue = linearize_load_gen(C, ep, &ad); - pseudo_t dst; - static const int op_trans[] = { - [SPECIAL_ADD_ASSIGN - SPECIAL_BASE] = OP_ADD, - [SPECIAL_SUB_ASSIGN - SPECIAL_BASE] = OP_SUB, - [SPECIAL_MUL_ASSIGN - SPECIAL_BASE] = OP_MULU, - [SPECIAL_DIV_ASSIGN - SPECIAL_BASE] = OP_DIVU, - [SPECIAL_MOD_ASSIGN - SPECIAL_BASE] = OP_MODU, - [SPECIAL_SHL_ASSIGN - SPECIAL_BASE] = OP_SHL, - [SPECIAL_SHR_ASSIGN - SPECIAL_BASE] = OP_LSR, - [SPECIAL_AND_ASSIGN - SPECIAL_BASE] = OP_AND, - [SPECIAL_OR_ASSIGN - SPECIAL_BASE] = OP_OR, - [SPECIAL_XOR_ASSIGN - SPECIAL_BASE] = OP_XOR - }; - int opcode; - - if (!src) - return VOID_PSEUDO(C); - - ctype = src->ctype; - oldvalue = cast_pseudo(C, ep, oldvalue, target->ctype, ctype); - opcode = opcode_sign(C, op_trans[expr->op - SPECIAL_BASE], ctype); - dst = add_binary_op(C, ep, ctype, opcode, oldvalue, value); - - value = cast_pseudo(C, ep, dst, ctype, expr->ctype); - } - value = linearize_store_gen(C, ep, value, &ad); - finish_address_gen(ep, &ad); - return value; -} - -static pseudo_t linearize_call_expression(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - struct expression *arg, *fn; - struct instruction *insn = alloc_typed_instruction(C, OP_CALL, expr->ctype); - pseudo_t retval, call; - struct ctype *ctype = NULL; - struct symbol *fntype; - struct context *context; - - if (!expr->ctype) { - dmrC_warning(C, expr->pos, "call with no type!"); - return VOID_PSEUDO(C); - } - - // first generate all the parameters - FOR_EACH_PTR(expr->args, arg) { - pseudo_t new = linearize_expression(C, ep, arg); - dmrC_use_pseudo(C, insn, new, dmrC_add_pseudo(C, &insn->arguments, new)); - } END_FOR_EACH_PTR(arg); - - fn = expr->fn; - - if (fn->ctype) - ctype = &fn->ctype->ctype; - - fntype = fn->ctype; - if (fntype) { - if (fntype->type == SYM_NODE) - fntype = fntype->ctype.base_type; - } - insn->fntype = fntype; - - if (fn->type == EXPR_PREOP) { - if (fn->unop->type == EXPR_SYMBOL) { - struct symbol *sym = fn->unop->symbol; - if (sym->ctype.base_type->type == SYM_FN) - fn = fn->unop; - } - } - if (fn->type == EXPR_SYMBOL) { - call = symbol_pseudo(C, ep, fn->symbol); - } else { - call = linearize_expression(C, ep, fn); - } - dmrC_use_pseudo(C, insn, call, &insn->func); - retval = VOID_PSEUDO(C); - if (expr->ctype != &C->S->void_ctype) - retval = dmrC_alloc_pseudo(C, insn); - insn->target = retval; - add_one_insn(C, ep, insn); - - if (ctype) { - FOR_EACH_PTR(ctype->contexts, context) { - int in = context->in; - int out = context->out; - int check = 0; - int context_diff; - if (in < 0) { - check = 1; - in = 0; - } - if (out < 0) { - check = 0; - out = 0; - } - context_diff = out - in; - if (check || context_diff) { - insn = alloc_instruction(C, OP_CONTEXT, 0); - insn->increment = context_diff; - insn->check = check; - insn->context_expr = context->context_expr; - add_one_insn(C, ep, insn); - } - } END_FOR_EACH_PTR(context); - } - - return retval; -} - -static pseudo_t linearize_binop_bool(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - pseudo_t src1, src2, dst; - int op = (expr->op == SPECIAL_LOGICAL_OR) ? OP_OR_BOOL : OP_AND_BOOL; - - src1 = linearize_expression_to_bool(C, ep, expr->left); - src2 = linearize_expression_to_bool(C, ep, expr->right); - dst = add_binary_op(C, ep, &C->S->bool_ctype, op, src1, src2); - if (expr->ctype != &C->S->bool_ctype) - dst = cast_pseudo(C, ep, dst, &C->S->bool_ctype, expr->ctype); - return dst; -} -static pseudo_t linearize_binop(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - pseudo_t src1, src2, dst; - static const int opcode[] = { - ['+'] = OP_ADD, ['-'] = OP_SUB, - ['*'] = OP_MULU, ['/'] = OP_DIVU, - ['%'] = OP_MODU, ['&'] = OP_AND, - ['|'] = OP_OR, ['^'] = OP_XOR, - [SPECIAL_LEFTSHIFT] = OP_SHL, - [SPECIAL_RIGHTSHIFT] = OP_LSR, - }; - int op; - - src1 = linearize_expression(C, ep, expr->left); - src2 = linearize_expression(C, ep, expr->right); - op = opcode_sign(C, opcode[expr->op], expr->ctype); - dst = add_binary_op(C, ep, expr->ctype, op, src1, src2); - return dst; -} - -static pseudo_t linearize_logical_branch(struct dmr_C *C, struct entrypoint *ep, struct expression *expr, struct basic_block *bb_true, struct basic_block *bb_false); - -static pseudo_t linearize_cond_branch(struct dmr_C *C, struct entrypoint *ep, struct expression *expr, struct basic_block *bb_true, struct basic_block *bb_false); - -static pseudo_t linearize_select(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - pseudo_t cond, true, false, res; - struct instruction *insn; - - true = linearize_expression(C, ep, expr->cond_true); - false = linearize_expression(C, ep, expr->cond_false); - cond = linearize_expression(C, ep, expr->conditional); - - insn = alloc_typed_instruction(C, OP_SEL, expr->ctype); - if (!expr->cond_true) - true = cond; - dmrC_use_pseudo(C, insn, cond, &insn->src1); - dmrC_use_pseudo(C, insn, true, &insn->src2); - dmrC_use_pseudo(C, insn, false, &insn->src3); - - res = dmrC_alloc_pseudo(C, insn); - insn->target = res; - add_one_insn(C, ep, insn); - return res; -} - -static pseudo_t add_join_conditional(struct dmr_C *C, struct entrypoint *ep, struct expression *expr, - pseudo_t phi1, pseudo_t phi2) -{ - pseudo_t target; - struct instruction *phi_node; - - if (phi1 == VOID_PSEUDO(C)) - return phi2; - if (phi2 == VOID_PSEUDO(C)) - return phi1; - - phi_node = alloc_typed_instruction(C, OP_PHI, expr->ctype); - dmrC_use_pseudo(C, phi_node, phi1, dmrC_add_pseudo(C, &phi_node->phi_list, phi1)); - dmrC_use_pseudo(C, phi_node, phi2, dmrC_add_pseudo(C, &phi_node->phi_list, phi2)); - phi_node->target = target = dmrC_alloc_pseudo(C, phi_node); - add_one_insn(C, ep, phi_node); - return target; -} - -static pseudo_t linearize_short_conditional(struct dmr_C *C, struct entrypoint *ep, struct expression *expr, - struct expression *cond, - struct expression *expr_false) -{ - pseudo_t src1, src2; - struct basic_block *bb_false; - struct basic_block *merge = alloc_basic_block(C, ep, expr->pos); - pseudo_t phi1, phi2; - - if (!expr_false || !ep->active) - return VOID_PSEUDO(C); - - bb_false = alloc_basic_block(C, ep, expr_false->pos); - src1 = linearize_expression(C, ep, cond); - phi1 = dmrC_alloc_phi(C, ep->active, src1, expr->ctype); - add_branch(C, ep, expr, src1, merge, bb_false); - - set_activeblock(C, ep, bb_false); - src2 = linearize_expression(C, ep, expr_false); - phi2 = dmrC_alloc_phi(C, ep->active, src2, expr->ctype); - set_activeblock(C, ep, merge); - - return add_join_conditional(C, ep, expr, phi1, phi2); -} - -static pseudo_t linearize_conditional(struct dmr_C *C, struct entrypoint *ep, struct expression *expr, - struct expression *cond, - struct expression *expr_true, - struct expression *expr_false) -{ - pseudo_t src1, src2; - pseudo_t phi1, phi2; - struct basic_block *bb_true, *bb_false, *merge; - - if (!cond || !expr_true || !expr_false || !ep->active) - return VOID_PSEUDO(C); - bb_true = alloc_basic_block(C, ep, expr_true->pos); - bb_false = alloc_basic_block(C, ep, expr_false->pos); - merge = alloc_basic_block(C, ep, expr->pos); - - linearize_cond_branch(C, ep, cond, bb_true, bb_false); - - set_activeblock(C, ep, bb_true); - src1 = linearize_expression(C, ep, expr_true); - phi1 = dmrC_alloc_phi(C, ep->active, src1, expr->ctype); - add_goto(C, ep, merge); - - set_activeblock(C, ep, bb_false); - src2 = linearize_expression(C, ep, expr_false); - phi2 = dmrC_alloc_phi(C, ep->active, src2, expr->ctype); - set_activeblock(C, ep, merge); - - return add_join_conditional(C, ep, expr, phi1, phi2); -} - -static pseudo_t linearize_logical(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - struct expression *shortcut; - - shortcut = dmrC_alloc_const_expression(C, expr->pos, expr->op == SPECIAL_LOGICAL_OR); - shortcut->ctype = expr->ctype; - if (expr->op == SPECIAL_LOGICAL_OR) - return linearize_conditional(C, ep, expr, expr->left, shortcut, expr->right); - return linearize_conditional(C, ep, expr, expr->left, expr->right, shortcut); -} - -static pseudo_t linearize_compare(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - static const int cmpop[] = { - ['>'] = OP_SET_GT, ['<'] = OP_SET_LT, - [SPECIAL_EQUAL] = OP_SET_EQ, - [SPECIAL_NOTEQUAL] = OP_SET_NE, - [SPECIAL_GTE] = OP_SET_GE, - [SPECIAL_LTE] = OP_SET_LE, - [SPECIAL_UNSIGNED_LT] = OP_SET_B, - [SPECIAL_UNSIGNED_GT] = OP_SET_A, - [SPECIAL_UNSIGNED_LTE] = OP_SET_BE, - [SPECIAL_UNSIGNED_GTE] = OP_SET_AE, - }; - - pseudo_t src1 = linearize_expression(C, ep, expr->left); - pseudo_t src2 = linearize_expression(C, ep, expr->right); - pseudo_t dst = add_binary_op(C, ep, expr->ctype, cmpop[expr->op], src1, src2); - return dst; -} - - -static pseudo_t linearize_cond_branch(struct dmr_C *C, struct entrypoint *ep, struct expression *expr, struct basic_block *bb_true, struct basic_block *bb_false) -{ - pseudo_t cond; - - if (!expr || !dmrC_bb_reachable(ep->active)) - return VOID_PSEUDO(C); - - switch (expr->type) { - - case EXPR_STRING: - case EXPR_VALUE: - add_goto(C, ep, expr->value ? bb_true : bb_false); - return VOID_PSEUDO(C); - - case EXPR_FVALUE: - add_goto(C, ep, expr->fvalue ? bb_true : bb_false); - return VOID_PSEUDO(C); - - case EXPR_LOGICAL: - linearize_logical_branch(C, ep, expr, bb_true, bb_false); - return VOID_PSEUDO(C); - - case EXPR_COMPARE: - cond = linearize_compare(C, ep, expr); - add_branch(C, ep, expr, cond, bb_true, bb_false); - break; - - case EXPR_PREOP: - if (expr->op == '!') - return linearize_cond_branch(C, ep, expr->unop, bb_false, bb_true); - /* fall through */ - default: { - cond = linearize_expression(C, ep, expr); - add_branch(C, ep, expr, cond, bb_true, bb_false); - - return VOID_PSEUDO(C); - } - } - return VOID_PSEUDO(C); -} - - - -static pseudo_t linearize_logical_branch(struct dmr_C *C, struct entrypoint *ep, struct expression *expr, struct basic_block *bb_true, struct basic_block *bb_false) -{ - struct basic_block *next = alloc_basic_block(C, ep, expr->pos); - - if (expr->op == SPECIAL_LOGICAL_OR) - linearize_cond_branch(C, ep, expr->left, bb_true, next); - else - linearize_cond_branch(C, ep, expr->left, next, bb_false); - set_activeblock(C, ep, next); - linearize_cond_branch(C, ep, expr->right, bb_true, bb_false); - return VOID_PSEUDO(C); -} - -static pseudo_t linearize_cast(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - pseudo_t src; - struct expression *orig = expr->cast_expression; - - if (!orig) - return VOID_PSEUDO(C); - - src = linearize_expression(C, ep, orig); - return cast_pseudo(C, ep, src, orig->ctype, expr->ctype); -} - -static pseudo_t linearize_position(struct dmr_C *C, struct entrypoint *ep, struct expression *pos, struct access_data *ad) -{ - struct expression *init_expr = pos->init_expr; - - ad->offset = pos->init_offset; - ad->source_type = base_type(C, init_expr->ctype); - ad->result_type = init_expr->ctype; - return linearize_initializer(C, ep, init_expr, ad); -} - -static pseudo_t linearize_initializer(struct dmr_C *C, struct entrypoint *ep, struct expression *initializer, struct access_data *ad) -{ - switch (initializer->type) { - case EXPR_INITIALIZER: { - struct expression *expr; - FOR_EACH_PTR(initializer->expr_list, expr) { - linearize_initializer(C, ep, expr, ad); - } END_FOR_EACH_PTR(expr); - break; - } - case EXPR_POS: - linearize_position(C, ep, initializer, ad); - break; - default: { - pseudo_t value = linearize_expression(C, ep, initializer); - ad->source_type = base_type(C, initializer->ctype); - ad->result_type = initializer->ctype; - linearize_store_gen(C, ep, value, ad); - return value; - } - } - - return VOID_PSEUDO(C); -} - -static void linearize_argument(struct dmr_C *C, struct entrypoint *ep, struct symbol *arg, int nr) -{ - struct access_data ad; - - memset(&ad, 0, sizeof ad); - ad.source_type = arg; - ad.result_type = arg; - ad.address = symbol_pseudo(C, ep, arg); - linearize_store_gen(C, ep, argument_pseudo(C, ep, nr, arg), &ad); - finish_address_gen(ep, &ad); -} - -static pseudo_t linearize_expression(struct dmr_C *C, struct entrypoint *ep, struct expression *expr) -{ - if (!expr) - return VOID_PSEUDO(C); - - C->L->current_pos = expr->pos; - switch (expr->type) { - case EXPR_SYMBOL: - linearize_one_symbol(C, ep, expr->symbol); - return add_symbol_address(C, ep, expr); - - case EXPR_VALUE: - return dmrC_value_pseudo(C, expr->ctype, expr->value); - - case EXPR_STRING: case EXPR_FVALUE: case EXPR_LABEL: - return add_setval(C, ep, expr->ctype, expr); - - case EXPR_STATEMENT: - return linearize_statement(C, ep, expr->statement); - - case EXPR_CALL: - return linearize_call_expression(C, ep, expr); - - case EXPR_BINOP: - if (expr->op == SPECIAL_LOGICAL_AND || expr->op == SPECIAL_LOGICAL_OR) - return linearize_binop_bool(C, ep, expr); - return linearize_binop(C, ep, expr); - - case EXPR_LOGICAL: - return linearize_logical(C, ep, expr); - - case EXPR_COMPARE: - return linearize_compare(C, ep, expr); - - case EXPR_SELECT: - return linearize_select(C, ep, expr); - - case EXPR_CONDITIONAL: - if (!expr->cond_true) - return linearize_short_conditional(C, ep, expr, expr->conditional, expr->cond_false); - - return linearize_conditional(C, ep, expr, expr->conditional, - expr->cond_true, expr->cond_false); - - case EXPR_COMMA: - linearize_expression(C, ep, expr->left); - return linearize_expression(C, ep, expr->right); - - case EXPR_ASSIGNMENT: - return linearize_assignment(C, ep, expr); - - case EXPR_PREOP: - return linearize_preop(C, ep, expr); - - case EXPR_POSTOP: - return linearize_postop(C, ep, expr); - - case EXPR_CAST: - case EXPR_FORCE_CAST: - case EXPR_IMPLIED_CAST: - return linearize_cast(C, ep, expr); - - case EXPR_SLICE: - return linearize_slice(C, ep, expr); - - case EXPR_INITIALIZER: - case EXPR_POS: - dmrC_warning(C, expr->pos, "unexpected initializer expression (%d %d)", expr->type, expr->op); - return VOID_PSEUDO(C); - default: - dmrC_warning(C, expr->pos, "unknown expression (%d %d)", expr->type, expr->op); - return VOID_PSEUDO(C); - } - return VOID_PSEUDO(C); -} - -static pseudo_t linearize_one_symbol(struct dmr_C *C, struct entrypoint *ep, struct symbol *sym) -{ - struct access_data ad; - pseudo_t value; - - memset(&ad, 0, sizeof ad); - if (!sym || !sym->initializer || sym->initialized) - return VOID_PSEUDO(C); - - /* We need to output these puppies some day too.. */ - if (sym->ctype.modifiers & (MOD_STATIC | MOD_TOPLEVEL)) - return VOID_PSEUDO(C); - - sym->initialized = 1; - ad.address = symbol_pseudo(C, ep, sym); - value = linearize_initializer(C, ep, sym->initializer, &ad); - finish_address_gen(ep, &ad); - return value; -} - -static pseudo_t linearize_compound_statement(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt) -{ - pseudo_t pseudo; - struct statement *s; - struct symbol *ret = stmt->ret; - - pseudo = VOID_PSEUDO(C); - FOR_EACH_PTR(stmt->stmts, s) { - pseudo = linearize_statement(C, ep, s); - } END_FOR_EACH_PTR(s); - - if (ret) { - struct basic_block *bb = add_label(C, ep, ret); - struct instruction *phi_node = dmrC_first_instruction(bb->insns); - - if (!phi_node) - return pseudo; -#if 0 - /* https://github.com/lucvoo/sparse/commit/1609176c9 */ - if (dmrC_pseudo_list_size(phi_node->phi_list)==1) { - pseudo = dmrC_first_pseudo(phi_node->phi_list); - assert(pseudo->type == PSEUDO_PHI); - return pseudo->def->src1; - } -#endif - return phi_node->target; - } - - return pseudo; -} - -static pseudo_t linearize_inlined_call(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt) -{ - struct instruction *insn = alloc_instruction(C, OP_INLINED_CALL, 0); - struct statement *args = stmt->args; - struct basic_block *bb; - pseudo_t pseudo; - - if (args) { - struct symbol *sym; - - dmrC_concat_symbol_list(args->declaration, &ep->syms); - FOR_EACH_PTR(args->declaration, sym) { - pseudo_t value = linearize_one_symbol(C, ep, sym); - dmrC_use_pseudo(C, insn, value, dmrC_add_pseudo(C, &insn->arguments, value)); - } END_FOR_EACH_PTR(sym); - } - - insn->target = pseudo = linearize_compound_statement(C, ep, stmt); - dmrC_use_pseudo(C, insn, symbol_pseudo(C, ep, stmt->inline_fn), &insn->func); - bb = ep->active; - if (bb && !bb->insns) - bb->pos = stmt->pos; - add_one_insn(C, ep, insn); - return pseudo; -} - -static pseudo_t linearize_context(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt) -{ - struct instruction *insn = alloc_instruction(C, OP_CONTEXT, 0); - struct expression *expr = stmt->expression; - int value = 0; - - if (expr->type == EXPR_VALUE) - value = (int) expr->value; - - insn->increment = value; - insn->context_expr = stmt->context; - add_one_insn(C, ep, insn); - return VOID_PSEUDO(C); -} - -static pseudo_t linearize_range(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt) -{ - struct instruction *insn = alloc_instruction(C, OP_RANGE, 0); - - dmrC_use_pseudo(C, insn, linearize_expression(C, ep, stmt->range_expression), &insn->src1); - dmrC_use_pseudo(C, insn, linearize_expression(C, ep, stmt->range_low), &insn->src2); - dmrC_use_pseudo(C, insn, linearize_expression(C, ep, stmt->range_high), &insn->src3); - add_one_insn(C, ep, insn); - return VOID_PSEUDO(C); -} - -static void add_asm_input(struct dmr_C *C, struct entrypoint *ep, struct instruction *insn, struct expression *expr, - const char *constraint, const struct ident *ident) -{ - pseudo_t pseudo = linearize_expression(C, ep, expr); - struct asm_constraint *rule = (struct asm_constraint *)dmrC_allocator_allocate(&C->L->asm_constraint_allocator, 0); - - rule->ident = ident; - rule->constraint = constraint; - dmrC_use_pseudo(C, insn, pseudo, &rule->pseudo); - ptrlist_add((struct ptr_list **)&insn->asm_rules->inputs, rule, &C->ptrlist_allocator); -} - -static void add_asm_output(struct dmr_C *C, struct entrypoint *ep, struct instruction *insn, struct expression *expr, - const char *constraint, const struct ident *ident) -{ - struct access_data ad; - pseudo_t pseudo = dmrC_alloc_pseudo(C, insn); - struct asm_constraint *rule; - - memset(&ad, 0, sizeof ad); - if (!expr || !linearize_address_gen(C, ep, expr, &ad)) - return; - linearize_store_gen(C, ep, pseudo, &ad); - finish_address_gen(ep, &ad); - rule = (struct asm_constraint *) dmrC_allocator_allocate(&C->L->asm_constraint_allocator, 0); - rule->ident = ident; - rule->constraint = constraint; - dmrC_use_pseudo(C, insn, pseudo, &rule->pseudo); - ptrlist_add((struct ptr_list **)&insn->asm_rules->outputs, rule, &C->ptrlist_allocator); -} - -static pseudo_t linearize_asm_statement(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt) -{ - int state; - struct expression *expr; - struct instruction *insn; - struct asm_rules *rules; - const char *constraint; - struct ident *ident; - - insn = alloc_instruction(C, OP_ASM, 0); - expr = stmt->asm_string; - if (!expr || expr->type != EXPR_STRING) { - dmrC_warning(C, stmt->pos, "expected string in inline asm"); - return VOID_PSEUDO(C); - } - insn->string = expr->string->data; - - rules = (struct asm_rules *) dmrC_allocator_allocate(&C->L->asm_rules_allocator, 0); - insn->asm_rules = rules; - - /* Gather the inputs.. */ - state = 0; - ident = NULL; - constraint = NULL; - FOR_EACH_PTR(stmt->asm_inputs, expr) { - switch (state) { - case 0: /* Identifier */ - state = 1; - ident = (struct ident *)expr; - continue; - - case 1: /* Constraint */ - state = 2; - constraint = expr ? expr->string->data : ""; - continue; - - case 2: /* Expression */ - state = 0; - add_asm_input(C, ep, insn, expr, constraint, ident); - } - } END_FOR_EACH_PTR(expr); - - add_one_insn(C, ep, insn); - - /* Assign the outputs */ - state = 0; - ident = NULL; - constraint = NULL; - FOR_EACH_PTR(stmt->asm_outputs, expr) { - switch (state) { - case 0: /* Identifier */ - state = 1; - ident = (struct ident *)expr; - continue; - - case 1: /* Constraint */ - state = 2; - constraint = expr ? expr->string->data : ""; - continue; - - case 2: - state = 0; - add_asm_output(C, ep, insn, expr, constraint, ident); - } - } END_FOR_EACH_PTR(expr); - - return VOID_PSEUDO(C); -} - -static int multijmp_cmp(void *ud, const void *_a, const void *_b) -{ - (void) ud; - const struct multijmp *a = (const struct multijmp *)_a; - const struct multijmp *b = (const struct multijmp *)_b; - - // "default" case? - if (a->begin > a->end) { - if (b->begin > b->end) - return 0; - return 1; - } - if (b->begin > b->end) - return -1; - if (a->begin == b->begin) { - if (a->end == b->end) - return 0; - return (a->end < b->end) ? -1 : 1; - } - return a->begin < b->begin ? -1 : 1; -} - -static void sort_switch_cases(struct dmr_C *C, struct instruction *insn) -{ - ptrlist_sort((struct ptr_list **)&insn->multijmp_list, C, multijmp_cmp); -} - -static pseudo_t linearize_declaration(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt) -{ - struct symbol *sym; - - dmrC_concat_symbol_list(stmt->declaration, &ep->syms); - - FOR_EACH_PTR(stmt->declaration, sym) { - linearize_one_symbol(C, ep, sym); - } END_FOR_EACH_PTR(sym); - return VOID_PSEUDO(C); -} - -static pseudo_t linearize_return(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt) -{ - struct expression *expr = stmt->expression; - struct basic_block *bb_return = get_bound_block(C, ep, stmt->ret_target); - struct basic_block *active; - pseudo_t src = linearize_expression(C, ep, expr); - active = ep->active; - if (active && src != VOID_PSEUDO(C)) { - struct instruction *phi_node = dmrC_first_instruction(bb_return->insns); - pseudo_t phi; - if (!phi_node) { - phi_node = alloc_typed_instruction(C, OP_PHI, expr->ctype); - phi_node->target = dmrC_alloc_pseudo(C, phi_node); - phi_node->bb = bb_return; - dmrC_add_instruction(C, &bb_return->insns, phi_node); - } - phi = dmrC_alloc_phi(C, active, src, expr->ctype); - phi->ident = C->S->return_ident; - dmrC_use_pseudo(C, phi_node, phi, dmrC_add_pseudo(C, &phi_node->phi_list, phi)); - } - add_goto(C, ep, bb_return); - return VOID_PSEUDO(C); -} - -static pseudo_t linearize_switch(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt) -{ - struct symbol *sym; - struct instruction *switch_ins; - struct basic_block *switch_end = alloc_basic_block(C, ep, stmt->pos); - struct basic_block *active, *default_case; - struct expression *expr = stmt->switch_expression; - struct multijmp *jmp; - pseudo_t pseudo; - - pseudo = linearize_expression(C, ep, expr); - - active = ep->active; - if (!dmrC_bb_reachable(active)) - return VOID_PSEUDO(C); - - switch_ins = alloc_typed_instruction(C, OP_SWITCH, expr->ctype); - dmrC_use_pseudo(C, switch_ins, pseudo, &switch_ins->cond); - add_one_insn(C, ep, switch_ins); - finish_block(ep); - - default_case = NULL; - FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) { - struct statement *case_stmt = sym->stmt; - struct basic_block *bb_case = get_bound_block(C, ep, sym); - - if (!case_stmt->case_expression) { - default_case = bb_case; - continue; - } else { - long long begin, end; - - begin = end = case_stmt->case_expression->value; - if (case_stmt->case_to) - end = case_stmt->case_to->value; - if (begin > end) - jmp = alloc_multijmp(C, bb_case, end, begin); - else - jmp = alloc_multijmp(C, bb_case, begin, end); - - } - dmrC_add_multijmp(C, &switch_ins->multijmp_list, jmp); - dmrC_add_bb(C, &bb_case->parents, active); - dmrC_add_bb(C, &active->children, bb_case); - } END_FOR_EACH_PTR(sym); - - bind_label(C, stmt->switch_break, switch_end, stmt->pos); - - /* And linearize the actual statement */ - linearize_statement(C, ep, stmt->switch_statement); - set_activeblock(C, ep, switch_end); - - if (!default_case) - default_case = switch_end; - - jmp = alloc_multijmp(C, default_case, 1, 0); - dmrC_add_multijmp(C, &switch_ins->multijmp_list, jmp); - dmrC_add_bb(C, &default_case->parents, active); - dmrC_add_bb(C, &active->children, default_case); - sort_switch_cases(C, switch_ins); - - return VOID_PSEUDO(C); -} - -static pseudo_t linearize_iterator(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt) -{ - struct statement *pre_statement = stmt->iterator_pre_statement; - struct expression *pre_condition = stmt->iterator_pre_condition; - struct statement *statement = stmt->iterator_statement; - struct statement *post_statement = stmt->iterator_post_statement; - struct expression *post_condition = stmt->iterator_post_condition; - struct basic_block *loop_top, *loop_body, *loop_continue, *loop_end; - struct symbol *sym; - - FOR_EACH_PTR(stmt->iterator_syms, sym) { - linearize_one_symbol(C, ep, sym); - } END_FOR_EACH_PTR(sym); - - dmrC_concat_symbol_list(stmt->iterator_syms, &ep->syms); - linearize_statement(C, ep, pre_statement); - - loop_body = loop_top = alloc_basic_block(C, ep, stmt->pos); - loop_continue = alloc_basic_block(C, ep, stmt->pos); - loop_end = alloc_basic_block(C, ep, stmt->pos); - - /* An empty post-condition means that it's the same as the pre-condition */ - if (!post_condition) { - loop_top = alloc_basic_block(C, ep, stmt->pos); - set_activeblock(C, ep, loop_top); - } - - if (pre_condition) - linearize_cond_branch(C, ep, pre_condition, loop_body, loop_end); - - bind_label(C, stmt->iterator_continue, loop_continue, stmt->pos); - bind_label(C, stmt->iterator_break, loop_end, stmt->pos); - - set_activeblock(C, ep, loop_body); - linearize_statement(C, ep, statement); - add_goto(C, ep, loop_continue); - - set_activeblock(C, ep, loop_continue); - linearize_statement(C, ep, post_statement); - if (!post_condition) - add_goto(C, ep, loop_top); - else - linearize_cond_branch(C, ep, post_condition, loop_top, loop_end); - set_activeblock(C, ep, loop_end); - - return VOID_PSEUDO(C); -} - -static pseudo_t linearize_statement(struct dmr_C *C, struct entrypoint *ep, struct statement *stmt) -{ - struct basic_block *bb; - - if (!stmt) - return VOID_PSEUDO(C); - - bb = ep->active; - if (bb && !bb->insns) - bb->pos = stmt->pos; - C->L->current_pos = stmt->pos; - - switch (stmt->type) { - case STMT_NONE: - break; - - case STMT_DECLARATION: - return linearize_declaration(C, ep, stmt); - - case STMT_CONTEXT: - return linearize_context(C, ep, stmt); - - case STMT_RANGE: - return linearize_range(C, ep, stmt); - - case STMT_EXPRESSION: - return linearize_expression(C, ep, stmt->expression); - - case STMT_ASM: - return linearize_asm_statement(C, ep, stmt); - - case STMT_RETURN: - return linearize_return(C, ep, stmt); - - case STMT_CASE: { - add_label(C, ep, stmt->case_label); - linearize_statement(C, ep, stmt->case_statement); - break; - } - - case STMT_LABEL: { - struct symbol *label = stmt->label_identifier; - - if (label->used) { - bb = add_label(C, ep, label); - } - return linearize_statement(C, ep, stmt->label_statement); - } - - case STMT_GOTO: { - struct symbol *sym; - struct expression *expr; - struct instruction *goto_ins; - struct basic_block *active; - pseudo_t pseudo; - - active = ep->active; - if (!dmrC_bb_reachable(active)) - break; - - if (stmt->goto_label) { - add_goto(C, ep, get_bound_block(C, ep, stmt->goto_label)); - break; - } - - expr = stmt->goto_expression; - if (!expr) - break; - - /* This can happen as part of simplification */ - if (expr->type == EXPR_LABEL) { - add_goto(C, ep, get_bound_block(C, ep, expr->label_symbol)); - break; - } - - pseudo = linearize_expression(C, ep, expr); - goto_ins = alloc_instruction(C, OP_COMPUTEDGOTO, 0); - dmrC_use_pseudo(C, goto_ins, pseudo, &goto_ins->target); - add_one_insn(C, ep, goto_ins); - - FOR_EACH_PTR(stmt->target_list, sym) { - struct basic_block *bb_computed = get_bound_block(C, ep, sym); - struct multijmp *jmp = alloc_multijmp(C, bb_computed, 1, 0); - dmrC_add_multijmp(C, &goto_ins->multijmp_list, jmp); - dmrC_add_bb(C, &bb_computed->parents, ep->active); - dmrC_add_bb(C, &active->children, bb_computed); - } END_FOR_EACH_PTR(sym); - - finish_block(ep); - break; - } - - case STMT_COMPOUND: - if (stmt->inline_fn) - return linearize_inlined_call(C, ep, stmt); - return linearize_compound_statement(C, ep, stmt); - - /* - * This could take 'likely/unlikely' into account, and - * switch the arms around appropriately.. - */ - case STMT_IF: { - struct basic_block *bb_true, *bb_false, *endif; - struct expression *cond = stmt->if_conditional; - - bb_true = alloc_basic_block(C, ep, stmt->pos); - bb_false = endif = alloc_basic_block(C, ep, stmt->pos); - - linearize_cond_branch(C, ep, cond, bb_true, bb_false); - - set_activeblock(C, ep, bb_true); - linearize_statement(C, ep, stmt->if_true); - - if (stmt->if_false) { - endif = alloc_basic_block(C, ep, stmt->pos); - add_goto(C, ep, endif); - set_activeblock(C, ep, bb_false); - linearize_statement(C, ep, stmt->if_false); - } - set_activeblock(C, ep, endif); - break; - } - - case STMT_SWITCH: - return linearize_switch(C, ep, stmt); - - case STMT_ITERATOR: - return linearize_iterator(C, ep, stmt); - - default: - break; - } - return VOID_PSEUDO(C); -} - -static struct entrypoint *linearize_fn(struct dmr_C *C, struct symbol *sym, struct symbol *base_type) -{ - struct entrypoint *ep; - struct basic_block *bb; - struct symbol *arg; - struct instruction *entry; - pseudo_t result; - int i; - - if (!base_type->stmt) - return NULL; - - ep = alloc_entrypoint(C); - bb = alloc_basic_block(C, ep, sym->pos); - - ep->name = sym; - sym->ep = ep; - set_activeblock(C, ep, bb); - - entry = alloc_instruction(C, OP_ENTRY, 0); - add_one_insn(C, ep, entry); - ep->entry = entry; - - dmrC_concat_symbol_list(base_type->arguments, &ep->syms); - - /* FIXME!! We should do something else about varargs.. */ - i = 0; - FOR_EACH_PTR(base_type->arguments, arg) { - linearize_argument(C, ep, arg, ++i); - } END_FOR_EACH_PTR(arg); - - result = linearize_statement(C, ep, base_type->stmt); - if (dmrC_bb_reachable(ep->active) && !dmrC_bb_terminated(ep->active)) { - struct symbol *ret_type = base_type->ctype.base_type; - struct instruction *insn = alloc_typed_instruction(C, OP_RET, ret_type); - - if (type_size(ret_type) > 0) - dmrC_use_pseudo(C, insn, result, &insn->src); - add_one_insn(C, ep, insn); - } - - int show_details = C->verbose > 2; - - if (show_details) { - printf("%s(%d): pre dmrC_kill_unreachable_bbs()\n", __FILE__, __LINE__); - dmrC_show_entry(C, ep); - } - if (C->fdump_linearize) { - if (C->fdump_linearize == 2) - return ep; - dmrC_show_entry(C, ep); - } - - - /* - * Do trivial flow simplification - branches to - * branches, kill dead basicblocks etc - */ - dmrC_kill_unreachable_bbs(C, ep); - -#if 0 - if (C->optimize) { - - if (show_details) { - printf("%s(%d): pre dmrC_simplify_symbol_usage()\n", __FILE__, __LINE__); - dmrC_show_entry(C, ep); - } - - /* - * Turn symbols into pseudos - */ - dmrC_simplify_symbol_usage(C, ep); - repeat: - /* - * Remove trivial instructions, and try to CSE - * the rest. - */ - do { - if (show_details) { - printf("%s(%d): pre dmrC_cleanup_and_cse()\n", __FILE__, __LINE__); - dmrC_show_entry(C, ep); - } - dmrC_cleanup_and_cse(C, ep); - if (show_details) { - printf("%s(%d): pre dmrC_pack_basic_blocks()\n", __FILE__, __LINE__); - dmrC_show_entry(C, ep); - } - dmrC_pack_basic_blocks(C, ep); - } while (C->L->repeat_phase & REPEAT_CSE); - - if (show_details) { - printf("%s(%d): pre dmrC_kill_unreachable_bbs() and dmrC_vrfy_flow()\n", __FILE__, __LINE__); - dmrC_show_entry(C, ep); - } - dmrC_kill_unreachable_bbs(C, ep); - dmrC_vrfy_flow(ep); - - if (show_details) { - printf("%s(%d): pre clear_symbol_pseudos()\n", __FILE__, __LINE__); - dmrC_show_entry(C, ep); - } - - /* Cleanup */ - clear_symbol_pseudos(ep); - - if (show_details) { - printf("%s(%d): pre dmrC_track_pseudo_liveness()\n", __FILE__, __LINE__); - dmrC_show_entry(C, ep); - } - - /* And track pseudo register usage */ - dmrC_track_pseudo_liveness(C, ep); - - if (show_details) { - printf("%s(%d): pre dmrC_simplify_flow()\n", __FILE__, __LINE__); - dmrC_show_entry(C, ep); - } - /* - * Some flow optimizations can only effectively - * be done when we've done liveness analysis. But - * if they trigger, we need to start all over - * again - */ - if (dmrC_simplify_flow(C, ep)) { - - if (show_details) { - printf("%s(%d): pre dmrC_clear_liveness()\n", __FILE__, __LINE__); - dmrC_show_entry(C, ep); - } - - dmrC_clear_liveness(ep); - goto repeat; - } - } -#endif - - /* Finally, add deathnotes to pseudos now that we have them */ - if (C->dbg_dead) - /* Note that this sets phi_users list on phisrc instructions which are relied upon by the - LLVM backend */ - dmrC_track_pseudo_death(C, ep); - - return ep; -} - -struct entrypoint *dmrC_linearize_symbol(struct dmr_C *C, struct symbol *sym) -{ - struct symbol *base_type; - - if (!sym) - return NULL; - C->L->current_pos = sym->pos; - base_type = sym->ctype.base_type; - if (!base_type) - return NULL; - if (base_type->type == SYM_FN) - return linearize_fn(C, sym, base_type); - return NULL; -} - -static void mark_bb_reachable(struct basic_block *bb, unsigned long generation) -{ - struct basic_block *child; - - if (bb->generation == generation) - return; - bb->generation = generation; - FOR_EACH_PTR(bb->children, child) { - mark_bb_reachable(child, generation); - } END_FOR_EACH_PTR(child); -} - -void dmrC_kill_unreachable_bbs(struct dmr_C *C, struct entrypoint *ep) -{ - struct basic_block *bb; - unsigned long generation = ++C->L->bb_generation; - - mark_bb_reachable(ep->entry->bb, generation); - FOR_EACH_PTR(ep->bbs, bb) { - if (bb->generation == generation) - continue; - /* Mark it as being dead */ - dmrC_kill_bb(C, bb); - bb->ep = NULL; - DELETE_CURRENT_PTR(bb); - } END_FOR_EACH_PTR(bb); - ptrlist_pack((struct ptr_list **) &ep->bbs); -} - -static int delete_pseudo_user_list_entry(struct dmr_C *C, struct pseudo_user_list **list, pseudo_t *entry, int count) -{ - (void)C; - struct pseudo_user *pu; - - FOR_EACH_PTR(*list, pu) { - if (pu->userp == entry) { - MARK_CURRENT_DELETED(struct pseudo_user *, pu); - if (!--count) - goto out; - } - } END_FOR_EACH_PTR(pu); - assert(count <= 0); -out: - if (ptrlist_size((struct ptr_list *)*list) == 0) - *list = NULL; - return count; -} - -static inline void remove_usage(struct dmr_C *C, pseudo_t p, pseudo_t *usep) -{ - if (dmrC_has_use_list(p)) { - delete_pseudo_user_list_entry(C, &p->users, usep, 1); - if (!p->users) - dmrC_kill_instruction(C, p->def); - } -} - -static inline void concat_user_list(struct pseudo_user_list *src, struct pseudo_user_list **dst) -{ - ptrlist_concat((struct ptr_list *)src, (struct ptr_list **)dst); -} - -void dmrC_convert_instruction_target(struct dmr_C *C, struct instruction *insn, pseudo_t src) -{ - pseudo_t target; - struct pseudo_user *pu; - /* - * Go through the "insn->users" list and replace them all.. - */ - target = insn->target; - if (target == src) - return; - FOR_EACH_PTR(target->users, pu) { - if (*pu->userp != VOID_PSEUDO(C)) { - assert(*pu->userp == target); - *pu->userp = src; - } - } END_FOR_EACH_PTR(pu); - if (dmrC_has_use_list(src)) - concat_user_list(target->users, &src->users); - target->users = NULL; -} - -static void kill_defs(struct dmr_C *C, struct instruction *insn) -{ - pseudo_t target = insn->target; - - if (!dmrC_has_use_list(target)) - return; - if (target->def != insn) - return; - - dmrC_convert_instruction_target(C, insn, VOID_PSEUDO(C)); -} - -void dmrC_kill_bb(struct dmr_C *C, struct basic_block *bb) -{ - struct instruction *insn; - struct basic_block *child, *parent; - - FOR_EACH_PTR(bb->insns, insn) { - dmrC_kill_instruction_force(C, insn); - kill_defs(C, insn); - /* - * We kill unreachable instructions even if they - * otherwise aren't "killable" (e.g. volatile loads) - */ - } END_FOR_EACH_PTR(insn); - bb->insns = NULL; - - FOR_EACH_PTR(bb->children, child) { - dmrC_remove_bb_from_list(&child->parents, bb, 0); - } END_FOR_EACH_PTR(child); - bb->children = NULL; - - FOR_EACH_PTR(bb->parents, parent) { - dmrC_remove_bb_from_list(&parent->children, bb, 0); - } END_FOR_EACH_PTR(parent); - bb->parents = NULL; -} - - -void dmrC_kill_use(struct dmr_C *C, pseudo_t *usep) -{ - if (usep) { - pseudo_t p = *usep; - *usep = VOID_PSEUDO(C); - remove_usage(C, p, usep); - } -} - -static void kill_use_list(struct dmr_C *C, struct pseudo_list *list) -{ - pseudo_t p; - FOR_EACH_PTR(list, p) { - if (p == VOID_PSEUDO(C)) - continue; - dmrC_kill_use(C, THIS_ADDRESS(pseudo_t, p)); - } END_FOR_EACH_PTR(p); -} - -/* - * kill an instruction: - * - remove it from its bb - * - remove the usage of all its operands - * If forse is zero, the normal case, the function only for - * instructions free of (possible) side-effects. Otherwise - * the function does that unconditionally (must only be used - * for unreachable instructions. - */ -void dmrC_kill_insn(struct dmr_C *C, struct instruction *insn, int force) -{ - if (!insn || !insn->bb) - return; - - switch (insn->opcode) { - case OP_SEL: - case OP_RANGE: - dmrC_kill_use(C, &insn->src3); - /* fall through */ - - case OP_ADD: - case OP_SUB: - case OP_MULU: - case OP_MULS: - case OP_DIVU: - case OP_DIVS: - case OP_MODU: - case OP_MODS: - case OP_SHL: - case OP_LSR: - case OP_ASR: - - /* Logical */ - case OP_AND: - case OP_OR: - case OP_XOR: - case OP_AND_BOOL: - case OP_OR_BOOL: - - case OP_SET_EQ: - case OP_SET_NE: - case OP_SET_LE: - case OP_SET_GE: - case OP_SET_LT: - case OP_SET_GT: - case OP_SET_B: - case OP_SET_A: - case OP_SET_BE: - case OP_SET_AE: - dmrC_kill_use(C, &insn->src2); - /* fall through */ - - case OP_CAST: - case OP_SCAST: - case OP_FPCAST: - case OP_PTRCAST: - case OP_SETVAL: - case OP_NOT: case OP_NEG: - case OP_SLICE: - dmrC_kill_use(C, &insn->src1); - break; - - case OP_PHI: - kill_use_list(C, insn->phi_list); - break; - case OP_PHISOURCE: - dmrC_kill_use(C, &insn->phi_src); - break; - - case OP_SYMADDR: - C->L->repeat_phase |= REPEAT_SYMBOL_CLEANUP; - break; - - case OP_CBR: - /* fall through */ - case OP_COMPUTEDGOTO: - dmrC_kill_use(C, &insn->cond); - break; - - case OP_CALL: - if (!force) { - /* a "pure" function can be killed too */ - if (!(insn->func->type == PSEUDO_SYM)) - return; - if (!(insn->func->sym->ctype.modifiers & MOD_PURE)) - return; - } - kill_use_list(C, insn->arguments); - if (insn->func->type == PSEUDO_REG) - dmrC_kill_use(C, &insn->func); - break; - - case OP_LOAD: - if (!force && insn->type->ctype.modifiers & MOD_VOLATILE) - return; - dmrC_kill_use(C, &insn->src); - break; - - case OP_STORE: - if (!force) - return; - dmrC_kill_use(C, &insn->src); - dmrC_kill_use(C, &insn->target); - break; - - case OP_ENTRY: - /* ignore */ - return; - - case OP_BR: - default: - break; - } - - insn->bb = NULL; - C->L->repeat_phase |= REPEAT_CSE; - return; -} - -void dmrC_init_linearizer(struct dmr_C *C) { - struct linearizer_state_t *L = (struct linearizer_state_t *)calloc(1, sizeof(struct linearizer_state_t)); - dmrC_allocator_init(&L->asm_rules_allocator, "asm rules", sizeof(struct asm_rules), - __alignof__(struct asm_rules), CHUNK); - dmrC_allocator_init(&L->pseudo_allocator, "pseudos", sizeof(struct pseudo), - __alignof__(struct pseudo), CHUNK); - dmrC_allocator_init(&L->pseudo_user_allocator, "pseudo_users", sizeof(struct pseudo_user), - __alignof__(struct pseudo_user), CHUNK); - dmrC_allocator_init(&L->asm_constraint_allocator, "asm_constraints", sizeof(struct asm_constraint), - __alignof__(struct asm_constraint), CHUNK); - dmrC_allocator_init(&L->multijmp_allocator, "multijmps", sizeof(struct multijmp), - __alignof__(struct multijmp), CHUNK); - dmrC_allocator_init(&L->basic_block_allocator, "basic_blocks", sizeof(struct basic_block), - __alignof__(struct basic_block), CHUNK); - dmrC_allocator_init(&L->entrypoint_allocator, "entrypoints", sizeof(struct entrypoint), - __alignof__(struct entrypoint), CHUNK); - dmrC_allocator_init(&L->instruction_allocator, "instructions", sizeof(struct instruction), - __alignof__(struct instruction), CHUNK); - C->L = L; -} - -void dmrC_destroy_linearizer(struct dmr_C *C) { - struct linearizer_state_t *L = C->L; - assert(L); - dmrC_allocator_destroy(&L->asm_rules_allocator); - dmrC_allocator_destroy(&L->pseudo_allocator); - dmrC_allocator_destroy(&L->pseudo_user_allocator); - dmrC_allocator_destroy(&L->asm_constraint_allocator); - dmrC_allocator_destroy(&L->multijmp_allocator); - dmrC_allocator_destroy(&L->basic_block_allocator); - dmrC_allocator_destroy(&L->entrypoint_allocator); - dmrC_allocator_destroy(&L->instruction_allocator); - free(L); - C->L = NULL; -} \ No newline at end of file diff --git a/dmr_c/src/linearize.h b/dmr_c/src/linearize.h deleted file mode 100644 index 0e94d28..0000000 --- a/dmr_c/src/linearize.h +++ /dev/null @@ -1,506 +0,0 @@ -#ifndef DMR_C_LINEARIZE_H -#define DMR_C_LINEARIZE_H - -/* -* Linearize - walk the parse tree and generate a linear version -* of it and the basic blocks. -* -* Copyright (C) 2004 Linus Torvalds -* Copyright (C) 2004 Christopher Li -*/ - -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct instruction; - -DECLARE_PTR_LIST(basic_block_list, struct basic_block); -DECLARE_PTR_LIST(instruction_list, struct instruction); -DECLARE_PTR_LIST(multijmp_list, struct multijmp); -DECLARE_PTR_LIST(pseudo_list, struct pseudo); - -struct pseudo_user { - struct instruction *insn; - pseudo_t *userp; -}; - -DECLARE_PTR_LIST(pseudo_user_list, struct pseudo_user); - -enum pseudo_type { - PSEUDO_VOID, - PSEUDO_REG, - PSEUDO_SYM, - PSEUDO_VAL, - PSEUDO_ARG, - PSEUDO_PHI, -}; - -/* Have you ever heard of "static single assignment" or SSA form? - struct pseudo represents one of those single-assignment variables. - Each one has a pointer to the symbol it represents (which may - have many pseudos referencing it). Each one also has a pointer - to the instruction that defines it.*/ -struct pseudo { - int nr; - enum pseudo_type type; - int size; /* OP_SETVAL only */ - struct pseudo_user_list *users; /* pseudo_user list */ - struct ident *ident; - union { - struct symbol *sym; // PSEUDO_SYM, VAL & ARG - struct instruction *def; // PSEUDO_REG & PHI - long long value; // PSEUDO_VAL - }; - DMRC_BACKEND_TYPE priv; - DMRC_BACKEND_TYPE priv2; /* FIXME - we use this to save ptr to allocated stack in PHI instructions (nanojit) */ -}; - -struct linearizer_state_t { - struct allocator pseudo_allocator; - struct allocator pseudo_user_allocator; - struct allocator asm_constraint_allocator; - struct allocator asm_rules_allocator; - struct allocator multijmp_allocator; - struct allocator basic_block_allocator; - struct allocator entrypoint_allocator; - struct allocator instruction_allocator; - - struct pseudo void_pseudo; - struct position current_pos; - - int repeat_phase; - unsigned long bb_generation; - int liveness_changed; - - struct pseudo_list **live_list; - struct pseudo_list *dead_list; - -#define MAX_VAL_HASH 64 - struct pseudo_list *prev[MAX_VAL_HASH]; /* from pseudo_t value_pseudo(long long val) in linearize.c */ - int nr; /* pseudo number */ - int bb_nr; /* basic block number */ - char buffer[4096*4]; - int n; - char pseudo_buffer[4][64]; -#define INSN_HASH_SIZE 256 - struct instruction_list *insn_hash_table[INSN_HASH_SIZE]; -}; - -#define VOID_PSEUDO(C) (&C->L->void_pseudo) - -struct multijmp { - struct basic_block *target; - long long begin, end; -}; - -struct asm_constraint { - pseudo_t pseudo; - const char *constraint; - const struct ident *ident; -}; - -DECLARE_PTR_LIST(asm_constraint_list, struct asm_constraint); - -struct asm_rules { - struct asm_constraint_list *inputs; /* list of asm_constraint */ - struct asm_constraint_list *outputs; /* list of asm_constraint */ - struct asm_constraint_list *clobbers; /* list of asm_constraint */ -}; - -struct instruction { - unsigned opcode:8, - size:24; - struct basic_block *bb; - struct position pos; - struct symbol *type; - union { - pseudo_t target; - pseudo_t cond; /* for branch and switch */ - }; - union { - struct /* entrypoint */ { - struct pseudo_list *arg_list; /* pseudo list */ - }; - struct /* branch */ { - struct basic_block *bb_true, *bb_false; - }; - struct /* switch */ { - struct multijmp_list *multijmp_list; - }; - struct /* phi_node */ { - struct pseudo_list *phi_list; /* pseudo list */ - }; - struct /* phi source */ { - pseudo_t phi_src; - struct instruction_list *phi_users; /* instruction list */ - }; - struct /* unops */ { - pseudo_t src; - struct symbol *orig_type; /* casts */ - unsigned int offset; /* memops */ - }; - struct /* binops and sel */ { - pseudo_t src1, src2, src3; - }; - struct /* slice */ { - pseudo_t base; - unsigned from, len; - }; - struct /* setval */ { - pseudo_t symbol; /* Subtle: same offset as "src" !! */ - struct expression *val; - }; - struct /* call */ { - pseudo_t func; - struct pseudo_list *arguments; /* instruction list */ - struct symbol *fntype; - }; - struct /* context */ { - int increment; - int check; - struct expression *context_expr; - }; - struct /* asm */ { - const char *string; - struct asm_rules *asm_rules; - }; - }; -}; - -enum opcode { - OP_BADOP, - - /* Entry */ - OP_ENTRY, - - /* Terminator */ - OP_TERMINATOR, - OP_RET = OP_TERMINATOR, - OP_BR, - OP_CBR, - OP_SWITCH, - OP_INVOKE, - OP_COMPUTEDGOTO, - OP_UNWIND, - OP_TERMINATOR_END = OP_UNWIND, - - /* Binary */ - OP_BINARY, - OP_ADD = OP_BINARY, - OP_SUB, - OP_MULU, OP_MULS, - OP_DIVU, OP_DIVS, - OP_MODU, OP_MODS, - OP_SHL, - OP_LSR, OP_ASR, - - /* Logical */ - OP_AND, - OP_OR, - OP_XOR, - OP_AND_BOOL, - OP_OR_BOOL, - OP_BINARY_END = OP_OR_BOOL, - - /* Binary comparison */ - OP_BINCMP, - OP_SET_EQ = OP_BINCMP, - OP_SET_NE, - OP_SET_LE, - OP_SET_GE, - OP_SET_LT, - OP_SET_GT, - OP_SET_B, - OP_SET_A, - OP_SET_BE, - OP_SET_AE, - OP_BINCMP_END = OP_SET_AE, - - /* Uni */ - OP_NOT, - OP_NEG, - - /* Select - three input values */ - OP_SEL, - - /* Memory */ - OP_MALLOC, - OP_FREE, - OP_ALLOCA, - OP_LOAD, - OP_STORE, - OP_SETVAL, - OP_SYMADDR, - OP_GET_ELEMENT_PTR, - - /* Other */ - OP_PHI, - OP_PHISOURCE, - OP_CAST, - OP_SCAST, - OP_FPCAST, - OP_PTRCAST, - OP_INLINED_CALL, - OP_CALL, - OP_VANEXT, - OP_VAARG, - OP_SLICE, - OP_SNOP, - OP_LNOP, - OP_NOP, - OP_DEATHNOTE, - OP_ASM, - - /* Sparse tagging (line numbers, context, whatever) */ - OP_CONTEXT, - OP_RANGE, - - /* Needed to translate SSA back to normal form */ - OP_COPY, -}; - -/* -A basic block represents a series of instructions with no branches. -Straight-line code. A branch only occurs at the end of a basic block, -and branches can only target the beginning of a basic block. Typically, -a conditional will consist of a basic block leading up to the branch, -a basic block for the true case, a basic block for the false case, -and a basic block where the two paths merge back together. Either the true -or the false case may not exist. A loop will normally have a basic block -for the loop body, which can branch to the top at the end or continue -to the next basic block. So basic blocks represent a node in the control -flow graph. The edges in that graph lead from one basic block to a -basic block which can follow it in the execution of the program. -*/ -struct basic_block { - struct position pos; - unsigned long generation; - int context; - struct entrypoint *ep; - struct basic_block_list *parents; /* basic_block sources */ /* predecessors */ - struct basic_block_list *children; /* basic_block destinations */ /* successors */ - struct instruction_list *insns; /* Linear list of instructions */ - struct pseudo_list *needs, *defines; /* pseudo lists */ - /* TODO Following fields are used by the codegen backends. - In Sparse this is a union but we need the nr field - for NanoJIT backend's liveness analysis in addition to - creating unique labels. - */ - //union { - unsigned int nr; /* unique id for label's names */ - DMRC_BACKEND_TYPE priv; - //}; -}; - -static inline int dmrC_instruction_list_size(struct instruction_list *list) -{ - return ptrlist_size((struct ptr_list *)list); -} - -static inline int dmrC_pseudo_list_size(struct pseudo_list *list) -{ - return ptrlist_size((struct ptr_list *)list); -} - -static inline int dmrC_bb_list_size(struct basic_block_list *list) -{ - return ptrlist_size((struct ptr_list *)list); -} - -static inline void dmrC_free_instruction_list(struct pseudo_list **head) -{ - ptrlist_remove_all((struct ptr_list **)head); -} - -static inline struct instruction * dmrC_delete_last_instruction(struct instruction_list **head) -{ - return (struct instruction *) ptrlist_undo_last((struct ptr_list **)head); -} - -static inline struct basic_block * dmrC_delete_last_basic_block(struct basic_block_list **head) -{ - return (struct basic_block *) ptrlist_delete_last((struct ptr_list **)head); -} - -static inline struct basic_block *dmrC_first_basic_block(struct basic_block_list *head) -{ - return (struct basic_block *) ptrlist_first((struct ptr_list *)head); -} - -static inline struct instruction *dmrC_last_instruction(struct instruction_list *head) -{ - return (struct instruction *) ptrlist_last((struct ptr_list *)head); -} - -static inline struct instruction *dmrC_first_instruction(struct instruction_list *head) -{ - return (struct instruction *) ptrlist_first((struct ptr_list *)head); -} - -static inline pseudo_t dmrC_first_pseudo(struct pseudo_list *head) -{ - return (pseudo_t) ptrlist_first((struct ptr_list *)head); -} - -static inline void dmrC_concat_basic_block_list(struct basic_block_list *from, struct basic_block_list **to) -{ - ptrlist_concat((struct ptr_list *)from, (struct ptr_list **)to); -} - -static inline void dmrC_concat_instruction_list(struct instruction_list *from, struct instruction_list **to) -{ - ptrlist_concat((struct ptr_list *)from, (struct ptr_list **)to); -} - -static inline int dmrC_is_branch_goto(struct instruction *br) -{ - return br && br->opcode==OP_BR && (!br->bb_true || !br->bb_false); -} - -static inline void dmrC_add_bb(struct dmr_C *C, struct basic_block_list **list, struct basic_block *bb) -{ - ptrlist_add((struct ptr_list **)list, bb, &C->ptrlist_allocator); -} - -static inline void dmrC_add_instruction(struct dmr_C *C, struct instruction_list **list, struct instruction *insn) -{ - ptrlist_add((struct ptr_list **)list, insn, &C->ptrlist_allocator); -} - -static inline void dmrC_add_multijmp(struct dmr_C *C, struct multijmp_list **list, struct multijmp *multijmp) -{ - ptrlist_add((struct ptr_list **)list, multijmp, &C->ptrlist_allocator); -} - -static inline pseudo_t *dmrC_add_pseudo(struct dmr_C *C, struct pseudo_list **list, pseudo_t pseudo) -{ - return (pseudo_t *) ptrlist_add((struct ptr_list **)list, pseudo, &C->ptrlist_allocator); -} - -static inline int dmrC_remove_pseudo(struct pseudo_list **list, pseudo_t pseudo) -{ - return ptrlist_remove((struct ptr_list **)list, pseudo, 0) != 0; -} - -static inline int dmrC_bb_terminated(struct basic_block *bb) -{ - struct instruction *insn; - if (!bb) - return 0; - insn = dmrC_last_instruction(bb->insns); - return insn && insn->opcode >= OP_TERMINATOR - && insn->opcode <= OP_TERMINATOR_END; -} - -static inline int dmrC_bb_reachable(struct basic_block *bb) -{ - return bb != NULL; -} - - -static inline void dmrC_add_pseudo_user_ptr(struct dmr_C *C, struct pseudo_user *user, struct pseudo_user_list **list) -{ - ptrlist_add((struct ptr_list **)list, user, &C->ptrlist_allocator); -} - -static inline int dmrC_has_use_list(pseudo_t p) -{ - return (p && p->type != PSEUDO_VOID && p->type != PSEUDO_VAL); -} - -static inline struct pseudo_user *dmrC_alloc_pseudo_user(struct dmr_C *C, struct instruction *insn, pseudo_t *pp) -{ - struct pseudo_user *user = (struct pseudo_user *) dmrC_allocator_allocate(&C->L->pseudo_user_allocator, 0); - user->userp = pp; - user->insn = insn; - return user; -} - -static inline void dmrC_use_pseudo(struct dmr_C *C, struct instruction *insn, pseudo_t p, pseudo_t *pp) -{ - *pp = p; - if (dmrC_has_use_list(p)) - dmrC_add_pseudo_user_ptr(C, dmrC_alloc_pseudo_user(C, insn, pp), &p->users); -} - -static inline void dmrC_remove_bb_from_list(struct basic_block_list **list, struct basic_block *entry, int count) -{ - ptrlist_remove((struct ptr_list **)list, entry, count); -} - -static inline void dmrC_replace_bb_in_list(struct basic_block_list **list, - struct basic_block *old, struct basic_block *newbb, int count) -{ - ptrlist_replace((struct ptr_list **)list, old, newbb, count); -} - -struct entrypoint { - struct symbol *name; - struct symbol_list *syms; /* symbol list */ - struct pseudo_list *accesses; /* pseudo list */ - struct basic_block_list *bbs; /* basic_block list */ - struct basic_block *active; - struct instruction *entry; -}; - -extern void dmrC_insert_select(struct dmr_C *C, struct basic_block *bb, struct instruction *br, struct instruction *phi, pseudo_t if_true, pseudo_t if_false); -extern void dmrC_insert_branch(struct dmr_C *C, struct basic_block *bb, struct instruction *br, struct basic_block *target); -// From Luc: sssa-mini -struct instruction *dmrC_alloc_phisrc(struct dmr_C *C, pseudo_t pseudo, struct symbol *type); -pseudo_t dmrC_insert_phi_node(struct dmr_C *C, struct basic_block *bb, struct symbol *type); -pseudo_t dmrC_alloc_phi(struct dmr_C *C, struct basic_block *source, pseudo_t pseudo, struct symbol *type); -pseudo_t dmrC_alloc_pseudo(struct dmr_C *C, struct instruction *def); -pseudo_t dmrC_value_pseudo(struct dmr_C *C, struct symbol *type, long long val); -unsigned int dmrC_value_size(long long value); - -struct entrypoint *dmrC_linearize_symbol(struct dmr_C *C, struct symbol *sym); -int dmrC_unssa(struct dmr_C *C, struct entrypoint *ep); -void dmrC_show_entry(struct dmr_C *C, struct entrypoint *ep); -const char *dmrC_show_pseudo(struct dmr_C *C, pseudo_t pseudo); -void dmrC_show_bb(struct dmr_C *C, struct basic_block *bb); -const char *dmrC_show_instruction(struct dmr_C *C, struct instruction *insn); - -void dmrC_convert_instruction_target(struct dmr_C *C, struct instruction *insn, pseudo_t src); -void dmrC_kill_use(struct dmr_C *C, pseudo_t *usep); -void dmrC_kill_insn(struct dmr_C *C, struct instruction *, int force); -void dmrC_kill_unreachable_bbs(struct dmr_C *C, struct entrypoint *ep); -void dmrC_kill_bb(struct dmr_C *C, struct basic_block *); - -static inline void dmrC_kill_instruction(struct dmr_C *C, struct instruction *insn) -{ - dmrC_kill_insn(C, insn, 0); -} -static inline void dmrC_kill_instruction_force(struct dmr_C *C, struct instruction *insn) -{ - dmrC_kill_insn(C, insn, 1); -} - -void dmrC_clear_liveness(struct entrypoint *ep); -void dmrC_track_pseudo_liveness(struct dmr_C *C, struct entrypoint *ep); -void dmrC_track_pseudo_death(struct dmr_C *C, struct entrypoint *ep); -void dmrC_track_phi_uses(struct dmr_C *C, struct instruction *insn); - -void dmrC_init_linearizer(struct dmr_C *C); -void dmrC_destroy_linearizer(struct dmr_C *C); - -#define dmrC_hashval(x) ((unsigned long)(((uintptr_t)(x)))) - -#define REPEAT_CSE 1 -#define REPEAT_SYMBOL_CLEANUP 2 -#define REPEAT_CFG_CLEANUP 3 - - -#ifdef __cplusplus -} -#endif - - -#endif /* LINEARIZE_H */ - diff --git a/dmr_c/src/liveness.c b/dmr_c/src/liveness.c deleted file mode 100644 index 73a0db0..0000000 --- a/dmr_c/src/liveness.c +++ /dev/null @@ -1,384 +0,0 @@ -/* - * Register - track pseudo usage, maybe eventually try to do register - * allocation. - * - * Copyright (C) 2004 Linus Torvalds - */ - -#include - -#include -#include -#include -#include -//#include - -static void phi_defines(struct dmr_C *C, struct instruction * phi_node, pseudo_t target, - void (*defines)(struct dmr_C *C, struct basic_block *, pseudo_t)) -{ - pseudo_t phi; - FOR_EACH_PTR(phi_node->phi_list, phi) { - struct instruction *def; - if (phi == VOID_PSEUDO(C)) - continue; - def = phi->def; - if (!def || !def->bb) - continue; - defines(C, def->bb, target); - } END_FOR_EACH_PTR(phi); -} - -static void asm_liveness(struct dmr_C *C, struct basic_block *bb, struct instruction *insn, - void (*def)(struct dmr_C *C, struct basic_block *, pseudo_t), - void (*use)(struct dmr_C *C, struct basic_block *, pseudo_t)) -{ - struct asm_constraint *entry; - - FOR_EACH_PTR(insn->asm_rules->inputs, entry) { - use(C, bb, entry->pseudo); - } END_FOR_EACH_PTR(entry); - - FOR_EACH_PTR(insn->asm_rules->outputs, entry) { - def(C, bb, entry->pseudo); - } END_FOR_EACH_PTR(entry); -} - -static void track_instruction_usage(struct dmr_C *C, struct basic_block *bb, struct instruction *insn, - void (*def)(struct dmr_C *C, struct basic_block *, pseudo_t), - void (*use)(struct dmr_C *C, struct basic_block *, pseudo_t)) -{ - #define USES(x) use(C, bb, insn->x) - #define DEFINES(x) def(C, bb, insn->x) - - switch (insn->opcode) { - case OP_RET: - USES(src); - break; - - case OP_CBR: - case OP_SWITCH: - USES(cond); - break; - - case OP_COMPUTEDGOTO: - USES(target); - break; - - /* Binary */ - case OP_ADD: - case OP_SUB: - case OP_MULU: - case OP_MULS: - case OP_DIVU: - case OP_DIVS: - case OP_MODU: - case OP_MODS: - case OP_SHL: - case OP_LSR: - case OP_ASR: - case OP_AND: - case OP_OR: - case OP_XOR: - case OP_AND_BOOL: - case OP_OR_BOOL: - case OP_SET_EQ: - case OP_SET_NE: - case OP_SET_LE: - case OP_SET_GE: - case OP_SET_LT: - case OP_SET_GT: - case OP_SET_B: - case OP_SET_A: - case OP_SET_BE: - case OP_SET_AE: - USES(src1); USES(src2); DEFINES(target); - break; - - /* Uni */ - case OP_NOT: case OP_NEG: - USES(src1); DEFINES(target); - break; - - case OP_SEL: - USES(src1); USES(src2); USES(src3); DEFINES(target); - break; - - /* Memory */ - case OP_LOAD: - USES(src); DEFINES(target); - break; - - case OP_STORE: - USES(src); USES(target); - break; - - case OP_SETVAL: - DEFINES(target); - break; - - case OP_SYMADDR: - USES(symbol); DEFINES(target); - break; - - /* Other */ - case OP_PHI: - /* Phi-nodes are "backwards" nodes. Their def doesn't matter */ - phi_defines(C, insn, insn->target, def); - break; - - case OP_PHISOURCE: - /* - * We don't care about the phi-source define, they get set - * up and expanded by the OP_PHI - */ - USES(phi_src); - break; - - case OP_CAST: - case OP_SCAST: - case OP_FPCAST: - case OP_PTRCAST: - USES(src); DEFINES(target); - break; - - case OP_CALL: { - pseudo_t arg; - USES(func); - if (insn->target != VOID_PSEUDO(C)) - DEFINES(target); - FOR_EACH_PTR(insn->arguments, arg) { - use(C, bb, arg); - } END_FOR_EACH_PTR(arg); - break; - } - - case OP_SLICE: - USES(base); DEFINES(target); - break; - - case OP_ASM: - asm_liveness(C, bb, insn, def, use); - break; - - case OP_RANGE: - USES(src1); USES(src2); USES(src3); - break; - - case OP_BADOP: - case OP_INVOKE: - case OP_UNWIND: - case OP_MALLOC: - case OP_FREE: - case OP_ALLOCA: - case OP_GET_ELEMENT_PTR: - case OP_VANEXT: - case OP_VAARG: - case OP_SNOP: - case OP_LNOP: - case OP_NOP: - case OP_CONTEXT: - break; - } -} - -int dmrC_pseudo_in_list(struct pseudo_list *list, pseudo_t pseudo) -{ - pseudo_t old; - FOR_EACH_PTR(list,old) { - if (old == pseudo) - return 1; - } END_FOR_EACH_PTR(old); - return 0; -} - -static void add_pseudo_exclusive(struct dmr_C *C, struct pseudo_list **list, pseudo_t pseudo) -{ - if (!dmrC_pseudo_in_list(*list, pseudo)) { - C->L->liveness_changed = 1; - dmrC_add_pseudo(C, list, pseudo); - } -} - -static inline int trackable_pseudo(pseudo_t pseudo) -{ - return pseudo && (pseudo->type == PSEUDO_REG || pseudo->type == PSEUDO_ARG); -} - -static void insn_uses(struct dmr_C *C, struct basic_block *bb, pseudo_t pseudo) -{ - if (trackable_pseudo(pseudo)) { - struct instruction *def = pseudo->def; - if (pseudo->type != PSEUDO_REG || def->bb != bb || def->opcode == OP_PHI) - add_pseudo_exclusive(C, &bb->needs, pseudo); - } -} - -static void insn_defines(struct dmr_C *C, struct basic_block *bb, pseudo_t pseudo) -{ - assert(trackable_pseudo(pseudo)); - dmrC_add_pseudo(C, &bb->defines, pseudo); -} - -static void track_bb_liveness(struct dmr_C *C, struct basic_block *bb) -{ - pseudo_t needs; - - FOR_EACH_PTR(bb->needs, needs) { - struct basic_block *parent; - FOR_EACH_PTR(bb->parents, parent) { - if (!dmrC_pseudo_in_list(parent->defines, needs)) { - add_pseudo_exclusive(C, &parent->needs, needs); - } - } END_FOR_EACH_PTR(parent); - } END_FOR_EACH_PTR(needs); -} - -/* - * We need to clear the liveness information if we - * are going to re-run it. - */ -void dmrC_clear_liveness(struct entrypoint *ep) -{ - struct basic_block *bb; - - FOR_EACH_PTR(ep->bbs, bb) { - ptrlist_remove_all((struct ptr_list **)&bb->needs); - ptrlist_remove_all((struct ptr_list **)&bb->defines); - } END_FOR_EACH_PTR(bb); -} - -/* - * Track inter-bb pseudo liveness. The intra-bb case - * is purely local information. - */ -void dmrC_track_pseudo_liveness(struct dmr_C *C, struct entrypoint *ep) -{ - struct basic_block *bb; - - /* Add all the bb pseudo usage */ - FOR_EACH_PTR(ep->bbs, bb) { - struct instruction *insn; - FOR_EACH_PTR(bb->insns, insn) { - if (!insn->bb) - continue; - assert(insn->bb == bb); - track_instruction_usage(C, bb, insn, insn_defines, insn_uses); - } END_FOR_EACH_PTR(insn); - } END_FOR_EACH_PTR(bb); - - /* Calculate liveness.. */ - do { - C->L->liveness_changed = 0; - FOR_EACH_PTR_REVERSE(ep->bbs, bb) { - track_bb_liveness(C, bb); - } END_FOR_EACH_PTR_REVERSE(bb); - } while (C->L->liveness_changed); - - /* Remove the pseudos from the "defines" list that are used internally */ - FOR_EACH_PTR(ep->bbs, bb) { - pseudo_t def; - FOR_EACH_PTR(bb->defines, def) { - struct basic_block *child; - FOR_EACH_PTR(bb->children, child) { - if (dmrC_pseudo_in_list(child->needs, def)) - goto is_used; - } END_FOR_EACH_PTR(child); - DELETE_CURRENT_PTR(def); -is_used: - ; - } END_FOR_EACH_PTR(def); - ptrlist_pack((struct ptr_list **)&bb->defines); - } END_FOR_EACH_PTR(bb); -} - -static void merge_pseudo_list(struct dmr_C *C, struct pseudo_list *src, struct pseudo_list **dest) -{ - pseudo_t pseudo; - FOR_EACH_PTR(src, pseudo) { - add_pseudo_exclusive(C, dest, pseudo); - } END_FOR_EACH_PTR(pseudo); -} - -void dmrC_track_phi_uses(struct dmr_C *C, struct instruction *insn) -{ - pseudo_t phi; - FOR_EACH_PTR(insn->phi_list, phi) { - struct instruction *def; - if (phi == VOID_PSEUDO(C) || !phi->def) - continue; - def = phi->def; - assert(def->opcode == OP_PHISOURCE); - dmrC_add_instruction(C, &def->phi_users, insn); - } END_FOR_EACH_PTR(phi); -} - -static void track_bb_phi_uses(struct dmr_C *C, struct basic_block *bb) -{ - struct instruction *insn; - FOR_EACH_PTR(bb->insns, insn) { - if (insn->bb && insn->opcode == OP_PHI) - dmrC_track_phi_uses(C, insn); - } END_FOR_EACH_PTR(insn); -} - -static void death_def(struct dmr_C *C, struct basic_block *bb, pseudo_t pseudo) -{ - (void) C; - (void) bb; - (void) pseudo; -} - -static void death_use(struct dmr_C *C, struct basic_block *bb, pseudo_t pseudo) -{ - (void) C; - (void) bb; - if (trackable_pseudo(pseudo) && !dmrC_pseudo_in_list(*C->L->live_list, pseudo)) { - dmrC_add_pseudo(C, &C->L->dead_list, pseudo); - dmrC_add_pseudo(C, C->L->live_list, pseudo); - } -} - -static void track_pseudo_death_bb(struct dmr_C *C, struct basic_block *bb) -{ - struct pseudo_list *live = NULL; - struct basic_block *child; - struct instruction *insn; - - FOR_EACH_PTR(bb->children, child) { - merge_pseudo_list(C, child->needs, &live); - } END_FOR_EACH_PTR(child); - - C->L->live_list = &live; - FOR_EACH_PTR_REVERSE(bb->insns, insn) { - if (!insn->bb) - continue; - - C->L->dead_list = NULL; - track_instruction_usage(C, bb, insn, death_def, death_use); - if (C->L->dead_list) { - pseudo_t dead; - FOR_EACH_PTR(C->L->dead_list, dead) { - struct instruction *deathnote = dmrC_allocator_allocate(&C->L->instruction_allocator, 0); - deathnote->bb = bb; - deathnote->opcode = OP_DEATHNOTE; - deathnote->target = dead; - INSERT_CURRENT(deathnote, insn); - } END_FOR_EACH_PTR(dead); - ptrlist_remove_all((struct ptr_list **)&C->L->dead_list); - } - } END_FOR_EACH_PTR_REVERSE(insn); - ptrlist_remove_all((struct ptr_list **)&live); -} - -void dmrC_track_pseudo_death(struct dmr_C *C, struct entrypoint *ep) -{ - struct basic_block *bb; - - FOR_EACH_PTR(ep->bbs, bb) { - track_bb_phi_uses(C, bb); - } END_FOR_EACH_PTR(bb); - - FOR_EACH_PTR(ep->bbs, bb) { - track_pseudo_death_bb(C, bb); - } END_FOR_EACH_PTR(bb); -} diff --git a/dmr_c/src/memops.c b/dmr_c/src/memops.c deleted file mode 100644 index d497ab9..0000000 --- a/dmr_c/src/memops.c +++ /dev/null @@ -1,196 +0,0 @@ -/* - * memops - try to combine memory ops. - * - * Copyright (C) 2004 Linus Torvalds - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -static int find_dominating_parents(struct dmr_C *C, pseudo_t pseudo, struct instruction *insn, - struct basic_block *bb, unsigned long generation, struct pseudo_list **dominators, - int local) -{ - struct basic_block *parent; - - FOR_EACH_PTR(bb->parents, parent) { - struct instruction *one; - struct instruction *br; - pseudo_t phi; - - FOR_EACH_PTR_REVERSE(parent->insns, one) { - int dominance; - if (!one->bb) - continue; - if (one == insn) - goto no_dominance; - dominance = dmrC_dominates(C, pseudo, insn, one, local); - if (dominance < 0) { - if (one->opcode == OP_LOAD) - continue; - return 0; - } - if (!dominance) - continue; - goto found_dominator; - } END_FOR_EACH_PTR_REVERSE(one); -no_dominance: - if (parent->generation == generation) - continue; - parent->generation = generation; - - if (!find_dominating_parents(C, pseudo, insn, parent, generation, dominators, local)) - return 0; - continue; - -found_dominator: - br = dmrC_delete_last_instruction(&parent->insns); - phi = dmrC_alloc_phi(C, parent, one->target, one->type); - phi->ident = phi->ident ? phi->ident: one->target->ident; - dmrC_add_instruction(C, &parent->insns, br); - dmrC_use_pseudo(C, insn, phi, dmrC_add_pseudo(C, dominators, phi)); - } END_FOR_EACH_PTR(parent); - return 1; -} - -static int address_taken(pseudo_t pseudo) -{ - struct pseudo_user *pu; - FOR_EACH_PTR(pseudo->users, pu) { - struct instruction *insn = pu->insn; - if (insn->bb && (insn->opcode != OP_LOAD && insn->opcode != OP_STORE)) - return 1; - } END_FOR_EACH_PTR(pu); - return 0; -} - -static int local_pseudo(pseudo_t pseudo) -{ - return pseudo->type == PSEUDO_SYM - && !(pseudo->sym->ctype.modifiers & (MOD_STATIC | MOD_NONLOCAL)) - && !address_taken(pseudo); -} - -static void simplify_loads(struct dmr_C *C, struct basic_block *bb) -{ - struct instruction *insn; - - FOR_EACH_PTR_REVERSE(bb->insns, insn) { - if (!insn->bb) - continue; - if (insn->opcode == OP_LOAD) { - struct instruction *dom; - pseudo_t pseudo = insn->src; - int local = local_pseudo(pseudo); - struct pseudo_list *dominators; - unsigned long generation; - - /* Check for illegal offsets.. */ - dmrC_check_access(C, insn); - - if (insn->type->ctype.modifiers & MOD_VOLATILE) - continue; - RECURSE_PTR_REVERSE(insn, dom) { - int dominance; - if (!dom->bb) - continue; - dominance = dmrC_dominates(C, pseudo, insn, dom, local); - if (dominance) { - /* possible partial dominance? */ - if (dominance < 0) { - if (dom->opcode == OP_LOAD) - continue; - goto next_load; - } - /* Yeehaa! Found one! */ - dmrC_convert_load_instruction(C, insn, dom->target); - goto next_load; - } - } END_FOR_EACH_PTR_REVERSE(dom); - /* OK, go find the parents */ - generation = ++C->L->bb_generation; - bb->generation = generation; - dominators = NULL; - if (find_dominating_parents(C, pseudo, insn, bb, generation, &dominators, local)) { - /* This happens with initial assignments to structures etc.. */ - if (!dominators) { - if (local) { - assert(pseudo->type != PSEUDO_ARG); - dmrC_convert_load_instruction(C, insn, dmrC_value_pseudo(C, insn->type, 0)); - } - goto next_load; - } - dmrC_rewrite_load_instruction(C, insn, dominators); - } - } -next_load: - /* Do the next one */; - } END_FOR_EACH_PTR_REVERSE(insn); -} - -static void kill_store(struct dmr_C *C, struct instruction *insn) -{ - if (insn) { - insn->bb = NULL; - insn->opcode = OP_SNOP; - dmrC_kill_use(C, &insn->target); - } -} - -static void kill_dominated_stores(struct dmr_C *C, struct basic_block *bb) -{ - struct instruction *insn; - - FOR_EACH_PTR_REVERSE(bb->insns, insn) { - if (!insn->bb) - continue; - if (insn->opcode == OP_STORE) { - struct instruction *dom; - pseudo_t pseudo = insn->src; - int local = local_pseudo(pseudo); - - RECURSE_PTR_REVERSE(insn, dom) { - int dominance; - if (!dom->bb) - continue; - dominance = dmrC_dominates(C, pseudo, insn, dom, local); - if (dominance) { - /* possible partial dominance? */ - if (dominance < 0) - goto next_store; - if (dom->opcode == OP_LOAD) - goto next_store; - /* Yeehaa! Found one! */ - kill_store(C, dom); - } - } END_FOR_EACH_PTR_REVERSE(dom); - - /* OK, we should check the parents now */ - } -next_store: - /* Do the next one */; - } END_FOR_EACH_PTR_REVERSE(insn); -} - -void dmrC_simplify_memops(struct dmr_C *C, struct entrypoint *ep) -{ - struct basic_block *bb; - - FOR_EACH_PTR_REVERSE(ep->bbs, bb) { - simplify_loads(C, bb); - } END_FOR_EACH_PTR_REVERSE(bb); - - FOR_EACH_PTR_REVERSE(ep->bbs, bb) { - kill_dominated_stores(C, bb); - } END_FOR_EACH_PTR_REVERSE(bb); -} diff --git a/dmr_c/src/parse.c b/dmr_c/src/parse.c deleted file mode 100644 index 5904d3a..0000000 --- a/dmr_c/src/parse.c +++ /dev/null @@ -1,2968 +0,0 @@ -/* - * Stupid C parser, version 1e-6. - * - * Let's see how hard this is to do. - * - * Copyright (C) 2003 Transmeta Corp. - * 2003-2004 Linus Torvalds - * Copyright (C) 2004 Christopher Li - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - /* - * This version is part of the dmr_c project. - * Copyright (C) 2017 Dibyendu Majumdar - */ - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct token *statement(struct dmr_C *C, struct token *token, struct statement **tree); -static struct token *handle_attributes(struct dmr_C *C, struct token *token, struct decl_state *ctx, unsigned int keywords); -struct token *dmrC_compound_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -struct token *dmrC_initializer(struct dmr_C *C, struct expression **tree, struct token *token); - -typedef struct token *declarator_t(struct dmr_C *C, struct token *, struct decl_state *); -static declarator_t - struct_specifier, union_specifier, enum_specifier, - attribute_specifier, typeof_specifier, parse_asm_declarator, - typedef_specifier, inline_specifier, auto_specifier, - register_specifier, static_specifier, extern_specifier, - thread_specifier, const_qualifier, volatile_qualifier; - -static struct token *parse_if_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_return_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_loop_iterator(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_default_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_case_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_switch_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_for_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_while_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_do_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_goto_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_context_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_range_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *parse_asm_statement(struct dmr_C *C, struct token *token, struct statement *stmt); -static struct token *toplevel_asm_declaration(struct dmr_C *C, struct token *token, struct symbol_list **list); -static struct token *parse_static_assert(struct dmr_C *C, struct token *token, struct symbol_list **unused); -static struct token *parameter_type_list(struct dmr_C *C, struct token *, struct symbol *); -static struct token *identifier_list(struct dmr_C *C, struct token *, struct symbol *); -static struct token *declarator(struct dmr_C *C, struct token *token, struct decl_state *ctx); - -typedef struct token *attr_t(struct dmr_C *C, struct token *, struct symbol *, - struct decl_state *); - -static attr_t - attribute_packed, attribute_aligned, attribute_modifier, - attribute_bitwise, - attribute_address_space, attribute_context, - attribute_designated_init, - attribute_transparent_union, ignore_attribute, - attribute_mode, attribute_force; - -typedef struct symbol *to_mode_t(struct dmr_C *C, struct symbol *); - -static to_mode_t - to_QI_mode, to_HI_mode, to_SI_mode, to_DI_mode, to_TI_mode, to_word_mode; - -enum { - Set_T = 1, - Set_S = 2, - Set_Char = 4, - Set_Int = 8, - Set_Double = 16, - Set_Float = 32, - Set_Signed = 64, - Set_Unsigned = 128, - Set_Short = 256, - Set_Long = 512, - Set_Vlong = 1024, - Set_Int128 = 2048, - Set_Any = Set_T | Set_Short | Set_Long | Set_Signed | Set_Unsigned -}; - -enum { - CInt = 0, CSInt, CUInt, CReal, CChar, CSChar, CUChar, -}; - -enum { - SNone = 0, STypedef, SAuto, SRegister, SExtern, SStatic, SForced, SMax, -}; - -static struct symbol_op typedef_op = { - .type = KW_MODIFIER, - .declarator = typedef_specifier, -}; - -static struct symbol_op inline_op = { - .type = KW_MODIFIER, - .declarator = inline_specifier, -}; - -static declarator_t noreturn_specifier; -static struct symbol_op noreturn_op = { - .type = KW_MODIFIER, - .declarator = noreturn_specifier, -}; - -static declarator_t alignas_specifier; -static struct symbol_op alignas_op = { - .type = KW_MODIFIER, - .declarator = alignas_specifier, -}; - -static struct symbol_op auto_op = { - .type = KW_MODIFIER, - .declarator = auto_specifier, -}; - -static struct symbol_op register_op = { - .type = KW_MODIFIER, - .declarator = register_specifier, -}; - -static struct symbol_op static_op = { - .type = KW_MODIFIER, - .declarator = static_specifier, -}; - -static struct symbol_op extern_op = { - .type = KW_MODIFIER, - .declarator = extern_specifier, -}; - -static struct symbol_op thread_op = { - .type = KW_MODIFIER, - .declarator = thread_specifier, -}; - -static struct symbol_op const_op = { - .type = KW_QUALIFIER, - .declarator = const_qualifier, -}; - -static struct symbol_op volatile_op = { - .type = KW_QUALIFIER, - .declarator = volatile_qualifier, -}; - -static struct symbol_op restrict_op = { - .type = KW_QUALIFIER, -}; - -static struct symbol_op typeof_op = { - .type = KW_SPECIFIER, - .declarator = typeof_specifier, - .test = Set_Any, - .set = Set_S|Set_T, -}; - -static struct symbol_op attribute_op = { - .type = KW_ATTRIBUTE, - .declarator = attribute_specifier, -}; - -static struct symbol_op struct_op = { - .type = KW_SPECIFIER, - .declarator = struct_specifier, - .test = Set_Any, - .set = Set_S|Set_T, -}; - -static struct symbol_op union_op = { - .type = KW_SPECIFIER, - .declarator = union_specifier, - .test = Set_Any, - .set = Set_S|Set_T, -}; - -static struct symbol_op enum_op = { - .type = KW_SPECIFIER, - .declarator = enum_specifier, - .test = Set_Any, - .set = Set_S|Set_T, -}; - -static struct symbol_op spec_op = { - .type = KW_SPECIFIER | KW_EXACT, - .test = Set_Any, - .set = Set_S|Set_T, -}; - -static struct symbol_op char_op = { - .type = KW_SPECIFIER, - .test = Set_T|Set_Long|Set_Short, - .set = Set_T|Set_Char, - .cls = CChar, -}; - -static struct symbol_op int_op = { - .type = KW_SPECIFIER, - .test = Set_T, - .set = Set_T|Set_Int, -}; - -static struct symbol_op double_op = { - .type = KW_SPECIFIER, - .test = Set_T|Set_Signed|Set_Unsigned|Set_Short|Set_Vlong, - .set = Set_T|Set_Double, - .cls = CReal, -}; - -static struct symbol_op float_op = { - .type = KW_SPECIFIER | KW_SHORT, - .test = Set_T|Set_Signed|Set_Unsigned|Set_Short|Set_Long, - .set = Set_T|Set_Float, - .cls = CReal, -}; - -static struct symbol_op short_op = { - .type = KW_SPECIFIER | KW_SHORT, - .test = Set_S|Set_Char|Set_Float|Set_Double|Set_Long|Set_Short, - .set = Set_Short, -}; - -static struct symbol_op signed_op = { - .type = KW_SPECIFIER, - .test = Set_S|Set_Float|Set_Double|Set_Signed|Set_Unsigned, - .set = Set_Signed, - .cls = CSInt, -}; - -static struct symbol_op unsigned_op = { - .type = KW_SPECIFIER, - .test = Set_S|Set_Float|Set_Double|Set_Signed|Set_Unsigned, - .set = Set_Unsigned, - .cls = CUInt, -}; - -static struct symbol_op long_op = { - .type = KW_SPECIFIER | KW_LONG, - .test = Set_S|Set_Char|Set_Float|Set_Short|Set_Vlong, - .set = Set_Long, -}; - -static struct symbol_op int128_op = { - .type = KW_SPECIFIER | KW_LONG, - .test = Set_S|Set_T|Set_Char|Set_Short|Set_Int|Set_Float|Set_Double|Set_Long|Set_Vlong|Set_Int128, - .set = Set_T|Set_Int128, -}; - -static struct symbol_op if_op = { - .statement = parse_if_statement, -}; - -static struct symbol_op return_op = { - .statement = parse_return_statement, -}; - -static struct symbol_op loop_iter_op = { - .statement = parse_loop_iterator, -}; - -static struct symbol_op default_op = { - .statement = parse_default_statement, -}; - -static struct symbol_op case_op = { - .statement = parse_case_statement, -}; - -static struct symbol_op switch_op = { - .statement = parse_switch_statement, -}; - -static struct symbol_op for_op = { - .statement = parse_for_statement, -}; - -static struct symbol_op while_op = { - .statement = parse_while_statement, -}; - -static struct symbol_op do_op = { - .statement = parse_do_statement, -}; - -static struct symbol_op goto_op = { - .statement = parse_goto_statement, -}; - -static struct symbol_op __context___op = { - .statement = parse_context_statement, -}; - -static struct symbol_op range_op = { - .statement = parse_range_statement, -}; - -static struct symbol_op asm_op = { - .type = KW_ASM, - .declarator = parse_asm_declarator, - .statement = parse_asm_statement, - .toplevel = toplevel_asm_declaration, -}; - -static struct symbol_op static_assert_op = { - .toplevel = parse_static_assert, -}; - -static struct symbol_op packed_op = { - .attribute = attribute_packed, -}; - -static struct symbol_op aligned_op = { - .attribute = attribute_aligned, -}; - -static struct symbol_op attr_mod_op = { - .attribute = attribute_modifier, -}; - -static struct symbol_op attr_bitwise_op = { - .attribute = attribute_bitwise, -}; - -static struct symbol_op attr_force_op = { - .attribute = attribute_force, -}; - -static struct symbol_op address_space_op = { - .attribute = attribute_address_space, -}; - -static struct symbol_op mode_op = { - .attribute = attribute_mode, -}; - -static struct symbol_op context_op = { - .attribute = attribute_context, -}; - -static struct symbol_op designated_init_op = { - .attribute = attribute_designated_init, -}; - -static struct symbol_op transparent_union_op = { - .attribute = attribute_transparent_union, -}; - -static struct symbol_op ignore_attr_op = { - .attribute = ignore_attribute, -}; - -static struct symbol_op mode_QI_op = { - .type = KW_MODE, - .to_mode = to_QI_mode -}; - -static struct symbol_op mode_HI_op = { - .type = KW_MODE, - .to_mode = to_HI_mode -}; - -static struct symbol_op mode_SI_op = { - .type = KW_MODE, - .to_mode = to_SI_mode -}; - -static struct symbol_op mode_DI_op = { - .type = KW_MODE, - .to_mode = to_DI_mode -}; - -static struct symbol_op mode_TI_op = { - .type = KW_MODE, - .to_mode = to_TI_mode -}; - -static struct symbol_op mode_word_op = { - .type = KW_MODE, - .to_mode = to_word_mode -}; - - -static const char *ignored_attributes[] = { - -#define GCC_ATTR(x) \ - STRINGIFY(x), \ - STRINGIFY(__##x##__), - -#include "gcc-attr-list.h" - -#undef GCC_ATTR - - "bounded", - "__bounded__", - "__noclone", - "__nonnull", - "__nothrow", -}; - - -void dmrC_init_parser(struct dmr_C *C, int stream) -{ - /* Using NS_TYPEDEF will also make the keyword a reserved one */ - struct init_keyword { - const char *name; - enum namespace_type ns; - unsigned long modifiers; - struct symbol_op *op; - struct symbol *type; - } keyword_table[] = { - - /* Type qualifiers */ - { "const", NS_TYPEDEF,.op = &const_op }, - { "__const", NS_TYPEDEF,.op = &const_op }, - { "__const__", NS_TYPEDEF,.op = &const_op }, - { "volatile", NS_TYPEDEF,.op = &volatile_op }, - { "__volatile", NS_TYPEDEF,.op = &volatile_op }, - { "__volatile__", NS_TYPEDEF,.op = &volatile_op }, - - /* Typedef.. */ - { "typedef", NS_TYPEDEF,.op = &typedef_op }, - - /* Type specifiers */ - { "void", NS_TYPEDEF,.type = &C->S->void_ctype,.op = &spec_op }, - { "char", NS_TYPEDEF,.op = &char_op }, - { "short", NS_TYPEDEF,.op = &short_op }, - { "int", NS_TYPEDEF,.op = &int_op }, - { "long", NS_TYPEDEF,.op = &long_op }, - { "float", NS_TYPEDEF,.op = &float_op }, - { "double", NS_TYPEDEF,.op = &double_op }, - { "signed", NS_TYPEDEF,.op = &signed_op }, - { "__signed", NS_TYPEDEF,.op = &signed_op }, - { "__signed__", NS_TYPEDEF,.op = &signed_op }, - { "unsigned", NS_TYPEDEF,.op = &unsigned_op }, - { "__int128", NS_TYPEDEF, .op = &int128_op }, - { "_Bool", NS_TYPEDEF,.type = &C->S->bool_ctype,.op = &spec_op }, - - /* Predeclared types */ - { "__builtin_va_list", NS_TYPEDEF,.type = &C->S->ptr_ctype,.op = &spec_op }, - { "__builtin_ms_va_list", NS_TYPEDEF,.type = &C->S->ptr_ctype,.op = &spec_op }, - { "__int128_t", NS_TYPEDEF,.type = &C->S->lllong_ctype,.op = &spec_op }, - { "__uint128_t",NS_TYPEDEF,.type = &C->S->ulllong_ctype,.op = &spec_op }, - - - /* Extended types */ - { "typeof", NS_TYPEDEF,.op = &typeof_op }, - { "__typeof", NS_TYPEDEF,.op = &typeof_op }, - { "__typeof__", NS_TYPEDEF,.op = &typeof_op }, - - { "__attribute", NS_TYPEDEF,.op = &attribute_op }, - { "__attribute__", NS_TYPEDEF,.op = &attribute_op }, - - { "struct", NS_TYPEDEF,.op = &struct_op }, - { "union", NS_TYPEDEF,.op = &union_op }, - { "enum", NS_TYPEDEF,.op = &enum_op }, - - { "inline", NS_TYPEDEF,.op = &inline_op }, - { "__inline", NS_TYPEDEF,.op = &inline_op }, - { "__inline__", NS_TYPEDEF,.op = &inline_op }, - - { "_Noreturn", NS_TYPEDEF, .op = &noreturn_op }, - - { "_Alignas", NS_TYPEDEF, .op = &alignas_op }, - - /* Ignored for now.. */ - { "restrict", NS_TYPEDEF,.op = &restrict_op }, - { "__restrict", NS_TYPEDEF,.op = &restrict_op }, - { "__restrict__", NS_TYPEDEF,.op = &restrict_op }, - - /* Static assertion */ - { "_Static_assert", NS_KEYWORD, .op = &static_assert_op }, - /* Storage class */ - { "auto", NS_TYPEDEF,.op = &auto_op }, - { "register", NS_TYPEDEF,.op = ®ister_op }, - { "static", NS_TYPEDEF,.op = &static_op }, - { "extern", NS_TYPEDEF,.op = &extern_op }, - { "__thread", NS_TYPEDEF,.op = &thread_op }, - { "_Thread_local", NS_TYPEDEF, .op = &thread_op }, - - /* Statement */ - { "if", NS_KEYWORD,.op = &if_op }, - { "return", NS_KEYWORD,.op = &return_op }, - { "break", NS_KEYWORD,.op = &loop_iter_op }, - { "continue", NS_KEYWORD,.op = &loop_iter_op }, - { "default", NS_KEYWORD,.op = &default_op }, - { "case", NS_KEYWORD,.op = &case_op }, - { "switch", NS_KEYWORD,.op = &switch_op }, - { "for", NS_KEYWORD,.op = &for_op }, - { "while", NS_KEYWORD,.op = &while_op }, - { "do", NS_KEYWORD,.op = &do_op }, - { "goto", NS_KEYWORD,.op = &goto_op }, - { "__context__",NS_KEYWORD,.op = &__context___op }, - { "__range__", NS_KEYWORD,.op = &range_op }, - { "asm", NS_KEYWORD,.op = &asm_op }, - { "__asm", NS_KEYWORD,.op = &asm_op }, - { "__asm__", NS_KEYWORD,.op = &asm_op }, - - /* Attribute */ - { "packed", NS_KEYWORD,.op = &packed_op }, - { "__packed__", NS_KEYWORD,.op = &packed_op }, - { "aligned", NS_KEYWORD,.op = &aligned_op }, - { "__aligned__",NS_KEYWORD,.op = &aligned_op }, - { "nocast", NS_KEYWORD, MOD_NOCAST,.op = &attr_mod_op }, - { "noderef", NS_KEYWORD, MOD_NODEREF,.op = &attr_mod_op }, - { "safe", NS_KEYWORD, MOD_SAFE,.op = &attr_mod_op }, - { "force", NS_KEYWORD,.op = &attr_force_op }, - { "bitwise", NS_KEYWORD, MOD_BITWISE, .op = &attr_bitwise_op }, - { "__bitwise__",NS_KEYWORD, MOD_BITWISE, .op = &attr_bitwise_op }, - { "address_space",NS_KEYWORD,.op = &address_space_op }, - { "mode", NS_KEYWORD,.op = &mode_op }, - { "context", NS_KEYWORD,.op = &context_op }, - { "designated_init", NS_KEYWORD,.op = &designated_init_op }, - { "__transparent_union__", NS_KEYWORD,.op = &transparent_union_op }, - { "noreturn", NS_KEYWORD, MOD_NORETURN,.op = &attr_mod_op }, - { "__noreturn__", NS_KEYWORD, MOD_NORETURN,.op = &attr_mod_op }, - { "pure", NS_KEYWORD, MOD_PURE,.op = &attr_mod_op }, - { "__pure__", NS_KEYWORD, MOD_PURE,.op = &attr_mod_op }, - { "const", NS_KEYWORD, MOD_PURE,.op = &attr_mod_op }, - { "__const", NS_KEYWORD, MOD_PURE,.op = &attr_mod_op }, - { "__const__", NS_KEYWORD, MOD_PURE,.op = &attr_mod_op }, - - { "__mode__", NS_KEYWORD,.op = &mode_op }, - { "QI", NS_KEYWORD, MOD_CHAR,.op = &mode_QI_op }, - { "__QI__", NS_KEYWORD, MOD_CHAR,.op = &mode_QI_op }, - { "HI", NS_KEYWORD, MOD_SHORT,.op = &mode_HI_op }, - { "__HI__", NS_KEYWORD, MOD_SHORT,.op = &mode_HI_op }, - { "SI", NS_KEYWORD,.op = &mode_SI_op }, - { "__SI__", NS_KEYWORD,.op = &mode_SI_op }, - { "DI", NS_KEYWORD, MOD_LONGLONG,.op = &mode_DI_op }, - { "__DI__", NS_KEYWORD, MOD_LONGLONG,.op = &mode_DI_op }, - { "TI", NS_KEYWORD, MOD_LONGLONGLONG,.op = &mode_TI_op }, - { "__TI__", NS_KEYWORD, MOD_LONGLONGLONG,.op = &mode_TI_op }, - { "word", NS_KEYWORD, MOD_LONG,.op = &mode_word_op }, - { "__word__", NS_KEYWORD, MOD_LONG,.op = &mode_word_op }, - }; - - C->P = (struct parse_state_t *) calloc(1, sizeof(struct parse_state_t)); - - int i; - for (i = 0; i < (int)ARRAY_SIZE(keyword_table); i++) { - struct init_keyword *ptr = keyword_table + i; - struct symbol *sym = dmrC_create_symbol(C->S, stream, ptr->name, SYM_KEYWORD, ptr->ns); - sym->ident->keyword = 1; - if (ptr->ns == NS_TYPEDEF) - sym->ident->reserved = 1; - sym->ctype.modifiers = ptr->modifiers; - sym->ctype.base_type = ptr->type; - sym->op = ptr->op; - } - - for (i = 0; i < (int)ARRAY_SIZE(ignored_attributes); i++) { - const char * name = ignored_attributes[i]; - struct symbol *sym = dmrC_create_symbol(C->S, stream, name, SYM_KEYWORD, - NS_KEYWORD); - if (!sym->op) { - sym->ident->keyword = 1; - sym->op = &ignore_attr_op; - } - } - - C->P->int_types[0] = &C->S->short_ctype; - C->P->int_types[1] = &C->S->int_ctype; - C->P->int_types[2] = &C->S->long_ctype; - C->P->int_types[3] = &C->S->llong_ctype; - C->P->signed_types[0] = &C->S->sshort_ctype; - C->P->signed_types[1] = &C->S->sint_ctype; - C->P->signed_types[2] = &C->S->slong_ctype; - C->P->signed_types[3] = &C->S->sllong_ctype; - C->P->signed_types[4] = &C->S->slllong_ctype; - C->P->unsigned_types[0] = &C->S->ushort_ctype; - C->P->unsigned_types[1] = &C->S->uint_ctype; - C->P->unsigned_types[2] = &C->S->ulong_ctype; - C->P->unsigned_types[3] = &C->S->ullong_ctype; - C->P->unsigned_types[4] = &C->S->ulllong_ctype; - C->P->real_types[0] = &C->S->float_ctype; - C->P->real_types[1] = &C->S->double_ctype; - C->P->real_types[2] = &C->S->ldouble_ctype; - C->P->char_types[0] = &C->S->char_ctype; - C->P->char_types[1] = &C->S->schar_ctype; - C->P->char_types[2] = &C->S->uchar_ctype; - C->P->types[0] = C->P->int_types + 1; - C->P->types[1] = C->P->signed_types + 1; - C->P->types[2] = C->P->unsigned_types + 1; - C->P->types[3] = C->P->real_types + 1; - C->P->types[4] = C->P->char_types; - C->P->types[5] = C->P->char_types + 1; - C->P->types[6] = C->P->char_types + 2; -} - -void dmrC_destroy_parser(struct dmr_C *C) { - free(C->P); - C->P = NULL; -} - - -// Add a symbol to the list of function-local symbols -static void fn_local_symbol(struct dmr_C *C, struct symbol *sym) -{ - if (C->P->function_symbol_list) - dmrC_add_symbol(C, C->P->function_symbol_list, sym); -} - -static int SENTINEL_ATTR match_idents(struct dmr_C *C, struct token *token, ...) -{ - va_list args; - struct ident * next; - - (void) C; - - if (dmrC_token_type(token) != TOKEN_IDENT) - return 0; - - va_start(args, token); - do { - next = va_arg(args, struct ident *); - } while (next && token->ident != next); - va_end(args); - - return next && token->ident == next; -} - - -struct statement *dmrC_alloc_statement(struct dmr_C *C, struct position pos, int type) -{ - struct statement *stmt = (struct statement *)dmrC_allocator_allocate(&C->statement_allocator, 0); - stmt->type = type; - stmt->pos = pos; - return stmt; -} - -static struct token *struct_declaration_list(struct dmr_C *C, struct token *token, struct symbol_list **list); - -static void apply_modifiers(struct dmr_C *C, struct position pos, struct decl_state *ctx) -{ - struct symbol *ctype; - if (!ctx->mode) - return; - ctype = ctx->mode->to_mode(C, ctx->ctype.base_type); - if (!ctype) - dmrC_sparse_error(C, pos, "don't know how to apply mode to %s", - dmrC_show_typename(C, ctx->ctype.base_type)); - else - ctx->ctype.base_type = ctype; - -} - -static struct symbol * alloc_indirect_symbol(struct dmr_C *C, struct position pos, struct ctype *ctype, int type) -{ - struct symbol *sym = dmrC_alloc_symbol(C->S, pos, type); - - sym->ctype.base_type = ctype->base_type; - sym->ctype.modifiers = ctype->modifiers; - - ctype->base_type = sym; - ctype->modifiers = 0; - return sym; -} - -/* - * NOTE! NS_LABEL is not just a different namespace, - * it also ends up using function scope instead of the - * regular symbol scope. - */ -struct symbol *dmrC_label_symbol(struct dmr_C *C, struct token *token) -{ - struct symbol *sym = dmrC_lookup_symbol(token->ident, NS_LABEL); - if (!sym) { - sym = dmrC_alloc_symbol(C->S, token->pos, SYM_LABEL); - dmrC_bind_symbol(C->S, sym, token->ident, NS_LABEL); - fn_local_symbol(C, sym); - } - return sym; -} - -static struct token *struct_union_enum_specifier(struct dmr_C *C, enum type type, - struct token *token, struct decl_state *ctx, - struct token *(*parse)(struct dmr_C *C, struct token *, struct symbol *)) -{ - struct symbol *sym; - struct position *repos; - - token = handle_attributes(C, token, ctx, KW_ATTRIBUTE); - if (dmrC_token_type(token) == TOKEN_IDENT) { - sym = dmrC_lookup_symbol(token->ident, NS_STRUCT); - if (!sym || - (dmrC_is_outer_scope(C, sym->scope) && - (dmrC_match_op(token->next,';') || dmrC_match_op(token->next,'{')))) { - // Either a new symbol, or else an out-of-scope - // symbol being redefined. - sym = dmrC_alloc_symbol(C->S, token->pos, type); - dmrC_bind_symbol(C->S, sym, token->ident, NS_STRUCT); - } - if (sym->type != type) - dmrC_error_die(C, token->pos, "invalid tag applied to %s", dmrC_show_typename (C, sym)); - ctx->ctype.base_type = sym; - repos = &token->pos; - token = token->next; - if (dmrC_match_op(token, '{')) { - // The following test is actually wrong for empty - // structs, but (1) they are not C99, (2) gcc does - // the same thing, and (3) it's easier. - if (sym->symbol_list) - dmrC_error_die(C, token->pos, "redefinition of %s", dmrC_show_typename (C, sym)); - sym->pos = *repos; - token = parse(C, token->next, sym); - token = dmrC_expect_token(C, token, '}', "at end of struct-union-enum-specifier"); - - // Mark the structure as needing re-examination - sym->examined = 0; - sym->endpos = token->pos; - } - return token; - } - - // private struct/union/enum type - if (!dmrC_match_op(token, '{')) { - dmrC_sparse_error(C, token->pos, "expected declaration"); - ctx->ctype.base_type = &C->S->bad_ctype; - return token; - } - - sym = dmrC_alloc_symbol(C->S, token->pos, type); - token = parse(C, token->next, sym); - ctx->ctype.base_type = sym; - token = dmrC_expect_token(C, token, '}', "at end of specifier"); - sym->endpos = token->pos; - - return token; -} - -static struct token *parse_struct_declaration(struct dmr_C *C, struct token *token, struct symbol *sym) -{ - struct symbol *field, *last = NULL; - struct token *res; - res = struct_declaration_list(C, token, &sym->symbol_list); - FOR_EACH_PTR(sym->symbol_list, field) { - if (!field->ident) { - struct symbol *base = field->ctype.base_type; - if (base && base->type == SYM_BITFIELD) - continue; - } - if (last) - last->next_subobject = field; - last = field; - } END_FOR_EACH_PTR(field); - return res; -} - -static struct token *parse_union_declaration(struct dmr_C *C, struct token *token, struct symbol *sym) -{ - return struct_declaration_list(C, token, &sym->symbol_list); -} - -static struct token *struct_specifier(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - return struct_union_enum_specifier(C, SYM_STRUCT, token, ctx, parse_struct_declaration); -} - -static struct token *union_specifier(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - return struct_union_enum_specifier(C, SYM_UNION, token, ctx, parse_union_declaration); -} - - -typedef struct { - int x; - unsigned long long y; -} Num; - -static void upper_boundary(Num *n, Num *v) -{ - if (n->x > v->x) - return; - if (n->x < v->x) { - *n = *v; - return; - } - if (n->y < v->y) - n->y = v->y; -} - -static void lower_boundary(Num *n, Num *v) -{ - if (n->x < v->x) - return; - if (n->x > v->x) { - *n = *v; - return; - } - if (n->y > v->y) - n->y = v->y; -} - -static int type_is_ok(struct dmr_C *C, struct symbol *type, Num *upper, Num *lower) -{ - (void) C; - int shift = type->bit_size; - int is_unsigned = type->ctype.modifiers & MOD_UNSIGNED; - - if (!is_unsigned) - shift--; - if (upper->x == 0 && upper->y >> shift) - return 0; - if (lower->x == 0 || (!is_unsigned && (~lower->y >> shift) == 0)) - return 1; - return 0; -} - -static struct symbol *bigger_enum_type(struct dmr_C *C, struct symbol *s1, struct symbol *s2) -{ - if (s1->bit_size < s2->bit_size) { - s1 = s2; - } else if (s1->bit_size == s2->bit_size) { - if (s2->ctype.modifiers & MOD_UNSIGNED) - s1 = s2; - } - if (s1->bit_size < C->target->bits_in_int) - return &C->S->int_ctype; - return s1; -} - -static void cast_enum_list(struct dmr_C *C, struct symbol_list *list, struct symbol *base_type) -{ - struct symbol *sym; - - FOR_EACH_PTR(list, sym) { - struct expression *expr = sym->initializer; - struct symbol *ctype; - if (expr->type != EXPR_VALUE) - continue; - ctype = expr->ctype; - if (ctype->bit_size == base_type->bit_size) - continue; - dmrC_cast_value(C, expr, base_type, expr, ctype); - } END_FOR_EACH_PTR(sym); -} - -static struct token *parse_enum_declaration(struct dmr_C *C, struct token *token, struct symbol *parent) -{ - unsigned long long lastval = 0; - struct symbol *ctype = NULL, *base_type = NULL; - Num upper = {-1, 0}, lower = {1, 0}; - - parent->examined = 1; - parent->ctype.base_type = &C->S->int_ctype; - while (dmrC_token_type(token) == TOKEN_IDENT) { - struct expression *expr = NULL; - struct token *next = token->next; - struct symbol *sym; - - if (dmrC_match_op(next, '=')) { - next = dmrC_constant_expression(C, next->next, &expr); - lastval = dmrC_get_expression_value(C, expr); - ctype = &C->S->void_ctype; - if (expr && expr->ctype) - ctype = expr->ctype; - } else if (!ctype) { - ctype = &C->S->int_ctype; - } else if (dmrC_is_int_type(C->S, ctype)) { - lastval++; - } else { - dmrC_error_die(C, token->pos, "can't increment the last enum member"); - } - - if (!expr) { - expr = dmrC_alloc_expression(C, token->pos, EXPR_VALUE); - expr->value = lastval; - expr->ctype = ctype; - } - - sym = dmrC_alloc_symbol(C->S, token->pos, SYM_NODE); - dmrC_bind_symbol(C->S, sym, token->ident, NS_SYMBOL); - sym->ctype.modifiers &= ~MOD_ADDRESSABLE; - sym->initializer = expr; - sym->enum_member = 1; - sym->ctype.base_type = parent; - dmrC_add_symbol(C, &parent->symbol_list, sym); - - if (base_type != &C->S->bad_ctype) { - if (ctype->type == SYM_NODE) - ctype = ctype->ctype.base_type; - if (ctype->type == SYM_ENUM) { - if (ctype == parent) - ctype = base_type; - else - ctype = ctype->ctype.base_type; - } - /* - * base_type rules: - * - if all enums are of the same type, then - * the base_type is that type (two first - * cases) - * - if enums are of different types, they - * all have to be integer types, and the - * base type is at least "int_ctype". - * - otherwise the base_type is "bad_ctype". - */ - if (!base_type) { - base_type = ctype; - } else if (ctype == base_type) { - /* nothing */ - } else if (dmrC_is_int_type(C->S, base_type) && dmrC_is_int_type(C->S, ctype)) { - base_type = bigger_enum_type(C, base_type, ctype); - } else - base_type = &C->S->bad_ctype; - parent->ctype.base_type = base_type; - } - if (dmrC_is_int_type(C->S, base_type)) { - Num v = {.y = lastval}; - if (ctype->ctype.modifiers & MOD_UNSIGNED) - v.x = 0; - else if ((long long)lastval >= 0) - v.x = 0; - else - v.x = -1; - upper_boundary(&upper, &v); - lower_boundary(&lower, &v); - } - token = next; - - sym->endpos = token->pos; - - if (!dmrC_match_op(token, ',')) - break; - token = token->next; - } - if (!base_type) { - dmrC_sparse_error(C, token->pos, "bad enum definition"); - base_type = &C->S->bad_ctype; - } - else if (!dmrC_is_int_type(C->S, base_type)) - ; //base_type = base_type; - else if (type_is_ok(C, base_type, &upper, &lower)) - ; //base_type = base_type; - else if (type_is_ok(C, &C->S->int_ctype, &upper, &lower)) - base_type = &C->S->int_ctype; - else if (type_is_ok(C, &C->S->uint_ctype, &upper, &lower)) - base_type = &C->S->uint_ctype; - else if (type_is_ok(C, &C->S->long_ctype, &upper, &lower)) - base_type = &C->S->long_ctype; - else if (type_is_ok(C, &C->S->ulong_ctype, &upper, &lower)) - base_type = &C->S->ulong_ctype; - else if (type_is_ok(C, &C->S->llong_ctype, &upper, &lower)) - base_type = &C->S->llong_ctype; - else if (type_is_ok(C, &C->S->ullong_ctype, &upper, &lower)) - base_type = &C->S->ullong_ctype; - else - base_type = &C->S->bad_ctype; - parent->ctype.base_type = base_type; - parent->ctype.modifiers |= (base_type->ctype.modifiers & MOD_UNSIGNED); - parent->examined = 0; - - cast_enum_list(C, parent->symbol_list, base_type); - - return token; -} - -static struct token *enum_specifier(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - struct token *ret = struct_union_enum_specifier(C, SYM_ENUM, token, ctx, parse_enum_declaration); - struct ctype *ctype = &ctx->ctype.base_type->ctype; - - if (!ctype->base_type) - ctype->base_type = &C->S->incomplete_ctype; - - return ret; -} - -static void apply_ctype(struct dmr_C *C, struct position pos, struct ctype *thistype, struct ctype *ctype); -struct token *dmrC_typename(struct dmr_C *C, struct token *token, struct symbol **p, int *forced); - -static struct token *typeof_specifier(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - struct symbol *sym; - - if (!dmrC_match_op(token, '(')) { - dmrC_sparse_error(C, token->pos, "expected '(' after typeof"); - return token; - } - if (dmrC_lookup_type(token->next)) { - token = dmrC_typename(C, token->next, &sym, NULL); - ctx->ctype.base_type = sym->ctype.base_type; - apply_ctype(C, token->pos, &sym->ctype, &ctx->ctype); - } else { - struct symbol *typeof_sym = dmrC_alloc_symbol(C->S, token->pos, SYM_TYPEOF); - token = dmrC_parse_expression(C, token->next, &typeof_sym->initializer); - - typeof_sym->endpos = token->pos; - if (!typeof_sym->initializer) { - dmrC_sparse_error(C, token->pos, "expected expression after the '(' token"); - typeof_sym = &C->S->bad_ctype; - } - ctx->ctype.base_type = typeof_sym; - } - return dmrC_expect_token(C, token, ')', "after typeof"); -} - -static struct token *ignore_attribute(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - (void) ctx; - (void) attr; - struct expression *expr = NULL; - if (dmrC_match_op(token, '(')) - token = dmrC_parens_expression(C, token, &expr, "in attribute"); - return token; -} - -static struct token *attribute_packed(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - (void) C; - (void) attr; - if (!ctx->ctype.alignment) - ctx->ctype.alignment = 1; - return token; -} - -static struct token *attribute_aligned(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - (void) attr; - int alignment = C->target->max_alignment; - struct expression *expr = NULL; - - if (dmrC_match_op(token, '(')) { - token = dmrC_parens_expression(C, token, &expr, "in attribute"); - if (expr) - alignment = (int) dmrC_const_expression_value(C, expr); - } - if (alignment & (alignment-1)) { - dmrC_warning(C, token->pos, "I don't like non-power-of-2 alignments"); - return token; - } else if (alignment > (int)ctx->ctype.alignment) - ctx->ctype.alignment = alignment; - return token; -} - -static void apply_qualifier(struct dmr_C *C, struct position *pos, struct ctype *ctx, unsigned long qual) -{ - if (ctx->modifiers & qual) - dmrC_warning(C, *pos, "duplicate %s", dmrC_modifier_string(C, qual)); - ctx->modifiers |= qual; -} - -static struct token *attribute_modifier(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - apply_qualifier(C, &token->pos, &ctx->ctype, attr->ctype.modifiers); - return token; -} - -static struct token *attribute_bitwise(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - if (C->Wbitwise) - attribute_modifier(C, token, attr, ctx); - return token; -} - -static struct token *attribute_address_space(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - (void) attr; - struct expression *expr = NULL; - int as; - token = dmrC_expect_token(C, token, '(', "after address_space attribute"); - token = dmrC_conditional_expression(C, token, &expr); - if (expr) { - as = (int) dmrC_const_expression_value(C, expr); - if (C->Waddress_space && as) - ctx->ctype.as = as; - } - token = dmrC_expect_token(C, token, ')', "after address_space attribute"); - return token; -} - -static struct symbol *to_QI_mode(struct dmr_C *C, struct symbol *ctype) -{ - if (ctype->ctype.base_type != &C->S->int_type) - return NULL; - if (ctype == &C->S->char_ctype) - return ctype; - return ctype->ctype.modifiers & MOD_UNSIGNED ? &C->S->uchar_ctype - : &C->S->schar_ctype; -} - -static struct symbol *to_HI_mode(struct dmr_C *C, struct symbol *ctype) -{ - if (ctype->ctype.base_type != &C->S->int_type) - return NULL; - return ctype->ctype.modifiers & MOD_UNSIGNED ? &C->S->ushort_ctype - : &C->S->sshort_ctype; -} - -static struct symbol *to_SI_mode(struct dmr_C *C, struct symbol *ctype) -{ - if (ctype->ctype.base_type != &C->S->int_type) - return NULL; - return ctype->ctype.modifiers & MOD_UNSIGNED ? &C->S->uint_ctype - : &C->S->sint_ctype; -} - -static struct symbol *to_DI_mode(struct dmr_C *C, struct symbol *ctype) -{ - if (ctype->ctype.base_type != &C->S->int_type) - return NULL; - return ctype->ctype.modifiers & MOD_UNSIGNED ? &C->S->ullong_ctype - : &C->S->sllong_ctype; -} - -static struct symbol *to_TI_mode(struct dmr_C *C, struct symbol *ctype) -{ - if (ctype->ctype.base_type != &C->S->int_type) - return NULL; - return ctype->ctype.modifiers & MOD_UNSIGNED ? &C->S->ulllong_ctype - : &C->S->slllong_ctype; -} - -static struct symbol *to_word_mode(struct dmr_C *C, struct symbol *ctype) -{ - if (ctype->ctype.base_type != &C->S->int_type) - return NULL; - return ctype->ctype.modifiers & MOD_UNSIGNED ? &C->S->ulong_ctype - : &C->S->slong_ctype; -} - -static struct token *attribute_mode(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - (void) attr; - token = dmrC_expect_token(C, token, '(', "after mode attribute"); - if (dmrC_token_type(token) == TOKEN_IDENT) { - struct symbol *mode = dmrC_lookup_keyword(token->ident, NS_KEYWORD); - if (mode && mode->op->type == KW_MODE) - ctx->mode = mode->op; - else - dmrC_sparse_error(C, token->pos, "unknown mode attribute %s\n", dmrC_show_ident(C, token->ident)); - token = token->next; - } else - dmrC_sparse_error(C, token->pos, "expect attribute mode symbol\n"); - token = dmrC_expect_token(C, token, ')', "after mode attribute"); - return token; -} - -static struct token *attribute_context(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - (void) attr; - struct context *context = (struct context *)dmrC_allocator_allocate(&C->S->context_allocator, 0); - struct expression *args[3]; - int argc = 0; - - token = dmrC_expect_token(C, token, '(', "after context attribute"); - while (!dmrC_match_op(token, ')')) { - struct expression *expr = NULL; - token = dmrC_conditional_expression(C, token, &expr); - if (!expr) - break; - if (argc < 3) - args[argc++] = expr; - if (!dmrC_match_op(token, ',')) - break; - token = token->next; - } - - switch(argc) { - case 0: - dmrC_sparse_error(C, token->pos, "expected context input/output values"); - break; - case 1: - context->in = (unsigned int)dmrC_get_expression_value(C, args[0]); - break; - case 2: - context->in = (unsigned int)dmrC_get_expression_value(C, args[0]); - context->out = (unsigned int)dmrC_get_expression_value(C, args[1]); - break; - case 3: - context->context_expr = args[0]; - context->in = (unsigned int)dmrC_get_expression_value(C, args[1]); - context->out = (unsigned int)dmrC_get_expression_value(C, args[2]); - break; - } - - if (argc) - dmrC_add_context(C, &ctx->ctype.contexts, context); - - token = dmrC_expect_token(C, token, ')', "after context attribute"); - return token; -} - -static struct token *attribute_designated_init(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - (void) attr; - if (ctx->ctype.base_type && ctx->ctype.base_type->type == SYM_STRUCT) - ctx->ctype.base_type->designated_init = 1; - else - dmrC_warning(C, token->pos, "attribute designated_init applied to non-structure type"); - return token; -} - -static struct token *attribute_transparent_union(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - (void) attr; - if (C->Wtransparent_union) - dmrC_warning(C, token->pos, "attribute __transparent_union__"); - if (ctx->ctype.base_type && ctx->ctype.base_type->type == SYM_UNION) - ctx->ctype.base_type->transparent_union = 1; - else - dmrC_warning(C, token->pos, "attribute __transparent_union__ applied to non-union type"); - return token; -} - -static struct token *recover_unknown_attribute(struct dmr_C *C, struct token *token) -{ - struct expression *expr = NULL; - - if (C->Wunknown_attribute) - dmrC_warning(C, token->pos, "attribute '%s': unknown attribute", dmrC_show_ident(C, token->ident)); - token = token->next; - if (dmrC_match_op(token, '(')) - token = dmrC_parens_expression(C, token, &expr, "in attribute"); - return token; -} - -static struct token *attribute_specifier(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - token = dmrC_expect_token(C, token, '(', "after attribute"); - token = dmrC_expect_token(C, token, '(', "after attribute"); - - for (;;) { - struct ident *attribute_name; - struct symbol *attr; - - if (dmrC_eof_token(token)) - break; - if (dmrC_match_op(token, ';')) - break; - if (dmrC_token_type(token) != TOKEN_IDENT) - break; - attribute_name = token->ident; - attr = dmrC_lookup_keyword(attribute_name, NS_KEYWORD); - if (attr && attr->op->attribute) - token = attr->op->attribute(C, token->next, attr, ctx); - else - token = recover_unknown_attribute(C, token); - - if (!dmrC_match_op(token, ',')) - break; - token = token->next; - } - - token = dmrC_expect_token(C, token, ')', "after attribute"); - token = dmrC_expect_token(C, token, ')', "after attribute"); - return token; -} - -static const char *storage_class[] = -{ - [STypedef] = "typedef", - [SAuto] = "auto", - [SExtern] = "extern", - [SStatic] = "static", - [SRegister] = "register", - [SForced] = "[force]" -}; - -static unsigned long storage_modifiers(struct dmr_C *C, struct decl_state *ctx) -{ - (void) C; - static unsigned long mod[SMax] = - { - [SAuto] = MOD_AUTO, - [SExtern] = MOD_EXTERN, - [SStatic] = MOD_STATIC, - [SRegister] = MOD_REGISTER - }; - return mod[ctx->storage_class] | (ctx->is_inline ? MOD_INLINE : 0) - | (ctx->is_tls ? MOD_TLS : 0); -} - -static void set_storage_class(struct dmr_C *C, struct position *pos, struct decl_state *ctx, int klass) -{ - /* __thread can be used alone, or with extern or static */ - if (ctx->is_tls && (klass != SStatic && klass != SExtern)) { - dmrC_sparse_error(C, *pos, "__thread can only be used alone, or with " - "extern or static"); - return; - } - - if (!ctx->storage_class) { - ctx->storage_class = klass; - return; - } - if (ctx->storage_class == klass) - dmrC_sparse_error(C, *pos, "duplicate %s", storage_class[klass]); - else - dmrC_sparse_error(C, *pos, "multiple storage classes"); -} - -static struct token *typedef_specifier(struct dmr_C *C, struct token *next, struct decl_state *ctx) -{ - set_storage_class(C, &next->pos, ctx, STypedef); - return next; -} - -static struct token *auto_specifier(struct dmr_C *C, struct token *next, struct decl_state *ctx) -{ - set_storage_class(C, &next->pos, ctx, SAuto); - return next; -} - -static struct token *register_specifier(struct dmr_C *C, struct token *next, struct decl_state *ctx) -{ - set_storage_class(C, &next->pos, ctx, SRegister); - return next; -} - -static struct token *static_specifier(struct dmr_C *C, struct token *next, struct decl_state *ctx) -{ - set_storage_class(C, &next->pos, ctx, SStatic); - return next; -} - -static struct token *extern_specifier(struct dmr_C *C, struct token *next, struct decl_state *ctx) -{ - set_storage_class(C, &next->pos, ctx, SExtern); - return next; -} - -static struct token *thread_specifier(struct dmr_C *C, struct token *next, struct decl_state *ctx) -{ - /* This GCC extension can be used alone, or with extern or static */ - if (!ctx->storage_class || ctx->storage_class == SStatic - || ctx->storage_class == SExtern) { - ctx->is_tls = 1; - } else { - dmrC_sparse_error(C, next->pos, "__thread can only be used alone, or " - "with extern or static"); - } - - return next; -} - -static struct token *attribute_force(struct dmr_C *C, struct token *token, struct symbol *attr, struct decl_state *ctx) -{ - (void) attr; - set_storage_class(C, &token->pos, ctx, SForced); - return token; -} - -static struct token *inline_specifier(struct dmr_C *C, struct token *next, struct decl_state *ctx) -{ - (void) C; - ctx->is_inline = 1; - return next; -} - -static struct token *noreturn_specifier(struct dmr_C *C, struct token *next, struct decl_state *ctx) -{ - apply_qualifier(C, &next->pos, &ctx->ctype, MOD_NORETURN); - return next; -} - -static struct token *alignas_specifier(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - int alignment = 0; - - if (!dmrC_match_op(token, '(')) { - dmrC_sparse_error(C, token->pos, "expected '(' after _Alignas"); - return token; - } - if (dmrC_lookup_type(token->next)) { - struct symbol *sym = NULL; - token = dmrC_typename(C, token->next, &sym, NULL); - sym = dmrC_examine_symbol_type(C->S, sym); - alignment = sym->ctype.alignment; - token = dmrC_expect_token(C, token, ')', "after _Alignas(..."); - } else { - struct expression *expr = NULL; - token = dmrC_parens_expression(C, token, &expr, "after _Alignas"); - if (!expr) - return token; - alignment = (int) dmrC_const_expression_value(C, expr); - } - - if (alignment < 0) { - dmrC_warning(C, token->pos, "non-positive alignment"); - return token; - } - if (alignment & (alignment-1)) { - dmrC_warning(C, token->pos, "non-power-of-2 alignment"); - return token; - } - if (alignment > (int)ctx->ctype.alignment) - ctx->ctype.alignment = alignment; - return token; -} -static struct token *const_qualifier(struct dmr_C *C, struct token *next, struct decl_state *ctx) -{ - apply_qualifier(C, &next->pos, &ctx->ctype, MOD_CONST); - return next; -} - -static struct token *volatile_qualifier(struct dmr_C *C, struct token *next, struct decl_state *ctx) -{ - apply_qualifier(C, &next->pos, &ctx->ctype, MOD_VOLATILE); - return next; -} - -static void apply_ctype(struct dmr_C *C, struct position pos, struct ctype *thistype, struct ctype *ctype) -{ - unsigned long mod = thistype->modifiers; - - if (mod) - apply_qualifier(C, &pos, ctype, mod); - - /* Context */ - dmrC_concat_context_list(thistype->contexts, &ctype->contexts); - - /* Alignment */ - if (thistype->alignment > ctype->alignment) - ctype->alignment = thistype->alignment; - - /* Address space */ - if (thistype->as) - ctype->as = thistype->as; -} - -static void specifier_conflict(struct dmr_C *C, struct position pos, int what, struct ident *news) -{ - const char *old; - if (what & (Set_S | Set_T)) - goto Catch_all; - if (what & Set_Char) - old = "char"; - else if (what & Set_Double) - old = "double"; - else if (what & Set_Float) - old = "float"; - else if (what & Set_Signed) - old = "signed"; - else if (what & Set_Unsigned) - old = "unsigned"; - else if (what & Set_Short) - old = "short"; - else if (what & Set_Long) - old = "long"; - else - old = "long long"; - dmrC_sparse_error(C, pos, "impossible combination of type specifiers: %s %s", - old, dmrC_show_ident(C, news)); - return; - -Catch_all: - dmrC_sparse_error(C, pos, "two or more data types in declaration specifiers"); -} - -struct symbol *dmrC_ctype_integer(struct dmr_C *C, int size, int want_unsigned) -{ - return C->P->types[want_unsigned ? CUInt : CInt][size]; -} - -static struct token *handle_qualifiers(struct dmr_C *C, struct token *t, struct decl_state *ctx) -{ - while (dmrC_token_type(t) == TOKEN_IDENT) { - struct symbol *s = dmrC_lookup_symbol(t->ident, NS_TYPEDEF); - if (!s) - break; - if (s->type != SYM_KEYWORD) - break; - if (!(s->op->type & (KW_ATTRIBUTE | KW_QUALIFIER))) - break; - t = t->next; - if (s->op->declarator) - t = s->op->declarator(C, t, ctx); - } - return t; -} - -static struct token *declaration_specifiers(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - int seen = 0; - int cls = CInt; - int size = 0; - - while (dmrC_token_type(token) == TOKEN_IDENT) { - struct symbol *s = dmrC_lookup_symbol(token->ident, - NS_TYPEDEF | NS_SYMBOL); - if (!s || !(s->ns & NS_TYPEDEF)) - break; - if (s->type != SYM_KEYWORD) { - if (seen & Set_Any) - break; - seen |= Set_S | Set_T; - ctx->ctype.base_type = s->ctype.base_type; - apply_ctype(C, token->pos, &s->ctype, &ctx->ctype); - token = token->next; - continue; - } - if (s->op->type & KW_SPECIFIER) { - if (seen & s->op->test) { - specifier_conflict(C, token->pos, - seen & s->op->test, - token->ident); - break; - } - seen |= s->op->set; - cls += s->op->cls; - if (s->op->set & Set_Int128) - size = 2; - if (s->op->type & KW_SHORT) { - size = -1; - } else if (s->op->type & KW_LONG && size++) { - if (cls == CReal) { - specifier_conflict(C, token->pos, - Set_Vlong, - C->S->double_ident); - break; - } - seen |= Set_Vlong; - } - } - token = token->next; - if (s->op->declarator) - token = s->op->declarator(C, token, ctx); - if (s->op->type & KW_EXACT) { - ctx->ctype.base_type = s->ctype.base_type; - ctx->ctype.modifiers |= s->ctype.modifiers; - } - } - - if (!(seen & Set_S)) { /* not set explicitly? */ - struct symbol *base = &C->S->incomplete_ctype; - if (seen & Set_Any) - base = C->P->types[cls][size]; - ctx->ctype.base_type = base; - } - - if (ctx->ctype.modifiers & MOD_BITWISE) { - struct symbol *type; - ctx->ctype.modifiers &= ~MOD_BITWISE; - if (!dmrC_is_int_type(C->S, ctx->ctype.base_type)) { - dmrC_sparse_error(C, token->pos, "invalid modifier"); - return token; - } - type = dmrC_alloc_symbol(C->S, token->pos, SYM_BASETYPE); - *type = *ctx->ctype.base_type; - type->ctype.modifiers &= ~MOD_SPECIFIER; - type->ctype.base_type = ctx->ctype.base_type; - type->type = SYM_RESTRICT; - ctx->ctype.base_type = type; - dmrC_create_fouled(C->S, type); - } - return token; -} - -static struct token *abstract_array_static_declarator(struct dmr_C *C, struct token *token, int *has_static) -{ - while (token->ident == C->S->static_ident) { - if (*has_static) - dmrC_sparse_error(C, token->pos, "duplicate array static declarator"); - - *has_static = 1; - token = token->next; - } - return token; - -} -static struct token *abstract_array_declarator(struct dmr_C *C, struct token *token, struct symbol *sym) -{ - struct expression *expr = NULL; - int has_static = 0; - - token = abstract_array_static_declarator(C, token, &has_static); - - if (match_idents(C, token, C->S->restrict_ident, C->S->__restrict_ident, C->S->__restrict___ident, NULL)) - token = abstract_array_static_declarator(C, token->next, &has_static); - token = dmrC_parse_expression(C, token, &expr); - sym->array_size = expr; - return token; -} - -static struct token *skip_attribute(struct dmr_C *C, struct token *token) -{ - (void) C; - token = token->next; - if (dmrC_match_op(token, '(')) { - int depth = 1; - token = token->next; - while (depth && !dmrC_eof_token(token)) { - if (dmrC_token_type(token) == TOKEN_SPECIAL) { - if (token->special == '(') - depth++; - else if (token->special == ')') - depth--; - } - token = token->next; - } - } - return token; -} - -static struct token *skip_attributes(struct dmr_C *C, struct token *token) -{ - struct symbol *keyword; - for (;;) { - if (dmrC_token_type(token) != TOKEN_IDENT) - break; - keyword = dmrC_lookup_keyword(token->ident, NS_KEYWORD | NS_TYPEDEF); - if (!keyword || keyword->type != SYM_KEYWORD) - break; - if (!(keyword->op->type & KW_ATTRIBUTE)) - break; - token = dmrC_expect_token(C, token->next, '(', "after attribute"); - token = dmrC_expect_token(C, token, '(', "after attribute"); - for (;;) { - if (dmrC_eof_token(token)) - break; - if (dmrC_match_op(token, ';')) - break; - if (dmrC_token_type(token) != TOKEN_IDENT) - break; - token = skip_attribute(C, token); - if (!dmrC_match_op(token, ',')) - break; - token = token->next; - } - token = dmrC_expect_token(C, token, ')', "after attribute"); - token = dmrC_expect_token(C, token, ')', "after attribute"); - } - return token; -} - -static struct token *handle_attributes(struct dmr_C *C, struct token *token, struct decl_state *ctx, unsigned int keywords) -{ - struct symbol *keyword; - for (;;) { - if (dmrC_token_type(token) != TOKEN_IDENT) - break; - keyword = dmrC_lookup_keyword(token->ident, NS_KEYWORD | NS_TYPEDEF); - if (!keyword || keyword->type != SYM_KEYWORD) - break; - if (!(keyword->op->type & keywords)) - break; - token = keyword->op->declarator(C, token->next, ctx); - keywords &= KW_ATTRIBUTE; - } - return token; -} - -static int is_nested(struct dmr_C *C, struct token *token, struct token **p, - int prefer_abstract) -{ - /* - * This can be either a parameter list or a grouping. - * For the direct (non-abstract) case, we know if must be - * a parameter list if we already saw the identifier. - * For the abstract case, we know if must be a parameter - * list if it is empty or starts with a type. - */ - struct token *next = token->next; - - *p = next = skip_attributes(C, next); - - if (dmrC_token_type(next) == TOKEN_IDENT) { - if (dmrC_lookup_type(next)) - return !prefer_abstract; - return 1; - } - - if (dmrC_match_op(next, ')') || dmrC_match_op(next, SPECIAL_ELLIPSIS)) - return 0; - - return 1; -} - -enum kind { - Empty, K_R, Proto, Bad_Func, -}; - -static enum kind which_func(struct dmr_C *C, struct token *token, - struct ident **n, - int prefer_abstract) -{ - struct token *next = token->next; - - if (dmrC_token_type(next) == TOKEN_IDENT) { - if (dmrC_lookup_type(next)) - return Proto; - /* identifier list not in definition; complain */ - if (prefer_abstract) - dmrC_warning(C, token->pos, - "identifier list not in definition"); - return K_R; - } - - if (dmrC_token_type(next) != TOKEN_SPECIAL) - return Bad_Func; - - if (next->special == ')') { - /* don't complain about those */ - if (!n || dmrC_match_op(next->next, ';')) - return Empty; - dmrC_warning(C, next->pos, - "non-ANSI function declaration of function '%s'", - dmrC_show_ident(C, *n)); - return Empty; - } - - if (next->special == SPECIAL_ELLIPSIS) { - dmrC_warning(C, next->pos, - "variadic functions must have one named argument"); - return Proto; - } - - return Bad_Func; -} - -static struct token *direct_declarator(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - struct ctype *ctype = &ctx->ctype; - struct token *next; - struct ident **p = ctx->ident; - - if (ctx->ident && dmrC_token_type(token) == TOKEN_IDENT) { - *ctx->ident = token->ident; - token = token->next; - } else if (dmrC_match_op(token, '(') && - is_nested(C, token, &next, ctx->prefer_abstract)) { - struct symbol *base_type = ctype->base_type; - if (token->next != next) - next = handle_attributes(C, token->next, ctx, - KW_ATTRIBUTE); - token = declarator(C, next, ctx); - token = dmrC_expect_token(C, token, ')', "in nested declarator"); - while (ctype->base_type != base_type) - ctype = &ctype->base_type->ctype; - p = NULL; - } - - if (dmrC_match_op(token, '(')) { - enum kind kind = which_func(C, token, p, ctx->prefer_abstract); - struct symbol *fn; - fn = alloc_indirect_symbol(C, token->pos, ctype, SYM_FN); - token = token->next; - if (kind == K_R) - token = identifier_list(C, token, fn); - else if (kind == Proto) - token = parameter_type_list(C, token, fn); - token = dmrC_expect_token(C, token, ')', "in function declarator"); - fn->endpos = token->pos; - return token; - } - - while (dmrC_match_op(token, '[')) { - struct symbol *array; - array = alloc_indirect_symbol(C, token->pos, ctype, SYM_ARRAY); - token = abstract_array_declarator(C, token->next, array); - token = dmrC_expect_token(C, token, ']', "in abstract_array_declarator"); - array->endpos = token->pos; - ctype = &array->ctype; - } - return token; -} - -static struct token *pointer(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - while (dmrC_match_op(token,'*')) { - struct symbol *ptr = dmrC_alloc_symbol(C->S, token->pos, SYM_PTR); - ptr->ctype.modifiers = ctx->ctype.modifiers; - ptr->ctype.base_type = ctx->ctype.base_type; - ptr->ctype.as = ctx->ctype.as; - ptr->ctype.contexts = ctx->ctype.contexts; - ctx->ctype.modifiers = 0; - ctx->ctype.base_type = ptr; - ctx->ctype.as = 0; - ctx->ctype.contexts = NULL; - ctx->ctype.alignment = 0; - - token = handle_qualifiers(C, token->next, ctx); - ctx->ctype.base_type->endpos = token->pos; - } - return token; -} - -static struct token *declarator(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - token = pointer(C, token, ctx); - return direct_declarator(C, token, ctx); -} - -static struct token *handle_bitfield(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - struct ctype *ctype = &ctx->ctype; - struct expression *expr; - struct symbol *bitfield; - long long width; - - if (ctype->base_type != &C->S->int_type && !dmrC_is_int_type(C->S, ctype->base_type)) { - dmrC_sparse_error(C, token->pos, "invalid bitfield specifier for type %s.", - dmrC_show_typename(C, ctype->base_type)); - // Parse this to recover gracefully. - return dmrC_conditional_expression(C, token->next, &expr); - } - - bitfield = alloc_indirect_symbol(C, token->pos, ctype, SYM_BITFIELD); - token = dmrC_conditional_expression(C, token->next, &expr); - width = dmrC_const_expression_value(C, expr); - bitfield->bit_size = (int) width; - - if (width < 0 || width > INT_MAX) { - dmrC_sparse_error(C, token->pos, "invalid bitfield width, %lld.", width); - width = -1; - } else if (*ctx->ident && width == 0) { - dmrC_sparse_error(C, token->pos, "invalid named zero-width bitfield `%s'", - dmrC_show_ident(C, *ctx->ident)); - width = -1; - } else if (*ctx->ident) { - struct symbol *base_type = bitfield->ctype.base_type; - struct symbol *bitfield_type = base_type == &C->S->int_type ? bitfield : base_type; - int is_signed = !(bitfield_type->ctype.modifiers & MOD_UNSIGNED); - if (C->Wone_bit_signed_bitfield && width == 1 && is_signed) { - // Valid values are either {-1;0} or {0}, depending on integer - // representation. The latter makes for very efficient code... - dmrC_sparse_error(C, token->pos, "dubious one-bit signed bitfield"); - } - if (C->Wdefault_bitfield_sign && - bitfield_type->type != SYM_ENUM && - !(bitfield_type->ctype.modifiers & MOD_EXPLICITLY_SIGNED) && - is_signed) { - // The sign of bitfields is unspecified by default. - dmrC_warning(C, token->pos, "dubious bitfield without explicit `signed' or `unsigned'"); - } - } - bitfield->bit_size = (int) width; - bitfield->endpos = token->pos; - return token; -} - -static struct token *declaration_list(struct dmr_C *C, struct token *token, struct symbol_list **list) -{ - struct decl_state ctx = {.prefer_abstract = 0}; - struct ctype saved; - unsigned long mod; - - token = declaration_specifiers(C, token, &ctx); - mod = storage_modifiers(C, &ctx); - saved = ctx.ctype; - for (;;) { - struct symbol *decl = dmrC_alloc_symbol(C->S, token->pos, SYM_NODE); - ctx.ident = &decl->ident; - - token = declarator(C, token, &ctx); - if (dmrC_match_op(token, ':')) - token = handle_bitfield(C, token, &ctx); - - token = handle_attributes(C, token, &ctx, KW_ATTRIBUTE); - apply_modifiers(C, token->pos, &ctx); - - decl->ctype = ctx.ctype; - decl->ctype.modifiers |= mod; - decl->endpos = token->pos; - dmrC_add_symbol(C, list, decl); - if (!dmrC_match_op(token, ',')) - break; - token = token->next; - ctx.ctype = saved; - } - return token; -} - -static struct token *struct_declaration_list(struct dmr_C *C, struct token *token, struct symbol_list **list) -{ - while (!dmrC_match_op(token, '}')) { - if (dmrC_match_ident(token, C->S->_Static_assert_ident)) { - token = parse_static_assert(C, token, NULL); - continue; - } - if (!dmrC_match_op(token, ';')) - token = declaration_list(C, token, list); - if (!dmrC_match_op(token, ';')) { - dmrC_sparse_error(C, token->pos, "expected ; at end of declaration"); - break; - } - token = token->next; - } - return token; -} - -static struct token *parameter_declaration(struct dmr_C *C, struct token *token, struct symbol *sym) -{ - struct decl_state ctx = {.prefer_abstract = 1}; - - token = declaration_specifiers(C, token, &ctx); - ctx.ident = &sym->ident; - token = declarator(C, token, &ctx); - token = handle_attributes(C, token, &ctx, KW_ATTRIBUTE); - apply_modifiers(C, token->pos, &ctx); - sym->ctype = ctx.ctype; - sym->ctype.modifiers |= storage_modifiers(C, &ctx); - sym->endpos = token->pos; - sym->forced_arg = ctx.storage_class == SForced; - return token; -} - -struct token *dmrC_typename(struct dmr_C *C, struct token *token, struct symbol **p, int *forced) -{ - struct decl_state ctx = {.prefer_abstract = 1}; - int klass; - struct symbol *sym = dmrC_alloc_symbol(C->S, token->pos, SYM_NODE); - *p = sym; - token = declaration_specifiers(C, token, &ctx); - token = declarator(C, token, &ctx); - apply_modifiers(C, token->pos, &ctx); - sym->ctype = ctx.ctype; - sym->endpos = token->pos; - klass = ctx.storage_class; - if (forced) { - *forced = 0; - if (klass == SForced) { - *forced = 1; - klass = 0; - } - } - if (klass) - dmrC_warning(C, sym->pos, "storage class in typename (%s %s)", - storage_class[klass], dmrC_show_typename(C, sym)); - return token; -} - -static struct token *expression_statement(struct dmr_C *C, struct token *token, struct expression **tree) -{ - token = dmrC_parse_expression(C, token, tree); - return dmrC_expect_token(C, token, ';', "at end of statement"); -} - -static struct token *parse_asm_operands(struct dmr_C *C, struct token *token, struct statement *stmt, - struct expression_list **inout) -{ - (void) stmt; - struct expression *expr; - - /* Allow empty operands */ - if (dmrC_match_op(token->next, ':') || dmrC_match_op(token->next, ')')) - return token->next; - do { - struct ident *ident = NULL; - if (dmrC_match_op(token->next, '[') && - dmrC_token_type(token->next->next) == TOKEN_IDENT && - dmrC_match_op(token->next->next->next, ']')) { - ident = token->next->next->ident; - token = token->next->next->next; - } - dmrC_add_expression(C, inout, (struct expression *)ident); /* UGGLEE!!! */ - token = dmrC_primary_expression(C, token->next, &expr); - dmrC_add_expression(C, inout, expr); - token = dmrC_parens_expression(C, token, &expr, "in asm parameter"); - dmrC_add_expression(C, inout, expr); - } while (dmrC_match_op(token, ',')); - return token; -} - -static struct token *parse_asm_clobbers(struct dmr_C *C, struct token *token, struct statement *stmt, - struct expression_list **clobbers) -{ - (void) stmt; - struct expression *expr; - - do { - token = dmrC_primary_expression(C, token->next, &expr); - if (expr) - dmrC_add_expression(C, clobbers, expr); - } while (dmrC_match_op(token, ',')); - return token; -} - -static struct token *parse_asm_labels(struct dmr_C *C, struct token *token, struct statement *stmt, - struct symbol_list **labels) -{ - struct symbol *label; - (void) stmt; - do { - token = token->next; /* skip ':' and ',' */ - if (dmrC_token_type(token) != TOKEN_IDENT) - return token; - label = dmrC_label_symbol(C, token); - dmrC_add_symbol(C, labels, label); - token = token->next; - } while (dmrC_match_op(token, ',')); - return token; -} - -static struct token *parse_asm_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - int is_goto = 0; - - token = token->next; - stmt->type = STMT_ASM; - if (match_idents(C, token, C->S->__volatile___ident, C->S->__volatile_ident, C->S->volatile_ident, NULL)) { - token = token->next; - } - if (dmrC_token_type(token) == TOKEN_IDENT && token->ident == C->S->goto_ident) { - is_goto = 1; - token = token->next; - } - token = dmrC_expect_token(C, token, '(', "after asm"); - token = dmrC_parse_expression(C, token, &stmt->asm_string); - if (dmrC_match_op(token, ':')) - token = parse_asm_operands(C, token, stmt, &stmt->asm_outputs); - if (dmrC_match_op(token, ':')) - token = parse_asm_operands(C, token, stmt, &stmt->asm_inputs); - if (dmrC_match_op(token, ':')) - token = parse_asm_clobbers(C, token, stmt, &stmt->asm_clobbers); - if (is_goto && dmrC_match_op(token, ':')) - token = parse_asm_labels(C, token, stmt, &stmt->asm_labels); - token = dmrC_expect_token(C, token, ')', "after asm"); - return dmrC_expect_token(C, token, ';', "at end of asm-statement"); -} - -static struct token *parse_asm_declarator(struct dmr_C *C, struct token *token, struct decl_state *ctx) -{ - (void) ctx; - struct expression *expr; - token = dmrC_expect_token(C, token, '(', "after asm"); - token = dmrC_parse_expression(C, token->next, &expr); - token = dmrC_expect_token(C, token, ')', "after asm"); - return token; -} - -static struct token *parse_static_assert(struct dmr_C *C, struct token *token, struct symbol_list **unused) -{ - (void) unused; - struct expression *cond = NULL, *message = NULL; - - token = dmrC_expect_token(C, token->next, '(', "after _Static_assert"); - token = dmrC_constant_expression(C, token, &cond); - if (!cond) - dmrC_sparse_error(C, token->pos, "Expected constant expression"); - token = dmrC_expect_token(C, token, ',', "after conditional expression in _Static_assert"); - token = dmrC_parse_expression(C, token, &message); - if (!message || message->type != EXPR_STRING) { - struct position pos; - - pos = message ? message->pos : token->pos; - dmrC_sparse_error(C, pos, "bad or missing string literal"); - cond = NULL; - } - token = dmrC_expect_token(C, token, ')', "after diagnostic message in _Static_assert"); - - token = dmrC_expect_token(C, token, ';', "after _Static_assert()"); - - if (cond && !dmrC_const_expression_value(C, cond) && cond->type == EXPR_VALUE) - dmrC_sparse_error(C, cond->pos, "static assertion failed: %s", - dmrC_show_string(C, message->string)); - return token; -} - -/* Make a statement out of an expression */ -static struct statement *make_statement(struct dmr_C *C, struct expression *expr) -{ - struct statement *stmt; - - if (!expr) - return NULL; - stmt = dmrC_alloc_statement(C, expr->pos, STMT_EXPRESSION); - stmt->expression = expr; - return stmt; -} - -/* - * All iterators have two symbols associated with them: - * the "continue" and "break" symbols, which are targets - * for continue and break statements respectively. - * - * They are in a special name-space, but they follow - * all the normal visibility rules, so nested iterators - * automatically work right. - */ -static void start_iterator(struct dmr_C *C, struct statement *stmt) -{ - struct symbol *cont, *brk; - - dmrC_start_symbol_scope(C); - cont = dmrC_alloc_symbol(C->S, stmt->pos, SYM_NODE); - dmrC_bind_symbol(C->S, cont, C->S->continue_ident, NS_ITERATOR); - brk = dmrC_alloc_symbol(C->S, stmt->pos, SYM_NODE); - dmrC_bind_symbol(C->S, brk, C->S->break_ident, NS_ITERATOR); - - stmt->type = STMT_ITERATOR; - stmt->iterator_break = brk; - stmt->iterator_continue = cont; - fn_local_symbol(C, brk); - fn_local_symbol(C, cont); -} - -static void end_iterator(struct dmr_C *C, struct statement *stmt) -{ - (void) stmt; - dmrC_end_symbol_scope(C); -} - -static struct statement *start_function(struct dmr_C *C, struct symbol *sym) -{ - struct symbol *ret; - struct statement *stmt = dmrC_alloc_statement(C, sym->pos, STMT_COMPOUND); - - dmrC_start_function_scope(C); - ret = dmrC_alloc_symbol(C->S, sym->pos, SYM_NODE); - ret->ctype = sym->ctype.base_type->ctype; - ret->ctype.modifiers &= ~(MOD_STORAGE | MOD_CONST | MOD_VOLATILE | MOD_TLS | MOD_INLINE | MOD_ADDRESSABLE | MOD_NOCAST | MOD_NODEREF | MOD_ACCESSED | MOD_TOPLEVEL); - ret->ctype.modifiers |= (MOD_AUTO | MOD_REGISTER); - dmrC_bind_symbol(C->S, ret, C->S->return_ident, NS_ITERATOR); - stmt->ret = ret; - fn_local_symbol(C, ret); - - // Currently parsed symbol for __func__/__FUNCTION__/__PRETTY_FUNCTION__ - C->current_fn = sym; - - return stmt; -} - -static void end_function(struct dmr_C *C, struct symbol *sym) -{ - (void) sym; - C->current_fn = NULL; - dmrC_end_function_scope(C); -} - -/* - * A "switch()" statement, like an iterator, has a - * the "break" symbol associated with it. It works - * exactly like the iterator break - it's the target - * for any break-statements in scope, and means that - * "break" handling doesn't even need to know whether - * it's breaking out of an iterator or a switch. - * - * In addition, the "case" symbol is a marker for the - * case/default statements to find the switch statement - * that they are associated with. - */ -static void start_switch(struct dmr_C *C, struct statement *stmt) -{ - struct symbol *brk, *switch_case; - - dmrC_start_symbol_scope(C); - brk = dmrC_alloc_symbol(C->S, stmt->pos, SYM_NODE); - dmrC_bind_symbol(C->S, brk, C->S->break_ident, NS_ITERATOR); - - switch_case = dmrC_alloc_symbol(C->S, stmt->pos, SYM_NODE); - dmrC_bind_symbol(C->S, switch_case, C->S->case_ident, NS_ITERATOR); - switch_case->stmt = stmt; - - stmt->type = STMT_SWITCH; - stmt->switch_break = brk; - stmt->switch_case = switch_case; - - fn_local_symbol(C, brk); - fn_local_symbol(C, switch_case); -} - -static void end_switch(struct dmr_C *C, struct statement *stmt) -{ - if (!stmt->switch_case->symbol_list) - dmrC_warning(C, stmt->pos, "switch with no cases"); - dmrC_end_symbol_scope(C); -} - -static void add_case_statement(struct dmr_C *C, struct statement *stmt) -{ - struct symbol *target = dmrC_lookup_symbol(C->S->case_ident, NS_ITERATOR); - struct symbol *sym; - - if (!target) { - dmrC_sparse_error(C, stmt->pos, "not in switch scope"); - stmt->type = STMT_NONE; - return; - } - sym = dmrC_alloc_symbol(C->S, stmt->pos, SYM_NODE); - dmrC_add_symbol(C, &target->symbol_list, sym); - sym->stmt = stmt; - stmt->case_label = sym; - fn_local_symbol(C, sym); -} - -static struct token *parse_return_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - struct symbol *target = dmrC_lookup_symbol(C->S->return_ident, NS_ITERATOR); - - if (!target) - dmrC_error_die(C, token->pos, "internal error: return without a function target"); - stmt->type = STMT_RETURN; - stmt->ret_target = target; - return expression_statement(C, token->next, &stmt->ret_value); -} - -static void validate_for_loop_decl(struct dmr_C *C, struct symbol *sym) -{ - unsigned long storage = sym->ctype.modifiers & MOD_STORAGE; - - if (storage & ~(MOD_AUTO | MOD_REGISTER)) { - const char *name = dmrC_show_ident(C, sym->ident); - dmrC_sparse_error(C, sym->pos, "non-local var '%s' in for-loop initializer", name); - sym->ctype.modifiers &= ~MOD_STORAGE; - } -} -static struct token *parse_for_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - struct symbol_list *syms; - struct expression *e1, *e2, *e3; - struct statement *iterator; - - start_iterator(C, stmt); - token = dmrC_expect_token(C, token->next, '(', "after 'for'"); - - syms = NULL; - e1 = NULL; - /* C99 variable declaration? */ - if (dmrC_lookup_type(token)) { - token = dmrC_external_declaration(C, token, &syms, validate_for_loop_decl); - } else { - token = dmrC_parse_expression(C, token, &e1); - token = dmrC_expect_token(C, token, ';', "in 'for'"); - } - token = dmrC_parse_expression(C, token, &e2); - token = dmrC_expect_token(C, token, ';', "in 'for'"); - token = dmrC_parse_expression(C, token, &e3); - token = dmrC_expect_token(C, token, ')', "in 'for'"); - token = statement(C, token, &iterator); - - stmt->iterator_syms = syms; - stmt->iterator_pre_statement = make_statement(C, e1); - stmt->iterator_pre_condition = e2; - stmt->iterator_post_statement = make_statement(C, e3); - stmt->iterator_post_condition = NULL; - stmt->iterator_statement = iterator; - end_iterator(C, stmt); - - return token; -} - -static struct token *parse_while_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - struct expression *expr; - struct statement *iterator; - - start_iterator(C, stmt); - token = dmrC_parens_expression(C, token->next, &expr, "after 'while'"); - token = statement(C, token, &iterator); - - stmt->iterator_pre_condition = expr; - stmt->iterator_post_condition = NULL; - stmt->iterator_statement = iterator; - end_iterator(C, stmt); - - return token; -} - -static struct token *parse_do_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - struct expression *expr; - struct statement *iterator; - - start_iterator(C, stmt); - token = statement(C, token->next, &iterator); - if (dmrC_token_type(token) == TOKEN_IDENT && token->ident == C->S->while_ident) - token = token->next; - else - dmrC_sparse_error(C, token->pos, "expected 'while' after 'do'"); - token = dmrC_parens_expression(C, token, &expr, "after 'do-while'"); - - stmt->iterator_post_condition = expr; - stmt->iterator_statement = iterator; - end_iterator(C, stmt); - - if (iterator && iterator->type != STMT_COMPOUND && C->Wdo_while) - dmrC_warning(C, iterator->pos, "do-while statement is not a compound statement"); - - return dmrC_expect_token(C, token, ';', "after statement"); -} - -static struct token *parse_if_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - stmt->type = STMT_IF; - token = dmrC_parens_expression(C, token->next, &stmt->if_conditional, "after if"); - token = statement(C, token, &stmt->if_true); - if (dmrC_token_type(token) != TOKEN_IDENT) - return token; - if (token->ident != C->S->else_ident) - return token; - return statement(C, token->next, &stmt->if_false); -} - -static inline struct token *case_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - stmt->type = STMT_CASE; - token = dmrC_expect_token(C, token, ':', "after default/case"); - add_case_statement(C, stmt); - return statement(C, token, &stmt->case_statement); -} - -static struct token *parse_case_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - token = dmrC_parse_expression(C, token->next, &stmt->case_expression); - if (dmrC_match_op(token, SPECIAL_ELLIPSIS)) - token = dmrC_parse_expression(C, token->next, &stmt->case_to); - return case_statement(C, token, stmt); -} - -static struct token *parse_default_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - return case_statement(C, token->next, stmt); -} - -static struct token *parse_loop_iterator(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - struct symbol *target = dmrC_lookup_symbol(token->ident, NS_ITERATOR); - stmt->type = STMT_GOTO; - stmt->goto_label = target; - if (!target) - dmrC_sparse_error(C, stmt->pos, "break/continue not in iterator scope"); - return dmrC_expect_token(C, token->next, ';', "at end of statement"); -} - -static struct token *parse_switch_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - stmt->type = STMT_SWITCH; - start_switch(C, stmt); - token = dmrC_parens_expression(C, token->next, &stmt->switch_expression, "after 'switch'"); - token = statement(C, token, &stmt->switch_statement); - end_switch(C, stmt); - return token; -} - -static struct token *parse_goto_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - stmt->type = STMT_GOTO; - token = token->next; - if (dmrC_match_op(token, '*')) { - token = dmrC_parse_expression(C, token->next, &stmt->goto_expression); - dmrC_add_statement(C, &C->P->function_computed_goto_list, stmt); - } else if (dmrC_token_type(token) == TOKEN_IDENT) { - stmt->goto_label = dmrC_label_symbol(C, token); - token = token->next; - } else { - dmrC_sparse_error(C, token->pos, "Expected identifier or goto expression"); - } - return dmrC_expect_token(C, token, ';', "at end of statement"); -} - -static struct token *parse_context_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - stmt->type = STMT_CONTEXT; - token = dmrC_parse_expression(C, token->next, &stmt->expression); - if (stmt->expression->type == EXPR_PREOP - && stmt->expression->op == '(' - && stmt->expression->unop->type == EXPR_COMMA) { - struct expression *expr; - expr = stmt->expression->unop; - stmt->context = expr->left; - stmt->expression = expr->right; - } - return dmrC_expect_token(C, token, ';', "at end of statement"); -} - -static struct token *parse_range_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - stmt->type = STMT_RANGE; - token = dmrC_assignment_expression(C, token->next, &stmt->range_expression); - token = dmrC_expect_token(C, token, ',', "after range expression"); - token = dmrC_assignment_expression(C, token, &stmt->range_low); - token = dmrC_expect_token(C, token, ',', "after low range"); - token = dmrC_assignment_expression(C, token, &stmt->range_high); - return dmrC_expect_token(C, token, ';', "after range statement"); -} - -static struct token *statement(struct dmr_C *C, struct token *token, struct statement **tree) -{ - struct statement *stmt = dmrC_alloc_statement(C, token->pos, STMT_NONE); - - *tree = stmt; - if (dmrC_token_type(token) == TOKEN_IDENT) { - struct symbol *s = dmrC_lookup_keyword(token->ident, NS_KEYWORD); - if (s && s->op->statement) - return s->op->statement(C, token, stmt); - - if (dmrC_match_op(token->next, ':')) { - struct symbol *s = dmrC_label_symbol(C, token); - stmt->type = STMT_LABEL; - stmt->label_identifier = s; - if (s->stmt) - dmrC_sparse_error(C, stmt->pos, "label '%s' redefined", dmrC_show_ident(C, token->ident)); - s->stmt = stmt; - token = skip_attributes(C, token->next->next); - return statement(C, token, &stmt->label_statement); - } - } - - if (dmrC_match_op(token, '{')) { - stmt->type = STMT_COMPOUND; - dmrC_start_symbol_scope(C); - token = dmrC_compound_statement(C, token->next, stmt); - dmrC_end_symbol_scope(C); - - return dmrC_expect_token(C, token, '}', "at end of compound statement"); - } - - stmt->type = STMT_EXPRESSION; - return expression_statement(C, token, &stmt->expression); -} - -/* gcc extension - __label__ ident-list; in the beginning of compound stmt */ -static struct token *label_statement(struct dmr_C *C, struct token *token) -{ - while (dmrC_token_type(token) == TOKEN_IDENT) { - struct symbol *sym = dmrC_alloc_symbol(C->S, token->pos, SYM_LABEL); - /* it's block-scope, but we want label namespace */ - dmrC_bind_symbol(C->S, sym, token->ident, NS_SYMBOL); - sym->ns = NS_LABEL; - fn_local_symbol(C, sym); - token = token->next; - if (!dmrC_match_op(token, ',')) - break; - token = token->next; - } - return dmrC_expect_token(C, token, ';', "at end of label declaration"); -} - -static struct token * statement_list(struct dmr_C *C, struct token *token, struct statement_list **list) -{ - int seen_statement = 0; - while (dmrC_token_type(token) == TOKEN_IDENT && - token->ident == C->S->__label___ident) - token = label_statement(C, token->next); - for (;;) { - struct statement * stmt; - if (dmrC_eof_token(token)) - break; - if (dmrC_match_op(token, '}')) - break; - if (dmrC_match_ident(token, C->S->_Static_assert_ident)) { - token = parse_static_assert(C, token, NULL); - continue; - } - if (dmrC_lookup_type(token)) { - if (seen_statement) { - dmrC_warning(C, token->pos, "mixing declarations and code"); - seen_statement = 0; - } - stmt = dmrC_alloc_statement(C, token->pos, STMT_DECLARATION); - token = dmrC_external_declaration(C, token, &stmt->declaration, NULL); - } else { - seen_statement = C->Wdeclarationafterstatement; - token = statement(C, token, &stmt); - } - dmrC_add_statement(C, list, stmt); - } - return token; -} - -static struct token *identifier_list(struct dmr_C *C, struct token *token, struct symbol *fn) -{ - struct symbol_list **list = &fn->arguments; - for (;;) { - struct symbol *sym = dmrC_alloc_symbol(C->S, token->pos, SYM_NODE); - sym->ident = token->ident; - token = token->next; - sym->endpos = token->pos; - sym->ctype.base_type = &C->S->incomplete_ctype; - dmrC_add_symbol(C, list, sym); - if (!dmrC_match_op(token, ',') || - dmrC_token_type(token->next) != TOKEN_IDENT || - dmrC_lookup_type(token->next)) - break; - token = token->next; - } - return token; -} - -static struct token *parameter_type_list(struct dmr_C *C, struct token *token, struct symbol *fn) -{ - struct symbol_list **list = &fn->arguments; - - for (;;) { - struct symbol *sym; - - if (dmrC_match_op(token, SPECIAL_ELLIPSIS)) { - fn->variadic = 1; - token = token->next; - break; - } - - sym = dmrC_alloc_symbol(C->S, token->pos, SYM_NODE); - token = parameter_declaration(C, token, sym); - if (sym->ctype.base_type == &C->S->void_ctype) { - /* Special case: (void) */ - if (!*list && !sym->ident) - break; - dmrC_warning(C, token->pos, "void parameter"); - } - dmrC_add_symbol(C, list, sym); - if (!dmrC_match_op(token, ',')) - break; - token = token->next; - } - return token; -} - -struct token *dmrC_compound_statement(struct dmr_C *C, struct token *token, struct statement *stmt) -{ - token = statement_list(C, token, &stmt->stmts); - return token; -} - -static struct expression *identifier_expression(struct dmr_C *C, struct token *token) -{ - struct expression *expr = dmrC_alloc_expression(C, token->pos, EXPR_IDENTIFIER); - expr->expr_ident = token->ident; - return expr; -} - -static struct expression *index_expression(struct dmr_C *C, struct expression *from, struct expression *to) -{ - int idx_from, idx_to; - struct expression *expr = dmrC_alloc_expression(C, from->pos, EXPR_INDEX); - - idx_from = (int) dmrC_const_expression_value(C, from); - idx_to = idx_from; - if (to) { - idx_to = (int) dmrC_const_expression_value(C, to); - if (idx_to < idx_from || idx_from < 0) - dmrC_warning(C, from->pos, "nonsense array initializer index range"); - } - expr->idx_from = idx_from; - expr->idx_to = idx_to; - return expr; -} - -static struct token *single_initializer(struct dmr_C *C, struct expression **ep, struct token *token) -{ - int expect_equal = 0; - struct token *next = token->next; - struct expression **tail = ep; - int nested; - - *ep = NULL; - - if ((dmrC_token_type(token) == TOKEN_IDENT) && dmrC_match_op(next, ':')) { - struct expression *expr = identifier_expression(C, token); - if (C->Wold_initializer) - dmrC_warning(C, token->pos, "obsolete struct initializer, use C99 syntax"); - token = dmrC_initializer(C, &expr->ident_expression, next->next); - if (expr->ident_expression) - *ep = expr; - return token; - } - - for (tail = ep, nested = 0; ; nested++, next = token->next) { - if (dmrC_match_op(token, '.') && (dmrC_token_type(next) == TOKEN_IDENT)) { - struct expression *expr = identifier_expression(C, next); - *tail = expr; - tail = &expr->ident_expression; - expect_equal = 1; - token = next->next; - } else if (dmrC_match_op(token, '[')) { - struct expression *from = NULL, *to = NULL, *expr; - token = dmrC_constant_expression(C, token->next, &from); - if (!from) { - dmrC_sparse_error(C, token->pos, "Expected constant expression"); - break; - } - if (dmrC_match_op(token, SPECIAL_ELLIPSIS)) - token = dmrC_constant_expression(C, token->next, &to); - expr = index_expression(C, from, to); - *tail = expr; - tail = &expr->idx_expression; - token = dmrC_expect_token(C, token, ']', "at end of initializer index"); - if (nested) - expect_equal = 1; - } else { - break; - } - } - if (nested && !expect_equal) { - if (!dmrC_match_op(token, '=')) - dmrC_warning(C, token->pos, "obsolete array initializer, use C99 syntax"); - else - expect_equal = 1; - } - if (expect_equal) - token = dmrC_expect_token(C, token, '=', "at end of initializer index"); - - token = dmrC_initializer(C, tail, token); - if (!*tail) - *ep = NULL; - return token; -} - -static struct token *initializer_list(struct dmr_C *C, struct expression_list **list, struct token *token) -{ - struct expression *expr; - - for (;;) { - token = single_initializer(C, &expr, token); - if (!expr) - break; - dmrC_add_expression(C, list, expr); - if (!dmrC_match_op(token, ',')) - break; - token = token->next; - } - return token; -} - -struct token *dmrC_initializer(struct dmr_C *C, struct expression **tree, struct token *token) -{ - if (dmrC_match_op(token, '{')) { - struct expression *expr = dmrC_alloc_expression(C, token->pos, EXPR_INITIALIZER); - *tree = expr; - token = initializer_list(C, &expr->expr_list, token->next); - return dmrC_expect_token(C, token, '}', "at end of initializer"); - } - return dmrC_assignment_expression(C, token, tree); -} - -static void declare_argument(struct dmr_C *C, struct symbol *sym, struct symbol *fn) -{ - (void) fn; - if (!sym->ident) { - dmrC_sparse_error(C, sym->pos, "no identifier for function argument"); - return; - } - dmrC_bind_symbol(C->S, sym, sym->ident, NS_SYMBOL); -} - -static struct token *parse_function_body(struct dmr_C *C, struct token *token, struct symbol *decl, - struct symbol_list **list) -{ - struct symbol_list **old_symbol_list; - struct symbol *base_type = decl->ctype.base_type; - struct statement *stmt, **p; - struct symbol *prev; - struct symbol *arg; - - old_symbol_list = C->P->function_symbol_list; - if (decl->ctype.modifiers & MOD_INLINE) { - C->P->function_symbol_list = &decl->inline_symbol_list; - p = &base_type->inline_stmt; - } else { - C->P->function_symbol_list = &decl->symbol_list; - p = &base_type->stmt; - } - C->P->function_computed_target_list = NULL; - C->P->function_computed_goto_list = NULL; - - if (decl->ctype.modifiers & MOD_EXTERN) { - if (!(decl->ctype.modifiers & MOD_INLINE)) - dmrC_warning(C, decl->pos, "function '%s' with external linkage has definition", dmrC_show_ident(C, decl->ident)); - } - if (!(decl->ctype.modifiers & MOD_STATIC)) - decl->ctype.modifiers |= MOD_EXTERN; - - stmt = start_function(C, decl); - - *p = stmt; - FOR_EACH_PTR (base_type->arguments, arg) { - declare_argument(C, arg, base_type); - } END_FOR_EACH_PTR(arg); - - token = dmrC_compound_statement(C, token->next, stmt); - - end_function(C, decl); - if (!(decl->ctype.modifiers & MOD_INLINE)) - dmrC_add_symbol(C, list, decl); - dmrC_check_declaration(C->S, decl); - decl->definition = decl; - prev = decl->same_symbol; - if (prev && prev->definition) { - dmrC_warning(C, decl->pos, "multiple definitions for function '%s'", - dmrC_show_ident(C, decl->ident)); - dmrC_info(C, prev->definition->pos, " the previous one is here"); - } else { - while (prev) { - dmrC_rebind_scope(C, prev, decl->scope); - prev->definition = decl; - prev = prev->same_symbol; - } - } - C->P->function_symbol_list = old_symbol_list; - if (C->P->function_computed_goto_list) { - if (!C->P->function_computed_target_list) - dmrC_warning(C, decl->pos, "function '%s' has computed goto but no targets?", dmrC_show_ident(C, decl->ident)); - else { - FOR_EACH_PTR(C->P->function_computed_goto_list, stmt) { - stmt->target_list = C->P->function_computed_target_list; - } END_FOR_EACH_PTR(stmt); - } - } - return dmrC_expect_token(C, token, '}', "at end of function"); -} - -static void promote_k_r_types(struct dmr_C *C, struct symbol *arg) -{ - struct symbol *base = arg->ctype.base_type; - if (base && base->ctype.base_type == &C->S->int_type && (base->ctype.modifiers & (MOD_CHAR | MOD_SHORT))) { - arg->ctype.base_type = &C->S->int_ctype; - } -} - -static void apply_k_r_types(struct dmr_C *C, struct symbol_list *argtypes, struct symbol *fn) -{ - struct symbol_list *real_args = fn->ctype.base_type->arguments; - struct symbol *arg; - - FOR_EACH_PTR(real_args, arg) { - struct symbol *type; - - /* This is quadratic in the number of arguments. We _really_ don't care */ - FOR_EACH_PTR(argtypes, type) { - if (type->ident == arg->ident) - goto match; - } END_FOR_EACH_PTR(type); - dmrC_sparse_error(C, arg->pos, "missing type declaration for parameter '%s'", dmrC_show_ident(C, arg->ident)); - continue; -match: - type->used = 1; - /* "char" and "short" promote to "int" */ - promote_k_r_types(C, type); - - arg->ctype = type->ctype; - } END_FOR_EACH_PTR(arg); - - FOR_EACH_PTR(argtypes, arg) { - if (!arg->used) - dmrC_warning(C, arg->pos, "nonsensical parameter declaration '%s'", dmrC_show_ident(C, arg->ident)); - } END_FOR_EACH_PTR(arg); -} - -static struct token *parse_k_r_arguments(struct dmr_C *C, struct token *token, struct symbol *decl, - struct symbol_list **list) -{ - struct symbol_list *args = NULL; - - dmrC_warning(C, token->pos, "non-ANSI definition of function '%s'", dmrC_show_ident(C, decl->ident)); - do { - token = declaration_list(C, token, &args); - if (!dmrC_match_op(token, ';')) { - dmrC_sparse_error(C, token->pos, "expected ';' at end of parameter declaration"); - break; - } - token = token->next; - } while (dmrC_lookup_type(token)); - - apply_k_r_types(C, args, decl); - - if (!dmrC_match_op(token, '{')) { - dmrC_sparse_error(C, token->pos, "expected function body"); - return token; - } - return parse_function_body(C, token, decl, list); -} - -static struct token *toplevel_asm_declaration(struct dmr_C *C, struct token *token, struct symbol_list **list) -{ - struct symbol *anon = dmrC_alloc_symbol(C->S, token->pos, SYM_NODE); - struct symbol *fn = dmrC_alloc_symbol(C->S, token->pos, SYM_FN); - struct statement *stmt; - - anon->ctype.base_type = fn; - stmt = dmrC_alloc_statement(C, token->pos, STMT_NONE); - fn->stmt = stmt; - - token = parse_asm_statement(C, token, stmt); - - dmrC_add_symbol(C, list, anon); - return token; -} - -struct token *dmrC_external_declaration(struct dmr_C *C, struct token *token, struct symbol_list **list, validate_decl_t validate_decl) -{ - struct ident *ident = NULL; - struct symbol *decl; - struct decl_state ctx = { .ident = &ident }; - struct ctype saved; - struct symbol *base_type; - unsigned long mod; - int is_typedef; - - /* Top-level inline asm? or static assertion? */ - if (dmrC_token_type(token) == TOKEN_IDENT) { - struct symbol *s = dmrC_lookup_keyword(token->ident, NS_KEYWORD); - if (s && s->op->toplevel) - return s->op->toplevel(C, token, list); - } - - /* Parse declaration-specifiers, if any */ - token = declaration_specifiers(C, token, &ctx); - mod = storage_modifiers(C, &ctx); - decl = dmrC_alloc_symbol(C->S, token->pos, SYM_NODE); - /* Just a type declaration? */ - if (dmrC_match_op(token, ';')) { - apply_modifiers(C, token->pos, &ctx); - return token->next; - } - - saved = ctx.ctype; - token = declarator(C, token, &ctx); - token = handle_attributes(C, token, &ctx, KW_ATTRIBUTE | KW_ASM); - apply_modifiers(C, token->pos, &ctx); - - decl->ctype = ctx.ctype; - decl->ctype.modifiers |= mod; - decl->endpos = token->pos; - - /* Just a type declaration? */ - if (!ident) { - dmrC_warning(C, token->pos, "missing identifier in declaration"); - return dmrC_expect_token(C, token, ';', "at the end of type declaration"); - } - - /* type define declaration? */ - is_typedef = ctx.storage_class == STypedef; - - /* Typedefs don't have meaningful storage */ - if (is_typedef) - decl->ctype.modifiers |= MOD_USERTYPE; - - dmrC_bind_symbol(C->S, decl, ident, is_typedef ? NS_TYPEDEF: NS_SYMBOL); - - base_type = decl->ctype.base_type; - - if (is_typedef) { - if (base_type && !base_type->ident) { - switch (base_type->type) { - case SYM_STRUCT: - case SYM_UNION: - case SYM_ENUM: - case SYM_RESTRICT: - base_type->ident = ident; - break; - default: - break; - } - } - } else if (base_type && base_type->type == SYM_FN) { - if (base_type->ctype.base_type == &C->S->incomplete_ctype) { - dmrC_warning(C, decl->pos, "'%s()' has implicit return type", - dmrC_show_ident(C, decl->ident)); - base_type->ctype.base_type = &C->S->int_ctype; - } - /* K&R argument declaration? */ - if (dmrC_lookup_type(token)) - return parse_k_r_arguments(C, token, decl, list); - if (dmrC_match_op(token, '{')) - return parse_function_body(C, token, decl, list); - - if (!(decl->ctype.modifiers & MOD_STATIC)) - decl->ctype.modifiers |= MOD_EXTERN; - } else if (base_type == &C->S->void_ctype && !(decl->ctype.modifiers & MOD_EXTERN)) { - dmrC_sparse_error(C, token->pos, "void declaration"); - } - if (base_type == &C->S->incomplete_ctype) { - dmrC_warning(C, decl->pos, "'%s' has implicit type", dmrC_show_ident(C, decl->ident)); - decl->ctype.base_type = &C->S->int_ctype; - } - - for (;;) { - if (!is_typedef && dmrC_match_op(token, '=')) { - token = dmrC_initializer(C, &decl->initializer, token->next); - } - if (!is_typedef) { - if (validate_decl) - validate_decl(C, decl); - if (decl->initializer && decl->ctype.modifiers & MOD_EXTERN) { - dmrC_warning(C, decl->pos, "symbol with external linkage has initializer"); - decl->ctype.modifiers &= ~MOD_EXTERN; - } - if (!(decl->ctype.modifiers & (MOD_EXTERN | MOD_INLINE))) { - dmrC_add_symbol(C, list, decl); - fn_local_symbol(C, decl); - } - } - dmrC_check_declaration(C->S, decl); - if (decl->same_symbol) { - decl->definition = decl->same_symbol->definition; - decl->op = decl->same_symbol->op; - } - - if (!dmrC_match_op(token, ',')) - break; - - token = token->next; - ident = NULL; - decl = dmrC_alloc_symbol(C->S, token->pos, SYM_NODE); - ctx.ctype = saved; - token = handle_attributes(C, token, &ctx, KW_ATTRIBUTE); - token = declarator(C, token, &ctx); - token = handle_attributes(C, token, &ctx, KW_ATTRIBUTE | KW_ASM); - apply_modifiers(C, token->pos, &ctx); - decl->ctype = ctx.ctype; - decl->ctype.modifiers |= mod; - decl->endpos = token->pos; - if (!ident) { - dmrC_sparse_error(C, token->pos, "expected identifier name in type definition"); - return token; - } - - if (is_typedef) - decl->ctype.modifiers |= MOD_USERTYPE; - - dmrC_bind_symbol(C->S, decl, ident, is_typedef ? NS_TYPEDEF: NS_SYMBOL); - - /* Function declarations are automatically extern unless specifically static */ - base_type = decl->ctype.base_type; - if (!is_typedef && base_type && base_type->type == SYM_FN) { - if (!(decl->ctype.modifiers & MOD_STATIC)) - decl->ctype.modifiers |= MOD_EXTERN; - } - } - return dmrC_expect_token(C, token, ';', "at end of declaration"); -} - -int dmrC_test_parse() { - struct dmr_C *C = new_dmr_C(); - char test1[100] = "extern int printf(const char *, ...); int main() { printf(\"hello world!\\n\"); return 0; }"; - struct token *start; - struct token *end; - start = dmrC_tokenize_buffer(C, (unsigned char *)test1, - (unsigned long)strlen(test1), &end); - for (struct token *p = start; !dmrC_eof_token(p); p = p->next) { - printf("%s\n", dmrC_show_token(C, p)); - } - printf("\n"); - start = dmrC_preprocess(C, start); - for (struct token *p = start; !dmrC_eof_token(p); p = p->next) { - printf("%s\n", dmrC_show_token(C, p)); - } - while (!dmrC_eof_token(start)) - start = dmrC_external_declaration(C, start, &C->S->translation_unit_used_list, NULL); - dmrC_show_symbol_list(C, C->S->translation_unit_used_list, "\n\n"); - destroy_dmr_C(C); - return 0; -} diff --git a/dmr_c/src/parse.h b/dmr_c/src/parse.h deleted file mode 100644 index 4d27b94..0000000 --- a/dmr_c/src/parse.h +++ /dev/null @@ -1,185 +0,0 @@ -#ifndef DMR_C_PARSE_H -#define DMR_C_PARSE_H -/* -* Basic parsing data structures. Statements and symbols. -* -* Copyright (C) 2003 Transmeta Corp. -* 2003 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -enum statement_type { - STMT_NONE, - STMT_DECLARATION, - STMT_EXPRESSION, - STMT_COMPOUND, - STMT_IF, - STMT_RETURN, - STMT_CASE, - STMT_SWITCH, - STMT_ITERATOR, - STMT_LABEL, - STMT_GOTO, - STMT_ASM, - STMT_CONTEXT, - STMT_RANGE, -}; - -DECLARE_PTR_LIST(statement_list, struct statement); - -struct statement { - enum statement_type type; - struct position pos; - union { - struct /* declaration */ { - struct symbol_list *declaration; - }; - struct { - struct expression *expression; - struct expression *context; - }; - struct /* return_statement */ { - struct expression *ret_value; - struct symbol *ret_target; - }; - struct /* if_statement */ { - struct expression *if_conditional; - struct statement *if_true; - struct statement *if_false; - }; - struct /* compound_struct */ { - struct statement_list *stmts; - struct symbol *ret; - struct symbol *inline_fn; - struct statement *args; - }; - struct /* labeled_struct */ { - struct symbol *label_identifier; - struct statement *label_statement; - }; - struct /* case_struct */ { - struct expression *case_expression; - struct expression *case_to; - struct statement *case_statement; - struct symbol *case_label; - }; - struct /* switch_struct */ { - struct expression *switch_expression; - struct statement *switch_statement; - struct symbol *switch_break, *switch_case; - }; - struct /* iterator_struct */ { - struct symbol *iterator_break; - struct symbol *iterator_continue; - struct symbol_list *iterator_syms; - struct statement *iterator_pre_statement; - struct expression *iterator_pre_condition; - - struct statement *iterator_statement; - - struct statement *iterator_post_statement; - struct expression *iterator_post_condition; - }; - struct /* goto_struct */ { - struct symbol *goto_label; - - /* computed gotos have these: */ - struct expression *goto_expression; - struct symbol_list *target_list; - }; - struct /* asm */ { - struct expression *asm_string; - struct expression_list *asm_outputs; - struct expression_list *asm_inputs; - struct expression_list *asm_clobbers; - struct symbol_list *asm_labels; - }; - struct /* range */ { - struct expression *range_expression; - struct expression *range_low; - struct expression *range_high; - }; - }; -}; - -struct parse_state_t { - struct symbol_list **function_symbol_list; - struct symbol_list *function_computed_target_list; - struct statement_list *function_computed_goto_list; - struct symbol * int_types[4]; - struct symbol * signed_types[5]; - struct symbol * unsigned_types[5]; - struct symbol * real_types[3]; - struct symbol * char_types[3]; - struct symbol ** types[7]; -}; - -extern void dmrC_init_parser(struct dmr_C *C, int stream); -void dmrC_destroy_parser(struct dmr_C *C); - -extern struct token *dmrC_parse_expression(struct dmr_C *C, struct token *, struct expression **); -extern struct symbol *dmrC_label_symbol(struct dmr_C *C, struct token *token); - -extern int dmrC_show_statement(struct dmr_C *C, struct statement *); -extern int dmrC_show_expression(struct dmr_C *C, struct expression *); -typedef void(*validate_decl_t)(struct dmr_C *C, struct symbol *decl); -extern struct token *dmrC_external_declaration(struct dmr_C *C, struct token *token, struct symbol_list **symbol_list, validate_decl_t); - -extern struct symbol *dmrC_ctype_integer(struct dmr_C *C, int size, int want_unsigned); - -extern void dmrC_copy_statement(struct dmr_C *C, struct statement *src, struct statement *dst); -extern int dmrC_inline_function(struct dmr_C *C, struct expression *expr, struct symbol *sym); -extern void dmrC_uninline(struct dmr_C *C, struct symbol *sym); - -static inline void dmrC_add_statement(struct dmr_C *C, struct statement_list **list, struct statement *stmt) -{ - ptrlist_add((struct ptr_list **)list, stmt, &C->ptrlist_allocator); -} - -static inline void dmrC_add_expression(struct dmr_C *C, struct expression_list **list, struct expression *expr) -{ - ptrlist_add((struct ptr_list **)list, expr, &C->ptrlist_allocator); -} - -static inline int dmrC_expression_list_size(struct expression_list *list) -{ - return ptrlist_size((struct ptr_list *)list); -} - -extern int dmrC_test_parse(); - -#ifdef __cplusplus -} -#endif - - -#endif /* PARSE_H */ diff --git a/dmr_c/src/port.h b/dmr_c/src/port.h deleted file mode 100644 index 1e6f042..0000000 --- a/dmr_c/src/port.h +++ /dev/null @@ -1,59 +0,0 @@ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#ifndef DMR_C_PORT_H -#define DMR_C_PORT_H - -#ifndef _WIN32 -#include -#include -#else -#include -#include -#endif - -#if defined(_WIN32) && defined(_MSC_VER) -#include -#ifndef __cplusplus -#define inline __inline -#endif -#define __alignof__ __alignof -#define __builtin_bswap16 _byteswap_ushort -#define __builtin_bswap32 _byteswap_ulong -#define __builtin_bswap64 _byteswap_uint64 -#endif - -#ifdef __GNUC__ -#define FORMAT_ATTR(pos) __attribute__((__format__(__printf__, pos, pos + 1))) -#define NORETURN_ATTR __attribute__((__noreturn__)) -#define SENTINEL_ATTR __attribute__((__sentinel__)) -#else -#define FORMAT_ATTR(pos) -#define NORETURN_ATTR -#define SENTINEL_ATTR -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -void *dmrC_blob_alloc(size_t size); -void dmrC_blob_free(void *addr, size_t size); -long double dmrC_string_to_ld(const char *nptr, char **endptr); - -#include - -#ifdef ASMJIT_STATIC -struct backend_data { uint64_t x[2]; }; -#define DMRC_BACKEND_TYPE struct backend_data -#else -#define DMRC_BACKEND_TYPE void * -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/dmr_c/src/pre-process.c b/dmr_c/src/pre-process.c deleted file mode 100644 index 4817939..0000000 --- a/dmr_c/src/pre-process.c +++ /dev/null @@ -1,2130 +0,0 @@ -/* - * Do C preprocessing, based on a token list gathered by - * the tokenizer. - * - * This may not be the smartest preprocessor on the planet. - * - * Copyright (C) 2003 Transmeta Corp. - * 2003-2004 Linus Torvalds - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - /* - * This version is part of the dmr_c project. - * Copyright (C) 2017 Dibyendu Majumdar - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#define dirty_stream(stream) \ - do { \ - if (!stream->dirty) { \ - stream->dirty = 1; \ - if (!stream->ifndef) \ - stream->protect = NULL; \ - } \ - } while(0) - -#define end_group(stream) \ - do { \ - if (stream->ifndef == stream->top_if) { \ - stream->ifndef = NULL; \ - if (!stream->dirty) \ - stream->protect = NULL; \ - else if (stream->protect) \ - stream->dirty = 0; \ - } \ - } while(0) - -#define nesting_error(stream) \ - do { \ - stream->dirty = 1; \ - stream->ifndef = NULL; \ - stream->protect = NULL; \ - } while(0) - -static struct token *alloc_token(struct dmr_C *C, struct position *pos) -{ - struct token *token = (struct token *)dmrC_allocator_allocate(&C->token_allocator, 0); - - token->pos.stream = pos->stream; - token->pos.line = pos->line; - token->pos.pos = pos->pos; - token->pos.whitespace = 1; - return token; -} - -/* Expand symbol 'sym' at '*list' */ -static int expand(struct dmr_C *C, struct token **, struct symbol *); - -static void replace_with_string(struct dmr_C *C, struct token *token, const char *str) -{ - int size = (int) strlen(str) + 1; - struct string *s = (struct string *)dmrC_allocator_allocate(&C->string_allocator, size); - - s->length = size; - memcpy(s->data, str, size); - dmrC_token_type(token) = TOKEN_STRING; - token->string = s; -} - -static void replace_with_integer(struct dmr_C *C, struct token *token, unsigned int val) -{ - char *buf = (char *)dmrC_allocator_allocate(&C->byte_allocator, 11); - sprintf(buf, "%u", val); - dmrC_token_type(token) = TOKEN_NUMBER; - token->number = buf; -} - -static struct symbol *lookup_macro(struct dmr_C *C, struct ident *ident) -{ - (void) C; - struct symbol *sym = dmrC_lookup_symbol(ident, (enum namespace_type) (NS_MACRO | NS_UNDEF)); - if (sym && sym->ns != NS_MACRO) - sym = NULL; - return sym; -} - -static int token_defined(struct dmr_C *C, struct token *token) -{ - if (dmrC_token_type(token) == TOKEN_IDENT) { - struct symbol *sym = lookup_macro(C, token->ident); - if (sym) { - sym->used_in = C->file_scope; - return 1; - } - return 0; - } - - dmrC_sparse_error(C, token->pos, "expected preprocessor identifier"); - return 0; -} - -static void replace_with_defined(struct dmr_C *C, struct token *token) -{ - static const char *string[] = { "0", "1" }; - int defined = token_defined(C, token); - - dmrC_token_type(token) = TOKEN_NUMBER; - token->number = string[defined]; -} - -static int expand_one_symbol(struct dmr_C *C, struct token **list) -{ - struct token *token = *list; - struct symbol *sym; - - if (token->pos.noexpand) - return 1; - - sym = lookup_macro(C, token->ident); - if (sym) { - sym->used_in = C->file_scope; - return expand(C, list, sym); - } - if (token->ident == C->S->__LINE___ident) { - replace_with_integer(C, token, token->pos.line); - } else if (token->ident == C->S->__FILE___ident) { - replace_with_string(C, token, dmrC_stream_name(C, token->pos.stream)); - } else if (token->ident == C->S->__DATE___ident) { - if (!C->t) - time(&C->t); - strftime(C->date_buffer, 12, "%b %e %Y", localtime(&C->t)); - replace_with_string(C, token, C->date_buffer); - } else if (token->ident == C->S->__TIME___ident) { - if (!C->t) - time(&C->t); - strftime(C->date_buffer, 9, "%T", localtime(&C->t)); - replace_with_string(C, token, C->date_buffer); - } else if (token->ident == C->S->__COUNTER___ident) { - replace_with_integer(C, token, C->counter_macro++); - } - return 1; -} - -static inline struct token *scan_next(struct dmr_C *C, struct token **where) -{ - struct token *token = *where; - (void) C; - if (dmrC_token_type(token) != TOKEN_UNTAINT) - return token; - do { - token->ident->tainted = 0; - token = token->next; - } while (dmrC_token_type(token) == TOKEN_UNTAINT); - *where = token; - return token; -} - -static void expand_list(struct dmr_C *C, struct token **list) -{ - struct token *next; - while (!dmrC_eof_token(next = scan_next(C, list))) { - if (dmrC_token_type(next) != TOKEN_IDENT || expand_one_symbol(C, list)) - list = &next->next; - } -} - -static void preprocessor_line(struct dmr_C *C, struct stream *stream, struct token **line); - -static struct token *collect_arg(struct dmr_C *C, struct token *prev, int vararg, struct position *pos, int count) -{ - struct stream *stream = C->T->input_streams + prev->pos.stream; - struct token **p = &prev->next; - struct token *next; - int nesting = 0; - - while (!dmrC_eof_token(next = scan_next(C, p))) { - if (next->pos.newline && dmrC_match_op(next, '#')) { - if (!next->pos.noexpand) { - dmrC_sparse_error(C, next->pos, - "directive in argument list"); - preprocessor_line(C, stream, p); - dmrC_allocator_free(&C->token_allocator, next); /* Free the '#' token */ - continue; - } - } - switch (dmrC_token_type(next)) { - case TOKEN_STREAMEND: - case TOKEN_STREAMBEGIN: - *p = &dmrC_eof_token_entry_; - return next; - case TOKEN_STRING: - case TOKEN_WIDE_STRING: - if (count > 1) - next->string->immutable = 1; - break; - } - if (C->false_nesting) { - *p = next->next; - dmrC_allocator_free(&C->token_allocator, next); - continue; - } - if (dmrC_match_op(next, '(')) { - nesting++; - } else if (dmrC_match_op(next, ')')) { - if (!nesting--) - break; - } else if (dmrC_match_op(next, ',') && !nesting && !vararg) { - break; - } - next->pos.stream = pos->stream; - next->pos.line = pos->line; - next->pos.pos = pos->pos; - p = &next->next; - } - *p = &dmrC_eof_token_entry_; - return next; -} - -/* - * We store arglist as [arg1] ... eof - */ - -struct arg { - struct token *argument; - struct token *expanded; - struct token *str; - int n_normal; - int n_quoted; - int n_str; -}; - -static int collect_arguments(struct dmr_C *C, struct token *start, struct token *arglist, struct arg *args, struct token *what) -{ - int wanted = arglist->count.normal; - struct token *next = NULL; - int count = 0; - - arglist = arglist->next; /* skip counter */ - - if (!wanted) { - next = collect_arg(C, start, 0, &what->pos, 0); - if (dmrC_eof_token(next)) - goto Eclosing; - if (!dmrC_eof_token(start->next) || !dmrC_match_op(next, ')')) { - count++; - goto Emany; - } - } else { - for (count = 0; count < wanted; count++) { - struct argcount *p = &arglist->next->count; - next = collect_arg(C, start, p->vararg, &what->pos, p->normal); - arglist = arglist->next->next; - if (dmrC_eof_token(next)) - goto Eclosing; - args[count].argument = start->next; - args[count].n_normal = p->normal; - args[count].n_quoted = p->quoted; - args[count].n_str = p->str; - if (dmrC_match_op(next, ')')) { - count++; - break; - } - start = next; - } - if (count == wanted && !dmrC_match_op(next, ')')) - goto Emany; - if (count == wanted - 1) { - struct argcount *p = &arglist->next->count; - if (!p->vararg) - goto Efew; - args[count].argument = NULL; - args[count].n_normal = p->normal; - args[count].n_quoted = p->quoted; - args[count].n_str = p->str; - } - if (count < wanted - 1) - goto Efew; - } - what->next = next->next; - return 1; - -Efew: - dmrC_sparse_error(C, what->pos, "macro \"%s\" requires %d arguments, but only %d given", - dmrC_show_token(C, what), wanted, count); - goto out; -Emany: - while (dmrC_match_op(next, ',')) { - next = collect_arg(C, next, 0, &what->pos, 0); - count++; - } - if (dmrC_eof_token(next)) - goto Eclosing; - dmrC_sparse_error(C, what->pos, "macro \"%s\" passed %d arguments, but takes just %d", - dmrC_show_token(C, what), count, wanted); - goto out; -Eclosing: - dmrC_sparse_error(C, what->pos, "unterminated argument list invoking macro \"%s\"", - dmrC_show_token(C, what)); -out: - what->next = next->next; - return 0; -} - -static struct token *dup_list(struct dmr_C *C, struct token *list) -{ - struct token *res = NULL; - struct token **p = &res; - - while (!dmrC_eof_token(list)) { - struct token *newtok = (struct token *)dmrC_allocator_allocate(&C->token_allocator, 0); - *newtok = *list; - *p = newtok; - p = &newtok->next; - list = list->next; - } - return res; -} - -static const char *show_token_sequence(struct dmr_C *C, struct token *token, int quote) -{ - char *ptr = C->preprocessor_buffer; - int whitespace = 0; - - if (!token && !quote) - return ""; - while (!dmrC_eof_token(token)) { - const char *val = quote ? dmrC_quote_token(C, token) : dmrC_show_token(C, token); - int len = (int) strlen(val); - - if (ptr + whitespace + len >= C->preprocessor_buffer + sizeof C->preprocessor_buffer) { - dmrC_sparse_error(C, token->pos, "too long token expansion"); - break; - } - - if (whitespace) - *ptr++ = ' '; - memcpy(ptr, val, len); - ptr += len; - token = token->next; - whitespace = token->pos.whitespace; - } - *ptr = 0; - return C->preprocessor_buffer; -} - -static struct token *stringify(struct dmr_C *C, struct token *arg) -{ - const char *s = show_token_sequence(C, arg, 1); - int size = (int) strlen(s)+1; - struct token *token = (struct token *)dmrC_allocator_allocate(&C->token_allocator, 0); - struct string *string = (struct string *)dmrC_allocator_allocate(&C->string_allocator, size); - - memcpy(string->data, s, size); - string->length = size; - token->pos = arg->pos; - dmrC_token_type(token) = TOKEN_STRING; - token->string = string; - token->next = &dmrC_eof_token_entry_; - return token; -} - -static void expand_arguments(struct dmr_C *C, int count, struct arg *args) -{ - int i; - for (i = 0; i < count; i++) { - struct token *arg = args[i].argument; - if (!arg) - arg = &dmrC_eof_token_entry_; - if (args[i].n_str) - args[i].str = stringify(C, arg); - if (args[i].n_normal) { - if (!args[i].n_quoted) { - args[i].expanded = arg; - args[i].argument = NULL; - } else if (dmrC_eof_token(arg)) { - args[i].expanded = arg; - } else { - args[i].expanded = dup_list(C, arg); - } - expand_list(C, &args[i].expanded); - } - } -} - -/* - * Possibly valid combinations: - * - ident + ident -> ident - * - ident + number -> ident unless number contains '.', '+' or '-'. - * - 'L' + char constant -> wide char constant - * - 'L' + string literal -> wide string literal - * - number + number -> number - * - number + ident -> number - * - number + '.' -> number - * - number + '+' or '-' -> number, if number used to end on [eEpP]. - * - '.' + number -> number, if number used to start with a digit. - * - special + special -> either special or an error. - */ -static enum e_token_type combine(struct dmr_C *C, struct token *left, struct token *right, char *p) -{ - int len; - enum e_token_type t1 = (enum e_token_type) dmrC_token_type(left), t2 = (enum e_token_type) dmrC_token_type(right); - - if (t1 != TOKEN_IDENT && t1 != TOKEN_NUMBER && t1 != TOKEN_SPECIAL) - return TOKEN_ERROR; - - if (t1 == TOKEN_IDENT && left->ident == C->S->L_ident) { - if (t2 >= TOKEN_CHAR && t2 < TOKEN_WIDE_CHAR) - return (enum e_token_type) (t2 + TOKEN_WIDE_CHAR - TOKEN_CHAR); - if (t2 == TOKEN_STRING) - return TOKEN_WIDE_STRING; - } - - if (t2 != TOKEN_IDENT && t2 != TOKEN_NUMBER && t2 != TOKEN_SPECIAL) - return TOKEN_ERROR; - - strcpy(p, dmrC_show_token(C, left)); - strcat(p, dmrC_show_token(C, right)); - len = (int) strlen(p); - - if (len >= 256) - return TOKEN_ERROR; - - if (t1 == TOKEN_IDENT) { - if (t2 == TOKEN_SPECIAL) - return TOKEN_ERROR; - if (t2 == TOKEN_NUMBER && strpbrk(p, "+-.")) - return TOKEN_ERROR; - return TOKEN_IDENT; - } - - if (t1 == TOKEN_NUMBER) { - if (t2 == TOKEN_SPECIAL) { - switch (right->special) { - case '.': - break; - case '+': case '-': - if (strchr("eEpP", p[len - 2])) - break; - default: - return TOKEN_ERROR; - } - } - return TOKEN_NUMBER; - } - - if (p[0] == '.' && isdigit((unsigned char)p[1])) - return TOKEN_NUMBER; - - return TOKEN_SPECIAL; -} - -static int merge(struct dmr_C *C, struct token *left, struct token *right) -{ - enum e_token_type res = combine(C, left, right, C->preprocessor_mergebuffer); - int n; - - switch (res) { - case TOKEN_IDENT: - left->ident = dmrC_built_in_ident(C, C->preprocessor_mergebuffer); - left->pos.noexpand = 0; - return 1; - - case TOKEN_NUMBER: { - char *number = (char *) dmrC_allocator_allocate(&C->byte_allocator, strlen(C->preprocessor_mergebuffer) + 1); - memcpy(number, C->preprocessor_mergebuffer, strlen(C->preprocessor_mergebuffer) + 1); - dmrC_token_type(left) = TOKEN_NUMBER; /* could be . + num */ - left->number = number; - return 1; - } - - case TOKEN_SPECIAL: - if (C->preprocessor_mergebuffer[2] && C->preprocessor_mergebuffer[3]) - break; - for (n = SPECIAL_BASE; n < SPECIAL_ARG_SEPARATOR; n++) { - if (!memcmp(C->preprocessor_mergebuffer, dmrC_combinations_[n-SPECIAL_BASE], 3)) { - left->special = n; - return 1; - } - } - break; - - case TOKEN_WIDE_CHAR: - case TOKEN_WIDE_STRING: - dmrC_token_type(left) = res; - left->pos.noexpand = 0; - left->string = right->string; - return 1; - - case TOKEN_WIDE_CHAR_EMBEDDED_0: - case TOKEN_WIDE_CHAR_EMBEDDED_1: - case TOKEN_WIDE_CHAR_EMBEDDED_2: - case TOKEN_WIDE_CHAR_EMBEDDED_3: - dmrC_token_type(left) = res; - left->pos.noexpand = 0; - memcpy(left->embedded, right->embedded, 4); - return 1; - - default: - ; - } - dmrC_sparse_error(C, left->pos, "'##' failed: concatenation is not a valid token"); - return 0; -} - -static struct token *dup_token(struct dmr_C *C, struct token *token, struct position *streampos) -{ - struct token *alloc = alloc_token(C, streampos); - dmrC_token_type(alloc) = dmrC_token_type(token); - alloc->pos.newline = token->pos.newline; - alloc->pos.whitespace = token->pos.whitespace; - alloc->number = token->number; - alloc->pos.noexpand = token->pos.noexpand; - return alloc; -} - -static struct token **copy(struct dmr_C *C, struct token **where, struct token *list, int *count) -{ - int need_copy = --*count; - while (!dmrC_eof_token(list)) { - struct token *token; - if (need_copy) - token = dup_token(C, list, &list->pos); - else - token = list; - if (dmrC_token_type(token) == TOKEN_IDENT && token->ident->tainted) - token->pos.noexpand = 1; - *where = token; - where = &token->next; - list = list->next; - } - *where = &dmrC_eof_token_entry_; - return where; -} - -static int handle_kludge(struct dmr_C *C, struct token **p, struct arg *args) -{ - struct token *t = (*p)->next->next; - (void) C; - while (1) { - struct arg *v = &args[t->argnum]; - if (dmrC_token_type(t->next) != TOKEN_CONCAT) { - if (v->argument) { - /* ignore the first ## */ - *p = (*p)->next; - return 0; - } - /* skip the entire thing */ - *p = t; - return 1; - } - if (v->argument && !dmrC_eof_token(v->argument)) - return 0; /* no magic */ - t = t->next->next; - } -} - -static struct token **substitute(struct dmr_C *C, struct token **list, struct token *body, struct arg *args) -{ - struct position *base_pos = &(*list)->pos; - int *count; - enum {Normal, Placeholder, Concat} state = Normal; - - for (; !dmrC_eof_token(body); body = body->next) { - struct token *added, *arg; - struct token **tail; - struct token *t; - - switch (dmrC_token_type(body)) { - case TOKEN_GNU_KLUDGE: - /* - * GNU kludge: if we had ##, behaviour - * depends on whether we had enough arguments to have - * a vararg. If we did, ## is just ignored. Otherwise - * both , and ## are ignored. Worse, there can be - * an arbitrary number of ## in between; if all of - * those are empty, we act as if they hadn't been there, - * otherwise we act as if the kludge didn't exist. - */ - t = body; - if (handle_kludge(C, &body, args)) { - if (state == Concat) - state = Normal; - else - state = Placeholder; - continue; - } - added = dup_token(C, t, base_pos); - dmrC_token_type(added) = TOKEN_SPECIAL; - tail = &added->next; - break; - - case TOKEN_STR_ARGUMENT: - arg = args[body->argnum].str; - count = &args[body->argnum].n_str; - goto copy_arg; - - case TOKEN_QUOTED_ARGUMENT: - arg = args[body->argnum].argument; - count = &args[body->argnum].n_quoted; - if (!arg || dmrC_eof_token(arg)) { - if (state == Concat) - state = Normal; - else - state = Placeholder; - continue; - } - goto copy_arg; - - case TOKEN_MACRO_ARGUMENT: - arg = args[body->argnum].expanded; - count = &args[body->argnum].n_normal; - if (dmrC_eof_token(arg)) { - state = Normal; - continue; - } - copy_arg: - tail = copy(C, &added, arg, count); - added->pos.newline = body->pos.newline; - added->pos.whitespace = body->pos.whitespace; - break; - - case TOKEN_CONCAT: - if (state == Placeholder) - state = Normal; - else - state = Concat; - continue; - - case TOKEN_IDENT: - added = dup_token(C, body, base_pos); - if (added->ident->tainted) - added->pos.noexpand = 1; - tail = &added->next; - break; - - default: - added = dup_token(C, body, base_pos); - tail = &added->next; - break; - } - - /* - * if we got to doing real concatenation, we already have - * added something into the list, so dmrC_containing_token() is OK. - */ - if (state == Concat && merge(C, dmrC_containing_token(list), added)) { - *list = added->next; - if (tail != &added->next) - list = tail; - } else { - *list = added; - list = tail; - } - state = Normal; - } - *list = &dmrC_eof_token_entry_; - return list; -} - -static int expand(struct dmr_C *C, struct token **list, struct symbol *sym) -{ - struct token *last; - struct token *token = *list; - struct ident *expanding = token->ident; - struct token **tail; - int nargs = sym->arglist ? sym->arglist->count.normal : 0; -#ifndef _MSC_VER - struct arg args[nargs]; -#else - struct arg *args = (struct arg *)alloca(sizeof(struct arg)*nargs); -#endif - - if (expanding->tainted) { - token->pos.noexpand = 1; - return 1; - } - - if (sym->arglist) { - if (!dmrC_match_op(scan_next(C, &token->next), '(')) - return 1; - if (!collect_arguments(C, token->next, sym->arglist, args, token)) - return 1; - expand_arguments(C, nargs, args); - } - - expanding->tainted = 1; - - last = token->next; - tail = substitute(C, list, sym->expansion, args); - /* - * Note that it won't be eof - at least TOKEN_UNTAINT will be there. - * We still can lose the newline flag if the sucker expands to nothing, - * but the price of dealing with that is probably too high (we'd need - * to collect the flags during scan_next()) - */ - (*list)->pos.newline = token->pos.newline; - (*list)->pos.whitespace = token->pos.whitespace; - *tail = last; - - return 0; -} - -static const char *token_name_sequence(struct dmr_C *C, struct token *token, int endop, struct token *start) -{ - char *ptr = C->preprocessor_tokenseqbuffer; - - while (!dmrC_eof_token(token) && !dmrC_match_op(token, endop)) { - int len; - const char *val = token->string->data; - if (dmrC_token_type(token) != TOKEN_STRING) - val = dmrC_show_token(C, token); - len = (int) strlen(val); - memcpy(ptr, val, len); - ptr += len; - token = token->next; - } - *ptr = 0; - if (endop && !dmrC_match_op(token, endop)) - dmrC_sparse_error(C, start->pos, "expected '>' at end of filename"); - return C->preprocessor_tokenseqbuffer; -} - -static int already_tokenized(struct dmr_C *C, const char *path) -{ - int stream, next; - - for (stream = *dmrC_hash_stream(path); stream >= 0 ; stream = next) { - struct stream *s = C->T->input_streams + stream; - - next = s->next_stream; - if (s->once) { - if (strcmp(path, s->name)) - continue; - return 1; - } - if (s->constant != CONSTANT_FILE_YES) - continue; - if (strcmp(path, s->name)) - continue; - if (s->protect && !lookup_macro(C, s->protect)) - continue; - return 1; - } - return 0; -} - -/* Handle include of header files. - * The relevant options are made compatible with gcc. The only options that - * are not supported is -withprefix and friends. - * - * Three set of include paths are known: - * quote_includepath: Path to search when using #include "file.h" - * angle_includepath: Paths to search when using #include - * isys_includepath: Paths specified with -isystem, come before the - * built-in system include paths. Gcc would suppress - * warnings from system headers. Here we separate - * them from the angle_ ones to keep search ordering. - * - * sys_includepath: Built-in include paths. - * dirafter_includepath Paths added with -dirafter. - * - * The above is implemented as one array with pointers - * +--------------+ - * quote_includepath ---> | | - * +--------------+ - * | | - * +--------------+ - * angle_includepath ---> | | - * +--------------+ - * isys_includepath ---> | | - * +--------------+ - * sys_includepath ---> | | - * +--------------+ - * dirafter_includepath -> | | - * +--------------+ - * - * -I dir insert dir just before isys_includepath and move the rest - * -I- makes all dirs specified with -I before to quote dirs only and - * angle_includepath is set equal to isys_includepath. - * -nostdinc removes all sys dirs by storing NULL in entry pointed - * to by * sys_includepath. Note that this will reset all dirs built-in - * and added before -nostdinc by -isystem and -idirafter. - * -isystem dir adds dir where isys_includepath points adding this dir as - * first systemdir - * -idirafter dir adds dir to the end of the list - */ - -static void set_stream_include_path(struct dmr_C *C, struct stream *stream) -{ - const char *path = stream->path; - if (!path) { - const char *p = strrchr(stream->name, '/'); - path = ""; - if (p) { - int len = (int)(p - stream->name + 1); - char *m = (char *)dmrC_allocator_allocate(&C->byte_allocator, len+1); - /* This includes the final "/" */ - memcpy(m, stream->name, len); - m[len] = 0; - path = m; - } - stream->path = path; - } - C->includepath[0] = path; -} - -static int try_include(struct dmr_C *C, const char *path, const char *filename, int flen, struct token **where, const char **next_path) -{ - int fd; - int plen = (int) strlen(path); - - memcpy(C->fullname, path, plen); - if (plen && path[plen-1] != '/') { - C->fullname[plen] = '/'; - plen++; - } - /* flen includes extra 0 byte */ - memcpy(C->fullname+plen, filename, flen); - if (already_tokenized(C, C->fullname)) - return 1; - //printf("Opening %s\n", C->fullname); - fd = open(C->fullname, O_RDONLY); - if (fd >= 0) { - char * streamname = (char *)dmrC_allocator_allocate(&C->byte_allocator, plen + flen); - memcpy(streamname, C->fullname, plen + flen); - *where = dmrC_tokenize(C, streamname, fd, *where, next_path); - close(fd); - return 1; - } - return 0; -} - -static int do_include_path(struct dmr_C *C, const char **pptr, struct token **list, struct token *token, const char *filename, int flen) -{ - const char *path; - - (void) token; - while ((path = *pptr++) != NULL) { - if (!try_include(C, path, filename, flen, list, pptr)) - continue; - return 1; - } - return 0; -} - -static int free_preprocessor_line(struct dmr_C *C, struct token *token) -{ - while (dmrC_token_type(token) != TOKEN_EOF) { - struct token *free = token; - token = token->next; - dmrC_allocator_free(&C->token_allocator, free); - }; - return 1; -} - -static int handle_include_path(struct dmr_C *C, struct stream *stream, struct token **list, struct token *token, int how) -{ - const char *filename; - struct token *next; - const char **path; - int expect; - int flen; - - next = token->next; - expect = '>'; - if (!dmrC_match_op(next, '<')) { - expand_list(C, &token->next); - expect = 0; - next = token; - if (dmrC_match_op(token->next, '<')) { - next = token->next; - expect = '>'; - } - } - - token = next->next; - filename = token_name_sequence(C, token, expect, token); - flen = (int)strlen(filename) + 1; - - /* Absolute path? */ - if (filename[0] == '/') { - if (try_include(C, "", filename, flen, list, C->includepath)) - return 0; - goto out; - } - - switch (how) { - case 1: - path = stream->next_path; - break; - case 2: - C->includepath[0] = ""; - path = C->includepath; - break; - default: - /* Dir of input file is first dir to search for quoted includes */ - set_stream_include_path(C, stream); - path = expect ? C->angle_includepath : C->quote_includepath; - break; - } - /* Check the standard include paths.. */ - if (do_include_path(C, path, list, token, filename, flen)) - return 0; -out: - dmrC_error_die(C, token->pos, "unable to open '%s'", filename); - return 0; -} - -static int handle_include(struct dmr_C *C, struct stream *stream, struct token **list, struct token *token) -{ - return handle_include_path(C, stream, list, token, 0); -} - -static int handle_include_next(struct dmr_C *C, struct stream *stream, struct token **list, struct token *token) -{ - return handle_include_path(C, stream, list, token, 1); -} - -static int handle_argv_include(struct dmr_C *C, struct stream *stream, struct token **list, struct token *token) -{ - return handle_include_path(C, stream, list, token, 2); -} - -static int token_different(struct dmr_C *C, struct token *t1, struct token *t2) -{ - int different; - - (void) C; - if (dmrC_token_type(t1) != dmrC_token_type(t2)) - return 1; - - switch (dmrC_token_type(t1)) { - case TOKEN_IDENT: - different = t1->ident != t2->ident; - break; - case TOKEN_ARG_COUNT: - case TOKEN_UNTAINT: - case TOKEN_CONCAT: - case TOKEN_GNU_KLUDGE: - different = 0; - break; - case TOKEN_NUMBER: - different = strcmp(t1->number, t2->number); - break; - case TOKEN_SPECIAL: - different = t1->special != t2->special; - break; - case TOKEN_MACRO_ARGUMENT: - case TOKEN_QUOTED_ARGUMENT: - case TOKEN_STR_ARGUMENT: - different = t1->argnum != t2->argnum; - break; - case TOKEN_CHAR_EMBEDDED_0: - case TOKEN_CHAR_EMBEDDED_1: - case TOKEN_CHAR_EMBEDDED_2: - case TOKEN_CHAR_EMBEDDED_3: - case TOKEN_WIDE_CHAR_EMBEDDED_0: - case TOKEN_WIDE_CHAR_EMBEDDED_1: - case TOKEN_WIDE_CHAR_EMBEDDED_2: - case TOKEN_WIDE_CHAR_EMBEDDED_3: - different = memcmp(t1->embedded, t2->embedded, 4); - break; - case TOKEN_CHAR: - case TOKEN_WIDE_CHAR: - case TOKEN_STRING: - case TOKEN_WIDE_STRING: { - struct string *s1, *s2; - - s1 = t1->string; - s2 = t2->string; - different = 1; - if (s1->length != s2->length) - break; - different = memcmp(s1->data, s2->data, s1->length); - break; - } - default: - different = 1; - break; - } - return different; -} - -static int token_list_different(struct dmr_C *C, struct token *list1, struct token *list2) -{ - for (;;) { - if (list1 == list2) - return 0; - if (!list1 || !list2) - return 1; - if (token_different(C, list1, list2)) - return 1; - list1 = list1->next; - list2 = list2->next; - } -} - -static inline void set_arg_count(struct dmr_C *C, struct token *token) -{ - (void) C; - dmrC_token_type(token) = TOKEN_ARG_COUNT; - token->count.normal = token->count.quoted = - token->count.str = token->count.vararg = 0; -} - -static struct token *parse_arguments(struct dmr_C *C, struct token *list) -{ - struct token *arg = list->next, *next = list; - struct argcount *count = &list->count; - - set_arg_count(C, list); - - if (dmrC_match_op(arg, ')')) { - next = arg->next; - list->next = &dmrC_eof_token_entry_; - return next; - } - - while (dmrC_token_type(arg) == TOKEN_IDENT) { - if (arg->ident == C->S->__VA_ARGS___ident) - goto Eva_args; - if (!++count->normal) - goto Eargs; - next = arg->next; - - if (dmrC_match_op(next, ',')) { - set_arg_count(C, next); - arg = next->next; - continue; - } - - if (dmrC_match_op(next, ')')) { - set_arg_count(C, next); - next = next->next; - arg->next->next = &dmrC_eof_token_entry_; - return next; - } - - /* normal cases are finished here */ - - if (dmrC_match_op(next, SPECIAL_ELLIPSIS)) { - if (dmrC_match_op(next->next, ')')) { - set_arg_count(C, next); - next->count.vararg = 1; - next = next->next; - arg->next->next = &dmrC_eof_token_entry_; - return next->next; - } - - arg = next; - goto Enotclosed; - } - - if (dmrC_eof_token(next)) { - goto Enotclosed; - } else { - arg = next; - goto Ebadstuff; - } - } - - if (dmrC_match_op(arg, SPECIAL_ELLIPSIS)) { - next = arg->next; - dmrC_token_type(arg) = TOKEN_IDENT; - arg->ident = C->S->__VA_ARGS___ident; - if (!dmrC_match_op(next, ')')) - goto Enotclosed; - if (!++count->normal) - goto Eargs; - set_arg_count(C, next); - next->count.vararg = 1; - next = next->next; - arg->next->next = &dmrC_eof_token_entry_; - return next; - } - - if (dmrC_eof_token(arg)) { - arg = next; - goto Enotclosed; - } - if (dmrC_match_op(arg, ',')) - goto Emissing; - else - goto Ebadstuff; - - -Emissing: - dmrC_sparse_error(C, arg->pos, "parameter name missing"); - return NULL; -Ebadstuff: - dmrC_sparse_error(C, arg->pos, "\"%s\" may not appear in macro parameter list", - dmrC_show_token(C, arg)); - return NULL; -Enotclosed: - dmrC_sparse_error(C, arg->pos, "missing ')' in macro parameter list"); - return NULL; -Eva_args: - dmrC_sparse_error(C, arg->pos, "__VA_ARGS__ can only appear in the expansion of a C99 variadic macro"); - return NULL; -Eargs: - dmrC_sparse_error(C, arg->pos, "too many arguments in macro definition"); - return NULL; -} - -static int try_arg(struct dmr_C *C, struct token *token, enum e_token_type type, struct token *arglist) -{ - struct ident *ident = token->ident; - int nr; - - (void) C; - - if (!arglist || dmrC_token_type(token) != TOKEN_IDENT) - return 0; - - arglist = arglist->next; - - for (nr = 0; !dmrC_eof_token(arglist); nr++, arglist = arglist->next->next) { - if (arglist->ident == ident) { - struct argcount *count = &arglist->next->count; - int n; - - token->argnum = nr; - dmrC_token_type(token) = type; - switch (type) { - case TOKEN_MACRO_ARGUMENT: - n = ++count->normal; - break; - case TOKEN_QUOTED_ARGUMENT: - n = ++count->quoted; - break; - default: - n = ++count->str; - } - if (n) - return count->vararg ? 2 : 1; - /* - * XXX - need saner handling of that - * (>= 1024 instances of argument) - */ - dmrC_token_type(token) = TOKEN_ERROR; - return -1; - } - } - return 0; -} - -static struct token *handle_hash(struct dmr_C *C, struct token **p, struct token *arglist) -{ - struct token *token = *p; - if (arglist) { - struct token *next = token->next; - if (!try_arg(C, next, TOKEN_STR_ARGUMENT, arglist)) - goto Equote; - next->pos.whitespace = token->pos.whitespace; - dmrC_allocator_free(&C->token_allocator, token); - token = *p = next; - } else { - token->pos.noexpand = 1; - } - return token; - -Equote: - dmrC_sparse_error(C, token->pos, "'#' is not followed by a macro parameter"); - return NULL; -} - -/* token->next is ## */ -static struct token *handle_hashhash(struct dmr_C *C, struct token *token, struct token *arglist) -{ - struct token *last = token; - struct token *concat; - int state = dmrC_match_op(token, ','); - - try_arg(C, token, TOKEN_QUOTED_ARGUMENT, arglist); - - while (1) { - struct token *t; - int is_arg; - - /* eat duplicate ## */ - concat = token->next; - while (dmrC_match_op(t = concat->next, SPECIAL_HASHHASH)) { - token->next = t; - dmrC_allocator_free(&C->token_allocator, concat); - concat = t; - } - dmrC_token_type(concat) = TOKEN_CONCAT; - - if (dmrC_eof_token(t)) - goto Econcat; - - if (dmrC_match_op(t, '#')) { - t = handle_hash(C, &concat->next, arglist); - if (!t) - return NULL; - } - - is_arg = try_arg(C, t, TOKEN_QUOTED_ARGUMENT, arglist); - - if (state == 1 && is_arg) { - state = is_arg; - } else { - last = t; - state = dmrC_match_op(t, ','); - } - - token = t; - if (!dmrC_match_op(token->next, SPECIAL_HASHHASH)) - break; - } - /* handle GNU ,##__VA_ARGS__ kludge, in all its weirdness */ - if (state == 2) - dmrC_token_type(last) = TOKEN_GNU_KLUDGE; - return token; - -Econcat: - dmrC_sparse_error(C, concat->pos, "'##' cannot appear at the ends of macro expansion"); - return NULL; -} - -static struct token *parse_expansion(struct dmr_C *C, struct token *expansion, struct token *arglist, struct ident *name) -{ - struct token *token = expansion; - struct token **p; - - if (dmrC_match_op(token, SPECIAL_HASHHASH)) - goto Econcat; - - for (p = &expansion; !dmrC_eof_token(token); p = &token->next, token = *p) { - if (dmrC_match_op(token, '#')) { - token = handle_hash(C, p, arglist); - if (!token) - return NULL; - } - if (dmrC_match_op(token->next, SPECIAL_HASHHASH)) { - token = handle_hashhash(C, token, arglist); - if (!token) - return NULL; - } else { - try_arg(C, token, TOKEN_MACRO_ARGUMENT, arglist); - } - switch (dmrC_token_type(token)) { - case TOKEN_ERROR: - goto Earg; - - case TOKEN_STRING: - case TOKEN_WIDE_STRING: - token->string->immutable = 1; - break; - } - } - token = alloc_token(C, &expansion->pos); - dmrC_token_type(token) = TOKEN_UNTAINT; - token->ident = name; - token->next = *p; - *p = token; - return expansion; - -Econcat: - dmrC_sparse_error(C, token->pos, "'##' cannot appear at the ends of macro expansion"); - return NULL; -Earg: - dmrC_sparse_error(C, token->pos, "too many instances of argument in body"); - return NULL; -} - -static int do_handle_define(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token, int attr) -{ - struct token *arglist, *expansion; - struct token *left = token->next; - struct symbol *sym; - struct ident *name; - int ret; - - (void) stream; - (void) line; - - if (dmrC_token_type(left) != TOKEN_IDENT) { - dmrC_sparse_error(C, token->pos, "expected identifier to 'define'"); - return 1; - } - - name = left->ident; - - arglist = NULL; - expansion = left->next; - if (!expansion->pos.whitespace) { - if (dmrC_match_op(expansion, '(')) { - arglist = expansion; - expansion = parse_arguments(C, expansion); - if (!expansion) - return 1; - } else if (!dmrC_eof_token(expansion)) { - dmrC_warning(C, expansion->pos, - "no whitespace before object-like macro body"); - } - } - - expansion = parse_expansion(C, expansion, arglist, name); - if (!expansion) - return 1; - - ret = 1; - sym = dmrC_lookup_symbol(name, (enum namespace_type) (NS_MACRO | NS_UNDEF)); - if (sym) { - int clean; - - if (attr < sym->attr) - goto out; - - clean = (attr == sym->attr && sym->ns == NS_MACRO); - - if (token_list_different(C, sym->expansion, expansion) || - token_list_different(C, sym->arglist, arglist)) { - ret = 0; - if ((clean && attr == SYM_ATTR_NORMAL) - || sym->used_in == C->file_scope) { - dmrC_warning(C, left->pos, "preprocessor token %.*s redefined", - name->len, name->name); - dmrC_info(C, sym->pos, "this was the original definition"); - } - } else if (clean) - goto out; - } - - if (!sym || sym->scope != C->file_scope) { - sym = dmrC_alloc_symbol(C->S, left->pos, SYM_NODE); - dmrC_bind_symbol(C->S, sym, name, NS_MACRO); - dmrC_add_ident(C, &C->macros, name); - ret = 0; - } - - if (!ret) { - sym->expansion = expansion; - sym->arglist = arglist; - dmrC_allocator_free(&C->token_allocator, token); /* Free the "define" token, but not the rest of the line */ - } - - sym->ns = NS_MACRO; - sym->used_in = NULL; - sym->attr = attr; -out: - return ret; -} - -static int handle_define(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - return do_handle_define(C, stream, line, token, SYM_ATTR_NORMAL); -} - -static int handle_weak_define(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - return do_handle_define(C, stream, line, token, SYM_ATTR_WEAK); -} - -static int handle_strong_define(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - return do_handle_define(C, stream, line, token, SYM_ATTR_STRONG); -} - -static int do_handle_undef(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token, int attr) -{ - struct token *left = token->next; - struct symbol *sym; - - (void) stream; - (void) line; - - if (dmrC_token_type(left) != TOKEN_IDENT) { - dmrC_sparse_error(C, token->pos, "expected identifier to 'undef'"); - return 1; - } - - sym = dmrC_lookup_symbol(left->ident, (enum namespace_type) (NS_MACRO | NS_UNDEF)); - if (sym) { - if (attr < sym->attr) - return 1; - if (attr == sym->attr && sym->ns == NS_UNDEF) - return 1; - } else if (attr <= SYM_ATTR_NORMAL) - return 1; - - if (!sym || sym->scope != C->file_scope) { - sym = dmrC_alloc_symbol(C->S, left->pos, SYM_NODE); - dmrC_bind_symbol(C->S, sym, left->ident, NS_MACRO); - } - - sym->ns = NS_UNDEF; - sym->used_in = NULL; - sym->attr = attr; - - return 1; -} - -static int handle_undef(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - return do_handle_undef(C, stream, line, token, SYM_ATTR_NORMAL); -} - -static int handle_strong_undef(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - return do_handle_undef(C, stream, line, token, SYM_ATTR_STRONG); -} - -static int preprocessor_if(struct dmr_C *C, struct stream *stream, struct token *token, int true_value) -{ - dmrC_token_type(token) = C->false_nesting ? TOKEN_SKIP_GROUPS : TOKEN_IF; - free_preprocessor_line(C, token->next); - token->next = stream->top_if; - stream->top_if = token; - if (C->false_nesting || true_value != 1) - C->false_nesting++; - return 0; -} - -static int handle_ifdef(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - struct token *next = token->next; - int arg; - - (void) line; - if (dmrC_token_type(next) == TOKEN_IDENT) { - arg = token_defined(C, next); - } else { - dirty_stream(stream); - if (!C->false_nesting) - dmrC_sparse_error(C, token->pos, "expected preprocessor identifier"); - arg = -1; - } - return preprocessor_if(C, stream, token, arg); -} - -static int handle_ifndef(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - struct token *next = token->next; - int arg; - - (void) line; - if (dmrC_token_type(next) == TOKEN_IDENT) { - if (!stream->dirty && !stream->ifndef) { - if (!stream->protect) { - stream->ifndef = token; - stream->protect = next->ident; - } else if (stream->protect == next->ident) { - stream->ifndef = token; - stream->dirty = 1; - } - } - arg = !token_defined(C, next); - } else { - dirty_stream(stream); - if (!C->false_nesting) - dmrC_sparse_error(C, token->pos, "expected preprocessor identifier"); - arg = -1; - } - - return preprocessor_if(C, stream, token, arg); -} - -static const char *show_token_sequence(struct dmr_C *C, struct token *token, int quote); - -/* - * Expression handling for #if and #elif; it differs from normal expansion - * due to special treatment of "defined". - */ -static int expression_value(struct dmr_C *C, struct token **where) -{ - struct expression *expr; - struct token *p; - struct token **list = where, **beginning = NULL; - long long value; - int state = 0; - - while (!dmrC_eof_token(p = scan_next(C, list))) { - switch (state) { - case 0: - if (dmrC_token_type(p) != TOKEN_IDENT) - break; - if (p->ident == C->S->defined_ident) { - state = 1; - beginning = list; - break; - } - if (!expand_one_symbol(C, list)) - continue; - if (dmrC_token_type(p) != TOKEN_IDENT) - break; - dmrC_token_type(p) = TOKEN_ZERO_IDENT; - break; - case 1: - if (dmrC_match_op(p, '(')) { - state = 2; - } else { - state = 0; - replace_with_defined(C, p); - *beginning = p; - } - break; - case 2: - if (dmrC_token_type(p) == TOKEN_IDENT) - state = 3; - else - state = 0; - replace_with_defined(C, p); - *beginning = p; - break; - case 3: - state = 0; - if (!dmrC_match_op(p, ')')) - dmrC_sparse_error(C, p->pos, "missing ')' after \"defined\""); - *list = p->next; - continue; - } - list = &p->next; - } - - p = dmrC_constant_expression(C, *where, &expr); - if (!dmrC_eof_token(p)) - dmrC_sparse_error(C, p->pos, "garbage at end: %s", show_token_sequence(C, p, 0)); - value = dmrC_get_expression_value(C, expr); - return value != 0; -} - -static int handle_if(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - int value = 0; - - (void)line; - if (!C->false_nesting) - value = expression_value(C, &token->next); - - dirty_stream(stream); - return preprocessor_if(C, stream, token, value); -} - -static int handle_elif(struct dmr_C *C, struct stream * stream, struct token **line, struct token *token) -{ - struct token *top_if = stream->top_if; - - (void) line; - end_group(stream); - - if (!top_if) { - nesting_error(stream); - dmrC_sparse_error(C, token->pos, "unmatched #elif within stream"); - return 1; - } - - if (dmrC_token_type(top_if) == TOKEN_ELSE) { - nesting_error(stream); - dmrC_sparse_error(C, token->pos, "#elif after #else"); - if (!C->false_nesting) - C->false_nesting = 1; - return 1; - } - - dirty_stream(stream); - if (dmrC_token_type(top_if) != TOKEN_IF) - return 1; - if (C->false_nesting) { - C->false_nesting = 0; - if (!expression_value(C, &token->next)) - C->false_nesting = 1; - } else { - C->false_nesting = 1; - dmrC_token_type(top_if) = TOKEN_SKIP_GROUPS; - } - return 1; -} - -static int handle_else(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - struct token *top_if = stream->top_if; - - (void) line; - end_group(stream); - - if (!top_if) { - nesting_error(stream); - dmrC_sparse_error(C, token->pos, "unmatched #else within stream"); - return 1; - } - - if (dmrC_token_type(top_if) == TOKEN_ELSE) { - nesting_error(stream); - dmrC_sparse_error(C, token->pos, "#else after #else"); - } - if (C->false_nesting) { - if (dmrC_token_type(top_if) == TOKEN_IF) - C->false_nesting = 0; - } else { - C->false_nesting = 1; - } - dmrC_token_type(top_if) = TOKEN_ELSE; - return 1; -} - -static int handle_endif(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - struct token *top_if = stream->top_if; - - (void) line; - end_group(stream); - if (!top_if) { - nesting_error(stream); - dmrC_sparse_error(C, token->pos, "unmatched #endif in stream"); - return 1; - } - if (C->false_nesting) - C->false_nesting--; - stream->top_if = top_if->next; - dmrC_allocator_free(&C->token_allocator, top_if); - return 1; -} - -static int handle_warning(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - (void) line; - (void) stream; - dmrC_warning(C, token->pos, "%s", show_token_sequence(C, token->next, 0)); - return 1; -} - -static int handle_error(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - (void) line; - (void) stream; - - dmrC_sparse_error(C, token->pos, "%s", show_token_sequence(C, token->next, 0)); - return 1; -} - -static int handle_nostdinc(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - (void) token; - (void) line; - (void) stream; - /* - * Do we have any non-system includes? - * Clear them out if so.. - */ - *C->sys_includepath = NULL; - return 1; -} - -static inline void update_inc_ptrs(struct dmr_C *C, const char ***where) -{ - - if (*where <= C->dirafter_includepath) { - C->dirafter_includepath++; - /* If this was the entry that we prepend, don't - * rise the lower entries, even if they are at - * the same level. */ - if (where == &C->dirafter_includepath) - return; - } - if (*where <= C->sys_includepath) { - C->sys_includepath++; - if (where == &C->sys_includepath) - return; - } - if (*where <= C->isys_includepath) { - C->isys_includepath++; - if (where == &C->isys_includepath) - return; - } - - /* angle_includepath is actually never updated, since we - * don't suppport -iquote rught now. May change some day. */ - if (*where <= C->angle_includepath) { - C->angle_includepath++; - if (where == &C->angle_includepath) - return; - } -} - -/* Add a path before 'where' and update the pointers associated with the - * includepath array */ -static void add_path_entry(struct dmr_C *C, struct token *token, const char *path, - const char ***where) -{ - const char **dst; - const char *next; - - /* Need one free entry.. */ - if (C->includepath[INCLUDEPATHS-2]) - dmrC_error_die(C, token->pos, "too many include path entries"); - - /* check that this is not a duplicate */ - dst = C->includepath; - while (*dst) { - if (strcmp(*dst, path) == 0) - return; - dst++; - } - next = path; - dst = *where; - - update_inc_ptrs(C, where); - - /* - * Move them all up starting at dst, - * insert the new entry.. - */ - do { - const char *tmp = *dst; - *dst = next; - next = tmp; - dst++; - } while (next); -} - -static int handle_add_include(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - (void) stream; - (void) line; - for (;;) { - token = token->next; - if (dmrC_eof_token(token)) - return 1; - if (dmrC_token_type(token) != TOKEN_STRING) { - dmrC_warning(C, token->pos, "expected path string"); - return 1; - } - add_path_entry(C, token, token->string->data, &C->isys_includepath); - } -} - -static int handle_add_isystem(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - (void)line; - (void)stream; - for (;;) { - token = token->next; - if (dmrC_eof_token(token)) - return 1; - if (dmrC_token_type(token) != TOKEN_STRING) { - dmrC_sparse_error(C, token->pos, "expected path string"); - return 1; - } - add_path_entry(C, token, token->string->data, &C->sys_includepath); - } -} - -static int handle_add_system(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - (void) line; - (void) stream; - for (;;) { - token = token->next; - if (dmrC_eof_token(token)) - return 1; - if (dmrC_token_type(token) != TOKEN_STRING) { - dmrC_sparse_error(C, token->pos, "expected path string"); - return 1; - } - add_path_entry(C, token, token->string->data, &C->dirafter_includepath); - } -} - -/* Add to end on includepath list - no pointer updates */ -static void add_dirafter_entry(struct dmr_C *C, struct token *token, const char *path) -{ - const char **dst = C->includepath; - - /* Need one free entry.. */ - if (C->includepath[INCLUDEPATHS-2]) - dmrC_error_die(C, token->pos, "too many include path entries"); - - /* Add to the end */ - while (*dst) - dst++; - *dst = path; - dst++; - *dst = NULL; -} - -static int handle_add_dirafter(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - (void) line; - (void) stream; - for (;;) { - token = token->next; - if (dmrC_eof_token(token)) - return 1; - if (dmrC_token_type(token) != TOKEN_STRING) { - dmrC_sparse_error(C, token->pos, "expected path string"); - return 1; - } - add_dirafter_entry(C, token, token->string->data); - } -} - -static int handle_split_include(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - (void) stream; - (void) line; - (void) token; - /* - * -I- - * From info gcc: - * Split the include path. Any directories specified with `-I' - * options before `-I-' are searched only for headers requested with - * `#include "FILE"'; they are not searched for `#include '. - * If additional directories are specified with `-I' options after - * the `-I-', those directories are searched for all `#include' - * directives. - * In addition, `-I-' inhibits the use of the directory of the current - * file directory as the first search directory for `#include "FILE"'. - */ - C->quote_includepath = C->includepath+1; - C->angle_includepath = C->sys_includepath; - return 1; -} - -/* - * We replace "#pragma xxx" with "__pragma__" in the token - * stream. Just as an example. - * - * We'll just #define that away for now, but the theory here - * is that we can use this to insert arbitrary token sequences - * to turn the pragmas into internal front-end sequences for - * when we actually start caring about them. - * - * So eventually this will turn into some kind of extended - * __attribute__() like thing, except called __pragma__(xxx). - */ -static int handle_pragma(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - struct token *next = *line; - - if (dmrC_match_ident(token->next, C->S->once_ident) && dmrC_eof_token(token->next->next)) { - stream->once = 1; - return 1; - } - token->ident = C->S->pragma_ident; - token->pos.newline = 1; - token->pos.whitespace = 1; - token->pos.pos = 1; - *line = token; - token->next = next; - return 0; -} - -/* - * We ignore #line for now. - */ -static int handle_line(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - (void) stream; - (void) token; - (void)line; - (void) C; - return 1; -} - -static int handle_nondirective(struct dmr_C *C, struct stream *stream, struct token **line, struct token *token) -{ - (void) stream; - (void) line; - dmrC_sparse_error(C, token->pos, "unrecognized preprocessor line '%s'", show_token_sequence(C, token, 0)); - return 1; -} - - -static void init_preprocessor(struct dmr_C *C) -{ - int i; - int stream = dmrC_init_stream(C, "preprocessor", -1, C->includepath); - static struct { - const char *name; - int (*handler)(struct dmr_C *, struct stream *, struct token **, struct token *); - } normal[] = { - { "define", handle_define }, - { "weak_define", handle_weak_define }, - { "strong_define", handle_strong_define }, - { "undef", handle_undef }, - { "strong_undef", handle_strong_undef }, - { "warning", handle_warning }, - { "error", handle_error }, - { "include", handle_include }, - { "include_next", handle_include_next }, - { "pragma", handle_pragma }, - { "line", handle_line }, - - // our internal preprocessor tokens - { "nostdinc", handle_nostdinc }, - { "add_include", handle_add_include }, - { "add_isystem", handle_add_isystem }, - { "add_system", handle_add_system }, - { "add_dirafter", handle_add_dirafter }, - { "split_include", handle_split_include }, - { "argv_include", handle_argv_include }, - }, special[] = { - { "ifdef", handle_ifdef }, - { "ifndef", handle_ifndef }, - { "else", handle_else }, - { "endif", handle_endif }, - { "if", handle_if }, - { "elif", handle_elif }, - }; - - for (i = 0; i < (int)ARRAY_SIZE(normal); i++) { - struct symbol *sym; - sym = dmrC_create_symbol(C->S, stream, normal[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR); - sym->handler = normal[i].handler; - sym->normal = 1; - } - for (i = 0; i < (int)ARRAY_SIZE(special); i++) { - struct symbol *sym; - sym = dmrC_create_symbol(C->S, stream, special[i].name, SYM_PREPROCESSOR, NS_PREPROCESSOR); - sym->handler = special[i].handler; - sym->normal = 0; - } - - C->counter_macro = 0; -} - -static void handle_preprocessor_line(struct dmr_C *C, struct stream *stream, struct token **line, struct token *start) -{ - int (*handler)(struct dmr_C *, struct stream *, struct token **, struct token *); - struct token *token = start->next; - int is_normal = 1; - - if (dmrC_eof_token(token)) - return; - - if (dmrC_token_type(token) == TOKEN_IDENT) { - struct symbol *sym = dmrC_lookup_symbol(token->ident, NS_PREPROCESSOR); - if (sym) { - handler = sym->handler; - is_normal = sym->normal; - } else { - handler = handle_nondirective; - } - } else if (dmrC_token_type(token) == TOKEN_NUMBER) { - handler = handle_line; - } else { - handler = handle_nondirective; - } - - if (is_normal) { - dirty_stream(stream); - if (C->false_nesting) - goto out; - } - if (!handler(C, stream, line, token)) /* all set */ - return; - -out: - free_preprocessor_line(C, token); -} - -static void preprocessor_line(struct dmr_C *C, struct stream *stream, struct token **line) -{ - struct token *start = *line, *next; - struct token **tp = &start->next; - - for (;;) { - next = *tp; - if (next->pos.newline) - break; - tp = &next->next; - } - *line = next; - *tp = &dmrC_eof_token_entry_; - handle_preprocessor_line(C, stream, line, start); -} - -static void do_preprocess(struct dmr_C *C, struct token **list) -{ - struct token *next; - - while (!dmrC_eof_token(next = scan_next(C, list))) { - struct stream *stream = C->T->input_streams + next->pos.stream; - - if (next->pos.newline && dmrC_match_op(next, '#')) { - if (!next->pos.noexpand) { - preprocessor_line(C, stream, list); - dmrC_allocator_free(&C->token_allocator, next); /* Free the '#' token */ - continue; - } - } - - switch (dmrC_token_type(next)) { - case TOKEN_STREAMEND: - if (stream->top_if) { - nesting_error(stream); - dmrC_sparse_error(C, stream->top_if->pos, "unterminated preprocessor conditional"); - stream->top_if = NULL; - C->false_nesting = 0; - } - if (!stream->dirty) - stream->constant = CONSTANT_FILE_YES; - *list = next->next; - continue; - case TOKEN_STREAMBEGIN: - *list = next->next; - continue; - - default: - dirty_stream(stream); - if (C->false_nesting) { - *list = next->next; - dmrC_allocator_free(&C->token_allocator, next); - continue; - } - - if (dmrC_token_type(next) != TOKEN_IDENT || - expand_one_symbol(C, list)) - list = &next->next; - } - } -} - -struct token * dmrC_preprocess(struct dmr_C *C, struct token *token) -{ - C->preprocessing = 1; - init_preprocessor(C); - do_preprocess(C, &token); - - // Drop all expressions from preprocessing, they're not used any more. - // This is not true when we have multiple files, though ;/ - // clear_expression_alloc(); - C->preprocessing = 0; - - return token; -} - -void dmrC_init_preprocessor_state(struct dmr_C *C) { - assert(C->includepath[0] == NULL); - C->includepath[0] = ""; - C->includepath[1] = "/usr/include"; - C->includepath[2] = "/usr/local/include"; - C->includepath[3] = NULL; - - C->quote_includepath = C->includepath; - C->angle_includepath = C->includepath + 1; - C->isys_includepath = C->includepath + 1; - C->sys_includepath = C->includepath + 1; - C->dirafter_includepath = C->includepath + 3; -} - -static void dump_macro(struct dmr_C *C, struct symbol *sym) -{ - int nargs = sym->arglist ? sym->arglist->count.normal : 0; - struct token **args; - struct token *token; - - args = alloca(sizeof(struct token *) * nargs); - printf("#define %s", dmrC_show_ident(C, sym->ident)); - token = sym->arglist; - if (token) { - const char *sep = ""; - int narg = 0; - putchar('('); - for (; !dmrC_eof_token(token); token = token->next) { - if (dmrC_token_type(token) == TOKEN_ARG_COUNT) - continue; - printf("%s%s", sep, dmrC_show_token(C, token)); - args[narg++] = token; - sep = ", "; - } - putchar(')'); - } - putchar(' '); - - token = sym->expansion; - while (!dmrC_eof_token(token)) { - struct token *next = token->next; - switch (dmrC_token_type(token)) { - case TOKEN_UNTAINT: - break; - case TOKEN_MACRO_ARGUMENT: - token = args[token->argnum]; - /* fall-through */ - default: - printf("%s", dmrC_show_token(C, token)); - if (next->pos.whitespace) - putchar(' '); - } - token = next; - } - putchar('\n'); -} - -void dmrC_dump_macro_definitions(struct dmr_C *C) -{ - struct ident *name; - - FOR_EACH_PTR(C->macros, name) { - struct symbol *sym = lookup_macro(C, name); - if (sym) - dump_macro(C, sym); - } END_FOR_EACH_PTR(name); -} \ No newline at end of file diff --git a/dmr_c/src/ptrlist.c b/dmr_c/src/ptrlist.c deleted file mode 100644 index 9467e8f..0000000 --- a/dmr_c/src/ptrlist.c +++ /dev/null @@ -1,977 +0,0 @@ -/* -* ptrlist.c -* -* Pointer ptrlist_t manipulation -* -* (C) Copyright Linus Torvalds 2003-2005 -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#define PARANOIA 1 - -#include - -#include -#include - -/* The ptr list */ - -/* For testing we change this */ -static int N_ = LIST_NODE_NR; - -void ptrlist_split_node(struct ptr_list *head) -{ - int old = head->nr_, nr = old / 2; - struct allocator *alloc = head->allocator_; - assert(alloc); - struct ptr_list *newlist = - (struct ptr_list *)dmrC_allocator_allocate(alloc, 0); - struct ptr_list *next = head->next_; - newlist->allocator_ = alloc; - - old -= nr; - head->nr_ = old; - newlist->next_ = next; - next->prev_ = newlist; - newlist->prev_ = head; - head->next_ = newlist; - newlist->nr_ = nr; - memcpy(newlist->list_, head->list_ + old, nr * sizeof(void *)); - memset(head->list_ + old, 0xf0, nr * sizeof(void *)); -} - -struct ptr_list_iter ptrlist_forward_iterator(struct ptr_list *head) -{ - struct ptr_list_iter iter; - iter.__head = iter.__list = head; - iter.__nr = -1; - return iter; -} - -// Reverse iterator has to start from previous node not previous entry -// in the given head -struct ptr_list_iter ptrlist_reverse_iterator(struct ptr_list *head) -{ - struct ptr_list_iter iter; - iter.__head = iter.__list = head ? head->prev_ : NULL; - iter.__nr = iter.__head ? iter.__head->nr_ : 0; - return iter; -} - -void *ptrlist_iter_next(struct ptr_list_iter *self) -{ - if (self->__head == NULL) - return NULL; - self->__nr++; -Lretry: - if (self->__nr < self->__list->nr_) { - void *ptr = self->__list->list_[self->__nr]; - if (self->__list->rm_ && !ptr) { - self->__nr++; - goto Lretry; - } - return ptr; - } else if (self->__list->next_ != self->__head) { - self->__list = self->__list->next_; - self->__nr = 0; - goto Lretry; - } - return NULL; -} - -void *ptrlist_nth_entry(struct ptr_list *list, unsigned int idx) -{ - struct ptr_list *head = list; - if (!head) - return NULL; - do { - unsigned int nr = list->nr_; - if (idx < nr) - return list->list_[idx]; - else - idx -= nr; - } while ((list = list->next_) != head); - return NULL; -} - -void *ptrlist_iter_prev(struct ptr_list_iter *self) -{ - if (self->__head == NULL) - return NULL; - self->__nr--; -Lretry: - if (self->__nr >= 0 && self->__nr < self->__list->nr_) { - void *ptr = self->__list->list_[self->__nr]; - if (self->__list->rm_ && !ptr) { - self->__nr--; - goto Lretry; - } - return ptr; - } else if (self->__list->prev_ != self->__head) { - self->__list = self->__list->prev_; - self->__nr = self->__list->nr_ - 1; - goto Lretry; - } - return NULL; -} - -void ptrlist_iter_split_current(struct ptr_list_iter *self) -{ - if (self->__list->nr_ == N_) { - /* full so split */ - ptrlist_split_node(self->__list); - if (self->__nr >= self->__list->nr_) { - self->__nr -= self->__list->nr_; - self->__list = self->__list->next_; - } - } -} - -void ptrlist_iter_insert(struct ptr_list_iter *self, void *newitem) -{ - assert(self->__nr >= 0); - ptrlist_iter_split_current(self); - void **__this = self->__list->list_ + self->__nr; - void **__last = self->__list->list_ + self->__list->nr_ - 1; - while (__last >= __this) { - __last[1] = __last[0]; - __last--; - } - *__this = newitem; - self->__list->nr_++; -} - -void ptrlist_iter_remove(struct ptr_list_iter *self) -{ - assert(self->__nr >= 0); - void **__this = self->__list->list_ + self->__nr; - void **__last = self->__list->list_ + self->__list->nr_ - 1; - while (__this < __last) { - __this[0] = __this[1]; - __this++; - } - *__this = (void *)((uintptr_t)0xf0f0f0f0); - self->__list->nr_--; - self->__nr--; -} - -void ptrlist_iter_set(struct ptr_list_iter *self, void *ptr) -{ - assert(self->__list && self->__nr >= 0 && - self->__nr < self->__list->nr_); - self->__list->list_[self->__nr] = ptr; -} - -void ptrlist_iter_mark_deleted(struct ptr_list_iter *self) -{ - ptrlist_iter_set(self, NULL); - self->__list->rm_++; -} - -int ptrlist_size(const struct ptr_list *head) { - int nr = 0; - if (head) { - const struct ptr_list *list = head; - do { - nr += list->nr_ - list->rm_; - } while ((list = list->next_) != head); - } - return nr; -} - -void **ptrlist_add(struct ptr_list **listp, void *ptr, struct allocator *alloc) -{ - struct ptr_list *list = *listp; - struct ptr_list *last = NULL; - void **ret; - int nr; - - if (!list || (nr = (last = list->prev_)->nr_) >= N_) { - struct ptr_list *newlist = - (struct ptr_list *)dmrC_allocator_allocate(alloc, 0); - newlist->allocator_ = alloc; - if (!list) { - newlist->next_ = newlist; - newlist->prev_ = newlist; - *listp = newlist; - } else { - newlist->prev_ = last; - newlist->next_ = list; - list->prev_ = newlist; - last->next_ = newlist; - } - last = newlist; - nr = 0; - } - ret = last->list_ + nr; - *ret = ptr; - nr++; - last->nr_ = nr; - return ret; -} - -void *ptrlist_first(struct ptr_list *list) -{ - if (!list) - return NULL; - return list->list_[0]; -} - -void *ptrlist_last(struct ptr_list *list) -{ - if (!list) - return NULL; - list = list->prev_; - return list->list_[list->nr_ - 1]; -} - -/* -* Linearize the entries of a list up to a total of 'max', -* and return the nr of entries linearized. -* -* The array to linearize into (second argument) should really -* be "void *x[]", but we want to let people fill in any kind -* of pointer array, so let's just call it "void **". -*/ -int ptrlist_linearize(struct ptr_list *head, void **arr, int max) { - int nr = 0; - if (head && max > 0) { - struct ptr_list *list = head; - - do { - int i = list->nr_; - if (i > max) - i = max; - memcpy(arr, list->list_, i * sizeof(void *)); - arr += i; - nr += i; - max -= i; - if (!max) - break; - } while ((list = list->next_) != head); - } - return nr; -} - -/* -* When we've walked the list and deleted entries, -* we may need to re-pack it so that we don't have -* any empty blocks left (empty blocks upset the -* walking code -*/ -void ptrlist_pack(struct ptr_list **listp) -{ - struct ptr_list *head = *listp; - - if (head) { - struct ptr_list *entry = head; - do { - struct ptr_list *next; - restart: - next = entry->next_; - if (!entry->nr_) { - struct ptr_list *prev; - if (next == entry) { - dmrC_allocator_free(entry->allocator_, entry); - *listp = NULL; - return; - } - prev = entry->prev_; - prev->next_ = next; - next->prev_ = prev; - dmrC_allocator_free(entry->allocator_, entry); - if (entry == head) { - *listp = next; - head = next; - entry = next; - goto restart; - } - } - entry = next; - } while (entry != head); - } -} - -void ptrlist_remove_all(struct ptr_list **listp) { - struct ptr_list *tmp, *list = *listp; - if (!list) - return; - list->prev_->next_ = NULL; - while (list) { - tmp = list; - list = list->next_; - dmrC_allocator_free(tmp->allocator_, tmp); - } - *listp = NULL; -} - - -int ptrlist_remove(struct ptr_list **self, void *entry, int count) { - struct ptr_list_iter iter = ptrlist_forward_iterator(*self); - for (void *ptr = ptrlist_iter_next(&iter); ptr != NULL; - ptr = ptrlist_iter_next(&iter)) { - if (ptr == entry) { - ptrlist_iter_remove(&iter); - if (!--count) - goto out; - } - } - assert(count <= 0); -out: - ptrlist_pack(self); - return count; -} - -int ptrlist_replace(struct ptr_list **self, void *old_ptr, void *new_ptr, - int count) { - struct ptr_list_iter iter = ptrlist_forward_iterator(*self); - for (void *ptr = ptrlist_iter_next(&iter); ptr != NULL; - ptr = ptrlist_iter_next(&iter)) { - if (ptr == old_ptr) { - ptrlist_iter_set(&iter, new_ptr); - if (!--count) - goto out; - } - } - assert(count <= 0); -out: - return count; -} - -/* This removes the last entry, but doesn't pack the ptr list */ -void *ptrlist_undo_last(struct ptr_list **head) -{ - struct ptr_list *last, *first = *head; - - if (!first) - return NULL; - last = first; - do { - last = last->prev_; - if (last->nr_) { - void *ptr; - int nr = --last->nr_; - ptr = last->list_[nr]; - last->list_[nr] = (void *)((intptr_t)0xf1f1f1f1); - return ptr; - } - } while (last != first); - return NULL; -} - - -void *ptrlist_delete_last(struct ptr_list **head) -{ - void *ptr = NULL; - struct ptr_list *last, *first = *head; - - if (!first) - return NULL; - last = first->prev_; - if (last->nr_) - ptr = last->list_[--last->nr_]; - if (last->nr_ <= 0) { - first->prev_ = last->prev_; - last->prev_->next_ = first; - if (last == first) - *head = NULL; - dmrC_allocator_free(last->allocator_, last); - } - return ptr; -} - -void ptrlist_concat(struct ptr_list *a, struct ptr_list **b) { - struct allocator *alloc = NULL; - struct ptr_list_iter iter = ptrlist_forward_iterator(a); - if (a) - alloc = a->allocator_; - else if (*b) - alloc = (*b)->allocator_; - else - return; - for (void *ptr = ptrlist_iter_next(&iter); ptr != NULL; - ptr = ptrlist_iter_next(&iter)) { - ptrlist_add(b, ptr, alloc); - } -} - -/* -* sort_list: a stable sort for lists. -* -* Time complexity: O(n*log n) -* [assuming limited zero-element fragments] -* -* Space complexity: O(1). -* -* Stable: yes. -*/ - -static void array_sort(void **ptr, int nr, void *userdata, - int (*cmp)(void *, const void *, const void *)) { - int i; - for (i = 1; i < nr; i++) { - void *p = ptr[i]; - if (cmp(userdata, ptr[i - 1], p) > 0) { - int j = i; - do { - ptr[j] = ptr[j - 1]; - if (!--j) - break; - } while (cmp(userdata, ptr[j - 1], p) > 0); - ptr[j] = p; - } - } -} - -static void verify_sorted(struct ptr_list *l, int n, void *userdata, - int (*cmp)(void *, const void *, const void *)) { - int i = 0; - const void *a; - struct ptr_list *head = l; - - while (l->nr_ == 0) { - l = l->next_; - if (--n == 0) - return; - assert(l != head); - } - - a = l->list_[0]; - while (n > 0) { - const void *b; - if (++i >= l->nr_) { - i = 0; - l = l->next_; - n--; - assert(l != head || n == 0); - continue; - } - b = l->list_[i]; - assert(cmp(userdata, a, b) <= 0); - a = b; - } -} - -static void flush_to(struct ptr_list *b, void **buffer, int *nbuf) { - int nr = b->nr_; - assert(*nbuf >= nr); - memcpy(b->list_, buffer, nr * sizeof(void *)); - *nbuf = *nbuf - nr; - memmove(buffer, buffer + nr, *nbuf * sizeof(void *)); -} - -static void dump_to(struct ptr_list *b, void **buffer, int nbuf) { - assert(nbuf <= b->nr_); - memcpy(b->list_, buffer, nbuf * sizeof(void *)); -} - -// Merge two already-sorted sequences of blocks: -// (b1_1, ..., b1_n) and (b2_1, ..., b2_m) -// Since we may be moving blocks around, we return the new head -// of the merged list. -static struct ptr_list * -merge_block_seqs(struct ptr_list *b1, int n, struct ptr_list *b2, - int m, void *userdata, int (*cmp)(void *, const void *, const void *)) { - int i1 = 0, i2 = 0; - void *buffer[2 * LIST_NODE_NR]; - int nbuf = 0; - struct ptr_list *newhead = b1; - - // printf ("Merging %d blocks at %p with %d blocks at %p\n", n, b1, m, b2); - - // Skip empty blocks in b2. - while (b2->nr_ == 0) { - // BEEN_THERE('F'); - b2 = b2->next_; - if (--m == 0) { - // BEEN_THERE('G'); - return newhead; - } - } - - // Do a quick skip in case entire blocks from b1 are - // already less than smallest element in b2. - while (b1->nr_ == 0 || - cmp(userdata, PTR_ENTRY(b1, b1->nr_ - 1), PTR_ENTRY(b2,0)) < 0) { - // printf ("Skipping whole block.\n"); - // BEEN_THERE('H'); - b1 = b1->next_; - if (--n == 0) { - // BEEN_THERE('I'); - return newhead; - } - } - - while (1) { - void *d1 = PTR_ENTRY(b1,i1); - void *d2 = PTR_ENTRY(b2,i2); - - assert(i1 >= 0 && i1 < b1->nr_); - assert(i2 >= 0 && i2 < b2->nr_); - assert(b1 != b2); - assert(n > 0); - assert(m > 0); - - if (cmp(userdata, d1, d2) <= 0) { - // BEEN_THERE('J'); - buffer[nbuf++] = d1; - // Element from b1 is smaller - if (++i1 >= b1->nr_) { - // BEEN_THERE('L'); - flush_to(b1, buffer, &nbuf); - do { - b1 = b1->next_; - if (--n == 0) { - // BEEN_THERE('O'); - while (b1 != b2) { - // BEEN_THERE('P'); - flush_to(b1, buffer, &nbuf); - b1 = b1->next_; - } - assert(nbuf == i2); - dump_to(b2, buffer, nbuf); - return newhead; - } - } while (b1->nr_ == 0); - i1 = 0; - } - } else { - // BEEN_THERE('K'); - // Element from b2 is smaller - buffer[nbuf++] = d2; - if (++i2 >= b2->nr_) { - struct ptr_list *l = b2; - // BEEN_THERE('M'); - // OK, we finished with b2. Pull it out - // and plug it in before b1. - - b2 = b2->next_; - b2->prev_ = l->prev_; - b2->prev_->next_ = b2; - l->next_ = b1; - l->prev_ = b1->prev_; - l->next_->prev_ = l; - l->prev_->next_ = l; - - if (b1 == newhead) { - // BEEN_THERE('N'); - newhead = l; - } - - flush_to(l, buffer, &nbuf); - b2 = b2->prev_; - do { - b2 = b2->next_; - if (--m == 0) { - // BEEN_THERE('Q'); - assert(nbuf == i1); - dump_to(b1, buffer, nbuf); - return newhead; - } - } while (b2->nr_ == 0); - i2 = 0; - } - } - } -} - - - -void ptrlist_sort(struct ptr_list **plist, void *userdata, - int (*cmp)(void *, const void *, const void *)) { - struct ptr_list *head = *plist, *list = head; - int blocks = 1; - - assert(N_ == LIST_NODE_NR); - if (!head) - return; - - // Sort all the sub-lists - do { - array_sort(list->list_, list->nr_, userdata, cmp); -#ifdef PARANOIA - verify_sorted(list, 1, userdata, cmp); -#endif - list = list->next_; - } while (list != head); - - // Merge the damn things together - while (1) { - struct ptr_list *block1 = head; - - do { - struct ptr_list *block2 = block1; - struct ptr_list *next, *newhead; - int i; - - for (i = 0; i < blocks; i++) { - block2 = block2->next_; - if (block2 == head) { - if (block1 == head) { - // BEEN_THERE('A'); - *plist = head; - return; - } - // BEEN_THERE('B'); - goto next_pass; - } - } - - next = block2; - for (i = 0; i < blocks;) { - next = next->next_; - i++; - if (next == head) { - // BEEN_THERE('C'); - break; - } - // BEEN_THERE('D'); - } - - newhead = merge_block_seqs(block1, blocks, block2, i, userdata, cmp); -#ifdef PARANOIA - verify_sorted(newhead, blocks + i, userdata, cmp); -#endif - if (block1 == head) { - // BEEN_THERE('E'); - head = newhead; - } - block1 = next; - } while (block1 != head); - next_pass: - blocks <<= 1; - } -} - -static int int_cmp(void *ud, const void *_a, const void *_b) { - (void) ud; - const int *a = (const int *)_a; - const int *b = (const int *)_b; - return *a - *b; -} - -#define MIN(_x, _y) ((_x) < (_y) ? (_x) : (_y)) - -static int test_sort() { - int i, *e; - const int N = 10000; - - srand(N); - for (i = 0; i < 1000; i++) - (void)rand(); - - struct allocator ptrlist_allocator; - dmrC_allocator_init(&ptrlist_allocator, "ptrlist_nodes", sizeof(struct ptr_list), - __alignof__(struct ptr_list), CHUNK); - struct allocator int_allocator; - dmrC_allocator_init(&int_allocator, "ints", sizeof(int), __alignof__(int), CHUNK); - struct ptr_list *int_list = NULL; - - for (i = 0; i < N; i++) { - e = (int*)dmrC_allocator_allocate(&int_allocator, 0); - *e = rand(); - ptrlist_add(&int_list, e, &ptrlist_allocator); - } - if (ptrlist_size(int_list) != N) - return 1; - ptrlist_sort(&int_list, NULL, int_cmp); - // Sort already sorted stuff. - ptrlist_sort(&int_list, NULL, int_cmp); - - int *p = NULL; - struct ptr_list_iter iter = ptrlist_forward_iterator(int_list); - int count = 0; - for (int *k = (int*)ptrlist_iter_next(&iter); k != NULL; - k = (int*)ptrlist_iter_next(&iter)) { - if (p != NULL) { - if (*k < *p) - return 1; - } - p = k; - count++; - } - if (count != N) - return 1; - - struct ptr_list *l = int_list, *l2; - l2 = l; - int expected_count = 0; - do { - l2->nr_ = MIN(l2->nr_, rand() % 3); - for (i = 0; i < l2->nr_; i++) { - *((int *)(l2->list_[i])) = rand(); - expected_count++; - } - l2 = l2->next_; - } while (l2 != l); - ptrlist_sort(&int_list, NULL, int_cmp); - - p = NULL; - iter = ptrlist_forward_iterator(int_list); - count = 0; - for (int *k = (int*)ptrlist_iter_next(&iter); k != NULL; - k = (int*)ptrlist_iter_next(&iter)) { - if (p != NULL) { - if (*k < *p) - return 1; - } - p = k; - count++; - } - if (count != expected_count) - return 1; - ptrlist_remove_all(&int_list); - dmrC_allocator_destroy(&int_allocator); - dmrC_allocator_destroy(&ptrlist_allocator); - return 0; -} - -struct mystruct { - int i; -}; - -struct mytoken { - const char *a; -}; - -static int test_ptrlist_basics() { - struct allocator ptrlist_allocator; - dmrC_allocator_init(&ptrlist_allocator, "ptrlist_nodes", sizeof(struct ptr_list), - __alignof__(struct ptr_list), CHUNK); - struct allocator token_allocator; - dmrC_allocator_init(&token_allocator, "ptr_list_tokens", sizeof(struct mytoken), - __alignof__(struct mytoken), CHUNK); - struct ptr_list *token_list = NULL; - if (ptrlist_size(token_list) != 0) - return 1; - struct mytoken *tok1 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0); - struct mytoken **tok1p = (struct mytoken **)ptrlist_add(&token_list, tok1, &ptrlist_allocator); - if (ptrlist_size(token_list) != 1) - return 1; - if (tok1 != *tok1p) - return 1; - if (ptrlist_first(token_list) != tok1) - return 1; - if (ptrlist_last(token_list) != tok1) - return 1; - struct mytoken *tok2 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0); - struct mytoken **tok2p = (struct mytoken **)ptrlist_add(&token_list, tok2, &ptrlist_allocator); - if (ptrlist_size(token_list) != 2) - return 1; - struct mytoken *tok3 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0); - ptrlist_add(&token_list, tok3, &ptrlist_allocator); - if (ptrlist_size(token_list) != 3) - return 1; - struct mytoken *tok4 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0); - ptrlist_add(&token_list, tok4, &ptrlist_allocator); - if (ptrlist_size(token_list) != 4) - return 1; - struct mytoken *tok5 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0); - struct mytoken **tok5p = (struct mytoken **)ptrlist_add(&token_list, tok5, &ptrlist_allocator); - if (ptrlist_size(token_list) != 5) - return 1; - - if (tok2 != *tok2p) - return 1; - if (tok5 != *tok5p) - return 1; - if (ptrlist_first(token_list) != tok1) - return 1; - if (ptrlist_last(token_list) != tok5) - return 1; - struct mytoken *toks[5]; - int lin1 = ptrlist_linearize(token_list, (void **)toks, 5); - if (lin1 != 5) - return 1; - if (toks[0] != tok1) - return 1; - if (toks[1] != tok2) - return 1; - if (toks[2] != tok3) - return 1; - if (toks[3] != tok4) - return 1; - if (toks[4] != tok5) - return 1; - if (ptrlist_size(token_list) != 5) - return 1; - ptrlist_pack(&token_list); - if (ptrlist_size(token_list) != 5) - return 1; - - if (ptrlist_first(token_list) != tok1) - return 1; - if (ptrlist_last(token_list) != tok5) - return 1; - - const int X = 5 + 1; - const int Y = X - 1; - const int Z = Y - 1; - struct ptr_list_iter iter1 = ptrlist_forward_iterator(token_list); - for (int i = 0; i < X; i++) { - struct mytoken *tk = (struct mytoken *)ptrlist_iter_next(&iter1); - if (tk == NULL) { - if (i == Y) - break; - return 1; - } - if (tk != toks[i]) - return 1; - } - struct ptr_list_iter iter2 = ptrlist_reverse_iterator(token_list); - for (int i = 0; i < X; i++) { - struct mytoken *tk = (struct mytoken *)ptrlist_iter_prev(&iter2); - if (tk == NULL) { - if (i == Y) - break; - return 1; - } - if (tk != toks[Z - i]) - return 1; - } - struct mytoken *tok0 = (struct mytoken *)dmrC_allocator_allocate(&token_allocator, 0); - struct ptr_list_iter iter3 = ptrlist_forward_iterator(token_list); - if (!ptrlist_iter_next(&iter3)) - return 1; - ptrlist_iter_insert(&iter3, tok0); - if (ptrlist_size(token_list) != 6) - return 1; - if (ptrlist_first(token_list) != tok0) - return 1; - if (ptrlist_last(token_list) != tok5) - return 1; - - struct allocator mystruct_allocator; - dmrC_allocator_init(&mystruct_allocator, "mystructs", sizeof(struct mystruct), - __alignof__(struct mystruct), CHUNK); - struct ptr_list *mystruct_list = NULL; - - struct mystruct *s1 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0); - s1->i = 1; - struct mystruct *s2 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0); - s2->i = 2; - struct mystruct *s3 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0); - s3->i = 3; - struct mystruct *s4 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0); - s4->i = 4; - struct mystruct *s5 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0); - s5->i = 5; - struct mystruct *s6 = (struct mystruct *)dmrC_allocator_allocate(&mystruct_allocator, 0); - s6->i = 6; - - ptrlist_add(&mystruct_list, s1, &ptrlist_allocator); - ptrlist_add(&mystruct_list, s2, &ptrlist_allocator); - ptrlist_add(&mystruct_list, s3, &ptrlist_allocator); - ptrlist_add(&mystruct_list, s4, &ptrlist_allocator); - ptrlist_add(&mystruct_list, s5, &ptrlist_allocator); - ptrlist_add(&mystruct_list, s6, &ptrlist_allocator); - - struct mystruct *serial1_expected[6] = { s1, s2, s3, s4, s5, s6 }; - struct mystruct *serial1_got[6]; - ptrlist_linearize(mystruct_list, (void **)serial1_got, 6); - for (int i = 0; i < 6; i++) { - if (serial1_expected[i] != serial1_got[i]) - return 1; - } - - if (ptrlist_remove(&mystruct_list, s3, 1) != 0) - return 1; - struct ptr_list_iter iter4 = ptrlist_forward_iterator(mystruct_list); - for (struct mystruct *p = (struct mystruct *)ptrlist_iter_next(&iter4); p != NULL; - p = (struct mystruct *)ptrlist_iter_next(&iter4)) { - if (p->i == 4) - ptrlist_iter_remove(&iter4); - } - if (ptrlist_size(mystruct_list) != 4) - return 1; - - struct mystruct *serial3_expected[4] = { s1, s2, s5, s6 }; - struct mystruct *serial3_got[4]; - int reverse_expected[2] = { 2, 1 }; - - int i = 0; - struct mystruct *p; - FOR_EACH_PTR(mystruct_list, p) { - if (i == 4) - return 1; - serial3_got[i++] = p; - if (i == 3) { - struct mystruct *p2; - int j = 0; - RECURSE_PTR_REVERSE(p, p2) { - if (j >= 2 || reverse_expected[j] != p2->i) - return 1; - j++; - } END_FOR_EACH_PTR_REVERSE(p2); - } - } END_FOR_EACH_PTR(p); - if (i != 4) - return 1; - for (int i = 0; i < 4; i++) { - if (serial3_expected[i] != serial3_got[i]) - return 1; - } - - i = 0; - PREPARE_PTR_LIST(mystruct_list, p); - while (p != NULL) { - if (i == 4) - return 1; - serial3_got[i++] = p; - NEXT_PTR_LIST(p); - } - FINISH_PTR_LIST(p); - if (i != 4) - return 1; - for (int i = 0; i < 4; i++) { - if (serial3_expected[i] != serial3_got[i]) - return 1; - } - - i = 0; - FOR_EACH_PTR_REVERSE(mystruct_list, p) { - if (i == 4) - return 1; - serial3_got[i++] = p; - if (i == 2) { - struct mystruct *p3; - int j = 0; - RECURSE_PTR_REVERSE(p, p3) { - if (j >= 2 || reverse_expected[j] != p3->i) - return 1; - j++; - } END_FOR_EACH_PTR_REVERSE(p3); - } - } END_FOR_EACH_PTR_REVERSE(p); - if (i != 4) - return 1; - for (int i = 0; i < 4; i++) { - if (serial3_expected[3-i] != serial3_got[i]) - return 1; - } - - ptrlist_remove_all(&token_list); - ptrlist_remove_all(&mystruct_list); - - dmrC_allocator_destroy(&token_allocator); - dmrC_allocator_destroy(&mystruct_allocator); - dmrC_allocator_destroy(&ptrlist_allocator); - return 0; -} - -int test_ptrlist() { - if (test_sort() != 0) - return 1; - - /* For testing we set N_ temporarily */ - N_ = 2; - int failure_count = test_ptrlist_basics(); - N_ = LIST_NODE_NR; - - if (failure_count == 0) - printf("ptrlist test okay\n"); - return failure_count; -} diff --git a/dmr_c/src/ptrlist.h b/dmr_c/src/ptrlist.h deleted file mode 100644 index e8f29dd..0000000 --- a/dmr_c/src/ptrlist.h +++ /dev/null @@ -1,333 +0,0 @@ -#ifndef DMR_C_PTRLIST_H -#define DMR_C_PTRLIST_H - -/* -* Generic pointer list manipulation code. -* -* (C) Copyright Linus Torvalds 2003-2005 -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/* -* The ptr list data structure is like a train - with cars linked to each other. -* Just as in a train each car has many seats, so in ptr list each "node" has -* several entries. Unlike a train however, the ptr list is arranged as a ring, -* i.e. the the front and back nodes are linked to each other. Hence there is no -* such thing as a 'head' of the list - i.e. any node can be the head! -*/ - -#ifndef LIST_NODE_NR -#define LIST_NODE_NR (29) -#endif - -#define DECLARE_PTR_LIST(listname, type) \ - struct listname { \ - int nr_ : 8; \ - int rm_ : 8; \ - struct listname *prev_; \ - struct listname *next_; \ - struct allocator *allocator_; \ - type *list_[LIST_NODE_NR]; \ - } - -/* Each node in the list */ -DECLARE_PTR_LIST(ptr_list, void); - -struct ptr_list_iter { - struct ptr_list *__head; - struct ptr_list *__list; - int __nr; -}; - -/* The ptr list */ -extern int ptrlist_size(const struct ptr_list *self); -extern void **ptrlist_add(struct ptr_list **self, void *ptr, struct allocator *alloc); -extern void *ptrlist_nth_entry(struct ptr_list *list, unsigned int idx); -extern void *ptrlist_first(struct ptr_list *list); -extern void *ptrlist_last(struct ptr_list *list); -extern int ptrlist_linearize(struct ptr_list *head, void **arr, int max); -extern void ptrlist_split_node(struct ptr_list *head); -extern void ptrlist_pack(struct ptr_list **self); -extern void ptrlist_remove_all(struct ptr_list **self); -extern int ptrlist_remove(struct ptr_list **self, void *entry, int count); -extern int ptrlist_replace(struct ptr_list **self, void *old_ptr, void *new_ptr, - int count); -extern void *ptrlist_undo_last(struct ptr_list **self); -extern void *ptrlist_delete_last(struct ptr_list **self); -extern void ptrlist_concat(struct ptr_list *a, struct ptr_list **self); -extern void ptrlist_sort(struct ptr_list **self, void *, - int (*cmp)(void *, const void *, const void *)); - -/* iterator functions */ -extern struct ptr_list_iter ptrlist_forward_iterator(struct ptr_list *self); -extern struct ptr_list_iter ptrlist_reverse_iterator(struct ptr_list *self); -extern void *ptrlist_iter_next(struct ptr_list_iter *self); -extern void *ptrlist_iter_prev(struct ptr_list_iter *self); -extern void ptrlist_iter_split_current(struct ptr_list_iter *self); -extern void ptrlist_iter_insert(struct ptr_list_iter *self, void *newitem); -extern void ptrlist_iter_remove(struct ptr_list_iter *self); -extern void ptrlist_iter_set(struct ptr_list_iter *self, void *ptr); -extern void ptrlist_iter_mark_deleted(struct ptr_list_iter *self); - -static inline void **ptrlist_iter_this_address(struct ptr_list_iter *self) { - return &self->__list->list_[self->__nr]; -} -#define ptr_list_empty(x) ((x) == NULL) -#define PTR_ENTRY_NOTAG(h,i) ((h)->list_[i]) -#define PTR_ENTRY(h,i) (void *)(PTR_ENTRY_NOTAG(h,i)) - -#if 1 - -#define FOR_EACH_PTR(list, var) \ - { struct ptr_list_iter var##iter__ = ptrlist_forward_iterator((struct ptr_list *)list); \ - for (var = ptrlist_iter_next(&var##iter__); var != NULL; var = ptrlist_iter_next(&var##iter__)) -#define END_FOR_EACH_PTR(var) } - -#define FOR_EACH_PTR_REVERSE(list, var) \ - { struct ptr_list_iter var##iter__ = ptrlist_reverse_iterator((struct ptr_list *)list); \ - for (var = ptrlist_iter_prev(&var##iter__); var != NULL; var = ptrlist_iter_prev(&var##iter__)) -#define END_FOR_EACH_PTR_REVERSE(var) } - -#define RECURSE_PTR_REVERSE(list, var) \ - { struct ptr_list_iter var##iter__ = list##iter__; \ - for (var = ptrlist_iter_prev(&var##iter__); var != NULL; var = ptrlist_iter_prev(&var##iter__)) - -#define PREPARE_PTR_LIST(list, var) \ - struct ptr_list_iter var##iter__ = ptrlist_forward_iterator((struct ptr_list *)list); \ - var = ptrlist_iter_next(&var##iter__) - -#define NEXT_PTR_LIST(var) \ - var = ptrlist_iter_next(&var##iter__) -#define FINISH_PTR_LIST(var) - -#define THIS_ADDRESS(type, var) \ - (type *)ptrlist_iter_this_address(&var##iter__) - -#define DELETE_CURRENT_PTR(var) \ - ptrlist_iter_remove(&var##iter__) - -#define REPLACE_CURRENT_PTR(type, var, replacement) \ - ptrlist_iter_set(&var##iter__, replacement) - -#define INSERT_CURRENT(newval, var) \ - ptrlist_iter_insert(&var##iter__, newval) - -#define MARK_CURRENT_DELETED(PTR_TYPE, var) \ - ptrlist_iter_mark_deleted(&var##iter__) - -#else - -#define DO_PREPARE(head, ptr, __head, __list, __nr, PTR_ENTRY) \ - do { \ - struct ptr_list *__head = (struct ptr_list *) (head); \ - struct ptr_list *__list = __head; \ - int __nr = 0; \ - if (__head) ptr = PTR_ENTRY(__head, 0); \ - else ptr = NULL - -#define DO_NEXT(ptr, __head, __list, __nr, PTR_ENTRY) \ - if (ptr) { \ - if (++__nr < __list->nr_) { \ - ptr = PTR_ENTRY(__list,__nr); \ - } else { \ - __list = __list->next_; \ - ptr = NULL; \ - while (__list->nr_ == 0 && __list != __head) \ - __list = __list->next_; \ - if (__list != __head) { \ - __nr = 0; \ - ptr = PTR_ENTRY(__list,0); \ - } \ - } \ - } - -#define DO_RESET(ptr, __head, __list, __nr, PTR_ENTRY) \ - do { \ - __nr = 0; \ - __list = __head; \ - if (__head) ptr = PTR_ENTRY(__head, 0); \ - } while (0) - -#define DO_FINISH(ptr, __head, __list, __nr) \ - (void)(__nr); /* Sanity-check nesting */ \ - } while (0) - -#define PREPARE_PTR_LIST(head, ptr) \ - DO_PREPARE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY) - -#define NEXT_PTR_LIST(ptr) \ - DO_NEXT(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY) - -#define RESET_PTR_LIST(ptr) \ - DO_RESET(ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY) - -#define FINISH_PTR_LIST(ptr) \ - DO_FINISH(ptr, __head##ptr, __list##ptr, __nr##ptr) - -#define DO_FOR_EACH(head, ptr, __head, __list, __nr, PTR_ENTRY) do { \ - struct ptr_list *__head = (struct ptr_list *) (head); \ - struct ptr_list *__list = __head; \ - if (__head) { \ - do { int __nr; \ - for (__nr = 0; __nr < __list->nr_; __nr++) { \ - do { \ - ptr = PTR_ENTRY(__list,__nr); \ - if (__list->rm_ && !ptr) \ - continue; \ - do { - -#define DO_END_FOR_EACH(ptr, __head, __list, __nr) \ - } while (0); \ - } while (0); \ - } \ - } while ((__list = __list->next_) != __head); \ - } \ -} while (0) - -#define DO_FOR_EACH_REVERSE(head, ptr, __head, __list, __nr, PTR_ENTRY) do { \ - struct ptr_list *__head = (struct ptr_list *) (head); \ - struct ptr_list *__list = __head; \ - if (__head) { \ - do { int __nr; \ - __list = __list->prev_; \ - __nr = __list->nr_; \ - while (--__nr >= 0) { \ - do { \ - ptr = PTR_ENTRY(__list,__nr); \ - if (__list->rm_ && !ptr) \ - continue; \ - do { - - -#define DO_END_FOR_EACH_REVERSE(ptr, __head, __list, __nr) \ - } while (0); \ - } while (0); \ - } \ - } while (__list != __head); \ - } \ -} while (0) - -#define DO_REVERSE(ptr, __head, __list, __nr, new, __newhead, \ - __newlist, __newnr, PTR_ENTRY) do { \ - struct ptr_list *__newhead = __head; \ - struct ptr_list *__newlist = __list; \ - int __newnr = __nr; \ - new = ptr; \ - goto __inside##new; \ - if (1) { \ - do { \ - __newlist = __newlist->prev_; \ - __newnr = __newlist->nr_; \ - __inside##new: \ - while (--__newnr >= 0) { \ - do { \ - new = PTR_ENTRY(__newlist,__newnr); \ - do { - -#define RECURSE_PTR_REVERSE(ptr, new) \ - DO_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr, \ - new, __head##new, __list##new, __nr##new, PTR_ENTRY) - -#define DO_THIS_ADDRESS(PTR_TYPE, ptr, __head, __list, __nr) \ - ((PTR_TYPE*) (__list->list_ + __nr)) - - -#define FOR_EACH_PTR(head, ptr) \ - DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY) - -#define END_FOR_EACH_PTR(ptr) \ - DO_END_FOR_EACH(ptr, __head##ptr, __list##ptr, __nr##ptr) - -#define FOR_EACH_PTR_NOTAG(head, ptr) \ - DO_FOR_EACH(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG) - -#define END_FOR_EACH_PTR_NOTAG(ptr) END_FOR_EACH_PTR(ptr) - -#define FOR_EACH_PTR_REVERSE(head, ptr) \ - DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY) - -#define END_FOR_EACH_PTR_REVERSE(ptr) \ - DO_END_FOR_EACH_REVERSE(ptr, __head##ptr, __list##ptr, __nr##ptr) - -#define FOR_EACH_PTR_REVERSE_NOTAG(head, ptr) \ - DO_FOR_EACH_REVERSE(head, ptr, __head##ptr, __list##ptr, __nr##ptr, PTR_ENTRY_NOTAG) - -#define END_FOR_EACH_PTR_REVERSE_NOTAG(ptr) END_FOR_EACH_PTR_REVERSE(ptr) - -#define THIS_ADDRESS(PTR_TYPE, ptr) \ - DO_THIS_ADDRESS(PTR_TYPE, ptr, __head##ptr, __list##ptr, __nr##ptr) - - -#define DO_SPLIT(ptr, __head, __list, __nr) do { \ - ptrlist_split_node(__list); \ - if (__nr >= __list->nr_) { \ - __nr -= __list->nr_; \ - __list = __list->next_; \ - }; \ -} while (0) - -#define DO_INSERT_CURRENT(new, ptr, __head, __list, __nr) do { \ - void **__this, **__last; \ - if (__list->nr_ == LIST_NODE_NR) \ - DO_SPLIT(ptr, __head, __list, __nr); \ - __this = __list->list_ + __nr; \ - __last = __list->list_ + __list->nr_ - 1; \ - while (__last >= __this) { \ - __last[1] = __last[0]; \ - __last--; \ - } \ - *__this = (new); \ - __list->nr_++; \ -} while (0) - -#define INSERT_CURRENT(new, ptr) \ - DO_INSERT_CURRENT(new, ptr, __head##ptr, __list##ptr, __nr##ptr) - -#define DO_DELETE_CURRENT(ptr, __head, __list, __nr) do { \ - void **__this = __list->list_ + __nr; \ - void **__last = __list->list_ + __list->nr_ - 1; \ - while (__this < __last) { \ - __this[0] = __this[1]; \ - __this++; \ - } \ - *__this = (void *)((uintptr_t)0xf0f0f0f0); \ - __list->nr_--; __nr--; \ -} while (0) - -#define DELETE_CURRENT_PTR(ptr) \ - DO_DELETE_CURRENT(ptr, __head##ptr, __list##ptr, __nr##ptr) - -#define REPLACE_CURRENT_PTR(PTR_TYPE, ptr, new_ptr) \ - do { *THIS_ADDRESS(PTR_TYPE, ptr) = (new_ptr); } while (0) - -#define DO_MARK_CURRENT_DELETED(PTR_TYPE, ptr, __list) do { \ - REPLACE_CURRENT_PTR(PTR_TYPE, ptr, NULL); \ - __list->rm++; \ - } while (0) - -#define MARK_CURRENT_DELETED(PTR_TYPE, ptr) \ - DO_MARK_CURRENT_DELETED(PTR_TYPE, ptr, __list##ptr) - -#endif - -extern int test_ptrlist(); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/dmr_c/src/runtests.c b/dmr_c/src/runtests.c deleted file mode 100644 index b2cd04d..0000000 --- a/dmr_c/src/runtests.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include -#include -#include -#include - -int main() -{ - int failure_count = 0; - failure_count += dmrC_test_allocator(); - failure_count += test_ptrlist(); - //failure_count += test_tokenizer(); - //failure_count += dmrC_test_parse(); - - if (failure_count == 0) - printf("Tests OK\n"); - else - printf("Tests FAILED\n"); - return failure_count == 0 ? 0 : 1; -} \ No newline at end of file diff --git a/dmr_c/src/scope.c b/dmr_c/src/scope.c deleted file mode 100644 index 19f73a7..0000000 --- a/dmr_c/src/scope.c +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Symbol scoping. - * - * This is pretty trivial. - * - * Copyright (C) 2003 Transmeta Corp. - * 2003-2004 Linus Torvalds - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - /* - * This version is part of the dmr_c project. - * Copyright (C) 2017 Dibyendu Majumdar - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - -void dmrC_init_scope(struct dmr_C *C) { - struct scope *scope = (struct scope *)dmrC_allocator_allocate(&C->scope_allocator, 0); - memset(scope, 0, sizeof(*scope)); - scope->next = scope; - C->builtin_scope = scope; - C->block_scope = C->builtin_scope; // regular automatic variables etc - C->function_scope = C->builtin_scope; // labels, arguments etc - C->file_scope = C->builtin_scope; // static - C->global_scope = C->builtin_scope; // externally visible -} - -void dmrC_destroy_all_scopes(struct dmr_C *C) { - (void) C; -} - -void dmrC_bind_scope(struct dmr_C *C, struct symbol *sym, struct scope *scope) -{ - sym->scope = scope; - dmrC_add_symbol(C, &scope->symbols, sym); -} - -void dmrC_rebind_scope(struct dmr_C *C, struct symbol *sym, struct scope *news) -{ - struct scope *old = sym->scope; - - if (old == news) - return; - - if (old) - ptrlist_remove((struct ptr_list **) &old->symbols, sym, 1); - - dmrC_bind_scope(C, sym, news); -} - -static void start_scope(struct dmr_C *C, struct scope **s) -{ - struct scope *scope = (struct scope *)dmrC_allocator_allocate(&C->scope_allocator, 0); - memset(scope, 0, sizeof(*scope)); - scope->next = *s; - *s = scope; -} - -void dmrC_start_file_scope(struct dmr_C *C) -{ - struct scope *scope = (struct scope *)dmrC_allocator_allocate(&C->scope_allocator, 0); - - memset(scope, 0, sizeof(*scope)); - scope->next = C->builtin_scope; - C->file_scope = scope; - - /* top-level stuff defaults to file scope, "extern" etc will choose global scope */ - C->function_scope = scope; - C->block_scope = scope; -} - -void dmrC_start_symbol_scope(struct dmr_C *C) -{ - start_scope(C, &C->block_scope); -} - -void dmrC_start_function_scope(struct dmr_C *C) -{ - start_scope(C, &C->function_scope); - start_scope(C, &C->block_scope); -} - -static void remove_symbol_scope(struct dmr_C *C, struct symbol *sym) -{ - (void) C; - struct symbol **ptr = &sym->ident->symbols; - - while (*ptr != sym) - ptr = &(*ptr)->next_id; - *ptr = sym->next_id; -} - -static void end_scope(struct dmr_C *C, struct scope **s) -{ - struct scope *scope = *s; - struct symbol_list *symbols = scope->symbols; - struct symbol *sym; - - *s = scope->next; - scope->symbols = NULL; - FOR_EACH_PTR(symbols, sym) { - remove_symbol_scope(C, sym); - } END_FOR_EACH_PTR(sym); -} - -void dmrC_end_file_scope(struct dmr_C *C) -{ - end_scope(C, &C->file_scope); -} - -void dmrC_new_file_scope(struct dmr_C *C) -{ - if (C->file_scope != C->builtin_scope) - dmrC_end_file_scope(C); - dmrC_start_file_scope(C); -} - -void dmrC_end_symbol_scope(struct dmr_C *C) -{ - end_scope(C, &C->block_scope); -} - -void dmrC_end_function_scope(struct dmr_C *C) -{ - end_scope(C, &C->block_scope); - end_scope(C, &C->function_scope); -} - -int dmrC_is_outer_scope(struct dmr_C *C, struct scope *scope) -{ - if (scope == C->block_scope) - return 0; - if (scope == C->builtin_scope && C->block_scope->next == C->builtin_scope) - return 0; - return 1; -} - diff --git a/dmr_c/src/scope.h b/dmr_c/src/scope.h deleted file mode 100644 index 75fdd60..0000000 --- a/dmr_c/src/scope.h +++ /dev/null @@ -1,73 +0,0 @@ -#ifndef DMR_C_SCOPE_H -#define DMR_C_SCOPE_H -/* -* Symbol scoping is pretty simple. -* -* Copyright (C) 2003 Transmeta Corp. -* 2003 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -struct scope { - struct token *token; /* Scope start information */ - struct symbol_list *symbols; /* List of symbols in this scope */ - struct scope *next; -}; - -static inline int dmrC_toplevel(struct dmr_C *C, struct scope *scope) -{ - return scope == C->file_scope || scope == C->global_scope; -} - -extern void dmrC_start_file_scope(struct dmr_C *C); -extern void dmrC_end_file_scope(struct dmr_C *C); -extern void dmrC_new_file_scope(struct dmr_C *C); - -extern void dmrC_start_symbol_scope(struct dmr_C *C); -extern void dmrC_end_symbol_scope(struct dmr_C *C); - -extern void dmrC_start_function_scope(struct dmr_C *C); -extern void dmrC_end_function_scope(struct dmr_C *C); - -extern void dmrC_bind_scope(struct dmr_C *C, struct symbol *, struct scope *); -extern void dmrC_rebind_scope(struct dmr_C *C, struct symbol *sym, struct scope *news); - -extern int dmrC_is_outer_scope(struct dmr_C *C, struct scope *); - -extern void dmrC_init_scope(struct dmr_C *C); -extern void dmrC_destroy_all_scopes(struct dmr_C *C); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/dmr_c/src/show-parse.c b/dmr_c/src/show-parse.c deleted file mode 100644 index c89979d..0000000 --- a/dmr_c/src/show-parse.c +++ /dev/null @@ -1,1141 +0,0 @@ -/* - * sparse/show-parse.c - * - * Copyright (C) 2003 Transmeta Corp. - * 2003-2004 Linus Torvalds - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - * - * Print out results of parsing for debugging and testing. - */ - /* - * This version is part of the dmr_c project. - * Copyright (C) 2017 Dibyendu Majumdar - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static int show_symbol_expr(struct dmr_C *C, struct symbol *sym); -static int show_string_expr(struct dmr_C *C, struct expression *expr); - - -static void do_debug_symbol(struct dmr_C *C, struct symbol *sym, int indent) -{ - static const char indent_string[] = " "; - static const char *typestr[] = { - [SYM_UNINITIALIZED] = "none", - [SYM_PREPROCESSOR] = "cpp.", - [SYM_BASETYPE] = "base", - [SYM_NODE] = "node", - [SYM_PTR] = "ptr.", - [SYM_FN] = "fn..", - [SYM_ARRAY] = "arry", - [SYM_STRUCT] = "strt", - [SYM_UNION] = "unin", - [SYM_ENUM] = "enum", - [SYM_TYPEDEF] = "tdef", - [SYM_TYPEOF] = "tpof", - [SYM_MEMBER] = "memb", - [SYM_BITFIELD] = "bitf", - [SYM_LABEL] = "labl", - [SYM_RESTRICT] = "rstr", - [SYM_FOULED] = "foul", - [SYM_BAD] = "bad.", - }; - struct context *context; - int i; - - if (!sym) - return; - const char *t = dmrC_builtin_typename(C, sym); - fprintf(stderr, "%.*s%s%3d:%lu %s %s (as: %d) %p (%s:%d:%d) %s\n", - indent, indent_string, typestr[sym->type], - sym->bit_size, sym->ctype.alignment, - dmrC_modifier_string(C, sym->ctype.modifiers), dmrC_show_ident(C, sym->ident), sym->ctype.as, - sym, dmrC_stream_name(C, sym->pos.stream), sym->pos.line, sym->pos.pos, - t ? t : ""); - i = 0; - FOR_EACH_PTR(sym->ctype.contexts, context) { - /* FIXME: should print context expression */ - fprintf(stderr, "< context%d: in=%d, out=%d\n", - i, context->in, context->out); - fprintf(stderr, " end context%d >\n", i); - i++; - } END_FOR_EACH_PTR(context); - if (sym->type == SYM_FN) { - struct symbol *arg; - i = 0; - FOR_EACH_PTR(sym->arguments, arg) { - fprintf(stderr, "< arg%d:\n", i); - do_debug_symbol(C, arg, 0); - fprintf(stderr, " end arg%d >\n", i); - i++; - } END_FOR_EACH_PTR(arg); - } - do_debug_symbol(C, sym->ctype.base_type, indent+2); -} - -void dmrC_debug_symbol(struct dmr_C *C, struct symbol *sym) -{ - do_debug_symbol(C, sym, 0); -} - -/* - * Symbol type printout. The type system is by far the most - * complicated part of C - everything else is trivial. - */ -const char *dmrC_modifier_string(struct dmr_C *C, unsigned long mod) -{ - int len = 0; - int i; - struct mod_name { - unsigned long mod; - const char *name; - } *m; - - static struct mod_name mod_names[] = { - {MOD_AUTO, "auto"}, - {MOD_REGISTER, "register"}, - {MOD_STATIC, "static"}, - {MOD_EXTERN, "extern"}, - {MOD_CONST, "const"}, - {MOD_VOLATILE, "volatile"}, - {MOD_SIGNED, "[signed]"}, - {MOD_UNSIGNED, "[unsigned]"}, - {MOD_CHAR, "[char]"}, - {MOD_SHORT, "[short]"}, - {MOD_LONG, "[long]"}, - {MOD_LONGLONG, "[long long]"}, - {MOD_LONGLONGLONG, "[long long long]"}, - {MOD_TYPEDEF, "[typedef]"}, - {MOD_TLS, "[tls]"}, - {MOD_INLINE, "inline"}, - {MOD_ADDRESSABLE, "[addressable]"}, - {MOD_NOCAST, "[nocast]"}, - {MOD_NODEREF, "[noderef]"}, - {MOD_ACCESSED, "[accessed]"}, - {MOD_TOPLEVEL, "[toplevel]"}, - {MOD_ASSIGNED, "[assigned]"}, - {MOD_TYPE, "[type]"}, - {MOD_SAFE, "[safe]"}, - {MOD_USERTYPE, "[usertype]"}, - {MOD_NORETURN, "[noreturn]"}, - {MOD_EXPLICITLY_SIGNED, "[explicitly-signed]"}, - {MOD_BITWISE, "[bitwise]"}, - {MOD_PURE, "[pure]"}, - }; - - for (i = 0; i < (int) ARRAY_SIZE(mod_names); i++) { - m = mod_names + i; - if (mod & m->mod) { - char c; - const char *name = m->name; - while ((c = *name++) != '\0' && len + 2 < (int)(sizeof C->modifier_string_buffer)) - C->modifier_string_buffer[len++] = c; - C->modifier_string_buffer[len++] = ' '; - } - } - C->modifier_string_buffer[len] = 0; - return C->modifier_string_buffer; -} - -static void show_struct_member(struct dmr_C *C, struct symbol *sym) -{ - printf("\t%s:%d:%ld at offset %ld.%d", dmrC_show_ident(C, sym->ident), sym->bit_size, sym->ctype.alignment, sym->offset, sym->bit_offset); - printf("\n"); -} - -void dmrC_show_symbol_list(struct dmr_C *C, struct symbol_list *list, const char *sep) -{ - (void) sep; - struct symbol *sym; - const char *prepend = ""; - - FOR_EACH_PTR(list, sym) { - puts(prepend); - prepend = ", "; - dmrC_show_symbol(C, sym); - } END_FOR_EACH_PTR(sym); -} - -struct type_name { - char *start; - char *end; -}; - -static void FORMAT_ATTR(3) prepend(struct dmr_C *C, struct type_name *name, const char *fmt, ...) -{ - (void) C; - static char buffer[512]; - int n; - - va_list args; - va_start(args, fmt); - n = vsprintf(buffer, fmt, args); - va_end(args); - - name->start -= n; - memcpy(name->start, buffer, n); -} - -static void FORMAT_ATTR(3) append(struct dmr_C *C, struct type_name *name, const char *fmt, ...) -{ - (void) C; - static char buffer[512]; - int n; - - va_list args; - va_start(args, fmt); - n = vsprintf(buffer, fmt, args); - va_end(args); - - memcpy(name->end, buffer, n); - name->end += n; -} - - -const char *dmrC_builtin_typename(struct dmr_C *C, struct symbol *sym) -{ - int i; - - for (i = 0; C->S->typenames[i].sym != NULL; i++) - if (C->S->typenames[i].sym == sym) - return C->S->typenames[i].name; - return NULL; -} - -const char *dmrC_builtin_ctypename(struct dmr_C *C, struct ctype *ctype) -{ - int i; - - for (i = 0; C->S->typenames[i].sym != NULL; i++) - if (&C->S->typenames[i].sym->ctype == ctype) - return C->S->typenames[i].name; - return NULL; -} - -static void do_show_type(struct dmr_C *C, struct symbol *sym, struct type_name *name) -{ - const char *typname; - unsigned long mod = 0; - int as = 0; - int was_ptr = 0; - int restr = 0; - int fouled = 0; - -deeper: - if (!sym || (sym->type != SYM_NODE && sym->type != SYM_ARRAY && - sym->type != SYM_BITFIELD)) { - const char *s; - size_t len; - - if (as) - prepend(C, name, "", as); - - s = dmrC_modifier_string(C, mod); - len = strlen(s); - name->start -= len; - memcpy(name->start, s, len); - mod = 0; - as = 0; - } - - if (!sym) - goto out; - - if ((typname = dmrC_builtin_typename(C, sym))) { - int len = (int) strlen(typname); - if (name->start != name->end) - *--name->start = ' '; - name->start -= len; - memcpy(name->start, typname, len); - goto out; - } - - /* Prepend */ - switch (sym->type) { - case SYM_PTR: - prepend(C, name, "*"); - mod = sym->ctype.modifiers; - as = sym->ctype.as; - was_ptr = 1; - break; - - case SYM_FN: - if (was_ptr) { - prepend(C, name, "( "); - append(C, name, " )"); - was_ptr = 0; - } - append(C, name, "( ... )"); - break; - - case SYM_STRUCT: - if (name->start != name->end) - *--name->start = ' '; - prepend(C, name, "struct %s", dmrC_show_ident(C, sym->ident)); - goto out; - - case SYM_UNION: - if (name->start != name->end) - *--name->start = ' '; - prepend(C, name, "union %s", dmrC_show_ident(C, sym->ident)); - goto out; - - case SYM_ENUM: - prepend(C, name, "enum %s ", dmrC_show_ident(C, sym->ident)); - break; - - case SYM_NODE: - append(C, name, "%s", dmrC_show_ident(C, sym->ident)); - mod |= sym->ctype.modifiers; - as |= sym->ctype.as; - break; - - case SYM_BITFIELD: - mod |= sym->ctype.modifiers; - as |= sym->ctype.as; - append(C, name, ":%d", sym->bit_size); - break; - - case SYM_LABEL: - append(C, name, "label(%s:%p)", dmrC_show_ident(C, sym->ident), sym); - return; - - case SYM_ARRAY: - mod |= sym->ctype.modifiers; - as |= sym->ctype.as; - if (was_ptr) { - prepend(C, name, "( "); - append(C, name, " )"); - was_ptr = 0; - } - append(C, name, "[%lld]", dmrC_get_expression_value(C, sym->array_size)); - break; - - case SYM_RESTRICT: - if (!sym->ident) { - restr = 1; - break; - } - if (name->start != name->end) - *--name->start = ' '; - prepend(C, name, "restricted %s", dmrC_show_ident(C, sym->ident)); - goto out; - - case SYM_FOULED: - fouled = 1; - break; - - default: - if (name->start != name->end) - *--name->start = ' '; - prepend(C, name, "unknown type %d", sym->type); - goto out; - } - - sym = sym->ctype.base_type; - goto deeper; - -out: - if (restr) - prepend(C, name, "restricted "); - if (fouled) - prepend(C, name, "fouled "); -} - -void dmrC_show_type(struct dmr_C *C, struct symbol *sym) -{ - char array[200]; - struct type_name name; - - name.start = name.end = array+100; - do_show_type(C, sym, &name); - *name.end = 0; - printf("%s", name.start); -} - -const char *dmrC_show_typename(struct dmr_C *C, struct symbol *sym) -{ - struct type_name name; - - name.start = name.end = C->typename_array+100; - do_show_type(C, sym, &name); - *name.end = 0; - return name.start; -} - -void dmrC_show_symbol(struct dmr_C *C, struct symbol *sym) -{ - struct symbol *type; - - if (!sym) - return; - - if (sym->ctype.alignment) - printf(".align %ld\n", sym->ctype.alignment); - - dmrC_show_type(C, sym); - type = sym->ctype.base_type; - if (!type) { - printf("\n"); - return; - } - - /* - * Show actual implementation information - */ - switch (type->type) { - struct symbol *member; - - case SYM_STRUCT: - case SYM_UNION: - printf(" {\n"); - FOR_EACH_PTR(type->symbol_list, member) { - show_struct_member(C, member); - } END_FOR_EACH_PTR(member); - printf("}\n"); - break; - - case SYM_FN: { - struct statement *stmt = type->stmt; - printf("\n"); - if (stmt) { - int val; - val = dmrC_show_statement(C, stmt); - if (val) - printf("\tmov.%d\t\tretval,%d\n", stmt->ret->bit_size, val); - printf("\tret\n"); - } - break; - } - - default: - printf("\n"); - break; - } - - if (sym->initializer) { - printf(" = \n"); - dmrC_show_expression(C, sym->initializer); - } -} - -static int show_symbol_init(struct dmr_C *C, struct symbol *sym); - -static int new_pseudo(void) -{ - static int nr = 0; - return ++nr; -} - -static int new_label(void) -{ - static int label = 0; - return ++label; -} - -static void show_switch_statement(struct dmr_C *C, struct statement *stmt) -{ - int val = dmrC_show_expression(C, stmt->switch_expression); - struct symbol *sym; - printf("\tswitch v%d\n", val); - - /* - * Debugging only: Check that the case list is correct - * by printing it out. - * - * This is where a _real_ back-end would go through the - * cases to decide whether to use a lookup table or a - * series of comparisons etc - */ - printf("# case table:\n"); - FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) { - struct statement *case_stmt = sym->stmt; - struct expression *expr = case_stmt->case_expression; - struct expression *to = case_stmt->case_to; - - if (!expr) { - printf(" default"); - } else { - if (expr->type == EXPR_VALUE) { - printf(" case %lld", expr->value); - if (to) { - if (to->type == EXPR_VALUE) { - printf(" .. %lld", to->value); - } else { - printf(" .. what?"); - } - } - } else - printf(" what?"); - } - printf(": .L%p\n", sym); - } END_FOR_EACH_PTR(sym); - printf("# end case table\n"); - - dmrC_show_statement(C, stmt->switch_statement); - - if (stmt->switch_break->used) - printf(".L%p:\n", stmt->switch_break); -} - -static void show_symbol_decl(struct dmr_C *C, struct symbol_list *syms) -{ - struct symbol *sym; - FOR_EACH_PTR(syms, sym) { - show_symbol_init(C, sym); - } END_FOR_EACH_PTR(sym); -} - -static int show_return_stmt(struct dmr_C *C, struct statement *stmt); - -/* - * Print out a statement - */ -int dmrC_show_statement(struct dmr_C *C, struct statement *stmt) -{ - if (!stmt) - return 0; - switch (stmt->type) { - case STMT_DECLARATION: - show_symbol_decl(C, stmt->declaration); - return 0; - case STMT_RETURN: - return show_return_stmt(C, stmt); - case STMT_COMPOUND: { - struct statement *s; - int last = 0; - - if (stmt->inline_fn) { - dmrC_show_statement(C, stmt->args); - printf("\tbegin_inline \t%s\n", dmrC_show_ident(C, stmt->inline_fn->ident)); - } - FOR_EACH_PTR(stmt->stmts, s) { - last = dmrC_show_statement(C, s); - } END_FOR_EACH_PTR(s); - if (stmt->ret) { - int addr, bits; - printf(".L%p:\n", stmt->ret); - addr = show_symbol_expr(C, stmt->ret); - bits = stmt->ret->bit_size; - last = new_pseudo(); - printf("\tld.%d\t\tv%d,[v%d]\n", bits, last, addr); - } - if (stmt->inline_fn) - printf("\tend_inlined\t%s\n", dmrC_show_ident(C, stmt->inline_fn->ident)); - return last; - } - - case STMT_EXPRESSION: - return dmrC_show_expression(C, stmt->expression); - case STMT_IF: { - int val, target; - struct expression *cond = stmt->if_conditional; - -/* This is only valid if nobody can jump into the "dead" statement */ -#if 0 - if (cond->type == EXPR_VALUE) { - struct statement *s = stmt->if_true; - if (!cond->value) - s = stmt->if_false; - dmrC_show_statement(s); - break; - } -#endif - val = dmrC_show_expression(C, cond); - target = new_label(); - printf("\tje\t\tv%d,.L%d\n", val, target); - dmrC_show_statement(C, stmt->if_true); - if (stmt->if_false) { - int last = new_label(); - printf("\tjmp\t\t.L%d\n", last); - printf(".L%d:\n", target); - target = last; - dmrC_show_statement(C, stmt->if_false); - } - printf(".L%d:\n", target); - break; - } - case STMT_SWITCH: - show_switch_statement(C, stmt); - break; - - case STMT_CASE: - printf(".L%p:\n", stmt->case_label); - dmrC_show_statement(C, stmt->case_statement); - break; - - case STMT_ITERATOR: { - struct statement *pre_statement = stmt->iterator_pre_statement; - struct expression *pre_condition = stmt->iterator_pre_condition; - struct statement *statement = stmt->iterator_statement; - struct statement *post_statement = stmt->iterator_post_statement; - struct expression *post_condition = stmt->iterator_post_condition; - int val, loop_top = 0, loop_bottom = 0; - - show_symbol_decl(C, stmt->iterator_syms); - dmrC_show_statement(C, pre_statement); - if (pre_condition) { - if (pre_condition->type == EXPR_VALUE) { - if (!pre_condition->value) { - loop_bottom = new_label(); - printf("\tjmp\t\t.L%d\n", loop_bottom); - } - } else { - loop_bottom = new_label(); - val = dmrC_show_expression(C, pre_condition); - printf("\tje\t\tv%d, .L%d\n", val, loop_bottom); - } - } - if (!post_condition || post_condition->type != EXPR_VALUE || post_condition->value) { - loop_top = new_label(); - printf(".L%d:\n", loop_top); - } - dmrC_show_statement(C, statement); - if (stmt->iterator_continue->used) - printf(".L%p:\n", stmt->iterator_continue); - dmrC_show_statement(C, post_statement); - if (!post_condition) { - printf("\tjmp\t\t.L%d\n", loop_top); - } else if (post_condition->type == EXPR_VALUE) { - if (post_condition->value) - printf("\tjmp\t\t.L%d\n", loop_top); - } else { - val = dmrC_show_expression(C, post_condition); - printf("\tjne\t\tv%d, .L%d\n", val, loop_top); - } - if (stmt->iterator_break->used) - printf(".L%p:\n", stmt->iterator_break); - if (loop_bottom) - printf(".L%d:\n", loop_bottom); - break; - } - case STMT_NONE: - break; - - case STMT_LABEL: - printf(".L%p:\n", stmt->label_identifier); - dmrC_show_statement(C, stmt->label_statement); - break; - - case STMT_GOTO: - if (stmt->goto_expression) { - int val = dmrC_show_expression(C, stmt->goto_expression); - printf("\tgoto\t\t*v%d\n", val); - } else { - printf("\tgoto\t\t.L%p\n", stmt->goto_label); - } - break; - case STMT_ASM: - printf("\tasm( .... )\n"); - break; - case STMT_CONTEXT: { - int val = dmrC_show_expression(C, stmt->expression); - printf("\tcontext( %d )\n", val); - break; - } - case STMT_RANGE: { - int val = dmrC_show_expression(C, stmt->range_expression); - int low = dmrC_show_expression(C, stmt->range_low); - int high = dmrC_show_expression(C, stmt->range_high); - printf("\trange( %d %d-%d)\n", val, low, high); - break; - } - } - return 0; -} - -static int show_call_expression(struct dmr_C *C, struct expression *expr) -{ - struct symbol *direct; - struct expression *arg, *fn; - int fncall, retval; - int framesize; - - if (!expr->ctype) { - dmrC_warning(C, expr->pos, "\tcall with no type!"); - return 0; - } - - framesize = 0; - FOR_EACH_PTR_REVERSE(expr->args, arg) { - int news = dmrC_show_expression(C, arg); - int size = arg->ctype->bit_size; - printf("\tpush.%d\t\tv%d\n", size, news); - framesize += dmrC_bits_to_bytes(C->target, size); - } END_FOR_EACH_PTR_REVERSE(arg); - - fn = expr->fn; - - /* Remove dereference, if any */ - direct = NULL; - if (fn->type == EXPR_PREOP) { - if (fn->unop->type == EXPR_SYMBOL) { - struct symbol *sym = fn->unop->symbol; - if (sym->ctype.base_type->type == SYM_FN) - direct = sym; - } - } - if (direct) { - printf("\tcall\t\t%s\n", dmrC_show_ident(C, direct->ident)); - } else { - fncall = dmrC_show_expression(C, fn); - printf("\tcall\t\t*v%d\n", fncall); - } - if (framesize) - printf("\tadd.%d\t\tvSP,vSP,$%d\n", C->target->bits_in_pointer, framesize); - - retval = new_pseudo(); - printf("\tmov.%d\t\tv%d,retval\n", expr->ctype->bit_size, retval); - return retval; -} - -static int show_comma(struct dmr_C *C, struct expression *expr) -{ - dmrC_show_expression(C, expr->left); - return dmrC_show_expression(C, expr->right); -} - -static int show_binop(struct dmr_C *C, struct expression *expr) -{ - int left = dmrC_show_expression(C, expr->left); - int right = dmrC_show_expression(C, expr->right); - int news = new_pseudo(); - const char *opname; - static const char *name[] = { - ['+'] = "add", ['-'] = "sub", - ['*'] = "mul", ['/'] = "div", - ['%'] = "mod", ['&'] = "and", - ['|'] = "lor", ['^'] = "xor" - }; - unsigned int op = expr->op; - - opname = dmrC_show_special(C, op); - if (op < ARRAY_SIZE(name)) - opname = name[op]; - printf("\t%s.%d\t\tv%d,v%d,v%d\n", opname, - expr->ctype->bit_size, - news, left, right); - return news; -} - -static int show_slice(struct dmr_C *C, struct expression *expr) -{ - int target = dmrC_show_expression(C, expr->base); - int news = new_pseudo(); - printf("\tslice.%d\t\tv%d,v%d,%d\n", expr->r_nrbits, target, news, expr->r_bitpos); - return news; -} - -static int show_regular_preop(struct dmr_C *C, struct expression *expr) -{ - int target = dmrC_show_expression(C, expr->unop); - int news = new_pseudo(); - static const char *name[] = { - ['!'] = "nonzero", ['-'] = "neg", - ['~'] = "not", - }; - unsigned int op = expr->op; - const char *opname; - - opname = dmrC_show_special(C, op); - if (op < ARRAY_SIZE(name)) - opname = name[op]; - printf("\t%s.%d\t\tv%d,v%d\n", opname, expr->ctype->bit_size, news, target); - return news; -} - -/* - * FIXME! Not all accesses are memory loads. We should - * check what kind of symbol is behind the dereference. - */ -static int show_address_gen(struct dmr_C *C, struct expression *expr) -{ - return dmrC_show_expression(C, expr->unop); -} - -static int show_load_gen(int bits, struct expression *expr, int addr) -{ - (void) expr; - int news = new_pseudo(); - - printf("\tld.%d\t\tv%d,[v%d]\n", bits, news, addr); - return news; -} - -static void show_store_gen(int bits, int value, struct expression *expr, int addr) -{ - (void) expr; - /* FIXME!!! Bitfield store! */ - printf("\tst.%d\t\tv%d,[v%d]\n", bits, value, addr); -} - -static int show_assignment(struct dmr_C *C, struct expression *expr) -{ - struct expression *target = expr->left; - int val, addr, bits; - - if (!expr->ctype) - return 0; - - bits = expr->ctype->bit_size; - val = dmrC_show_expression(C, expr->right); - addr = show_address_gen(C, target); - show_store_gen(bits, val, target, addr); - return val; -} - -static int show_return_stmt(struct dmr_C *C, struct statement *stmt) -{ - struct expression *expr = stmt->ret_value; - struct symbol *target = stmt->ret_target; - - if (expr && expr->ctype) { - int val = dmrC_show_expression(C, expr); - int bits = expr->ctype->bit_size; - int addr = show_symbol_expr(C, target); - show_store_gen(bits, val, NULL, addr); - } - printf("\tret\t\t(%p)\n", target); - return 0; -} - -static int show_initialization(struct dmr_C *C, struct symbol *sym, struct expression *expr) -{ - int val, addr, bits; - - if (!expr->ctype) - return 0; - - bits = expr->ctype->bit_size; - val = dmrC_show_expression(C, expr); - addr = show_symbol_expr(C, sym); - // FIXME! The "target" expression is for bitfield store information. - // Leave it NULL, which works fine. - show_store_gen(bits, val, NULL, addr); - return 0; -} - -static int show_access(struct dmr_C *C, struct expression *expr) -{ - int addr = show_address_gen(C, expr); - return show_load_gen(expr->ctype->bit_size, expr, addr); -} - -static int show_inc_dec(struct dmr_C *C, struct expression *expr, int postop) -{ - int addr = show_address_gen(C, expr->unop); - int retval, news; - const char *opname = expr->op == SPECIAL_INCREMENT ? "add" : "sub"; - int bits = expr->ctype->bit_size; - - retval = show_load_gen(bits, expr->unop, addr); - news = retval; - if (postop) - news = new_pseudo(); - printf("\t%s.%d\t\tv%d,v%d,$1\n", opname, bits, news, retval); - show_store_gen(bits, news, expr->unop, addr); - return retval; -} - -static int show_preop(struct dmr_C *C, struct expression *expr) -{ - /* - * '*' is an lvalue access, and is fundamentally different - * from an arithmetic operation. Maybe it should have an - * expression type of its own.. - */ - if (expr->op == '*') - return show_access(C, expr); - if (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT) - return show_inc_dec(C, expr, 0); - return show_regular_preop(C, expr); -} - -static int show_postop(struct dmr_C *C, struct expression *expr) -{ - return show_inc_dec(C, expr, 1); -} - -static int show_symbol_expr(struct dmr_C *C, struct symbol *sym) -{ - int news = new_pseudo(); - - if (sym->initializer && sym->initializer->type == EXPR_STRING) - return show_string_expr(C, sym->initializer); - - if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_EXTERN | MOD_STATIC)) { - printf("\tmovi.%d\t\tv%d,$%s\n", C->target->bits_in_pointer, news, dmrC_show_ident(C, sym->ident)); - return news; - } - if (sym->ctype.modifiers & MOD_ADDRESSABLE) { - printf("\taddi.%d\t\tv%d,vFP,$%lld\n", C->target->bits_in_pointer, news, sym->value); - return news; - } - printf("\taddi.%d\t\tv%d,vFP,$offsetof(%s:%p)\n", C->target->bits_in_pointer, news, dmrC_show_ident(C, sym->ident), sym); - return news; -} - -static int show_symbol_init(struct dmr_C *C, struct symbol *sym) -{ - struct expression *expr = sym->initializer; - - if (expr) { - int val, addr, bits; - - bits = expr->ctype->bit_size; - val = dmrC_show_expression(C, expr); - addr = show_symbol_expr(C, sym); - show_store_gen(bits, val, NULL, addr); - } - return 0; -} - -static int show_cast_expr(struct dmr_C *C, struct expression *expr) -{ - struct symbol *old_type, *new_type; - int op = dmrC_show_expression(C, expr->cast_expression); - int oldbits, newbits; - int news, is_signed; - - old_type = expr->cast_expression->ctype; - new_type = expr->cast_type; - - oldbits = old_type->bit_size; - newbits = new_type->bit_size; - if (oldbits >= newbits) - return op; - news = new_pseudo(); - is_signed = dmrC_is_signed_type(old_type); - if (is_signed) { - printf("\tsext%d.%d\tv%d,v%d\n", oldbits, newbits, news, op); - } else { - printf("\tandl.%d\t\tv%d,v%d,$%lu\n", newbits, news, op, (1UL << oldbits)-1); - } - return news; -} - -static int show_value(struct dmr_C *C, struct expression *expr) -{ - (void) C; - int news = new_pseudo(); - unsigned long long value = expr->value; - - printf("\tmovi.%d\t\tv%d,$%llu\n", expr->ctype->bit_size, news, value); - return news; -} - -static int show_fvalue(struct dmr_C *C, struct expression *expr) -{ - (void) C; - int news = new_pseudo(); - long double value = expr->fvalue; - - printf("\tmovf.%d\t\tv%d,$%Lf\n", expr->ctype->bit_size, news, value); - return news; -} - -static int show_string_expr(struct dmr_C *C, struct expression *expr) -{ - int news = new_pseudo(); - - printf("\tmovi.%d\t\tv%d,&%s\n", C->target->bits_in_pointer, news, dmrC_show_string(C, expr->string)); - return news; -} - -static int show_label_expr(struct dmr_C *C, struct expression *expr) -{ - int news = new_pseudo(); - printf("\tmovi.%d\t\tv%d,.L%p\n", C->target->bits_in_pointer, news, expr->label_symbol); - return news; -} - -static int show_conditional_expr(struct dmr_C *C, struct expression *expr) -{ - int cond = dmrC_show_expression(C, expr->conditional); - int truee = dmrC_show_expression(C, expr->cond_true); - int falsee = dmrC_show_expression(C, expr->cond_false); - int news = new_pseudo(); - - printf("[v%d]\tcmov.%d\t\tv%d,v%d,v%d\n", cond, expr->ctype->bit_size, news, truee, falsee); - return news; -} - -static int show_statement_expr(struct dmr_C *C, struct expression *expr) -{ - return dmrC_show_statement(C, expr->statement); -} - -static int show_position_expr(struct dmr_C *C, struct expression *expr, struct symbol *base) -{ - int news = dmrC_show_expression(C, expr->init_expr); - struct symbol *ctype = expr->init_expr->ctype; - int bit_offset; - - bit_offset = ctype ? ctype->bit_offset : -1; - - printf("\tinsert v%d at [%d:%d] of %s\n", news, - expr->init_offset, bit_offset, - dmrC_show_ident(C, base->ident)); - return 0; -} - -static int show_initializer_expr(struct dmr_C *C, struct expression *expr, struct symbol *ctype) -{ - struct expression *entry; - - FOR_EACH_PTR(expr->expr_list, entry) { - -again: - // Nested initializers have their positions already - // recursively calculated - just output them too - if (entry->type == EXPR_INITIALIZER) { - show_initializer_expr(C, entry, ctype); - continue; - } - - // Initializer indexes and identifiers should - // have been evaluated to EXPR_POS - if (entry->type == EXPR_IDENTIFIER) { - printf(" AT '%s':\n", dmrC_show_ident(C, entry->expr_ident)); - entry = entry->ident_expression; - goto again; - } - - if (entry->type == EXPR_INDEX) { - printf(" AT '%d..%d:\n", entry->idx_from, entry->idx_to); - entry = entry->idx_expression; - goto again; - } - if (entry->type == EXPR_POS) { - show_position_expr(C, entry, ctype); - continue; - } - show_initialization(C, ctype, entry); - } END_FOR_EACH_PTR(entry); - return 0; -} - -int dmrC_show_symbol_expr_init(struct dmr_C *C, struct symbol *sym) -{ - struct expression *expr = sym->initializer; - - if (expr) - dmrC_show_expression(C, expr); - return show_symbol_expr(C, sym); -} - -/* - * Print out an expression. Return the pseudo that contains the - * variable. - */ -int dmrC_show_expression(struct dmr_C *C, struct expression *expr) -{ - if (!expr) - return 0; - - if (!expr->ctype) { - struct position *pos = &expr->pos; - printf("\tno type at %s:%d:%d\n", - dmrC_stream_name(C, pos->stream), - pos->line, pos->pos); - return 0; - } - - switch (expr->type) { - case EXPR_CALL: - return show_call_expression(C, expr); - - case EXPR_ASSIGNMENT: - return show_assignment(C, expr); - - case EXPR_COMMA: - return show_comma(C, expr); - case EXPR_BINOP: - case EXPR_COMPARE: - case EXPR_LOGICAL: - return show_binop(C, expr); - case EXPR_PREOP: - return show_preop(C, expr); - case EXPR_POSTOP: - return show_postop(C, expr); - case EXPR_SYMBOL: - return show_symbol_expr(C, expr->symbol); - case EXPR_DEREF: - case EXPR_SIZEOF: - case EXPR_PTRSIZEOF: - case EXPR_ALIGNOF: - case EXPR_OFFSETOF: - dmrC_warning(C, expr->pos, "invalid expression after evaluation"); - return 0; - case EXPR_CAST: - case EXPR_FORCE_CAST: - case EXPR_IMPLIED_CAST: - return show_cast_expr(C, expr); - case EXPR_VALUE: - return show_value(C, expr); - case EXPR_FVALUE: - return show_fvalue(C, expr); - case EXPR_STRING: - return show_string_expr(C, expr); - case EXPR_INITIALIZER: - return show_initializer_expr(C, expr, expr->ctype); - case EXPR_SELECT: - case EXPR_CONDITIONAL: - return show_conditional_expr(C, expr); - case EXPR_STATEMENT: - return show_statement_expr(C, expr); - case EXPR_LABEL: - return show_label_expr(C, expr); - case EXPR_SLICE: - return show_slice(C, expr); - - // None of these should exist as direct expressions: they are only - // valid as sub-expressions of initializers. - case EXPR_POS: - dmrC_warning(C, expr->pos, "unable to show plain initializer position expression"); - return 0; - case EXPR_IDENTIFIER: - dmrC_warning(C, expr->pos, "unable to show identifier expression"); - return 0; - case EXPR_INDEX: - dmrC_warning(C, expr->pos, "unable to show index expression"); - return 0; - case EXPR_TYPE: - dmrC_warning(C, expr->pos, "unable to show type expression"); - return 0; - } - return 0; -} diff --git a/dmr_c/src/simplify.c b/dmr_c/src/simplify.c deleted file mode 100644 index 515717b..0000000 --- a/dmr_c/src/simplify.c +++ /dev/null @@ -1,1170 +0,0 @@ -/* - * Simplify - do instruction simplification before CSE - * - * Copyright (C) 2004 Linus Torvalds - */ - -#include - -#include -#include -#include -#include -#include -#include - -/* Find the trivial parent for a phi-source */ -static struct basic_block *phi_parent(struct dmr_C *C, struct basic_block *source, pseudo_t pseudo) -{ - /* Can't go upwards if the pseudo is defined in the bb it came from.. */ - if (pseudo->type == PSEUDO_REG) { - struct instruction *def = pseudo->def; - if (def->bb == source) - return source; - } - if (dmrC_bb_list_size(source->children) != 1 || dmrC_bb_list_size(source->parents) != 1) - return source; - return dmrC_first_basic_block(source->parents); -} - -/* - * Copy the phi-node's phisrcs into to given array. - * Returns 0 if the the list contained the expected - * number of element, a positive number if there was - * more than expected and a negative one if less. - * - * Note: we can't reuse a function like linearize_ptr_list() - * because any VOIDs in the phi-list must be ignored here - * as in this context they mean 'entry has been removed'. - */ -static int get_phisources(struct dmr_C *C, struct instruction *sources[], int nbr, struct instruction *insn) -{ - pseudo_t phi; - int i = 0; - - assert(insn->opcode == OP_PHI); - FOR_EACH_PTR(insn->phi_list, phi) { - struct instruction *def; - if (phi == VOID_PSEUDO(C)) - continue; - if (i >= nbr) - return 1; - def = phi->def; - assert(def->opcode == OP_PHISOURCE); - sources[i++] = def; - } END_FOR_EACH_PTR(phi); - return i - nbr; -} - -static int if_convert_phi(struct dmr_C *C, struct instruction *insn) -{ - struct instruction *array[2]; - struct basic_block *parents[3]; - struct basic_block *bb, *bb1, *bb2, *source; - struct instruction *br; - pseudo_t p1, p2; - - bb = insn->bb; - if (get_phisources(C, array, 2, insn)) - return 0; - if (ptrlist_linearize((struct ptr_list *)bb->parents, (void **)parents, 3) != 2) - return 0; - p1 = array[0]->src1; - bb1 = array[0]->bb; - p2 = array[1]->src1; - bb2 = array[1]->bb; - - /* Only try the simple "direct parents" case */ - if ((bb1 != parents[0] || bb2 != parents[1]) && - (bb1 != parents[1] || bb2 != parents[0])) - return 0; - - /* - * See if we can find a common source for this.. - */ - source = phi_parent(C, bb1, p1); - if (source != phi_parent(C, bb2, p2)) - return 0; - - /* - * Cool. We now know that 'source' is the exclusive - * parent of both phi-nodes, so the exit at the - * end of it fully determines which one it is, and - * we can turn it into a select. - * - * HOWEVER, right now we only handle regular - * conditional branches. No multijumps or computed - * stuff. Verify that here. - */ - br = dmrC_last_instruction(source->insns); - if (!br || br->opcode != OP_CBR) - return 0; - - assert(br->cond); - assert(br->bb_false); - - /* - * We're in business. Match up true/false with p1/p2. - */ - if (br->bb_true == bb2 || br->bb_false == bb1) { - pseudo_t p = p1; - p1 = p2; - p2 = p; - } - - /* - * OK, we can now replace that last - * - * br cond, a, b - * - * with the sequence - * - * setcc cond - * select pseudo, p1, p2 - * br cond, a, b - * - * and remove the phi-node. If it then - * turns out that 'a' or 'b' is entirely - * empty (common case), and now no longer - * a phi-source, we'll be able to simplify - * the conditional branch too. - */ - dmrC_insert_select(C, source, br, insn, p1, p2); - dmrC_kill_instruction(C, insn); - return REPEAT_CSE; -} - -static int clean_up_phi(struct dmr_C *C, struct instruction *insn) -{ - pseudo_t phi; - struct instruction *last; - int same; - - last = NULL; - same = 1; - FOR_EACH_PTR(insn->phi_list, phi) { - struct instruction *def; - if (phi == VOID_PSEUDO(C)) - continue; - def = phi->def; - if (def->src1 == VOID_PSEUDO(C) || !def->bb) - continue; - if (last) { - if (last->src1 != def->src1) - same = 0; - continue; - } - last = def; - } END_FOR_EACH_PTR(phi); - - if (same) { - pseudo_t pseudo = last ? last->src1 : VOID_PSEUDO(C); - dmrC_convert_instruction_target(C, insn, pseudo); - dmrC_kill_instruction(C, insn); - return REPEAT_CSE; - } - - return if_convert_phi(C, insn); -} - -static int delete_pseudo_user_list_entry(struct dmr_C *C, struct pseudo_user_list **list, pseudo_t *entry, int count) -{ - struct pseudo_user *pu; - - FOR_EACH_PTR(*list, pu) { - if (pu->userp == entry) { - MARK_CURRENT_DELETED(struct pseudo_user *, pu); - if (!--count) - goto out; - } - } END_FOR_EACH_PTR(pu); - assert(count <= 0); -out: - if (ptrlist_size((struct ptr_list *)*list) == 0) - *list = NULL; - return count; -} - -static inline void remove_usage(struct dmr_C *C, pseudo_t p, pseudo_t *usep) -{ - if (dmrC_has_use_list(p)) { - delete_pseudo_user_list_entry(C, &p->users, usep, 1); - if (!p->users) - dmrC_kill_instruction(C, p->def); - } -} - -// From Luc: sssa-mini -/* - * Like kill_use() but do not recursively kill instructions - * that become without users. - */ -void dmrC_remove_use(struct dmr_C *C, pseudo_t *usep) -{ - pseudo_t p = *usep; - *usep = VOID_PSEUDO(C); - if (dmrC_has_use_list(p)) { - delete_pseudo_user_list_entry(C, &p->users, usep, 1); - } -} - -static void kill_use_list(struct dmr_C *C, struct pseudo_list *list) -{ - pseudo_t p; - FOR_EACH_PTR(list, p) { - if (p == VOID_PSEUDO(C)) - continue; - dmrC_kill_use(C, THIS_ADDRESS(pseudo_t, p)); - } END_FOR_EACH_PTR(p); -} - -/* - * Kill trivially dead instructions - */ -static int dead_insn(struct dmr_C *C, struct instruction *insn, pseudo_t *src1, pseudo_t *src2, pseudo_t *src3) -{ - struct pseudo_user *pu; - FOR_EACH_PTR(insn->target->users, pu) { - if (*pu->userp != VOID_PSEUDO(C)) - return 0; - } END_FOR_EACH_PTR(pu); - - insn->bb = NULL; - dmrC_kill_use(C, src1); - dmrC_kill_use(C, src2); - dmrC_kill_use(C, src3); - return REPEAT_CSE; -} - -static inline int constant(pseudo_t pseudo) -{ - return pseudo->type == PSEUDO_VAL; -} - -static int replace_with_pseudo(struct dmr_C *C, struct instruction *insn, pseudo_t pseudo) -{ - dmrC_convert_instruction_target(C, insn, pseudo); - - switch (insn->opcode) { - case OP_SEL: - case OP_RANGE: - dmrC_kill_use(C, &insn->src3); - case OP_ADD: - case OP_SUB: - case OP_MULU: - case OP_MULS: - case OP_DIVU: - case OP_DIVS: - case OP_MODU: - case OP_MODS: - case OP_SHL: - case OP_LSR: - case OP_ASR: - - /* Logical */ - case OP_AND: - case OP_OR: - case OP_XOR: - case OP_AND_BOOL: - case OP_OR_BOOL: - - case OP_SET_EQ: - case OP_SET_NE: - case OP_SET_LE: - case OP_SET_GE: - case OP_SET_LT: - case OP_SET_GT: - case OP_SET_B: - case OP_SET_A: - case OP_SET_BE: - case OP_SET_AE: - dmrC_kill_use(C, &insn->src2); - case OP_NOT: - case OP_NEG: - case OP_SYMADDR: - case OP_CAST: - case OP_SCAST: - case OP_FPCAST: - case OP_PTRCAST: - dmrC_kill_use(C, &insn->src1); - break; - - default: - assert(0); - } - insn->bb = NULL; - return REPEAT_CSE; -} - -/* - * Try to determine the maximum size of bits in a pseudo. - * - * Right now this only follow casts and constant values, but we - * could look at things like logical 'and' instructions etc. - */ -static unsigned int operand_size(struct instruction *insn, pseudo_t pseudo) -{ - unsigned int size = insn->size; - - if (pseudo->type == PSEUDO_REG) { - struct instruction *src = pseudo->def; - if (src && src->opcode == OP_CAST && src->orig_type) { - unsigned int orig_size = src->orig_type->bit_size; - if (orig_size < size) - size = orig_size; - } - } - if (pseudo->type == PSEUDO_VAL) { - unsigned int orig_size = dmrC_value_size(pseudo->value); - //unsigned int orig_size = pseudo->size; - if (orig_size < size) - size = orig_size; - } - return size; -} - -static int simplify_asr(struct dmr_C *C, struct instruction *insn, pseudo_t pseudo, long long value) -{ - unsigned int size = operand_size(insn, pseudo); - - if (value >= size) { - dmrC_warning(C, insn->pos, "right shift by bigger than source value"); - return replace_with_pseudo(C, insn, dmrC_value_pseudo(C, insn->type, 0)); - } - if (!value) - return replace_with_pseudo(C, insn, pseudo); - return 0; -} - -static int simplify_mul_div(struct dmr_C *C, struct instruction *insn, long long value) -{ - unsigned long long sbit = 1ULL << (insn->size - 1); - unsigned long long bits = sbit | (sbit - 1); - - if (value == 1) - return replace_with_pseudo(C, insn, insn->src1); - - switch (insn->opcode) { - case OP_MULS: - case OP_MULU: - if (value == 0) - return replace_with_pseudo(C, insn, insn->src2); - /* Fall through */ - case OP_DIVS: - if (!(value & sbit)) // positive - break; - - value |= ~bits; - if (value == -1) { - insn->opcode = OP_NEG; - return REPEAT_CSE; - } - } - - return 0; -} - -static int compare_opcode(struct dmr_C *C, int opcode, int inverse) -{ - if (!inverse) - return opcode; - - switch (opcode) { - case OP_SET_EQ: return OP_SET_NE; - case OP_SET_NE: return OP_SET_EQ; - - case OP_SET_LT: return OP_SET_GE; - case OP_SET_LE: return OP_SET_GT; - case OP_SET_GT: return OP_SET_LE; - case OP_SET_GE: return OP_SET_LT; - - case OP_SET_A: return OP_SET_BE; - case OP_SET_AE: return OP_SET_B; - case OP_SET_B: return OP_SET_AE; - case OP_SET_BE: return OP_SET_A; - - default: - return opcode; - } -} - -static int simplify_seteq_setne(struct dmr_C *C, struct instruction *insn, long long value) -{ - pseudo_t old = insn->src1; - struct instruction *def = old->def; - pseudo_t src1, src2; - int inverse; - int opcode; - - if (value != 0 && value != 1) - return 0; - - if (!def) - return 0; - - inverse = (insn->opcode == OP_SET_NE) == value; - opcode = def->opcode; - switch (opcode) { - case OP_SET_EQ: - case OP_SET_NE: - case OP_SET_LE: - case OP_SET_GE: - case OP_SET_LT: - case OP_SET_GT: - case OP_SET_B: - case OP_SET_A: - case OP_SET_BE: - case OP_SET_AE: - // Convert: - // setcc.n %t <- %a, %b - // setne.m %r <- %t, $0 - // into: - // setcc.n %t <- %a, %b - // setcc.m %r <- %a, $b - // and similar for setne/eq ... 0/1 - src1 = def->src1; - src2 = def->src2; - insn->opcode = compare_opcode(C, opcode, inverse); - dmrC_use_pseudo(C, insn, src1, &insn->src1); - dmrC_use_pseudo(C, insn, src2, &insn->src2); - remove_usage(C, old, &insn->src1); - return REPEAT_CSE; - - default: - return 0; - } -} - -static int simplify_constant_rightside(struct dmr_C *C, struct instruction *insn) -{ - long long value = insn->src2->value; - - switch (insn->opcode) { - case OP_OR_BOOL: - if (value == 1) - return replace_with_pseudo(C, insn, insn->src2); - goto case_neutral_zero; - - case OP_SUB: - if (value) { - insn->opcode = OP_ADD; - insn->src2 = dmrC_value_pseudo(C, insn->type, -value); - return REPEAT_CSE; - } - /* Fall through */ - case OP_ADD: - case OP_OR: case OP_XOR: - case OP_SHL: - case OP_LSR: - case_neutral_zero: - if (!value) - return replace_with_pseudo(C, insn, insn->src1); - return 0; - case OP_ASR: - return simplify_asr(C, insn, insn->src1, value); - - case OP_MODU: case OP_MODS: - if (value == 1) - return replace_with_pseudo(C, insn, dmrC_value_pseudo(C, insn->type, 0)); - return 0; - - case OP_DIVU: case OP_DIVS: - case OP_MULU: case OP_MULS: - return simplify_mul_div(C, insn, value); - - case OP_AND_BOOL: - if (value == 1) - return replace_with_pseudo(C, insn, insn->src1); - /* Fall through */ - case OP_AND: - if (!value) - return replace_with_pseudo(C, insn, insn->src2); - return 0; - - case OP_SET_NE: - case OP_SET_EQ: - return simplify_seteq_setne(C, insn, value); - } - return 0; -} - -static int simplify_constant_leftside(struct dmr_C *C, struct instruction *insn) -{ - long long value = insn->src1->value; - - switch (insn->opcode) { - case OP_ADD: case OP_OR: case OP_XOR: - if (!value) - return replace_with_pseudo(C, insn, insn->src2); - return 0; - - case OP_SHL: - case OP_LSR: case OP_ASR: - case OP_AND: - case OP_MULU: case OP_MULS: - if (!value) - return replace_with_pseudo(C, insn, insn->src1); - return 0; - } - return 0; -} - -static int simplify_constant_binop(struct dmr_C *C, struct instruction *insn) -{ - /* FIXME! Verify signs and sizes!! */ - long long left = insn->src1->value; - long long right = insn->src2->value; - unsigned long long ul, ur; - long long res, mask, bits; - - mask = 1ULL << (insn->size-1); - bits = mask | (mask-1); - - if (left & mask) - left |= ~bits; - if (right & mask) - right |= ~bits; - ul = left & bits; - ur = right & bits; - - switch (insn->opcode) { - case OP_ADD: - res = left + right; - break; - case OP_SUB: - res = left - right; - break; - case OP_MULU: - res = ul * ur; - break; - case OP_MULS: - res = left * right; - break; - case OP_DIVU: - if (!ur) - return 0; - res = ul / ur; - break; - case OP_DIVS: - if (!right) - return 0; - if (left == mask && right == -1) - return 0; - res = left / right; - break; - case OP_MODU: - if (!ur) - return 0; - res = ul % ur; - break; - case OP_MODS: - if (!right) - return 0; - if (left == mask && right == -1) - return 0; - res = left % right; - break; - case OP_SHL: - res = left << right; - break; - case OP_LSR: - res = ul >> ur; - break; - case OP_ASR: - res = left >> right; - break; - /* Logical */ - case OP_AND: - res = left & right; - break; - case OP_OR: - res = left | right; - break; - case OP_XOR: - res = left ^ right; - break; - case OP_AND_BOOL: - res = left && right; - break; - case OP_OR_BOOL: - res = left || right; - break; - - /* Binary comparison */ - case OP_SET_EQ: - res = left == right; - break; - case OP_SET_NE: - res = left != right; - break; - case OP_SET_LE: - res = left <= right; - break; - case OP_SET_GE: - res = left >= right; - break; - case OP_SET_LT: - res = left < right; - break; - case OP_SET_GT: - res = left > right; - break; - case OP_SET_B: - res = ul < ur; - break; - case OP_SET_A: - res = ul > ur; - break; - case OP_SET_BE: - res = ul <= ur; - break; - case OP_SET_AE: - res = ul >= ur; - break; - default: - return 0; - } - res &= bits; - - replace_with_pseudo(C, insn, dmrC_value_pseudo(C, insn->type, res)); - return REPEAT_CSE; -} - -static int simplify_binop_same_args(struct dmr_C *C, struct instruction *insn, pseudo_t arg) -{ - switch (insn->opcode) { - case OP_SET_NE: - case OP_SET_LT: case OP_SET_GT: - case OP_SET_B: case OP_SET_A: - if (C->Wtautological_compare) - dmrC_warning(C, insn->pos, "self-comparison always evaluates to false"); - case OP_SUB: - case OP_XOR: - return replace_with_pseudo(C, insn, dmrC_value_pseudo(C, insn->type, 0)); - - case OP_SET_EQ: - case OP_SET_LE: case OP_SET_GE: - case OP_SET_BE: case OP_SET_AE: - if (C->Wtautological_compare) - dmrC_warning(C, insn->pos, "self-comparison always evaluates to true"); - return replace_with_pseudo(C, insn, dmrC_value_pseudo(C, insn->type, 1)); - - case OP_AND: - case OP_OR: - return replace_with_pseudo(C, insn, arg); - - case OP_AND_BOOL: - case OP_OR_BOOL: - remove_usage(C, arg, &insn->src2); - insn->src2 = dmrC_value_pseudo(C, insn->type, 0); - insn->opcode = OP_SET_NE; - return REPEAT_CSE; - - default: - break; - } - - return 0; -} - -static int simplify_binop(struct dmr_C *C, struct instruction *insn) -{ - if (dead_insn(C, insn, &insn->src1, &insn->src2, NULL)) - return REPEAT_CSE; - if (constant(insn->src1)) { - if (constant(insn->src2)) - return simplify_constant_binop(C, insn); - return simplify_constant_leftside(C, insn); - } - if (constant(insn->src2)) - return simplify_constant_rightside(C, insn); - if (insn->src1 == insn->src2) - return simplify_binop_same_args(C, insn, insn->src1); - return 0; -} - -static void switch_pseudo(struct dmr_C *C, struct instruction *insn1, pseudo_t *pp1, struct instruction *insn2, pseudo_t *pp2) -{ - pseudo_t p1 = *pp1, p2 = *pp2; - - dmrC_use_pseudo(C, insn1, p2, pp1); - dmrC_use_pseudo(C, insn2, p1, pp2); - remove_usage(C, p1, pp1); - remove_usage(C, p2, pp2); -} - -static int canonical_order(pseudo_t p1, pseudo_t p2) -{ - /* symbol/constants on the right */ - if (p1->type == PSEUDO_VAL) - return p2->type == PSEUDO_VAL; - - if (p1->type == PSEUDO_SYM) - return p2->type == PSEUDO_SYM || p2->type == PSEUDO_VAL; - - return 1; -} - -static int simplify_commutative_binop(struct dmr_C *C, struct instruction *insn) -{ - if (!canonical_order(insn->src1, insn->src2)) { - switch_pseudo(C, insn, &insn->src1, insn, &insn->src2); - return REPEAT_CSE; - } - return 0; -} - -static inline int simple_pseudo(pseudo_t pseudo) -{ - return pseudo->type == PSEUDO_VAL || pseudo->type == PSEUDO_SYM; -} - -static int simplify_associative_binop(struct dmr_C *C, struct instruction *insn) -{ - struct instruction *def; - pseudo_t pseudo = insn->src1; - - if (!simple_pseudo(insn->src2)) - return 0; - if (pseudo->type != PSEUDO_REG) - return 0; - def = pseudo->def; - if (def == insn) - return 0; - if (def->opcode != insn->opcode) - return 0; - if (!simple_pseudo(def->src2)) - return 0; - if (ptrlist_size((struct ptr_list *)def->target->users) != 1) - return 0; - switch_pseudo(C, def, &def->src1, insn, &insn->src2); - return REPEAT_CSE; -} - -static int simplify_constant_unop(struct dmr_C *C, struct instruction *insn) -{ - long long val = insn->src1->value; - long long res, mask; - - switch (insn->opcode) { - case OP_NOT: - res = ~val; - break; - case OP_NEG: - res = -val; - break; - default: - return 0; - } - mask = 1ULL << (insn->size-1); - res &= mask | (mask-1); - - replace_with_pseudo(C, insn, dmrC_value_pseudo(C, insn->type, res)); - return REPEAT_CSE; -} - -static int simplify_unop(struct dmr_C *C, struct instruction *insn) -{ - if (dead_insn(C, insn, &insn->src1, NULL, NULL)) - return REPEAT_CSE; - if (constant(insn->src1)) - return simplify_constant_unop(C, insn); - - switch (insn->opcode) { - struct instruction *def; - - case OP_NOT: - def = insn->src->def; - if (def && def->opcode == OP_NOT) - return replace_with_pseudo(C, insn, def->src); - break; - case OP_NEG: - def = insn->src->def; - if (def && def->opcode == OP_NEG) - return replace_with_pseudo(C, insn, def->src); - break; - default: - return 0; - } - return 0; -} - -static int simplify_one_memop(struct dmr_C *C, struct instruction *insn, pseudo_t orig) -{ - pseudo_t addr = insn->src; - pseudo_t new, off; - - if (addr->type == PSEUDO_REG) { - struct instruction *def = addr->def; - if (def->opcode == OP_SYMADDR && def->src) { - dmrC_kill_use(C, &insn->src); - dmrC_use_pseudo(C, insn, def->src, &insn->src); - return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP; - } - if (def->opcode == OP_ADD) { - new = def->src1; - off = def->src2; - if (constant(off)) - goto offset; - new = off; - off = def->src1; - if (constant(off)) - goto offset; - return 0; - } - } - return 0; - -offset: - /* Invalid code */ - if (new == orig) { - if (new == VOID_PSEUDO(C)) - return 0; - /* - * If some BB have been removed it is possible that this - * memop is in fact part of a dead BB. In this case - * we must not warn since nothing is wrong. - * If not part of a dead BB this will be redone after - * the BBs have been cleaned up. - */ - if (C->L->repeat_phase & REPEAT_CFG_CLEANUP) - return 0; - new = VOID_PSEUDO(C); - dmrC_warning(C, insn->pos, "crazy programmer"); - } - insn->offset += (int) off->value; - dmrC_use_pseudo(C, insn, new, &insn->src); - remove_usage(C, addr, &insn->src); - return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP; -} - -/* - * We walk the whole chain of adds/subs backwards. That's not - * only more efficient, but it allows us to find loops. - */ -static int simplify_memop(struct dmr_C *C, struct instruction *insn) -{ - int one, ret = 0; - pseudo_t orig = insn->src; - - do { - one = simplify_one_memop(C, insn, orig); - ret |= one; - } while (one); - return ret; -} - -static long long get_cast_value(long long val, int old_size, int new_size, int sign) -{ - long long mask; - - if (sign && new_size > old_size) { - mask = 1 << (old_size-1); - if (val & mask) - val |= ~(mask | (mask-1)); - } - mask = 1 << (new_size-1); - return val & (mask | (mask-1)); -} - -static int simplify_cast(struct dmr_C *C, struct instruction *insn) -{ - struct symbol *orig_type; - int orig_size, size; - pseudo_t src; - - if (dead_insn(C, insn, &insn->src, NULL, NULL)) - return REPEAT_CSE; - - orig_type = insn->orig_type; - if (!orig_type) - return 0; - - /* Keep casts with pointer on either side (not only case of OP_PTRCAST) */ - if (dmrC_is_ptr_type(orig_type) || dmrC_is_ptr_type(insn->type)) - return 0; - - orig_size = orig_type->bit_size; - size = insn->size; - src = insn->src; - - /* A cast of a constant? */ - if (constant(src)) { - int sign = orig_type->ctype.modifiers & MOD_SIGNED; - long long val = get_cast_value(src->value, orig_size, size, sign); - src = dmrC_value_pseudo(C, insn->type, val); - goto simplify; - } - - /* A cast of a "and" might be a no-op.. */ - if (src->type == PSEUDO_REG) { - struct instruction *def = src->def; - if (def->opcode == OP_AND && def->size >= size) { - pseudo_t val = def->src2; - if (val->type == PSEUDO_VAL) { - unsigned long long value = val->value; - if (!(value >> (size-1))) - goto simplify; - } - } - } - - if (size == orig_size) { - int op = (orig_type->ctype.modifiers & MOD_SIGNED) ? OP_SCAST : OP_CAST; - if (insn->opcode == op) - goto simplify; - if (insn->opcode == OP_FPCAST && dmrC_is_float_type(C->S, orig_type)) - goto simplify; - } - - return 0; - -simplify: - return replace_with_pseudo(C, insn, src); -} - -static int simplify_select(struct dmr_C *C, struct instruction *insn) -{ - pseudo_t cond, src1, src2; - - if (dead_insn(C, insn, &insn->src1, &insn->src2, &insn->src3)) - return REPEAT_CSE; - - cond = insn->src1; - src1 = insn->src2; - src2 = insn->src3; - if (constant(cond) || src1 == src2) { - pseudo_t *kill, take; - dmrC_kill_use(C, &insn->src1); - take = cond->value ? src1 : src2; - kill = cond->value ? &insn->src3 : &insn->src2; - dmrC_kill_use(C, kill); - replace_with_pseudo(C, insn, take); - return REPEAT_CSE; - } - if (constant(src1) && constant(src2)) { - long long val1 = src1->value; - long long val2 = src2->value; - - /* The pair 0/1 is special - replace with SETNE/SETEQ */ - if ((val1 | val2) == 1) { - int opcode = OP_SET_EQ; - if (val1) { - src1 = src2; - opcode = OP_SET_NE; - } - insn->opcode = opcode; - /* insn->src1 is already cond */ - insn->src2 = src1; /* Zero */ - return REPEAT_CSE; - } - } - return 0; -} - -static int is_in_range(pseudo_t src, long long low, long long high) -{ - long long value; - - switch (src->type) { - case PSEUDO_VAL: - value = src->value; - return value >= low && value <= high; - default: - return 0; - } -} - -static int simplify_range(struct dmr_C *C, struct instruction *insn) -{ - pseudo_t src1, src2, src3; - - src1 = insn->src1; - src2 = insn->src2; - src3 = insn->src3; - if (src2->type != PSEUDO_VAL || src3->type != PSEUDO_VAL) - return 0; - if (is_in_range(src1, src2->value, src3->value)) { - dmrC_kill_instruction(C, insn); - return REPEAT_CSE; - } - return 0; -} - -/* - * Simplify "set_ne/eq $0 + br" - */ -static int simplify_cond_branch(struct dmr_C *C, struct instruction *br, pseudo_t cond, struct instruction *def, pseudo_t *pp) -{ - dmrC_use_pseudo(C, br, *pp, &br->cond); - remove_usage(C, cond, &br->cond); - if (def->opcode == OP_SET_EQ) { - struct basic_block *true = br->bb_true; - struct basic_block *false = br->bb_false; - br->bb_false = true; - br->bb_true = false; - } - return REPEAT_CSE; -} - -static int simplify_branch(struct dmr_C *C, struct instruction *insn) -{ - pseudo_t cond = insn->cond; - - /* Constant conditional */ - if (constant(cond)) { - dmrC_insert_branch(C, insn->bb, insn, cond->value ? insn->bb_true : insn->bb_false); - return REPEAT_CSE; - } - - /* Same target? */ - if (insn->bb_true == insn->bb_false) { - struct basic_block *bb = insn->bb; - struct basic_block *target = insn->bb_false; - dmrC_remove_bb_from_list(&target->parents, bb, 1); - dmrC_remove_bb_from_list(&bb->children, target, 1); - insn->bb_false = NULL; - dmrC_kill_use(C, &insn->cond); - insn->cond = NULL; - insn->opcode = OP_BR; - return REPEAT_CSE; - } - - /* Conditional on a SETNE $0 or SETEQ $0 */ - if (cond->type == PSEUDO_REG) { - struct instruction *def = cond->def; - - if (def->opcode == OP_SET_NE || def->opcode == OP_SET_EQ) { - if (constant(def->src1) && !def->src1->value) - return simplify_cond_branch(C, insn, cond, def, &def->src2); - if (constant(def->src2) && !def->src2->value) - return simplify_cond_branch(C, insn, cond, def, &def->src1); - } - if (def->opcode == OP_SEL) { - if (constant(def->src2) && constant(def->src3)) { - long long val1 = def->src2->value; - long long val2 = def->src3->value; - if (!val1 && !val2) { - dmrC_insert_branch(C, insn->bb, insn, insn->bb_false); - return REPEAT_CSE; - } - if (val1 && val2) { - dmrC_insert_branch(C, insn->bb, insn, insn->bb_true); - return REPEAT_CSE; - } - if (val2) { - struct basic_block *true = insn->bb_true; - struct basic_block *false = insn->bb_false; - insn->bb_false = true; - insn->bb_true = false; - } - dmrC_use_pseudo(C, insn, def->src1, &insn->cond); - remove_usage(C, cond, &insn->cond); - return REPEAT_CSE; - } - } - if (def->opcode == OP_CAST || def->opcode == OP_SCAST) { - int orig_size = def->orig_type ? def->orig_type->bit_size : 0; - if (def->size > orig_size) { - dmrC_use_pseudo(C, insn, def->src, &insn->cond); - remove_usage(C, cond, &insn->cond); - return REPEAT_CSE; - } - } - } - return 0; -} - -static int simplify_switch(struct dmr_C *C, struct instruction *insn) -{ - pseudo_t cond = insn->cond; - long long val; - struct multijmp *jmp; - - if (!constant(cond)) - return 0; - val = insn->cond->value; - - FOR_EACH_PTR(insn->multijmp_list, jmp) { - /* Default case */ - if (jmp->begin > jmp->end) - goto found; - if (val >= jmp->begin && val <= jmp->end) - goto found; - } END_FOR_EACH_PTR(jmp); - dmrC_warning(C, insn->pos, "Impossible case statement"); - return 0; - -found: - dmrC_insert_branch(C, insn->bb, insn, jmp->target); - return REPEAT_CSE; -} - -int dmrC_simplify_instruction(struct dmr_C *C, struct instruction *insn) -{ - // This is a workaround for bugs in how floats are handled - if (!insn->bb || (insn->type && dmrC_is_float_type(C->S, insn->type))) - return 0; - switch (insn->opcode) { - case OP_ADD: case OP_MULS: - case OP_AND: case OP_OR: case OP_XOR: - case OP_AND_BOOL: case OP_OR_BOOL: - if (simplify_binop(C, insn)) - return REPEAT_CSE; - if (simplify_commutative_binop(C, insn)) - return REPEAT_CSE; - return simplify_associative_binop(C, insn); - - case OP_MULU: - case OP_SET_EQ: case OP_SET_NE: - if (simplify_binop(C, insn)) - return REPEAT_CSE; - return simplify_commutative_binop(C, insn); - - case OP_SUB: - case OP_DIVU: case OP_DIVS: - case OP_MODU: case OP_MODS: - case OP_SHL: - case OP_LSR: case OP_ASR: - case OP_SET_LE: case OP_SET_GE: - case OP_SET_LT: case OP_SET_GT: - case OP_SET_B: case OP_SET_A: - case OP_SET_BE: case OP_SET_AE: - return simplify_binop(C, insn); - - case OP_NOT: case OP_NEG: - return simplify_unop(C, insn); - case OP_LOAD: case OP_STORE: - return simplify_memop(C, insn); - case OP_SYMADDR: - if (dead_insn(C, insn, NULL, NULL, NULL)) - return REPEAT_CSE | REPEAT_SYMBOL_CLEANUP; - // return replace_with_pseudo(C, insn, insn->symbol); - // Keep SYMADDR (see patch from Luc) - return 0; - case OP_CAST: - case OP_SCAST: - case OP_FPCAST: - case OP_PTRCAST: - return simplify_cast(C, insn); - case OP_PHI: - if (dead_insn(C, insn, NULL, NULL, NULL)) { - kill_use_list(C, insn->phi_list); - return REPEAT_CSE; - } - return clean_up_phi(C, insn); - case OP_PHISOURCE: - if (dead_insn(C, insn, &insn->phi_src, NULL, NULL)) - return REPEAT_CSE; - break; - case OP_SEL: - return simplify_select(C, insn); - case OP_CBR: - return simplify_branch(C, insn); - case OP_SWITCH: - return simplify_switch(C, insn); - case OP_RANGE: - return simplify_range(C, insn); - } - return 0; -} diff --git a/dmr_c/src/symbol.c b/dmr_c/src/symbol.c deleted file mode 100644 index 9ea11c3..0000000 --- a/dmr_c/src/symbol.c +++ /dev/null @@ -1,827 +0,0 @@ -/* - * Symbol lookup and handling. - * - * Copyright (C) 2003 Transmeta Corp. - * 2003-2004 Linus Torvalds - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - /* - * This version is part of the dmr_c project. - * Copyright (C) 2017 Dibyendu Majumdar - */ - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -/* - * If the symbol is an inline symbol, add it to the list of symbols to parse - */ -void dmrC_access_symbol(struct global_symbols_t *S, struct symbol *sym) -{ - if (sym->ctype.modifiers & MOD_INLINE) { - if (!(sym->ctype.modifiers & MOD_ACCESSED)) { - dmrC_add_symbol(S->C, &S->translation_unit_used_list, sym); - sym->ctype.modifiers |= MOD_ACCESSED; - } - } -} - -struct symbol *dmrC_lookup_symbol(struct ident *ident, enum namespace_type ns) -{ - struct symbol *sym; - - for (sym = ident->symbols; sym; sym = sym->next_id) { - if (sym->ns & ns) { - sym->used = 1; - return sym; - } - } - return NULL; -} - -struct context *dmrC_alloc_context(struct global_symbols_t *S) -{ - return (struct context *)dmrC_allocator_allocate(&S->context_allocator, 0); -} - -struct symbol *dmrC_alloc_symbol(struct global_symbols_t *S, struct position pos, int type) -{ - struct symbol *sym = (struct symbol *) dmrC_allocator_allocate(&S->symbol_allocator, 0); - sym->type = type; - sym->pos = pos; - sym->endpos.type = 0; - return sym; -} - -struct struct_union_info { - unsigned long max_align; - unsigned long bit_size; - int align_size; -}; - -/* - * Unions are fairly easy to lay out ;) - */ -static void lay_out_union(struct global_symbols_t *S, struct symbol *sym, struct struct_union_info *info) -{ - dmrC_examine_symbol_type(S, sym); - - // Unnamed bitfields do not affect alignment. - if (sym->ident || !dmrC_is_bitfield_type(sym)) { - if (sym->ctype.alignment > info->max_align) - info->max_align = sym->ctype.alignment; - } - - if (sym->bit_size > (int) info->bit_size) - info->bit_size = sym->bit_size; - - sym->offset = 0; -} - -static int bitfield_base_size(struct symbol *sym) -{ - if (sym->type == SYM_NODE) - sym = sym->ctype.base_type; - if (sym->type == SYM_BITFIELD) - sym = sym->ctype.base_type; - return sym->bit_size; -} - -/* - * Structures are a bit more interesting to lay out - */ -static void lay_out_struct(struct global_symbols_t *S, struct symbol *sym, struct struct_union_info *info) -{ - unsigned long bit_size, align_bit_mask; - int base_size; - - dmrC_examine_symbol_type(S, sym); - - // Unnamed bitfields do not affect alignment. - if (sym->ident || !dmrC_is_bitfield_type(sym)) { - if (sym->ctype.alignment > info->max_align) - info->max_align = sym->ctype.alignment; - } - - bit_size = info->bit_size; - base_size = sym->bit_size; - - /* - * Unsized arrays cause us to not align the resulting - * structure size - */ - if (base_size < 0) { - info->align_size = 0; - base_size = 0; - } - - align_bit_mask = dmrC_bytes_to_bits(S->C->target, sym->ctype.alignment) - 1; - - /* - * Bitfields have some very special rules.. - */ - if (dmrC_is_bitfield_type (sym)) { - unsigned long bit_offset = bit_size & align_bit_mask; - int room = bitfield_base_size(sym) - bit_offset; - // Zero-width fields just fill up the unit. - int width = base_size ? base_size : (bit_offset ? room : 0); - - if (width > room) { - bit_size = (bit_size + align_bit_mask) & ~align_bit_mask; - bit_offset = 0; - } - sym->offset = dmrC_bits_to_bytes(S->C->target, bit_size - bit_offset); - sym->bit_offset = bit_offset; - sym->ctype.base_type->bit_offset = bit_offset; - info->bit_size = bit_size + width; - // dmrC_warning (sym->pos, "bitfield: offset=%d:%d size=:%d", sym->offset, sym->bit_offset, width); - - return; - } - - /* - * Otherwise, just align it right and add it up.. - */ - bit_size = (bit_size + align_bit_mask) & ~align_bit_mask; - sym->offset = dmrC_bits_to_bytes(S->C->target, bit_size); - - info->bit_size = bit_size + base_size; - // dmrC_warning (sym->pos, "regular: offset=%d", sym->offset); -} - -static struct symbol * examine_struct_union_type(struct global_symbols_t *S, struct symbol *sym, int advance) -{ - struct struct_union_info info = { - .max_align = 1, - .bit_size = 0, - .align_size = 1 - }; - unsigned long bit_size, bit_align; - void (*fn)(struct global_symbols_t *S, struct symbol *, struct struct_union_info *); - struct symbol *member; - - fn = advance ? lay_out_struct : lay_out_union; - FOR_EACH_PTR(sym->symbol_list, member) { - fn(S, member, &info); - } END_FOR_EACH_PTR(member); - - if (!sym->ctype.alignment) - sym->ctype.alignment = info.max_align; - bit_size = info.bit_size; - if (info.align_size) { - bit_align = dmrC_bytes_to_bits(S->C->target, sym->ctype.alignment)-1; - bit_size = (bit_size + bit_align) & ~bit_align; - } - sym->bit_size = bit_size; - return sym; -} - -static struct symbol *examine_base_type(struct global_symbols_t *S, struct symbol *sym) -{ - struct symbol *base_type; - - /* Check the base type */ - base_type = dmrC_examine_symbol_type(S, sym->ctype.base_type); - if (!base_type || base_type->type == SYM_PTR) - return base_type; - sym->ctype.as |= base_type->ctype.as; - sym->ctype.modifiers |= base_type->ctype.modifiers & MOD_PTRINHERIT; - dmrC_concat_context_list(base_type->ctype.contexts, - &sym->ctype.contexts); - if (base_type->type == SYM_NODE) { - base_type = base_type->ctype.base_type; - sym->ctype.base_type = base_type; - } - return base_type; -} - -static struct symbol * examine_array_type(struct global_symbols_t *S, struct symbol *sym) -{ - struct symbol *base_type = examine_base_type(S, sym); - unsigned int bit_size = -1, alignment; - struct expression *array_size = sym->array_size; - - if (!base_type) - return sym; - - if (array_size) { - bit_size = (unsigned int) dmrC_array_element_offset(S->C->target, base_type->bit_size, - (int) dmrC_get_expression_value_silent(S->C, array_size)); - if (array_size->type != EXPR_VALUE) { - if (S->C->Wvla) - dmrC_warning(S->C, array_size->pos, "Variable length array is used."); - bit_size = -1; - } - } - alignment = base_type->ctype.alignment; - if (!sym->ctype.alignment) - sym->ctype.alignment = alignment; - sym->bit_size = bit_size; - return sym; -} - -static struct symbol *examine_bitfield_type(struct global_symbols_t *S, struct symbol *sym) -{ - struct symbol *base_type = examine_base_type(S, sym); - unsigned long bit_size, alignment, modifiers; - - if (!base_type) - return sym; - bit_size = base_type->bit_size; - if (sym->bit_size > (int) bit_size) - dmrC_warning(S->C, sym->pos, "impossible field-width, %d, for this type", sym->bit_size); - - alignment = base_type->ctype.alignment; - if (!sym->ctype.alignment) - sym->ctype.alignment = alignment; - modifiers = base_type->ctype.modifiers; - - /* Bitfields are unsigned, unless the base type was explicitly signed */ - if (!(modifiers & MOD_EXPLICITLY_SIGNED)) - modifiers = (modifiers & ~MOD_SIGNED) | MOD_UNSIGNED; - sym->ctype.modifiers |= modifiers & MOD_SIGNEDNESS; - return sym; -} - -/* - * "typeof" will have to merge the types together - */ -void dmrC_merge_type(struct symbol *sym, struct symbol *base_type) -{ - sym->ctype.as |= base_type->ctype.as; - sym->ctype.modifiers |= (base_type->ctype.modifiers & ~MOD_STORAGE); - dmrC_concat_context_list(base_type->ctype.contexts, - &sym->ctype.contexts); - sym->ctype.base_type = base_type->ctype.base_type; - if (sym->ctype.base_type->type == SYM_NODE) - dmrC_merge_type(sym, sym->ctype.base_type); -} - -static int count_array_initializer(struct global_symbols_t *S, struct symbol *t, struct expression *expr) -{ - int nr = 0; - int is_char = 0; - - /* - * Arrays of character types are special; they can be initialized by - * string literal _or_ by string literal in braces. The latter means - * that with T x[] = {} number of elements in x depends - * on T - if it's a character type, we get the length of string literal - * (including NUL), otherwise we have one element here. - */ - if (t->ctype.base_type == &S->int_type && t->ctype.modifiers & MOD_CHAR) - is_char = 1; - - switch (expr->type) { - case EXPR_INITIALIZER: { - struct expression *entry; - int count = 0; - int str_len = 0; - FOR_EACH_PTR(expr->expr_list, entry) { - count++; - switch (entry->type) { - case EXPR_INDEX: - if ((int)entry->idx_to >= nr) - nr = entry->idx_to+1; - break; - case EXPR_PREOP: { - struct expression *e = entry; - if (is_char) { - while (e && e->type == EXPR_PREOP && e->op == '(') - e = e->unop; - if (e && e->type == EXPR_STRING) { - entry = e; - case EXPR_STRING: - if (is_char) - str_len = entry->string->length; - } - - - } - } - default: - nr++; - } - } END_FOR_EACH_PTR(entry); - if (count == 1 && str_len) - nr = str_len; - break; - } - case EXPR_PREOP: - if (is_char) { - struct expression *e = expr; - while (e && e->type == EXPR_PREOP && e->op == '(') - e = e->unop; - if (e && e->type == EXPR_STRING) { - expr = e; - case EXPR_STRING: - if (is_char) - nr = expr->string->length; - } - } - break; - default: - break; - } - return nr; -} - -static struct expression *get_symbol_initializer(struct symbol *sym) -{ - do { - if (sym->initializer) - return sym->initializer; - } while ((sym = sym->same_symbol) != NULL); - return NULL; -} -static struct symbol * examine_node_type(struct global_symbols_t *S, struct symbol *sym) -{ - struct symbol *base_type = examine_base_type(S, sym); - int bit_size; - unsigned long alignment; - - /* SYM_NODE - figure out what the type of the node was.. */ - bit_size = 0; - alignment = 0; - if (!base_type) - return sym; - - bit_size = base_type->bit_size; - alignment = base_type->ctype.alignment; - - /* Pick up signedness information into the node */ - sym->ctype.modifiers |= (MOD_SIGNEDNESS & base_type->ctype.modifiers); - - if (!sym->ctype.alignment) - sym->ctype.alignment = alignment; - - /* Unsized array? The size might come from the initializer.. */ - if (bit_size < 0 && base_type->type == SYM_ARRAY) { - struct expression *initializer = get_symbol_initializer(sym); - if (initializer) { - struct symbol *node_type = base_type->ctype.base_type; - int count = count_array_initializer(S, node_type, initializer); - - if (node_type && node_type->bit_size >= 0) - bit_size = (int) dmrC_array_element_offset(S->C->target, node_type->bit_size, count); - /* Note that the bit_size will be set on parent SYM_NODE rather than here */ - //base_type->bit_size = bit_size; - } - } - - sym->bit_size = bit_size; - return sym; -} - -static struct symbol *examine_enum_type(struct global_symbols_t *S, struct symbol *sym) -{ - struct symbol *base_type = examine_base_type(S, sym); - - sym->ctype.modifiers |= (base_type->ctype.modifiers & MOD_SIGNEDNESS); - sym->bit_size = S->C->target->bits_in_enum; - if (base_type->bit_size > sym->bit_size) - sym->bit_size = base_type->bit_size; - sym->ctype.alignment = S->C->target->enum_alignment; - if (base_type->ctype.alignment > sym->ctype.alignment) - sym->ctype.alignment = base_type->ctype.alignment; - return sym; -} - -static struct symbol *examine_pointer_type(struct global_symbols_t *S, struct symbol *sym) -{ - /* - * We need to set the pointer size first, and - * examine the thing we point to only afterwards. - * That's because this pointer type may end up - * being needed for the base type size evaluation. - */ - if (!sym->bit_size) - sym->bit_size = S->C->target->bits_in_pointer; - if (!sym->ctype.alignment) - sym->ctype.alignment = S->C->target->pointer_alignment; - return sym; -} - -/* - * Fill in type size and alignment information for - * regular SYM_TYPE things. - */ -struct symbol *dmrC_examine_symbol_type(struct global_symbols_t *S, struct symbol * sym) -{ - if (!sym) - return sym; - - /* Already done? */ - if (sym->examined) - return sym; - sym->examined = 1; - - switch (sym->type) { - case SYM_FN: - case SYM_NODE: - return examine_node_type(S, sym); - case SYM_ARRAY: - return examine_array_type(S, sym); - case SYM_STRUCT: - return examine_struct_union_type(S, sym, 1); - case SYM_UNION: - return examine_struct_union_type(S, sym, 0); - case SYM_PTR: - return examine_pointer_type(S, sym); - case SYM_ENUM: - return examine_enum_type(S, sym); - case SYM_BITFIELD: - return examine_bitfield_type(S, sym); - case SYM_BASETYPE: - /* Size and alignment had better already be set up */ - return sym; - case SYM_TYPEOF: { - struct symbol *base = dmrC_evaluate_expression(S->C, sym->initializer); - if (base) { - unsigned long mod = 0; - - if (dmrC_is_bitfield_type(base)) - dmrC_warning(S->C, base->pos, "typeof applied to bitfield type"); - if (base->type == SYM_NODE) { - mod |= base->ctype.modifiers & MOD_TYPEOF; - base = base->ctype.base_type; - } - sym->type = SYM_NODE; - sym->ctype.modifiers = mod; - sym->ctype.base_type = base; - return examine_node_type(S, sym); - } - break; - } - case SYM_PREPROCESSOR: - dmrC_sparse_error(S->C, sym->pos, "ctype on preprocessor command? (%s)", dmrC_show_ident(S->C, sym->ident)); - return NULL; - case SYM_UNINITIALIZED: - dmrC_sparse_error(S->C, sym->pos, "ctype on uninitialized symbol %p", sym); - return NULL; - case SYM_RESTRICT: - examine_base_type(S, sym); - return sym; - case SYM_FOULED: - examine_base_type(S, sym); - return sym; - default: - dmrC_sparse_error(S->C, sym->pos, "Examining unknown symbol type %d", sym->type); - break; - } - return sym; -} - -const char* dmrC_get_type_name(enum type type) -{ - const char *type_lookup[] = { - [SYM_UNINITIALIZED] = "uninitialized", - [SYM_PREPROCESSOR] = "preprocessor", - [SYM_BASETYPE] = "basetype", - [SYM_NODE] = "node", - [SYM_PTR] = "pointer", - [SYM_FN] = "function", - [SYM_ARRAY] = "array", - [SYM_STRUCT] = "struct", - [SYM_UNION] = "union", - [SYM_ENUM] = "enum", - [SYM_TYPEDEF] = "typedef", - [SYM_TYPEOF] = "typeof", - [SYM_MEMBER] = "member", - [SYM_BITFIELD] = "bitfield", - [SYM_LABEL] = "label", - [SYM_RESTRICT] = "restrict", - [SYM_FOULED] = "fouled", - [SYM_KEYWORD] = "keyword", - [SYM_BAD] = "bad"}; - - if (type <= SYM_BAD) - return type_lookup[type]; - else - return NULL; -} - -struct symbol *dmrC_examine_pointer_target(struct global_symbols_t *S, struct symbol *sym) -{ - return examine_base_type(S, sym); -} - -void dmrC_create_fouled(struct global_symbols_t *S, struct symbol *type) -{ - if (type->bit_size < S->C->target->bits_in_int) { - struct symbol *news = dmrC_alloc_symbol(S, type->pos, type->type); - *news = *type; - news->bit_size = S->C->target->bits_in_int; - news->type = SYM_FOULED; - news->ctype.base_type = type; - dmrC_add_symbol(S->C, &S->restr, type); - dmrC_add_symbol(S->C, &S->fouled, news); - } -} - -struct symbol *dmrC_befoul(struct global_symbols_t *S, struct symbol *type) -{ - struct symbol *t1, *t2; - while (type->type == SYM_NODE) - type = type->ctype.base_type; - PREPARE_PTR_LIST(S->restr, t1); - PREPARE_PTR_LIST(S->fouled, t2); - for (;;) { - if (t1 == type) - return t2; - if (!t1) - break; - NEXT_PTR_LIST(t1); - NEXT_PTR_LIST(t2); - } - FINISH_PTR_LIST(t2); - FINISH_PTR_LIST(t1); - return NULL; -} - -void dmrC_check_declaration(struct global_symbols_t *S, struct symbol *sym) -{ - int warned = 0; - struct symbol *next = sym; - - while ((next = next->next_id) != NULL) { - if (next->ns != sym->ns) - continue; - if (sym->scope == next->scope) { - sym->same_symbol = next; - return; - } - /* Extern in block level matches a TOPLEVEL non-static symbol */ - if (sym->ctype.modifiers & MOD_EXTERN) { - if ((next->ctype.modifiers & (MOD_TOPLEVEL|MOD_STATIC)) == MOD_TOPLEVEL) { - sym->same_symbol = next; - return; - } - } - - - if (!S->C->Wshadow || warned) - continue; - if (dmrC_get_sym_type(next) == SYM_FN) - continue; - warned = 1; - dmrC_warning(S->C, sym->pos, "symbol '%s' shadows an earlier one", dmrC_show_ident(S->C, sym->ident)); - dmrC_info(S->C, next->pos, "originally declared here"); - } -} - -void dmrC_bind_symbol(struct global_symbols_t *S, struct symbol *sym, struct ident *ident, enum namespace_type ns) -{ - struct scope *scope; - if (sym->bound) { - dmrC_sparse_error(S->C, sym->pos, "internal error: symbol type already bound"); - return; - } - if (ident->reserved && (ns & (NS_TYPEDEF | NS_STRUCT | NS_LABEL | NS_SYMBOL))) { - dmrC_sparse_error(S->C, sym->pos, "Trying to use reserved word '%s' as identifier", dmrC_show_ident(S->C, ident)); - return; - } - sym->ns = ns; - sym->next_id = ident->symbols; - ident->symbols = sym; - if (sym->ident && sym->ident != ident) - dmrC_warning(S->C, sym->pos, "Symbol '%s' already bound", dmrC_show_ident(S->C, sym->ident)); - sym->ident = ident; - sym->bound = 1; - - scope = S->C->block_scope; - if (ns == NS_SYMBOL && dmrC_toplevel(S->C, scope)) { - unsigned mod = MOD_ADDRESSABLE | MOD_TOPLEVEL; - - scope = S->C->global_scope; - if (sym->ctype.modifiers & MOD_STATIC || - dmrC_is_extern_inline(sym)) { - scope = S->C->file_scope; - mod = MOD_TOPLEVEL; - } - sym->ctype.modifiers |= mod; - } - if (ns == NS_MACRO) - scope = S->C->file_scope; - if (ns == NS_LABEL) - scope = S->C->function_scope; - dmrC_bind_scope(S->C, sym, scope); -} - -struct symbol *dmrC_create_symbol(struct global_symbols_t *S, int stream, const char *name, int type, int ns) -{ - struct ident *ident = dmrC_built_in_ident(S->C, name); - struct symbol *sym = dmrC_lookup_symbol(ident, ns); - - if (sym && sym->type != type) - dmrC_die(S->C, "symbol %s created with different types: %d old %d", name, - type, sym->type); - - if (!sym) { - struct token *token = dmrC_built_in_token(S->C, stream, ident); - - sym = dmrC_alloc_symbol(S, token->pos, type); - dmrC_bind_symbol(S, sym, token->ident, ns); - } - return sym; -} - -void dmrC_init_symbols(struct dmr_C *C) -{ - struct global_symbols_t *S = (struct global_symbols_t *) calloc(1, sizeof(struct global_symbols_t)); - C->S = S; - S->C = C; - dmrC_allocator_init(&S->context_allocator, "contexts", sizeof(struct context), __alignof__(struct context), - CHUNK); - dmrC_allocator_init(&S->global_ident_allocator, "global_identifiers", sizeof(struct ident), - __alignof__(struct ident), CHUNK); - dmrC_allocator_init(&S->symbol_allocator, "symbols", sizeof(struct symbol), - __alignof__(struct symbol), CHUNK); - - int stream = dmrC_init_stream(C, "builtin", -1, C->T->includepath); - -#define __INIT_IDENT(n, str, res) (struct ident *) dmrC_allocator_allocate(&S->global_ident_allocator, sizeof(str)); S->n->len = sizeof(str)-1; memcpy(S->n->name, str, sizeof(str)); S->n->reserved = res; -#define __IDENT(n,str,res) \ - {S->n = __INIT_IDENT(n, str, res)} -#include "ident-list.h" - -#define __IDENT(n,str,res) \ - dmrC_hash_ident(C, S->n) -#include "ident-list.h" - - dmrC_init_parser(C, stream); - dmrC_init_builtins(C, stream); -} - -void dmrC_destroy_symbols(struct dmr_C *C) { - /* tokenizer must be destroyed before this */ - assert(C->T == NULL); - - dmrC_destroy_parser(C); - assert(C->P == NULL); - - struct global_symbols_t *S = C->S; - - dmrC_allocator_destroy(&S->context_allocator); - dmrC_allocator_destroy(&S->global_ident_allocator); - dmrC_allocator_destroy(&S->symbol_allocator); - - free(S); - C->S = NULL; -} - -void dmrC_init_ctype(struct dmr_C *C) -{ - assert(C); - struct global_symbols_t *S = C->S; - assert(S); - struct target_t *T = C->target; - assert(T); - const struct ctype_declare *ctype; - -#ifdef _MSC_VER - if (sizeof(long long) == sizeof(size_t)) { - T->size_t_ctype = &S->ullong_ctype; - T->ssize_t_ctype = &S->llong_ctype; - } - else { - assert(sizeof(int) == sizeof(size_t)); - T->size_t_ctype = &S->uint_ctype; - T->ssize_t_ctype = &S->int_ctype; - } -#else - T->size_t_ctype = &S->uint_ctype; - T->ssize_t_ctype = &S->int_ctype; -#endif - -#define MOD_ESIGNED (MOD_SIGNED | MOD_EXPLICITLY_SIGNED) -#define MOD_LL (MOD_LONG | MOD_LONGLONG) -#define MOD_LLL MOD_LONGLONGLONG - const struct ctype_declare { - struct symbol *ptr; - enum type type; - unsigned long modifiers; - int *bit_size; - int *maxalign; - struct symbol *base_type; - } ctype_declaration[] = { - { &S->bool_ctype, SYM_BASETYPE, MOD_UNSIGNED, &T->bits_in_bool, &T->max_int_alignment, &S->int_type }, - { &S->void_ctype, SYM_BASETYPE, 0, NULL, NULL, NULL }, - { &S->type_ctype, SYM_BASETYPE, MOD_TYPE, NULL, NULL, NULL }, - { &S->incomplete_ctype,SYM_BASETYPE, 0, NULL, NULL, NULL }, - { &S->bad_ctype, SYM_BASETYPE, 0, NULL, NULL, NULL }, - - { &S->char_ctype, SYM_BASETYPE, MOD_SIGNED | MOD_CHAR, &T->bits_in_char, &T->max_int_alignment, &S->int_type }, - { &S->schar_ctype, SYM_BASETYPE, MOD_ESIGNED | MOD_CHAR, &T->bits_in_char, &T->max_int_alignment, &S->int_type }, - { &S->uchar_ctype, SYM_BASETYPE, MOD_UNSIGNED | MOD_CHAR, &T->bits_in_char, &T->max_int_alignment, &S->int_type }, - { &S->short_ctype, SYM_BASETYPE, MOD_SIGNED | MOD_SHORT, &T->bits_in_short, &T->max_int_alignment, &S->int_type }, - { &S->sshort_ctype, SYM_BASETYPE, MOD_ESIGNED | MOD_SHORT, &T->bits_in_short, &T->max_int_alignment, &S->int_type }, - { &S->ushort_ctype, SYM_BASETYPE, MOD_UNSIGNED | MOD_SHORT, &T->bits_in_short, &T->max_int_alignment, &S->int_type }, - { &S->int_ctype, SYM_BASETYPE, MOD_SIGNED, &T->bits_in_int, &T->max_int_alignment, &S->int_type }, - { &S->sint_ctype, SYM_BASETYPE, MOD_ESIGNED, &T->bits_in_int, &T->max_int_alignment, &S->int_type }, - { &S->uint_ctype, SYM_BASETYPE, MOD_UNSIGNED, &T->bits_in_int, &T->max_int_alignment, &S->int_type }, - { &S->long_ctype, SYM_BASETYPE, MOD_SIGNED | MOD_LONG, &T->bits_in_long, &T->max_int_alignment, &S->int_type }, - { &S->slong_ctype, SYM_BASETYPE, MOD_ESIGNED | MOD_LONG, &T->bits_in_long, &T->max_int_alignment, &S->int_type }, - { &S->ulong_ctype, SYM_BASETYPE, MOD_UNSIGNED | MOD_LONG, &T->bits_in_long, &T->max_int_alignment, &S->int_type }, - { &S->llong_ctype, SYM_BASETYPE, MOD_SIGNED | MOD_LL, &T->bits_in_longlong, &T->max_int_alignment, &S->int_type }, - { &S->sllong_ctype, SYM_BASETYPE, MOD_ESIGNED | MOD_LL, &T->bits_in_longlong, &T->max_int_alignment, &S->int_type }, - { &S->ullong_ctype, SYM_BASETYPE, MOD_UNSIGNED | MOD_LL, &T->bits_in_longlong, &T->max_int_alignment, &S->int_type }, - { &S->lllong_ctype, SYM_BASETYPE, MOD_SIGNED | MOD_LLL, &T->bits_in_longlonglong, &T->max_int_alignment, &S->int_type }, - { &S->slllong_ctype, SYM_BASETYPE, MOD_ESIGNED | MOD_LLL, &T->bits_in_longlonglong, &T->max_int_alignment, &S->int_type }, - { &S->ulllong_ctype, SYM_BASETYPE, MOD_UNSIGNED | MOD_LLL, &T->bits_in_longlonglong, &T->max_int_alignment, &S->int_type }, - - { &S->float_ctype, SYM_BASETYPE, 0, &T->bits_in_float, &T->max_fp_alignment, &S->fp_type }, - { &S->double_ctype, SYM_BASETYPE, MOD_LONG, &T->bits_in_double, &T->max_fp_alignment, &S->fp_type }, - { &S->ldouble_ctype, SYM_BASETYPE, MOD_LONG | MOD_LONGLONG, &T->bits_in_longdouble, &T->max_fp_alignment, &S->fp_type }, - - { &S->string_ctype, SYM_PTR, 0, &T->bits_in_pointer, &T->pointer_alignment, &S->char_ctype }, - { &S->ptr_ctype, SYM_PTR, 0, &T->bits_in_pointer, &T->pointer_alignment, &S->void_ctype }, - { &S->null_ctype, SYM_PTR, 0, &T->bits_in_pointer, &T->pointer_alignment, &S->void_ctype }, - { &S->label_ctype, SYM_PTR, 0, &T->bits_in_pointer, &T->pointer_alignment, &S->void_ctype }, - { &S->lazy_ptr_ctype, SYM_PTR, 0, &T->bits_in_pointer, &T->pointer_alignment, &S->void_ctype }, - { NULL, SYM_UNINITIALIZED, 0, NULL, NULL, NULL } - }; -#undef MOD_LLL -#undef MOD_LL -#undef MOD_ESIGNED - - - for (ctype = ctype_declaration ; ctype->ptr; ctype++) { - struct symbol *sym = ctype->ptr; - unsigned long bit_size = ctype->bit_size ? *ctype->bit_size : -1; - unsigned long maxalign = ctype->maxalign ? *ctype->maxalign : 0; - unsigned long alignment = dmrC_bits_to_bytes(T, bit_size); - - if (alignment > maxalign) - alignment = maxalign; - sym->type = ctype->type; - sym->bit_size = bit_size; - sym->ctype.alignment = alignment; - sym->ctype.base_type = ctype->base_type; - sym->ctype.modifiers = ctype->modifiers; - } - - S->typenames[0].sym = &S->char_ctype; S->typenames[0].name = "char"; - S->typenames[1].sym = &S->schar_ctype; S->typenames[1].name = "signed char"; - S->typenames[2].sym = &S->uchar_ctype; S->typenames[2].name = "unsigned char"; - S->typenames[3].sym = &S->short_ctype; S->typenames[3].name = "short"; - S->typenames[4].sym = &S->sshort_ctype; S->typenames[4].name = "signed short"; - S->typenames[5].sym = &S->ushort_ctype; S->typenames[5].name = "unsigned short"; - S->typenames[6].sym = &S->int_ctype; S->typenames[6].name = "int"; - S->typenames[7].sym = &S->sint_ctype; S->typenames[7].name = "signed int"; - S->typenames[8].sym = &S->uint_ctype; S->typenames[8].name = "unsigned int"; - S->typenames[9].sym = &S->slong_ctype; S->typenames[9].name = "signed long"; - S->typenames[10].sym = &S->long_ctype; S->typenames[10].name = "long"; - S->typenames[11].sym = &S->ulong_ctype; S->typenames[11].name = "unsigned long"; - S->typenames[12].sym = &S->llong_ctype; S->typenames[12].name = "long long"; - S->typenames[13].sym = &S->sllong_ctype; S->typenames[13].name = "signed long long"; - S->typenames[14].sym = &S->ullong_ctype; S->typenames[14].name = "unsigned long long"; - S->typenames[15].sym = &S->lllong_ctype; S->typenames[15].name = "long long long"; - S->typenames[16].sym = &S->slllong_ctype; S->typenames[16].name = "signed long long long"; - S->typenames[17].sym = &S->ulllong_ctype; S->typenames[17].name = "unsigned long long long"; - - S->typenames[18].sym = &S->void_ctype; S->typenames[18].name = "void"; - S->typenames[19].sym = &S->bool_ctype; S->typenames[19].name = "bool"; - S->typenames[20].sym = &S->string_ctype; S->typenames[20].name = "string"; - - S->typenames[21].sym = &S->float_ctype; S->typenames[21].name = "float"; - S->typenames[22].sym = &S->double_ctype; S->typenames[22].name = "double"; - S->typenames[23].sym = &S->ldouble_ctype; S->typenames[23].name = "long double"; - S->typenames[24].sym = &S->incomplete_ctype; S->typenames[24].name = "incomplete type"; - S->typenames[25].sym = &S->int_type; S->typenames[25].name = "abstract int"; - S->typenames[26].sym = &S->fp_type; S->typenames[26].name = "abstract fp"; - S->typenames[27].sym = &S->label_ctype; S->typenames[27].name = "label type"; - S->typenames[28].sym = &S->bad_ctype; S->typenames[28].name = "bad type"; - S->typenames[29].sym = NULL, S->typenames[29].name = NULL; -} - diff --git a/dmr_c/src/symbol.h b/dmr_c/src/symbol.h deleted file mode 100644 index 12c65b7..0000000 --- a/dmr_c/src/symbol.h +++ /dev/null @@ -1,595 +0,0 @@ -#ifndef DMR_C_SYMBOL_H -#define DMR_C_SYMBOL_H - -/* -* Basic symbol and namespace definitions. -* -* Copyright (C) 2003 Transmeta Corp. -* 2003 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - - -/* -* An identifier with semantic meaning is a "symbol". -* -* There's a 1:n relationship: each symbol is always -* associated with one identifier, while each identifier -* can have one or more semantic meanings due to C scope -* rules. -* -* The progression is symbol -> token -> identifier. The -* token contains the information on where the symbol was -* declared. -*/ -enum namespace_type { - NS_NONE = 0, - NS_MACRO = 1, - NS_TYPEDEF = 2, - NS_STRUCT = 4, // Also used for unions and enums. - NS_LABEL = 8, - NS_SYMBOL = 16, - NS_ITERATOR = 32, - NS_PREPROCESSOR = 64, - NS_UNDEF = 128, - NS_KEYWORD = 256, -}; - -enum type { - SYM_UNINITIALIZED, - SYM_PREPROCESSOR, - SYM_BASETYPE, - SYM_NODE, - SYM_PTR, - SYM_FN, - SYM_ARRAY, - SYM_STRUCT, - SYM_UNION, - SYM_ENUM, - SYM_TYPEDEF, - SYM_TYPEOF, - SYM_MEMBER, - SYM_BITFIELD, - SYM_LABEL, - SYM_RESTRICT, - SYM_FOULED, - SYM_KEYWORD, - SYM_BAD, -}; - -enum keyword { - KW_SPECIFIER = 1 << 0, - KW_MODIFIER = 1 << 1, - KW_QUALIFIER = 1 << 2, - KW_ATTRIBUTE = 1 << 3, - KW_STATEMENT = 1 << 4, - KW_ASM = 1 << 5, - KW_MODE = 1 << 6, - KW_SHORT = 1 << 7, - KW_LONG = 1 << 8, - KW_EXACT = 1 << 9, -}; - -struct context { - struct expression *context_expr; - unsigned int in, out; -}; - -DECLARE_PTR_LIST(context_list, struct context); -struct phi_map; - -struct ctype { - unsigned long modifiers; - unsigned long alignment; - struct context_list *contexts; - unsigned int as; - struct symbol *base_type; -}; - -struct decl_state { - struct ctype ctype; - struct ident **ident; - struct symbol_op *mode; - unsigned char prefer_abstract, is_inline, storage_class, is_tls; -}; - -struct symbol; -DECLARE_PTR_LIST(symbol_list, struct symbol); - -struct symbol_op { - enum keyword type; - int (*evaluate)(struct dmr_C *, struct expression *); - int (*expand)(struct dmr_C *, struct expression *, int); - int (*args)(struct dmr_C *, struct expression *); - - /* keywords */ - struct token *(*declarator)(struct dmr_C *, struct token *token, - struct decl_state *ctx); - struct token *(*statement)(struct dmr_C *, struct token *token, struct statement *stmt); - struct token *(*toplevel)(struct dmr_C *, struct token *token, struct symbol_list **list); - struct token *(*attribute)(struct dmr_C *, struct token *token, struct symbol *attr, - struct decl_state *ctx); - struct symbol *(*to_mode)(struct dmr_C *, struct symbol *); - - int test, set, cls; -}; - -#define SYM_ATTR_WEAK 0 -#define SYM_ATTR_NORMAL 1 -#define SYM_ATTR_STRONG 2 - -struct symbol { - enum type type : 8; - enum namespace_type ns : 9; - unsigned char used : 1, attr : 2, enum_member : 1, bound : 1; - struct position pos; /* Where this symbol was declared */ - struct position endpos; /* Where this symbol ends*/ - struct ident *ident; /* What identifier this symbol is associated with */ - struct symbol *next_id; /* Next semantic symbol that shares this identifier */ - struct symbol *replace; /* What is this symbol shadowed by in copy-expression */ - struct scope *scope; - union { - struct symbol *same_symbol; - struct symbol *next_subobject; - }; - - struct symbol_op *op; - - union { - struct /* NS_MACRO */ { - struct token *expansion; - struct token *arglist; - struct scope *used_in; - }; - struct /* NS_PREPROCESSOR */ { - int (*handler)(struct dmr_C *, struct stream *, struct token **, struct token *); - int normal; - }; - struct /* NS_SYMBOL */ { - unsigned long offset; - int bit_size; - unsigned int bit_offset:8, - arg_count:10, - variadic:1, - initialized:1, - examined:1, - expanding:1, - evaluated:1, - string:1, - designated_init:1, - forced_arg:1, - transparent_union:1; - struct expression *array_size; - struct ctype ctype; - struct symbol_list *arguments; - struct statement *stmt; - struct symbol_list *symbol_list; - struct statement *inline_stmt; - struct symbol_list *inline_symbol_list; - struct expression *initializer; - struct entrypoint *ep; - long long value; /* Initial value */ - struct symbol *definition; - }; - }; - union /* backend */ { - struct basic_block *bb_target; /* label */ - void *aux; /* Auxiliary info, e.g. backend information */ - struct { /* sparse ctags */ - char kind; - unsigned char visited:1; - }; - }; - pseudo_t pseudo; - DMRC_BACKEND_TYPE priv; -}; - -/* Modifiers */ -#define MOD_AUTO 0x0001 -#define MOD_REGISTER 0x0002 -#define MOD_STATIC 0x0004 -#define MOD_EXTERN 0x0008 - -#define MOD_CONST 0x0010 -#define MOD_VOLATILE 0x0020 -#define MOD_SIGNED 0x0040 -#define MOD_UNSIGNED 0x0080 - -#define MOD_CHAR 0x0100 -#define MOD_SHORT 0x0200 -#define MOD_LONG 0x0400 -#define MOD_LONGLONG 0x0800 -#define MOD_LONGLONGLONG 0x1000 -#define MOD_PURE 0x2000 - -#define MOD_TYPEDEF 0x10000 - -#define MOD_TLS 0x20000 -#define MOD_INLINE 0x40000 -#define MOD_ADDRESSABLE 0x80000 - -#define MOD_NOCAST 0x100000 -#define MOD_NODEREF 0x200000 -#define MOD_ACCESSED 0x400000 -#define MOD_TOPLEVEL 0x800000 // scoping.. - -#define MOD_ASSIGNED 0x2000000 -#define MOD_TYPE 0x4000000 -#define MOD_SAFE 0x8000000 // non-null/non-trapping pointer - -#define MOD_USERTYPE 0x10000000 -#define MOD_NORETURN 0x20000000 -#define MOD_EXPLICITLY_SIGNED 0x40000000 -#define MOD_BITWISE 0x80000000 - - -#define MOD_NONLOCAL (MOD_EXTERN | MOD_TOPLEVEL) -#define MOD_STORAGE (MOD_AUTO | MOD_REGISTER | MOD_STATIC | MOD_EXTERN | MOD_INLINE | MOD_TOPLEVEL) -#define MOD_SIGNEDNESS (MOD_SIGNED | MOD_UNSIGNED | MOD_EXPLICITLY_SIGNED) -#define MOD_LONG_ALL (MOD_LONG | MOD_LONGLONG | MOD_LONGLONGLONG) -#define MOD_SPECIFIER (MOD_CHAR | MOD_SHORT | MOD_LONG_ALL | MOD_SIGNEDNESS) -#define MOD_SIZE (MOD_CHAR | MOD_SHORT | MOD_LONG_ALL) -#define MOD_IGNORE (MOD_TOPLEVEL | MOD_STORAGE | MOD_ADDRESSABLE | \ - MOD_ASSIGNED | MOD_USERTYPE | MOD_ACCESSED | MOD_EXPLICITLY_SIGNED) -#define MOD_PTRINHERIT (MOD_VOLATILE | MOD_CONST | MOD_NODEREF | MOD_NORETURN | MOD_NOCAST) -/* modifiers preserved by typeof() operator */ -#define MOD_TYPEOF (MOD_VOLATILE | MOD_CONST | MOD_NOCAST | MOD_SPECIFIER) - -struct ctype_name { - struct symbol *sym; - const char *name; -}; - -struct global_symbols_t { - struct dmr_C *C; - - /* Abstract types */ - struct symbol int_type, - fp_type; - - /* C types */ - struct symbol bool_ctype, void_ctype, type_ctype, - char_ctype, schar_ctype, uchar_ctype, - short_ctype, sshort_ctype, ushort_ctype, - int_ctype, sint_ctype, uint_ctype, - long_ctype, slong_ctype, ulong_ctype, - llong_ctype, sllong_ctype, ullong_ctype, - lllong_ctype, slllong_ctype, ulllong_ctype, - float_ctype, double_ctype, ldouble_ctype, - string_ctype, ptr_ctype, lazy_ptr_ctype, - incomplete_ctype, label_ctype, bad_ctype, - null_ctype; - - /* Special internal symbols */ - struct symbol zero_int; - - /* - * Secondary symbol list for stuff that needs to be output because it - * was used. - */ - struct symbol_list *translation_unit_used_list; - - struct allocator context_allocator; - struct allocator symbol_allocator; - struct allocator global_ident_allocator; - - struct symbol_list *restr, *fouled; - - struct ctype_name typenames[30]; - -#define __IDENT(n, str, res) struct ident *n -#include "ident-list.h" -#undef __IDENT -}; - -extern void dmrC_init_symbols(struct dmr_C *C); -extern void dmrC_init_ctype(struct dmr_C *C); -extern void dmrC_init_builtins(struct dmr_C *C, int stream); -extern void dmrC_destroy_symbols(struct dmr_C *C); - -extern struct context *dmrC_alloc_context(struct global_symbols_t *S); -extern void dmrC_access_symbol(struct global_symbols_t *S, struct symbol *sym); - -extern const char *dmrC_type_difference(struct dmr_C *C, struct ctype *c1, struct ctype *c2, - unsigned long mod1, unsigned long mod2); - -extern struct symbol *dmrC_lookup_symbol(struct ident *, enum namespace_type); -extern struct symbol *dmrC_create_symbol(struct global_symbols_t *S, int stream, const char *name, int type, int ns); - -extern struct symbol *dmrC_alloc_symbol(struct global_symbols_t *S, - struct position pos, int type); -extern void dmrC_show_type(struct dmr_C *C, struct symbol *); -extern const char *dmrC_modifier_string(struct dmr_C *C, unsigned long mod); -extern void dmrC_show_symbol(struct dmr_C *C, struct symbol *); -extern int dmrC_show_symbol_expr_init(struct dmr_C *C, struct symbol *sym); -extern void dmrC_show_symbol_list(struct dmr_C *C, struct symbol_list *, const char *); -extern void dmrC_bind_symbol(struct global_symbols_t *S, struct symbol *sym, - struct ident *ident, enum namespace_type ns); - -extern struct symbol *dmrC_examine_symbol_type(struct global_symbols_t *S, - struct symbol *sym); -extern struct symbol *dmrC_examine_pointer_target(struct global_symbols_t *S, - struct symbol *sym); -extern const char *dmrC_show_typename(struct dmr_C *C, struct symbol *sym); -extern const char *dmrC_builtin_typename(struct dmr_C *C, struct symbol *sym); -extern const char *dmrC_builtin_ctypename(struct dmr_C *C, struct ctype *ctype); -extern const char *dmrC_get_type_name(enum type type); - -extern void dmrC_debug_symbol(struct dmr_C *C, struct symbol *); -extern void dmrC_merge_type(struct symbol *sym, struct symbol *base_type); -extern void dmrC_check_declaration(struct global_symbols_t *S, struct symbol *sym); - -static inline struct symbol *dmrC_get_base_type(struct global_symbols_t *S, - const struct symbol *sym) -{ - return dmrC_examine_symbol_type(S, sym->ctype.base_type); -} - -static inline int dmrC_is_int_type(struct global_symbols_t *S, - const struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - if (type->type == SYM_ENUM) - type = type->ctype.base_type; - return type->type == SYM_BITFIELD || - type->ctype.base_type == &S->int_type; -} - -static inline int dmrC_is_enum_type(const struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - return (type->type == SYM_ENUM); -} - -static inline int dmrC_is_type_type(struct symbol *type) -{ - return (type->ctype.modifiers & MOD_TYPE) != 0; -} - -static inline int dmrC_is_ptr_type(struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - return type->type == SYM_PTR || type->type == SYM_ARRAY || type->type == SYM_FN; -} - -static inline int dmrC_is_func_type(struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - return type->type == SYM_FN; -} - -static inline int dmrC_is_array_type(struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - return type->type == SYM_ARRAY; -} - -static inline int dmrC_is_float_type(struct global_symbols_t *S, struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - return type->ctype.base_type == &S->fp_type; -} - -static inline int dmrC_is_byte_type(const struct target_t *target, - struct symbol *type) -{ - return type->bit_size == target->bits_in_char && type->type != SYM_BITFIELD; -} - -static inline int dmrC_is_void_type(struct global_symbols_t *S, struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - return type == &S->void_ctype; -} - -static inline int dmrC_is_bool_type(struct global_symbols_t *S, struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - return type == &S->bool_ctype; -} - -static inline int dmrC_is_scalar_type(struct global_symbols_t *S, struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - switch (type->type) { - case SYM_ENUM: - case SYM_BITFIELD: - case SYM_PTR: - case SYM_ARRAY: // OK, will be a PTR after conversion - case SYM_FN: - case SYM_RESTRICT: // OK, always integer types - return 1; - default: - break; - } - if (type->ctype.base_type == &S->int_type) - return 1; - if (type->ctype.base_type == &S->fp_type) - return 1; - return 0; -} - -// From Luc - sssa-mini -static inline int dmrC_is_simple_type(struct global_symbols_t *S, struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - switch (type->type) { - case SYM_ENUM: - case SYM_BITFIELD: - case SYM_PTR: - case SYM_RESTRICT: // OK, always integer types - return 1; - // Following is causing failures because the IR - // attempts to store values into unions or structs - //case SYM_STRUCT: - //case SYM_UNION: - // return type->bit_size <= S->long_ctype.bit_size; - default: - break; - } - if (type->ctype.base_type == &S->int_type) - return 1; - if (type->ctype.base_type == &S->fp_type) - return 1; - return 0; -} - -// From Luc - sssa-mini -static inline int dmrC_is_simple_var(struct global_symbols_t *S, struct symbol *var) -{ - if (!dmrC_is_simple_type(S, var)) - return 0; -#define MOD_NONREG (MOD_STATIC|MOD_NONLOCAL|MOD_ADDRESSABLE|MOD_VOLATILE) - if (var->ctype.modifiers & MOD_NONREG) - return 0; - return 1; -} - -static inline int dmrC_is_function(struct symbol *type) -{ - return type && type->type == SYM_FN; -} - -static inline int dmrC_is_extern_inline(struct symbol *sym) -{ - return (sym->ctype.modifiers & MOD_EXTERN) && - (sym->ctype.modifiers & MOD_INLINE) && - dmrC_is_function(sym->ctype.base_type); -} - -static inline int dmrC_is_toplevel(struct symbol *sym) -{ - return (sym->ctype.modifiers & MOD_TOPLEVEL); -} - -static inline int dmrC_is_extern(struct symbol *sym) -{ - return (sym->ctype.modifiers & MOD_EXTERN); -} - -static inline int dmrC_is_static(struct symbol *sym) -{ - return (sym->ctype.modifiers & MOD_STATIC); -} - -static int dmrC_is_signed_type(struct symbol *sym) -{ - if (sym->type == SYM_NODE) - sym = sym->ctype.base_type; - if (sym->type == SYM_PTR) - return 0; - return !(sym->ctype.modifiers & MOD_UNSIGNED); -} - -static inline int dmrC_is_unsigned(struct symbol *sym) -{ - return !dmrC_is_signed_type(sym); -} - -static inline int dmrC_get_sym_type(struct symbol *type) -{ - if (type->type == SYM_NODE) - type = type->ctype.base_type; - if (type->type == SYM_ENUM) - type = type->ctype.base_type; - return type->type; -} - -static inline struct symbol *dmrC_get_nth_symbol(struct symbol_list *list, unsigned int idx) -{ - return (struct symbol *)ptrlist_nth_entry((struct ptr_list *)list, idx); -} - -static inline struct symbol *dmrC_lookup_keyword(struct ident *ident, - enum namespace_type ns) -{ - if (!ident->keyword) - return NULL; - return dmrC_lookup_symbol(ident, ns); -} - -static inline void dmrC_concat_symbol_list(struct symbol_list *from, struct symbol_list **to) -{ - ptrlist_concat((struct ptr_list *)from, (struct ptr_list **) to); -} - -static inline void dmrC_add_symbol(struct dmr_C *C, struct symbol_list **list, struct symbol *sym) -{ - ptrlist_add((struct ptr_list**)list, sym, &C->ptrlist_allocator); -} - -static inline int dmrC_symbol_list_size(struct symbol_list *list) -{ - return ptrlist_size((struct ptr_list *)list); -} - -static inline void dmrC_concat_context_list(struct context_list *from, - struct context_list **to) -{ - ptrlist_concat((struct ptr_list *)from, (struct ptr_list **)to); -} - -static inline void dmrC_add_context(struct dmr_C *C, struct context_list **list, - struct context *ctx) -{ - ptrlist_add((struct ptr_list **)list, ctx, &C->ptrlist_allocator); -} - -static inline int dmrC_is_prototype(struct symbol *sym) -{ - if (sym->type == SYM_NODE) - sym = sym->ctype.base_type; - return sym && sym->type == SYM_FN && !sym->stmt; -} - -#define dmrC_is_restricted_type(type) (dmrC_get_sym_type(type) == SYM_RESTRICT) -#define dmrC_is_fouled_type(type) (dmrC_get_sym_type(type) == SYM_FOULED) -#define dmrC_is_bitfield_type(type) (dmrC_get_sym_type(type) == SYM_BITFIELD) - -extern void dmrC_create_fouled(struct global_symbols_t *S, struct symbol *type); -extern struct symbol *dmrC_befoul(struct global_symbols_t *S, struct symbol *type); - -#ifdef __cplusplus -} -#endif - - -#endif diff --git a/dmr_c/src/target.c b/dmr_c/src/target.c deleted file mode 100644 index a7aa935..0000000 --- a/dmr_c/src/target.c +++ /dev/null @@ -1,88 +0,0 @@ -/* -* Copyright (C) 2003 Transmeta Corp. -* 2003 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#include -#include - -#include -#include -#include - -enum dummy { DUMMY }; - -void dmrC_init_target(struct dmr_C *C) { - - struct target_t *t = (struct target_t *)calloc(1, sizeof(struct target_t)); - - /* - * For "__attribute__((aligned))" - */ - t->max_alignment = 16; - - /* - * Integer data types - */ - t->bits_in_bool = 1; - t->bits_in_char = 8; - t->bits_in_short = 16; - t->bits_in_int = 32; - t->bits_in_long = sizeof(long) * t->bits_in_char; - t->bits_in_longlong = 64; - t->bits_in_longlonglong = 128; - - t->bits_in_wchar = 32; - t->max_int_alignment = __alignof__(long long); - - /* - * Floating point data types - */ - t->bits_in_float = 32; - t->bits_in_double = 64; - t->bits_in_longdouble = sizeof(long double) * t->bits_in_char; - - t->max_fp_alignment = 8; - - /* - * Pointer data type - */ - t->bits_in_pointer = sizeof(void *) * t->bits_in_char; - t->pointer_alignment = __alignof__(void *); - - /* - * Enum data types - */ - t->bits_in_enum = 32; - t->enum_alignment = 4; - - C->target = t; -} - -void dmrC_destroy_target(struct dmr_C *C) { - free(C->target); - C->target = NULL; -} - diff --git a/dmr_c/src/target.h b/dmr_c/src/target.h deleted file mode 100644 index 5ad1a5e..0000000 --- a/dmr_c/src/target.h +++ /dev/null @@ -1,85 +0,0 @@ -#ifndef DMR_C_TARGET_H -#define DMR_C_TARGET_H -/* -* sparse/target.h -* -* Copyright (C) 2003 Transmeta Corp. -* 2003 Linus Torvalds -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#include - -struct target_t { - struct symbol *size_t_ctype; - struct symbol *ssize_t_ctype; - - /* - * For "__attribute__((aligned))" - */ - int max_alignment; - - /* - * Integer data types - */ - int bits_in_bool; - int bits_in_char; - int bits_in_short; - int bits_in_int; - int bits_in_long; - int bits_in_longlong; - int bits_in_longlonglong; - - int bits_in_wchar; - int max_int_alignment; - - /* - * Floating point data types - */ - int bits_in_float; - int bits_in_double; - int bits_in_longdouble; - - int max_fp_alignment; - - /* - * Pointer data type - */ - int bits_in_pointer; - int pointer_alignment; - - /* - * Enum data types - */ - int bits_in_enum; - int enum_alignment; -}; - -/* -* Helper functions for converting bits to bytes and vice versa. -*/ - -static inline int dmrC_bits_to_bytes(const struct target_t *target, int bits) { - return bits >= 0 ? (bits + target->bits_in_char - 1) / target->bits_in_char : -1; -} - -static inline int dmrC_bytes_to_bits(const struct target_t *target, int bytes) { - return bytes * target->bits_in_char; -} - -static inline unsigned long long dmrC_array_element_offset(const struct target_t *target, unsigned int base_bits, int idx) -{ - int fragment = base_bits % target->bits_in_char; - if (fragment) - base_bits += target->bits_in_char - fragment; - return base_bits * idx; -} - -extern void dmrC_init_target(struct dmr_C *C); -extern void dmrC_destroy_target(struct dmr_C *C); - - -#endif \ No newline at end of file diff --git a/dmr_c/src/token.h b/dmr_c/src/token.h deleted file mode 100644 index 0bf32ba..0000000 --- a/dmr_c/src/token.h +++ /dev/null @@ -1,294 +0,0 @@ -/* -* Basic tokenization structures. NOTE! Those tokens had better -* be pretty small, since we're going to keep them all in memory -* indefinitely. -* -* Copyright (C) 2003 Transmeta Corp. -* 2003 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ - -#ifndef DMR_C_TOKENIZER_H -#define DMR_C_TOKENIZER_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * This describes the pure lexical elements (tokens), with - * no semantic meaning. In other words, an identifier doesn't - * have a type or meaning, it is only a specific string in - * the input stream. - * - * Semantic meaning is handled elsewhere. - */ - -enum constantfile { - CONSTANT_FILE_MAYBE, // To be determined, not inside any #ifs in this file - CONSTANT_FILE_IFNDEF, // To be determined, currently inside #ifndef - CONSTANT_FILE_NOPE, // No - CONSTANT_FILE_YES // Yes -}; - -struct stream { - int fd; - const char *name; - const char *path; // input-file path - see set_stream_include_path() - const char **next_path; - - /* Use these to check for "already parsed" */ - enum constantfile constant; - int dirty, next_stream, once; - struct ident *protect; - struct token *ifndef; - struct token *top_if; -}; - -struct ident { - struct ident *next; /* Hash chain of identifiers */ - struct symbol *symbols; /* Pointer to semantic meaning list */ - unsigned char len; /* Length of identifier name */ - unsigned char tainted:1, - reserved:1, - keyword:1; - char name[]; /* Actual identifier */ -}; -DECLARE_PTR_LIST(ident_list, struct ident); - -enum e_token_type { - TOKEN_EOF, - TOKEN_ERROR, - TOKEN_IDENT, - TOKEN_ZERO_IDENT, - TOKEN_NUMBER, - TOKEN_CHAR, - TOKEN_CHAR_EMBEDDED_0, - TOKEN_CHAR_EMBEDDED_1, - TOKEN_CHAR_EMBEDDED_2, - TOKEN_CHAR_EMBEDDED_3, - TOKEN_WIDE_CHAR, - TOKEN_WIDE_CHAR_EMBEDDED_0, - TOKEN_WIDE_CHAR_EMBEDDED_1, - TOKEN_WIDE_CHAR_EMBEDDED_2, - TOKEN_WIDE_CHAR_EMBEDDED_3, - TOKEN_STRING, - TOKEN_WIDE_STRING, - TOKEN_SPECIAL, - TOKEN_STREAMBEGIN, - TOKEN_STREAMEND, - TOKEN_MACRO_ARGUMENT, - TOKEN_STR_ARGUMENT, - TOKEN_QUOTED_ARGUMENT, - TOKEN_CONCAT, - TOKEN_GNU_KLUDGE, - TOKEN_UNTAINT, - TOKEN_ARG_COUNT, - TOKEN_IF, - TOKEN_SKIP_GROUPS, - TOKEN_ELSE, -}; - -/* Combination tokens */ -#define COMBINATION_STRINGS { \ - "+=", "++", \ - "-=", "--", "->", \ - "*=", \ - "/=", \ - "%=", \ - "<=", ">=", \ - "==", "!=", \ - "&&", "&=", \ - "||", "|=", \ - "^=", "##", \ - "<<", ">>", "..", \ - "<<=", ">>=", "...", \ - "", \ - "<", ">", "<=", ">=" \ -} - -extern unsigned char dmrC_combinations_[][4]; - -enum special_token { - SPECIAL_BASE = 256, - SPECIAL_ADD_ASSIGN = SPECIAL_BASE, - SPECIAL_INCREMENT, - SPECIAL_SUB_ASSIGN, - SPECIAL_DECREMENT, - SPECIAL_DEREFERENCE, - SPECIAL_MUL_ASSIGN, - SPECIAL_DIV_ASSIGN, - SPECIAL_MOD_ASSIGN, - SPECIAL_LTE, - SPECIAL_GTE, - SPECIAL_EQUAL, - SPECIAL_NOTEQUAL, - SPECIAL_LOGICAL_AND, - SPECIAL_AND_ASSIGN, - SPECIAL_LOGICAL_OR, - SPECIAL_OR_ASSIGN, - SPECIAL_XOR_ASSIGN, - SPECIAL_HASHHASH, - SPECIAL_LEFTSHIFT, - SPECIAL_RIGHTSHIFT, - SPECIAL_DOTDOT, - SPECIAL_SHL_ASSIGN, - SPECIAL_SHR_ASSIGN, - SPECIAL_ELLIPSIS, - SPECIAL_ARG_SEPARATOR, - SPECIAL_UNSIGNED_LT, - SPECIAL_UNSIGNED_GT, - SPECIAL_UNSIGNED_LTE, - SPECIAL_UNSIGNED_GTE, -}; - -struct string { - unsigned int length:31; - unsigned int immutable:1; - char data[]; -}; - -/* will fit into 32 bits */ -struct argcount { - unsigned normal:10; - unsigned quoted:10; - unsigned str:10; - unsigned vararg:1; -}; - -/* - * This is a very common data structure, it should be kept - * as small as humanly possible. Big (rare) types go as - * pointers. - */ -struct token { - struct position pos; - struct token *next; - union { - const char *number; - struct ident *ident; - unsigned int special; - struct string *string; - int argnum; - struct argcount count; - char embedded[4]; - }; -}; - -static inline struct token *dmrC_containing_token(struct token **p) -{ - void *addr = (char *)p - ((char *)&((struct token *)0)->next - (char *)0); - return (struct token *)addr; -} - -struct tokenizer_state_t { - unsigned int tabstop; - int input_stream_nr; - struct stream *input_streams; - int input_streams_allocated; - char special[256]; // identifies CR LF TAB - long cclass[257]; // character class - unsigned char hash_results[32][2]; // hashes compound operators - int code[32]; // token values for compound operators - char special_buffer[4]; - char ident_buffer[256]; - char string_buffer[4 * MAX_STRING + 3]; - char char_buffer[MAX_STRING + 4]; - char quote_buffer[2 * MAX_STRING + 6]; - char token_buffer[256]; - char quoted_token_buffer[256]; - char number_buffer[4095]; - char string_buffer2[MAX_STRING]; - struct ident **hash_table; - int ident_hit, ident_miss, idents; - const char **includepath; -}; - - -#define dmrC_token_type(x) ((x)->pos.type) - -/* - * Last token in the stream - points to itself. - * This allows us to not test for NULL pointers - * when following the token->next chain.. - */ -extern struct token dmrC_eof_token_entry_; -#define dmrC_eof_token(x) ((x) == &dmrC_eof_token_entry_) -extern void dmrC_init_tokenizer(struct dmr_C *C); -extern void dmrC_destroy_tokenizer(struct dmr_C *C); - -extern int dmrC_init_stream(struct dmr_C *C, const char *name, int fd, - const char **next_path); -extern const char *dmrC_stream_name(struct dmr_C *C, int stream); -extern struct ident *dmrC_hash_ident(struct dmr_C *C, struct ident *ident); -extern struct ident *dmrC_built_in_ident(struct dmr_C *C, const char *name); -extern struct token *dmrC_built_in_token(struct dmr_C *C, int stream, struct ident *ident); -extern const char *dmrC_show_special(struct dmr_C *C, int val); -extern const char *dmrC_show_ident(struct dmr_C *C, const struct ident *ident); -extern const char *dmrC_show_string(struct dmr_C *C, const struct string *string); -extern const char *dmrC_show_token(struct dmr_C *C, const struct token *token); -extern const char *dmrC_quote_token(struct dmr_C *C, const struct token *token); -extern int *dmrC_hash_stream(const char *name); -extern struct token *dmrC_tokenize(struct dmr_C *C, const char *name, int fd, - struct token *endtoken, const char **next_path); -/* This function assumes that stream 0 is being used - so it is not suitable - for general use */ -extern struct token *dmrC_tokenize_buffer(struct dmr_C *C, unsigned char *buffer, - unsigned long size, - struct token **endtoken); -/* This version allows a named stream to be created */ -extern struct token *dmrC_tokenize_buffer_stream(struct dmr_C *C, - const char *name, - unsigned char *buffer, - unsigned long size, - struct token **endtoken); -extern void dmrC_show_identifier_stats(struct dmr_C *C); -extern struct token *dmrC_preprocess(struct dmr_C *C, struct token *); -extern void dmrC_init_preprocessor_state(struct dmr_C *C); -static inline int dmrC_match_op(struct token *token, unsigned int op) -{ - return token->pos.type == TOKEN_SPECIAL && token->special == op; -} - -static inline int dmrC_match_ident(struct token *token, struct ident *id) -{ - return token->pos.type == TOKEN_IDENT && token->ident == id; -} - -static inline void dmrC_add_ident(struct dmr_C *C, struct ident_list **list, struct ident *ident) -{ - ptrlist_add((struct ptr_list **)list, ident, &C->ptrlist_allocator); -} - -extern int dmrC_test_tokenizer(); - -#ifdef __cplusplus -} -#endif - - -#endif \ No newline at end of file diff --git a/dmr_c/src/tokenize.c b/dmr_c/src/tokenize.c deleted file mode 100644 index 0304f4b..0000000 --- a/dmr_c/src/tokenize.c +++ /dev/null @@ -1,1190 +0,0 @@ -/* -* This is a really stupid C tokenizer. It doesn't do any include -* files or anything complex at all. That's the preprocessor. -* -* Copyright (C) 2003 Transmeta Corp. -* 2003 Linus Torvalds -* -* Permission is hereby granted, free of charge, to any person obtaining a copy -* of this software and associated documentation files (the "Software"), to deal -* in the Software without restriction, including without limitation the rights -* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -* copies of the Software, and to permit persons to whom the Software is -* furnished to do so, subject to the following conditions: -* -* The above copyright notice and this permission notice shall be included in -* all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -* THE SOFTWARE. -*/ -/* -* This version is part of the dmr_c project. -* Copyright (C) 2017 Dibyendu Majumdar -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#define EOF (-1) -#define BUFSIZE (8192) - -typedef struct { - int fd, offset, size; - int pos, line, nr; - int newline, whitespace; - struct token **tokenlist; - struct token *token; - unsigned char *buffer; -} stream_t; - -const char *dmrC_stream_name(struct dmr_C *C, int stream) -{ - if (stream == 0 && C->T->input_stream_nr == 0) - return ""; - if (stream < 0 || stream > C->T->input_stream_nr) - return ""; - return C->T->input_streams[stream].name; -} - -static struct position stream_pos(stream_t *stream) -{ - struct position pos; - pos.type = 0; - pos.stream = stream->nr; - pos.newline = stream->newline; - pos.whitespace = stream->whitespace; - pos.pos = stream->pos; - pos.line = stream->line; - pos.noexpand = 0; - return pos; -} - -const char *dmrC_show_special(struct dmr_C *C, int val) -{ - C->T->special_buffer[0] = val; - C->T->special_buffer[1] = 0; - if (val >= SPECIAL_BASE) - strcpy(C->T->special_buffer, - (char *)dmrC_combinations_[val - SPECIAL_BASE]); - return C->T->special_buffer; -} - -const char *dmrC_show_ident(struct dmr_C *C, const struct ident *ident) -{ - if (!ident) - return ""; - sprintf(C->T->ident_buffer, "%.*s", ident->len, ident->name); - return C->T->ident_buffer; -} - -static char *charstr(char *ptr, unsigned char c, unsigned char escape, unsigned char next) -{ - if (isprint(c)) { - if (c == escape || c == '\\') - *ptr++ = '\\'; - *ptr++ = c; - return ptr; - } - *ptr++ = '\\'; - switch (c) { - case '\n': - *ptr++ = 'n'; - return ptr; - case '\t': - *ptr++ = 't'; - return ptr; - } - if (!isdigit(next)) - return ptr + sprintf(ptr, "%o", c); - - return ptr + sprintf(ptr, "%03o", c); -} - -const char *dmrC_show_string(struct dmr_C *C, const struct string *string) -{ - char *ptr; - int i; - - if (!string->length) - return ""; - ptr = C->T->string_buffer; - *ptr++ = '"'; - for (i = 0; i < string->length - 1; i++) { - const char *p = string->data + i; - ptr = charstr(ptr, p[0], '"', p[1]); - } - *ptr++ = '"'; - *ptr = '\0'; - return C->T->string_buffer; -} - -static const char *show_char(struct dmr_C *C, const char *s, size_t len, char prefix, char delim) -{ - char *p = C->T->char_buffer; - if (prefix) - *p++ = prefix; - *p++ = delim; - memcpy(p, s, len); - p += len; - *p++ = delim; - *p++ = '\0'; - return C->T->char_buffer; -} - -static const char *quote_char(struct dmr_C *C, const char *s, size_t len, char prefix, char delim) -{ - size_t i; - char *p = C->T->quote_buffer; - if (prefix) - *p++ = prefix; - if (delim == '"') - *p++ = '\\'; - *p++ = delim; - for (i = 0; i < len; i++) { - if (s[i] == '"' || s[i] == '\\') - *p++ = '\\'; - *p++ = s[i]; - } - if (delim == '"') - *p++ = '\\'; - *p++ = delim; - *p++ = '\0'; - return C->T->quote_buffer; -} - -const char *dmrC_show_token(struct dmr_C *C, const struct token *token) -{ - if (!token) - return ""; - switch (dmrC_token_type(token)) { - case TOKEN_ERROR: - return "syntax error"; - - case TOKEN_EOF: - return "end-of-input"; - - case TOKEN_IDENT: - return dmrC_show_ident(C, token->ident); - - case TOKEN_NUMBER: - return token->number; - - case TOKEN_SPECIAL: - return dmrC_show_special(C, token->special); - - case TOKEN_CHAR: - return show_char(C, token->string->data, - token->string->length - 1, 0, '\''); - case TOKEN_CHAR_EMBEDDED_0: - case TOKEN_CHAR_EMBEDDED_1: - case TOKEN_CHAR_EMBEDDED_2: - case TOKEN_CHAR_EMBEDDED_3: - return show_char(C, token->embedded, - dmrC_token_type(token) - TOKEN_CHAR, 0, '\''); - case TOKEN_WIDE_CHAR: - return show_char(C, token->string->data, - token->string->length - 1, 'L', '\''); - case TOKEN_WIDE_CHAR_EMBEDDED_0: - case TOKEN_WIDE_CHAR_EMBEDDED_1: - case TOKEN_WIDE_CHAR_EMBEDDED_2: - case TOKEN_WIDE_CHAR_EMBEDDED_3: - return show_char(C, token->embedded, - dmrC_token_type(token) - TOKEN_WIDE_CHAR, 'L', '\''); - case TOKEN_STRING: - return show_char(C, token->string->data, - token->string->length - 1, 0, '"'); - case TOKEN_WIDE_STRING: - return show_char(C, token->string->data, - token->string->length - 1, 'L', '"'); - - case TOKEN_STREAMBEGIN: - snprintf(C->T->token_buffer, sizeof C->T->token_buffer, - "", - dmrC_stream_name(C, token->pos.stream)); - return C->T->token_buffer; - - case TOKEN_STREAMEND: - snprintf(C->T->token_buffer, sizeof C->T->token_buffer, - "", dmrC_stream_name(C, token->pos.stream)); - return C->T->token_buffer; - - case TOKEN_UNTAINT: - snprintf(C->T->token_buffer, sizeof C->T->token_buffer, - ""); - return C->T->token_buffer; - - case TOKEN_ARG_COUNT: - snprintf(C->T->token_buffer, sizeof C->T->token_buffer, - ""); - return C->T->token_buffer; - - default: - snprintf(C->T->token_buffer, sizeof C->T->token_buffer, - "unhandled token type '%d' ", dmrC_token_type(token)); - return C->T->token_buffer; - } -} - -const char *dmrC_quote_token(struct dmr_C *C, const struct token *token) -{ - switch (dmrC_token_type(token)) { - case TOKEN_ERROR: - return "syntax error"; - - case TOKEN_IDENT: - return dmrC_show_ident(C, token->ident); - - case TOKEN_NUMBER: - return token->number; - - case TOKEN_SPECIAL: - return dmrC_show_special(C, token->special); - - case TOKEN_CHAR: - return quote_char(C, token->string->data, - token->string->length - 1, 0, '\''); - case TOKEN_CHAR_EMBEDDED_0: - case TOKEN_CHAR_EMBEDDED_1: - case TOKEN_CHAR_EMBEDDED_2: - case TOKEN_CHAR_EMBEDDED_3: - return quote_char(C, token->embedded, - dmrC_token_type(token) - TOKEN_CHAR, 0, '\''); - case TOKEN_WIDE_CHAR: - return quote_char(C, token->string->data, - token->string->length - 1, 'L', '\''); - case TOKEN_WIDE_CHAR_EMBEDDED_0: - case TOKEN_WIDE_CHAR_EMBEDDED_1: - case TOKEN_WIDE_CHAR_EMBEDDED_2: - case TOKEN_WIDE_CHAR_EMBEDDED_3: - return quote_char(C, token->embedded, - dmrC_token_type(token) - TOKEN_WIDE_CHAR, 'L', - '\''); - case TOKEN_STRING: - return quote_char(C, token->string->data, - token->string->length - 1, 0, '"'); - case TOKEN_WIDE_STRING: - return quote_char(C, token->string->data, - token->string->length - 1, 'L', '"'); - default: - snprintf(C->T->quoted_token_buffer, - sizeof C->T->quoted_token_buffer, - "unhandled token type '%d' ", dmrC_token_type(token)); - return C->T->quoted_token_buffer; - } -} - -#define HASHED_INPUT_BITS (6) -#define HASHED_INPUT (1 << HASHED_INPUT_BITS) -#define HASH_PRIME 0x9e370001UL - -#ifndef _MSC_VER -static int input_stream_hashes[HASHED_INPUT] = {[0 ... HASHED_INPUT - 1] = -1}; -#else -static int input_stream_hashes[HASHED_INPUT] = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}; -#endif - -int *dmrC_hash_stream(const char *name) -{ - uint32_t hash = 0; - unsigned char c; - - while ((c = *name++) != 0) - hash = (hash + (c << 4) + (c >> 4)) * 11; - - hash *= HASH_PRIME; - hash >>= 32 - HASHED_INPUT_BITS; - return input_stream_hashes + hash; -} - -int dmrC_init_stream(struct dmr_C *C, const char *name, int fd, const char **next_path) -{ - int stream = C->T->input_stream_nr, *hash; - struct stream *current; - - if (stream >= C->T->input_streams_allocated) { - int newalloc = stream * 4 / 3 + 10; - C->T->input_streams = (struct stream *)realloc(C->T->input_streams, newalloc * sizeof(struct stream)); - if (!C->T->input_streams) - dmrC_die(C, "Unable to allocate more streams space"); - C->T->input_streams_allocated = newalloc; - } - current = C->T->input_streams + stream; - memset(current, 0, sizeof(*current)); - current->name = name; - current->fd = fd; - current->next_path = next_path; - current->path = NULL; - current->constant = CONSTANT_FILE_MAYBE; - C->T->input_stream_nr = stream + 1; - hash = dmrC_hash_stream(name); - current->next_stream = *hash; - *hash = stream; - return stream; -} - -static struct token *alloc_token(struct dmr_C *C, stream_t *stream) -{ - struct token *token = (struct token *)dmrC_allocator_allocate(&C->token_allocator, 0); - token->pos = stream_pos(stream); - return token; -} - -/* -* Argh... That was surprisingly messy - handling '\r' complicates the -* things a _lot_. -*/ -static int nextchar_slow(struct dmr_C *C, stream_t *stream) -{ - int offset = stream->offset; - int size = stream->size; - int c; - int spliced = 0, had_cr, had_backslash; - -restart: - had_cr = had_backslash = 0; - -repeat: - if (offset >= size) { - if (stream->fd < 0) - goto got_eof; - size = read(stream->fd, stream->buffer, BUFSIZE); - if (size <= 0) - goto got_eof; - stream->size = size; - stream->offset = offset = 0; - } - - c = stream->buffer[offset++]; - if (had_cr) - goto check_lf; - - if (c == '\r') { - had_cr = 1; - goto repeat; - } - -norm: - if (!had_backslash) { - switch (c) { - case '\t': - stream->pos += C->T->tabstop - stream->pos % C->T->tabstop; - break; - case '\n': - stream->line++; - stream->pos = 0; - stream->newline = 1; - break; - case '\\': - had_backslash = 1; - stream->pos++; - goto repeat; - default: - stream->pos++; - } - } else { - if (c == '\n') { - stream->line++; - stream->pos = 0; - spliced = 1; - goto restart; - } - offset--; - c = '\\'; - } -out: - stream->offset = offset; - - return c; - -check_lf: - if (c != '\n') - offset--; - c = '\n'; - goto norm; - -got_eof: - if (had_backslash) { - c = '\\'; - goto out; - } - if (stream->pos) - dmrC_warning(C, stream_pos(stream), "no newline at end of file"); - else if (spliced) - dmrC_warning(C, stream_pos(stream), "backslash-newline at end of file"); - return EOF; -} - -/* -* We want that as light as possible while covering all normal cases. -* Slow path (including the logics with line-splicing and EOF sanity -* checks) is in nextchar_slow(). -*/ -static inline int nextchar(struct dmr_C *C, stream_t *stream) -{ - int offset = stream->offset; - - if (offset < stream->size) { - int c = stream->buffer[offset++]; - if (!C->T->special[c]) { - stream->offset = offset; - stream->pos++; - return c; - } - } - return nextchar_slow(C, stream); -} - -struct token dmrC_eof_token_entry_; - -static struct token *mark_eof(struct dmr_C *C, stream_t *stream) -{ - struct token *end; - - end = alloc_token(C, stream); - dmrC_token_type(end) = TOKEN_STREAMEND; - end->pos.newline = 1; - - dmrC_eof_token_entry_.next = &dmrC_eof_token_entry_; - dmrC_eof_token_entry_.pos.newline = 1; - - end->next = &dmrC_eof_token_entry_; - *stream->tokenlist = end; - stream->tokenlist = NULL; - return end; -} - -static void add_token(stream_t *stream) -{ - struct token *token = stream->token; - - stream->token = NULL; - token->next = NULL; - *stream->tokenlist = token; - stream->tokenlist = &token->next; -} - -static void drop_token(stream_t *stream) -{ - stream->newline |= stream->token->pos.newline; - stream->whitespace |= stream->token->pos.whitespace; - stream->token = NULL; -} - -enum { - Letter = 1, - Digit = 2, - Hex = 4, - Exp = 8, - Dot = 16, - ValidSecond = 32, - Quote = 64, -}; - -/* -* pp-number: -* digit -* . digit -* pp-number digit -* pp-number identifier-nodigit -* pp-number e sign -* pp-number E sign -* pp-number p sign -* pp-number P sign -* pp-number . -*/ -static int get_one_number(struct dmr_C *C, int c, int next, stream_t *stream) -{ - struct token *token; - char *buffer = C->T->number_buffer; - char *p = buffer, *buf, *buffer_end = buffer + sizeof C->T->number_buffer; - size_t len; - - *p++ = c; - for (;;) { - long kclass = C->T->cclass[next + 1]; - if (!(kclass & (Dot | Digit | Letter))) - break; - if (p != buffer_end) - *p++ = next; - next = nextchar(C, stream); - if (kclass & Exp) { - if (next == '-' || next == '+') { - if (p != buffer_end) - *p++ = next; - next = nextchar(C, stream); - } - } - } - - if (p == buffer_end) { - dmrC_sparse_error(C, stream_pos(stream), - "number token exceeds %td characters", - buffer_end - buffer); - // Pretend we saw just "1". - buffer[0] = '1'; - p = buffer + 1; - } - - *p++ = 0; - len = p - buffer; - buf = (char *)dmrC_allocator_allocate(&C->byte_allocator, len); - memcpy(buf, buffer, len); - - token = stream->token; - dmrC_token_type(token) = TOKEN_NUMBER; - token->number = buf; - add_token(stream); - - return next; -} - -static int eat_string(struct dmr_C *C, int next, stream_t *stream, - enum e_token_type type) -{ - char *buffer = C->T->string_buffer2; - struct string *string; - struct token *token = stream->token; - int len = 0; - int escape; - int want_hex = 0; - char delim = type < TOKEN_STRING ? '\'' : '"'; - - for (escape = 0; escape || next != delim; next = nextchar(C, stream)) { - if (len < MAX_STRING) - buffer[len] = next; - len++; - if (next == '\n') { - dmrC_warning(C, stream_pos(stream), - "Newline in string or character constant"); - if (delim == '\'') /* assume it's lost ' */ - break; - } - if (next == EOF) { - dmrC_warning(C, stream_pos(stream), - "End of file in middle of string"); - return next; - } - if (!escape) { - if (want_hex && !(C->T->cclass[next + 1] & Hex)) - dmrC_warning( - C, stream_pos(stream), - "\\x used with no following hex digits"); - want_hex = 0; - escape = next == '\\'; - } else { - escape = 0; - want_hex = next == 'x'; - } - } - if (want_hex) - dmrC_warning(C, stream_pos(stream), - "\\x used with no following hex digits"); - if (len > MAX_STRING) { - dmrC_warning(C, stream_pos(stream), - "string too long (%d bytes, %d bytes max)", len, MAX_STRING); - len = MAX_STRING; - } - if (delim == '\'' && len <= 4) { - if (len == 0) { - dmrC_sparse_error(C, stream_pos(stream), - "empty character constant"); - return nextchar(C, stream); - } - dmrC_token_type(token) = type + len; - memset(buffer + len, '\0', 4 - len); - memcpy(token->embedded, buffer, 4); - } else { - dmrC_token_type(token) = type; - string = (struct string *)dmrC_allocator_allocate(&C->string_allocator, len + 1); - memcpy(string->data, buffer, len); - string->data[len] = '\0'; - string->length = len + 1; - token->string = string; - } - - /* Pass it on.. */ - token = stream->token; - add_token(stream); - return nextchar(C, stream); -} - -static int drop_stream_eoln(struct dmr_C *C, stream_t *stream) -{ - drop_token(stream); - for (;;) { - switch (nextchar(C, stream)) { - case EOF: - return EOF; - case '\n': - return nextchar(C, stream); - } - } -} - -static int drop_stream_comment(struct dmr_C *C, stream_t *stream) -{ - int newline; - int next; - drop_token(stream); - newline = stream->newline; - - next = nextchar(C, stream); - for (;;) { - int curr = next; - if (curr == EOF) { - dmrC_warning(C, stream_pos(stream), - "End of file in the middle of a comment"); - return curr; - } - next = nextchar(C, stream); - if (curr == '*' && next == '/') - break; - } - stream->newline = newline; - return nextchar(C, stream); -} - -unsigned char dmrC_combinations_[][4] = COMBINATION_STRINGS; - -#define NR_COMBINATIONS (SPECIAL_ARG_SEPARATOR - SPECIAL_BASE) - -/* hash function for two-character punctuators - all give unique values */ -#define special_hash(c0, c1) (((c0*8+c1*2)+((c0*8+c1*2)>>5))&31) - -static int get_one_special(struct dmr_C *C, int c, stream_t *stream) -{ - struct token *token; - int next, value, i; - - next = nextchar(C, stream); - - /* - * Check for numbers, strings, character constants, and comments - */ - switch (c) { - case '.': - if (next >= '0' && next <= '9') - return get_one_number(C, c, next, stream); - break; - case '"': - return eat_string(C, next, stream, TOKEN_STRING); - case '\'': - return eat_string(C, next, stream, TOKEN_CHAR); - case '/': - if (next == '/') - return drop_stream_eoln(C, stream); - if (next == '*') - return drop_stream_comment(C, stream); - } - - /* - * Check for combinations - */ - value = c; - if (C->T->cclass[next + 1] & ValidSecond) { - i = special_hash(c, next); - if (C->T->hash_results[i][0] == c && C->T->hash_results[i][1] == next) { - value = C->T->code[i]; - next = nextchar(C, stream); - if (value >= SPECIAL_LEFTSHIFT && - next == "==."[value - SPECIAL_LEFTSHIFT]) { - value += 3; - next = nextchar(C, stream); - } - } - } - - /* Pass it on.. */ - token = stream->token; - dmrC_token_type(token) = TOKEN_SPECIAL; - token->special = value; - add_token(stream); - return next; -} - -#define IDENT_HASH_BITS (13) -#define IDENT_HASH_SIZE (1<> IDENT_HASH_BITS) + (hash)) & IDENT_HASH_MASK) - -void dmrC_show_identifier_stats(struct dmr_C *C) -{ - int i; - int distribution[100]; - - fprintf(stderr, "identifiers: %d hits, %d misses\n", - C->T->ident_hit, C->T->ident_miss); - - for (i = 0; i < 100; i++) - distribution[i] = 0; - - for (i = 0; i < IDENT_HASH_SIZE; i++) { - struct ident *ident = C->T->hash_table[i]; - int count = 0; - - while (ident) { - count++; - ident = ident->next; - } - if (count > 99) - count = 99; - distribution[count]++; - } - - for (i = 0; i < 100; i++) { - if (distribution[i]) - fprintf(stderr, "%2d: %d buckets\n", i, - distribution[i]); - } -} - -static struct ident *alloc_ident(struct dmr_C *C, const char *name, size_t len) -{ - struct ident *ident = (struct ident *)dmrC_allocator_allocate(&C->ident_allocator, len); - ident->symbols = NULL; - assert(len <= 256); - ident->len = (unsigned char)len; - ident->tainted = 0; - memcpy(ident->name, name, len); - return ident; -} - -static struct ident *insert_hash(struct dmr_C *C, struct ident *ident, - unsigned long hash) -{ - ident->next = C->T->hash_table[hash]; - C->T->hash_table[hash] = ident; - C->T->ident_miss++; - return ident; -} - -static struct ident *create_hashed_ident(struct dmr_C *C, const char *name, - size_t len, unsigned long hash) -{ - struct ident *ident; - struct ident **p; - - p = &C->T->hash_table[hash]; - while ((ident = *p) != NULL) { - if (ident->len == (unsigned char) len) { - if (strncmp(name, ident->name, len) != 0) - goto next; - - C->T->ident_hit++; - return ident; - } -next: - //misses++; - p = &ident->next; - } - ident = alloc_ident(C, name, len); - *p = ident; - ident->next = NULL; - C->T->ident_miss++; - C->T->idents++; - return ident; -} - -static unsigned long hash_name(const char *name, int len) -{ - unsigned long hash; - const unsigned char *p = (const unsigned char *)name; - - hash = ident_hash_init(*p++); - while (--len) { - unsigned int i = *p++; - hash = ident_hash_add(hash, i); - } - return ident_hash_end(hash); -} - -struct ident *dmrC_hash_ident(struct dmr_C *C, struct ident *ident) -{ - return insert_hash(C, ident, hash_name(ident->name, (int)ident->len)); -} - -struct ident *dmrC_built_in_ident(struct dmr_C *C, const char *name) -{ - size_t len = strlen(name); - return create_hashed_ident(C, name, len, hash_name(name, (int)len)); -} - -struct token *dmrC_built_in_token(struct dmr_C *C, int stream, struct ident *ident) -{ - struct token *token; - - token = (struct token *)dmrC_allocator_allocate(&C->token_allocator, 0); - token->pos.stream = stream; - dmrC_token_type(token) = TOKEN_IDENT; - token->ident = ident; - return token; -} - -static int get_one_identifier(struct dmr_C *C, int c, stream_t *stream) -{ - struct token *token; - struct ident *ident; - unsigned long hash; - char buf[256]; - int len = 1; - int next; - - hash = ident_hash_init(c); - buf[0] = c; - for (;;) { - next = nextchar(C, stream); - if (!(C->T->cclass[next + 1] & (Letter | Digit))) - break; - if (len >= (int)sizeof(buf)) - break; - hash = ident_hash_add(hash, next); - buf[len] = next; - len++; - }; - if (C->T->cclass[next + 1] & Quote) { - if (len == 1 && buf[0] == 'L') { - if (next == '\'') - return eat_string(C, nextchar(C, stream), - stream, TOKEN_WIDE_CHAR); - else - return eat_string(C, nextchar(C, stream), - stream, TOKEN_WIDE_STRING); - } - } - hash = ident_hash_end(hash); - ident = create_hashed_ident(C, buf, len, hash); - - /* Pass it on.. */ - token = stream->token; - dmrC_token_type(token) = TOKEN_IDENT; - token->ident = ident; - add_token(stream); - return next; -} - -static int get_one_token(struct dmr_C *C, int c, stream_t *stream) -{ - long kclass = C->T->cclass[c + 1]; - if (kclass & Digit) - return get_one_number(C, c, nextchar(C, stream), stream); - if (kclass & Letter) - return get_one_identifier(C, c, stream); - return get_one_special(C, c, stream); -} - -static struct token *setup_stream(struct dmr_C *C, stream_t *stream, - int idx, int fd, unsigned char *buf, - unsigned int buf_size) -{ - struct token *begin; - - stream->nr = idx; - stream->line = 1; - stream->newline = 1; - stream->whitespace = 0; - stream->pos = 0; - - stream->token = NULL; - stream->fd = fd; - stream->offset = 0; - stream->size = buf_size; - stream->buffer = buf; - - begin = alloc_token(C, stream); - dmrC_token_type(begin) = TOKEN_STREAMBEGIN; - stream->tokenlist = &begin->next; - return begin; -} - -static struct token *tokenize_stream(struct dmr_C *C, stream_t *stream) -{ - int c = nextchar(C, stream); - while (c != EOF) { - if (!isspace(c)) { - struct token *token = alloc_token(C, stream); - stream->token = token; - stream->newline = 0; - stream->whitespace = 0; - c = get_one_token(C, c, stream); - continue; - } - stream->whitespace = 1; - c = nextchar(C, stream); - } - return mark_eof(C, stream); -} - -struct token *dmrC_tokenize_buffer(struct dmr_C *C, unsigned char *buffer, - unsigned long size, struct token **endtoken) -{ - stream_t stream; - struct token *begin; - - begin = setup_stream(C, &stream, 0, -1, buffer, size); - *endtoken = tokenize_stream(C, &stream); - return begin; -} - -struct token *dmrC_tokenize_buffer_stream(struct dmr_C *C, const char *name, - unsigned char *buffer, - unsigned long size, - struct token **endtoken) -{ - stream_t stream; - struct token *begin; - int idx; - - idx = dmrC_init_stream(C, name, -1, C->includepath); - if (idx < 0) { - return NULL; - } - begin = setup_stream(C, &stream, idx, -1, buffer, size); - *endtoken = tokenize_stream(C, &stream); - return begin; -} - -struct token *dmrC_tokenize(struct dmr_C *C, const char *name, int fd, - struct token *endtoken, const char **next_path) -{ - struct token *begin, *end; - stream_t stream; - unsigned char buffer[BUFSIZE]; - int idx; - - idx = dmrC_init_stream(C, name, fd, next_path); - if (idx < 0) { - // dmrC_info(endtoken->pos, "File %s is const", name); - return endtoken; - } - - begin = setup_stream(C, &stream, idx, fd, buffer, 0); - end = tokenize_stream(C, &stream); - if (endtoken) - end->next = endtoken; - return begin; -} - -void dmrC_init_tokenizer(struct dmr_C *C) -{ - C->T = (struct tokenizer_state_t *)calloc( - 1, sizeof(struct tokenizer_state_t)); - C->T->tabstop = 8; - - C->T->special['\t'] = 1; - C->T->special['\r'] = 1; - C->T->special['\n'] = 1; - C->T->special['\\'] = 1; - - C->T->cclass['0' + 1] = Digit | Hex; /* \ */ - C->T->cclass['1' + 1] = Digit | Hex; /* \ */ - C->T->cclass['2' + 1] = Digit | Hex; /* \ */ - C->T->cclass['3' + 1] = Digit | Hex; /* \ */ - C->T->cclass['4' + 1] = Digit | Hex; /* \ */ - C->T->cclass['5' + 1] = Digit | Hex; /* \ */ - C->T->cclass['6' + 1] = Digit | Hex; /* \ */ - C->T->cclass['7' + 1] = Digit | Hex; /* \ */ - C->T->cclass['8' + 1] = Digit | Hex; - C->T->cclass['9' + 1] = Digit | Hex; - C->T->cclass['A' + 1] = Letter | Hex; - C->T->cclass['B' + 1] = Letter | Hex; - C->T->cclass['C' + 1] = Letter | Hex; - C->T->cclass['D' + 1] = Letter | Hex; - C->T->cclass['E' + 1] = Letter | Hex | Exp; /* E */ - C->T->cclass['F' + 1] = Letter | Hex; - C->T->cclass['G' + 1] = Letter; - C->T->cclass['H' + 1] = Letter; - C->T->cclass['I' + 1] = Letter; - C->T->cclass['J' + 1] = Letter; - C->T->cclass['K' + 1] = Letter; - C->T->cclass['L' + 1] = Letter; - C->T->cclass['M' + 1] = Letter; - C->T->cclass['N' + 1] = Letter; - C->T->cclass['O' + 1] = Letter; - C->T->cclass['P' + 1] = Letter | Exp; /* P */ - C->T->cclass['Q' + 1] = Letter; - C->T->cclass['R' + 1] = Letter; - C->T->cclass['S' + 1] = Letter; - C->T->cclass['T' + 1] = Letter; - C->T->cclass['U' + 1] = Letter; - C->T->cclass['V' + 1] = Letter; - C->T->cclass['W' + 1] = Letter; - C->T->cclass['X' + 1] = Letter; - C->T->cclass['Y' + 1] = Letter; - C->T->cclass['Z' + 1] = Letter; - C->T->cclass['a' + 1] = Letter | Hex; /* \a, \b */ - C->T->cclass['b' + 1] = Letter | Hex; /* \a, \b */ - C->T->cclass['c' + 1] = Letter | Hex; - C->T->cclass['d' + 1] = Letter | Hex; - C->T->cclass['e' + 1] = Letter | Hex | Exp; /* \e, e */ - C->T->cclass['f' + 1] = Letter | Hex; /* \f */ - C->T->cclass['g' + 1] = Letter; - C->T->cclass['h' + 1] = Letter; - C->T->cclass['i' + 1] = Letter; - C->T->cclass['j' + 1] = Letter; - C->T->cclass['k' + 1] = Letter; - C->T->cclass['l' + 1] = Letter; - C->T->cclass['m' + 1] = Letter; - C->T->cclass['n' + 1] = Letter; /* \n */ - C->T->cclass['o' + 1] = Letter; - C->T->cclass['p' + 1] = Letter | Exp; /* p */ - C->T->cclass['q' + 1] = Letter; - C->T->cclass['r' + 1] = Letter; /* \r */ - C->T->cclass['s' + 1] = Letter; - C->T->cclass['t' + 1] = Letter; /* \t */ - C->T->cclass['u' + 1] = Letter; - C->T->cclass['v' + 1] = Letter; /* \v */ - C->T->cclass['w' + 1] = Letter; - C->T->cclass['x' + 1] = Letter; /* \x */ - C->T->cclass['y' + 1] = Letter; - C->T->cclass['z' + 1] = Letter; - C->T->cclass['_' + 1] = Letter; - C->T->cclass['.' + 1] = Dot | ValidSecond; - C->T->cclass['=' + 1] = ValidSecond; - C->T->cclass['+' + 1] = ValidSecond; - C->T->cclass['-' + 1] = ValidSecond; - C->T->cclass['>' + 1] = ValidSecond; - C->T->cclass['<' + 1] = ValidSecond; - C->T->cclass['&' + 1] = ValidSecond; - C->T->cclass['|' + 1] = ValidSecond; - C->T->cclass['#' + 1] = ValidSecond; - C->T->cclass['\'' + 1] = Quote; - C->T->cclass['"' + 1] = Quote; - -/* -* note that we won't get false positives - special_hash(0,0) is 0 and -* entry 0 is filled (by +=), so all the missing ones are OK. -*/ -#define RES(c0, c1) \ - C->T->hash_results[special_hash(c0, c1)][0] = c0, \ - C->T->hash_results[special_hash(c0, c1)][1] = c1 - RES('+', '='); /* 00 */ - RES('/', '='); /* 01 */ - RES('^', '='); /* 05 */ - RES('&', '&'); /* 07 */ - RES('#', '#'); /* 08 */ - RES('<', '<'); /* 0a */ - RES('<', '='); /* 0c */ - RES('!', '='); /* 0e */ - RES('%', '='); /* 0f */ - RES('-', '-'); /* 10 */ - RES('-', '='); /* 11 */ - RES('-', '>'); /* 13 */ - RES('=', '='); /* 15 */ - RES('&', '='); /* 17 */ - RES('*', '='); /* 18 */ - RES('.', '.'); /* 1a */ - RES('+', '+'); /* 1b */ - RES('|', '='); /* 1c */ - RES('>', '='); /* 1d */ - RES('|', '|'); /* 1e */ - RES('>', '>'); /* 1f */ -#undef RES - -#define CODE(c0, c1, value) C->T->code[special_hash(c0, c1)] = value - CODE('+', '=', SPECIAL_ADD_ASSIGN); /* 00 */ - CODE('/', '=', SPECIAL_DIV_ASSIGN); /* 01 */ - CODE('^', '=', SPECIAL_XOR_ASSIGN); /* 05 */ - CODE('&', '&', SPECIAL_LOGICAL_AND); /* 07 */ - CODE('#', '#', SPECIAL_HASHHASH); /* 08 */ - CODE('<', '<', SPECIAL_LEFTSHIFT); /* 0a */ - CODE('<', '=', SPECIAL_LTE); /* 0c */ - CODE('!', '=', SPECIAL_NOTEQUAL); /* 0e */ - CODE('%', '=', SPECIAL_MOD_ASSIGN); /* 0f */ - CODE('-', '-', SPECIAL_DECREMENT); /* 10 */ - CODE('-', '=', SPECIAL_SUB_ASSIGN); /* 11 */ - CODE('-', '>', SPECIAL_DEREFERENCE); /* 13 */ - CODE('=', '=', SPECIAL_EQUAL); /* 15 */ - CODE('&', '=', SPECIAL_AND_ASSIGN); /* 17 */ - CODE('*', '=', SPECIAL_MUL_ASSIGN); /* 18 */ - CODE('.', '.', SPECIAL_DOTDOT); /* 1a */ - CODE('+', '+', SPECIAL_INCREMENT); /* 1b */ - CODE('|', '=', SPECIAL_OR_ASSIGN); /* 1c */ - CODE('>', '=', SPECIAL_GTE); /* 1d */ - CODE('|', '|', SPECIAL_LOGICAL_OR); /* 1e */ - CODE('>', '>', SPECIAL_RIGHTSHIFT); /* 1f */ -#undef CODE - - C->T->hash_table = - (struct ident **)calloc(IDENT_HASH_SIZE, sizeof(struct ident *)); -} - -void dmrC_destroy_tokenizer(struct dmr_C *C) -{ - free(C->T->input_streams); - free(C->T->hash_table); - free(C->T); - C->T = NULL; -} - -int dmrC_test_tokenizer() -{ - struct dmr_C *C = new_dmr_C(); - char test1[100] = - "int main() { printf(\"hello world!\\n\"); return 0; }"; - const char *expected[] = {"", - "int", - "main", - "(", - ")", - "{", - "printf", - "(", - "\"hello world!\\n\"", - ")", - ";", - "return", - "0", - ";", - "}", - NULL}; - - struct token *start; - struct token *end; - start = dmrC_tokenize_buffer(C, (unsigned char *)test1, - (unsigned long)strlen(test1), &end); - int i = 0; - int failure_count = 0; - for (struct token *p = start; p != end; p = p->next) { - if (expected[i] == NULL) { - failure_count++; - break; - } - if (strcmp(dmrC_show_token(C, p), expected[i]) != 0) { - fprintf(stderr, "Expected '%s' got '%s'\n", expected[i], - dmrC_show_token(C, p)); - failure_count++; - break; - } - i++; - } - destroy_dmr_C(C); - if (failure_count == 0) { - printf("tokenizer hello world test okay\n"); - } - return failure_count; -} diff --git a/dmr_c/src/unssa.c b/dmr_c/src/unssa.c deleted file mode 100644 index b0a7c32..0000000 --- a/dmr_c/src/unssa.c +++ /dev/null @@ -1,148 +0,0 @@ -/* - * UnSSA - translate the SSA back to normal form. - * - * For now it's done by replacing to set of copies: - * 1) For each phi-node, replace all their phisrc by copies to a common - * temporary. - * 2) Replace all the phi-nodes by copies of the temporaries to the phi-node target. - * This is node to preserve the semantic of the phi-node (they should all "execute" - * simultaneously on entry in the basic block in which they belong). - * - * This is similar to the "Sreedhar method I" except that the copies to the - * temporaries are not placed at the end of the predecessor basic blocks, but - * at the place where the phi-node operands are defined. - * This is particulary easy since these copies are essentialy already present - * as the corresponding OP_PHISOURCE. - * - * While very simple this method create a lot more copies that really necessary. - * We eliminate some of these copies but most probably most of them are still - * useless. - * Ideally, "Sreedhar method III" should be used: - * "Translating Out of Static Single Assignment Form", V. C. Sreedhar, R. D.-C. Ju, - * D. M. Gillies and V. Santhanam. SAS'99, Vol. 1694 of Lecture Notes in Computer - * Science, Springer-Verlag, pp. 194-210, 1999. - * But for this we need precise liveness, on each %phi and not only on OP_PHI's - * target pseudos. - * - * Copyright (C) 2005 Luc Van Oostenryck - */ - -#include - -#include -#include -#include -#include -#include - -static inline int nbr_pseudo_users(pseudo_t p) -{ - return ptrlist_size((struct ptr_list *)p->users); -} - -static int simplify_phi_node(struct dmr_C *C, struct instruction *phi, pseudo_t tmp) -{ - pseudo_t target = phi->target; - struct pseudo_user *pu; - pseudo_t src; - - // verify if this phi can be simplified - FOR_EACH_PTR(phi->phi_list, src) { - struct instruction *def = src->def; - - if (!def) - continue; - if (def->bb == phi->bb) - return 0; - } END_FOR_EACH_PTR(src); - - // no need to make a copy of this one - // -> replace the target pseudo by the tmp - FOR_EACH_PTR(target->users, pu) { - dmrC_use_pseudo(C, pu->insn, tmp, pu->userp); - } END_FOR_EACH_PTR(pu); - - phi->bb = NULL; - return 1; -} - -static void replace_phi_node(struct dmr_C *C, struct instruction *phi) -{ - pseudo_t tmp; - pseudo_t p; - - tmp = dmrC_alloc_pseudo(C, NULL); - tmp->type = phi->target->type; - tmp->ident = phi->target->ident; - tmp->def = NULL; // defined by all the phisrc - - // can we avoid to make of copy? - simplify_phi_node(C, phi, tmp); - - // rewrite all it's phi_src to copy to a new tmp - FOR_EACH_PTR(phi->phi_list, p) { - struct instruction *def = p->def; - pseudo_t src; - - if (p == VOID_PSEUDO(C)) - continue; - - assert(def->opcode == OP_PHISOURCE); - - def->opcode = OP_COPY; - def->target = tmp; - - // can we eliminate the copy? - src = def->phi_src; - if (src->type != PSEUDO_REG) - continue; - switch (nbr_pseudo_users(src)) { - struct instruction *insn; - case 1: - insn = src->def; - if (!insn) - break; - insn->target = tmp; - case 0: - dmrC_kill_instruction(C, def); - def->bb = NULL; - } - } END_FOR_EACH_PTR(p); - - if (!phi->bb) - return; - - // rewrite the phi node: - // phi %rt, ... - // to: - // copy %rt, %tmp - phi->opcode = OP_COPY; - dmrC_use_pseudo(C, phi, tmp, &phi->src); -} - -static void rewrite_phi_bb(struct dmr_C *C, struct basic_block *bb) -{ - struct instruction *insn; - - // Replace all the phi-nodes by copies of a temporary - // (which represent the set of all the %phi that feed them). - // The target pseudo doesn't change. - FOR_EACH_PTR(bb->insns, insn) { - if (!insn->bb) - continue; - if (insn->opcode != OP_PHI) - continue; - replace_phi_node(C, insn); - } END_FOR_EACH_PTR(insn); -} - -int dmrC_unssa(struct dmr_C *C, struct entrypoint *ep) -{ - struct basic_block *bb; - - FOR_EACH_PTR(ep->bbs, bb) { - rewrite_phi_bb(C, bb); - } END_FOR_EACH_PTR(bb); - - return 0; -} diff --git a/dmr_c/src/walksymbol.c b/dmr_c/src/walksymbol.c deleted file mode 100644 index e705860..0000000 --- a/dmr_c/src/walksymbol.c +++ /dev/null @@ -1,868 +0,0 @@ -#include -#include -#include -#include -#include -#include - -#include - -static void walk_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor); -static void walk_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor); -static void walk_symbol_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor); -static void walk_assignment_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor); -static void walk_binary_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor); -static void walk_preop_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor); -static void walk_postop_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor); -static void walk_call_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor); -static void walk_cast_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor); -static void walk_conditional_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor); -static void walk_label_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor); -static void walk_initializer_expression(struct dmr_C *C, struct expression *expr, struct symbol *ctype, - struct symbol_visitor *visitor); -static void walk_label(struct dmr_C *C, struct symbol *label, struct symbol_visitor *visitor); -static void walk_return_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor); -static void walk_iterator_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor); -static void walk_switch_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor); - -void walk_return_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor) -{ - struct expression *expr = stmt->ret_value; - struct symbol *target = stmt->ret_target; - - if (expr && expr->ctype) { - walk_expression(C, expr, visitor); - } - visitor->begin_statement(visitor->data, STMT_GOTO); - dmrC_walk_symbol(C, target, visitor); - visitor->end_statement(visitor->data); -} - -void walk_label(struct dmr_C *C, struct symbol *label, struct symbol_visitor *visitor) -{ - visitor->begin_label(visitor->data, dmrC_show_ident(C, label->ident)); - dmrC_walk_symbol(C, label, visitor); - visitor->end_label(visitor->data); -} - -void walk_iterator_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor) -{ - struct statement *pre_statement = stmt->iterator_pre_statement; - struct expression *pre_condition = stmt->iterator_pre_condition; - struct statement *statement = stmt->iterator_statement; - struct statement *post_statement = stmt->iterator_post_statement; - struct expression *post_condition = stmt->iterator_post_condition; - dmrC_walk_symbol_list(C, stmt->iterator_syms, visitor); - if (pre_statement) { - visitor->begin_iterator_prestatement(visitor->data); - walk_statement(C, pre_statement, visitor); - visitor->end_iterator_prestatement(visitor->data); - } - if (pre_condition) { - visitor->begin_iterator_precondition(visitor->data); - walk_expression(C, pre_condition, visitor); - visitor->end_iterator_precondition(visitor->data); - } - visitor->begin_iterator_statement(visitor->data); - walk_statement(C, statement, visitor); - visitor->end_iterator_statement(visitor->data); - if (stmt->iterator_continue->used) { - walk_label(C, stmt->iterator_continue, visitor); - } - if (post_statement) { - visitor->begin_iterator_poststatement(visitor->data); - walk_statement(C, post_statement, visitor); - visitor->end_iterator_poststatement(visitor->data); - } - if (post_condition) { - visitor->begin_iterator_postcondition(visitor->data); - walk_expression(C, post_condition, visitor); - visitor->end_iterator_postcondition(visitor->data); - } - if (stmt->iterator_break->used) { - walk_label(C, stmt->iterator_break, visitor); - } -} - -void walk_switch_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor) -{ - walk_expression(C, stmt->switch_expression, visitor); - struct symbol *sym; - - /* - * Debugging only: Check that the case list is correct - * by printing it out. - * - * This is where a _real_ back-end would go through the - * cases to decide whether to use a lookup table or a - * series of comparisons etc - */ - FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) - { - struct statement *case_stmt = sym->stmt; - struct expression *expr = case_stmt->case_expression; - struct expression *to = case_stmt->case_to; - - if (!expr) { - visitor->begin_default_case(visitor->data); - } else { - if (expr->type == EXPR_VALUE) { - if (to) { - if (to->type == EXPR_VALUE) { - visitor->begin_case_range(visitor->data, expr->value, to->value); - } - } else { - visitor->begin_case_value(visitor->data, expr->value); - } - } - } - dmrC_walk_symbol(C, sym, visitor); - visitor->end_case(visitor->data); - } - END_FOR_EACH_PTR(sym); - - walk_statement(C, stmt->switch_statement, visitor); - - if (stmt->switch_break->used) - walk_label(C, stmt->switch_break, visitor); -} - -void walk_statement(struct dmr_C *C, struct statement *stmt, struct symbol_visitor *visitor) -{ - if (!stmt) - return; - - visitor->begin_statement(visitor->data, stmt->type); - switch (stmt->type) { - case STMT_DECLARATION: - dmrC_walk_symbol_list(C, stmt->declaration, visitor); - break; - case STMT_RETURN: - walk_return_statement(C, stmt, visitor); - break; - case STMT_COMPOUND: { - struct statement *s; - // if (stmt->inline_fn) { - // dmrC_show_statement(C, stmt->args); - // printf("\tbegin_inline \t%s\n", dmrC_show_ident(C, - // stmt->inline_fn->ident)); - //} - FOR_EACH_PTR(stmt->stmts, s) { walk_statement(C, s, visitor); } - END_FOR_EACH_PTR(s); - if (stmt->ret) { - walk_label(C, stmt->ret, visitor); - } - // if (stmt->inline_fn) - // printf("\tend_inlined\t%s\n", dmrC_show_ident(C, - // stmt->inline_fn->ident)); - break; - } - - case STMT_EXPRESSION: - walk_expression(C, stmt->expression, visitor); - break; - case STMT_IF: { - struct expression *cond = stmt->if_conditional; - walk_expression(C, cond, visitor); - visitor->begin_if_then(visitor->data); - walk_statement(C, stmt->if_true, visitor); - visitor->end_if_then(visitor->data); - if (stmt->if_false) { - visitor->begin_if_else(visitor->data); - walk_statement(C, stmt->if_false, visitor); - visitor->end_if_else(visitor->data); - } - break; - } - case STMT_SWITCH: - walk_switch_statement(C, stmt, visitor); - break; - - case STMT_CASE: - walk_label(C, stmt->case_label, visitor); - walk_statement(C, stmt->case_statement, visitor); - break; - - case STMT_ITERATOR: - walk_iterator_statement(C, stmt, visitor); - break; - - case STMT_NONE: - break; - - case STMT_LABEL: - visitor->begin_label(visitor->data, dmrC_show_ident(C, stmt->label_identifier->ident)); - dmrC_walk_symbol(C, stmt->label_identifier, visitor); - visitor->end_label(visitor->data); - walk_statement(C, stmt->label_statement, visitor); - break; - - case STMT_GOTO: - if (stmt->goto_expression) { - walk_expression(C, stmt->goto_expression, visitor); - } else { - dmrC_walk_symbol(C, stmt->goto_label, visitor); - } - break; - case STMT_ASM: - // printf("\tasm( .... )\n"); - break; - case STMT_CONTEXT: { - // int val = dmrC_show_expression(C, stmt->expression); - // printf("\tcontext( %d )\n", val); - break; - } - case STMT_RANGE: { - // int val = dmrC_show_expression(C, stmt->range_expression); - // int low = dmrC_show_expression(C, stmt->range_low); - // int high = dmrC_show_expression(C, stmt->range_high); - // printf("\trange( %d %d-%d)\n", val, low, high); - break; - } - } - visitor->end_statement(visitor->data); -} - -void walk_symbol_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor) -{ - assert(expr->type == EXPR_SYMBOL); - struct symbol *sym = expr->symbol; - if (!sym) - return; - dmrC_walk_symbol(C, sym, visitor); -} - -void walk_assignment_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor) -{ - assert(expr->type == EXPR_ASSIGNMENT); - if (!expr->ctype) - return; - - int op = expr->op; - visitor->begin_assignment_expression(visitor->data, expr->type, op); - walk_expression(C, expr->left, visitor); - walk_expression(C, expr->right, visitor); - visitor->end_assignment_expression(visitor->data); -} - -void walk_binary_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor) -{ - assert(expr->type == EXPR_BINOP || expr->type == EXPR_COMPARE || expr->type == EXPR_LOGICAL); - if (!expr->ctype) - return; - - int op = expr->op; - visitor->begin_binop_expression(visitor->data, expr->type, op); - walk_expression(C, expr->left, visitor); - walk_expression(C, expr->right, visitor); - visitor->end_binop_expression(visitor->data); -} - -void walk_preop_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor) -{ - assert(expr->type == EXPR_PREOP); - visitor->begin_preop_expression(visitor->data, expr->type, expr->op); - walk_expression(C, expr->unop, visitor); - visitor->end_preop_expression(visitor->data); -} - -void walk_postop_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor) -{ - assert(expr->type == EXPR_POSTOP); - visitor->begin_postop_expression(visitor->data, expr->type, expr->op); - walk_expression(C, expr->unop, visitor); - visitor->end_postop_expression(visitor->data); -} - -void walk_call_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor) -{ - assert(expr->type == EXPR_CALL); - if (!expr->ctype) { - return; - } - struct symbol *direct; - struct expression *arg, *fn; - fn = expr->fn; - - /* Remove dereference, if any */ - direct = NULL; - if (fn->type == EXPR_PREOP) { - if (fn->unop->type == EXPR_SYMBOL) { - struct symbol *sym = fn->unop->symbol; - if (sym->ctype.base_type->type == SYM_FN) - direct = sym; - } - } - if (direct && !direct->aux) { - dmrC_walk_symbol(C, direct, visitor); - } - if (direct) { - visitor->begin_direct_call_expression(visitor->data, expr->type, dmrC_show_ident(C, direct->ident)); - } else { - visitor->begin_indirect_call_expression(visitor->data, expr->type); - walk_expression(C, fn, visitor); - } - int n = 0; - FOR_EACH_PTR(expr->args, arg) - { - visitor->begin_callarg_expression(visitor->data, expr->type, ++n); - walk_expression(C, arg, visitor); - visitor->end_callarg_expression(visitor->data); - } - END_FOR_EACH_PTR(arg); - visitor->end_call_expression(visitor->data); -} - -void walk_cast_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor) -{ - struct symbol *old_type, *new_type; - int oldbits, newbits; - int is_signed; - - old_type = expr->cast_expression->ctype; - new_type = expr->cast_type; - - oldbits = old_type->bit_size; - newbits = new_type->bit_size; - is_signed = dmrC_is_signed_type(old_type); - visitor->begin_cast_expression(visitor->data, expr->type, oldbits, newbits, !is_signed); - walk_expression(C, expr->cast_expression, visitor); - dmrC_walk_symbol(C, new_type, visitor); - visitor->end_cast_expression(visitor->data); -} - -void walk_conditional_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor) -{ - visitor->begin_conditional_expression(visitor->data, expr->type); - walk_expression(C, expr->conditional, visitor); - walk_expression(C, expr->cond_true, visitor); - walk_expression(C, expr->cond_false, visitor); - visitor->end_conditional_expression(visitor->data); -} - -void walk_label_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor) -{ - visitor->begin_label_expression(visitor->data, expr->type); - dmrC_walk_symbol(C, expr->label_symbol, visitor); - visitor->end_label_expression(visitor->data); -} - -static void walk_initialization(struct dmr_C *C, struct symbol *sym, struct expression *expr, - struct symbol_visitor *visitor) -{ - if (!expr->ctype) - return; - visitor->begin_initialization(visitor->data, expr->type); - walk_expression(C, expr, visitor); - dmrC_walk_symbol(C, sym, visitor); - visitor->end_initialization(visitor->data); -} - -static void walk_position_expression(struct dmr_C *C, struct expression *expr, struct symbol *base, - struct symbol_visitor *visitor) -{ - struct symbol *ctype = expr->init_expr->ctype; - int bit_offset; - - bit_offset = ctype ? ctype->bit_offset : -1; - visitor->begin_expression_position(visitor->data, EXPR_POS, expr->init_offset, bit_offset, - dmrC_show_ident(C, base->ident)); - walk_expression(C, expr->init_expr, visitor); - visitor->end_expression_position(visitor->data); -} - -void walk_initializer_expression(struct dmr_C *C, struct expression *expr, struct symbol *ctype, - struct symbol_visitor *visitor) -{ - struct expression *entry; - - FOR_EACH_PTR(expr->expr_list, entry) - { - - again: - // Nested initializers have their positions already - // recursively calculated - just output them too - if (entry->type == EXPR_INITIALIZER) { - walk_initializer_expression(C, entry, ctype, visitor); - continue; - } - - // Initializer indexes and identifiers should - // have been evaluated to EXPR_POS - if (entry->type == EXPR_IDENTIFIER) { - visitor->do_expression_identifier(visitor->data, entry->type, - dmrC_show_ident(C, entry->expr_ident)); - entry = entry->ident_expression; - goto again; - } - - if (entry->type == EXPR_INDEX) { - visitor->do_expression_index(visitor->data, entry->type, entry->idx_from, entry->idx_to); - entry = entry->idx_expression; - goto again; - } - if (entry->type == EXPR_POS) { - walk_position_expression(C, entry, ctype, visitor); - continue; - } - walk_initialization(C, ctype, entry, visitor); - } - END_FOR_EACH_PTR(entry); -} - -void walk_expression(struct dmr_C *C, struct expression *expr, struct symbol_visitor *visitor) -{ - if (!expr) - return; - if (!expr->ctype) - return; - - visitor->begin_expression(visitor->data, expr->type); - switch (expr->type) { - case EXPR_CALL: - walk_call_expression(C, expr, visitor); - break; - - case EXPR_ASSIGNMENT: - walk_assignment_expression(C, expr, visitor); - break; - - case EXPR_COMMA: - // return show_comma(C, expr); - break; - case EXPR_BINOP: - case EXPR_COMPARE: - case EXPR_LOGICAL: - walk_binary_expression(C, expr, visitor); - break; - case EXPR_PREOP: - walk_preop_expression(C, expr, visitor); - break; - case EXPR_POSTOP: - walk_postop_expression(C, expr, visitor); - break; - case EXPR_SYMBOL: - walk_symbol_expression(C, expr, visitor); - break; - case EXPR_DEREF: - case EXPR_SIZEOF: - case EXPR_PTRSIZEOF: - case EXPR_ALIGNOF: - case EXPR_OFFSETOF: - break; - case EXPR_CAST: - case EXPR_FORCE_CAST: - case EXPR_IMPLIED_CAST: - walk_cast_expression(C, expr, visitor); - break; - case EXPR_VALUE: - visitor->int_literal(visitor->data, expr->value, expr->ctype->bit_size, - expr->ctype->ctype.modifiers & MOD_UNSIGNED); - break; - case EXPR_FVALUE: - visitor->float_literal(visitor->data, expr->fvalue, expr->ctype->bit_size); - break; - case EXPR_STRING: - visitor->string_literal(visitor->data, dmrC_show_string(C, expr->string)); - break; - case EXPR_INITIALIZER: - walk_initializer_expression(C, expr, expr->ctype, visitor); - break; - case EXPR_SELECT: - case EXPR_CONDITIONAL: - walk_conditional_expression(C, expr, visitor); - break; - case EXPR_STATEMENT: - // return show_statement_expr(C, expr); - break; - case EXPR_LABEL: - walk_label_expression(C, expr, visitor); - break; - case EXPR_SLICE: - // return show_slice(C, expr); - break; - - // None of these should exist as direct expressions: they are - // only valid as sub-expressions of initializers. - case EXPR_POS: - case EXPR_IDENTIFIER: - case EXPR_INDEX: - case EXPR_TYPE: - break; - } - visitor->end_expression(visitor->data); -} - -void dmrC_walk_symbol_list(struct dmr_C *C, struct symbol_list *list, struct symbol_visitor *visitor) -{ - struct symbol *sym; - - FOR_EACH_PTR(list, sym) { dmrC_walk_symbol(C, sym, visitor); } - END_FOR_EACH_PTR(sym); -} - -void dmrC_walk_symbol(struct dmr_C *C, struct symbol *sym, struct symbol_visitor *visitor) -{ - if (!sym) - return; - if (sym->type != SYM_BASETYPE) { - if (sym->aux) { - /* already visited */ - const char *name = sym->ident ? dmrC_show_ident(C, sym->ident) : ""; - visitor->reference_symbol(visitor->data, (uint64_t)sym->aux, name); - return; - } - visitor->id++; - sym->aux = (void *)visitor->id; - } - char name[80] = {0}; - if (sym->ident) - snprintf(name, sizeof name, "%s", dmrC_show_ident(C, sym->ident)); - else if (sym->type == SYM_BASETYPE) - snprintf(name, sizeof name, "%s", dmrC_builtin_typename(C, sym)); - struct symbol_info syminfo = {.id = (uint64_t)sym->aux, - .name = name, - .symbol_namespace = sym->ns, - .symbol_type = sym->type, - .alignment = sym->ctype.alignment, - .pos = sym->pos, - .bit_size = sym->bit_size, - .offset = sym->offset}; - if (sym->ns == NS_STRUCT && dmrC_is_bitfield_type(sym)) { - syminfo.bit_offset = sym->bit_offset; - } - if (sym->array_size) { - syminfo.array_size = dmrC_get_expression_value(C, sym->array_size); - } - - visitor->begin_symbol(visitor->data, &syminfo); - - if (sym->type == SYM_STRUCT || sym->type == SYM_UNION) { - struct symbol *member; - visitor->begin_struct_members(visitor->data, &syminfo); - FOR_EACH_PTR(sym->symbol_list, member) { dmrC_walk_symbol(C, member, visitor); } - END_FOR_EACH_PTR(member); - visitor->end_struct_members(visitor->data); - } - - if (sym->type == SYM_FN) { - struct symbol *arg; - visitor->begin_func_arguments(visitor->data, &syminfo); - FOR_EACH_PTR(sym->arguments, arg) { dmrC_walk_symbol(C, arg, visitor); } - END_FOR_EACH_PTR(member); - visitor->end_func_arguments(visitor->data); - } - - // Is there a base type? - if (sym->type != SYM_BASETYPE && sym->ctype.base_type) { - if (sym->type == SYM_FN) - visitor->begin_func_returntype(visitor->data, &syminfo); - else - visitor->begin_basetype(visitor->data, &syminfo); - dmrC_walk_symbol(C, sym->ctype.base_type, visitor); - if (sym->type == SYM_FN) - visitor->end_func_returntype(visitor->data); - else - visitor->end_basetype(visitor->data); - } - - if (sym->type == SYM_FN) { - if (sym->stmt) { - visitor->begin_func_body(visitor->data, &syminfo); - walk_statement(C, sym->stmt, visitor); - visitor->end_func_body(visitor->data); - } - } - if (sym->initializer) { - visitor->begin_initializer(visitor->data, &syminfo); - walk_expression(C, sym->initializer, visitor); - visitor->end_initializer(visitor->data); - } - visitor->end_symbol(visitor->data); -} - -static void begin_symbol_default(void *data, struct symbol_info *syminfo) -{ - (void)data; - (void)syminfo; -} -static void end_symbol_default(void *data) { (void)data; } -static void begin_members_default(void *data, struct symbol_info *syminfo) -{ - (void)data; - (void)syminfo; -} -static void end_members_default(void *data) { (void)data; } -static void begin_arguments_default(void *data, struct symbol_info *syminfo) -{ - (void)data; - (void)syminfo; -} -static void end_arguments_default(void *data) { (void)data; } -static void reference_symbol_default(void *data, uint64_t id, const char *name) -{ - (void)data; - (void)id; - (void)name; -} -static void begin_body_default(void *data, struct symbol_info *syminfo) -{ - (void)data; - (void)syminfo; -} -static void end_body_default(void *data) { (void)data; } -static void begin_func_returntype_default(void *data, struct symbol_info *syminfo) -{ - (void)data; - (void)syminfo; -} -static void end_func_returntype_default(void *data) { (void)data; } -static void begin_basetype_default(void *data, struct symbol_info *syminfo) -{ - (void)data; - (void)syminfo; -} -static void end_basetype_default(void *data) { (void)data; } -static void begin_initializer_default(void *data, struct symbol_info *syminfo) -{ - (void)data; - (void)syminfo; -} -static void end_initializer_default(void *data) { (void)data; } -static void string_expression_default(void *data, const char *str) -{ - (void)data; - (void)str; -} -static void int_literal_default(void *data, long long value, int bit_size, bool is_unsigned) -{ - (void)data; - (void)value; - (void)bit_size; - (void)is_unsigned; -} -static void float_literal_default(void *data, long double fvalue, int bit_size) -{ - (void)data; - (void)fvalue; - (void)bit_size; -} -static void begin_statement_default(void *data, enum statement_type statement_type) -{ - (void)data; - (void)statement_type; -} -static void end_statement_default(void *data) { (void)data; } -static void begin_expression_default(void *data, enum expression_type expr_type) -{ - (void)data; - (void)expr_type; -} -static void end_expression_default(void *data) { (void)data; } -static void begin_assignment_expression_default(void *data, enum expression_type expr_type, int op) -{ - (void)data; - (void)expr_type; - (void)op; -} -static void end_assignment_expression_default(void *data) { (void)data; } -static void begin_binop_expression_default(void *data, enum expression_type expr_type, int op) -{ - (void)data; - (void)expr_type; - (void)op; -} -static void end_binop_expression_default(void *data) { (void)data; } -static void begin_preop_expression_default(void *data, enum expression_type expr_type, int op) -{ - (void)data; - (void)expr_type; - (void)op; -} -static void end_preop_expression_default(void *data) { (void)data; } -static void begin_postop_expression_default(void *data, enum expression_type expr_type, int op) -{ - (void)data; - (void)expr_type; - (void)op; -} -static void end_postop_expression_default(void *data) { (void)data; } -static void begin_direct_call_expression_default(void *data, enum expression_type expr_type, const char *name) -{ - (void)data; - (void)expr_type; - (void)name; -} -static void begin_indirect_call_expression_default(void *data, enum expression_type expr_type) -{ - (void)data; - (void)expr_type; -} -static void end_call_expression_default(void *data) { (void)data; } - -static void begin_callarg_expression_default(void *data, enum expression_type expr_type, int argpos) -{ - (void)data; - (void)expr_type; - (void)argpos; -} -static void end_callarg_expression_default(void *data) { (void)data; } - -static void begin_cast_expression_default(void *data, enum expression_type expr_type, int oldbits, int newbits, - bool is_unsigned) -{ - (void)data; - (void)expr_type; - (void)oldbits; - (void)newbits; - (void)is_unsigned; -} -static void end_cast_expression_default(void *data) { (void)data; } -static void begin_conditional_expression_default(void *data, enum expression_type expr_type) -{ - (void)data; - (void)expr_type; -} -static void end_conditional_expression_default(void *data) { (void)data; } -static void begin_label_expression_default(void *data, enum expression_type expr_type) -{ - (void)data; - (void)expr_type; -} -static void end_label_expression_default(void *data) { (void)data; } -static void do_expression_identifier_default(void *data, enum expression_type expr_type, const char *ident) -{ - (void)data; - (void)expr_type; - (void)ident; -} -static void do_expression_index_default(void *data, enum expression_type expr_type, unsigned from, unsigned to) -{ - (void)data; - (void)expr_type; - (void)from; - (void)to; -} -static void begin_expression_position_default(void *data, enum expression_type expr_type, unsigned init_offset, - int bit_offset, const char *ident) -{ - (void)data; - (void)expr_type; - (void)init_offset; - (void)ident; - (void)bit_offset; -} -static void end_expression_position_default(void *data) { (void)data; } -static void begin_initialization_default(void *data, enum expression_type expr_type) -{ - (void)data; - (void)expr_type; -} -static void end_initialization_default(void *data) { (void)data; } -static void begin_label_default(void *data, const char *name) -{ - (void)data; - (void)name; -} -static void end_label_default(void *data) { (void)data; } -static void begin_iterator_prestatement_default(void *data) { (void)data; } -static void end_iterator_prestatement_default(void *data) { (void)data; } -static void begin_iterator_precondition_default(void *data) { (void)data; } -static void end_iterator_precondition_default(void *data) { (void)data; } -static void begin_iterator_statement_default(void *data) { (void)data; } -static void end_iterator_statement_default(void *data) { (void)data; } -static void begin_iterator_postcondition_default(void *data) { (void)data; } -static void end_iterator_postcondition_default(void *data) { (void)data; } -static void begin_iterator_poststatement_default(void *data) { (void)data; } -static void end_iterator_poststatement_default(void *data) { (void)data; } -static void begin_case_value_default(void *data, long long value) -{ - (void)data; - (void)value; -} -static void begin_case_range_default(void *data, long long from, long long to) -{ - (void)data; - (void)from; - (void)to; -} -static void begin_default_case_default(void *data) { (void)data; } -static void end_case_default(void *data) { (void)data; } - -static void begin_if_then_default(void *data) { (void)data; } -static void end_if_then_default(void *data) { (void)data; } -static void begin_if_else_default(void *data) { (void)data; } -static void end_if_else_default(void *data) { (void)data; } - -void dmrC_init_symbol_visitor(struct symbol_visitor *visitor) -{ - visitor->data = NULL; - visitor->id = 0; - visitor->begin_symbol = begin_symbol_default; - visitor->end_symbol = end_symbol_default; - visitor->begin_struct_members = begin_members_default; - visitor->end_struct_members = end_members_default; - visitor->begin_func_arguments = begin_arguments_default; - visitor->end_func_arguments = end_arguments_default; - visitor->reference_symbol = reference_symbol_default; - visitor->begin_func_body = begin_body_default; - visitor->end_func_body = end_body_default; - visitor->begin_func_returntype = begin_func_returntype_default; - visitor->end_func_returntype = end_func_returntype_default; - visitor->begin_basetype = begin_basetype_default; - visitor->end_basetype = end_basetype_default; - visitor->begin_initializer = begin_initializer_default; - visitor->end_initializer = end_initializer_default; - visitor->string_literal = string_expression_default; - visitor->float_literal = float_literal_default; - visitor->int_literal = int_literal_default; - visitor->begin_statement = begin_statement_default; - visitor->end_statement = end_statement_default; - visitor->begin_expression = begin_expression_default; - visitor->end_expression = end_expression_default; - visitor->begin_assignment_expression = begin_assignment_expression_default; - visitor->end_assignment_expression = end_assignment_expression_default; - visitor->begin_binop_expression = begin_binop_expression_default; - visitor->end_binop_expression = end_binop_expression_default; - visitor->begin_preop_expression = begin_preop_expression_default; - visitor->end_preop_expression = end_preop_expression_default; - visitor->begin_postop_expression = begin_postop_expression_default; - visitor->end_postop_expression = end_postop_expression_default; - visitor->begin_direct_call_expression = begin_direct_call_expression_default; - visitor->begin_indirect_call_expression = begin_indirect_call_expression_default; - visitor->end_call_expression = end_call_expression_default; - visitor->begin_callarg_expression = begin_callarg_expression_default; - visitor->end_callarg_expression = end_callarg_expression_default; - visitor->begin_cast_expression = begin_cast_expression_default; - visitor->end_cast_expression = end_cast_expression_default; - visitor->begin_conditional_expression = begin_conditional_expression_default; - visitor->end_conditional_expression = end_conditional_expression_default; - visitor->begin_label_expression = begin_label_expression_default; - visitor->end_label_expression = end_label_expression_default; - visitor->do_expression_identifier = do_expression_identifier_default; - visitor->do_expression_index = do_expression_index_default; - visitor->begin_expression_position = begin_expression_position_default; - visitor->end_expression_position = end_expression_position_default; - visitor->begin_initialization = begin_initialization_default; - visitor->end_initialization = end_initialization_default; - visitor->begin_label = begin_label_default; - visitor->end_label = end_label_default; - visitor->begin_iterator_prestatement = begin_iterator_prestatement_default; - visitor->end_iterator_prestatement = end_iterator_prestatement_default; - visitor->begin_iterator_precondition = begin_iterator_precondition_default; - visitor->end_iterator_precondition = end_iterator_precondition_default; - visitor->begin_iterator_statement = begin_iterator_statement_default; - visitor->end_iterator_statement = end_iterator_statement_default; - visitor->begin_iterator_postcondition = begin_iterator_postcondition_default; - visitor->end_iterator_postcondition = end_iterator_postcondition_default; - visitor->begin_iterator_poststatement = begin_iterator_poststatement_default; - visitor->end_iterator_poststatement = end_iterator_poststatement_default; - visitor->begin_case_value = begin_case_value_default; - visitor->begin_case_range = begin_case_range_default; - visitor->begin_default_case = begin_default_case_default; - visitor->end_case = end_case_default; - visitor->begin_if_then = begin_if_then_default; - visitor->end_if_then = end_if_then_default; - visitor->begin_if_else = begin_if_else_default; - visitor->end_if_else = end_if_else_default; -} diff --git a/dmr_c/src/walksymbol.h b/dmr_c/src/walksymbol.h deleted file mode 100644 index b1bc8d5..0000000 --- a/dmr_c/src/walksymbol.h +++ /dev/null @@ -1,144 +0,0 @@ -#ifndef DMR_C_PARSETREE_H -#define DMR_C_PARSETREE_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -struct symbol_info { - uint64_t id; - enum namespace_type symbol_namespace; - enum type symbol_type; - const char *name; - int bit_size; - unsigned long alignment; - unsigned int offset; - int bit_offset; - long long array_size; - struct position pos; -}; - -struct symbol_visitor { - void *data; - uint64_t id; - void (*begin_symbol)(void *data, struct symbol_info *syminfo); - void (*end_symbol)(void *data); - void (*begin_struct_members)(void *data, struct symbol_info *syminfo); - void (*end_struct_members)(void *data); - void (*begin_func_arguments)(void *data, struct symbol_info *syminfo); - void (*end_func_arguments)(void *data); - void (*reference_symbol)(void *data, uint64_t id, const char *name); - void (*begin_func_body)(void *data, struct symbol_info *syminfo); - void (*end_func_body)(void *data); - void (*begin_func_returntype)(void *data, struct symbol_info *syminfo); - void (*end_func_returntype)(void *data); - void (*begin_basetype)(void *data, struct symbol_info *syminfo); - void (*end_basetype)(void *data); - void (*begin_initializer)(void *data, struct symbol_info *syminfo); - void (*end_initializer)(void *data); - void (*string_literal)(void *data, const char *str); - void (*int_literal)(void *data, long long value, int bit_size, - bool is_unsigned); - void (*float_literal)(void *data, long double fvalue, int bit_size); - - void (*begin_statement)(void *data, enum statement_type statement_type); - void (*end_statement)(void *data); - - void (*begin_expression)(void *data, enum expression_type expr_type); - void (*end_expression)(void *data); - void (*begin_assignment_expression)(void *data, - enum expression_type expr_type, - int op); - void (*end_assignment_expression)(void *data); - void (*begin_binop_expression)(void *data, - enum expression_type expr_type, int op); - void (*end_binop_expression)(void *data); - void (*begin_preop_expression)(void *data, - enum expression_type expr_type, int op); - void (*end_preop_expression)(void *data); - void (*begin_postop_expression)(void *data, - enum expression_type expr_type, int op); - void (*end_postop_expression)(void *data); - - void (*begin_direct_call_expression)(void *data, - enum expression_type expr_type, - const char *name); - void (*begin_indirect_call_expression)(void *data, - enum expression_type expr_type); - void (*end_call_expression)(void *data); - void (*begin_callarg_expression)(void *data, - enum expression_type expr_type, - int argpos); - void (*end_callarg_expression)(void *data); - void (*begin_cast_expression)(void *data, - enum expression_type expr_type, - int oldbits, int newbits, - bool is_unsigned); - void (*end_cast_expression)(void *data); - void (*begin_conditional_expression)(void *data, - enum expression_type expr_type); - void (*end_conditional_expression)(void *data); - void (*begin_label_expression)(void *data, - enum expression_type expr_type); - void (*end_label_expression)(void *data); - void (*do_expression_identifier)(void *data, - enum expression_type expr_type, - const char *ident); - void (*do_expression_index)(void *data, enum expression_type expr_type, - unsigned from, unsigned to); - void (*begin_expression_position)(void *data, - enum expression_type expr_type, - unsigned init_offset, int bit_offset, - const char *ident); - void (*end_expression_position)(void *data); - void (*begin_initialization)(void *data, - enum expression_type expr_type); - void (*end_initialization)(void *data); - - void (*begin_label)(void *data, const char *name); - void (*end_label)(void *data); - - void(*begin_iterator_prestatement)(void *data); - void(*end_iterator_prestatement)(void *data); - void(*begin_iterator_precondition)(void *data); - void(*end_iterator_precondition)(void *data); - void(*begin_iterator_statement)(void *data); - void(*end_iterator_statement)(void *data); - void(*begin_iterator_postcondition)(void *data); - void(*end_iterator_postcondition)(void *data); - void(*begin_iterator_poststatement)(void *data); - void(*end_iterator_poststatement)(void *data); - - void(*begin_case_value)(void *data, long long value); - void(*begin_case_range)(void *data, long long from, long long to); - void(*begin_default_case)(void *data); - void(*end_case)(void *data); - - void(*begin_if_then)(void *data); - void(*end_if_then)(void *data); - void(*begin_if_else)(void *data); - void(*end_if_else)(void *data); -}; - -extern void dmrC_init_symbol_visitor(struct symbol_visitor *visitor); -extern void dmrC_walk_symbol_list(struct dmr_C *C, struct symbol_list *list, - struct symbol_visitor *visitor); -extern void dmrC_walk_symbol(struct dmr_C *C, struct symbol *sym, - struct symbol_visitor *visitor); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/include/ravi_llvmcodegen.h b/include/ravi_llvmcodegen.h index c49c569..2c7565b 100644 --- a/include/ravi_llvmcodegen.h +++ b/include/ravi_llvmcodegen.h @@ -488,8 +488,6 @@ class RaviJITState { // May slow down compilation unsigned int validation_ : 1; - unsigned int use_dmrc_ : 1; - // min code size for compilation int min_code_size_; @@ -589,7 +587,6 @@ class RaviJITState { else compiling_--; } - int is_use_dmrc() const { return use_dmrc_; } }; // A wrapper for LLVM Module @@ -891,12 +888,6 @@ class RaviCodeGenerator { public: RaviCodeGenerator(RaviJITState *jitState); - // Compile given function if possible - // The p->ravi_jit structure will be updated - // Note that if a function fails to compile then - // a flag is set so that it doesn't get compiled again - bool alt_compile(lua_State *L, Proto *p, std::shared_ptr module, ravi_compile_options_t *options); - // Compile given function if possible // The p->ravi_jit structure will be updated // Note that if a function fails to compile then diff --git a/include/ravi_omrjit.h b/include/ravi_omrjit.h deleted file mode 100644 index 5dc5a5e..0000000 --- a/include/ravi_omrjit.h +++ /dev/null @@ -1,51 +0,0 @@ -/****************************************************************************** -* Copyright (C) 2015-2020 Dibyendu Majumdar -* -* Permission is hereby granted, free of charge, to any person obtaining -* a copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to -* permit persons to whom the Software is furnished to do so, subject to -* the following conditions: -* -* The above copyright notice and this permission notice shall be -* included in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, -* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE -* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -******************************************************************************/ -#ifndef RAVI_OMRJIT_H -#define RAVI_OMRJIT_H - -#include - -#ifdef USE_OMRJIT -#include "dmr_c.h" - -struct ravi_State { - JIT_ContextRef jit; - unsigned long long id; // counter to generate function names - unsigned int verbosity_ : 3; - unsigned int auto_ : 1; /* Should we auto compile what we can? */ - unsigned int enabled_ : 1; /* is JIT enabled */ - unsigned int opt_level_ : 3; /* optimization level */ - unsigned int tracehook_enabled_ : 1; /* enable calls to luaG_traceexec() at every bytecode, this is expensive ! */ - unsigned int validation_ : 1; /* Enable extra validation such as IL verification */ - unsigned int compiling_; /* flag to help avoid recursion */ - int min_code_size_; /* min code size for compilation */ - int min_exec_count_; /* min execution count for compilation */ -}; - -#ifdef __cplusplus -}; -#endif - -#endif /* USE_OMRJIT */ - -#endif /* RAVI_OMRJIT_H */ diff --git a/readthedocs/index.rst b/readthedocs/index.rst index 5decd5a..c7044e0 100644 --- a/readthedocs/index.rst +++ b/readthedocs/index.rst @@ -14,9 +14,7 @@ Contents: ravi-overview ravi-reference ravi-mir-instructions - ravi-omr-instructions ravi-llvm-instructions - ravi-dmrc lua-introduction lua_bytecode_reference lua-parser diff --git a/readthedocs/ravi-dmrc.rst b/readthedocs/ravi-dmrc.rst deleted file mode 100644 index 85c20d9..0000000 --- a/readthedocs/ravi-dmrc.rst +++ /dev/null @@ -1,21 +0,0 @@ -==================================== -dmr_C embedded C parser and compiler -==================================== - -Ravi includes dmr_C, an embedded C parser and compiler. The C compiler supports LLVM and Eclipse OMR backends. -The following api is under development, but is not yet fully functional, and is subject to change. - -``drmc.getsymbols(source)`` - Parses the input and returns a table of symbols found. -``dmrc.compileC(source)`` - Compiles the input source. - -Examples -======== -An example use of the C parser is `ravi-tests/dmrc_getsymbols.lua `_. -For an example of invoking the C compiler with LLVM backend see `ravi-tests/dmrc_testllvm.lua `_. - -Outstanding issues -================== -* The Eclipse OMR backend cannot automatically access C functions externally defined; these have to be pre-registered. A solution might be to expose the resolution of symbols from dynamic libraries. -* We need to validate that the compiled C function is callable from Lua. This is not as easy to do with Eclipse OMR backend as with the LLVM backend. diff --git a/readthedocs/ravi-omr-instructions.rst b/readthedocs/ravi-omr-instructions.rst deleted file mode 100644 index 5e45393..0000000 --- a/readthedocs/ravi-omr-instructions.rst +++ /dev/null @@ -1,150 +0,0 @@ -=============================== -Build Ravi with Eclipse OMR JIT -=============================== - -.. contents:: Table of Contents - :depth: 2 - :backlinks: top - -Overview -======== -.. note:: The Eclipse OMR JIT backend is work in progress. The code generation is not yet optimal. In particular several bytecodes are not yet inlined. - -Recently support has been added in Ravi to use the Eclipse OMR JIT backend. -A `trimmed down version of the Eclipse OMR JIT `_ is used to ensure that the resulting -binaries are smaller in size. - -The main advantages / disadvantages of the OMR JIT backend over LLVM are: - -* The OMR JIT backend is much smaller compared to LLVM. On my iMac it takes less than 3 minutes to compile and build the library. -* The OMR JIT engine contains an optimizing compiler, therefore the generated code is much better than say `NanoJIT `_, - although not perhaps as optimized as LLVM. - -The approach taken with the OMR JIT backend is somewhat different compared with the LLVM backend. - -* An intermediate C compiler is used; this is based on the `dmr_C `_ project. Using a C intermediate layer makes - development of the JIT backend easier to evolve. In comparison the LLVM backed was written by hand, using the LLVM api. -* Users can view the intermediate C code for a Lua function by simply invoking ``ravi.dumpir(function)`` on any function: - -:: - - Ravi 5.3.4 - Copyright (C) 1994-2017 Lua.org, PUC-Rio - Portions Copyright (C) 2015-2017 Dibyendu Majumdar - Options assertions ltests omrjit - > x = function() print 'hello world' end - > ravi.dumpir(x) - -Above results in (note that only the function code is shown below):: - - int jit_function(lua_State *L) { - int error_code = 0; - lua_Integer i = 0; - lua_Integer ic = 0; - lua_Number n = 0.0; - lua_Number nc = 0.0; - int result = 0; - StkId ra = NULL; - StkId rb = NULL; - StkId rc = NULL; - lua_Unsigned ukey = 0; - lua_Integer *iptr = NULL; - lua_Number *nptr = NULL; - Table *t = NULL; - CallInfo *ci = L->ci; - LClosure *cl = clLvalue(ci->func); - TValue *k = cl->p->k; - StkId base = ci->u.l.base; - ra = R(0); - rc = K(0); - raviV_gettable_sskey(L, cl->upvals[0]->v, rc, ra); - base = ci->u.l.base; - ra = R(1); - rb = K(1); - setobj2s(L, ra, rb); - L->top = R(2); - ra = R(0); - result = luaD_precall(L, ra, 0, 1); - if (result) { - if (result == 1 && 0 >= 0) - L->top = ci->top; - } - else { /* Lua function */ - result = luaV_execute(L); - if (result) L->top = ci->top; - } - base = ci->u.l.base; - ra = R(0); - if (cl->p->sizep > 0) luaF_close(L, base); - result = (1 != 0 ? 1 - 1 : cast_int(L->top - ra)); - return luaD_poscall(L, ci, ra, result); - Lraise_error: - raise_error(L, error_code); /* does not return */ - return 0; - } - -Build Dependencies -================== - -* `CMake `_ is required -* On Windows you will need Visual Studio 2017 Community edition - -Build Instructions -================== -* Ravi uses a cut-down version of the `Eclipse OMR JIT engine `_. First build this library and install it. -* The Ravi CMake build assumes you have installed the OMR JIT library under ``\Software\omr`` on Windows and ``$HOME/Software/omr`` on Linux or Mac OSX. -* Now you can build Ravi as follows on Linux or Mac OSX: - -:: - - cd build - cmake -DOMR_JIT=ON -DCMAKE_INSTALL_PREFIX=$HOME/ravi -DCMAKE_BUILD_TYPE=Release -G "Unix Makefiles" .. - make - -If you did not use the default locations above to install OMR, then you will need to amend the file ``cmake/FindOMRJIT.cmake``. - -JIT API for OMR backend -======================= -auto mode - in this mode the compiler decides when to compile a Lua function. The current implementation is very simple - - any Lua function call is checked to see if the bytecodes contained in it can be compiled. If this is true then - the function is compiled provided either a) function has a fornum loop, or b) it is largish (greater than 150 bytecodes) - or c) it is being executed many times (> 50). Because of the simplistic behaviour performance the benefit of JIT - compilation is only available if the JIT compiled functions will be executed many times so that the cost of JIT - compilation can be amortized. -manual mode - in this mode user must explicitly request compilation. This is the default mode. This mode is suitable for library - developers who can pre compile the functions in library module table. - -A JIT api is available with following functions: - -``ravi.jit([b])`` - returns enabled setting of JIT compiler; also enables/disables the JIT compiler; defaults to true -``ravi.auto([b [, min_size [, min_executions]]])`` - returns setting of auto compilation and compilation thresholds; also sets the new settings if values are supplied; defaults are false, 150, 50. -``ravi.compile(func_or_table[, options])`` - compiles a Lua function (or functions if a table is supplied) if possible, returns ``true`` if compilation was - successful for at least one function. - ``options`` is an optional table with compilation options - in particular, - ``omitArrayGetRangeCheck`` if set true disables range checks in array get operations to improve performance in some cases. - ``inlineLuaArithmeticOperators`` if set to true enables generation of inline code for Lua arithemtic op codes such as - ``OP_ADD``, ``OP_MUL`` and ``OP_SUB``. -``ravi.iscompiled(func)`` - returns the JIT status of a function -``ravi.dumplua(func)`` - dumps the Lua bytecode of the function -``ravi.dumpir(func)`` - dumps the C intermediate code for a Lua function -``ravi.optlevel([n])`` - sets optimization level (0, 1, 2); defaults to 1. -``ravi.verbosity([b])`` - If set to 1 then everytime a Lua function is compiled the C intermediate code will be dumped. - -Compiler Trace Output from OMR -============================== -The OMR JIT backend can generate detailed compilation traces if you define following environment variable:: - - export TR_Options=traceIlGen,traceFull,log=trtrace.log - -Note that the generated traces can be huge! - diff --git a/readthedocs/ravi-overview.rst b/readthedocs/ravi-overview.rst index 28e4b5a..b52a869 100644 --- a/readthedocs/ravi-overview.rst +++ b/readthedocs/ravi-overview.rst @@ -5,8 +5,8 @@ Ravi Programming Language :target: https://travis-ci.org/dibyendumajumdar/ravi Ravi is a derivative/dialect of `Lua 5.3 `_ with limited optional static typing and -features `MIR `_, `LLVM `_ and `Eclipse OMR `_ -powered JIT compilers. The name Ravi comes from the Sanskrit word for the Sun. +features `MIR `_ and `LLVM `_ powered JIT compilers. +The name Ravi comes from the Sanskrit word for the Sun. Interestingly a precursor to Lua was `Sol `_ which had support for static types; Sol means the Sun in Portugese. @@ -35,14 +35,12 @@ Features * Compatibility with Lua 5.3 (see Compatibility section below) * New! JIT backend `MIR `_; only Linux and x86-64 supported for now. * `LLVM `_ powered JIT compiler -* `Eclipse OMR `_ powered JIT compiler * A `distribution with batteries `_. Documentation ============= * For the Lua extensions in Ravi see the `Reference Manual `_. * `MIR JIT Build instructions `_. -* `OMR JIT Build instructions `_. * `LLVM JIT Build instructions `_. * Also see `Ravi Documentation `_. * and the slides I presented at the `Lua 2015 Workshop `_. @@ -90,10 +88,10 @@ History * 2016 - Implemented debugger for Ravi and Lua 5.3 for `Visual Studio Code `_ * 2017 - - Embedded C compiler using dmrC project (C JIT compiler) + - Embedded C compiler using dmrC project (C JIT compiler) (now discontinued) - Additional type-annotations * 2018 - - Implemented Eclipse OMR JIT backend + - Implemented Eclipse OMR JIT backend (now discontinued) - Created `Ravi with batteries `_. * 2019 - New language feature - `defer` statement diff --git a/src/linit.c b/src/linit.c index 49eac93..d3f44b3 100644 --- a/src/linit.c +++ b/src/linit.c @@ -34,8 +34,6 @@ #include "lualib.h" #include "lauxlib.h" -LUAMOD_API int raviopen_dmrcluaapi(lua_State *L); - /* ** these libs are loaded by lua.c and are readily available to any Lua ** program @@ -52,9 +50,6 @@ static const luaL_Reg loadedlibs[] = { {LUA_UTF8LIBNAME, luaopen_utf8}, {LUA_DBLIBNAME, luaopen_debug}, {LUA_RAVILIBNAME, raviopen_jit}, -#if USE_DMR_C - { "dmrc", raviopen_dmrcluaapi }, -#endif #if defined(LUA_COMPAT_BITLIB) {LUA_BITLIBNAME, luaopen_bit32}, #endif diff --git a/src/ravi_llvmcodegen.cpp b/src/ravi_llvmcodegen.cpp index 81bac0e..eae7d02 100644 --- a/src/ravi_llvmcodegen.cpp +++ b/src/ravi_llvmcodegen.cpp @@ -23,7 +23,6 @@ #include #include #include -#include namespace ravi { @@ -1345,67 +1344,6 @@ llvm::Value *RaviCodeGenerator::emit_gep_upval_value( #endif } -// Alternative code generator uses dmrC based C front-end -// That the codegen emits C code that is then JIT compiled -// via dmrC and LLVM. -bool RaviCodeGenerator::alt_compile(lua_State *L, Proto *p, - std::shared_ptr module, - ravi_compile_options_t *options) { - if (p->ravi_jit.jit_status != RAVI_JIT_NOT_COMPILED) { - return false; - } - if (module->owner()->get_compiling_flag()) return false; - if (!raviJ_cancompile(p)) { - p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; - return false; - } - - auto M = module->module(); - LLVMModuleRef moduleRef = llvm::wrap(M); - - // Set flag so we can avoid recursive calls - module->owner()->set_compiling_flag(true); - - membuff_t buf; - membuff_init(&buf, 4096); - - const char *fname = unique_function_name(); - if (!raviJ_codegen(L, p, options, fname, &buf)) { - p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; - } - else { - if (options->manual_request && module->owner()->get_verbosity()) { - ravi_writestring(L, buf.buf, strlen(buf.buf)); - ravi_writeline(L); - } - char *argv[] = {(char *)fname, NULL}; - if (!dmrC_llvmcompile(2, argv, moduleRef, buf.buf)) { - p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; - } - else { - p->ravi_jit.jit_function = nullptr; - std::unique_ptr func = - std::unique_ptr(new RaviJITFunction(&p->ravi_jit.jit_function, module, fname)); - if (func->function() == nullptr) { - fprintf(stderr, "LLVM Compilation failed\n"); - exit(1); - } - bool doVerify = module->owner()->get_validation() != 0; - if (doVerify && llvm::verifyFunction(*func->function(), &llvm::errs())) { - func->dump(); - fprintf(stderr, "LLVM Code Verification failed\n"); - exit(1); - } - ravi::RaviJITFunction *llvm_func = func.release(); - p->ravi_jit.jit_data = reinterpret_cast(llvm_func); - p->ravi_jit.jit_status = RAVI_JIT_COMPILED; - } - } - membuff_free(&buf); - module->owner()->set_compiling_flag(false); - return p->ravi_jit.jit_status == RAVI_JIT_COMPILED; -} - bool RaviCodeGenerator::compile(lua_State *L, Proto *p, std::shared_ptr module, ravi_compile_options_t *options) { diff --git a/src/ravi_llvmjit.cpp b/src/ravi_llvmjit.cpp index 0cc7246..bec404a 100644 --- a/src/ravi_llvmjit.cpp +++ b/src/ravi_llvmjit.cpp @@ -182,7 +182,6 @@ RaviJITState::RaviJITState() verbosity_(0), tracehook_enabled_(false), validation_(false), - use_dmrc_(false), min_code_size_(150), min_exec_count_(50), allocated_modules_(0), @@ -200,8 +199,6 @@ RaviJITState::RaviJITState() init++; } triple_ = llvm::sys::getProcessTriple(); - if (::getenv("RAVI_USE_DMRC_LLVM")) - use_dmrc_ = true; #if USE_ORCv2_JIT @@ -847,8 +844,7 @@ int raviV_compile(struct lua_State *L, struct Proto *p, ravi_compile_options_t * } if (doCompile) { auto module = std::make_shared(G->ravi_state->jit); - if (G->ravi_state->jit->is_use_dmrc() ? G->ravi_state->code_generator->alt_compile(L, p, module, options) - : G->ravi_state->code_generator->compile(L, p, module, options)) { + if (G->ravi_state->code_generator->compile(L, p, module, options)) { module->runpasses(); module->finalize(G->ravi_state->jit->get_verbosity() == 3); } @@ -866,8 +862,7 @@ int raviV_compile_n(struct lua_State *L, struct Proto *p[], int n, ravi_compile_ return 0; auto module = std::make_shared(G->ravi_state->jit); for (int i = 0; i < n; i++) { - if (G->ravi_state->jit->is_use_dmrc() ? G->ravi_state->code_generator->alt_compile(L, p[i], module, options) - : G->ravi_state->code_generator->compile(L, p[i], module, options)) + if (G->ravi_state->code_generator->compile(L, p[i], module, options)) count++; } if (count) { diff --git a/src/ravi_omrjit.c b/src/ravi_omrjit.c deleted file mode 100644 index 8ae9166..0000000 --- a/src/ravi_omrjit.c +++ /dev/null @@ -1,562 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2018-2020 Dibyendu Majumdar - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ******************************************************************************/ - -#include -#include -#include -#include - -#define LUA_CORE - -#include "lauxlib.h" -#include "lobject.h" -#include "lstate.h" -#include "lua.h" - -static const char *errortext[] = {"integer expected", - "number expected", - "integer[] expected", - "number[] expected", - "table expected", - "upvalue of integer type, cannot be set to non integer value", - "upvalue of number type, cannot be set to non number value", - "upvalue of integer[] type, cannot be set to non integer[] value", - "upvalue of number[] type, cannot be set to non number[] value", - "upvalue of table type, cannot be set to non table value", - "for llimit must be a number", - "for step must be a number", - "for initial value must be a number", - "array index is out of bounds", - "string expected", - "closure expected", - "type mismatch: wrong userdata type", - NULL}; - -static void raise_error(lua_State *L, int errorcode) { - assert(errorcode >= 0 && errorcode < Error_type_mismatch); - luaG_runerror(L, errortext[errorcode]); -} - -static void raise_error_with_info(lua_State *L, int errorcode, const char *info) { - assert(errorcode == Error_type_mismatch); - luaG_runerror(L, "type mismatch: expected %s", info); -} - -static void register_builtin_arg1(JIT_ContextRef module, const char *name, - void *fp, JIT_Type return_type, - JIT_Type arg1) { - JIT_Type args[1]; - args[0] = arg1; - JIT_RegisterFunction(module, name, return_type, 1, args, fp); -} -static void register_builtin_arg2(JIT_ContextRef module, const char *name, - void *fp, JIT_Type return_type, - JIT_Type arg1, - JIT_Type arg2) { - JIT_Type args[2]; - args[0] = arg1; - args[1] = arg2; - JIT_RegisterFunction(module, name, return_type, 2, args, fp); -} -static void register_builtin_arg3(JIT_ContextRef module, const char *name, - void *fp, JIT_Type return_type, - JIT_Type arg1, - JIT_Type arg2, - JIT_Type arg3) { - JIT_Type args[3]; - args[0] = arg1; - args[1] = arg2; - args[2] = arg3; - JIT_RegisterFunction(module, name, return_type, 3, args, fp); -} -static void register_builtin_arg4(JIT_ContextRef module, const char *name, - void *fp, JIT_Type return_type, - JIT_Type arg1, - JIT_Type arg2, - JIT_Type arg3, - JIT_Type arg4) { - JIT_Type args[4]; - args[0] = arg1; - args[1] = arg2; - args[2] = arg3; - args[3] = arg4; - JIT_RegisterFunction(module, name, return_type, 4, args, fp); -} -static void register_builtin_arg5(JIT_ContextRef module, const char *name, - void *fp, JIT_Type return_type, - JIT_Type arg1, - JIT_Type arg2, - JIT_Type arg3, - JIT_Type arg4, - JIT_Type arg5) { - JIT_Type args[5]; - args[0] = arg1; - args[1] = arg2; - args[2] = arg3; - args[3] = arg4; - args[4] = arg5; - JIT_RegisterFunction(module, name, return_type, 5, args, fp); -} - -#if !RAVI_TARGET_X64 -#error OMRJIT is currently only supported on X64 architecture -#endif - -// Initialize the JIT State and attach it to the -// Global Lua State -// If a JIT State already exists then this function -// will return -1 -int raviV_initjit(struct lua_State *L) { - global_State *G = G(L); - if (G->ravi_state != NULL) return -1; - ravi_State *jit = (ravi_State *)calloc(1, sizeof(ravi_State)); - jit->auto_ = 0; - jit->enabled_ = 1; - jit->min_code_size_ = 150; - jit->min_exec_count_ = 50; - jit->opt_level_ = 1; - // The parameter true means we will be dumping stuff as we compile - jit->jit = JIT_CreateContext(); - - // FIXME Portability - following needs to handle 32-bit arch - - //extern void luaF_close (lua_State *L, StkId level); - register_builtin_arg2(jit->jit, "luaF_close", luaF_close, JIT_NoType, JIT_Address, JIT_Address); - register_builtin_arg2(jit->jit, "raise_error", raise_error, JIT_NoType, JIT_Address, JIT_Int32); - register_builtin_arg3(jit->jit, "raise_error_with_info", raise_error_with_info, JIT_NoType, JIT_Address, JIT_Int32, JIT_Address); - //extern int luaV_tonumber_(const TValue *obj, lua_Number *n); - register_builtin_arg2(jit->jit, "luaV_tonumber_", luaV_tonumber_, JIT_Int32, JIT_Address, JIT_Address); - //extern int luaV_tointeger(const TValue *obj, lua_Integer *p, int mode); - register_builtin_arg3(jit->jit, "luaV_tointeger", luaV_tointeger, JIT_Int32, JIT_Address, JIT_Address, JIT_Int32); - //extern int luaD_poscall (lua_State *L, CallInfo *ci, StkId firstResult, int nres); - register_builtin_arg4(jit->jit, "luaD_poscall", luaD_poscall, JIT_Int32, JIT_Address, JIT_Address, JIT_Address, JIT_Int32); - //extern int luaV_equalobj(lua_State *L, const TValue *t1, const TValue *t2);\n" - register_builtin_arg3(jit->jit, "luaV_equalobj", luaV_equalobj, JIT_Int32, JIT_Address, JIT_Address, JIT_Address); - //extern int luaV_lessthan(lua_State *L, const TValue *l, const TValue *r);\n" - register_builtin_arg3(jit->jit, "luaV_lessthan", luaV_lessthan, JIT_Int32, JIT_Address, JIT_Address, JIT_Address); - //extern int luaV_lessequal(lua_State *L, const TValue *l, const TValue *r);\n" - register_builtin_arg3(jit->jit, "luaV_lessequal", luaV_lessequal, JIT_Int32, JIT_Address, JIT_Address, JIT_Address); - //extern int luaV_execute(lua_State *L); - register_builtin_arg1(jit->jit, "luaV_execute", luaV_execute, JIT_Int32, JIT_Address); - //extern void luaV_gettable (lua_State *L, const TValue *t, TValue *key, StkId val) - register_builtin_arg4(jit->jit, "luaV_gettable", luaV_gettable, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Address); - //extern void luaV_settable (lua_State *L, const TValue *t, TValue *key, StkId val); - register_builtin_arg4(jit->jit, "luaV_settable", luaV_settable, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Address); - //int luaD_precall (lua_State *L, StkId func, int nresults, int op_call); - register_builtin_arg4(jit->jit, "luaD_precall", luaD_precall, JIT_Int32, JIT_Address, JIT_Address, JIT_Int32, JIT_Int32); - //extern void raviV_op_newtable(lua_State *L, CallInfo *ci, TValue *ra, int b, int c) - register_builtin_arg5(jit->jit, "raviV_op_newtable", raviV_op_newtable, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Int32, JIT_Int32); - //extern void luaO_arith (lua_State *L, int op, const TValue *p1, const TValue *p2, TValue *res); - register_builtin_arg5(jit->jit, "luaO_arith", luaO_arith, JIT_NoType, JIT_Address, JIT_Int32, JIT_Address, JIT_Address, JIT_Address); - //extern void raviV_op_newarrayint(lua_State *L, CallInfo *ci, TValue *ra); - register_builtin_arg3(jit->jit, "raviV_op_newarrayint", raviV_op_newarrayint, JIT_NoType, JIT_Address, JIT_Address, JIT_Address); - //extern void raviV_op_newarrayfloat(lua_State *L, CallInfo *ci, TValue *ra); - register_builtin_arg3(jit->jit, "raviV_op_newarrayfloat", raviV_op_newarrayfloat, JIT_NoType, JIT_Address, JIT_Address, JIT_Address); - //LUAI_FUNC void raviV_op_setlist(lua_State *L, CallInfo *ci, TValue *ra, int b, int c); - register_builtin_arg5(jit->jit, "raviV_op_setlist", raviV_op_setlist, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Int32, JIT_Int32); - //LUAI_FUNC void raviV_op_concat(lua_State *L, CallInfo *ci, int a, int b, int c); - register_builtin_arg5(jit->jit, "raviV_op_concat", raviV_op_concat, JIT_NoType, JIT_Address, JIT_Address, JIT_Int32, JIT_Int32, JIT_Int32); - //LUAI_FUNC void raviV_op_closure(lua_State *L, CallInfo *ci, LClosure *cl, int a, int Bx); - register_builtin_arg5(jit->jit, "raviV_op_closure", raviV_op_closure, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Int32, JIT_Int32); - //LUAI_FUNC void raviV_op_vararg(lua_State *L, CallInfo *ci, LClosure *cl, int a, int b); - register_builtin_arg5(jit->jit, "raviV_op_vararg", raviV_op_vararg, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Int32, JIT_Int32); - // void luaV_objlen (lua_State *L, StkId ra, const TValue *rb) - register_builtin_arg3(jit->jit, "luaV_objlen", luaV_objlen, JIT_NoType, JIT_Address, JIT_Address, JIT_Address); - //int luaV_forlimit(const TValue *obj, lua_Integer *p, lua_Integer step, int *stopnow); - register_builtin_arg4(jit->jit, "luaV_forlimit", luaV_forlimit, JIT_Int32, JIT_Address, JIT_Address, JIT_Int64, JIT_Address); - // void raviV_op_setupval(lua_State *L, LClosure *cl, TValue *ra, int b); - register_builtin_arg4(jit->jit, "raviV_op_setupval", raviV_op_setupval, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Int32); - register_builtin_arg4(jit->jit, "raviV_op_setupvali", raviV_op_setupvali, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Int32); - register_builtin_arg4(jit->jit, "raviV_op_setupvalf", raviV_op_setupvalf, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Int32); - register_builtin_arg4(jit->jit, "raviV_op_setupvalai", raviV_op_setupvalai, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Int32); - register_builtin_arg4(jit->jit, "raviV_op_setupvalaf", raviV_op_setupvalaf, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Int32); - register_builtin_arg4(jit->jit, "raviV_op_setupvalt", raviV_op_setupvalt, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Int32); - //extern void luaD_call (lua_State *L, StkId func, int nResults); - register_builtin_arg3(jit->jit, "luaD_call", luaD_call, JIT_NoType, JIT_Address, JIT_Address, JIT_Int32); - //"extern void raviH_set_int(lua_State *L, Table *t, lua_Unsigned key, lua_Integer value);\n" - register_builtin_arg4(jit->jit, "raviH_set_int", raviH_set_int, JIT_NoType, JIT_Address, JIT_Address, JIT_Int64, JIT_Int64); - //"extern void raviH_set_float(lua_State *L, Table *t, lua_Unsigned key, lua_Number value);\n" - register_builtin_arg4(jit->jit, "raviH_set_float", raviH_set_float, JIT_NoType, JIT_Address, JIT_Address, JIT_Int64, JIT_Double); - //int raviV_check_usertype(lua_State *L, TString *name, const TValue *o); - register_builtin_arg3(jit->jit, "raviV_check_usertype", raviV_check_usertype, JIT_Int32, JIT_Address, JIT_Address, JIT_Address); - // void luaT_trybinTM (lua_State *L, const TValue *p1, const TValue *p2, TValue *res, TMS event); - register_builtin_arg5(jit->jit, "luaT_trybinTM", luaT_trybinTM, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Address, JIT_Int32); - // void raviV_gettable_sskey(lua_State *L, const TValue *t, TValue *key, StkId val); - register_builtin_arg4(jit->jit, "raviV_gettable_sskey", raviV_gettable_sskey, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Address); - // void raviV_settable_sskey(lua_State *L, const TValue *t, TValue *key, StkId val); - register_builtin_arg4(jit->jit, "raviV_settable_sskey", raviV_settable_sskey, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Address); - // void raviV_gettable_i(lua_State *L, const TValue *t, TValue *key, StkId val); - register_builtin_arg4(jit->jit, "raviV_gettable_i", raviV_gettable_i, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Address); - // void raviV_settable_i(lua_State *L, const TValue *t, TValue *key, StkId val); - register_builtin_arg4(jit->jit, "raviV_settable_i", raviV_settable_i, JIT_NoType, JIT_Address, JIT_Address, JIT_Address, JIT_Address); - - //LUA_API int (lua_absindex)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_absindex", lua_absindex, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API int (lua_gettop)(lua_State *L); - register_builtin_arg1(jit->jit, "lua_gettop", lua_gettop, JIT_Int32, JIT_Address); - //LUA_API void (lua_pushvalue)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_pushvalue", lua_pushvalue, JIT_NoType, JIT_Address, JIT_Int32); - - //LUA_API int (lua_isnumber)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_isnumber", lua_isnumber, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API int (lua_isstring)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_isstring", lua_isstring, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API int (lua_iscfunction)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_iscfunction", lua_iscfunction, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API int (lua_isinteger)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_isinteger", lua_isinteger, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API int (lua_isuserdata)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_isuserdata", lua_isuserdata, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API int (lua_type)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_type", lua_type, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API const char *(lua_typename)(lua_State *L, int tp); - register_builtin_arg2(jit->jit, "lua_typename", (void*)lua_typename, JIT_Address, JIT_Address, JIT_Int32); - //LUA_API const char * (ravi_typename)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "ravi_typename", (void*)ravi_typename, JIT_Address, JIT_Address, JIT_Int32); - - //LUA_API lua_Number(lua_tonumberx) (lua_State *L, int idx, int *isnum); - register_builtin_arg3(jit->jit, "lua_tonumberx", lua_tonumberx, JIT_Double, JIT_Address, JIT_Int32, JIT_Address); - //LUA_API lua_Integer(lua_tointegerx) (lua_State *L, int idx, int *isnum); - register_builtin_arg3(jit->jit, "lua_tointegerx", lua_tointegerx, JIT_Int64, JIT_Address, JIT_Int32, JIT_Address); - //LUA_API int (lua_toboolean)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_toboolean", lua_toboolean, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API const char *(lua_tolstring)(lua_State *L, int idx, size_t *len); - register_builtin_arg3(jit->jit, "lua_tolstring", (void*)lua_tolstring, JIT_Address, JIT_Address, JIT_Int32, JIT_Address); - //LUA_API size_t(lua_rawlen) (lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_rawlen", lua_rawlen, JIT_Int64, JIT_Address, JIT_Int32); - //LUA_API lua_CFunction(lua_tocfunction) (lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_tocfunction", lua_tocfunction, JIT_Address, JIT_Address, JIT_Int32); - //LUA_API void *(lua_touserdata)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_touserdata", lua_touserdata, JIT_Address, JIT_Address, JIT_Int32); - //LUA_API lua_State *(lua_tothread)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_tothread", lua_tothread, JIT_Address, JIT_Address, JIT_Int32); - //LUA_API const void *(lua_topointer)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_topointer", (void *)lua_topointer, JIT_Address, JIT_Address, JIT_Int32); - - //LUA_API void (lua_arith)(lua_State *L, int op); - register_builtin_arg2(jit->jit, "lua_arith", lua_arith, JIT_NoType, JIT_Address, JIT_Int32); - //LUA_API int (lua_rawequal)(lua_State *L, int idx1, int idx2); - register_builtin_arg3(jit->jit, "lua_rawequal", lua_rawequal, JIT_Int32, JIT_Address, JIT_Int32, JIT_Int32); - //LUA_API int (lua_compare)(lua_State *L, int idx1, int idx2, int op); - register_builtin_arg4(jit->jit, "lua_compare", lua_compare, JIT_Int32, JIT_Address, JIT_Int32, JIT_Int32, JIT_Int32); - //LUA_API void (lua_pushnil)(lua_State *L); - register_builtin_arg1(jit->jit, "lua_pushnil", lua_pushnil, JIT_NoType, JIT_Address); - - //LUA_API void (lua_pushnumber)(lua_State *L, lua_Number n); - register_builtin_arg2(jit->jit, "lua_pushnumber", lua_pushnumber, JIT_NoType, JIT_Address, JIT_Double); - //LUA_API void (lua_pushinteger)(lua_State *L, lua_Integer n); - register_builtin_arg2(jit->jit, "lua_pushinteger", lua_pushinteger, JIT_NoType, JIT_Address, JIT_Int64); - //LUA_API const char *(lua_pushlstring)(lua_State *L, const char *s, size_t len); - register_builtin_arg3(jit->jit, "lua_pushlstring", (void*)lua_pushlstring, JIT_Address, JIT_Address, JIT_Address, JIT_Int64); - //LUA_API const char *(lua_pushstring)(lua_State *L, const char *s); - register_builtin_arg2(jit->jit, "lua_pushstring", (void*)lua_pushstring, JIT_Address, JIT_Address, JIT_Address); - //LUA_API void (lua_pushcclosure)(lua_State *L, lua_CFunction fn, int n); - register_builtin_arg3(jit->jit, "lua_pushcclosure", lua_pushcclosure, JIT_NoType, JIT_Address, JIT_Address, JIT_Int32); - // LUA_API void (lua_pushboolean)(lua_State *L, int b); - register_builtin_arg2(jit->jit, "lua_pushboolean", lua_pushboolean, JIT_NoType, JIT_Address, JIT_Int32); - //LUA_API void (lua_pushlightuserdata)(lua_State *L, void *p); - register_builtin_arg2(jit->jit, "lua_pushlightuserdata", lua_pushlightuserdata, JIT_NoType, JIT_Address, JIT_Address); - //LUA_API int (lua_pushthread)(lua_State *L); - register_builtin_arg1(jit->jit, "lua_pushthread", lua_pushthread, JIT_Int32, JIT_Address); - - //LUA_API int (lua_getglobal)(lua_State *L, const char *name); - register_builtin_arg2(jit->jit, "lua_getglobal", lua_getglobal, JIT_Int32, JIT_Address, JIT_Address); - //LUA_API int (lua_gettable)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_gettable", lua_gettable, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API int (lua_getfield)(lua_State *L, int idx, const char *k); - register_builtin_arg3(jit->jit, "lua_getfield", lua_getfield, JIT_Int32, JIT_Address, JIT_Int32, JIT_Address); - //LUA_API int (lua_geti)(lua_State *L, int idx, lua_Integer n); - register_builtin_arg3(jit->jit, "lua_geti", lua_geti, JIT_Int32, JIT_Address, JIT_Int32, JIT_Int64); - //LUA_API int (lua_rawget)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_rawget", lua_rawget, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API int (lua_rawgeti)(lua_State *L, int idx, lua_Integer n); - register_builtin_arg3(jit->jit, "lua_rawgeti", lua_rawgeti, JIT_Int32, JIT_Address, JIT_Int32, JIT_Int64); - //LUA_API int (lua_rawgetp)(lua_State *L, int idx, const void *p); - register_builtin_arg3(jit->jit, "lua_rawgetp", lua_rawgetp, JIT_Int32, JIT_Address, JIT_Int32, JIT_Address); - //LUA_API void (lua_createtable)(lua_State *L, int narr, int nrec); - register_builtin_arg3(jit->jit, "lua_createtable", lua_createtable, JIT_NoType, JIT_Address, JIT_Int32, JIT_Int32); - //LUA_API void *(lua_newuserdata)(lua_State *L, size_t sz); - register_builtin_arg2(jit->jit, "lua_newuserdata", lua_newuserdata, JIT_Address, JIT_Address, JIT_Int64); - //LUA_API int (lua_getmetatable)(lua_State *L, int objindex); - register_builtin_arg2(jit->jit, "lua_getmetatable", lua_getmetatable, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API int (lua_getuservalue)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_getuservalue", lua_getuservalue, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API void (lua_setglobal)(lua_State *L, const char *name); - register_builtin_arg2(jit->jit, "lua_setglobal", lua_setglobal, JIT_NoType, JIT_Address, JIT_Address); - //LUA_API void (lua_settable)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_settable", lua_settable, JIT_NoType, JIT_Address, JIT_Int32); - //LUA_API void (lua_setfield)(lua_State *L, int idx, const char *k); - register_builtin_arg3(jit->jit, "lua_setfield", lua_setfield, JIT_NoType, JIT_Address, JIT_Int32, JIT_Address); - //LUA_API void (lua_seti)(lua_State *L, int idx, lua_Integer n); - register_builtin_arg3(jit->jit, "lua_seti", lua_seti, JIT_NoType, JIT_Address, JIT_Int32, JIT_Int64); - //LUA_API void (lua_rawset)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_rawset", lua_rawset, JIT_NoType, JIT_Address, JIT_Int32); - //LUA_API void (lua_rawseti)(lua_State *L, int idx, lua_Integer n); - register_builtin_arg3(jit->jit, "lua_rawseti", lua_rawseti, JIT_NoType, JIT_Address, JIT_Int32, JIT_Int64); - //LUA_API void (lua_rawsetp)(lua_State *L, int idx, const void *p); - register_builtin_arg3(jit->jit, "lua_rawsetp", lua_rawsetp, JIT_NoType, JIT_Address, JIT_Int32, JIT_Address); - //LUA_API int (lua_setmetatable)(lua_State *L, int objindex); - register_builtin_arg2(jit->jit, "lua_setmetatable", lua_setmetatable, JIT_Int32, JIT_Address, JIT_Int32); - //LUA_API void (lua_setuservalue)(lua_State *L, int idx); - register_builtin_arg2(jit->jit, "lua_setuservalue", lua_setuservalue, JIT_NoType, JIT_Address, JIT_Int32); -#ifdef RAVI_DEFER_STATEMENT - //LUA_API void raviV_op_defer(lua_State *L, TValue *ra); - register_builtin_arg2(jit->jit, "raviV_op_defer", raviV_op_defer, JIT_NoType, JIT_Address, JIT_Address); -#endif - //LUAI_FUNC lua_Integer luaV_shiftl (lua_Integer x, lua_Integer y); - register_builtin_arg2(jit->jit, "luaV_shiftl", luaV_shiftl, JIT_Int64, JIT_Int64, JIT_Int64); - // extern void raviV_op_bnot(lua_State *L, TValue *ra, TValue *rb); - register_builtin_arg3(jit->jit, "raviV_op_bnot", raviV_op_bnot, JIT_NoType, JIT_Address, JIT_Address, JIT_Address); - - G->ravi_state = jit; - return 0; -} - -// Free up the JIT State -void raviV_close(struct lua_State *L) { - global_State *G = G(L); - if (G->ravi_state == NULL) return; - // All compiled functions will be deleted at this stage - JIT_DestroyContext(G->ravi_state->jit); - free(G->ravi_state); -} - -// Dump the intermediate C code -void raviV_dumpIR(struct lua_State *L, struct Proto *p) { - global_State *G = G(L); - if (G->ravi_state == NULL) - return; - - membuff_t buf; - membuff_init(&buf, 4096); - - char fname[30]; - snprintf(fname, sizeof fname, "%s", "jit_function"); - ravi_compile_options_t options; - memset(&options, 0, sizeof options); - options.codegen_type = RAVI_CODEGEN_ALL; - if (raviJ_codegen(L, p, &options, fname, &buf)) { - ravi_writestring(L, buf.buf, strlen(buf.buf)); - ravi_writeline(L); - } - membuff_free(&buf); -} - -// Dump the LLVM ASM -void raviV_dumpASM(struct lua_State *L, struct Proto *p) { - (void)L; - (void)p; -} - -void raviV_setminexeccount(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) return; - G->ravi_state->min_exec_count_ = value; -} -int raviV_getminexeccount(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) return 0; - return G->ravi_state->min_exec_count_; -} - -void raviV_setmincodesize(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) return; - G->ravi_state->min_code_size_ = value; -} -int raviV_getmincodesize(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) return 0; - return G->ravi_state->min_code_size_; -} - -void raviV_setauto(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) return; - G->ravi_state->auto_ = value; -} -int raviV_getauto(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) return 0; - return G->ravi_state->auto_; -} - -// Turn on/off the JIT compiler -void raviV_setjitenabled(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) return; - G->ravi_state->enabled_ = value; -} -int raviV_getjitenabled(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) return 0; - return G->ravi_state->enabled_; -} - -void raviV_setoptlevel(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) return; - G->ravi_state->opt_level_ = value; -} -int raviV_getoptlevel(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) return 0; - return G->ravi_state->opt_level_; -} - -void raviV_setsizelevel(lua_State *L, int value) { - (void)L; - (void)value; -} -int raviV_getsizelevel(lua_State *L) { - (void)L; - return 0; -} - -void raviV_setvalidation(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) return; - G->ravi_state->validation_ = value; -} -int raviV_getvalidation(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) return 0; - return G->ravi_state->validation_; -} - -void raviV_setverbosity(lua_State *L, int value) { - global_State *G = G(L); - if (!G->ravi_state) return; - G->ravi_state->verbosity_ = value; -} -int raviV_getverbosity(lua_State *L) { - global_State *G = G(L); - if (!G->ravi_state) return 0; - return G->ravi_state->verbosity_; -} - -// Turn on/off the JIT compiler -void raviV_settraceenabled(lua_State *L, int value) { - (void)L; - (void)value; -} -int raviV_gettraceenabled(lua_State *L) { - (void)L; - return 0; -} - -int raviV_compile_n(struct lua_State *L, struct Proto *p[], int n, - ravi_compile_options_t *options) { - int count = 0; - for (int i = 0; i < n; i++) { - if (raviV_compile(L, p[i], options)) count++; - } - return count > 0; -} - -// Compile a Lua function -// If JIT is turned off then compilation is skipped -// Compilation occurs if either auto compilation is ON (subject to some -// thresholds) -// or if a manual compilation request was made -// Returns true if compilation was successful -int raviV_compile(struct lua_State *L, struct Proto *p, ravi_compile_options_t *options) { - if (p->ravi_jit.jit_status == RAVI_JIT_COMPILED) - return true; - else if (p->ravi_jit.jit_status == RAVI_JIT_CANT_COMPILE) - return false; - if (options == NULL) return false; - - global_State *G = G(L); - if (G->ravi_state == NULL) return false; - JIT_ContextRef context = G->ravi_state->jit; - if (context == NULL) return false; - - bool doCompile = (bool)(options && options->manual_request != 0); - if (!doCompile && G->ravi_state->auto_) { - if (p->ravi_jit.jit_flags == RAVI_JIT_FLAG_HASFORLOOP) /* function has fornum loop, so compile */ - doCompile = true; - else if (p->sizecode > G->ravi_state->min_code_size_) /* function is long so compile */ - doCompile = true; - else { - if (p->ravi_jit.execution_count < G->ravi_state->min_exec_count_) /* function has been executed many - times so compile */ - p->ravi_jit.execution_count++; - else - doCompile = true; - } - } - if (!doCompile) { return false; } - if (!raviJ_cancompile(p)) { - p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; - return false; - } - - if (G->ravi_state->compiling_) return false; - G->ravi_state->compiling_ = 1; - - membuff_t buf; - membuff_init(&buf, 4096); - - int (*fp)(lua_State * L) = NULL; - char fname[30]; - snprintf(fname, sizeof fname, "jit%lld", G->ravi_state->id++); - char *argv[] = { fname, "-O1", NULL }; - - if (!raviJ_codegen(L, p, options, fname, &buf)) { - p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; - goto Lerror; - } - if (options->manual_request && G->ravi_state->verbosity_) { - ravi_writestring(L, buf.buf, strlen(buf.buf)); - ravi_writeline(L); - } - int opt_level = G->ravi_state->opt_level_; - if (opt_level == 0) - argv[1] = "-O0"; - else if (opt_level >= 2) - argv[1] = "-O2"; - if (!dmrC_omrcompile(2, argv, context, buf.buf)) { - p->ravi_jit.jit_status = RAVI_JIT_CANT_COMPILE; - } - else { - fp = JIT_GetFunction(context, fname); - if (fp != NULL) { - p->ravi_jit.jit_data = NULL; - p->ravi_jit.jit_function = fp; - p->ravi_jit.jit_status = RAVI_JIT_COMPILED; - } - } -Lerror: - membuff_free(&buf); - G->ravi_state->compiling_ = 0; - return fp != NULL; -} - -// Free the JIT compiled function -// Note that this is called by the garbage collector -void raviV_freeproto(struct lua_State *L, struct Proto *p) { - (void)L; - (void)p; -} - diff --git a/src/ravi_omrjitapi.c b/src/ravi_omrjitapi.c deleted file mode 100644 index 019c278..0000000 --- a/src/ravi_omrjitapi.c +++ /dev/null @@ -1,188 +0,0 @@ -#include -#include -#include -#include - -#define LUA_CORE - -#include "lauxlib.h" -#include "lobject.h" -#include "lstate.h" -#include "lua.h" - - -static const char Lua_header[] = "" -"typedef __SIZE_TYPE__ size_t;\n" -"typedef long long ptrdiff_t;\n" -"typedef long long intptr_t;\n" -"typedef long long int64_t;\n" -"typedef unsigned long long uint64_t;\n" -"typedef int int32_t;\n" -"typedef unsigned int uint32_t;\n" -"typedef short int16_t;\n" -"typedef unsigned short uint16_t;\n" -"typedef char int8_t;\n" -"typedef unsigned char uint8_t;\n" -"typedef size_t lu_mem;\n" -"typedef ptrdiff_t l_mem;\n" -"typedef unsigned char lu_byte;\n" -"typedef uint16_t LuaType;\n" -"#define NULL ((void *)0)\n" -"typedef struct lua_State lua_State;\n" -"#define LUA_TNONE (-1)\n" -"#define LUA_TNIL 0\n" -"#define LUA_TBOOLEAN 1\n" -"#define LUA_TLIGHTUSERDATA 2\n" -"#define LUA_TNUMBER 3\n" -"#define LUA_TSTRING 4\n" -"#define LUA_TTABLE 5\n" -"#define LUA_TFUNCTION 6\n" -"#define LUA_TUSERDATA 7\n" -"#define LUA_TTHREAD 8\n" -"typedef double lua_Number;\n" -"typedef int64_t lua_Integer;\n" -"typedef uint64_t lua_Unsigned;\n" -"typedef int (*lua_CFunction) (lua_State *L);\n" -"extern int (lua_absindex)(lua_State *L, int idx);\n" -"extern int (lua_gettop)(lua_State *L);\n" -"extern void (lua_pushvalue)(lua_State *L, int idx);\n" -"extern int (lua_isnumber)(lua_State *L, int idx);\n" -"extern int (lua_isstring)(lua_State *L, int idx);\n" -"extern int (lua_iscfunction)(lua_State *L, int idx);\n" -"extern int (lua_isinteger)(lua_State *L, int idx);\n" -"extern int (lua_isuserdata)(lua_State *L, int idx);\n" -"extern int (lua_type)(lua_State *L, int idx);\n" -"extern const char *(lua_typename)(lua_State *L, int tp);\n" -"extern const char * (ravi_typename)(lua_State *L, int idx);\n" -"extern lua_Number(lua_tonumberx) (lua_State *L, int idx, int *isnum);\n" -"extern lua_Integer(lua_tointegerx) (lua_State *L, int idx, int *isnum);\n" -"extern int (lua_toboolean)(lua_State *L, int idx);\n" -"extern const char *(lua_tolstring)(lua_State *L, int idx, size_t *len);\n" -"extern size_t(lua_rawlen) (lua_State *L, int idx);\n" -"extern lua_CFunction(lua_tocfunction) (lua_State *L, int idx);\n" -"extern void *(lua_touserdata)(lua_State *L, int idx);\n" -"extern lua_State *(lua_tothread)(lua_State *L, int idx);\n" -"extern const void *(lua_topointer)(lua_State *L, int idx);\n" -"#define LUA_OPADD 0\n" -"#define LUA_OPSUB 1\n" -"#define LUA_OPMUL 2\n" -"#define LUA_OPMOD 3\n" -"#define LUA_OPPOW 4\n" -"#define LUA_OPDIV 5\n" -"#define LUA_OPIDIV 6\n" -"#define LUA_OPBAND 7\n" -"#define LUA_OPBOR 8\n" -"#define LUA_OPBXOR 9\n" -"#define LUA_OPSHL 10\n" -"#define LUA_OPSHR 11\n" -"#define LUA_OPUNM 12\n" -"#define LUA_OPBNOT 13\n" -"extern void (lua_arith)(lua_State *L, int op);\n" -"#define LUA_OPEQ 0\n" -"#define LUA_OPLT 1\n" -"#define LUA_OPLE 2\n" -"extern int (lua_rawequal)(lua_State *L, int idx1, int idx2);\n" -"extern int (lua_compare)(lua_State *L, int idx1, int idx2, int op);\n" -"extern void (lua_pushnil)(lua_State *L);\n" -"extern void (lua_pushnumber)(lua_State *L, lua_Number n);\n" -"extern void (lua_pushinteger)(lua_State *L, lua_Integer n);\n" -"extern const char *(lua_pushlstring)(lua_State *L, const char *s, size_t len);\n" -"extern const char *(lua_pushstring)(lua_State *L, const char *s);\n" -"extern void (lua_pushcclosure)(lua_State *L, lua_CFunction fn, int n);\n" -"extern void (lua_pushboolean)(lua_State *L, int b);\n" -"extern void (lua_pushlightuserdata)(lua_State *L, void *p);\n" -"extern int (lua_pushthread)(lua_State *L);\n" -"extern int (lua_getglobal)(lua_State *L, const char *name);\n" -"extern int (lua_gettable)(lua_State *L, int idx);\n" -"extern int (lua_getfield)(lua_State *L, int idx, const char *k);\n" -"extern int (lua_geti)(lua_State *L, int idx, lua_Integer n);\n" -"extern int (lua_rawget)(lua_State *L, int idx);\n" -"extern int (lua_rawgeti)(lua_State *L, int idx, lua_Integer n);\n" -"extern int (lua_rawgetp)(lua_State *L, int idx, const void *p);\n" -"extern void (lua_createtable)(lua_State *L, int narr, int nrec);\n" -"extern void *(lua_newuserdata)(lua_State *L, size_t sz);\n" -"extern int (lua_getmetatable)(lua_State *L, int objindex);\n" -"extern int (lua_getuservalue)(lua_State *L, int idx);\n" -"extern void (lua_setglobal)(lua_State *L, const char *name);\n" -"extern void (lua_settable)(lua_State *L, int idx);\n" -"extern void (lua_setfield)(lua_State *L, int idx, const char *k);\n" -"extern void (lua_seti)(lua_State *L, int idx, lua_Integer n);\n" -"extern void (lua_rawset)(lua_State *L, int idx);\n" -"extern void (lua_rawseti)(lua_State *L, int idx, lua_Integer n);\n" -"extern void (lua_rawsetp)(lua_State *L, int idx, const void *p);\n" -"extern int (lua_setmetatable)(lua_State *L, int objindex);\n" -"extern void (lua_setuservalue)(lua_State *L, int idx);\n" -; - -enum { - MAX_ARGS = 50, - MAX_BUFFER = 4096 -}; - -static int collect_args(lua_State *L, int tabindex, char *argv[], int maxargs, - char *buf, int buflen) { - char errormessage[128]; - int len = lua_rawlen(L, tabindex); - if (len > maxargs) { - snprintf(errormessage, sizeof errormessage, - "Arguments exceed total count %d elements", maxargs); - luaL_argerror(L, 2, errormessage); - len = maxargs; - } - char *p = buf; - char *endp = buf + buflen; - int n = 0; - for (int i = 0; i < len; i++) { - lua_rawgeti(L, tabindex, i + 1); - size_t size = 0; - const char *argument = luaL_checklstring(L, -1, &size); - if (argument && size > 0) { - if (p + size + 1 >= endp) { - snprintf(errormessage, sizeof errormessage, - "Arguments exceed combined size of %d bytes", buflen); - luaL_argerror(L, 2, errormessage); - break; - } - strncpy(p, argument, size + 1); - argv[n] = p; - p += (size + 1); - n++; - } - } - assert(p <= endp); - return n; -} - -int ravi_compile_C(lua_State *L) { - global_State *G = G(L); - if (G->ravi_state == NULL) return 0; - JIT_ContextRef context = G->ravi_state->jit; - if (context == NULL) return 0; - - const char *codebuffer = NULL; - char *argv[MAX_ARGS + 1] = {NULL}; - int argc = 0; - char buf[MAX_BUFFER + 1] = {0}; - int guard = 0xfefefefe; - int codearg = 1; - if (lua_istable(L, 1)) { - argc = collect_args(L, 1, argv, MAX_ARGS, buf, sizeof buf); - assert(argc >= 0 && argc <= MAX_ARGS); - assert(argv[MAX_ARGS] == NULL); - assert(guard == 0xfefefefe); - codearg++; - } - codebuffer = luaL_checkstring(L, codearg); - membuff_t mbuf; - membuff_init(&mbuf, strlen(Lua_header) + 4096); - membuff_add_string(&mbuf, Lua_header); - membuff_add_string(&mbuf, codebuffer); - if (!dmrC_omrcompile(argc, argv, context, mbuf.buf)) { - lua_pushboolean(L, false); - } - else { - lua_pushboolean(L, true); - } - membuff_free(&mbuf); - return 1; -}