├── .editorconfig ├── .gitignore ├── CMakeLists.txt ├── README.md ├── core ├── Block.cpp ├── Block.h ├── Func.cpp ├── Func.h ├── PassType.h ├── Program.cpp └── Program.h ├── expr ├── BinaryExpr.cpp ├── BinaryExpr.h ├── Expr.cpp ├── Expr.h ├── ExprVisitor.h ├── UnaryExpr.cpp └── UnaryExpr.h ├── main.cpp ├── parser ├── ProgramParser.cpp ├── ProgramParser.h ├── README.md ├── SimplifyingExprVisitor.cpp ├── SimplifyingExprVisitor.h ├── addSignCasts.cpp ├── arrowify.cpp ├── cfunc.h ├── compare.h ├── computeGlobalVarsOrder.cpp ├── constval.cpp ├── constval.h ├── createAllocas.cpp ├── createBlocks.cpp ├── createConstants.cpp ├── createExpressions.cpp ├── createFunctionParameters.cpp ├── createFunctions.cpp ├── deleteRedundantCasts.cpp ├── deleteUnusedVariables.cpp ├── determineIncludes.cpp ├── extractVars.cpp ├── findDeclaredFunctions.cpp ├── findMetadataFunctionNames.cpp ├── findMetadataVariableNames.cpp ├── fixMainParameters.cpp ├── identifyInlinableBlocks.cpp ├── initializeGlobalVars.cpp ├── inlineBlocks.cpp ├── memcpyToAssign.cpp ├── nameFunctions.cpp ├── parseBreaks.cpp ├── parseMetadataTypes.cpp ├── parseStructDeclarations.cpp ├── parseStructItems.cpp ├── passes.h ├── prepareBitcastUnion.cpp ├── refDeref.cpp ├── toinst.cpp └── toinst.h ├── test ├── CMakeLists.txt ├── base.c ├── csmith_testing.py ├── diffs ├── expected │ ├── asm │ │ ├── basic_add.c │ │ ├── mov.c │ │ └── multiple_asm.c │ ├── branching │ │ ├── if.c │ │ └── nested_if.c │ ├── globals │ │ ├── init_by_func.c │ │ ├── no_init.c │ │ └── recursive_init.c │ ├── loops │ │ ├── do_while.c │ │ ├── for_loop.c │ │ ├── inline_inc.c │ │ ├── nested_loops.c │ │ └── while.c │ ├── main │ │ ├── main_int.c │ │ └── main_void.c │ ├── math │ │ ├── add_sub_div_mul.c │ │ ├── and_xor.c │ │ ├── digit_sum.c │ │ ├── fact.c │ │ ├── fact_rec.c │ │ ├── isPrime.c │ │ ├── mod.c │ │ ├── pow_gt.c │ │ └── shifts.c │ ├── phi │ │ └── phi1.c │ ├── pointer │ │ ├── array_of_ptr.c │ │ ├── func_ptr.c │ │ ├── ref_deref.c │ │ └── ret_array_ptr.c │ ├── standard_lib │ │ ├── math.c │ │ ├── stdlib.c │ │ └── string.c │ ├── statements │ │ ├── select.c │ │ └── switch.c │ ├── struct │ │ ├── array_of_structs.c │ │ ├── basic_struct.c │ │ ├── return_struct.c │ │ ├── struct_assignment.c │ │ ├── struct_with_ptrarray.c │ │ ├── struct_with_struct.c │ │ └── struct_with_structptr.c │ └── union │ │ └── float_and_unsigned.c ├── inputs │ ├── asm │ │ ├── basic_add.c │ │ ├── mov.c │ │ └── multiple_asm.c │ ├── branching │ │ ├── if.c │ │ └── nested_if.c │ ├── globals │ │ ├── init_by_func.c │ │ ├── no_init.c │ │ └── recursive_init.c │ ├── loops │ │ ├── do_while.c │ │ ├── for_loop.c │ │ ├── inline_inc.c │ │ ├── nested_loops.c │ │ └── while.c │ ├── main │ │ ├── main_int.c │ │ └── main_void.c │ ├── math │ │ ├── add_sub_div_mul.c │ │ ├── and_xor.c │ │ ├── digit_sum.c │ │ ├── fact.c │ │ ├── fact_rec.c │ │ ├── isPrime.c │ │ ├── mod.c │ │ ├── pow_gt.c │ │ └── shifts.c │ ├── phi │ │ └── phi1.c │ ├── pointer │ │ ├── array_of_ptr.c │ │ ├── func_ptr.c │ │ ├── ref_deref.c │ │ └── ret_array_ptr.c │ ├── standard_lib │ │ ├── math.c │ │ ├── stdlib.c │ │ └── string.c │ ├── statements │ │ ├── select.c │ │ └── switch.c │ ├── struct │ │ ├── array_of_structs.c │ │ ├── basic_struct.c │ │ ├── return_struct.c │ │ ├── struct_assignment.c │ │ ├── struct_with_ptrarray.c │ │ ├── struct_with_struct.c │ │ └── struct_with_structptr.c │ └── union │ │ └── float_and_unsigned.c ├── run.in └── update-expected ├── type ├── Type.cpp ├── Type.h ├── TypeHandler.cpp └── TypeHandler.h └── writer ├── CWriter.cpp ├── CWriter.h ├── ExprWriter.cpp ├── ExprWriter.h ├── Writer.cpp └── Writer.h /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most EditorConfig file 2 | # see https://editorconfig.org/ for more information 3 | root = true 4 | 5 | [*.{c,cpp,h}] 6 | end_of_line = lf 7 | insert_final_newline = true 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 4 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | CMakeCache.txt 2 | CMakeFiles/ 3 | Makefile 4 | tags 5 | cmake_install.cmake 6 | llvm2c 7 | test/llvm2c 8 | build 9 | build-* 10 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | # FIXME: Unfortunately, C is (at least temporarily) required due to a bug 4 | # in LLVM 14. See https://github.com/llvm/llvm-project/issues/53950. 5 | project(llvm2c LANGUAGES C CXX) 6 | 7 | # -------------------------------------------------- 8 | # Build type 9 | # -------------------------------------------------- 10 | if(NOT CMAKE_BUILD_TYPE) 11 | message(STATUS "Build type not set. Setting default.") 12 | set(CMAKE_BUILD_TYPE "RelWithDebInfo" CACHE STRING "" FORCE) 13 | endif() 14 | message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") 15 | set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "RelWithDebInfo" 16 | "MinSizeRel" "Release") 17 | 18 | # -------------------------------------------------- 19 | # Compilation flags 20 | # -------------------------------------------------- 21 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 22 | set(CMAKE_CXX_EXTENSIONS OFF) 23 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -Wextra -pedantic -fno-rtti") 24 | 25 | # -------------------------------------------------- 26 | # LLVM 27 | # -------------------------------------------------- 28 | find_package(LLVM REQUIRED CONFIG) 29 | 30 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 31 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 32 | 33 | if(${LLVM_PACKAGE_VERSION} VERSION_LESS "5.0") 34 | message(FATAL_ERROR "LLVM 5.0 or newer is required!") 35 | endif() 36 | 37 | message(STATUS "LLVM include dir: ${LLVM_INCLUDE_DIRS}") 38 | message(STATUS "LLVM libraries dir: ${LLVM_LIBRARY_DIRS}") 39 | message(STATUS "LLVM definitions: ${LLVM_DEFINITIONS}") 40 | 41 | list(APPEND CMAKE_MODULE_PATH "${LLVM_DIR}") 42 | include(AddLLVM) 43 | 44 | add_definitions(${LLVM_DEFINITIONS}) 45 | include_directories(SYSTEM ${LLVM_INCLUDE_DIRS}) 46 | link_directories(${LLVM_LIBRARY_DIRS}) 47 | 48 | option(LLVM_LINK_DYLIB "Link with LLVM dynamically" ON) 49 | if(LLVM_LINK_DYLIB) 50 | message(STATUS "LLVM linking: dynamic") 51 | set(llvm_libs LLVM) 52 | else() 53 | message(STATUS "LLVM linking: static") 54 | # Find the libraries that correspond to the LLVM components 55 | # that we wish to use 56 | llvm_map_components_to_libnames(llvm_libs bitwriter core irreader linker 57 | support) 58 | endif() 59 | 60 | # -------------------------------------------------- 61 | # llvm2c 62 | # -------------------------------------------------- 63 | set(llvm2c_sources 64 | main.cpp 65 | 66 | core/Block.cpp 67 | core/Block.h 68 | core/Func.cpp 69 | core/Func.h 70 | core/Program.cpp 71 | core/Program.h 72 | 73 | expr/BinaryExpr.cpp 74 | expr/BinaryExpr.h 75 | expr/Expr.cpp 76 | expr/Expr.h 77 | expr/UnaryExpr.cpp 78 | expr/UnaryExpr.h 79 | 80 | parser/ProgramParser.cpp 81 | parser/ProgramParser.h 82 | parser/SimplifyingExprVisitor.cpp 83 | parser/addSignCasts.cpp 84 | parser/arrowify.cpp 85 | parser/cfunc.h 86 | parser/computeGlobalVarsOrder.cpp 87 | parser/constval.cpp 88 | parser/createAllocas.cpp 89 | parser/createBlocks.cpp 90 | parser/createConstants.cpp 91 | parser/createExpressions.cpp 92 | parser/createFunctionParameters.cpp 93 | parser/createFunctions.cpp 94 | parser/deleteRedundantCasts.cpp 95 | parser/deleteUnusedVariables.cpp 96 | parser/determineIncludes.cpp 97 | parser/extractVars.cpp 98 | parser/findDeclaredFunctions.cpp 99 | parser/findMetadataFunctionNames.cpp 100 | parser/findMetadataVariableNames.cpp 101 | parser/fixMainParameters.cpp 102 | parser/identifyInlinableBlocks.cpp 103 | parser/initializeGlobalVars.cpp 104 | parser/inlineBlocks.cpp 105 | parser/memcpyToAssign.cpp 106 | parser/nameFunctions.cpp 107 | parser/parseBreaks.cpp 108 | parser/parseMetadataTypes.cpp 109 | parser/parseStructDeclarations.cpp 110 | parser/parseStructItems.cpp 111 | parser/passes.h 112 | parser/prepareBitcastUnion.cpp 113 | parser/refDeref.cpp 114 | parser/toinst.cpp 115 | parser/toinst.h 116 | 117 | type/Type.cpp 118 | type/Type.h 119 | type/TypeHandler.cpp 120 | type/TypeHandler.h 121 | 122 | writer/CWriter.cpp 123 | writer/ExprWriter.cpp 124 | writer/Writer.cpp 125 | ) 126 | add_executable(llvm2c ${llvm2c_sources}) 127 | target_link_libraries(llvm2c ${llvm_libs}) 128 | 129 | include(GNUInstallDirs) 130 | install(TARGETS llvm2c 131 | RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) 132 | 133 | # -------------------------------------------------- 134 | # Subdirectories 135 | # -------------------------------------------------- 136 | add_subdirectory(test) 137 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # llvm2c 2 | 3 | Translation of LLVM bitcode to C 4 | 5 | ## Dependencies 6 | 7 | The only requirements are CMake in version at least 3.1 and LLVM 5 or newer. 8 | The project is not compilable on older LLVM's at the moment. (Patches are 9 | welcome :smile:) 10 | 11 | ## Building 12 | 13 | ```sh 14 | git clone https://github.com/staticafi/llvm2c 15 | cd llvm2c 16 | mkdir build 17 | cd build 18 | cmake .. -DCMAKE_INSTALL_PREFIX=installation/path/ 19 | make 20 | ``` 21 | 22 | ## Testing 23 | 24 | Just run `make check`. 25 | 26 | ### Testing with CSmith 27 | 28 | To test `llvm2c` with [csmith](https://github.com/csmith-project/csmith/): 29 | 30 | 1. compile `csmith` and `llvm2c` 31 | 2. copy `csmith/src/csmith` binary to `test/` folder 32 | 3. copy `csmith/runtime` to `test/` folder and rename it to `csmith-runtime` 33 | 4. `cd test/` 34 | 5. `mkdir csmith-tests/` 35 | 6. `./csmith_testing.py` 36 | 37 | The script generates 1000 testing programs. Each program is translated to LLVM 38 | via `clang` and then back to C via `llvm2c`. The only thing that is currently 39 | tested is, that `llvm2c` binary does not crash. 40 | 41 | ## Unsupported features 42 | 43 | - vector instructions 44 | - atomic operations 45 | - some special intrinsics 46 | - the code generation is currently fitted to x86\_64 bitcode 47 | 48 | ## Authors 49 | 50 | * **Petr Vitovský** - [petrv7](https://github.com/petrv7) 51 | * **Tomáš Jašek** - [tomsik68](https://github.com/tomsik68) 52 | * **Marek Chalupa** - [mchalupa](https://github.com/mchalupa) 53 | -------------------------------------------------------------------------------- /core/Block.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include "Block.h" 3 | 4 | #include "llvm/Support/raw_ostream.h" 5 | #include "llvm/IR/Constants.h" 6 | #include "llvm/IR/BasicBlock.h" 7 | #include "llvm/IR/InstrTypes.h" 8 | #include "llvm/IR/DerivedTypes.h" 9 | #include "llvm/IR/GetElementPtrTypeIterator.h" 10 | #include "llvm/ADT/APInt.h" 11 | 12 | #include "Func.h" 13 | #include "../type/Type.h" 14 | #include "../expr/BinaryExpr.h" 15 | #include "../expr/UnaryExpr.h" 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | 26 | Block::Block(const std::string &blockName, const llvm::BasicBlock* block, Func* func) 27 | : block(block), func(func), blockName(blockName) { } 28 | 29 | void Block::addOwnership(std::unique_ptr expr) { 30 | func->program->ownership.push_back(std::move(expr)); 31 | } 32 | 33 | void Block::addExprAndOwnership(std::unique_ptr expr) { 34 | addExpr(expr.get()); 35 | addOwnership(std::move(expr)); 36 | } 37 | -------------------------------------------------------------------------------- /core/Block.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "llvm/ADT/DenseMap.h" 4 | #include "llvm/IR/Instruction.h" 5 | #include "llvm/IR/Instructions.h" 6 | #include "llvm/IR/Value.h" 7 | #include "llvm/IR/Constants.h" 8 | #include "llvm/IR/DebugInfoMetadata.h" 9 | #include "llvm/IR/InlineAsm.h" 10 | 11 | #include "../expr/Expr.h" 12 | 13 | class Func; 14 | 15 | /** 16 | * @brief The Block class represents one of the block of the LLVM function. 17 | */ 18 | class Block { 19 | friend class Func; 20 | public: 21 | const llvm::BasicBlock* block; 22 | 23 | Func* func; 24 | 25 | // a sequence of expression forming this basic block 26 | std::vector expressions; 27 | 28 | //store expressions 29 | std::map derefs; //Map used for storing pointers to DerefExpr (used in store instruction parsing) 30 | 31 | // instead of `goto block`, the block will be outputed in place 32 | bool doInline = false; 33 | 34 | // is this first block of a function? 35 | bool isFirst; 36 | 37 | /** 38 | * @brief createConstantValue Creates Value for given ConstantInt or ConstantFP and inserts it into exprMap. 39 | * @param val constant value 40 | */ 41 | void createConstantValue(const llvm::Value* val); 42 | 43 | /** 44 | * @brief createFuncCallParam Creates new Expr for parameter of function call. 45 | * @param param Parameter of function call 46 | */ 47 | void createFuncCallParam(const llvm::Use& param); 48 | 49 | /** 50 | * @brief getAsmOutputString Parses asm constraint string to get output operands. 51 | * @param info ConstraintInfoVector containing parsed asm constraint string 52 | * @return Strings containing output operand for inline assembler 53 | */ 54 | std::vector getAsmOutputStrings(llvm::InlineAsm::ConstraintInfoVector info) const; 55 | 56 | /** 57 | * @brief getAsmInputStrings Parses asm constraint string to get input operands. 58 | * @param info ConstraintInfoVector containing parsed asm constraint string 59 | * @return Vector of strings containing input operand for inline assembler 60 | */ 61 | std::vector getAsmInputStrings(llvm::InlineAsm::ConstraintInfoVector info) const; 62 | 63 | /** 64 | * @brief getRegisterString Parses string containing register label from LLVM to C. 65 | * @param str LLVM register string 66 | * @return C register string 67 | */ 68 | std::string getRegisterString(const std::string& str) const; 69 | 70 | /** 71 | * @brief getAsmUsedRegString Parses asm constraint string to get used registers. 72 | * @param info ConstraintInfoVector containing parsed asm constraint string 73 | * @return String containing used registers 74 | */ 75 | std::string getAsmUsedRegString(llvm::InlineAsm::ConstraintInfoVector info) const; 76 | 77 | /** 78 | * @brief toRawString Converts string to its raw format (including escape chars etc.) 79 | * @param str String 80 | * @return String in raw format 81 | */ 82 | std::string toRawString(const std::string& str) const; 83 | 84 | public: 85 | std::string blockName; 86 | 87 | void addExpr(Expr *expr) { 88 | assert(expr); 89 | expressions.push_back(expr); 90 | } 91 | 92 | /** 93 | * @brief Block Constructor for Block. 94 | * @param blockName Name of the block 95 | * @param block llvm::BasicBlock for parsing 96 | * @param func Func where the block is located 97 | */ 98 | Block(const std::string &blockName, const llvm::BasicBlock* block, Func* func); 99 | 100 | void insertValue(const llvm::Value* value, std::unique_ptr expr); 101 | 102 | Value* getValue(const llvm::Value* value); 103 | 104 | void addOwnership(std::unique_ptr expr); 105 | 106 | void addExprAndOwnership(std::unique_ptr expr); 107 | }; 108 | -------------------------------------------------------------------------------- /core/Func.cpp: -------------------------------------------------------------------------------- 1 | #include "Func.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "../type/Type.h" 8 | #include "../parser/cfunc.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | Func::Func(const llvm::Function* func, Program* program, bool isDeclaration) { 18 | this->program = program; 19 | function = func; 20 | this->isDeclaration = isDeclaration; 21 | returnType = getType(func->getReturnType()); 22 | } 23 | 24 | Expr* Func::getExpr(const llvm::Value* val) { 25 | auto it = program->exprMap.find(val); 26 | if (it == program->exprMap.end()) { 27 | if (auto F = llvm::dyn_cast_or_null(val)) { 28 | createExpr(val, std::make_unique(F->getName().str(), getType(F->getReturnType()))); 29 | return program->exprMap.find(val)->second; 30 | } 31 | } else { 32 | return it->second; 33 | } 34 | 35 | return program->getGlobalVar(val); 36 | } 37 | 38 | void Func::createExpr(const llvm::Value* val, std::unique_ptr expr) { 39 | program->exprMap[val] = expr.get(); 40 | program->ownership.push_back(std::move(expr)); 41 | } 42 | 43 | std::string Func::getVarName() { 44 | std::string varName = "var"; 45 | while (metadataVarNames.count(varName + std::to_string(varCount))) { 46 | varCount++; 47 | } 48 | varName += std::to_string(varCount); 49 | varCount++; 50 | 51 | return varName; 52 | } 53 | 54 | StructType* Func::getStruct(const llvm::StructType* strct) const { 55 | return program->getStruct(strct); 56 | } 57 | 58 | StructType* Func::getStruct(const std::string& name) const { 59 | return program->getStruct(name); 60 | } 61 | 62 | RefExpr* Func::getGlobalVar(llvm::Value* val) const { 63 | return program->getGlobalVar(val); 64 | } 65 | 66 | void Func::stackIgnored() { 67 | program->stackIgnored = true; 68 | } 69 | 70 | void Func::createNewUnnamedStruct(const llvm::StructType* strct) { 71 | program->createNewUnnamedStruct(strct); 72 | } 73 | 74 | Type* Func::getType(const llvm::Type* type) { 75 | return program->getType(type); 76 | } 77 | 78 | Expr* Func::createPhiVariable(const llvm::Value* phi) { 79 | auto var = std::make_unique(getVarName() + "_phi", getType(phi->getType())); 80 | auto* stackAlloc = program->makeExpr(var.get()); 81 | entry->addExpr(stackAlloc); 82 | 83 | return program->addOwnership(std::move(var)); 84 | } 85 | 86 | Block* Func::createBlockIfNotExist(const llvm::BasicBlock* block) { 87 | auto iter = blockMap.find(block); 88 | Block *result = nullptr; 89 | if (iter == blockMap.end()) { 90 | std::string blockName = "block"; 91 | blockName += std::to_string(blockCount); 92 | auto newBlock = std::make_unique(blockName, block, this); 93 | result = newBlock.get(); 94 | blockMap[block] = std::move(newBlock); 95 | blockCount++; 96 | } else { 97 | result = iter->second.get(); 98 | } 99 | return result; 100 | } 101 | 102 | Block* Func::getBlock(const llvm::BasicBlock* block) { 103 | auto iter = blockMap.find(block); 104 | if (iter == blockMap.end()) { 105 | return nullptr; 106 | } 107 | return iter->second.get(); 108 | } 109 | 110 | void Func::setVarArg(bool va) { 111 | isVarArg = va; 112 | } 113 | 114 | void Func::addMetadataVarName(const std::string& varName) { 115 | metadataVarNames.insert(varName); 116 | } 117 | -------------------------------------------------------------------------------- /core/Func.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "llvm/ADT/DenseMap.h" 9 | 10 | class Program; 11 | 12 | #include "../expr/Expr.h" 13 | #include "../expr/UnaryExpr.h" 14 | #include "../expr/BinaryExpr.h" 15 | #include "Block.h" 16 | #include "Program.h" 17 | 18 | /** 19 | * @brief The Func class represents one of the functions of the LLVM program. 20 | */ 21 | class Func { 22 | friend class Block; 23 | friend class Program; 24 | 25 | public: 26 | Type* returnType; 27 | 28 | const llvm::Function* function; 29 | Program* program; 30 | 31 | Block* entry; 32 | 33 | std::map> blockMap; //DenseMap used for mapping llvm::BasicBlock to Block 34 | 35 | std::string name; 36 | 37 | std::vector parameters; 38 | 39 | //set containing metadata names of variables (and names of global variables) that are in "var[0-9]+" format, used in creating variable names 40 | std::set metadataVarNames; 41 | 42 | // variables that should be declared at the beginning of the function 43 | std::vector variables; 44 | 45 | // if there are more variables named the same way in this function, we maintain a counter 46 | std::unordered_map variableCounters; 47 | 48 | //variables used for creating names for variables and blocks 49 | unsigned varCount = 0; 50 | unsigned blockCount = 0; 51 | 52 | bool isDeclaration; //function is only being declared 53 | bool isVarArg = false; //function has variable number of arguments 54 | 55 | Expr* lastArg; //last argument before variable arguments 56 | 57 | 58 | /** 59 | * @brief createNewUnnamedStruct 60 | * @param strct 61 | */ 62 | void createNewUnnamedStruct(const llvm::StructType* strct); 63 | 64 | /** 65 | * @brief getMetadataNames Parses variable medatada in function and saves the variable names into the metadataVarNames set. 66 | */ 67 | void getMetadataNames(); 68 | 69 | public: 70 | /** 71 | * @brief getBlockName Returns name of the block if the block already has an assigned name. 72 | * Otherwise assigns new name for the block in form of string containing block + blockCount, 73 | * inserts the block to the blockMap and return the assigned name. 74 | * @param block llvm::BasicBlock 75 | * @return Name assigned for given block. 76 | */ 77 | std::string getBlockName(const llvm::BasicBlock* block); //RENAME 78 | 79 | /** 80 | * @brief Func Constructor for Func. 81 | * @param func llvm::Function for parsing 82 | * @param program Program to which function belongs 83 | * @param isDeclaration function is only being declared 84 | */ 85 | Func(const llvm::Function* func, Program* program, bool isDeclaration); 86 | 87 | /** 88 | * @brief getStruct Returns pointer to the Struct corresponding to the given LLVM StructType. 89 | * @param strct LLVM StructType 90 | * @return Pointer to Struct expression if the struct is found, nullptr otherwise 91 | */ 92 | StructType* getStruct(const llvm::StructType* strct) const; 93 | 94 | /** 95 | * @brief getStruct Returns pointer to the Struct with the given name. 96 | * @param name Name of the struct 97 | * @return Pointer to Struct expression if the struct is found, nullptr otherwise 98 | */ 99 | StructType* getStruct(const std::string& name) const; 100 | 101 | /** 102 | * @brief getGlobalVar Returns corresponding refference to GlobalValue expression. 103 | * @param val llvm global variable 104 | * @return RefExpr expression 105 | */ 106 | RefExpr* getGlobalVar(llvm::Value* val) const; 107 | 108 | /** 109 | * @brief stackIgnored Indicated that intrinsic stacksave/stackrestore was ignored. 110 | */ 111 | void stackIgnored(); 112 | 113 | /** 114 | * @brief getType Transforms llvm::Type into corresponding Type object 115 | * @param type llvm::Type for transformation 116 | * @return unique_ptr to corresponding Type object 117 | */ 118 | Type* getType(const llvm::Type* type); 119 | 120 | /** 121 | * @brief createBlockIfNotExist Creates a new block inside of this function that corresponds to @block 122 | * @param block LLVM BasicBlock to create a new block for 123 | */ 124 | Block* createBlockIfNotExist(const llvm::BasicBlock* block); 125 | 126 | /** 127 | * @brief getExpr Finds Expr in exprMap or globalRefs with key val. If val is function, creates Value containing refference to the function and returns pointer to this Value. 128 | * @param val Key of the Expr 129 | * @return Pointer to the Expr if val is found, nullptr otherwise. 130 | */ 131 | Expr* getExpr(const llvm::Value* val); 132 | 133 | /** 134 | * @brief createExpr Inserts expr into the exprMap using val as a key. 135 | * @param val Key 136 | * @param expr Mapped Value 137 | */ 138 | void createExpr(const llvm::Value* val, std::unique_ptr expr); 139 | 140 | /** 141 | * @brief getBlock Obtains a block from this function that corresponds to the specified LLVM block 142 | * @param block LLVM basic block 143 | * @return Pointer to the block if found, nullptr otherwise. 144 | */ 145 | Block* getBlock(const llvm::BasicBlock* block); 146 | 147 | /** 148 | * @brief getVarName Creates a new name for a variable in form of string containing "var" + varCount. 149 | * @return String containing a variable name. 150 | */ 151 | std::string getVarName(); 152 | 153 | void setVarArg(bool va); 154 | 155 | template< typename T > 156 | void fillMetadataVarNames(const T& globalVarNames) { 157 | metadataVarNames.insert(globalVarNames.begin(), globalVarNames.end()); 158 | } 159 | 160 | void addMetadataVarName(const std::string& varName); 161 | 162 | /** 163 | * @brief createPhiVariable Creates a new variable for @phi. 164 | */ 165 | Expr* createPhiVariable(const llvm::Value* phi); 166 | 167 | void output(std::ostream& out); 168 | 169 | }; 170 | -------------------------------------------------------------------------------- /core/PassType.h: -------------------------------------------------------------------------------- 1 | 2 | enum class PassType { 3 | InitializeGlobalVars, 4 | ParseStructDeclarations, 5 | ParseStructItems, 6 | ParseFunctions, 7 | DetermineIncludes, 8 | FindMetadataFunctionNames, 9 | FindMetadataVariableNames, 10 | CreateFunctions, 11 | CreateFunctionParameters, 12 | CreateBlocks, 13 | CreateAllocas, 14 | ParseMetadataTypes, 15 | CreateExpressions, 16 | FindDeclaredFunctions, 17 | NameFunctions, 18 | ParseBreaks, 19 | IdentifyInlinableBlocks, 20 | InlineBlocks, 21 | RefDeref, 22 | FixMainParameters, 23 | AddSignCasts, 24 | DeleteRedundantCasts, 25 | DeleteUnusedVariables, 26 | ExtractVars, 27 | Arrowify, 28 | MemcpyToAssignment, 29 | ComputeGlobalVarsOrder, 30 | CreateConstants, 31 | PrepareBitcastUnion, 32 | }; 33 | -------------------------------------------------------------------------------- /core/Program.cpp: -------------------------------------------------------------------------------- 1 | #include "Program.h" 2 | 3 | #include 4 | #include "llvm/Support/raw_ostream.h" 5 | #include "llvm/IRReader/IRReader.h" 6 | #include "llvm/IR/Constants.h" 7 | 8 | #include "../type/Type.h" 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | Program::Program() : typeHandler(TypeHandler(this)) { 17 | } 18 | 19 | std::string Program::getAnonStructName() { 20 | std::string name = "anonymous_struct" + std::to_string(anonStructCount); 21 | anonStructCount++; 22 | return name; 23 | } 24 | 25 | StructType* Program::getStruct(const llvm::StructType* strct) const { 26 | std::string structName = TypeHandler::getStructName(strct->getName().str()); 27 | 28 | for (const auto& structElem : structs) { 29 | if (structElem->name.compare(structName) == 0) { 30 | return structElem.get(); 31 | } 32 | } 33 | 34 | if (unnamedStructs.find(strct) != unnamedStructs.end()) { 35 | return unnamedStructs.find(strct)->second.get(); 36 | } 37 | 38 | return nullptr; 39 | } 40 | 41 | StructType* Program::getStruct(const std::string& name) const { 42 | for (const auto& structElem : structs) { 43 | if (structElem->name.compare(name) == 0) { 44 | return structElem.get(); 45 | } 46 | } 47 | 48 | for (const auto& mapElem : unnamedStructs) { 49 | if (mapElem.second->name.compare(name) == 0) { 50 | return mapElem.second.get(); 51 | } 52 | } 53 | 54 | return nullptr; 55 | } 56 | 57 | RefExpr* Program::getGlobalVar(const llvm::Value* val) { 58 | if (const llvm::GlobalVariable* GV = llvm::dyn_cast_or_null(val)) { 59 | if (globalRefs.count(GV)) { 60 | return globalRefs.find(GV)->second.get(); 61 | } 62 | } 63 | 64 | return nullptr; 65 | } 66 | 67 | void Program::createNewUnnamedStruct(const llvm::StructType *strct) { 68 | if (unnamedStructs.find(strct) != unnamedStructs.end()) { 69 | return; 70 | } 71 | 72 | auto structExpr = std::make_unique(getAnonStructName()); 73 | 74 | for (llvm::Type* type : strct->elements()) { 75 | structExpr->addItem(getType(type), getStructVarName()); 76 | } 77 | 78 | unnamedStructs[strct] = std::move(structExpr); 79 | } 80 | 81 | Type* Program::getType(const llvm::Type* type) { 82 | auto result = typeHandler.getType(type); 83 | assert(result); 84 | return result; 85 | } 86 | 87 | Func* Program::getFunction(const llvm::Function* f) { 88 | auto it = functions.find(f); 89 | if (it == functions.end()) { 90 | return nullptr; 91 | } 92 | 93 | return it->second.get(); 94 | } 95 | 96 | RefExpr* Program::getGlobalRef(const llvm::GlobalVariable* gvar) { 97 | return globalRefs[gvar].get(); 98 | } 99 | 100 | void Program::addFunction(const llvm::Function* llvmFunc, std::unique_ptr func) { 101 | functions[llvmFunc] = std::move(func); 102 | } 103 | 104 | void Program::addStruct(std::unique_ptr strct) { 105 | structs.push_back(std::move(strct)); 106 | } 107 | 108 | const std::set& Program::getGlobalVarNames() const { 109 | return globalVarNames; 110 | } 111 | 112 | std::string Program::getStructVarName() { 113 | std::string varName = "structVar"; 114 | varName += std::to_string(structVarCount); 115 | structVarCount++; 116 | 117 | return varName; 118 | } 119 | 120 | bool Program::isFunctionDeclared(const llvm::Function* llvmFunc) const { 121 | return functions.find(llvmFunc) != functions.end(); 122 | } 123 | 124 | Expr* Program::addOwnership(std::unique_ptr expr) { 125 | Expr* result = expr.get(); 126 | ownership.push_back(std::move(expr)); 127 | return result; 128 | } 129 | 130 | Expr* Program::getExpr(const llvm::Value* value) { 131 | auto it = exprMap.find(value); 132 | if (it == exprMap.end()) { 133 | return nullptr; 134 | } 135 | 136 | return it->second; 137 | } 138 | 139 | void Program::addExpr(const llvm::Value* value, Expr* expr) { 140 | exprMap[value] = expr; 141 | } 142 | 143 | bool Program::isPassCompleted(PassType pass) const { 144 | return passes.find(pass) != passes.end(); 145 | } 146 | 147 | void Program::addPass(PassType pass) { 148 | passes.insert(pass); 149 | } 150 | 151 | std::string Program::getUnionName() { 152 | ++unionCounter; 153 | return "u" + std::to_string(unionCounter); 154 | } 155 | 156 | UnionType* Program::addUnion(const std::vector& subtypes) { 157 | auto ut = std::make_unique(getUnionName()); 158 | 159 | size_t index = 0; 160 | for (auto* type : subtypes) { 161 | ut->addItem(type, "ty" + std::to_string(index)); 162 | ++index; 163 | } 164 | 165 | auto* result = ut.get(); 166 | unions.push_back(std::move(ut)); 167 | return result; 168 | } 169 | -------------------------------------------------------------------------------- /core/Program.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | #include "llvm/ADT/DenseMap.h" 10 | 11 | #include "Func.h" 12 | #include "../expr/Expr.h" 13 | #include "../type/TypeHandler.h" 14 | #include "PassType.h" 15 | 16 | class ProgramParser; 17 | 18 | /** 19 | * @brief The Program class represents the whole parsed LLVM program. 20 | */ 21 | class Program { 22 | friend class TypeHandler; 23 | friend class Func; 24 | friend class ProgramParser; 25 | public: 26 | //std::unique_ptr module; 27 | 28 | TypeHandler typeHandler; 29 | 30 | //expressions 31 | llvm::DenseMap> functions; //map containing function definitions 32 | 33 | std::vector> structs; // vector of parsed structs 34 | std::vector> unions; 35 | std::vector> globalVars; // vector of parsed global variables 36 | llvm::DenseMap> globalRefs; //map containing references to global variables 37 | llvm::DenseMap> unnamedStructs; // map containing unnamed structs 38 | 39 | llvm::DenseMap exprMap; // DenseMap used for mapping llvm::Value to Expr 40 | 41 | //set containing names of global variables that are in "var[0-9]+" format, used in creating variable names in functions 42 | std::set globalVarNames; 43 | 44 | // all expressions in the program (just for memory management purposes) 45 | std::vector> ownership; 46 | 47 | // union used for bitcasts from LLVM 48 | UnionType* bitcastUnion = nullptr; 49 | 50 | // set of passes applied to the program 51 | std::unordered_set passes; 52 | 53 | //variables used for creating names for structs and anonymous structs 54 | unsigned structVarCount = 0; 55 | unsigned anonStructCount = 0; 56 | unsigned unionCounter = 0; 57 | 58 | /** 59 | * @brief getAnonStructName Creates new name for anonymous struct. 60 | * @return New name for anonymous struct 61 | */ 62 | std::string getAnonStructName(); 63 | 64 | /** 65 | * @brief getInitValue Return string containing value used for global variable initialization. 66 | * @param val llvm Constant used for initialization 67 | * @return Init value 68 | */ 69 | std::string getInitValue(const llvm::Constant* val); 70 | 71 | /** 72 | * @brief unsetAllInit Resets the init flag for every global variable. 73 | * Used for repeated calling of print and saveFile. 74 | */ 75 | void unsetAllInit(); 76 | 77 | /** 78 | * @brief getIncludeString Returns string containing all includes program uses. 79 | * @return String containing includes; 80 | */ 81 | std::string getIncludeString() const; 82 | 83 | void createNewUnnamedStruct(const llvm::StructType *strct); 84 | 85 | public: 86 | bool stackIgnored = false; //instruction stacksave was ignored 87 | 88 | bool hasVarArg = false; //program uses "stdarg.h" 89 | bool hasStdLib = false; //program uses "stdlib.h" 90 | bool hasString = false; //program uses "string.h" 91 | bool hasStdio = false; //program uses "stdio.h" 92 | bool hasPthread = false; //program uses "pthread.h" 93 | bool hasCMath = false; 94 | 95 | bool includes; //program uses includes instead of declarations for standard library functions, for testing purposes only 96 | bool noFuncCasts; //program removes any function call casts, for testing purposes only 97 | 98 | /** 99 | * @brief Program Constructor of a Program class, parses given file into a llvm::Module. 100 | * @param file Path to a file for parsing. 101 | * @param includes Program uses includes instead of declarations. 102 | * @param casts Program removes function call casts. 103 | */ 104 | //Program(const std::string& file, bool includes, bool casts); 105 | Program(); 106 | 107 | /** 108 | * @brief getStruct Returns pointer to the Struct corresponding to the given LLVM StructType. 109 | * @param strct LLVM StructType 110 | * @return Pointer to Struct expression if the struct is found, nullptr otherwise 111 | */ 112 | StructType* getStruct(const llvm::StructType* strct) const; 113 | 114 | /** 115 | * @brief getStruct Returns pointer to the Struct with the given name. 116 | * @param name Name of the struct 117 | * @return Pointer to Struct expression if the struct is found, nullptr otherwise 118 | */ 119 | StructType* getStruct(const std::string& name) const; 120 | 121 | /** 122 | * @brief getGlobalVar Returns corresponding refference to GlobalValue expression. 123 | * @param val llvm global variable 124 | * @return RefExpr expression or nullptr 125 | */ 126 | RefExpr* getGlobalVar(const llvm::Value* val); 127 | 128 | /** 129 | * @brief getFunction Returns corresponding function to LLVM function. 130 | * @param f llvm function pointer 131 | * @return Func function or nullptr 132 | */ 133 | Func* getFunction(const llvm::Function* f); 134 | 135 | /** 136 | * @brief addDeclaration Adds new declaration of given function. 137 | * @param func LLVM Function 138 | */ 139 | void addDeclaration(const llvm::Function* func, std::unique_ptr decl); 140 | 141 | /** 142 | * @brief getType Transforms llvm::Type into corresponding Type object 143 | * @param type llvm::Type for transformation 144 | * @return unique_ptr to corresponding Type object 145 | */ 146 | Type* getType(const llvm::Type* type); 147 | 148 | RefExpr* getGlobalRef(const llvm::GlobalVariable* gv); 149 | 150 | void addFunction(const llvm::Function* llvmFunc, std::unique_ptr func); 151 | 152 | bool isFunctionDeclared(const llvm::Function* func) const; 153 | 154 | /** 155 | * @brief getVarName Creates a new name for a variable in form of string containing "var" + structVarCount. 156 | * @return String containing a new variable name. 157 | */ 158 | std::string getStructVarName(); 159 | 160 | void addStruct(std::unique_ptr strct); 161 | 162 | const std::set& getGlobalVarNames() const; 163 | 164 | Func* getDeclaration(const llvm::Function* func); 165 | 166 | Expr* addOwnership(std::unique_ptr expr); 167 | 168 | template 169 | Expr* makeExpr(Args&&... args) { 170 | return addOwnership(std::make_unique(std::forward(args)...)); 171 | } 172 | 173 | Expr* getExpr(const llvm::Value* value); 174 | 175 | void addExpr(const llvm::Value* value, Expr* expr); 176 | 177 | bool isPassCompleted(PassType pass) const; 178 | 179 | void addPass(PassType pass); 180 | 181 | std::string getUnionName(); 182 | 183 | UnionType* addUnion(const std::vector& subtypes); 184 | }; 185 | -------------------------------------------------------------------------------- /expr/BinaryExpr.cpp: -------------------------------------------------------------------------------- 1 | #include "BinaryExpr.h" 2 | 3 | #include "llvm/Support/raw_ostream.h" 4 | 5 | #include "../type/TypeHandler.h" 6 | 7 | BoolType CmpExpr::type = BoolType{}; 8 | 9 | /* 10 | * BinaryExpr classes 11 | */ 12 | 13 | BinaryExpr::BinaryExpr(Expr* l, Expr* r, ExprKind kind): ExprBase(kind) { 14 | left = l; 15 | right = r; 16 | 17 | setType(TypeHandler::getBinaryType(left->getType(), right->getType())); 18 | } 19 | 20 | AddExpr::AddExpr(Expr* l, Expr* r, bool isUnsigned) : 21 | BinaryExpr(l, r, EK_AddExpr), isUnsigned(isUnsigned) { } 22 | 23 | void AddExpr::accept(ExprVisitor& visitor) { 24 | visitor.visit(*this); 25 | } 26 | 27 | bool AddExpr::classof(const Expr* expr) { 28 | return expr->getKind() == EK_AddExpr; 29 | } 30 | 31 | SubExpr::SubExpr(Expr* l, Expr* r, bool isUnsigned) : 32 | BinaryExpr(l, r, EK_SubExpr), isUnsigned(isUnsigned) { } 33 | 34 | void SubExpr::accept(ExprVisitor& visitor) { 35 | visitor.visit(*this); 36 | } 37 | 38 | bool SubExpr::classof(const Expr* expr) { 39 | return expr->getKind() == EK_SubExpr; 40 | } 41 | 42 | AssignExpr::AssignExpr(Expr* l, Expr* r) : 43 | BinaryExpr(l, r, EK_AssignExpr) { } 44 | 45 | void AssignExpr::accept(ExprVisitor& visitor) { 46 | visitor.visit(*this); 47 | } 48 | 49 | bool AssignExpr::classof(const Expr* expr) { 50 | return expr->getKind() == EK_AssignExpr; 51 | } 52 | 53 | MulExpr::MulExpr(Expr* l, Expr* r, bool isUnsigned) : 54 | BinaryExpr(l, r, EK_MulExpr), isUnsigned(isUnsigned) { } 55 | 56 | void MulExpr::accept(ExprVisitor& visitor) { 57 | visitor.visit(*this); 58 | } 59 | 60 | bool MulExpr::classof(const Expr* expr) { 61 | return expr->getKind() == EK_MulExpr; 62 | } 63 | 64 | DivExpr::DivExpr(Expr* l, Expr* r, bool isUnsigned) : 65 | BinaryExpr(l, r, EK_DivExpr), isUnsigned(isUnsigned) { } 66 | 67 | void DivExpr::accept(ExprVisitor& visitor) { 68 | visitor.visit(*this); 69 | } 70 | 71 | bool DivExpr::classof(const Expr* expr) { 72 | return expr->getKind() == EK_DivExpr; 73 | } 74 | 75 | RemExpr::RemExpr(Expr* l, Expr* r, bool isUnsigned) : 76 | BinaryExpr(l, r, EK_RemExpr), isUnsigned(isUnsigned) { } 77 | 78 | void RemExpr::accept(ExprVisitor& visitor) { 79 | visitor.visit(*this); 80 | } 81 | 82 | bool RemExpr::classof(const Expr* expr) { 83 | return expr->getKind() == EK_RemExpr; 84 | } 85 | 86 | AndExpr::AndExpr(Expr* l, Expr* r) : 87 | BinaryExpr(l, r, EK_AndExpr) { } 88 | 89 | void AndExpr::accept(ExprVisitor& visitor) { 90 | visitor.visit(*this); 91 | } 92 | 93 | bool AndExpr::classof(const Expr* expr) { 94 | return expr->getKind() == EK_AndExpr; 95 | } 96 | 97 | OrExpr::OrExpr(Expr* l, Expr* r) : 98 | BinaryExpr(l, r, EK_OrExpr) { } 99 | 100 | void OrExpr::accept(ExprVisitor& visitor) { 101 | visitor.visit(*this); 102 | } 103 | 104 | bool OrExpr::classof(const Expr* expr) { 105 | return expr->getKind() == EK_OrExpr; 106 | } 107 | 108 | XorExpr::XorExpr(Expr* l, Expr* r) : 109 | BinaryExpr(l, r, EK_XorExpr) { } 110 | 111 | void XorExpr::accept(ExprVisitor& visitor) { 112 | visitor.visit(*this); 113 | } 114 | 115 | bool XorExpr::classof(const Expr* expr) { 116 | return expr->getKind() == EK_XorExpr; 117 | } 118 | 119 | CmpExpr::CmpExpr(Expr* l, Expr* r, const std::string& cmp, bool isUnsigned) : 120 | BinaryExpr(l,r, EK_CmpExpr) { 121 | comparsion = cmp; 122 | this->isUnsigned = isUnsigned; 123 | setType(&CmpExpr::type); 124 | } 125 | 126 | void CmpExpr::accept(ExprVisitor& visitor) { 127 | visitor.visit(*this); 128 | } 129 | 130 | bool CmpExpr::classof(const Expr* expr) { 131 | return expr->getKind() == EK_CmpExpr; 132 | } 133 | 134 | AshrExpr::AshrExpr(Expr* l, Expr* r) : 135 | BinaryExpr(l, r, EK_AshrExpr) { } 136 | 137 | void AshrExpr::accept(ExprVisitor& visitor) { 138 | visitor.visit(*this); 139 | } 140 | 141 | bool AshrExpr::classof(const Expr* expr) { 142 | return expr->getKind() == EK_AshrExpr; 143 | } 144 | 145 | LshrExpr::LshrExpr(Expr* l, Expr* r) : 146 | BinaryExpr(l, r, EK_LshrExpr) { } 147 | 148 | void LshrExpr::accept(ExprVisitor& visitor) { 149 | visitor.visit(*this); 150 | } 151 | 152 | bool LshrExpr::classof(const Expr* expr) { 153 | return expr->getKind() == EK_LshrExpr; 154 | } 155 | 156 | ShlExpr::ShlExpr(Expr* l, Expr* r, bool isUnsigned) : 157 | BinaryExpr(l, r, EK_ShlExpr), isUnsigned(isUnsigned) { } 158 | 159 | void ShlExpr::accept(ExprVisitor& visitor) { 160 | visitor.visit(*this); 161 | } 162 | 163 | bool ShlExpr::classof(const Expr* expr) { 164 | return expr->getKind() == EK_ShlExpr; 165 | } 166 | 167 | -------------------------------------------------------------------------------- /expr/BinaryExpr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Expr.h" 6 | 7 | /** 8 | * @brief The BinaryExpr class is a base class for all binary expressions. 9 | */ 10 | class BinaryExpr : public ExprBase { 11 | public: 12 | Expr* left; //first operand of binary operation 13 | Expr* right; //second operand of binary operation 14 | 15 | BinaryExpr(Expr*, Expr*, ExprKind); 16 | }; 17 | 18 | /** 19 | * @brief The AddExpr class represents add. 20 | */ 21 | class AddExpr : public BinaryExpr { 22 | public: 23 | bool isUnsigned; 24 | 25 | AddExpr(Expr*, Expr*, bool isUnsigned); 26 | 27 | void accept(ExprVisitor& visitor) override; 28 | 29 | static bool classof(const Expr* expr); 30 | }; 31 | 32 | /** 33 | * @brief The SubExpr class represents substitution. 34 | */ 35 | class SubExpr : public BinaryExpr { 36 | public: 37 | bool isUnsigned; 38 | 39 | SubExpr(Expr*, Expr*, bool isUnsigned); 40 | 41 | void accept(ExprVisitor& visitor) override; 42 | 43 | static bool classof(const Expr* expr); 44 | }; 45 | 46 | /** 47 | * @brief The AssignExpr class represents assingment. 48 | */ 49 | class AssignExpr : public BinaryExpr { 50 | public: 51 | AssignExpr(Expr*, Expr*); 52 | 53 | void accept(ExprVisitor& visitor) override; 54 | 55 | static bool classof(const Expr* expr); 56 | }; 57 | 58 | /** 59 | * @brief The MulExpr class represents multiplication. 60 | */ 61 | class MulExpr : public BinaryExpr { 62 | public: 63 | bool isUnsigned; 64 | 65 | MulExpr(Expr*, Expr*, bool isUnsigned); 66 | 67 | void accept(ExprVisitor& visitor) override; 68 | 69 | static bool classof(const Expr* expr); 70 | }; 71 | 72 | /** 73 | * @brief The DivExpr class represents division. 74 | */ 75 | class DivExpr : public BinaryExpr { 76 | public: 77 | bool isUnsigned; 78 | 79 | DivExpr(Expr*, Expr*, bool isUnsigned); 80 | 81 | void accept(ExprVisitor& visitor) override; 82 | 83 | static bool classof(const Expr* expr); 84 | }; 85 | 86 | /** 87 | * @brief The RemExpr class represents remainder (modulo). 88 | */ 89 | class RemExpr : public BinaryExpr { 90 | public: 91 | bool isUnsigned; 92 | 93 | RemExpr(Expr*, Expr*, bool isUnsigned); 94 | 95 | void accept(ExprVisitor& visitor) override; 96 | 97 | static bool classof(const Expr* expr); 98 | }; 99 | 100 | /** 101 | * @brief The AndExpr class represents bitwise AND. 102 | */ 103 | class AndExpr : public BinaryExpr { 104 | public: 105 | AndExpr(Expr*, Expr*); 106 | 107 | void accept(ExprVisitor& visitor) override; 108 | 109 | static bool classof(const Expr* expr); 110 | }; 111 | 112 | /** 113 | * @brief The OrExpr class represents bitwise OR. 114 | */ 115 | class OrExpr : public BinaryExpr { 116 | public: 117 | OrExpr(Expr*, Expr*); 118 | 119 | void accept(ExprVisitor& visitor) override; 120 | 121 | static bool classof(const Expr* expr); 122 | }; 123 | 124 | /** 125 | * @brief The XorExpr class represents bitwise XOR. 126 | */ 127 | class XorExpr : public BinaryExpr { 128 | public: 129 | XorExpr(Expr*, Expr*); 130 | 131 | void accept(ExprVisitor& visitor) override; 132 | 133 | static bool classof(const Expr* expr); 134 | }; 135 | 136 | /** 137 | * @brief The CmpExpr class represents comparsion. 138 | */ 139 | class CmpExpr : public BinaryExpr { 140 | public: 141 | std::string comparsion; //symbol of comparsion 142 | bool isUnsigned; //indicates that unsigned version of cmp instruction was used 143 | CmpExpr(Expr*, Expr*, const std::string&, bool); 144 | 145 | void accept(ExprVisitor& visitor) override; 146 | 147 | static bool classof(const Expr* expr); 148 | 149 | static BoolType type; 150 | }; 151 | 152 | /** 153 | * @brief The AshrExpr class represents arithmetic shift right. 154 | */ 155 | class AshrExpr : public BinaryExpr { 156 | public: 157 | AshrExpr(Expr*, Expr*); 158 | 159 | void accept(ExprVisitor& visitor) override; 160 | 161 | static bool classof(const Expr* expr); 162 | }; 163 | 164 | /** 165 | * @brief The LshrExpr class represents logical shift right. 166 | */ 167 | class LshrExpr : public BinaryExpr { 168 | public: 169 | LshrExpr(Expr*, Expr*); 170 | 171 | void accept(ExprVisitor& visitor) override; 172 | 173 | static bool classof(const Expr* expr); 174 | }; 175 | 176 | /** 177 | * @brief The ShlExpr class represents shift left. 178 | */ 179 | class ShlExpr : public BinaryExpr { 180 | public: 181 | bool isUnsigned; 182 | 183 | ShlExpr(Expr*, Expr*, bool isUnsigned); 184 | 185 | void accept(ExprVisitor& visitor) override; 186 | 187 | static bool classof(const Expr* expr); 188 | }; 189 | -------------------------------------------------------------------------------- /expr/ExprVisitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | class AggregateElement; 4 | class ArrayElement; 5 | class ExtractValueExpr; 6 | class Value; 7 | class GlobalValue; 8 | class IfExpr; 9 | class SwitchExpr; 10 | class AsmExpr; 11 | class CallExpr; 12 | class PointerShift; 13 | class GepExpr; 14 | class SelectExpr; 15 | class RefExpr; 16 | class DerefExpr; 17 | class RetExpr; 18 | class CastExpr; 19 | class AddExpr; 20 | class SubExpr; 21 | class AssignExpr; 22 | class MulExpr; 23 | class DivExpr; 24 | class RemExpr; 25 | class AndExpr; 26 | class OrExpr; 27 | class XorExpr; 28 | class CmpExpr; 29 | class AshrExpr; 30 | class LshrExpr; 31 | class ShlExpr; 32 | class StackAlloc; 33 | class AggregateInitializer; 34 | class ArrowExpr; 35 | class LogicalAnd; 36 | class LogicalOr; 37 | class LogicalNot; 38 | class GotoExpr; 39 | class ExprList; 40 | class MinusExpr; 41 | class DoWhile; 42 | 43 | class ExprVisitor { 44 | public: 45 | virtual void visit(AggregateElement& ) {} 46 | virtual void visit(ArrayElement& ) {} 47 | virtual void visit(ExtractValueExpr& ) {} 48 | virtual void visit(Value& ) {} 49 | virtual void visit(GlobalValue& ) {} 50 | virtual void visit(IfExpr& ) {} 51 | virtual void visit(SwitchExpr& ) {} 52 | virtual void visit(AsmExpr& ) {} 53 | virtual void visit(CallExpr& ) {} 54 | virtual void visit(PointerShift& ) {} 55 | virtual void visit(GepExpr& ) {} 56 | virtual void visit(SelectExpr& ) {} 57 | virtual void visit(RefExpr& ) {} 58 | virtual void visit(DerefExpr& ) {} 59 | virtual void visit(RetExpr& ) {} 60 | virtual void visit(CastExpr& ) {} 61 | virtual void visit(AddExpr& ) {} 62 | virtual void visit(SubExpr& ) {} 63 | virtual void visit(AssignExpr& ) {} 64 | virtual void visit(MulExpr& ) {} 65 | virtual void visit(DivExpr& ) {} 66 | virtual void visit(RemExpr& ) {} 67 | virtual void visit(AndExpr& ) {} 68 | virtual void visit(OrExpr& ) {} 69 | virtual void visit(XorExpr& ) {} 70 | virtual void visit(CmpExpr& ) {} 71 | virtual void visit(AshrExpr& ) {} 72 | virtual void visit(LshrExpr& ) {} 73 | virtual void visit(ShlExpr& ) {} 74 | virtual void visit(StackAlloc& ) {} 75 | virtual void visit(AggregateInitializer& ) {} 76 | virtual void visit(ArrowExpr& ) {} 77 | virtual void visit(LogicalAnd& ) {} 78 | virtual void visit(LogicalOr& ) {} 79 | virtual void visit(GotoExpr& ) {} 80 | virtual void visit(ExprList& ) {} 81 | virtual void visit(MinusExpr& ) {} 82 | virtual void visit(LogicalNot& ) {} 83 | virtual void visit(DoWhile& ) {} 84 | 85 | virtual ~ExprVisitor() = default; 86 | }; 87 | -------------------------------------------------------------------------------- /expr/UnaryExpr.cpp: -------------------------------------------------------------------------------- 1 | #include "UnaryExpr.h" 2 | 3 | #include "llvm/Support/raw_ostream.h" 4 | #include "../type/TypeHandler.h" 5 | 6 | /* 7 | * UnaryExpr classes 8 | */ 9 | 10 | UnaryExpr::UnaryExpr(Expr *expr, ExprKind kind): ExprBase(kind) { 11 | this->expr = expr; 12 | if (expr) { 13 | setType(expr->getType()); 14 | } 15 | } 16 | 17 | RefExpr::RefExpr(Expr* expr, Type* type) : 18 | UnaryExpr(expr, EK_RefExpr) { 19 | setType(type); 20 | } 21 | 22 | void RefExpr::accept(ExprVisitor& visitor) { 23 | visitor.visit(*this); 24 | } 25 | 26 | bool RefExpr::classof(const Expr* expr) { 27 | return expr->getKind() == EK_RefExpr; 28 | } 29 | 30 | DerefExpr::DerefExpr(Expr* expr) : 31 | UnaryExpr(expr, EK_DerefExpr) { 32 | if (auto PT = llvm::dyn_cast_or_null(expr->getType())) { 33 | setType(PT->type); 34 | } 35 | } 36 | 37 | void DerefExpr::accept(ExprVisitor& visitor) { 38 | visitor.visit(*this); 39 | } 40 | 41 | bool DerefExpr::classof(const Expr* expr) { 42 | return expr->getKind() == EK_DerefExpr; 43 | } 44 | 45 | RetExpr::RetExpr(Expr* ret) 46 | : UnaryExpr(ret, EK_RetExpr) { } 47 | 48 | RetExpr::RetExpr() 49 | : UnaryExpr(nullptr, EK_RetExpr) { } 50 | 51 | void RetExpr::accept(ExprVisitor& visitor) { 52 | visitor.visit(*this); 53 | } 54 | 55 | bool RetExpr::classof(const Expr* expr) { 56 | return expr->getKind() == EK_RetExpr; 57 | } 58 | 59 | CastExpr::CastExpr(Expr* expr, Type* type) 60 | : UnaryExpr(expr, EK_CastExpr) { 61 | setType(type); 62 | } 63 | 64 | void CastExpr::accept(ExprVisitor& visitor) { 65 | visitor.visit(*this); 66 | } 67 | 68 | bool CastExpr::classof(const Expr* expr) { 69 | return expr->getKind() == EK_CastExpr; 70 | } 71 | 72 | MinusExpr::MinusExpr(Expr* expr) : UnaryExpr(expr, EK_MinusExpr) { 73 | setType(expr->getType()); 74 | } 75 | 76 | void MinusExpr::accept(ExprVisitor& visitor) { 77 | visitor.visit(*this); 78 | } 79 | 80 | bool MinusExpr::classof(const Expr* expr) { 81 | return expr->getKind() == EK_MinusExpr; 82 | } 83 | 84 | LogicalNot::LogicalNot(Expr* expr) : UnaryExpr(expr, EK_LogicalNot) { 85 | setType(expr->getType()); 86 | } 87 | 88 | void LogicalNot::accept(ExprVisitor& visitor) { 89 | visitor.visit(*this); 90 | } 91 | 92 | bool LogicalNot::classof(const Expr* expr) { 93 | return expr->getKind() == EK_LogicalNot; 94 | } 95 | -------------------------------------------------------------------------------- /expr/UnaryExpr.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "Expr.h" 6 | 7 | /** 8 | * @brief The UnaryExpr class is a base class for all unary expressions. 9 | */ 10 | class UnaryExpr : public ExprBase { 11 | public: 12 | UnaryExpr(Expr *, ExprKind); 13 | 14 | Expr* expr; //operand of unary operation 15 | }; 16 | 17 | /** 18 | * @brief The RefExpr class represent reference. 19 | */ 20 | class RefExpr : public UnaryExpr { 21 | public: 22 | RefExpr(Expr*, Type*); 23 | 24 | void accept(ExprVisitor& visitor) override; 25 | 26 | static bool classof(const Expr* expr); 27 | }; 28 | 29 | /** 30 | * @brief The DerefExpr class represents dereference. 31 | */ 32 | class DerefExpr : public UnaryExpr { 33 | public: 34 | DerefExpr(Expr*); 35 | 36 | void accept(ExprVisitor& visitor) override; 37 | 38 | static bool classof(const Expr* expr); 39 | }; 40 | 41 | /** 42 | * @brief The RetExpr class represents return. 43 | */ 44 | class RetExpr : public UnaryExpr { 45 | public: 46 | RetExpr(Expr*); 47 | RetExpr(); 48 | 49 | void accept(ExprVisitor& visitor) override; 50 | 51 | static bool classof(const Expr* expr); 52 | }; 53 | 54 | /** 55 | * @brief The CastExpr class represents cast. 56 | */ 57 | class CastExpr : public UnaryExpr { 58 | public: 59 | CastExpr(Expr*, Type*); 60 | 61 | void accept(ExprVisitor& visitor) override; 62 | 63 | static bool classof(const Expr* expr); 64 | }; 65 | 66 | class MinusExpr : public UnaryExpr { 67 | public: 68 | MinusExpr(Expr*); 69 | 70 | void accept(ExprVisitor& visitor) override; 71 | 72 | static bool classof(const Expr* expr); 73 | }; 74 | 75 | class LogicalNot : public UnaryExpr { 76 | public: 77 | LogicalNot(Expr*); 78 | 79 | void accept(ExprVisitor& visitor) override; 80 | 81 | static bool classof(const Expr* expr); 82 | }; 83 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "core/Program.h" 2 | #include "parser/ProgramParser.h" 3 | #include "writer/Writer.h" 4 | 5 | #include "llvm/Support/raw_ostream.h" 6 | #include "llvm/Support/CommandLine.h" 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace llvm; 13 | 14 | int main(int argc, char** argv) { 15 | cl::OptionCategory options("llvm2c options"); 16 | cl::opt Output("o", cl::desc("Output filename"), cl::value_desc("filename"), cl::cat(options)); 17 | cl::opt Input(cl::Positional, cl::Required, cl::desc(""), cl::cat(options)); 18 | cl::opt Print("p", cl::desc("Print translated program"), cl::cat(options)); 19 | cl::opt Includes("add-includes", cl::desc("Uses includes instead of declarations. For experimental purposes."), cl::cat(options)); 20 | cl::opt Casts("no-function-call-casts", cl::desc("Removes casts around function calls. For experimental purposes."), cl::cat(options)); 21 | cl::opt BitcastUnions("bitcasts-with-unions", cl::desc("Use unions to translate bitcasts"), cl::cat(options), cl::init(false)); 22 | cl::opt BlockLabels("force-block-labels", cl::desc("Forces printing of block labels of inlined blocks"), cl::cat(options)); 23 | 24 | cl::HideUnrelatedOptions(options); 25 | cl::ParseCommandLineOptions(argc, argv); 26 | 27 | if (Output.empty() && !Print) { 28 | std::cout << "Output method not specified!\n"; 29 | return 1; 30 | } 31 | 32 | try { 33 | ProgramParser parser; 34 | auto program = parser.parse(Input, BitcastUnions); 35 | 36 | if (Print) { 37 | Writer wr{ std::cout, Includes, Casts, BlockLabels }; 38 | wr.writeProgram(program); 39 | } 40 | 41 | if (!Output.empty()) { 42 | std::ofstream file; 43 | file.open(Output); 44 | if (!file.is_open()) { 45 | throw std::invalid_argument("Output file cannot be opened!"); 46 | } 47 | Writer wr{ file, Includes, Casts, BlockLabels }; 48 | wr.writeProgram(program); 49 | } 50 | 51 | } catch (std::invalid_argument& e) { 52 | std::cerr << e.what(); 53 | return 1; 54 | } 55 | 56 | return 0; 57 | } 58 | -------------------------------------------------------------------------------- /parser/ProgramParser.cpp: -------------------------------------------------------------------------------- 1 | #include "ProgramParser.h" 2 | #include "passes.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #define RUN_PASS(pass) \ 9 | do {\ 10 | pass(mod, result); \ 11 | } while (0); 12 | 13 | 14 | Program ProgramParser::parse(const std::string& file, bool bitcastUnions) { 15 | Program result; 16 | llvm::LLVMContext context; 17 | 18 | auto error = llvm::SMDiagnostic(); 19 | auto module = llvm::parseIRFile(file, error, context); 20 | if (!module) { 21 | throw std::invalid_argument("Error loading module - invalid input file:\n" + file + "\n"); 22 | } 23 | 24 | const auto* mod = module.get(); 25 | 26 | RUN_PASS(determineIncludes); 27 | RUN_PASS(parseStructDeclarations); 28 | RUN_PASS(parseStructItems); 29 | RUN_PASS(findDeclaredFunctions); 30 | RUN_PASS(computeGlobalVarsOrder); 31 | RUN_PASS(createFunctions); 32 | RUN_PASS(findMetadataFunctionNames); 33 | RUN_PASS(nameFunctions); 34 | 35 | RUN_PASS(createConstants); 36 | RUN_PASS(initializeGlobalVars); 37 | 38 | RUN_PASS(createFunctionParameters); 39 | RUN_PASS(createBlocks); 40 | RUN_PASS(createAllocas); 41 | RUN_PASS(findMetadataVariableNames); 42 | 43 | // This pass is buggy. It can do signed type from 44 | // unsigned type when the original type is unsigned... 45 | // Do not use it until we fix that. 46 | //RUN_PASS(parseMetadataTypes); 47 | 48 | if (bitcastUnions) { 49 | RUN_PASS(prepareBitcastUnion); 50 | } 51 | //RUN_PASS(createExpressions); 52 | createExpressions(mod, result, bitcastUnions); 53 | 54 | RUN_PASS(parseBreaks); 55 | 56 | RUN_PASS(refDeref); 57 | RUN_PASS(memcpyToAssignment); 58 | RUN_PASS(arrowify); 59 | RUN_PASS(deleteUnusedVariables); 60 | RUN_PASS(fixMainParameters); 61 | RUN_PASS(addSignCasts); 62 | // This pass is not working well. It does not take 63 | // into account the signdness of types and can 64 | // remove casts that are needed, e.g.: 65 | // It can do (int)var from (int)(short)var 66 | // where var is (unsigned short). 67 | //RUN_PASS(deleteRedundantCasts); 68 | RUN_PASS(extractVars); 69 | RUN_PASS(identifyInlinableBlocks); 70 | RUN_PASS(inlineBlocks); 71 | 72 | return result; 73 | } 74 | -------------------------------------------------------------------------------- /parser/ProgramParser.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../core/Program.h" 4 | 5 | 6 | class ProgramParser 7 | { 8 | private: 9 | 10 | public: 11 | ProgramParser() = default; 12 | Program parse(const std::string& from, bool bitcastUnions); 13 | virtual ~ProgramParser() = default; 14 | }; 15 | -------------------------------------------------------------------------------- /parser/README.md: -------------------------------------------------------------------------------- 1 | Adding a new pass checklist: 2 | 3 | - [ ] create a new `.cpp` file here in `parser/` folder 4 | - [ ] name the file in `lowerCamelCase` 5 | - [ ] create a non-static function with the same name as the file (without `.cpp`) 6 | - [ ] add the function declaration to `passes.h` 7 | - [ ] add a new item into `../core/PassType.h` and clarify dependencies of your pass on other passes 8 | - [ ] call the pass from `ProgramParser.cpp` 9 | -------------------------------------------------------------------------------- /parser/SimplifyingExprVisitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../expr/Expr.h" 4 | #include "../expr/UnaryExpr.h" 5 | #include "../expr/BinaryExpr.h" 6 | #include "../expr/ExprVisitor.h" 7 | 8 | class SimplifyingExprVisitor : public ExprVisitor 9 | { 10 | 11 | protected: 12 | virtual Expr* simplify(Expr* expr) = 0; 13 | public: 14 | void visit(AggregateElement& expr) override; 15 | void visit(ArrayElement& expr) override; 16 | void visit(ExtractValueExpr& expr) override; 17 | void visit(IfExpr& expr) override; 18 | void visit(SwitchExpr& expr) override; 19 | void visit(AsmExpr& expr) override; 20 | void visit(CallExpr& expr) override; 21 | void visit(PointerShift& expr) override; 22 | void visit(GepExpr& expr) override; 23 | void visit(SelectExpr& expr) override; 24 | void visit(RefExpr& expr) override; 25 | void visit(DerefExpr& expr) override; 26 | void visit(RetExpr& expr) override; 27 | void visit(CastExpr& expr) override; 28 | void visit(AddExpr& expr) override; 29 | void visit(SubExpr& expr) override; 30 | void visit(AssignExpr& expr) override; 31 | void visit(MulExpr& expr) override; 32 | void visit(DivExpr& expr) override; 33 | void visit(RemExpr& expr) override; 34 | void visit(AndExpr& expr) override; 35 | void visit(OrExpr& expr) override; 36 | void visit(XorExpr& expr) override; 37 | void visit(CmpExpr& expr) override; 38 | void visit(AshrExpr& expr) override; 39 | void visit(LshrExpr& expr) override; 40 | void visit(ShlExpr& expr) override; 41 | void visit(AggregateInitializer& expr) override; 42 | void visit(ArrowExpr& expr) override; 43 | void visit(LogicalAnd& expr) override; 44 | void visit(LogicalOr& expr) override; 45 | void visit(ExprList& expr) override; 46 | void visit(MinusExpr& expr) override; 47 | void visit(LogicalNot& expr) override; 48 | void visit(DoWhile& expr) override; 49 | 50 | virtual ~SimplifyingExprVisitor() = default; 51 | }; 52 | -------------------------------------------------------------------------------- /parser/addSignCasts.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../core/Program.h" 5 | #include "../core/Func.h" 6 | #include "../core/Block.h" 7 | 8 | #include "../expr/ExprVisitor.h" 9 | 10 | class SignCastsVisitor : public ExprVisitor { 11 | Block* block; 12 | Program& program; 13 | 14 | Expr* castIfNeeded(Expr* expr, bool isUnsigned); 15 | IntegerType* toggleSignedness(IntegerType* ty); 16 | 17 | public: 18 | SignCastsVisitor(Program& program, Block* block) : block(block), program(program) {} 19 | 20 | void visit(AggregateElement& expr) override; 21 | void visit(ArrayElement& expr) override; 22 | void visit(ExtractValueExpr& expr) override; 23 | void visit(IfExpr& expr) override; 24 | void visit(SwitchExpr& expr) override; 25 | void visit(AsmExpr& expr) override; 26 | void visit(CallExpr& expr) override; 27 | void visit(PointerShift& expr) override; 28 | void visit(GepExpr& expr) override; 29 | void visit(SelectExpr& expr) override; 30 | void visit(RefExpr& expr) override; 31 | void visit(DerefExpr& expr) override; 32 | void visit(RetExpr& expr) override; 33 | void visit(CastExpr& expr) override; 34 | void visit(AddExpr& expr) override; 35 | void visit(SubExpr& expr) override; 36 | void visit(AssignExpr& expr) override; 37 | void visit(MulExpr& expr) override; 38 | void visit(DivExpr& expr) override; 39 | void visit(RemExpr& expr) override; 40 | void visit(AndExpr& expr) override; 41 | void visit(OrExpr& expr) override; 42 | void visit(XorExpr& expr) override; 43 | void visit(CmpExpr& expr) override; 44 | void visit(ShlExpr& expr) override; 45 | }; 46 | 47 | 48 | void addSignCasts(const llvm::Module* module, Program& program) { 49 | assert(program.isPassCompleted(PassType::CreateExpressions)); 50 | for (const llvm::Function& func : module->functions()) { 51 | auto* function = program.getFunction(&func); 52 | for (const auto& block : func) { 53 | auto* myBlock = function->getBlock(&block); 54 | SignCastsVisitor scv(program, myBlock); 55 | 56 | for (auto it = myBlock->expressions.begin(); it != myBlock->expressions.end(); ++it) { 57 | auto expr = *it; 58 | expr->accept(scv); 59 | 60 | } 61 | } 62 | } 63 | 64 | program.addPass(PassType::AddSignCasts); 65 | } 66 | 67 | void SignCastsVisitor::visit(IfExpr& expr) { 68 | if (expr.cmp) { 69 | expr.cmp->accept(*this); 70 | } 71 | } 72 | 73 | Expr* SignCastsVisitor::castIfNeeded(Expr* expr, bool isUnsigned) { 74 | Expr* result = expr; 75 | auto IT = llvm::dyn_cast_or_null(expr->getType()); 76 | 77 | if (IT && IT->unsignedType != isUnsigned) { 78 | Type* newType = toggleSignedness(IT); 79 | 80 | auto cast = std::make_unique(expr, newType); 81 | result = cast.get(); 82 | block->addOwnership(std::move(cast)); 83 | } 84 | 85 | return result; 86 | } 87 | 88 | void SignCastsVisitor::visit(CmpExpr& expr) { 89 | // cast are not necessary in these cases 90 | if (expr.comparsion == "==" || expr.comparsion == "!=") 91 | return; 92 | 93 | expr.left = castIfNeeded(expr.left, expr.isUnsigned); 94 | expr.right = castIfNeeded(expr.right, expr.isUnsigned); 95 | } 96 | 97 | void SignCastsVisitor::visit(AggregateElement& expr) { 98 | expr.expr->accept(*this); 99 | } 100 | 101 | void SignCastsVisitor::visit(ArrayElement& ae) { 102 | ae.expr->accept(*this); 103 | ae.element->accept(*this); 104 | } 105 | 106 | void SignCastsVisitor::visit(ExtractValueExpr& expr) { 107 | for (auto& index : expr.indices) { 108 | index->accept(*this); 109 | } 110 | } 111 | 112 | void SignCastsVisitor::visit(SwitchExpr& expr) { 113 | expr.cmp->accept(*this); 114 | } 115 | 116 | void SignCastsVisitor::visit(AsmExpr& /*expr*/) { 117 | } 118 | 119 | void SignCastsVisitor::visit(CallExpr& expr) { 120 | if (expr.funcValue) { 121 | expr.funcValue->accept(*this); 122 | } 123 | 124 | for (auto it = expr.params.begin(); it != expr.params.end(); ++it) { 125 | (*it)->accept(*this); 126 | } 127 | } 128 | 129 | void SignCastsVisitor::visit(PointerShift& expr) { 130 | expr.pointer->accept(*this); 131 | expr.move->accept(*this); 132 | } 133 | 134 | void SignCastsVisitor::visit(GepExpr& expr) { 135 | for (auto& index : expr.indices) { 136 | index->accept(*this); 137 | } 138 | } 139 | 140 | void SignCastsVisitor::visit(SelectExpr& expr) { 141 | expr.left->accept(*this); 142 | expr.right->accept(*this); 143 | expr.comp->accept(*this); 144 | } 145 | 146 | void SignCastsVisitor::visit(RefExpr& expr) { 147 | expr.expr->accept(*this); 148 | } 149 | 150 | void SignCastsVisitor::visit(DerefExpr& expr) { 151 | expr.expr->accept(*this); 152 | } 153 | 154 | void SignCastsVisitor::visit(RetExpr& expr) { 155 | if (expr.expr) { 156 | expr.expr->accept(*this); 157 | } 158 | } 159 | 160 | void SignCastsVisitor::visit(CastExpr& expr) { 161 | expr.expr->accept(*this); 162 | } 163 | 164 | void SignCastsVisitor::visit(AddExpr& expr) { 165 | expr.left->accept(*this); 166 | expr.right->accept(*this); 167 | 168 | expr.left = castIfNeeded(expr.left, expr.isUnsigned); 169 | expr.right = castIfNeeded(expr.right, expr.isUnsigned); 170 | } 171 | 172 | void SignCastsVisitor::visit(SubExpr& expr) { 173 | expr.left->accept(*this); 174 | expr.right->accept(*this); 175 | 176 | expr.left = castIfNeeded(expr.left, expr.isUnsigned); 177 | expr.right = castIfNeeded(expr.right, expr.isUnsigned); 178 | } 179 | 180 | void SignCastsVisitor::visit(AssignExpr& expr) { 181 | expr.left->accept(*this); 182 | expr.right->accept(*this); 183 | } 184 | 185 | void SignCastsVisitor::visit(MulExpr& expr) { 186 | expr.left->accept(*this); 187 | expr.right->accept(*this); 188 | 189 | expr.left = castIfNeeded(expr.left, expr.isUnsigned); 190 | expr.right = castIfNeeded(expr.right, expr.isUnsigned); 191 | } 192 | 193 | void SignCastsVisitor::visit(DivExpr& expr) { 194 | expr.left->accept(*this); 195 | expr.right->accept(*this); 196 | 197 | expr.left = castIfNeeded(expr.left, expr.isUnsigned); 198 | expr.right = castIfNeeded(expr.right, expr.isUnsigned); 199 | } 200 | 201 | void SignCastsVisitor::visit(RemExpr& expr) { 202 | expr.left->accept(*this); 203 | expr.right->accept(*this); 204 | 205 | expr.left = castIfNeeded(expr.left, expr.isUnsigned); 206 | expr.right = castIfNeeded(expr.right, expr.isUnsigned); 207 | } 208 | 209 | void SignCastsVisitor::visit(AndExpr& expr) { 210 | expr.left->accept(*this); 211 | expr.right->accept(*this); 212 | } 213 | 214 | void SignCastsVisitor::visit(OrExpr& expr) { 215 | expr.left->accept(*this); 216 | expr.right->accept(*this); 217 | } 218 | 219 | void SignCastsVisitor::visit(XorExpr& expr) { 220 | expr.left->accept(*this); 221 | expr.right->accept(*this); 222 | } 223 | 224 | void SignCastsVisitor::visit(ShlExpr& expr) { 225 | expr.left->accept(*this); 226 | expr.right->accept(*this); 227 | 228 | expr.left = castIfNeeded(expr.left, expr.isUnsigned); 229 | expr.right = castIfNeeded(expr.right, expr.isUnsigned); 230 | } 231 | 232 | IntegerType* SignCastsVisitor::toggleSignedness(IntegerType* ty) { 233 | return program.typeHandler.toggleSignedness(ty); 234 | } 235 | -------------------------------------------------------------------------------- /parser/arrowify.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/Program.h" 4 | #include "../core/Func.h" 5 | #include "../core/Block.h" 6 | 7 | #include "SimplifyingExprVisitor.h" 8 | 9 | class ArrowifyVisitor : public SimplifyingExprVisitor { 10 | private: 11 | Program& program; 12 | protected: 13 | Expr* simplify(Expr* expr) override; 14 | public: 15 | ArrowifyVisitor(Program& program): program(program) {} 16 | }; 17 | 18 | void arrowify(const llvm::Module* module, Program& program) { 19 | assert(program.isPassCompleted(PassType::CreateExpressions)); 20 | 21 | ArrowifyVisitor visitor{program}; 22 | for (const llvm::Function& func : module->functions()) { 23 | auto* function = program.getFunction(&func); 24 | for (const auto& block : func) { 25 | auto* myBlock = function->getBlock(&block); 26 | 27 | for (auto it = myBlock->expressions.begin(); it != myBlock->expressions.end(); ++it) { 28 | auto expr = *it; 29 | expr->accept(visitor); 30 | 31 | } 32 | 33 | } 34 | } 35 | 36 | program.addPass(PassType::Arrowify); 37 | } 38 | 39 | Expr* ArrowifyVisitor::simplify(Expr* expr) { 40 | 41 | if (auto* SE = llvm::dyn_cast_or_null(expr)) { 42 | if (auto* DE = llvm::dyn_cast_or_null(SE->expr)) { 43 | return program.makeExpr(DE->expr, SE->element); 44 | } 45 | } 46 | 47 | return expr; 48 | } 49 | -------------------------------------------------------------------------------- /parser/cfunc.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | bool isCFunc(const std::string& func); 6 | 7 | std::string trimPrefix(const std::string& fname); 8 | 9 | bool isCMath(const std::string& func); 10 | 11 | /** 12 | * @brief isStdLibFunc Checks whether the function is part of stdlib.h 13 | * @param func Function name 14 | * @return True if function is part of stdlib.h, false otherwise 15 | */ 16 | bool isStdLibFunc(const std::string& func); 17 | 18 | /** 19 | * @brief isStringFunc Checks whether the function is part of string.h 20 | * @param func Function name 21 | * @return True if function is part of string.h, false otherwise 22 | */ 23 | bool isStringFunc(const std::string& func); 24 | 25 | /** 26 | * @brief isStdioFunc Checks whether the function is part of stdio.h 27 | * @param func Function name 28 | * @return True if function is part of stdio.h, false otherwise 29 | */ 30 | bool isStdioFunc(const std::string& func); 31 | 32 | /** 33 | * @brief isPthreadFunc Checks whether the function is part of pthread.h 34 | * @param func Function name 35 | * @return True if function is part of pthread.h, false otherwise 36 | */ 37 | bool isPthreadFunc(const std::string& func); 38 | 39 | -------------------------------------------------------------------------------- /parser/compare.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | bool isIntegerCompareUnsigned(const llvm::CmpInst* cmp) { 4 | switch (cmp->getPredicate()) { 5 | case llvm::CmpInst::ICMP_EQ: 6 | case llvm::CmpInst::FCMP_OEQ: 7 | case llvm::CmpInst::FCMP_UEQ: 8 | return true; 9 | case llvm::CmpInst::ICMP_NE: 10 | case llvm::CmpInst::FCMP_ONE: 11 | case llvm::CmpInst::FCMP_UNE: 12 | return true; 13 | 14 | case llvm::CmpInst::ICMP_UGT: 15 | case llvm::CmpInst::ICMP_UGE: 16 | case llvm::CmpInst::ICMP_ULT: 17 | case llvm::CmpInst::ICMP_ULE: 18 | return true; 19 | 20 | case llvm::CmpInst::ICMP_SGT: 21 | case llvm::CmpInst::ICMP_SGE: 22 | case llvm::CmpInst::ICMP_SLT: 23 | case llvm::CmpInst::ICMP_SLE: 24 | return false; 25 | 26 | default: 27 | throw std::invalid_argument("unable to determine signedness of icmp predicate"); 28 | } 29 | } 30 | 31 | std::string getComparePredicate(const llvm::CmpInst* cmp) { 32 | switch(cmp->getPredicate()) { 33 | case llvm::CmpInst::ICMP_EQ: 34 | case llvm::CmpInst::FCMP_OEQ: 35 | case llvm::CmpInst::FCMP_UEQ: 36 | return "=="; 37 | case llvm::CmpInst::ICMP_NE: 38 | case llvm::CmpInst::FCMP_ONE: 39 | case llvm::CmpInst::FCMP_UNE: 40 | return "!="; 41 | case llvm::CmpInst::ICMP_UGT: 42 | case llvm::CmpInst::ICMP_SGT: 43 | case llvm::CmpInst::FCMP_UGT: 44 | case llvm::CmpInst::FCMP_OGT: 45 | return ">"; 46 | case llvm::CmpInst::ICMP_UGE: 47 | case llvm::CmpInst::ICMP_SGE: 48 | case llvm::CmpInst::FCMP_OGE: 49 | case llvm::CmpInst::FCMP_UGE: 50 | return ">="; 51 | case llvm::CmpInst::ICMP_ULT: 52 | case llvm::CmpInst::ICMP_SLT: 53 | case llvm::CmpInst::FCMP_OLT: 54 | case llvm::CmpInst::FCMP_ULT: 55 | return "<"; 56 | case llvm::CmpInst::ICMP_ULE: 57 | case llvm::CmpInst::ICMP_SLE: 58 | case llvm::CmpInst::FCMP_OLE: 59 | case llvm::CmpInst::FCMP_ULE: 60 | return "<="; 61 | default: 62 | throw std::invalid_argument("FCMP ORD/UNO and BAD PREDICATE not supported!"); 63 | 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /parser/computeGlobalVarsOrder.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../core/Program.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | static void computeTopo(const llvm::Constant* con, std::vector& order, std::unordered_set& visited) { 9 | if (auto gvar = llvm::dyn_cast_or_null(con)) { 10 | if (!visited.insert(gvar).second) { 11 | return; 12 | } 13 | } 14 | 15 | for (const auto& operand : con->operands()) { 16 | if (auto constOp = llvm::dyn_cast_or_null(operand.get())) { 17 | computeTopo(constOp, order, visited); 18 | } 19 | } 20 | 21 | if (auto gvar = llvm::dyn_cast_or_null(con)) { 22 | order.push_back(gvar); 23 | } 24 | } 25 | 26 | static void parseGlobalVar(const llvm::GlobalVariable& gvar, Program& program) { 27 | std::string gvarName = gvar.getName().str(); 28 | std::replace(gvarName.begin(), gvarName.end(), '.', '_'); 29 | 30 | std::regex varName("var[0-9]+"); 31 | if (std::regex_match(gvarName, varName)) { 32 | program.globalVarNames.insert(gvarName); 33 | } 34 | 35 | auto type = program.getType(gvar.getValueType()); 36 | if (!type) 37 | assert(false && "Unable to determine global variable type"); 38 | 39 | auto var = std::make_unique(gvarName, nullptr, type); 40 | var->isStatic = gvar.hasInternalLinkage(); 41 | 42 | program.globalRefs[&gvar] = std::make_unique(var.get(), program.typeHandler.pointerTo(var->getType())); 43 | 44 | program.addExpr(&gvar, program.globalRefs[&gvar].get()); 45 | program.globalVars.push_back(std::move(var)); 46 | } 47 | 48 | void computeGlobalVarsOrder(const llvm::Module* module, Program& program) { 49 | 50 | std::unordered_set visited; 51 | std::vector order; 52 | 53 | assert(program.isPassCompleted(PassType::ParseStructItems)); 54 | 55 | for (const llvm::GlobalVariable& gvar : module->globals()) { 56 | if (llvm::isa(&gvar)) { 57 | continue; 58 | } 59 | 60 | // do not initialize twice 61 | if (visited.find(&gvar) != visited.end()) { 62 | continue; 63 | } 64 | 65 | computeTopo(&gvar, order, visited); 66 | } 67 | 68 | for (const auto* gvar : order) { 69 | parseGlobalVar(*gvar, program); 70 | } 71 | 72 | program.addPass(PassType::ComputeGlobalVarsOrder); 73 | } 74 | -------------------------------------------------------------------------------- /parser/constval.cpp: -------------------------------------------------------------------------------- 1 | #include "constval.h" 2 | #include "toinst.h" 3 | 4 | Expr* parseLLVMInstruction(const llvm::Instruction& ins, Program& program); 5 | 6 | Expr* createUndefValue(const llvm::Type* ty, Program& program) { 7 | if (ty->isPointerTy()) { 8 | return program.makeExpr("0", program.getType(ty)); 9 | } 10 | 11 | if (ty->isIntegerTy()) { 12 | auto zero = std::make_unique("0", program.getType(ty)); 13 | return program.addOwnership(std::move(zero)); 14 | } 15 | 16 | std::vector values; 17 | 18 | if (auto* ST = llvm::dyn_cast_or_null(ty)) { 19 | for (unsigned i = 0; i < ST->getNumElements(); ++i) { 20 | values.push_back(createUndefValue(ST->getElementType(), program)); 21 | } 22 | 23 | } else if (auto* ST = llvm::dyn_cast_or_null(ty)) { 24 | for (unsigned i = 0; i < ST->getNumElements(); ++i) { 25 | values.push_back(createUndefValue(ST->getElementType(i), program)); 26 | } 27 | } else { 28 | ty->print(llvm::errs(), true); 29 | assert(false && "globalVars: unrecognized type of undef value"); 30 | } 31 | 32 | auto init = std::make_unique(values); 33 | init->setType(program.getType(ty)); 34 | return program.addOwnership(std::move(init)); 35 | } 36 | 37 | Expr* createConstantValue(const llvm::Value* val, Program& program) { 38 | if (llvm::isa(val)) { 39 | return createUndefValue(val->getType(), program); 40 | } 41 | 42 | if (llvm::isa(val)) 43 | return program.makeExpr("0", program.getType(val->getType())); 44 | 45 | if (const llvm::GlobalVariable* GV = llvm::dyn_cast_or_null(val)) { 46 | auto RE = program.getGlobalRef(GV); 47 | assert(RE && "initialize-global-vars: global value does not have a ref"); 48 | 49 | return RE; 50 | } 51 | 52 | 53 | if (llvm::isa(val)) { 54 | auto ref = std::make_unique(val->getName().str(), program.typeHandler.pointerTo(program.typeHandler.schar.get())); 55 | return program.addOwnership(std::move(ref)); 56 | } 57 | 58 | if (auto CI = llvm::dyn_cast_or_null(val)) { 59 | std::string value; 60 | if (CI->getBitWidth() > 64) { 61 | const llvm::APInt& API = CI->getValue(); 62 | value = std::to_string(API.getLimitedValue()); 63 | } else if (CI->getBitWidth() == 1) { //bool in LLVM 64 | value = std::to_string(-1 * CI->getSExtValue()); 65 | } else { 66 | value = std::to_string(CI->getSExtValue()); 67 | } 68 | 69 | return program.makeExpr(value, program.getType(CI->getType())); 70 | } 71 | 72 | if (auto CFP = llvm::dyn_cast_or_null(val)) { 73 | if (CFP->isInfinity()) { 74 | if (CFP->isNegative()) { 75 | auto call = std::make_unique(nullptr, "__builtin_inff", std::vector{}, program.getType(CFP->getType())); 76 | auto* callPtr = program.addOwnership(std::move(call)); 77 | return program.makeExpr(callPtr); 78 | } else { 79 | auto call = std::make_unique(nullptr, "__builtin_inff", std::vector{}, program.getType(CFP->getType())); 80 | return program.addOwnership(std::move(call)); 81 | } 82 | } else if (CFP->isNaN()){ 83 | auto param = std::make_unique("\"\"", program.typeHandler.pointerTo(program.typeHandler.uchar.get())); 84 | auto call = std::make_unique(nullptr, "__builtin_nanf", std::vector{param.get()}, program.typeHandler.floatType.get()); 85 | program.addOwnership(std::move(param)); 86 | return program.addOwnership(std::move(call)); 87 | } else { 88 | std::string CFPvalue; 89 | if (CFP->getType()->isFloatTy()) { 90 | CFPvalue = std::to_string(CFP->getValueAPF().convertToFloat()); 91 | } else if (CFP->getType()->isDoubleTy()) { 92 | CFPvalue = std::to_string(CFP->getValueAPF().convertToDouble()); 93 | } else { 94 | assert(false && "constval: unknown constant floating point type"); 95 | } 96 | 97 | if (CFPvalue.compare("-nan") == 0) { 98 | auto param = std::make_unique("\"\"", program.typeHandler.pointerTo(program.typeHandler.uchar.get())); 99 | auto call = std::make_unique(nullptr, "__builtin_nanf", std::vector{param.get()}, program.typeHandler.floatType.get()); 100 | auto* callPtr = program.addOwnership(std::move(call)); 101 | program.addOwnership(std::move(param)); 102 | return program.makeExpr(callPtr); 103 | } else { 104 | llvm::SmallVector string; 105 | CFPvalue = ""; 106 | CFP->getValueAPF().toString(string, 32, 0); 107 | for (unsigned i = 0; i < string.size(); i++) { 108 | CFPvalue += string[i]; 109 | } 110 | } 111 | 112 | return program.makeExpr(CFPvalue, program.getType(CFP->getType())); 113 | } 114 | } 115 | 116 | if (const auto* CAZ = llvm::dyn_cast_or_null(val)) { 117 | std::vector values; 118 | #if LLVM_VERSION_MAJOR >= 13 119 | unsigned count = CAZ->getElementCount().getFixedValue(); 120 | #else 121 | unsigned count = CAZ->getNumElements(); 122 | #endif 123 | 124 | for (unsigned i = 0; i < count; ++i) { 125 | auto* elem = CAZ->getElementValue(i); 126 | values.push_back(createConstantValue(elem, program)); 127 | } 128 | 129 | auto ai = std::make_unique(std::move(values)); 130 | ai->setType(program.getType(val->getType())); 131 | 132 | return program.addOwnership(std::move(ai)); 133 | } 134 | 135 | if (const llvm::ConstantAggregate* CA = llvm::dyn_cast_or_null(val)) { 136 | std::vector values; 137 | 138 | for (int i = 0; true; ++i) { 139 | auto* elem = CA->getAggregateElement(i); 140 | if (!elem) 141 | break; 142 | 143 | values.push_back(createConstantValue(elem, program)); 144 | } 145 | 146 | auto ai = std::make_unique(std::move(values)); 147 | ai->setType(program.getType(val->getType())); 148 | 149 | return program.addOwnership(std::move(ai)); 150 | } 151 | 152 | if (const llvm::ConstantDataSequential* CDS = llvm::dyn_cast_or_null(val)) { 153 | std::vector values; 154 | 155 | for (unsigned i = 0; i < CDS->getNumElements(); ++i) { 156 | values.push_back(createConstantValue(CDS->getElementAsConstant(i), program)); 157 | } 158 | 159 | auto ai = std::make_unique(values); 160 | ai->setType(program.getType(val->getType())); 161 | 162 | return program.addOwnership(std::move(ai)); 163 | } 164 | 165 | if (auto *CE = const_cast(llvm::dyn_cast_or_null(val))) { 166 | auto inst = toInst(CE); 167 | return parseLLVMInstruction(*inst.get(), program); 168 | } 169 | 170 | if (!val->getType()->isStructTy() && !val->getType()->isPointerTy() && !val->getType()->isArrayTy()) { 171 | val->getType()->print(llvm::errs(), true); 172 | 173 | val->print(llvm::errs(), true); 174 | 175 | assert(false && "constval: unknown type of constant value"); 176 | } 177 | 178 | auto ai = std::make_unique(std::vector{}); 179 | return program.addOwnership(std::move(ai)); 180 | } 181 | -------------------------------------------------------------------------------- /parser/constval.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include "../core/Func.h" 6 | #include "../core/Block.h" 7 | 8 | Expr* createConstantValue(const llvm::Value* val, Program& program); 9 | 10 | Expr* createUndefValue(const llvm::Type* ty, Program& program); 11 | -------------------------------------------------------------------------------- /parser/createAllocas.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../core/Program.h" 3 | #include "../core/Func.h" 4 | #include "../core/Block.h" 5 | 6 | #include "constval.h" 7 | 8 | void createAllocas(const llvm::Module* module, Program& program) { 9 | assert(program.isPassCompleted(PassType::CreateBlocks)); 10 | 11 | for (const auto& function : module->functions()) { 12 | auto* func = program.getFunction(&function); 13 | for (const auto& block : function) { 14 | auto* myBlock = func->getBlock(&block); 15 | 16 | for (const auto& ins : block) { 17 | if (ins.getOpcode() == llvm::Instruction::Alloca) { 18 | std::unique_ptr theVariable; 19 | std::unique_ptr alloc; 20 | const auto *allocaInst = llvm::cast(&ins); 21 | if (allocaInst->isArrayAllocation()) { 22 | //llvm::errs() << *allocaInst << "\n"; 23 | //llvm::errs() << *allocaInst->getAllocatedType() << "\n"; 24 | auto *llsize = allocaInst->getArraySize(); 25 | Expr *size = nullptr; 26 | if (llvm::isa(llsize)) { 27 | size = createConstantValue(llsize, program); 28 | } else { 29 | size = program.getExpr(llsize); 30 | } 31 | if (!size) { 32 | llvm::errs() << "Unhandled size argument of alloca: " << *allocaInst << "\n"; 33 | throw std::invalid_argument("Unhandled alloca"); 34 | } 35 | 36 | //theVariable = std::make_unique(func->getVarName(), func->getType(allocaInst->getType())); 37 | //alloc = std::make_unique(theVariable.get()); 38 | std::vector params; 39 | params.push_back(size); 40 | auto allocacall = std::make_unique( 41 | nullptr, 42 | "alloca", 43 | params, 44 | func->getType(allocaInst->getType())); 45 | 46 | // assign the result of the call to the variable 47 | theVariable = std::make_unique(func->getVarName(), allocacall->getType()); 48 | alloc = std::make_unique(theVariable.get()); 49 | auto assign = std::make_unique(theVariable.get(), allocacall.get()); 50 | myBlock->addExprAndOwnership(std::move(alloc)); 51 | myBlock->addOwnership(std::move(allocacall)); 52 | myBlock->addExprAndOwnership(std::move(assign)); 53 | //func->createExpr(&ins, std::move(allocacall)); 54 | } else { 55 | // normal alloca on the stack 56 | theVariable = std::make_unique(func->getVarName(), func->getType(allocaInst->getAllocatedType())); 57 | alloc = std::make_unique(theVariable.get()); 58 | myBlock->addExprAndOwnership(std::move(alloc)); 59 | } 60 | func->createExpr(&ins, std::make_unique(theVariable.get(), program.typeHandler.pointerTo(theVariable.get()->getType()))); 61 | myBlock->addOwnership(std::move(theVariable)); 62 | } 63 | } 64 | 65 | } 66 | } 67 | 68 | program.addPass(PassType::CreateAllocas); 69 | } 70 | -------------------------------------------------------------------------------- /parser/createBlocks.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../core/Program.h" 3 | #include "../core/Func.h" 4 | #include "../core/Block.h" 5 | 6 | void createBlocks(const llvm::Module* module, Program& program) { 7 | assert(program.isPassCompleted(PassType::CreateFunctions)); 8 | 9 | for (const llvm::Function& func : module->functions()) { 10 | if (func.size() == 0) 11 | continue; 12 | 13 | auto* function = program.getFunction(&func); 14 | for (const auto& block : func) { 15 | function->createBlockIfNotExist(&block); 16 | } 17 | 18 | if (function) 19 | function->entry = function->getBlock(&func.getEntryBlock()); 20 | } 21 | 22 | program.addPass(PassType::CreateBlocks); 23 | } 24 | -------------------------------------------------------------------------------- /parser/createConstants.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/Program.h" 4 | #include "constval.h" 5 | 6 | static void createConstantsForOperands(const llvm::User* ins, Program& program) { 7 | for (const auto& op : ins->operands()) { 8 | 9 | // assumption: the GV that is an operand of this has already been initialized 10 | // reason: pass ComputeGlobalVarsOrder has been completed 11 | if (llvm::isa(op.get())) 12 | continue; 13 | 14 | if (auto *user = llvm::dyn_cast_or_null(op.get())) { 15 | if (!llvm::isa(user)) 16 | createConstantsForOperands(user, program); 17 | } 18 | 19 | if (auto C = llvm::dyn_cast_or_null(op.get())) { 20 | if (program.getExpr(op.get()) == nullptr) 21 | program.addExpr(op.get(), createConstantValue(C, program)); 22 | } 23 | 24 | } 25 | } 26 | 27 | void createConstants(const llvm::Module* mod, Program& program) { 28 | 29 | assert(program.isPassCompleted(PassType::ComputeGlobalVarsOrder)); 30 | assert(program.isPassCompleted(PassType::CreateFunctions)); 31 | 32 | for (const auto& gvar : mod->globals()) { 33 | if (gvar.hasInitializer()) { 34 | auto* init = gvar.getInitializer(); 35 | if (auto *user = llvm::dyn_cast_or_null(init)) { 36 | createConstantsForOperands(user, program); 37 | } 38 | } 39 | } 40 | 41 | for (const auto& func : mod->functions()) { 42 | for (const auto& bb : func) { 43 | for (const auto& ins : bb) { 44 | createConstantsForOperands(&ins, program); 45 | } 46 | } 47 | } 48 | 49 | program.addPass(PassType::CreateConstants); 50 | } 51 | -------------------------------------------------------------------------------- /parser/createFunctionParameters.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Func.h" 3 | #include "../core/Block.h" 4 | 5 | #include 6 | #include 7 | 8 | static void createArgs(Program& program, const llvm::Function* llvmFunc, Func* func) { 9 | const llvm::Value* lastValue; 10 | for (const llvm::Value& arg : llvmFunc->args()) { 11 | lastValue = &arg; 12 | auto* argExpr = static_cast(func->getExpr(lastValue)); 13 | 14 | if (!argExpr) { 15 | auto argVal = std::make_unique(func->getVarName(), program.getType(arg.getType())); 16 | argExpr = argVal.get(); 17 | func->createExpr(lastValue, std::move(argVal)); 18 | } 19 | 20 | func->parameters.push_back(argExpr); 21 | } 22 | 23 | auto lastArg = program.exprMap[lastValue]; 24 | if (lastArg) { 25 | func->setVarArg(llvmFunc->isVarArg()); 26 | } 27 | } 28 | 29 | void createFunctionParameters(const llvm::Module* module, Program& program) { 30 | assert(program.isPassCompleted(PassType::CreateFunctions)); 31 | 32 | for (const llvm::Function& func : module->functions()) { 33 | auto* myFunc = program.getFunction(&func); 34 | 35 | 36 | if (myFunc) 37 | createArgs(program, &func, myFunc); 38 | 39 | } 40 | 41 | program.addPass(PassType::CreateFunctionParameters); 42 | } 43 | 44 | -------------------------------------------------------------------------------- /parser/createFunctions.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Func.h" 3 | #include "../core/Block.h" 4 | 5 | #include 6 | 7 | void createFunctions(const llvm::Module* module, Program& program) { 8 | assert(program.isPassCompleted(PassType::FindDeclaredFunctions)); 9 | 10 | for(const llvm::Function& func : module->functions()) { 11 | if (func.hasName() && !func.isDeclaration()) { 12 | auto *function = program.getFunction(&func); 13 | function->isDeclaration = false; 14 | } 15 | } 16 | 17 | program.addPass(PassType::CreateFunctions); 18 | } 19 | -------------------------------------------------------------------------------- /parser/deleteRedundantCasts.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/Program.h" 4 | #include "../core/Func.h" 5 | #include "../core/Block.h" 6 | 7 | #include "SimplifyingExprVisitor.h" 8 | 9 | class RedundantCastsVisitor: public SimplifyingExprVisitor { 10 | protected: 11 | Expr* simplify(Expr* expr) override; 12 | }; 13 | 14 | void deleteRedundantCasts(const llvm::Module* module, Program& program) { 15 | assert(program.isPassCompleted(PassType::CreateExpressions)); 16 | 17 | RedundantCastsVisitor rcv; 18 | 19 | for (const llvm::Function& func : module->functions()) { 20 | auto* function = program.getFunction(&func); 21 | for (const auto& block : func) { 22 | auto* myBlock = function->getBlock(&block); 23 | 24 | for (auto it = myBlock->expressions.begin(); it != myBlock->expressions.end(); ++it) { 25 | auto expr = *it; 26 | expr->accept(rcv); 27 | 28 | } 29 | } 30 | } 31 | program.addPass(PassType::DeleteRedundantCasts); 32 | } 33 | 34 | Expr* RedundantCastsVisitor::simplify(Expr* expr) { 35 | if (auto* cast = llvm::dyn_cast_or_null(expr)) { 36 | Expr* innermost = cast->expr; 37 | 38 | while (auto* inner = llvm::dyn_cast_or_null(innermost)) { 39 | innermost = inner->expr; 40 | } 41 | 42 | cast->expr = innermost; 43 | } 44 | 45 | return expr; 46 | } 47 | -------------------------------------------------------------------------------- /parser/deleteUnusedVariables.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "../core/Program.h" 5 | #include "../core/Func.h" 6 | #include "../core/Block.h" 7 | 8 | #include "SimplifyingExprVisitor.h" 9 | 10 | static void deleteExprFromBlock(Block* block, Expr* toDelete) { 11 | for (auto it = block->expressions.begin(); it != block->expressions.end(); ++it) { 12 | if (*it == toDelete) { 13 | block->expressions.erase(it); 14 | return; 15 | } 16 | } 17 | } 18 | 19 | void deleteUnusedVariables(const llvm::Module* module, Program& program) { 20 | assert(program.isPassCompleted(PassType::CreateExpressions)); 21 | for (const llvm::Function& func : module->functions()) { 22 | auto* function = program.getFunction(&func); 23 | for (const auto& block : func) { 24 | auto* myBlock = function->getBlock(&block); 25 | 26 | for (const auto& ins : block) { 27 | if (ins.getOpcode() == llvm::Instruction::Alloca) { 28 | if (ins.hasOneUse()) { 29 | auto* alloca = function->getExpr(&ins); 30 | auto* user = llvm::dyn_cast_or_null(*ins.users().begin()); 31 | if (!user) { 32 | continue; 33 | } 34 | 35 | // make sure the allocation is only used as a target of store 36 | if (user->getValueOperand() != &ins && user->getPointerOperand() == &ins) { 37 | deleteExprFromBlock(myBlock, alloca); 38 | deleteExprFromBlock(myBlock, function->getExpr(user)); 39 | } 40 | } 41 | } 42 | } 43 | } 44 | } 45 | 46 | program.addPass(PassType::DeleteUnusedVariables); 47 | } 48 | -------------------------------------------------------------------------------- /parser/extractVars.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Block.h" 3 | #include "../expr/Expr.h" 4 | 5 | #include 6 | 7 | static void deleteExprFromBlock(Block* block, Expr* toDelete) { 8 | for (auto it = block->expressions.begin(); it != block->expressions.end(); ++it) { 9 | if (*it == toDelete) { 10 | block->expressions.erase(it); 11 | return; 12 | } 13 | } 14 | } 15 | 16 | 17 | void extractVars(const llvm::Module* module, Program& program) { 18 | assert(program.isPassCompleted(PassType::CreateAllocas)); 19 | assert(program.isPassCompleted(PassType::CreateExpressions)); 20 | 21 | for (const auto& func : module->functions()) { 22 | auto* function = program.getFunction(&func); 23 | 24 | for (const auto& block : func) { 25 | std::vector allocs; 26 | // 1. find allocas 27 | auto* myBlock = function->getBlock(&block); 28 | for (const auto& expr : myBlock->expressions) { 29 | if (auto alloc = llvm::dyn_cast_or_null(expr)) { 30 | allocs.push_back(alloc); 31 | } 32 | } 33 | 34 | for (auto* alloc : allocs) { 35 | // 2. remove them from block->expressions (ownership can stay in principle) 36 | deleteExprFromBlock(myBlock, alloc); 37 | 38 | // 3. add them at the beginning of function 39 | function->variables.push_back(alloc->value); 40 | } 41 | 42 | } 43 | 44 | } 45 | 46 | program.addPass(PassType::ExtractVars); 47 | } 48 | -------------------------------------------------------------------------------- /parser/findDeclaredFunctions.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/Program.h" 4 | #include "../core/Func.h" 5 | #include "../core/Block.h" 6 | 7 | #include 8 | 9 | static void declareFunc(const llvm::Function* func, Program& program) { 10 | auto decl = std::make_unique(func, &program, func->isDeclaration()); 11 | for (const llvm::Value& arg : func->args()) { 12 | auto argVal = std::make_unique(decl->getVarName(), program.getType(arg.getType())); 13 | decl->createExpr(&arg, std::move(argVal)); 14 | } 15 | 16 | if (func->args().begin() != func->args().end()) { 17 | decl->setVarArg(func->isVarArg()); 18 | } 19 | 20 | // FIXME: a hack for CPAchecker -- do this optional 21 | if (func->getName().startswith("__VERIFIER_nondet_") && 22 | (func->getName().endswith("_int") || 23 | func->getName().endswith("_long") || 24 | func->getName().endswith("_short") || 25 | func->getName().endswith("_char") || 26 | func->getName().endswith("_float") || 27 | func->getName().endswith("_double"))) { 28 | decl->returnType = program.typeHandler.setSigned(static_cast(decl->returnType)); 29 | } 30 | program.addFunction(func, std::move(decl)); 31 | } 32 | 33 | void findDeclaredFunctions(const llvm::Module *module, Program& program) { 34 | for(const llvm::Function& func : module->functions()) { 35 | if (func.hasName()) { 36 | if (func.isDeclaration() || llvm::Function::isInternalLinkage(func.getLinkage())) { 37 | if (func.getName().str().substr(0, 8) != "llvm.dbg" && func.getName() != "isnan") { 38 | if (!program.isFunctionDeclared(&func)) { 39 | declareFunc(&func, program); 40 | } 41 | } 42 | } 43 | 44 | if (!func.isDeclaration()) { 45 | if (!program.isFunctionDeclared(&func)) { 46 | declareFunc(&func, program); 47 | } 48 | } 49 | } 50 | } 51 | 52 | program.addPass(PassType::FindDeclaredFunctions); 53 | } 54 | -------------------------------------------------------------------------------- /parser/findMetadataFunctionNames.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Func.h" 3 | #include "../core/Block.h" 4 | 5 | #include 6 | 7 | #include 8 | 9 | void findMetadataFunctionNames(const llvm::Module* module, Program& program) { 10 | assert(program.isPassCompleted(PassType::CreateFunctions)); 11 | 12 | for (const llvm::Function& func : module->functions()) { 13 | if (func.isDeclaration()) 14 | continue; 15 | 16 | auto function = program.getFunction(&func); 17 | assert(function && "Do not have function"); 18 | 19 | function->fillMetadataVarNames(program.getGlobalVarNames()); 20 | 21 | for (const llvm::BasicBlock& block : func) { 22 | for (const llvm::Instruction& ins : block) { 23 | if (ins.getOpcode() == llvm::Instruction::Call) { 24 | const auto CI = llvm::cast(&ins); 25 | if (CI->getCalledFunction() && CI->getCalledFunction()->getName().str().compare("llvm.dbg.declare") == 0) { 26 | llvm::Metadata* varMD = llvm::dyn_cast_or_null(ins.getOperand(1))->getMetadata(); 27 | llvm::DILocalVariable* localVar = llvm::dyn_cast_or_null(varMD); 28 | 29 | std::regex varName("var[0-9]+"); 30 | if (std::regex_match(localVar->getName().str(), varName)) { 31 | function->addMetadataVarName(localVar->getName().str()); 32 | } 33 | } 34 | } 35 | } 36 | } 37 | } 38 | 39 | program.addPass(PassType::FindMetadataFunctionNames); 40 | } 41 | -------------------------------------------------------------------------------- /parser/findMetadataVariableNames.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Func.h" 3 | #include "../core/Block.h" 4 | 5 | #include 6 | 7 | static void setMetadataInfo(const llvm::CallInst* ins, Block* block) { 8 | llvm::Metadata* md = llvm::dyn_cast_or_null(ins->getOperand(0))->getMetadata(); 9 | llvm::Value* referredVal = llvm::cast(md)->getValue(); 10 | Expr* referred = block->func->getExpr(referredVal); 11 | 12 | if (auto* re = llvm::dyn_cast_or_null(referred)) { 13 | referred = re->expr; 14 | } 15 | 16 | if (Value* variable = llvm::dyn_cast_or_null(referred)) { 17 | llvm::Metadata* varMD = llvm::dyn_cast_or_null(ins->getOperand(1))->getMetadata(); 18 | llvm::DILocalVariable* localVar = llvm::dyn_cast_or_null(varMD); 19 | 20 | if (!localVar->getName().empty()) { 21 | auto& counters = block->func->variableCounters; 22 | auto it = counters.find(localVar->getName().str()); 23 | std::string name = localVar->getName().str(); 24 | 25 | if (it != counters.end()) { 26 | it->second++; 27 | name += std::to_string(it->second); 28 | } else { 29 | counters[localVar->getName().str()] = 1; 30 | } 31 | 32 | variable->valueName = name; 33 | } 34 | } 35 | } 36 | 37 | 38 | void findMetadataVariableNames(const llvm::Module* module, Program& program) { 39 | assert(program.isPassCompleted(PassType::CreateAllocas)); 40 | 41 | for (const auto& function : module->functions()) { 42 | auto* func = program.getFunction(&function); 43 | for (const auto& block : function) { 44 | auto* myBlock = func->getBlock(&block); 45 | 46 | for (const auto& ins : block) { 47 | if (ins.getOpcode() == llvm::Instruction::Call) { 48 | const llvm::CallInst* CI = llvm::cast(&ins); 49 | if (CI->getCalledFunction()) { 50 | if (CI->getCalledFunction()->getName().str().compare("llvm.dbg.declare") == 0) { 51 | setMetadataInfo(CI, myBlock); 52 | } 53 | } 54 | } 55 | } 56 | 57 | } 58 | } 59 | 60 | program.addPass(PassType::FindMetadataVariableNames); 61 | } 62 | -------------------------------------------------------------------------------- /parser/fixMainParameters.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Func.h" 3 | #include "../core/Block.h" 4 | 5 | #include 6 | #include 7 | 8 | void fixMainParameters(const llvm::Module* module, Program& program) { 9 | assert(program.isPassCompleted(PassType::CreateFunctionParameters)); 10 | 11 | auto* uchar_ptr_ptr = program.typeHandler.pointerTo(program.typeHandler.pointerTo(program.typeHandler.schar.get())); 12 | 13 | for (const llvm::Function& func : module->functions()) { 14 | if (func.getName() != "main") { 15 | continue; 16 | } 17 | 18 | auto* myFunc = program.getFunction(&func); 19 | 20 | if (func.getReturnType()->isIntegerTy()) 21 | myFunc->returnType = program.typeHandler.sint.get(); 22 | 23 | if (myFunc->parameters.size() >= 1) { 24 | myFunc->parameters[0]->setType(program.typeHandler.sint.get()); 25 | myFunc->parameters[0]->setName("argc"); 26 | } 27 | 28 | if (myFunc->parameters.size() >= 2) { 29 | myFunc->parameters[1]->setType(uchar_ptr_ptr); 30 | myFunc->parameters[1]->setName("argv"); 31 | } 32 | 33 | } 34 | 35 | program.addPass(PassType::FixMainParameters); 36 | } 37 | -------------------------------------------------------------------------------- /parser/identifyInlinableBlocks.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | 8 | static bool isSafeToInline(const llvm::BasicBlock* llvmBlock, const Block* block) { 9 | if (llvmBlock->getSinglePredecessor()) { 10 | return true; 11 | } 12 | 13 | if (block->expressions.size() == 1) { 14 | const Expr* fst = block->expressions.front(); 15 | return llvm::isa(fst); 16 | } 17 | 18 | return false; 19 | } 20 | 21 | void identifyInlinableBlocks(const llvm::Module* module, Program& program) { 22 | assert(program.isPassCompleted(PassType::CreateExpressions)); 23 | assert(program.isPassCompleted(PassType::ParseBreaks)); 24 | 25 | for (const llvm::Function& func : module->functions()) { 26 | auto* function = program.getFunction(&func); 27 | for (const auto& block : func) { 28 | auto* myBlock = function->createBlockIfNotExist(&block); 29 | myBlock->doInline = isSafeToInline(&block, myBlock); 30 | } 31 | 32 | if (func.begin() == func.end()) 33 | continue; 34 | 35 | // first block is only inlinable if there are no predecessors 36 | auto& firstBlock = *func.begin(); 37 | auto* myBlock = function->createBlockIfNotExist(&firstBlock); 38 | 39 | myBlock->doInline = false; 40 | myBlock->isFirst = true; 41 | } 42 | 43 | program.addPass(PassType::IdentifyInlinableBlocks); 44 | } 45 | -------------------------------------------------------------------------------- /parser/initializeGlobalVars.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Func.h" 3 | #include "../core/Block.h" 4 | #include "../type/Type.h" 5 | 6 | #include "constval.h" 7 | 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | void initializeGlobalVars(const llvm::Module* module, Program& program) { 14 | assert(program.isPassCompleted(PassType::CreateConstants)); 15 | assert(program.isPassCompleted(PassType::ComputeGlobalVarsOrder)); 16 | 17 | for (const llvm::GlobalVariable& gvar : module->globals()) { 18 | if (llvm::isa(&gvar)) { 19 | continue; 20 | } 21 | 22 | if (gvar.hasInitializer()) { 23 | auto* ref = program.getGlobalVar(&gvar); 24 | auto* var = llvm::cast(ref->expr); 25 | var->value = createConstantValue(gvar.getInitializer(), program); 26 | } 27 | } 28 | 29 | program.addPass(PassType::InitializeGlobalVars); 30 | } 31 | -------------------------------------------------------------------------------- /parser/inlineBlocks.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "SimplifyingExprVisitor.h" 3 | 4 | #include 5 | 6 | #include 7 | 8 | class InliningVisitor : public SimplifyingExprVisitor { 9 | private: 10 | Block* container; 11 | public: 12 | InliningVisitor(Block* container) : container(container) {} 13 | Expr* simplify(Expr* expr) override; 14 | }; 15 | 16 | Expr* InliningVisitor::simplify(Expr* expr) { 17 | if (auto* gotoExpr = llvm::dyn_cast_or_null(expr)) { 18 | Block* target = gotoExpr->target; 19 | 20 | if (target->doInline) { 21 | std::vector targetBlockExpressions; 22 | for (auto* expr : target->expressions) { 23 | expr->accept(*this); 24 | targetBlockExpressions.push_back(simplify(expr)); 25 | } 26 | 27 | auto list = std::make_unique(std::move(targetBlockExpressions)); 28 | Expr* result = list.get(); 29 | container->addOwnership(std::move(list)); 30 | return result; 31 | } 32 | } 33 | 34 | return expr; 35 | } 36 | 37 | void inlineBlocks(const llvm::Module* module, Program& program) { 38 | assert(program.isPassCompleted(PassType::IdentifyInlinableBlocks)); 39 | 40 | 41 | for (const llvm::Function& func : module->functions()) { 42 | auto* function = program.getFunction(&func); 43 | for (const auto& block : func) { 44 | auto* myBlock = function->createBlockIfNotExist(&block); 45 | InliningVisitor iv(myBlock); 46 | 47 | for (auto& expr : myBlock->expressions) { 48 | expr->accept(iv); 49 | expr = iv.simplify(expr); 50 | } 51 | } 52 | } 53 | 54 | program.addPass(PassType::InlineBlocks); 55 | } 56 | -------------------------------------------------------------------------------- /parser/memcpyToAssign.cpp: -------------------------------------------------------------------------------- 1 | #include "cfunc.h" 2 | #include "toinst.h" 3 | 4 | #include "../core/Program.h" 5 | #include "../core/Func.h" 6 | #include "../core/Block.h" 7 | 8 | #include 9 | 10 | #include 11 | 12 | const llvm::Value* stripCast(const llvm::Value* val) { 13 | 14 | if (auto* BC = llvm::dyn_cast_or_null(val)) { 15 | return BC->getOperand(0); 16 | } 17 | 18 | if (auto* CE = const_cast(llvm::dyn_cast_or_null(val))) { 19 | auto inst = toInst(CE); 20 | return stripCast(inst.get()); 21 | } 22 | 23 | return nullptr; 24 | } 25 | 26 | void memcpyToAssignment(const llvm::Module* module, Program& program) { 27 | assert(program.isPassCompleted(PassType::CreateExpressions)); 28 | 29 | for (const auto& function : module->functions()) { 30 | auto* func = program.getFunction(&function); 31 | for (const auto& block : function) { 32 | auto* myBlock = func->getBlock(&block); 33 | 34 | for (const auto& ins : block) { 35 | if (auto callInst = llvm::dyn_cast_or_null(&ins)) { 36 | if (!callInst->getCalledFunction()) { 37 | continue; 38 | } 39 | 40 | std::string funcName = callInst->getCalledFunction()->getName().str(); 41 | 42 | if (funcName.substr(0,4) == "llvm") { 43 | funcName = trimPrefix(funcName); 44 | if (funcName == "memcpy") { 45 | auto* dstVal = callInst->getArgOperand(0); 46 | auto* srcVal = callInst->getArgOperand(1); 47 | auto* size = callInst->getArgOperand(2); 48 | 49 | // 1. check if operands are bitcasted pointer to structs 50 | if (auto* dst = stripCast(dstVal)) { 51 | if (auto* src = stripCast(srcVal)) { 52 | 53 | // 2. strip the bitcast 54 | auto* dstTy = dst->getType(); 55 | auto* srcTy = src->getType(); 56 | 57 | // check if both structs share the same type 58 | if (dstTy != srcTy) { 59 | // stop processing this call 60 | continue; 61 | } 62 | 63 | if (!dstTy->isPointerTy()) { 64 | continue; 65 | } 66 | 67 | auto *PT = dstTy->getPointerElementType(); 68 | 69 | // 3. check if the memcpy size is a constant 70 | if (auto* constSize = llvm::dyn_cast_or_null(size)) { 71 | size_t expectedSize = module->getDataLayout().getTypeAllocSize(PT); 72 | 73 | // 4. check if the memcpy size is size of the whole type 74 | if (expectedSize == constSize->getValue().getLimitedValue()) { 75 | auto* exprToReplace = func->getExpr(callInst); 76 | auto* srcExpr = func->getExpr(src); 77 | auto* dstExpr = func->getExpr(dst); 78 | 79 | if (auto* srcRef = llvm::dyn_cast_or_null(srcExpr)) { 80 | if (auto* dstRef = llvm::dyn_cast_or_null(dstExpr)) { 81 | auto assignment = std::make_unique(dstRef->expr, srcRef->expr); 82 | Expr* newExpr = assignment.get(); 83 | myBlock->addOwnership(std::move(assignment)); 84 | std::replace(myBlock->expressions.begin(), myBlock->expressions.end(), exprToReplace, newExpr); 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | 92 | } 93 | } 94 | } 95 | } 96 | 97 | } 98 | } 99 | 100 | program.addPass(PassType::MemcpyToAssignment); 101 | } 102 | -------------------------------------------------------------------------------- /parser/nameFunctions.cpp: -------------------------------------------------------------------------------- 1 | #include "cfunc.h" 2 | 3 | #include "../core/Program.h" 4 | 5 | #include 6 | 7 | static void nameFunction(const llvm::Function* llvmFunc, Func* func) { 8 | auto name = llvmFunc->getName().str(); 9 | if (isCFunc(trimPrefix(name))) { 10 | name = trimPrefix(name); 11 | if (name.compare("va_start") == 0 12 | || name.compare("va_end") == 0 13 | || name.compare("va_copy") == 0 14 | || isCMath(name)) { 15 | } 16 | } 17 | 18 | if (name.substr(0, 4).compare("llvm") == 0) { 19 | std::replace(name.begin(), name.end(), '.', '_'); 20 | } 21 | 22 | func->name = name; 23 | } 24 | 25 | void nameFunctions(const llvm::Module* module, Program& program) { 26 | assert(program.isPassCompleted(PassType::CreateFunctions)); 27 | 28 | for (const llvm::Function& func : module->functions()) { 29 | auto* function = program.getFunction(&func); 30 | 31 | if (function) 32 | nameFunction(&func, function); 33 | } 34 | 35 | program.addPass(PassType::NameFunctions); 36 | } 37 | -------------------------------------------------------------------------------- /parser/parseBreaks.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Func.h" 3 | #include "../core/Block.h" 4 | #include "cfunc.h" 5 | #include "constval.h" 6 | 7 | #include 8 | 9 | /** 10 | * return phi assignments as ExprList 11 | */ 12 | static std::vector generatePhiAssignments(Block* blockEnding, Block* nextBlock) { 13 | std::vector exprs; 14 | 15 | Program& program = *blockEnding->func->program; 16 | 17 | for (const auto& phi : nextBlock->block->phis()) { 18 | Expr* phiVar = program.getExpr(&phi); 19 | 20 | // see if nextBlock declares any incoming value from blockEnding 21 | for (unsigned i = 0; i < phi.getNumIncomingValues(); ++i) { 22 | if (phi.getIncomingBlock(i) == blockEnding->block) { 23 | Expr* incoming = program.getExpr(phi.getIncomingValue(i)); 24 | exprs.push_back(program.makeExpr(phiVar, incoming)); 25 | } 26 | } 27 | } 28 | 29 | return exprs; 30 | } 31 | 32 | static Expr* createListOfOneGoto(Block* container, Block* gotoTarget) { 33 | auto gotoExpr = std::make_unique(gotoTarget); 34 | 35 | std::vector exprs = generatePhiAssignments(container, gotoTarget); 36 | exprs.push_back(gotoExpr.get()); 37 | auto list = std::make_unique(std::move(exprs)); 38 | 39 | container->addOwnership(std::move(gotoExpr)); 40 | auto* result = list.get(); 41 | container->addOwnership(std::move(list)); 42 | return result; 43 | } 44 | 45 | static void parseBrInstruction(const llvm::Instruction& ins, Func* func, Block* block) { 46 | //no condition 47 | if (ins.getNumOperands() == 1) { 48 | Block* target = func->createBlockIfNotExist((llvm::BasicBlock*)ins.getOperand(0)); 49 | 50 | auto assignments = generatePhiAssignments(block, target); 51 | for (auto& assignment : assignments) { 52 | block->addExpr(assignment); 53 | } 54 | 55 | auto gotoExpr = std::make_unique(target); 56 | func->program->exprMap[&ins] = gotoExpr.get(); 57 | block->addExprAndOwnership(std::move(gotoExpr)); 58 | return; 59 | } 60 | 61 | Expr* cmp = func->getExpr(ins.getOperand(0)); 62 | 63 | Block* falseBlock = func->createBlockIfNotExist((llvm::BasicBlock*)ins.getOperand(1)); 64 | Block* trueBlock = func->createBlockIfNotExist((llvm::BasicBlock*)ins.getOperand(2)); 65 | 66 | auto ifExpr = std::make_unique(cmp, createListOfOneGoto(block, trueBlock), createListOfOneGoto(block, falseBlock)); 67 | 68 | func->createExpr(&ins, std::move(ifExpr)); 69 | block->addExpr(func->getExpr(&ins)); 70 | } 71 | 72 | static void parseRetInstruction(const llvm::Instruction& ins, Func* func, Block* block) { 73 | const llvm::Value* value = &ins; 74 | 75 | if (ins.getNumOperands() == 0) { 76 | func->createExpr(value, std::make_unique()); 77 | } else { 78 | Expr* expr = func->getExpr(ins.getOperand(0)); 79 | assert(expr); 80 | 81 | func->createExpr(value, std::make_unique(expr)); 82 | } 83 | 84 | block->addExpr(func->getExpr(&ins)); 85 | } 86 | 87 | 88 | void parseBreaks(const llvm::Module* module, Program& program) { 89 | assert(program.isPassCompleted(PassType::CreateExpressions)); 90 | 91 | for (const auto& function : module->functions()) { 92 | auto* func = program.getFunction(&function); 93 | for (const auto& block : function) { 94 | auto* myBlock = func->getBlock(&block); 95 | 96 | for (const auto& ins : block) { 97 | auto opcode = ins.getOpcode(); 98 | if (opcode == llvm::Instruction::Br) { 99 | parseBrInstruction(ins, func, myBlock); 100 | } else if (opcode == llvm::Instruction::Ret) { 101 | parseRetInstruction(ins, func, myBlock); 102 | } 103 | } 104 | } 105 | } 106 | 107 | program.addPass(PassType::ParseBreaks); 108 | } 109 | -------------------------------------------------------------------------------- /parser/parseMetadataTypes.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Func.h" 3 | #include "../core/Block.h" 4 | 5 | #include 6 | 7 | static void setMetadataInfo(Program& program, const llvm::CallInst* ins, Block* block) { 8 | llvm::Metadata* md = llvm::dyn_cast_or_null(ins->getOperand(0))->getMetadata(); 9 | llvm::Value* referredVal = llvm::cast(md)->getValue(); 10 | Expr* referred = block->func->getExpr(referredVal); 11 | 12 | if (auto* re = llvm::dyn_cast_or_null(referred)) { 13 | referred = re->expr; 14 | } 15 | 16 | if (Value* variable = llvm::dyn_cast_or_null(referred)) { 17 | llvm::Metadata* varMD = llvm::dyn_cast_or_null(ins->getOperand(1))->getMetadata(); 18 | llvm::DILocalVariable* localVar = llvm::dyn_cast_or_null(varMD); 19 | llvm::DIBasicType* type = llvm::dyn_cast_or_null(localVar->getType()); 20 | 21 | if (type && type->getName().str().compare(0, 8, "unsigned") == 0) { 22 | if (IntegerType* IT = llvm::dyn_cast_or_null(variable->getType())) { 23 | variable->setType(program.typeHandler.toggleSignedness(IT)); 24 | } 25 | } 26 | } 27 | } 28 | 29 | void parseMetadataTypes(const llvm::Module* module, Program& program) { 30 | assert(program.isPassCompleted(PassType::CreateAllocas)); 31 | 32 | for (const auto& function : module->functions()) { 33 | auto* func = program.getFunction(&function); 34 | for (const auto& block : function) { 35 | auto* myBlock = func->getBlock(&block); 36 | 37 | for (const auto& ins : block) { 38 | if (ins.getOpcode() == llvm::Instruction::Call) { 39 | const llvm::CallInst* CI = llvm::cast(&ins); 40 | if (CI->getCalledFunction()) { 41 | if (CI->getCalledFunction()->getName().str().compare("llvm.dbg.declare") == 0) { 42 | setMetadataInfo(program, CI, myBlock); 43 | } 44 | } 45 | } 46 | } 47 | 48 | } 49 | } 50 | 51 | program.addPass(PassType::ParseMetadataTypes); 52 | } 53 | -------------------------------------------------------------------------------- /parser/parseStructDeclarations.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Func.h" 3 | #include "../core/Block.h" 4 | #include "../type/TypeHandler.h" 5 | 6 | #include 7 | 8 | 9 | static void initVarargStruct(StructType& varargStruct, Program& program) { 10 | varargStruct.addItem(program.typeHandler.uint.get(), "gp_offset"); 11 | varargStruct.addItem(program.typeHandler.uint.get(), "fp_offset"); 12 | varargStruct.addItem(program.typeHandler.pointerTo(program.typeHandler.voidType.get()), "overflow_arg_area"); 13 | varargStruct.addItem(program.typeHandler.pointerTo(program.typeHandler.voidType.get()), "reg_save_area"); 14 | } 15 | 16 | void parseStructDeclarations(const llvm::Module* module, Program& program) { 17 | 18 | for (llvm::StructType* structType : module->getIdentifiedStructTypes()) { 19 | std::string structName = TypeHandler::getStructName(structType->getName().str()); 20 | 21 | if (!program.hasVarArg && structName.compare("__va_list_tag") == 0) { 22 | auto varargStruct = std::make_unique(structName); 23 | initVarargStruct(*varargStruct, program); 24 | program.addStruct(std::move(varargStruct)); 25 | 26 | program.hasVarArg = true; 27 | continue; 28 | } 29 | 30 | auto structExpr = std::make_unique(structName); 31 | program.addStruct(std::move(structExpr)); 32 | } 33 | 34 | program.addPass(PassType::ParseStructDeclarations); 35 | } 36 | -------------------------------------------------------------------------------- /parser/parseStructItems.cpp: -------------------------------------------------------------------------------- 1 | #include "../core/Program.h" 2 | #include "../core/Func.h" 3 | #include "../core/Block.h" 4 | #include "../type/TypeHandler.h" 5 | 6 | #include 7 | 8 | 9 | void parseStructItems(const llvm::Module* module, Program& program) { 10 | assert(program.isPassCompleted(PassType::ParseStructDeclarations)); 11 | 12 | for (llvm::StructType* structType : module->getIdentifiedStructTypes()) { 13 | auto structExpr = llvm::dyn_cast(program.typeHandler.getType(structType)); 14 | assert(structExpr && "parseStructItems: corresponding struct declaration not found"); 15 | 16 | for (llvm::Type* type : structType->elements()) { 17 | auto ty = program.getType(type); 18 | assert(ty && "parseStructItems: corresponding type not found"); 19 | structExpr->addItem(ty, program.getStructVarName()); 20 | } 21 | 22 | } 23 | 24 | program.addPass(PassType::ParseStructItems); 25 | } 26 | -------------------------------------------------------------------------------- /parser/passes.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include "../core/Program.h" 5 | 6 | // FIXME: create a class that represents options and pass it to every module 7 | void initializeGlobalVars(const llvm::Module* module, Program& program); 8 | void parseStructDeclarations(const llvm::Module* module, Program& program); 9 | void parseStructItems(const llvm::Module* module, Program& program); 10 | void parseFunctions(const llvm::Module* module, Program& program); 11 | void determineIncludes(const llvm::Module* module, Program& program); 12 | void findMetadataFunctionNames(const llvm::Module* module, Program& program); 13 | void findMetadataVariableNames(const llvm::Module* module, Program& program); 14 | void createFunctions(const llvm::Module* module, Program& program); 15 | void createFunctionParameters(const llvm::Module* module, Program& program); 16 | void createBlocks(const llvm::Module* module, Program& program); 17 | void createAllocas(const llvm::Module* module, Program& program); 18 | void parseMetadataTypes(const llvm::Module* module, Program& program); 19 | void createExpressions(const llvm::Module* module, Program& program, bool bitcastUnions); 20 | void findDeclaredFunctions(const llvm::Module* module, Program& program); 21 | void nameFunctions(const llvm::Module* module, Program& program); 22 | void parseBreaks(const llvm::Module* module, Program& program); 23 | void identifyInlinableBlocks(const llvm::Module* module, Program& program); 24 | void refDeref(const llvm::Module* mod, Program& program); 25 | void fixMainParameters(const llvm::Module* module, Program& program); 26 | void addSignCasts(const llvm::Module* module, Program& program); 27 | void deleteRedundantCasts(const llvm::Module* module, Program& program); 28 | void deleteUnusedVariables(const llvm::Module* module, Program& program); 29 | void extractVars(const llvm::Module* module, Program& program); 30 | void arrowify(const llvm::Module* module, Program& program); 31 | void memcpyToAssignment(const llvm::Module* module, Program& program); 32 | void computeGlobalVarsOrder(const llvm::Module* module, Program& program); 33 | void createConstants(const llvm::Module* mod, Program& program); 34 | void inlineBlocks(const llvm::Module* mod, Program& program); 35 | void prepareBitcastUnion(const llvm::Module* mod, Program& program); 36 | -------------------------------------------------------------------------------- /parser/prepareBitcastUnion.cpp: -------------------------------------------------------------------------------- 1 | #include "../type/Type.h" 2 | #include "../core/Program.h" 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | void prepareBitcastUnion(const llvm::Module* mod, Program& program) { 9 | assert(!program.isPassCompleted(PassType::CreateExpressions)); 10 | 11 | std::unordered_set types; 12 | 13 | for (const auto& function : mod->functions()) { 14 | for (const auto& bb : function) { 15 | for (const auto& ins : bb) { 16 | if (ins.getOpcode() == llvm::Instruction::BitCast) { 17 | const auto* cast = static_cast(&ins); 18 | types.insert(program.getType(cast->getSrcTy())); 19 | types.insert(program.getType(cast->getDestTy())); 20 | } 21 | } 22 | } 23 | } 24 | 25 | if (!types.empty()) { 26 | std::vector typeVector(types.begin(), types.end()); 27 | 28 | std::sort(typeVector.begin(), typeVector.end(), [](const Type* a, const Type* b) { 29 | return a->toString().compare(b->toString()); 30 | }); 31 | 32 | program.bitcastUnion = program.addUnion(typeVector); 33 | } 34 | 35 | program.addPass(PassType::PrepareBitcastUnion); 36 | } 37 | -------------------------------------------------------------------------------- /parser/refDeref.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "../core/Program.h" 4 | #include "../core/Func.h" 5 | #include "../core/Block.h" 6 | 7 | #include "SimplifyingExprVisitor.h" 8 | 9 | class RefDerefVisitor : public SimplifyingExprVisitor { 10 | 11 | protected: 12 | Expr* simplify(Expr* expr) override; 13 | }; 14 | 15 | void refDeref(const llvm::Module* module, Program& program) { 16 | assert(program.isPassCompleted(PassType::CreateExpressions)); 17 | 18 | RefDerefVisitor rdv; 19 | 20 | for (const llvm::Function& func : module->functions()) { 21 | auto* function = program.getFunction(&func); 22 | for (const auto& block : func) { 23 | auto* myBlock = function->getBlock(&block); 24 | 25 | for (auto it = myBlock->expressions.begin(); it != myBlock->expressions.end(); ++it) { 26 | auto expr = *it; 27 | expr->accept(rdv); 28 | } 29 | } 30 | } 31 | 32 | program.addPass(PassType::RefDeref); 33 | } 34 | 35 | Expr* RefDerefVisitor::simplify(Expr* expr) { 36 | if (auto RE = llvm::dyn_cast_or_null(expr)) { 37 | if (auto DE = llvm::dyn_cast_or_null(RE->expr)) { 38 | return DE->expr; 39 | } 40 | } 41 | 42 | if (auto DE = llvm::dyn_cast_or_null(expr)) { 43 | if (auto RE = llvm::dyn_cast_or_null(DE->expr)) { 44 | return RE->expr; 45 | } 46 | } 47 | 48 | return expr; 49 | } 50 | -------------------------------------------------------------------------------- /parser/toinst.cpp: -------------------------------------------------------------------------------- 1 | #include "toinst.h" 2 | 3 | std::unique_ptr> toInst( 4 | llvm::ConstantExpr* ce){ 5 | return std::unique_ptr>( 6 | ce->getAsInstruction(), 7 | [](llvm::Instruction* inst) { inst->deleteValue(); } 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /parser/toinst.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | /* 10 | * ConstantExpr is commonly transformed to Instruction using getAsInstruction. 11 | * The function, however, creates a new Instruction that is not part of the 12 | * program and causes issues. This function wraps the problematic Instruction in 13 | * a unique_ptr, so programmer won't forget to delete it. 14 | 15 | Example usage (in memcpyToAssign): 16 | if (auto* CE = llvm::dyn_cast_or_null(val)) { 17 | auto inst = gai(CE); 18 | return stripCast(inst.get()); 19 | } 20 | */ 21 | std::unique_ptr> toInst(llvm::ConstantExpr* ce); 22 | -------------------------------------------------------------------------------- /test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------- 2 | # CTest 3 | # -------------------------------------------------- 4 | enable_testing() 5 | 6 | include(ProcessorCount) 7 | ProcessorCount(N) 8 | if(N EQUAL 0) 9 | set(N 1) 10 | endif() 11 | 12 | set(CTEST_OPTS -j${N} --output-on-failure --progress ${CTEST_OPTS}) 13 | add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} ${CTEST_OPTS} 14 | USES_TERMINAL) 15 | add_dependencies(check llvm2c) 16 | 17 | # -------------------------------------------------- 18 | # Clang and Opt 19 | # -------------------------------------------------- 20 | # REQUIRED available only with CMake 3.18+ 21 | foreach(TOOL CLANG OPT) 22 | string(TOLOWER ${TOOL} TOOL_LOWER) 23 | 24 | # REQUIRED available only with CMake 3.18+ 25 | find_program(${TOOL} ${TOOL_LOWER} PATHS ${LLVM_TOOLS_BINARY_DIR} 26 | NO_DEFAULT_PATH) 27 | if(NOT ${TOOL}) 28 | message(FATAL_ERROR "${TOOL_LOWER}: version compatible with LLVM \ 29 | ${LLVM_PACKAGE_VERSION} not found") 30 | endif() 31 | message(STATUS "${TOOL_LOWER}: ${${TOOL}}") 32 | endforeach() 33 | 34 | # -------------------------------------------------- 35 | # Tests 36 | # -------------------------------------------------- 37 | set(LLVM2C $) 38 | configure_file(run.in run.imd @ONLY) 39 | file(GENERATE OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/run 40 | INPUT ${CMAKE_CURRENT_BINARY_DIR}/run.imd) 41 | 42 | set(tests 43 | asm 44 | branching 45 | globals 46 | loops 47 | main 48 | math 49 | phi 50 | pointer 51 | standard_lib 52 | statements 53 | struct 54 | union 55 | ) 56 | 57 | foreach(test ${tests}) 58 | add_test(NAME ${test} COMMAND ./run ${test}) 59 | endforeach() 60 | -------------------------------------------------------------------------------- /test/base.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != ) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/csmith_testing.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | num_tests = 1000 4 | csmith_runtime_dir = 'csmith-runtime' 5 | 6 | import tempfile, os 7 | from subprocess import run, DEVNULL 8 | 9 | dirname = 'csmith-tests' 10 | for i in range(num_tests): 11 | run(['./csmith', '--output', dirname + '/program.c']) 12 | run(['clang', '-I', csmith_runtime_dir, '-S', '-emit-llvm', dirname + '/program.c']) 13 | proc = run(['./llvm2c', '-o', dirname + '/output.c', dirname + '/program.ll']) 14 | 15 | if proc.returncode != 0: 16 | print("Found bug!") 17 | break 18 | 19 | proc = run(['clang', dirname + '/output.c']) 20 | if proc.returncode != 0: 21 | print("Found bug!") 22 | break 23 | -------------------------------------------------------------------------------- /test/diffs: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # View diffs of input and corresponding output files 4 | diff="vim -O" 5 | 6 | for FOLDER in `ls inputs`; do 7 | for f in inputs/$FOLDER/*.c; do 8 | $diff $f expected/$FOLDER/`basename $f` 9 | 10 | echo "Press enter to continue" 11 | read 12 | done 13 | done 14 | -------------------------------------------------------------------------------- /test/expected/asm/basic_add.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long l; 11 | unsigned long r; 12 | unsigned int result; 13 | block0: 14 | var2 = 0; 15 | argc = var0; 16 | argv = var1; 17 | if (argc != 3) { 18 | var2 = -1; 19 | return var2; 20 | } else { 21 | l = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 22 | if (((int)(*p)) != 0) { 23 | var2 = -1; 24 | return var2; 25 | } else { 26 | r = strtol(*(((unsigned char**)(argv)) + 2), &p, 10); 27 | __asm__("mov %%rbx, %%rax; \n\tadd %%rcx, %%rax; \n\t" 28 | : "=a" (result) 29 | : "c" (r), "b" (l) 30 | : 31 | ); 32 | var2 = result; 33 | return var2; 34 | } 35 | } 36 | } 37 | 38 | -------------------------------------------------------------------------------- /test/expected/asm/mov.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(void); 3 | 4 | int main(void){ 5 | unsigned int var0; 6 | unsigned long result; 7 | block0: 8 | var0 = 0; 9 | __asm__("mov $42, %%rbx; \n\tmov %%rbx, %0; \n\t" 10 | : "=c" (result) 11 | : 12 | : "%rbx" 13 | ); 14 | return (unsigned int)result; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /test/expected/asm/multiple_asm.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long l; 11 | unsigned long r; 12 | unsigned int result; 13 | block0: 14 | var2 = 0; 15 | argc = var0; 16 | argv = var1; 17 | if (argc != 3) { 18 | var2 = -1; 19 | return var2; 20 | } else { 21 | l = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 22 | if (((int)(*p)) != 0) { 23 | var2 = -1; 24 | return var2; 25 | } else { 26 | r = strtol(*(((unsigned char**)(argv)) + 2), &p, 10); 27 | if (((int)(*p)) != 0) { 28 | var2 = -1; 29 | return var2; 30 | } else { 31 | __asm__("addl %%ebx, %%eax;" 32 | : "=a" (result) 33 | : "b" (r), "a" (l) 34 | : 35 | ); 36 | __asm__("subl %%ebx, %%eax;" 37 | : "=a" (result) 38 | : "b" (10), "a" (result) 39 | : 40 | ); 41 | __asm__("imull %%ebx, %%eax;" 42 | : "=a" (result) 43 | : "b" (r), "a" (result) 44 | : 45 | ); 46 | var2 = result; 47 | return var2; 48 | } 49 | } 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /test/expected/branching/if.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | block0: 12 | var2 = 0; 13 | argc = var0; 14 | argv = var1; 15 | if (argc != 2) { 16 | var2 = -1; 17 | return var2; 18 | } else { 19 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 20 | if (((int)(*p)) != 0) { 21 | var2 = -1; 22 | return var2; 23 | } else { 24 | if (((long)num) > ((long)10)) { 25 | var2 = 1; 26 | return var2; 27 | } else { 28 | var2 = -1; 29 | return var2; 30 | } 31 | } 32 | } 33 | } 34 | 35 | -------------------------------------------------------------------------------- /test/expected/branching/nested_if.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | block0: 12 | var2 = 0; 13 | argc = var0; 14 | argv = var1; 15 | if (argc != 2) { 16 | var2 = -1; 17 | return var2; 18 | } else { 19 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 20 | if (((int)(*p)) != 0) { 21 | var2 = -1; 22 | return var2; 23 | } else { 24 | if (((long)num) > ((long)10)) { 25 | if (((long)num) > ((long)5)) { 26 | var2 = 2; 27 | return var2; 28 | } else { 29 | var2 = 1; 30 | return var2; 31 | } 32 | } else { 33 | if (((long)num) < ((long)-5)) { 34 | var2 = -2; 35 | return var2; 36 | } else { 37 | var2 = -1; 38 | return var2; 39 | } 40 | } 41 | } 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /test/expected/globals/init_by_func.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct s_mystruct; 3 | 4 | // type definitions 5 | typedef unsigned int(* typeDef_0)(unsigned int); 6 | 7 | // struct definitions 8 | struct s_mystruct { 9 | typeDef_0 structVar0; 10 | }; 11 | 12 | // function declarations 13 | int main(int var0, char** var1); 14 | unsigned int square(unsigned int var0); 15 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 16 | 17 | // global variable definitions 18 | struct s_mystruct test = {square,}; 19 | 20 | int main(int var0, char** var1){ 21 | unsigned int var2; 22 | unsigned int argc; 23 | unsigned char** argv; 24 | unsigned char* p; 25 | unsigned long num; 26 | block0: 27 | var2 = 0; 28 | argc = var0; 29 | argv = var1; 30 | if (argc != 2) { 31 | var2 = -1; 32 | return var2; 33 | } else { 34 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 35 | if (((int)(*p)) != 0) { 36 | var2 = -1; 37 | return var2; 38 | } else { 39 | var2 = (test.structVar0)((unsigned int)num); 40 | return var2; 41 | } 42 | } 43 | } 44 | 45 | unsigned int square(unsigned int var0){ 46 | unsigned int x; 47 | block0: 48 | x = var0; 49 | return ((int)x) * ((int)x); 50 | } 51 | 52 | -------------------------------------------------------------------------------- /test/expected/globals/no_init.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct s_parent; 3 | struct s_some_struct; 4 | 5 | // struct definitions 6 | struct s_some_struct { 7 | unsigned long structVar3; 8 | unsigned long structVar4; 9 | }; 10 | struct s_parent { 11 | struct s_some_struct structVar0; 12 | unsigned long structVar1; 13 | unsigned long structVar2; 14 | }; 15 | 16 | // function declarations 17 | int main(int var0, char** var1); 18 | 19 | // global variable definitions 20 | struct s_parent p = {{0,0,},0,0,}; 21 | 22 | int main(int var0, char** var1){ 23 | unsigned int var2; 24 | unsigned int argc; 25 | unsigned char** argv; 26 | block0: 27 | var2 = 0; 28 | argc = var0; 29 | argv = var1; 30 | return (unsigned int)((p.structVar0).structVar4); 31 | } 32 | 33 | -------------------------------------------------------------------------------- /test/expected/globals/recursive_init.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct s_list; 3 | 4 | // struct definitions 5 | struct s_list { 6 | unsigned long structVar0; 7 | struct s_list* structVar1; 8 | }; 9 | 10 | // function declarations 11 | int main(int var0, char** var1); 12 | 13 | // global variable definitions 14 | struct s_list mylist = {0,&mylist,}; 15 | 16 | int main(int var0, char** var1){ 17 | unsigned int var2; 18 | unsigned int argc; 19 | unsigned char** argv; 20 | block0: 21 | var2 = 0; 22 | argc = var0; 23 | argv = var1; 24 | return (unsigned int)(mylist.structVar0); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /test/expected/loops/do_while.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | unsigned int i; 12 | block0: 13 | var2 = 0; 14 | argc = var0; 15 | argv = var1; 16 | if (argc != 2) { 17 | var2 = -1; 18 | return var2; 19 | } else { 20 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 21 | if (((int)(*p)) != 0) { 22 | var2 = -1; 23 | return var2; 24 | } else { 25 | i = 0; 26 | goto block5; 27 | } 28 | } 29 | block5: 30 | num = (((long)num) + ((long)i)); 31 | i = (((int)i) + ((int)1)); 32 | if (((int)i) < ((int)10)) { 33 | goto block5; 34 | } else { 35 | var2 = ((unsigned int)num); 36 | return var2; 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /test/expected/loops/for_loop.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | unsigned int test; 12 | unsigned int i; 13 | block0: 14 | var2 = 0; 15 | argc = var0; 16 | argv = var1; 17 | if (argc != 2) { 18 | var2 = -1; 19 | return var2; 20 | } else { 21 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 22 | if (((int)(*p)) != 0) { 23 | var2 = -1; 24 | return var2; 25 | } else { 26 | test = 0; 27 | i = 0; 28 | goto block5; 29 | } 30 | } 31 | block5: 32 | if (((long)i) < ((long)num)) { 33 | test = (((int)test) + ((int)i)); 34 | i = (((int)i) + ((int)1)); 35 | goto block5; 36 | } else { 37 | var2 = test; 38 | return var2; 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /test/expected/loops/inline_inc.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | 4 | int main(int var0, char** var1){ 5 | unsigned int var2; 6 | unsigned int argc; 7 | unsigned char** argv; 8 | unsigned int i; 9 | unsigned int var6; 10 | block0: 11 | var2 = 0; 12 | argc = var0; 13 | argv = var1; 14 | i = 0; 15 | goto block1; 16 | block1: 17 | var6 = (((int)i) + ((int)1)); 18 | i = var6; 19 | if (((int)var6) < ((int)10)) { 20 | goto block1; 21 | } else { 22 | return i; 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /test/expected/loops/nested_loops.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | unsigned int i; 12 | unsigned int j; 13 | block0: 14 | var2 = 0; 15 | argc = var0; 16 | argv = var1; 17 | if (argc != 2) { 18 | var2 = -1; 19 | return var2; 20 | } else { 21 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 22 | if (((int)(*p)) != 0) { 23 | var2 = -1; 24 | return var2; 25 | } else { 26 | i = 0; 27 | goto block5; 28 | } 29 | } 30 | block5: 31 | if (((int)i) < ((int)10)) { 32 | j = 5; 33 | goto block7; 34 | } else { 35 | var2 = ((unsigned int)num); 36 | return var2; 37 | } 38 | block7: 39 | if (((int)j) < ((int)(i + 10))) { 40 | num = (((long)(((long)num) + ((long)j))) - ((long)i)); 41 | j = (((int)j) + ((int)1)); 42 | goto block7; 43 | } else { 44 | i = (((int)i) + ((int)1)); 45 | goto block5; 46 | } 47 | } 48 | 49 | -------------------------------------------------------------------------------- /test/expected/loops/while.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | unsigned int test; 12 | block0: 13 | var2 = 0; 14 | argc = var0; 15 | argv = var1; 16 | if (argc != 2) { 17 | var2 = -1; 18 | return var2; 19 | } else { 20 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 21 | if (((int)(*p)) != 0) { 22 | var2 = -1; 23 | return var2; 24 | } else { 25 | test = 0; 26 | goto block5; 27 | } 28 | } 29 | block5: 30 | if (((int)test) < ((int)10)) { 31 | num = (((long)num) - ((long)test)); 32 | test = (((int)test) + ((int)1)); 33 | goto block5; 34 | } else { 35 | var2 = ((unsigned int)num); 36 | return var2; 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /test/expected/main/main_int.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned int printf(unsigned char* var0, ...); 4 | 5 | // global variable definitions 6 | unsigned char _str[14] = {72,101,108,108,111,32,119,111,114,108,100,33,10,0,}; 7 | 8 | int main(int var0, char** var1){ 9 | unsigned int var2; 10 | unsigned int argc; 11 | unsigned char** argv; 12 | block0: 13 | var2 = 0; 14 | argc = var0; 15 | argv = var1; 16 | printf(&(_str[0])); 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /test/expected/main/main_void.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | void main(void); 3 | extern unsigned int printf(unsigned char* var0, ...); 4 | 5 | // global variable definitions 6 | unsigned char _str[15] = {72,101,108,108,111,44,32,119,111,114,108,100,33,10,0,}; 7 | 8 | void main(void){ 9 | block0: 10 | printf(&(_str[0])); 11 | return; 12 | } 13 | 14 | -------------------------------------------------------------------------------- /test/expected/math/add_sub_div_mul.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long l; 11 | unsigned long r; 12 | block0: 13 | var2 = 0; 14 | argc = var0; 15 | argv = var1; 16 | if (argc != 3) { 17 | var2 = -1; 18 | return var2; 19 | } else { 20 | l = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 21 | if (((int)(*p)) != 0) { 22 | var2 = -1; 23 | return var2; 24 | } else { 25 | r = strtol(*(((unsigned char**)(argv)) + 2), &p, 10); 26 | if (((int)(*p)) != 0) { 27 | var2 = -1; 28 | return var2; 29 | } else { 30 | if (l != 0) { 31 | var2 = ((unsigned int)(((long)(((long)(((long)l) * ((long)r))) - ((long)(((long)l) + ((long)r))))) / ((long)l))); 32 | return var2; 33 | } else { 34 | var2 = ((unsigned int)(((long)(((long)(((long)l) * ((long)r))) - ((long)(((long)l) + ((long)r))))) / ((long)r))); 35 | return var2; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /test/expected/math/and_xor.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | unsigned int i; 12 | block0: 13 | var2 = 0; 14 | argc = var0; 15 | argv = var1; 16 | if (argc != 2) { 17 | var2 = -1; 18 | return var2; 19 | } else { 20 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 21 | if (((int)(*p)) != 0) { 22 | var2 = -1; 23 | return var2; 24 | } else { 25 | i = ((unsigned int)num); 26 | i = (i | 123); 27 | i = (i & 111); 28 | var2 = i; 29 | return var2; 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /test/expected/math/digit_sum.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | unsigned int digitSum(unsigned long var0); 3 | int main(int var0, char** var1); 4 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 5 | 6 | unsigned int digitSum(unsigned long var0){ 7 | unsigned long num; 8 | unsigned long l; 9 | unsigned int rem; 10 | unsigned int sum; 11 | block0: 12 | num = var0; 13 | l = num; 14 | rem = 0; 15 | sum = 0; 16 | goto block1; 17 | block1: 18 | if (l != 0) { 19 | rem = ((unsigned int)(((long)l) % ((long)10))); 20 | sum = (((int)sum) + ((int)rem)); 21 | l = (((long)l) / ((long)10)); 22 | goto block1; 23 | } else { 24 | return sum; 25 | } 26 | } 27 | 28 | int main(int var0, char** var1){ 29 | unsigned int var2; 30 | unsigned int argc; 31 | unsigned char** argv; 32 | unsigned char* p; 33 | unsigned long num; 34 | block0: 35 | var2 = 0; 36 | argc = var0; 37 | argv = var1; 38 | if (argc != 2) { 39 | var2 = -1; 40 | return var2; 41 | } else { 42 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 43 | if (((int)(*p)) != 0) { 44 | var2 = -1; 45 | return var2; 46 | } else { 47 | var2 = digitSum(num); 48 | return var2; 49 | } 50 | } 51 | } 52 | 53 | -------------------------------------------------------------------------------- /test/expected/math/fact.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | unsigned long fact(unsigned long var0); 3 | int main(int var0, char** var1); 4 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 5 | 6 | unsigned long fact(unsigned long var0){ 7 | unsigned long num; 8 | unsigned long result; 9 | unsigned long l; 10 | block0: 11 | num = var0; 12 | result = 1; 13 | l = 1; 14 | goto block1; 15 | block1: 16 | if (((long)l) <= ((long)num)) { 17 | result = (result * l); 18 | l = (((long)l) + ((long)1)); 19 | goto block1; 20 | } else { 21 | return result; 22 | } 23 | } 24 | 25 | int main(int var0, char** var1){ 26 | unsigned int var2; 27 | unsigned int argc; 28 | unsigned char** argv; 29 | unsigned char* p; 30 | unsigned long num; 31 | block0: 32 | var2 = 0; 33 | argc = var0; 34 | argv = var1; 35 | if (argc != 2) { 36 | var2 = -1; 37 | return var2; 38 | } else { 39 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 40 | if (((int)(*p)) != 0) { 41 | var2 = -1; 42 | return var2; 43 | } else { 44 | var2 = ((unsigned int)fact(num)); 45 | return var2; 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /test/expected/math/fact_rec.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | unsigned long fact(unsigned long var0); 3 | int main(int var0, char** var1); 4 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 5 | 6 | unsigned long fact(unsigned long var0){ 7 | unsigned long var1; 8 | unsigned long num; 9 | unsigned long var3; 10 | block0: 11 | num = var0; 12 | if (((long)num) > ((long)0)) { 13 | var3 = num; 14 | var1 = (var3 * fact(((long)num) - ((long)1))); 15 | return var1; 16 | } else { 17 | var1 = 1; 18 | return var1; 19 | } 20 | } 21 | 22 | int main(int var0, char** var1){ 23 | unsigned int var2; 24 | unsigned int argc; 25 | unsigned char** argv; 26 | unsigned char* p; 27 | unsigned long num; 28 | block0: 29 | var2 = 0; 30 | argc = var0; 31 | argv = var1; 32 | if (argc != 2) { 33 | var2 = -1; 34 | return var2; 35 | } else { 36 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 37 | if (((int)(*p)) != 0) { 38 | var2 = -1; 39 | return var2; 40 | } else { 41 | var2 = ((unsigned int)fact(num)); 42 | return var2; 43 | } 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /test/expected/math/isPrime.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | unsigned int isPrime(unsigned long var0); 3 | int main(int var0, char** var1); 4 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 5 | 6 | unsigned int isPrime(unsigned long var0){ 7 | unsigned int var1; 8 | unsigned long num; 9 | unsigned int i; 10 | block0: 11 | num = var0; 12 | if (((long)num) < ((long)2)) { 13 | var1 = 0; 14 | return var1; 15 | } else { 16 | i = 2; 17 | goto block3; 18 | } 19 | block3: 20 | if (((long)i) < ((long)(num / 2))) { 21 | if ((num % ((long)i)) == 0) { 22 | var1 = 0; 23 | return var1; 24 | } else { 25 | i = (((int)i) + ((int)1)); 26 | goto block3; 27 | } 28 | } else { 29 | var1 = 1; 30 | return var1; 31 | } 32 | } 33 | 34 | int main(int var0, char** var1){ 35 | unsigned int var2; 36 | unsigned int argc; 37 | unsigned char** argv; 38 | unsigned char* p; 39 | unsigned long num; 40 | block0: 41 | var2 = 0; 42 | argc = var0; 43 | argv = var1; 44 | if (argc != 2) { 45 | var2 = -1; 46 | return var2; 47 | } else { 48 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 49 | if (((int)(*p)) != 0) { 50 | var2 = -1; 51 | return var2; 52 | } else { 53 | var2 = isPrime(num); 54 | return var2; 55 | } 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /test/expected/math/mod.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long l; 11 | unsigned long r; 12 | block0: 13 | var2 = 0; 14 | argc = var0; 15 | argv = var1; 16 | if (argc != 3) { 17 | var2 = -1; 18 | return var2; 19 | } else { 20 | l = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 21 | if (((int)(*p)) != 0) { 22 | var2 = -1; 23 | return var2; 24 | } else { 25 | r = strtol(*(((unsigned char**)(argv)) + 2), &p, 10); 26 | if (((int)(*p)) != 0) { 27 | var2 = -1; 28 | return var2; 29 | } else { 30 | if (l != 0) { 31 | var2 = ((unsigned int)(((long)r) % ((long)l))); 32 | return var2; 33 | } else { 34 | var2 = ((unsigned int)(((long)l) % ((long)r))); 35 | return var2; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /test/expected/math/pow_gt.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long l; 11 | unsigned long r; 12 | block0: 13 | var2 = 0; 14 | argc = var0; 15 | argv = var1; 16 | if (argc != 3) { 17 | var2 = -1; 18 | return var2; 19 | } else { 20 | l = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 21 | if (((int)(*p)) != 0) { 22 | var2 = -1; 23 | return var2; 24 | } else { 25 | r = strtol(*(((unsigned char**)(argv)) + 2), &p, 10); 26 | if (((int)(*p)) != 0) { 27 | var2 = -1; 28 | return var2; 29 | } else { 30 | if (((long)(l * l)) > ((long)(r * r))) { 31 | var2 = ((unsigned int)l); 32 | return var2; 33 | } else { 34 | var2 = ((unsigned int)r); 35 | return var2; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /test/expected/math/shifts.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | unsigned int i; 12 | block0: 13 | var2 = 0; 14 | argc = var0; 15 | argv = var1; 16 | if (argc != 2) { 17 | var2 = -1; 18 | return var2; 19 | } else { 20 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 21 | if (((int)(*p)) != 0) { 22 | var2 = -1; 23 | return var2; 24 | } else { 25 | i = ((unsigned int)num); 26 | i = (i >> 5); 27 | i = (i << 2); 28 | var2 = i; 29 | return var2; 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /test/expected/phi/phi1.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned char* p; 7 | unsigned int var3_phi; 8 | block0: 9 | switch ((unsigned int)strtol(*(((unsigned char**)(var1)) + 1), &p, 10)) { 10 | case 1: 11 | var3_phi = 43; 12 | return var3_phi; 13 | case 2: 14 | var3_phi = 42; 15 | return var3_phi; 16 | case 3: 17 | var3_phi = 44; 18 | return var3_phi; 19 | case 4: 20 | var3_phi = 30; 21 | return var3_phi; 22 | case 5: 23 | var3_phi = 21; 24 | return var3_phi; 25 | case 6: 26 | var3_phi = 40; 27 | return var3_phi; 28 | case 7: 29 | var3_phi = 0; 30 | return var3_phi; 31 | case 8: 32 | var3_phi = 70; 33 | return var3_phi; 34 | case 9: 35 | var3_phi = 11; 36 | return var3_phi; 37 | case 10: 38 | var3_phi = 1; 39 | return var3_phi; 40 | default: 41 | return var3_phi; 42 | } 43 | } 44 | 45 | -------------------------------------------------------------------------------- /test/expected/pointer/array_of_ptr.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | unsigned long* arr[5]; 12 | block0: 13 | var2 = 0; 14 | argc = var0; 15 | argv = var1; 16 | if (argc != 2) { 17 | var2 = -1; 18 | return var2; 19 | } else { 20 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 21 | if (((int)(*p)) != 0) { 22 | var2 = -1; 23 | return var2; 24 | } else { 25 | (arr[2]) = (&num); 26 | var2 = ((unsigned int)(*(arr[2]))); 27 | return var2; 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /test/expected/pointer/func_ptr.c: -------------------------------------------------------------------------------- 1 | // type definitions 2 | typedef unsigned long(* typeDef_0)(unsigned long); 3 | 4 | // function declarations 5 | int main(int var0, char** var1); 6 | unsigned long square(unsigned long var0); 7 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 8 | 9 | int main(int var0, char** var1){ 10 | unsigned int var2; 11 | unsigned int argc; 12 | unsigned char** argv; 13 | unsigned char* p; 14 | unsigned long num; 15 | typeDef_0 ptr; 16 | block0: 17 | var2 = 0; 18 | argc = var0; 19 | argv = var1; 20 | if (argc != 2) { 21 | var2 = -1; 22 | return var2; 23 | } else { 24 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 25 | if (((int)(*p)) != 0) { 26 | var2 = -1; 27 | return var2; 28 | } else { 29 | ptr = square; 30 | var2 = ((unsigned int)ptr(num)); 31 | return var2; 32 | } 33 | } 34 | } 35 | 36 | unsigned long square(unsigned long var0){ 37 | unsigned long l; 38 | block0: 39 | l = var0; 40 | return ((long)l) * ((long)l); 41 | } 42 | 43 | -------------------------------------------------------------------------------- /test/expected/pointer/ref_deref.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | unsigned long* ptr; 12 | block0: 13 | var2 = 0; 14 | argc = var0; 15 | argv = var1; 16 | if (argc != 2) { 17 | var2 = -1; 18 | return var2; 19 | } else { 20 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 21 | if (((int)(*p)) != 0) { 22 | var2 = -1; 23 | return var2; 24 | } else { 25 | ptr = (&num); 26 | var2 = ((unsigned int)(*ptr)); 27 | return var2; 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /test/expected/pointer/ret_array_ptr.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | union u1; 3 | 4 | // union definitions 5 | union u1 { 6 | unsigned char* ty0; 7 | unsigned char (*ty1)[5]; 8 | }; 9 | 10 | // function declarations 11 | unsigned char (*get_me(void))[5]; 12 | int main(int var0, char** var1); 13 | extern unsigned char* malloc(unsigned long var0); 14 | 15 | unsigned char (*get_me(void))[5]{ 16 | unsigned char* me; 17 | union u1 var1; 18 | block0: 19 | me = malloc(5); 20 | (var1.ty0) = me; 21 | return var1.ty1; 22 | } 23 | 24 | int main(int var0, char** var1){ 25 | unsigned int var2; 26 | unsigned int argc; 27 | unsigned char** argv; 28 | unsigned char* s; 29 | union u1 var6; 30 | block0: 31 | var2 = 0; 32 | argc = var0; 33 | argv = var1; 34 | (var6.ty1) = get_me(); 35 | s = (var6.ty0); 36 | return (unsigned int)s; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /test/expected/standard_lib/math.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(void); 3 | extern unsigned int printf(unsigned char* var0, ...); 4 | 5 | // global variable definitions 6 | unsigned char _str[7] = {37,46,49,108,102,10,0,}; 7 | 8 | int main(void){ 9 | unsigned int var0; 10 | float f; 11 | block0: 12 | var0 = 0; 13 | f = 1.23E+2; 14 | f = ((float)log10((double)f)); 15 | f = ((float)pow((double)f, 2.0E+0)); 16 | printf(&(_str[0]), floor((double)f)); 17 | return 0; 18 | } 19 | 20 | -------------------------------------------------------------------------------- /test/expected/standard_lib/stdlib.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | extern void free(unsigned char* var0); 3 | int main(void); 4 | extern unsigned char* malloc(unsigned long var0); 5 | extern unsigned int printf(unsigned char* var0, ...); 6 | extern unsigned char* realloc(unsigned char* var0, unsigned long var1); 7 | extern unsigned char* strcat(unsigned char* var0, unsigned char* var1); 8 | extern unsigned char* strcpy(unsigned char* var0, unsigned char* var1); 9 | 10 | // global variable definitions 11 | unsigned char _str[11] = {109,97,108,108,111,99,116,101,115,116,0,}; 12 | unsigned char _str_1[4] = {37,115,10,0,}; 13 | unsigned char _str_2[13] = {32,114,101,97,108,108,111,99,116,101,115,116,0,}; 14 | unsigned char _str_3[3] = {37,115,0,}; 15 | 16 | int main(void){ 17 | unsigned int var0; 18 | unsigned char* str; 19 | block0: 20 | var0 = 0; 21 | str = malloc(20); 22 | strcpy(str, &(_str[0])); 23 | printf(&(_str_1[0]), str); 24 | str = realloc(str, 40); 25 | strcat(str, &(_str_2[0])); 26 | printf(&(_str_3[0]), str); 27 | free(str); 28 | return 0; 29 | } 30 | 31 | -------------------------------------------------------------------------------- /test/expected/standard_lib/string.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | union u1; 3 | 4 | // union definitions 5 | union u1 { 6 | unsigned char (*ty0)[20]; 7 | unsigned char* ty1; 8 | }; 9 | 10 | // function declarations 11 | int main(void); 12 | extern unsigned int printf(unsigned char* var0, ...); 13 | extern unsigned long strlen(unsigned char* var0); 14 | 15 | // global variable definitions 16 | unsigned char __const_main_test1[20] = {109,101,109,99,112,121,116,101,115,116,0,0,0,0,0,0,0,0,0,0,}; 17 | unsigned char _str[4] = {37,115,10,0,}; 18 | 19 | int main(void){ 20 | unsigned int var0; 21 | unsigned char test1[20]; 22 | unsigned char test2[20]; 23 | union u1 var3; 24 | unsigned char* var4; 25 | unsigned char* var5; 26 | block0: 27 | var0 = 0; 28 | (var3.ty0) = (&test1); 29 | memcpy(var3.ty1, &(__const_main_test1[0]), 20); 30 | var4 = (&(test2[0])); 31 | var5 = (&(test1[0])); 32 | memcpy(var4, var5, strlen(&(test1[0])) + 1); 33 | printf(&(_str[0]), &(test2[0])); 34 | return 0; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /test/expected/statements/select.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | unsigned int var7; 12 | unsigned long var8; 13 | block0: 14 | var2 = 0; 15 | argc = var0; 16 | argv = var1; 17 | if (argc != 2) { 18 | var2 = -1; 19 | return var2; 20 | } else { 21 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 22 | if (((int)(*p)) != 0) { 23 | var2 = -1; 24 | return var2; 25 | } else { 26 | var7 = (((long)num) > ((long)0)); 27 | var8 = ((unsigned long)var7); 28 | var2 = (var7 ? 1 : -1); 29 | return var2; 30 | } 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /test/expected/statements/switch.c: -------------------------------------------------------------------------------- 1 | // function declarations 2 | int main(int var0, char** var1); 3 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 4 | 5 | int main(int var0, char** var1){ 6 | unsigned int var2; 7 | unsigned int argc; 8 | unsigned char** argv; 9 | unsigned char* p; 10 | unsigned long num; 11 | block0: 12 | var2 = 0; 13 | argc = var0; 14 | argv = var1; 15 | if (argc != 2) { 16 | var2 = -1; 17 | return var2; 18 | } else { 19 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 20 | if (((int)(*p)) != 0) { 21 | var2 = -1; 22 | return var2; 23 | } else { 24 | switch (num) { 25 | case -5: 26 | var2 = 10; 27 | return var2; 28 | case 0: 29 | var2 = 1; 30 | return var2; 31 | case 2: 32 | var2 = -1; 33 | return var2; 34 | default: 35 | var2 = 123; 36 | return var2; 37 | } 38 | } 39 | } 40 | } 41 | 42 | -------------------------------------------------------------------------------- /test/expected/struct/array_of_structs.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct s_test; 3 | 4 | // struct definitions 5 | struct s_test { 6 | unsigned int structVar0; 7 | }; 8 | 9 | // function declarations 10 | int main(int var0, char** var1); 11 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 12 | 13 | int main(int var0, char** var1){ 14 | unsigned int var2; 15 | unsigned int argc; 16 | unsigned char** argv; 17 | unsigned char* p; 18 | unsigned long num; 19 | struct s_test arr[5]; 20 | unsigned int i; 21 | unsigned int sum; 22 | unsigned int i2; 23 | block0: 24 | var2 = 0; 25 | argc = var0; 26 | argv = var1; 27 | if (argc != 2) { 28 | var2 = -1; 29 | return var2; 30 | } else { 31 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 32 | if (((int)(*p)) != 0) { 33 | var2 = -1; 34 | return var2; 35 | } else { 36 | i = 0; 37 | goto block5; 38 | } 39 | } 40 | block5: 41 | if (((int)i) < ((int)5)) { 42 | ((arr[(long)i]).structVar0) = ((unsigned int)(((long)num) + ((long)i))); 43 | i = (((int)i) + ((int)1)); 44 | goto block5; 45 | } else { 46 | sum = 0; 47 | i2 = 0; 48 | goto block9; 49 | } 50 | block9: 51 | if (((int)i2) < ((int)5)) { 52 | sum = (((int)sum) + ((int)((arr[(long)i2]).structVar0))); 53 | i2 = (((int)i2) + ((int)1)); 54 | goto block9; 55 | } else { 56 | var2 = sum; 57 | return var2; 58 | } 59 | } 60 | 61 | -------------------------------------------------------------------------------- /test/expected/struct/basic_struct.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct s_t; 3 | 4 | // struct definitions 5 | struct s_t { 6 | unsigned int structVar0; 7 | }; 8 | 9 | // function declarations 10 | int main(int var0, char** var1); 11 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 12 | 13 | int main(int var0, char** var1){ 14 | unsigned int var2; 15 | unsigned int argc; 16 | unsigned char** argv; 17 | unsigned char* p; 18 | unsigned long num; 19 | struct s_t test; 20 | block0: 21 | var2 = 0; 22 | argc = var0; 23 | argv = var1; 24 | if (argc != 2) { 25 | var2 = -1; 26 | return var2; 27 | } else { 28 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 29 | if (((int)(*p)) != 0) { 30 | var2 = -1; 31 | return var2; 32 | } else { 33 | (test.structVar0) = ((unsigned int)num); 34 | var2 = (test.structVar0); 35 | return var2; 36 | } 37 | } 38 | } 39 | 40 | -------------------------------------------------------------------------------- /test/expected/struct/return_struct.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct s_mystruct; 3 | 4 | // struct definitions 5 | struct s_mystruct { 6 | unsigned int structVar0; 7 | unsigned int structVar1; 8 | unsigned int structVar2; 9 | }; 10 | 11 | // function declarations 12 | struct s_mystruct* get_mystruct(void); 13 | int main(int var0, char** var1); 14 | 15 | // global variable definitions 16 | struct s_mystruct i = {0,0,0,}; 17 | 18 | struct s_mystruct* get_mystruct(void){ 19 | block0: 20 | return &i; 21 | } 22 | 23 | int main(int var0, char** var1){ 24 | unsigned int var2; 25 | unsigned int argc; 26 | unsigned char** argv; 27 | struct s_mystruct* a; 28 | block0: 29 | var2 = 0; 30 | argc = var0; 31 | argv = var1; 32 | a = get_mystruct(); 33 | return 0; 34 | } 35 | 36 | -------------------------------------------------------------------------------- /test/expected/struct/struct_assignment.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct s_mystruct; 3 | union u1; 4 | 5 | // struct definitions 6 | struct s_mystruct { 7 | unsigned int structVar0; 8 | unsigned char structVar1; 9 | }; 10 | 11 | // union definitions 12 | union u1 { 13 | unsigned char* ty0; 14 | unsigned long* ty1; 15 | struct s_mystruct* ty2; 16 | }; 17 | 18 | // function declarations 19 | unsigned long get_struct(void); 20 | int main(int var0, char** var1); 21 | 22 | // global variable definitions 23 | struct s_mystruct __const_get_struct_result = {0,97,}; 24 | static unsigned int counter = 0; 25 | 26 | unsigned long get_struct(void){ 27 | struct s_mystruct result; 28 | union u1 var1; 29 | union u1 var2; 30 | block0: 31 | (var1.ty2) = (&result); 32 | result = __const_get_struct_result; 33 | counter = (((int)counter) + ((int)1)); 34 | (var2.ty2) = (&result); 35 | return *(var2.ty1); 36 | } 37 | 38 | int main(int var0, char** var1){ 39 | unsigned int var2; 40 | unsigned int argc; 41 | unsigned char** argv; 42 | struct s_mystruct a; 43 | union u1 var6; 44 | block0: 45 | var2 = 0; 46 | argc = var0; 47 | argv = var1; 48 | (var6.ty2) = (&a); 49 | (*(var6.ty1)) = get_struct(); 50 | return ((int)counter) + ((int)(a.structVar1)); 51 | } 52 | 53 | -------------------------------------------------------------------------------- /test/expected/struct/struct_with_ptrarray.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct s_test; 3 | struct s_arrptr; 4 | union u1; 5 | 6 | // struct definitions 7 | struct s_test { 8 | unsigned int structVar0; 9 | }; 10 | struct s_arrptr { 11 | struct s_test (*structVar1)[1]; 12 | }; 13 | 14 | // union definitions 15 | union u1 { 16 | unsigned char* ty0; 17 | struct s_test* ty1; 18 | struct s_test (*ty2)[1]; 19 | }; 20 | 21 | // function declarations 22 | int main(int var0, char** var1); 23 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 24 | 25 | int main(int var0, char** var1){ 26 | unsigned int var2; 27 | unsigned int argc; 28 | unsigned char** argv; 29 | unsigned char* p; 30 | unsigned long num; 31 | struct s_test t; 32 | struct s_test arr[1]; 33 | struct s_arrptr aptr; 34 | union u1 var10; 35 | union u1 var11; 36 | union u1 var12; 37 | block0: 38 | var2 = 0; 39 | argc = var0; 40 | argv = var1; 41 | if (argc != 2) { 42 | var2 = -1; 43 | return var2; 44 | } else { 45 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 46 | if (((int)(*p)) != 0) { 47 | var2 = -1; 48 | return var2; 49 | } else { 50 | (t.structVar0) = ((unsigned int)num); 51 | (var10.ty1) = (&(arr[0])); 52 | (var11.ty1) = (&t); 53 | (arr[0]) = t; 54 | (var12.ty1) = (&(arr[0])); 55 | (aptr.structVar1) = (var12.ty2); 56 | var2 = (((*(aptr.structVar1))[0]).structVar0); 57 | return var2; 58 | } 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /test/expected/struct/struct_with_struct.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct s_two; 3 | struct s_one; 4 | 5 | // struct definitions 6 | struct s_one { 7 | unsigned int structVar1; 8 | }; 9 | struct s_two { 10 | struct s_one structVar0; 11 | }; 12 | 13 | // function declarations 14 | int main(int var0, char** var1); 15 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 16 | 17 | int main(int var0, char** var1){ 18 | unsigned int var2; 19 | unsigned int argc; 20 | unsigned char** argv; 21 | unsigned char* p; 22 | unsigned long num; 23 | struct s_two test; 24 | block0: 25 | var2 = 0; 26 | argc = var0; 27 | argv = var1; 28 | if (argc != 2) { 29 | var2 = -1; 30 | return var2; 31 | } else { 32 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 33 | if (((int)(*p)) != 0) { 34 | var2 = -1; 35 | return var2; 36 | } else { 37 | ((test.structVar0).structVar1) = ((unsigned int)num); 38 | var2 = ((test.structVar0).structVar1); 39 | return var2; 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /test/expected/struct/struct_with_structptr.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct s_test; 3 | struct s_sptr; 4 | 5 | // struct definitions 6 | struct s_test { 7 | unsigned int structVar0; 8 | }; 9 | struct s_sptr { 10 | struct s_test* structVar1; 11 | }; 12 | 13 | // function declarations 14 | int main(int var0, char** var1); 15 | extern unsigned long strtol(unsigned char* var0, unsigned char** var1, unsigned int var2); 16 | 17 | int main(int var0, char** var1){ 18 | unsigned int var2; 19 | unsigned int argc; 20 | unsigned char** argv; 21 | unsigned char* p; 22 | unsigned long num; 23 | struct s_test t; 24 | struct s_sptr s; 25 | block0: 26 | var2 = 0; 27 | argc = var0; 28 | argv = var1; 29 | if (argc != 2) { 30 | var2 = -1; 31 | return var2; 32 | } else { 33 | num = strtol(*(((unsigned char**)(argv)) + 1), &p, 10); 34 | if (((int)(*p)) != 0) { 35 | var2 = -1; 36 | return var2; 37 | } else { 38 | (t.structVar0) = ((unsigned int)num); 39 | (s.structVar1) = (&t); 40 | var2 = ((s.structVar1)->structVar0); 41 | return var2; 42 | } 43 | } 44 | } 45 | 46 | -------------------------------------------------------------------------------- /test/expected/union/float_and_unsigned.c: -------------------------------------------------------------------------------- 1 | // struct declarations 2 | struct u_float_shape; 3 | union u1; 4 | 5 | // struct definitions 6 | struct u_float_shape { 7 | float structVar0; 8 | }; 9 | 10 | // union definitions 11 | union u1 { 12 | float* ty0; 13 | struct u_float_shape* ty1; 14 | unsigned int* ty2; 15 | }; 16 | 17 | // function declarations 18 | int main(int var0, char** var1); 19 | extern unsigned int printf(unsigned char* var0, ...); 20 | 21 | // global variable definitions 22 | unsigned char _str[4] = {37,117,10,0,}; 23 | 24 | int main(int var0, char** var1){ 25 | unsigned int var2; 26 | unsigned int argc; 27 | unsigned char** argv; 28 | float a; 29 | struct u_float_shape fs; 30 | union u1 var7; 31 | union u1 var8; 32 | union u1 var9; 33 | block0: 34 | var2 = 0; 35 | argc = var0; 36 | argv = var1; 37 | a = ((float)argc); 38 | (var7.ty1) = (&fs); 39 | (*(var7.ty0)) = a; 40 | (var8.ty1) = (&fs); 41 | printf(&(_str[0]), *(var8.ty2)); 42 | (var9.ty1) = (&fs); 43 | return *(var9.ty2); 44 | } 45 | 46 | -------------------------------------------------------------------------------- /test/inputs/asm/basic_add.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char** argv) { 5 | if (argc != 3) { 6 | return -1; 7 | } 8 | 9 | char *p; 10 | long l = strtol(argv[1], &p, 10); 11 | 12 | if (*p != '\0') { 13 | return -1; 14 | } 15 | 16 | long r = strtol(argv[2], &p, 10); 17 | 18 | int result; 19 | 20 | __asm__ __volatile__( 21 | "mov %%rbx, %%rax; \n\t" 22 | "add %%rcx, %%rax; \n\t" 23 | : "=a" (result) 24 | : "b" (l), "c" (r) 25 | : 26 | ); 27 | 28 | return result; 29 | } 30 | -------------------------------------------------------------------------------- /test/inputs/asm/mov.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main() { 4 | unsigned long long result; 5 | __asm__ __volatile__( 6 | "mov $42, %%rbx; \n\t" 7 | "mov %%rbx, %0; \n\t" 8 | : "=c" (result) 9 | : 10 | : "%rbx" 11 | ); 12 | 13 | return result; 14 | } -------------------------------------------------------------------------------- /test/inputs/asm/multiple_asm.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main(int argc, char** argv) { 5 | if (argc != 3) { 6 | return -1; 7 | } 8 | 9 | char *p; 10 | long l = strtol(argv[1], &p, 10); 11 | 12 | if (*p != '\0') { 13 | return -1; 14 | } 15 | 16 | long r = strtol(argv[2], &p, 10); 17 | 18 | if (*p != '\0') { 19 | return -1; 20 | } 21 | 22 | int result; 23 | __asm__ ( "addl %%ebx, %%eax;" 24 | : "=a" (result) 25 | : "a" (l) , "b" (r) 26 | ); 27 | 28 | __asm__ ( "subl %%ebx, %%eax;" 29 | : "=a" (result) 30 | : "a" (result) , "b" (10) 31 | ); 32 | 33 | __asm__ ( "imull %%ebx, %%eax;" 34 | : "=a" (result) 35 | : "a" (result) , "b" (r) 36 | ); 37 | 38 | return result; 39 | } 40 | -------------------------------------------------------------------------------- /test/inputs/branching/if.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | if (num > 10) { 16 | return 1; 17 | } else { 18 | return -1; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /test/inputs/branching/nested_if.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | if (num > 10) { 16 | if (num > 5) { 17 | return 2; 18 | } else { 19 | return 1; 20 | } 21 | } else { 22 | if (num < -5) { 23 | return -2; 24 | } else { 25 | return -1; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /test/inputs/globals/init_by_func.c: -------------------------------------------------------------------------------- 1 | 2 | int square(int x) { 3 | return x * x; 4 | } 5 | 6 | struct mystruct { 7 | int (*myfunc)(int a); 8 | }; 9 | 10 | struct mystruct test = { square }; 11 | 12 | int main(int argc, char *argv[]) 13 | { 14 | if (argc != 2) { 15 | return -1; 16 | } 17 | 18 | char *p; 19 | long num = strtol(argv[1], &p, 10); 20 | 21 | if (*p != '\0') { 22 | return -1; 23 | } else { 24 | return test.myfunc(num); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/inputs/globals/no_init.c: -------------------------------------------------------------------------------- 1 | 2 | struct some_struct { 3 | long a; 4 | long b; 5 | }; 6 | 7 | struct parent { 8 | struct some_struct that; 9 | long c; 10 | long d; 11 | }; 12 | 13 | struct parent p; 14 | 15 | int main(int argc, char *argv[]) 16 | { 17 | return p.that.b; 18 | } 19 | -------------------------------------------------------------------------------- /test/inputs/globals/recursive_init.c: -------------------------------------------------------------------------------- 1 | 2 | typedef struct list { 3 | long value; 4 | struct list* next; 5 | } list_t; 6 | 7 | list_t mylist = { 0, &mylist }; 8 | 9 | int main(int argc, char *argv[]) 10 | { 11 | return mylist.value; 12 | } 13 | -------------------------------------------------------------------------------- /test/inputs/loops/do_while.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | int i = 0; 16 | 17 | do { 18 | num += i; 19 | i++; 20 | } while (i < 10); 21 | 22 | return num; 23 | } 24 | -------------------------------------------------------------------------------- /test/inputs/loops/for_loop.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | int test = 0; 16 | 17 | for (int i = 0; i < num; i++) { 18 | test += i; 19 | } 20 | 21 | return test; 22 | } 23 | -------------------------------------------------------------------------------- /test/inputs/loops/inline_inc.c: -------------------------------------------------------------------------------- 1 | int main(int argc, char *argv[]) 2 | { 3 | int i = 0; 4 | while (++i < 10) {} 5 | return i; 6 | } 7 | -------------------------------------------------------------------------------- /test/inputs/loops/nested_loops.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | int i = 0; 16 | 17 | while (i < 10) { 18 | for (int j = 5; j < i + 10; j++) { 19 | num = num + j - i; 20 | } 21 | i++; 22 | } 23 | 24 | return num; 25 | } 26 | -------------------------------------------------------------------------------- /test/inputs/loops/while.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | int test = 0; 16 | 17 | while (test < 10) { 18 | num -= test; 19 | test++; 20 | } 21 | 22 | return num; 23 | } 24 | -------------------------------------------------------------------------------- /test/inputs/main/main_int.c: -------------------------------------------------------------------------------- 1 | 2 | int main(int argc, char *argv[]) 3 | { 4 | printf("Hello world!\n"); 5 | return 0; 6 | } 7 | -------------------------------------------------------------------------------- /test/inputs/main/main_void.c: -------------------------------------------------------------------------------- 1 | 2 | void main() 3 | { 4 | printf("Hello, world!\n"); 5 | return; 6 | } 7 | -------------------------------------------------------------------------------- /test/inputs/math/add_sub_div_mul.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 3) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long l = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | long r = strtol(argv[2], &p, 10); 16 | 17 | if (*p != '\0') { 18 | return -1; 19 | } 20 | 21 | if (l != 0) { 22 | return (int)((l * r - (l + r)) / l); 23 | } 24 | 25 | return (int)((l * r - (l + r)) / r); 26 | } 27 | -------------------------------------------------------------------------------- /test/inputs/math/and_xor.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return - 1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } else { 14 | int i = num; 15 | i = i | 123; 16 | i = i & 111; 17 | return i; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/inputs/math/digit_sum.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int digitSum(long num) { 4 | long l = num; 5 | int rem = 0; 6 | int sum = 0; 7 | 8 | while (l != 0) { 9 | rem = l % 10; 10 | sum += rem; 11 | l = l / 10; 12 | } 13 | 14 | return sum; 15 | } 16 | 17 | int main(int argc, char** argv) { 18 | if (argc != 2) { 19 | return - 1; 20 | } 21 | 22 | char *p; 23 | long num = strtol(argv[1], &p, 10); 24 | 25 | if (*p != '\0') { 26 | return -1; 27 | } 28 | 29 | return digitSum(num); 30 | } 31 | -------------------------------------------------------------------------------- /test/inputs/math/fact.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned long long fact(long num) { 4 | unsigned long long result = 1; 5 | 6 | for (long l = 1; l <= num; l++) { 7 | result *= l; 8 | } 9 | 10 | return result; 11 | } 12 | 13 | int main(int argc, char** argv) { 14 | if (argc != 2) { 15 | return - 1; 16 | } 17 | 18 | char *p; 19 | long num = strtol(argv[1], &p, 10); 20 | 21 | if (*p != '\0') { 22 | return -1; 23 | } else { 24 | return fact(num); 25 | 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/inputs/math/fact_rec.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | unsigned long long fact(long num) { 4 | if (num > 0) { 5 | return num * fact(num - 1); 6 | } else { 7 | return 1; 8 | } 9 | } 10 | 11 | int main(int argc, char** argv) { 12 | if (argc != 2) { 13 | return - 1; 14 | } 15 | 16 | char *p; 17 | long num = strtol(argv[1], &p, 10); 18 | 19 | if (*p != '\0') { 20 | return -1; 21 | } else { 22 | return fact(num); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/inputs/math/isPrime.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int isPrime(long num) { 4 | if (num < 2) { 5 | return 0; 6 | } 7 | 8 | for (int i = 2; i < num / 2; i++) { 9 | if (num % i == 0) { 10 | return 0; 11 | } 12 | } 13 | 14 | return 1; 15 | } 16 | 17 | int main(int argc, char** argv) { 18 | if (argc != 2) { 19 | return - 1; 20 | } 21 | 22 | char *p; 23 | long num = strtol(argv[1], &p, 10); 24 | 25 | if (*p != '\0') { 26 | return -1; 27 | } 28 | 29 | return isPrime(num); 30 | } 31 | -------------------------------------------------------------------------------- /test/inputs/math/mod.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 3) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long l = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | long r = strtol(argv[2], &p, 10); 16 | 17 | if (*p != '\0') { 18 | return -1; 19 | } 20 | 21 | if (l != 0) { 22 | return r % l; 23 | } 24 | 25 | return l % r; 26 | } 27 | -------------------------------------------------------------------------------- /test/inputs/math/pow_gt.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 3) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long l = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | long r = strtol(argv[2], &p, 10); 16 | 17 | if (*p != '\0') { 18 | return -1; 19 | } 20 | 21 | if (l * l > r * r) { 22 | return l; 23 | } 24 | 25 | return r; 26 | } 27 | -------------------------------------------------------------------------------- /test/inputs/math/shifts.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return - 1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } else { 14 | int i = num; 15 | i = i >> 5; 16 | i = i << 2; 17 | return i; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /test/inputs/phi/phi1.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char *argv[]) 4 | { 5 | char *p; 6 | int v = strtol(argv[1], &p, 10); 7 | int g = 0; 8 | switch(v) { 9 | case 1: 10 | g = 43; 11 | break; 12 | case 2: 13 | g = 42; 14 | break; 15 | case 3: 16 | g = 44; 17 | break; 18 | case 4: 19 | g = 30; 20 | break; 21 | case 5: 22 | g = 21; 23 | break; 24 | case 6: 25 | g = 40; 26 | break; 27 | case 7: 28 | g = 0; 29 | break; 30 | case 8: 31 | g = 70; 32 | break; 33 | case 9: 34 | g = 11; 35 | break; 36 | case 10: 37 | g = 1; 38 | break; 39 | } 40 | return g; 41 | } 42 | -------------------------------------------------------------------------------- /test/inputs/pointer/array_of_ptr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | long* arr[5]; 16 | arr[2] = # 17 | 18 | return *arr[2]; 19 | } 20 | -------------------------------------------------------------------------------- /test/inputs/pointer/func_ptr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | long square(long l) { 4 | return l * l; 5 | } 6 | 7 | int main(int argc, char** argv) { 8 | if (argc != 2) { 9 | return -1; 10 | } 11 | 12 | char *p; 13 | long num = strtol(argv[1], &p, 10); 14 | 15 | if (*p != '\0') { 16 | return -1; 17 | } 18 | 19 | long (*ptr)(long) = □ 20 | return (*ptr)(num); 21 | } 22 | -------------------------------------------------------------------------------- /test/inputs/pointer/ref_deref.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | long* ptr = # 16 | 17 | return *ptr; 18 | } 19 | -------------------------------------------------------------------------------- /test/inputs/pointer/ret_array_ptr.c: -------------------------------------------------------------------------------- 1 | typedef char my_type[5]; 2 | 3 | my_type* get_me() { 4 | char *me = malloc(5); 5 | return me; 6 | } 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | char *s = { get_me() }; 11 | return s; 12 | } 13 | -------------------------------------------------------------------------------- /test/inputs/standard_lib/math.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int main () { 5 | float f = 123; 6 | f = log10(f); 7 | f = pow(f, 2); 8 | 9 | printf("%.1lf\n", floor(f)); 10 | 11 | return(0); 12 | } 13 | -------------------------------------------------------------------------------- /test/inputs/standard_lib/stdlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | int main () { 6 | char *str; 7 | 8 | str = (char *) malloc(20); 9 | strcpy(str, "malloctest"); 10 | printf("%s\n", str); 11 | str = (char *) realloc(str, 40); 12 | strcat(str, " realloctest"); 13 | printf("%s", str); 14 | 15 | free(str); 16 | 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /test/inputs/standard_lib/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main () { 4 | const char test1[20] = "memcpytest"; 5 | char test2[20]; 6 | memcpy(test2, test1, strlen(test1)+1); 7 | printf("%s\n", test2); 8 | 9 | return(0); 10 | } -------------------------------------------------------------------------------- /test/inputs/statements/select.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | return num > 0 ? 1 : -1; 16 | } 17 | -------------------------------------------------------------------------------- /test/inputs/statements/switch.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | if (argc != 2) { 5 | return -1; 6 | } 7 | 8 | char *p; 9 | long num = strtol(argv[1], &p, 10); 10 | 11 | if (*p != '\0') { 12 | return -1; 13 | } 14 | 15 | switch (num) { 16 | case 0: 17 | return 1; 18 | case -5: 19 | return 10; 20 | case 2: 21 | return -1; 22 | default: 23 | return 123; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /test/inputs/struct/array_of_structs.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct test { 4 | int i; 5 | }; 6 | 7 | int main(int argc, char** argv) { 8 | if (argc != 2) { 9 | return -1; 10 | } 11 | 12 | char *p; 13 | long num = strtol(argv[1], &p, 10); 14 | 15 | if (*p != '\0') { 16 | return -1; 17 | } 18 | 19 | struct test arr[5]; 20 | 21 | for (int i = 0; i < 5; i++) { 22 | arr[i].i = num + i; 23 | } 24 | 25 | int sum = 0; 26 | 27 | for (int i = 0; i < 5; i++) { 28 | sum += arr[i].i; 29 | } 30 | 31 | return sum; 32 | } 33 | -------------------------------------------------------------------------------- /test/inputs/struct/basic_struct.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct t { 4 | int i; 5 | }; 6 | 7 | int main(int argc, char** argv) { 8 | if (argc != 2) { 9 | return -1; 10 | } 11 | 12 | char *p; 13 | long num = strtol(argv[1], &p, 10); 14 | 15 | if (*p != '\0') { 16 | return -1; 17 | } 18 | 19 | struct t test = {num}; 20 | return test.i; 21 | } 22 | -------------------------------------------------------------------------------- /test/inputs/struct/return_struct.c: -------------------------------------------------------------------------------- 1 | struct mystruct { 2 | int a; 3 | int b; 4 | int c; 5 | }; 6 | 7 | struct mystruct i = {0,0,0}; 8 | 9 | struct mystruct* get_mystruct() { 10 | return &i; 11 | } 12 | 13 | int main(int argc, char *argv[]) 14 | { 15 | struct mystruct* a = get_mystruct(); 16 | return 0; 17 | } 18 | -------------------------------------------------------------------------------- /test/inputs/struct/struct_assignment.c: -------------------------------------------------------------------------------- 1 | static int counter = 0; 2 | 3 | struct mystruct { 4 | int a; 5 | char b; 6 | }; 7 | 8 | struct mystruct get_struct() { 9 | struct mystruct result = {0, 'a'}; 10 | ++counter; 11 | return result; 12 | } 13 | 14 | int main(int argc, char *argv[]) 15 | { 16 | struct mystruct a = get_struct(); 17 | return counter + a.b; 18 | } 19 | -------------------------------------------------------------------------------- /test/inputs/struct/struct_with_ptrarray.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct test { 4 | int i; 5 | }; 6 | 7 | struct arrptr { 8 | struct test (*ptr)[1]; 9 | }; 10 | 11 | int main(int argc, char** argv) { 12 | if (argc != 2) { 13 | return -1; 14 | } 15 | 16 | char *p; 17 | long num = strtol(argv[1], &p, 10); 18 | 19 | if (*p != '\0') { 20 | return -1; 21 | } 22 | 23 | struct test t = {num}; 24 | struct test arr[1] = {t}; 25 | struct arrptr aptr = {arr}; 26 | 27 | return (*aptr.ptr)[0].i; 28 | } 29 | -------------------------------------------------------------------------------- /test/inputs/struct/struct_with_struct.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct one { 4 | int i; 5 | }; 6 | 7 | struct two { 8 | struct one o; 9 | }; 10 | 11 | int main(int argc, char** argv) { 12 | if (argc != 2) { 13 | return -1; 14 | } 15 | 16 | char *p; 17 | long num = strtol(argv[1], &p, 10); 18 | 19 | if (*p != '\0') { 20 | return -1; 21 | } 22 | 23 | struct two test; 24 | test.o.i = num; 25 | 26 | return test.o.i; 27 | } 28 | -------------------------------------------------------------------------------- /test/inputs/struct/struct_with_structptr.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct test { 4 | int i; 5 | }; 6 | 7 | struct sptr { 8 | struct test* ptr; 9 | }; 10 | 11 | int main(int argc, char** argv) { 12 | if (argc != 2) { 13 | return -1; 14 | } 15 | 16 | char *p; 17 | long num = strtol(argv[1], &p, 10); 18 | 19 | if (*p != '\0') { 20 | return -1; 21 | } 22 | 23 | struct test t = {num}; 24 | struct sptr s = {&t}; 25 | 26 | return s.ptr->i; 27 | } 28 | -------------------------------------------------------------------------------- /test/inputs/union/float_and_unsigned.c: -------------------------------------------------------------------------------- 1 | 2 | typedef union { 3 | float f; 4 | unsigned w; 5 | } float_shape; 6 | 7 | 8 | int main(int argc, char *argv[]) 9 | { 10 | float a = argc; 11 | 12 | float_shape fs; 13 | fs.f = a; 14 | 15 | printf("%u\n", fs.w); 16 | 17 | return fs.w; 18 | } 19 | -------------------------------------------------------------------------------- /test/run.in: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ $# -ne 1 ]; then 4 | echo "Usage: $0 [test set]" 5 | exit 1 6 | fi 7 | 8 | LABEL="$1" 9 | FOLDER=$LABEL 10 | 11 | if ! [[ -e @LLVM2C@ ]]; then 12 | echo "llvm2c not found!" 13 | exit 1 14 | fi 15 | 16 | echo "Running $LABEL tests..." 17 | 18 | FAILED=0 19 | TEMPDIR=`mktemp -d` 20 | LDFLAGS="" 21 | 22 | if [[ "$LABEL" == "math" ]]; then 23 | LDFLAGS="$LDFLABS -lm" 24 | fi 25 | 26 | if [[ "$LABEL" == "standard_lib" ]]; then 27 | LDFLAGS="$LDFLABS -lm" 28 | fi 29 | 30 | 31 | for f in @CMAKE_CURRENT_SOURCE_DIR@/inputs/$FOLDER/*.c; do 32 | echo "Testing $f" 33 | @CLANG@ $LDFLAGS "$f" -o $TEMPDIR/orig 34 | @CLANG@ "$f" -g -emit-llvm -S -Xclang -disable-O0-optnone -o $TEMPDIR/temp.ll #2>/dev/null 35 | 36 | if [[ $LABEL = "phi" ]]; then 37 | @OPT@ -mem2reg $TEMPDIR/temp.ll -o $TEMPDIR/temp.ll 38 | fi 39 | 40 | @LLVM2C@ $TEMPDIR/temp.ll --o $TEMPDIR/temp.c # >> /dev/null 41 | 42 | if [[ $? != 0 ]]; then 43 | echo -e "\n\t[NOK] llvm2c failed to translate $f!" 44 | FAILED=$((FAILED+1)) 45 | else 46 | @CLANG@ $LDFLAGS $TEMPDIR/temp.c -o $TEMPDIR/new 47 | if [[ $? != 0 ]]; then 48 | echo -e "\n\t[NOK] Clang could not compile translated file $f!" 49 | FAILED=$((FAILED+1)) 50 | else 51 | for i in `seq -10 10`; do 52 | $TEMPDIR/orig $i 53 | ORIG=$? 54 | $TEMPDIR/new $i 55 | if [[ $ORIG != $? ]]; then 56 | echo -e "\t[NOK] Test $f failed with input $i!" 57 | FAILED=$((FAILED+1)) 58 | fi 59 | done 60 | 61 | if diff -y --suppress-common-lines @CMAKE_CURRENT_SOURCE_DIR@/expected/$FOLDER/$(basename $f) $TEMPDIR/temp.c; then 62 | echo -e "\n\t[OK ] Files are as expected" 63 | else 64 | echo -e "\n\t[NOK] Translated C file is different than expected" 65 | FAILED=$((FAILED+1)) 66 | fi 67 | fi 68 | fi 69 | rm -rf $TEMPDIR/* 70 | done 71 | 72 | rm -rf $TEMPDIR 73 | 74 | if [[ $FAILED -eq 0 ]]; then 75 | echo "All $LABEL tests passed!" 76 | else 77 | echo "$FAILED $LABEL tests failed!" 78 | fi 79 | 80 | exit $FAILED 81 | -------------------------------------------------------------------------------- /test/update-expected: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if ! [[ -e llvm2c ]]; then 4 | echo "llvm2c not found!" 5 | exit 1 6 | fi 7 | 8 | echo "Updating expected test results..." 9 | 10 | TEMPDIR=`mktemp -d` 11 | 12 | for FOLDER in `ls inputs`; do 13 | for f in inputs/$FOLDER/*.c; do 14 | [ -d expected/$FOLDER/ ] || mkdir expected/$FOLDER/ 15 | 16 | clang "$f" -o $TEMPDIR/orig 2>/dev/null 17 | clang "$f" -g -emit-llvm -S -Xclang -disable-O0-optnone -o $TEMPDIR/temp.ll #2>/dev/null 18 | if [[ $FOLDER = "phi" ]]; then 19 | opt -mem2reg $TEMPDIR/temp.ll -o $TEMPDIR/temp.ll 20 | fi 21 | 22 | if ! ./llvm2c ${TEMPDIR}/temp.ll --o expected/${FOLDER}/`basename $f`; then 23 | echo "Paused. Press enter to continue" 24 | echo "$TEMPDIR" 25 | read 26 | fi 27 | 28 | echo "Update $f" 29 | rm $TEMPDIR/* 30 | done 31 | done 32 | 33 | rm -rf $TEMPDIR 34 | -------------------------------------------------------------------------------- /type/TypeHandler.cpp: -------------------------------------------------------------------------------- 1 | #include "TypeHandler.h" 2 | 3 | #include "llvm/IR/DerivedTypes.h" 4 | 5 | #include "../core/Program.h" 6 | 7 | Type* TypeHandler::getType(const llvm::Type* type) { 8 | if (typeDefs.find(type) != typeDefs.end()) { 9 | return typeDefs[type].get(); 10 | } 11 | 12 | auto it = typeCache.find(type); 13 | if (it != typeCache.end()) { 14 | return it->second.get(); 15 | } 16 | 17 | if (type->isArrayTy()) { 18 | auto ty = std::make_unique(getType(type->getArrayElementType()), type->getArrayNumElements()); 19 | auto result = ty.get(); 20 | typeCache.insert(it, std::make_pair(type, std::move(ty))); 21 | return result; 22 | } 23 | 24 | if (type->isVoidTy()) { 25 | return voidType.get(); 26 | } 27 | 28 | if (type->isIntegerTy()) { 29 | std::unique_ptr ty; 30 | const auto intType = static_cast(type); 31 | if (intType->getBitWidth() == 1) { 32 | return uint.get(); 33 | } 34 | 35 | if (intType->getBitWidth() <= 8) { 36 | return uchar.get(); 37 | } 38 | 39 | if (intType->getBitWidth() <= 16) { 40 | return ushort.get(); 41 | } 42 | 43 | if (intType->getBitWidth() <= 32) { 44 | return uint.get(); 45 | } 46 | 47 | if (intType->getBitWidth() <= 64) { 48 | return ulong.get(); 49 | } 50 | 51 | return int128.get(); 52 | } 53 | 54 | if (type->isFloatTy()) { 55 | return floatType.get(); 56 | } 57 | 58 | if (type->isDoubleTy()) { 59 | return doubleType.get(); 60 | } 61 | 62 | if (type->isX86_FP80Ty()) { 63 | return longDoubleType.get(); 64 | } 65 | 66 | if (type->isPointerTy()) { 67 | const llvm::PointerType* PT = llvm::cast(type); 68 | 69 | if (const llvm::FunctionType* FT = llvm::dyn_cast_or_null(PT->getPointerElementType())) { 70 | std::vector params; 71 | if (FT->getNumParams() == 0) { 72 | params.push_back("void"); 73 | } else { 74 | std::string param; 75 | //parsing params to string 76 | for (unsigned i = 0; i < FT->getNumParams(); i++) { 77 | auto paramType = getType(FT->getParamType(i)); 78 | param = paramType->toString(); 79 | 80 | if (auto PT = llvm::dyn_cast_or_null(paramType)) { 81 | if (PT->isArrayPointer) { 82 | param += " ("; 83 | for (unsigned i = 0; i < PT->levels; i++) { 84 | param += "*"; 85 | } 86 | param += ")" + PT->sizes; 87 | } 88 | } 89 | 90 | if (auto AT = llvm::dyn_cast_or_null(paramType)) { 91 | param += AT->sizeToString(); 92 | } 93 | 94 | params.push_back(param); 95 | } 96 | 97 | if (FT->isVarArg()) { 98 | params.push_back("..."); 99 | } 100 | } 101 | 102 | std::string paramsToString = "("; 103 | bool first = true; 104 | for (const auto& param : params) { 105 | if (!first) { 106 | paramsToString += ", "; 107 | } 108 | first = false; 109 | 110 | paramsToString += param; 111 | } 112 | paramsToString += ")"; 113 | 114 | typeDefs[type] = std::make_unique(getType(FT->getReturnType())->toString() + "(*", getTypeDefName(), ")" + paramsToString); 115 | sortedTypeDefs.push_back(static_cast(typeDefs[type].get())); 116 | return typeDefs[type].get(); 117 | } 118 | 119 | auto* inner = getType(PT->getPointerElementType()); 120 | return makeCachedType(PT, inner); 121 | } 122 | 123 | if (type->isStructTy()) { 124 | const llvm::StructType* structType = llvm::cast(type); 125 | 126 | auto* strct = program->getStruct(structType); 127 | 128 | if (!strct) { 129 | if (structType->getStructName() == "") { 130 | program->createNewUnnamedStruct(structType); 131 | strct = program->getStruct(structType); 132 | } 133 | } 134 | 135 | return strct; 136 | 137 | } 138 | 139 | return nullptr; 140 | } 141 | 142 | Type* TypeHandler::getBinaryType(Type* left, Type* right) { 143 | if (left != nullptr) 144 | return left; 145 | 146 | return right; 147 | } 148 | 149 | std::string TypeHandler::getStructName(const std::string& structName) { 150 | std::string name = structName; 151 | std::replace(name.begin(), name.end(), '.', '_'); 152 | 153 | if (name.substr(0, 6).compare("struct") == 0) { 154 | name.erase(0, 7); 155 | name = "s_" + name; 156 | } else { 157 | //union 158 | name.erase(0, 6); 159 | name = "u_" + name; 160 | } 161 | 162 | if (name.compare("s___va_list_tag") == 0) { 163 | name = "__va_list_tag"; 164 | } 165 | 166 | 167 | return name; 168 | } 169 | 170 | Type* TypeHandler::pointerTo(Type* type) { 171 | auto it = pointerTypes.find(type); 172 | if (it != pointerTypes.end()) { 173 | return it->second.get(); 174 | } 175 | 176 | auto up = std::make_unique(type); 177 | Type* result = up.get(); 178 | pointerTypes.insert(it, std::make_pair(type, std::move(up))); 179 | return result; 180 | } 181 | 182 | IntegerType* TypeHandler::toggleSignedness(IntegerType* ty) { 183 | 184 | #define TYPES(unsignedType,signedType) \ 185 | do {\ 186 | if (ty == signedType.get()) return unsignedType.get();\ 187 | if (ty == unsignedType.get()) return signedType.get();\ 188 | } while(0); 189 | 190 | TYPES(uint, sint); 191 | TYPES(uchar, schar); 192 | TYPES(ushort, sshort); 193 | TYPES(ulong, slong); 194 | 195 | #undef TYPES 196 | return ty; 197 | } 198 | 199 | IntegerType* TypeHandler::setSigned(IntegerType* ty) { 200 | #define TYPES(unsignedType,signedType) \ 201 | do {\ 202 | if (ty == unsignedType.get()) return signedType.get();\ 203 | } while(0); 204 | 205 | TYPES(uint, sint); 206 | TYPES(uchar, schar); 207 | TYPES(ushort, sshort); 208 | TYPES(ulong, slong); 209 | 210 | #undef TYPES 211 | return ty; 212 | } 213 | 214 | IntegerType* TypeHandler::setUnsigned(IntegerType* ty) { 215 | #define TYPES(unsignedType,signedType) \ 216 | do {\ 217 | if (ty == signedType.get()) return unsignedType.get();\ 218 | } while(0); 219 | 220 | TYPES(uint, sint); 221 | TYPES(uchar, schar); 222 | TYPES(ushort, sshort); 223 | TYPES(ulong, slong); 224 | 225 | #undef TYPES 226 | return ty; 227 | } 228 | -------------------------------------------------------------------------------- /type/TypeHandler.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Type.h" 4 | #include "../expr/Expr.h" 5 | 6 | #include "llvm/IR/Type.h" 7 | #include "llvm/ADT/DenseMap.h" 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | class Program; 15 | 16 | class TypeHandler { 17 | private: 18 | template 19 | using uptr = std::unique_ptr; 20 | 21 | Program* program; 22 | llvm::DenseMap> typeDefs; //map containing typedefs 23 | std::unordered_map> typeCache; 24 | 25 | // key = T, value = Type representing pointer to T 26 | std::unordered_map> pointerTypes; 27 | 28 | unsigned typeDefCount = 0; //variable used for creating new name for typedef 29 | 30 | /** 31 | * @brief getTypeDefName Creates new name for a typedef. 32 | * @return String containing new name for a typedef 33 | */ 34 | std::string getTypeDefName() { 35 | std::string ret = "typeDef_" + std::to_string(typeDefCount); 36 | typeDefCount++; 37 | return ret; 38 | } 39 | 40 | template 41 | Type* makeCachedType(const llvm::Type* ty, Args&&... args) { 42 | auto ptr = std::make_unique(std::forward(args)...); 43 | auto* result = ptr.get(); 44 | typeCache[ty] = std::move(ptr); 45 | return result; 46 | } 47 | 48 | public: 49 | std::vector sortedTypeDefs; //vector of sorted typedefs, used in output 50 | 51 | // basic C types 52 | uptr uint = std::make_unique(true); 53 | uptr uchar = std::make_unique(true); 54 | uptr ushort = std::make_unique(true); 55 | uptr ulong = std::make_unique(true); 56 | 57 | uptr sint = std::make_unique(false); 58 | uptr schar = std::make_unique(false); 59 | uptr sshort = std::make_unique(false); 60 | uptr slong = std::make_unique(false); 61 | 62 | uptr int128 = std::make_unique(); 63 | uptr voidType = std::make_unique(); 64 | 65 | uptr floatType = std::make_unique(); 66 | uptr doubleType = std::make_unique(); 67 | uptr longDoubleType = std::make_unique(); 68 | 69 | 70 | TypeHandler(Program* program) 71 | : program(program) { 72 | } 73 | 74 | /** 75 | * @brief getType Transforms llvm::Type into corresponding Type object 76 | * @param type llvm::Type for transformation 77 | * @return unique_ptr to corresponding Type object 78 | */ 79 | Type* getType(const llvm::Type* type); 80 | 81 | 82 | /** 83 | * @brief getBinaryType Returns type that would be result of a binary operation 84 | * @param left left argument of the operation 85 | * @param right right argument of the operation 86 | * @return unique_ptr to Type object 87 | */ 88 | static Type* getBinaryType(Type* left, Type* right); 89 | 90 | /** 91 | * @brief getStructName Parses LLVM struct (union) name into llvm2c struct name. 92 | * @param structName LLVM struct name 93 | * @return New struct name 94 | */ 95 | static std::string getStructName(const std::string& structName); 96 | 97 | /** 98 | * @brief hasTypeDefs Returns whether the program has any typedefs. 99 | * @return True if program has typedefs, false otherwise 100 | */ 101 | bool hasTypeDefs() const { 102 | return !typeDefs.empty(); 103 | } 104 | 105 | IntegerType* toggleSignedness(IntegerType* ty); 106 | 107 | Type* pointerTo(Type* type); 108 | 109 | IntegerType* setSigned(IntegerType* ty); 110 | IntegerType* setUnsigned(IntegerType* ty); 111 | }; 112 | -------------------------------------------------------------------------------- /writer/CWriter.cpp: -------------------------------------------------------------------------------- 1 | #include "CWriter.h" 2 | 3 | 4 | void CWriter::include(StrRef header) { 5 | out << "#include <" << header << ">" << std::endl; 6 | } 7 | 8 | void CWriter::declareStruct(StrRef name) { 9 | out << "struct " << name << ";" << std::endl; 10 | } 11 | 12 | void CWriter::declareUnion(StrRef name) { 13 | out << "union " << name << ";" << std::endl; 14 | } 15 | 16 | void CWriter::comment(StrRef comment) { 17 | out << "// " << comment << std::endl; 18 | } 19 | 20 | void CWriter::startStruct(StrRef name) { 21 | out << "struct " << name << " {" << std::endl; 22 | } 23 | 24 | void CWriter::endStruct() { 25 | out << "};" << std::endl; 26 | } 27 | 28 | void CWriter::indent(size_t tabs) { 29 | for (size_t t = 0; t < tabs; ++t) { 30 | out << " "; 31 | } 32 | } 33 | 34 | void CWriter::structItem(StrRef ty, StrRef name) { 35 | out << ty << " " << name << ";" << std::endl; 36 | } 37 | 38 | void CWriter::defineType(StrRef ty, StrRef alias, StrRef end) { 39 | out << "typedef " << ty << " " << alias << end << ";" << std::endl; 40 | } 41 | 42 | void CWriter::startFunction(StrRef ret, StrRef name) { 43 | out << ret << " " << name; 44 | } 45 | 46 | void CWriter::startArrayFunction(StrRef ty, size_t levels, StrRef name) { 47 | out << ty << " ("; 48 | for (size_t i = 0; i < levels; ++i) { 49 | out << "*"; 50 | } 51 | out << name; 52 | } 53 | 54 | void CWriter::endFunctionDecl() { 55 | out << ";" << std::endl; 56 | } 57 | 58 | void CWriter::functionParam(StrRef type, StrRef name) { 59 | out << type << " " << name; 60 | } 61 | 62 | void CWriter::nextFunctionParam() { 63 | out << ", "; 64 | } 65 | 66 | void CWriter::raw(StrRef text) { 67 | out << text; 68 | } 69 | 70 | void CWriter::line(StrRef line) { 71 | out << line << std::endl; 72 | } 73 | 74 | void CWriter::functionVarArgs() { 75 | out << "..."; 76 | } 77 | 78 | void CWriter::startFunctionBody() { 79 | out << "{" << std::endl; 80 | } 81 | 82 | void CWriter::endFunctionBody() { 83 | out << "}" << std::endl; 84 | } 85 | 86 | 87 | void CWriter::startFunctionParams() { 88 | out << "("; 89 | } 90 | 91 | void CWriter::endFunctionParams() { 92 | out << ")"; 93 | } 94 | 95 | void CWriter::declareVar(StrRef ty, StrRef name) { 96 | out << ty << " " << name << ";" << std::endl; 97 | } 98 | 99 | void CWriter::startBlock(StrRef label) { 100 | out << label << ":" << std::endl; 101 | } 102 | 103 | void CWriter::functionNoArgs() { 104 | out << "void"; 105 | } 106 | 107 | void CWriter::startUnion(StrRef name) { 108 | out << "union " << name << " {" << std::endl; 109 | } 110 | -------------------------------------------------------------------------------- /writer/CWriter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | class CWriter 6 | { 7 | private: 8 | using StreamRef = std::ostream&; 9 | using StrRef = const std::string&; 10 | 11 | StreamRef out; 12 | 13 | 14 | public: 15 | CWriter(StreamRef stream) : out(stream) {} 16 | void include(StrRef header); 17 | void comment(StrRef comment); 18 | void declareStruct(StrRef name); 19 | void declareUnion(StrRef name); 20 | void startStruct(StrRef name); 21 | void startUnion(StrRef name); 22 | void endStruct(); 23 | void indent(size_t tabs); 24 | void structItem(StrRef ty, StrRef name); 25 | void defineType(StrRef ty, StrRef alias, StrRef end); 26 | void startFunction(StrRef ret, StrRef name); 27 | void startArrayFunction(StrRef ret, size_t levels, StrRef name); 28 | void endFunctionDecl(); 29 | void functionParam(StrRef ty, StrRef name); 30 | void nextFunctionParam(); 31 | 32 | // TODO: get rid of raw 33 | void raw(StrRef line); 34 | 35 | // TODO: get rid of line 36 | void line(StrRef line); 37 | 38 | void functionVarArgs(); 39 | void startFunctionParams(); 40 | void endFunctionParams(); 41 | void startFunctionBody(); 42 | void endFunctionBody(); 43 | void declareVar(StrRef ty, StrRef name); 44 | void startBlock(StrRef label); 45 | 46 | void functionNoArgs(); 47 | }; 48 | -------------------------------------------------------------------------------- /writer/ExprWriter.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | #include "../expr/Expr.h" 7 | #include "../expr/UnaryExpr.h" 8 | #include "../expr/BinaryExpr.h" 9 | #include "../expr/ExprVisitor.h" 10 | 11 | class ExprWriter : public ExprVisitor 12 | { 13 | private: 14 | std::ostream& ss; 15 | bool noFuncCasts; 16 | bool forceBlockLabels; 17 | size_t indentCount = 1; 18 | 19 | void parensIfNotSimple(Expr* expr); 20 | void writeCastType(Type* ty); 21 | void indent(); 22 | 23 | public: 24 | ExprWriter(std::ostream& os, bool noFuncCasts, bool forceBlockLabels); 25 | 26 | void gotoOrInline(Block* block, bool doIndent); 27 | 28 | void visit(AggregateElement& expr) override; 29 | void visit(ArrayElement& expr) override; 30 | void visit(ExtractValueExpr& expr) override; 31 | void visit(Value& expr) override; 32 | void visit(GlobalValue& expr) override; 33 | void visit(IfExpr& expr) override; 34 | void visit(SwitchExpr& expr) override; 35 | void visit(AsmExpr& expr) override; 36 | void visit(CallExpr& expr) override; 37 | void visit(PointerShift& expr) override; 38 | void visit(GepExpr& expr) override; 39 | void visit(SelectExpr& expr) override; 40 | void visit(RefExpr& expr) override; 41 | void visit(DerefExpr& expr) override; 42 | void visit(RetExpr& expr) override; 43 | void visit(CastExpr& expr) override; 44 | void visit(AddExpr& expr) override; 45 | void visit(SubExpr& expr) override; 46 | void visit(AssignExpr& expr) override; 47 | void visit(MulExpr& expr) override; 48 | void visit(DivExpr& expr) override; 49 | void visit(RemExpr& expr) override; 50 | void visit(AndExpr& expr) override; 51 | void visit(OrExpr& expr) override; 52 | void visit(XorExpr& expr) override; 53 | void visit(CmpExpr& expr) override; 54 | void visit(AshrExpr& expr) override; 55 | void visit(LshrExpr& expr) override; 56 | void visit(ShlExpr& expr) override; 57 | void visit(StackAlloc& expr) override; 58 | void visit(ArrowExpr& expr) override; 59 | void visit(AggregateInitializer& ai) override; 60 | void visit(LogicalAnd& expr) override; 61 | void visit(LogicalOr& expr) override; 62 | void visit(GotoExpr& expr) override; 63 | void visit(ExprList& expr) override; 64 | void visit(MinusExpr& expr) override; 65 | void visit(LogicalNot& expr) override; 66 | void visit(DoWhile& expr) override; 67 | 68 | virtual ~ExprWriter() = default; 69 | }; 70 | -------------------------------------------------------------------------------- /writer/Writer.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "../core/Program.h" 4 | #include "CWriter.h" 5 | #include "ExprWriter.h" 6 | 7 | #include 8 | #include 9 | 10 | /** 11 | * @brief Writer converts programs to C code 12 | */ 13 | class Writer 14 | { 15 | private: 16 | CWriter wr; 17 | ExprWriter ew; 18 | 19 | bool useIncludes; 20 | bool noFuncCasts; 21 | bool forceBlockLabels; 22 | 23 | void includes(const Program& program); 24 | void unionDeclarations(const Program& program); 25 | void structDeclarations(const Program& program); 26 | void structDefinitions(const Program& program); 27 | void globalVars(const Program& program); 28 | void anonymousStructDeclarations(const Program& program); 29 | void globalVarDefinitions(const Program& program); 30 | void functionDeclarations(const Program& program); 31 | void anonymousStructDefinitions(const Program& program); 32 | void functionDefinitions(const Program& program); 33 | void typedefs(const Program& program); 34 | void structDefinition(const Program& program, const StructType* strct, std::unordered_set& printed); 35 | bool isFunctionPrinted(const Func* func) const; 36 | void functionHead(const Func* func, bool isdecl=false); 37 | void writeBlock(const Block* block); 38 | void unionDefinition(const Program& program, const UnionType* unn); 39 | void unionDefinitions(const Program& program); 40 | 41 | 42 | public: 43 | Writer(std::ostream& stream, bool useIncludes, bool noFuncCasts, bool forceBlockLabels) : wr(CWriter(stream)), ew(ExprWriter(stream, noFuncCasts, forceBlockLabels)), useIncludes(useIncludes), noFuncCasts(true), forceBlockLabels(forceBlockLabels) {} 44 | void writeProgram(const Program& program); 45 | }; 46 | --------------------------------------------------------------------------------