├── LICENSE ├── README.md └── src └── libasr ├── ASR.asdl ├── CMakeLists.txt ├── alloc.h ├── asdl.py ├── asdl_cpp.py ├── asr_scopes.cpp ├── asr_scopes.h ├── asr_utils.cpp ├── asr_utils.h ├── asr_verify.cpp ├── asr_verify.h ├── assert.h ├── bigint.h ├── bwriter.h ├── casting_utils.cpp ├── casting_utils.h ├── codegen ├── KaleidoscopeJIT.h ├── asr_to_c.cpp ├── asr_to_c.h ├── asr_to_c_cpp.h ├── asr_to_cpp.cpp ├── asr_to_cpp.h ├── asr_to_fortran.cpp ├── asr_to_fortran.h ├── asr_to_julia.cpp ├── asr_to_julia.h ├── asr_to_llvm.cpp ├── asr_to_llvm.h ├── asr_to_py.cpp ├── asr_to_py.h ├── asr_to_wasm.cpp ├── asr_to_wasm.h ├── asr_to_x86.cpp ├── asr_to_x86.h ├── c_utils.h ├── evaluator.cpp ├── evaluator.h ├── llvm_array_utils.cpp ├── llvm_array_utils.h ├── llvm_utils.cpp ├── llvm_utils.h ├── wasm_assembler.h ├── wasm_decoder.h ├── wasm_to_wat.cpp ├── wasm_to_wat.h ├── wasm_to_x64.cpp ├── wasm_to_x64.h ├── wasm_to_x86.cpp ├── wasm_to_x86.h ├── wasm_utils.cpp ├── wasm_utils.h ├── x86_assembler.cpp └── x86_assembler.h ├── colors.h ├── compiler_tester ├── __init__.py └── tester.py ├── config.h.in ├── containers.h ├── dat_convert.py ├── diagnostics.cpp ├── diagnostics.h ├── dwarf_convert.py ├── exception.h ├── gen_pass.py ├── location.h ├── lsp_interface.h ├── modfile.cpp ├── modfile.h ├── pass ├── arr_dims_propagate.cpp ├── arr_dims_propagate.h ├── arr_slice.cpp ├── arr_slice.h ├── array_by_data.h ├── array_op.cpp ├── array_op.h ├── class_constructor.cpp ├── class_constructor.h ├── compare.h ├── create_subroutine_from_function.h ├── dead_code_removal.cpp ├── dead_code_removal.h ├── div_to_mul.cpp ├── div_to_mul.h ├── do_loops.cpp ├── do_loops.h ├── flip_sign.cpp ├── flip_sign.h ├── fma.cpp ├── fma.h ├── for_all.cpp ├── for_all.h ├── global_stmts.cpp ├── global_stmts.h ├── global_stmts_program.cpp ├── global_stmts_program.h ├── global_symbols.cpp ├── global_symbols.h ├── implied_do_loops.cpp ├── implied_do_loops.h ├── init_expr.cpp ├── init_expr.h ├── inline_function_calls.cpp ├── inline_function_calls.h ├── insert_deallocate.cpp ├── insert_deallocate.h ├── instantiate_template.cpp ├── instantiate_template.h ├── intrinsic_array_function_registry.h ├── intrinsic_function.cpp ├── intrinsic_function.h ├── intrinsic_function_registry.h ├── list_expr.h ├── loop_unroll.cpp ├── loop_unroll.h ├── loop_vectorise.cpp ├── loop_vectorise.h ├── nested_vars.cpp ├── nested_vars.h ├── param_to_const.cpp ├── param_to_const.h ├── pass_array_by_data.cpp ├── pass_array_by_data.h ├── pass_compare.cpp ├── pass_compare.h ├── pass_list_concat.cpp ├── pass_list_concat.h ├── pass_list_expr.cpp ├── pass_list_expr.h ├── pass_manager.h ├── pass_utils.cpp ├── pass_utils.h ├── print_arr.cpp ├── print_arr.h ├── print_list.cpp ├── print_list.h ├── print_list_tuple.cpp ├── print_list_tuple.h ├── print_struct_type.cpp ├── replace_arr_slice.h ├── replace_array_op.h ├── replace_class_constructor.h ├── replace_div_to_mul.h ├── replace_do_loops.h ├── replace_flip_sign.h ├── replace_fma.h ├── replace_for_all.h ├── replace_implied_do_loops.h ├── replace_init_expr.h ├── replace_intrinsic_function.h ├── replace_param_to_const.h ├── replace_print_arr.h ├── replace_print_list_tuple.h ├── replace_print_struct_type.h ├── replace_select_case.h ├── replace_sign_from_value.h ├── replace_symbolic.cpp ├── replace_symbolic.h ├── replace_where.h ├── select_case.cpp ├── select_case.h ├── sign_from_value.cpp ├── sign_from_value.h ├── stmt_walk_visitor.h ├── subroutine_from_function.cpp ├── subroutine_from_function.h ├── transform_optional_argument_functions.cpp ├── transform_optional_argument_functions.h ├── unique_symbols.cpp ├── unique_symbols.h ├── unused_functions.cpp ├── unused_functions.h ├── update_array_dim_intrinsic_calls.cpp ├── update_array_dim_intrinsic_calls.h ├── where.cpp ├── where.h └── wrap_global_stmts.h ├── pickle.cpp ├── pickle.h ├── runtime ├── lfortran_intrinsics.c └── lfortran_intrinsics.h ├── semantic_exception.h ├── serialization.cpp ├── serialization.h ├── stacktrace.cpp ├── stacktrace.h ├── string_utils.cpp ├── string_utils.h ├── utils.h ├── utils2.cpp ├── wasm_instructions.txt └── wasm_instructions_visitor.py /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 lcompilers 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # libasr 2 | 3 | This repository contains the ASR (Abstract Semantic Representation), all the 4 | backends, ASR -> ASR optimizations, diagnostic messages infrastructure and all 5 | other tooling that is common for all frontends. 6 | 7 | The following projects use `libasr`: 8 | 9 | * [LPython](https://lpython.org) 10 | * [LFortran](https://lfortran.org) 11 | -------------------------------------------------------------------------------- /src/libasr/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.10) 2 | 3 | project(libasr) 4 | 5 | if (NOT CMAKE_CXX_STANDARD) 6 | set(CMAKE_CXX_STANDARD 17 7 | CACHE STRING "C++ standard" FORCE) 8 | endif () 9 | 10 | if (NOT LFORTRAN_VERSION) 11 | set(LFORTRAN_VERSION "0.1-git" 12 | CACHE STRING "LFortran version" FORCE) 13 | endif () 14 | 15 | configure_file(config.h.in config.h) 16 | 17 | set(SRC 18 | codegen/asr_to_cpp.cpp 19 | codegen/asr_to_c.cpp 20 | codegen/asr_to_julia.cpp 21 | codegen/asr_to_fortran.cpp 22 | codegen/asr_to_py.cpp 23 | codegen/x86_assembler.cpp 24 | codegen/asr_to_x86.cpp 25 | codegen/asr_to_wasm.cpp 26 | codegen/wasm_to_wat.cpp 27 | codegen/wasm_to_x86.cpp 28 | codegen/wasm_to_x64.cpp 29 | codegen/wasm_utils.cpp 30 | 31 | pass/nested_vars.cpp 32 | pass/where.cpp 33 | pass/param_to_const.cpp 34 | pass/do_loops.cpp 35 | pass/for_all.cpp 36 | pass/global_stmts.cpp 37 | pass/select_case.cpp 38 | pass/init_expr.cpp 39 | pass/implied_do_loops.cpp 40 | pass/array_op.cpp 41 | pass/subroutine_from_function.cpp 42 | pass/transform_optional_argument_functions.cpp 43 | pass/class_constructor.cpp 44 | pass/arr_slice.cpp 45 | pass/print_arr.cpp 46 | pass/print_struct_type.cpp 47 | pass/print_list_tuple.cpp 48 | pass/pass_utils.cpp 49 | pass/unused_functions.cpp 50 | pass/flip_sign.cpp 51 | pass/div_to_mul.cpp 52 | pass/replace_symbolic.cpp 53 | pass/intrinsic_function.cpp 54 | pass/fma.cpp 55 | pass/loop_vectorise.cpp 56 | pass/sign_from_value.cpp 57 | pass/inline_function_calls.cpp 58 | pass/loop_unroll.cpp 59 | pass/dead_code_removal.cpp 60 | pass/instantiate_template.cpp 61 | pass/update_array_dim_intrinsic_calls.cpp 62 | pass/pass_array_by_data.cpp 63 | pass/pass_list_expr.cpp 64 | pass/pass_compare.cpp 65 | pass/unique_symbols.cpp 66 | pass/insert_deallocate.cpp 67 | 68 | asr_verify.cpp 69 | asr_utils.cpp 70 | casting_utils.cpp 71 | diagnostics.cpp 72 | stacktrace.cpp 73 | string_utils.cpp 74 | asr_scopes.cpp 75 | modfile.cpp 76 | pickle.cpp 77 | serialization.cpp 78 | utils2.cpp 79 | ) 80 | if (WITH_LLVM) 81 | set(SRC ${SRC} 82 | codegen/evaluator.cpp 83 | codegen/asr_to_llvm.cpp 84 | codegen/llvm_array_utils.cpp 85 | codegen/llvm_utils.cpp 86 | ) 87 | # We use deprecated API in LLVM, so we disable the warning until we upgrade 88 | if (NOT MSVC) 89 | set_source_files_properties(codegen/evaluator.cpp PROPERTIES 90 | COMPILE_FLAGS -Wno-deprecated-declarations) 91 | set_source_files_properties(codegen/asr_to_llvm.cpp PROPERTIES 92 | COMPILE_FLAGS -Wno-deprecated-declarations) 93 | set_source_files_properties(codegen/llvm_array_utils.cpp PROPERTIES 94 | COMPILE_FLAGS -Wno-deprecated-declarations) 95 | set_source_files_properties(codegen/llvm_utils.cpp PROPERTIES 96 | COMPILE_FLAGS -Wno-deprecated-declarations) 97 | endif() 98 | endif() 99 | add_library(asr STATIC ${SRC}) 100 | target_include_directories(asr BEFORE PUBLIC ${libasr_SOURCE_DIR}/..) 101 | target_include_directories(asr BEFORE PUBLIC ${libasr_BINARY_DIR}/..) 102 | if (WITH_BFD) 103 | target_link_libraries(asr p::bfd) 104 | endif() 105 | if (WITH_LINK) 106 | target_link_libraries(asr p::link) 107 | endif() 108 | if (WITH_EXECINFO) 109 | target_link_libraries(asr p::execinfo) 110 | endif() 111 | if (WITH_LLVM) 112 | target_link_libraries(asr p::llvm) 113 | endif() 114 | -------------------------------------------------------------------------------- /src/libasr/alloc.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PARSER_ALLOC_H 2 | #define LFORTRAN_PARSER_ALLOC_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | 12 | #define ALIGNMENT 8 13 | 14 | inline size_t align(size_t n) { 15 | return (n + ALIGNMENT - 1) & ~(ALIGNMENT - 1); 16 | } 17 | 18 | class Allocator 19 | { 20 | void *start; 21 | size_t current_pos; 22 | size_t size; 23 | std::vector blocks; 24 | public: 25 | Allocator(size_t s) { 26 | s += ALIGNMENT; 27 | start = malloc(s); 28 | if (start == nullptr) throw std::runtime_error("malloc failed."); 29 | current_pos = (size_t)start; 30 | current_pos = align(current_pos); 31 | size = s; 32 | blocks.push_back(start); 33 | } 34 | Allocator() = delete; 35 | Allocator(const Allocator&) = delete; 36 | Allocator& operator=(const Allocator&) = delete; 37 | Allocator(const Allocator&&) = delete; 38 | Allocator& operator=(const Allocator&&) = delete; 39 | ~Allocator() { 40 | for (size_t i = 0; i < blocks.size(); i++) { 41 | if (blocks[i] != nullptr) free(blocks[i]); 42 | } 43 | } 44 | 45 | // Allocates `s` bytes of memory, returns a pointer to it 46 | void *alloc(size_t s) { 47 | // For good performance, the code inside of `try` must be very short, as 48 | // it will get inlined. One could just `return new_chunk(s)` instead of 49 | // `throw std::bad_alloc()`, but a parsing benchmark gets about 2% or 3% 50 | // slower. Even though it is never executed for the benchmark, the extra 51 | // machine code makes the overall benchmark slower. One would have to 52 | // force new_chunk() not to get inlined, but there is no standard way of 53 | // doing it. This try/catch approach effectively achieves the same using 54 | // standard C++. 55 | #ifdef LCOMPILERS_FAST_ALLOC 56 | try { 57 | #endif 58 | LCOMPILERS_ASSERT(start != nullptr); 59 | size_t addr = current_pos; 60 | current_pos += align(s); 61 | if (size_current() > size_total()) { 62 | #ifdef LCOMPILERS_FAST_ALLOC 63 | throw std::bad_alloc(); 64 | #else 65 | return new_chunk(s); 66 | #endif 67 | } 68 | return (void*)addr; 69 | #ifdef LCOMPILERS_FAST_ALLOC 70 | } catch (const std::bad_alloc &e) { 71 | return new_chunk(s); 72 | } 73 | #endif 74 | } 75 | 76 | void *new_chunk(size_t s) { 77 | size_t snew = std::max(s+ALIGNMENT, 2*size); 78 | start = malloc(snew); 79 | blocks.push_back(start); 80 | if (start == nullptr) { 81 | throw std::runtime_error("malloc failed."); 82 | } 83 | current_pos = (size_t)start; 84 | current_pos = align(current_pos); 85 | size = snew; 86 | 87 | size_t addr = current_pos; 88 | current_pos += align(s); 89 | 90 | LCOMPILERS_ASSERT(size_current() <= size_total()); 91 | return (void*)addr; 92 | } 93 | 94 | // Allocates `n` elements of type T, returns the pointer T* to the first 95 | // element 96 | template T* allocate(size_t n=1) { 97 | return (T *)alloc(sizeof(T) * n); 98 | } 99 | 100 | // Just like `new`, but using Allocator 101 | // The following two examples both construct the same instance MyInt(5), 102 | // but first uses the default C++ allocator, while the second uses 103 | // Allocator: 104 | // 105 | // MyInt *n = new MyInt(5); // Default C++ allocator 106 | // 107 | // Allocator al(1024); 108 | // MyInt *n = al.make_new(5); // Allocator 109 | template T* make_new(Args &&... args) { 110 | return new(alloc(sizeof(T))) T(std::forward(args)...); 111 | // To test the default "new", comment the above and uncomment this: 112 | //return new T(std::forward(args)...); 113 | } 114 | 115 | size_t size_current() { 116 | return current_pos - (size_t)start; 117 | } 118 | 119 | size_t size_total() { 120 | return size; 121 | } 122 | 123 | size_t num_chunks() { 124 | return blocks.size(); 125 | } 126 | }; 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /src/libasr/asr_scopes.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | std::string lcompilers_unique_ID; 8 | 9 | namespace LCompilers { 10 | 11 | template< typename T > 12 | std::string hexify(T i) 13 | { 14 | std::stringbuf buf; 15 | std::ostream os(&buf); 16 | os << std::setfill('0') << std::setw(sizeof(T) * 2) << std::hex << i; 17 | return buf.str(); 18 | } 19 | 20 | unsigned int symbol_table_counter = 0; 21 | 22 | SymbolTable::SymbolTable(SymbolTable *parent) : parent{parent} { 23 | symbol_table_counter++; 24 | counter = symbol_table_counter; 25 | } 26 | 27 | void SymbolTable::reset_global_counter() { 28 | symbol_table_counter = 0; 29 | } 30 | 31 | void SymbolTable::mark_all_variables_external(Allocator &al) { 32 | for (auto &a : scope) { 33 | switch (a.second->type) { 34 | case (ASR::symbolType::Variable) : { 35 | ASR::Variable_t *v = ASR::down_cast(a.second); 36 | v->m_abi = ASR::abiType::Interactive; 37 | break; 38 | } 39 | case (ASR::symbolType::Function) : { 40 | ASR::Function_t *v = ASR::down_cast(a.second); 41 | ASR::FunctionType_t* v_func_type = ASR::down_cast(v->m_function_signature); 42 | v_func_type->m_abi = ASR::abiType::Interactive; 43 | v->m_body = nullptr; 44 | v->n_body = 0; 45 | break; 46 | } 47 | case (ASR::symbolType::Module) : { 48 | ASR::Module_t *v = ASR::down_cast(a.second); 49 | v->m_symtab->mark_all_variables_external(al); 50 | } 51 | default : {}; 52 | } 53 | } 54 | } 55 | 56 | ASR::symbol_t *SymbolTable::find_scoped_symbol(const std::string &name, 57 | size_t n_scope_names, char **m_scope_names) { 58 | const SymbolTable *s = this; 59 | for(size_t i=0; i < n_scope_names; i++) { 60 | std::string scope_name = m_scope_names[i]; 61 | if (s->scope.find(scope_name) != scope.end()) { 62 | ASR::symbol_t *sym = s->scope.at(scope_name); 63 | s = ASRUtils::symbol_symtab(sym); 64 | if (s == nullptr) { 65 | // The m_scope_names[i] found in the appropriate symbol table, 66 | // but points to a symbol that itself does not have a symbol 67 | // table 68 | return nullptr; 69 | } 70 | } else { 71 | // The m_scope_names[i] not found in the appropriate symbol table 72 | return nullptr; 73 | } 74 | } 75 | if (s->scope.find(name) != scope.end()) { 76 | ASR::symbol_t *sym = s->scope.at(name); 77 | LCOMPILERS_ASSERT(sym) 78 | return sym; 79 | } else { 80 | // The `name` not found in the appropriate symbol table 81 | return nullptr; 82 | } 83 | } 84 | 85 | std::string SymbolTable::get_unique_name(const std::string &name, bool use_unique_id) { 86 | std::string unique_name = name; 87 | if( use_unique_id && !lcompilers_unique_ID.empty()) { 88 | unique_name += "_" + lcompilers_unique_ID; 89 | } 90 | int counter = 1; 91 | while (scope.find(unique_name) != scope.end()) { 92 | unique_name = name + std::to_string(counter); 93 | counter++; 94 | } 95 | return unique_name; 96 | } 97 | 98 | } // namespace LCompilers 99 | -------------------------------------------------------------------------------- /src/libasr/asr_scopes.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_SEMANTICS_ASR_SCOPES_H 2 | #define LFORTRAN_SEMANTICS_ASR_SCOPES_H 3 | 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | namespace LCompilers { 10 | 11 | namespace ASR { 12 | struct asr_t; 13 | struct stmt_t; 14 | struct symbol_t; 15 | } 16 | 17 | struct SymbolTable { 18 | private: 19 | std::map scope; 20 | 21 | public: 22 | SymbolTable *parent; 23 | // The ASR node (either symbol_t or TranslationUnit_t) that contains this 24 | // SymbolTable as m_symtab member. One of: 25 | // * symbol_symtab(down_cast(this->asr_owner)) == this 26 | // * down_cast2(this->asr_owner)->m_symtab == this 27 | ASR::asr_t *asr_owner = nullptr; 28 | unsigned int counter; 29 | 30 | SymbolTable(SymbolTable *parent); 31 | 32 | // Determines a stable hash based on the content of the symbol table 33 | uint32_t get_hash_uint32(); // Returns the hash as an integer 34 | std::string get_counter() { // Returns a unique ID as a string 35 | return std::to_string(counter); 36 | } 37 | static void reset_global_counter(); // Resets the internal global counter 38 | 39 | // Resolves the symbol `name` recursively in current and parent scopes. 40 | // Returns `nullptr` if symbol not found. 41 | ASR::symbol_t* resolve_symbol(const std::string &name) { 42 | if (scope.find(name) == scope.end()) { 43 | if (parent) { 44 | return parent->resolve_symbol(name); 45 | } else { 46 | return nullptr; 47 | } 48 | } 49 | return scope[name]; 50 | } 51 | 52 | const std::map& get_scope() const { 53 | return scope; 54 | } 55 | 56 | // Obtains the symbol `name` from the current symbol table 57 | // Returns `nullptr` if symbol not found. 58 | ASR::symbol_t* get_symbol(const std::string &name) const { 59 | //auto it = scope.find(to_lower(name)); 60 | auto it = scope.find(name); 61 | if (it == scope.end()) { 62 | return nullptr; 63 | } else { 64 | return it->second; 65 | } 66 | } 67 | 68 | void erase_symbol(const std::string &name) { 69 | //auto it = scope.find(to_lower(name)); 70 | LCOMPILERS_ASSERT(scope.find(name) != scope.end()) 71 | scope.erase(name); 72 | } 73 | 74 | // Add a new symbol that did not exist before 75 | void add_symbol(const std::string &name, ASR::symbol_t* symbol) { 76 | LCOMPILERS_ASSERT(scope.find(name) == scope.end()) 77 | scope[name] = symbol; 78 | } 79 | 80 | // Overwrite an existing symbol 81 | void overwrite_symbol(const std::string &name, ASR::symbol_t* symbol) { 82 | LCOMPILERS_ASSERT(scope.find(name) != scope.end()) 83 | scope[name] = symbol; 84 | } 85 | 86 | // Use as the last resort, prefer to always either add a new symbol 87 | // or overwrite an existing one, not both 88 | void add_or_overwrite_symbol(const std::string &name, ASR::symbol_t* symbol) { 89 | scope[name] = symbol; 90 | } 91 | 92 | // Marks all variables as external 93 | void mark_all_variables_external(Allocator &al); 94 | 95 | ASR::symbol_t *find_scoped_symbol(const std::string &name, 96 | size_t n_scope_names, char **m_scope_names); 97 | 98 | std::string get_unique_name(const std::string &name, bool use_unique_id=true); 99 | }; 100 | 101 | } // namespace LCompilers 102 | 103 | #endif // LFORTRAN_SEMANTICS_ASR_SCOPES_H 104 | -------------------------------------------------------------------------------- /src/libasr/asr_verify.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_ASR_VERIFY_H 2 | #define LFORTRAN_ASR_VERIFY_H 3 | 4 | #include 5 | 6 | namespace LCompilers { 7 | 8 | // Verifies that ASR is correctly constructed and contains valid Fortran 9 | // code and passes all our requirements on ASR, such as: 10 | // 11 | // * All types and kinds are correctly inferred and implicit casting 12 | // nodes are correctly inserted in expressions 13 | // * Types match for function / subroutine calls 14 | // * All symbols in the Symbol Table correctly link back to it or the 15 | // parent table. 16 | // * All Fortran rules will be checked eventually, such as: 17 | // * Initializer expression only uses intrinsic functions 18 | // * Any function used in array dimension declaration is pure 19 | // * Pure function only calls pure functions 20 | // * ... 21 | // 22 | // This should not replace correct semantic checking in ast2asr. This is 23 | // only meant as a tool for LCompilers developers to check there are no bugs 24 | // in LCompilers code that constructs ASR and that some requirement was not 25 | // accidentally broken. 26 | // This should not be called in Release mode for performance reasons, but 27 | // it should be called in our tests to ensure ast2asr, deserialization, all 28 | // the ASR passes and any other code that constructs ASR does not have 29 | // bugs. 30 | // Any code that takes ASR as an argument can assume that it is verified. 31 | // Such as the LLVM, C++ backend, or any ASR pass, or pickle. 32 | 33 | // The function will raise an exception if there is an error. Otherwise 34 | // it will return true. It can be used in Debug mode only as: 35 | // 36 | // LCOMPILERS_ASSERT(asr_verify(*asr)); 37 | // 38 | bool asr_verify(const ASR::TranslationUnit_t &unit, 39 | bool check_external, diag::Diagnostics &diagnostics); 40 | 41 | } // namespace LCompilers 42 | 43 | #endif // LFORTRAN_ASR_VERIFY_H 44 | -------------------------------------------------------------------------------- /src/libasr/assert.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_ASSERT_H 2 | #define LFORTRAN_ASSERT_H 3 | 4 | // LCOMPILERS_ASSERT uses internal functions to perform as assert 5 | // so that there is no effect with NDEBUG 6 | #include 7 | #include 8 | #if defined(WITH_LFORTRAN_ASSERT) 9 | 10 | #include 11 | 12 | #if !defined(LCOMPILERS_ASSERT) 13 | #define stringize(s) #s 14 | #define XSTR(s) stringize(s) 15 | #if defined(HAVE_LFORTRAN_STACKTRACE) 16 | #define LCOMPILERS_ASSERT(cond) \ 17 | { \ 18 | if (!(cond)) { \ 19 | throw LCompilers::AssertFailed(XSTR(cond)); \ 20 | } \ 21 | } 22 | #else 23 | #define LCOMPILERS_ASSERT(cond) \ 24 | { \ 25 | if (!(cond)) { \ 26 | std::cerr << "LCOMPILERS_ASSERT failed: " << __FILE__ \ 27 | << "\nfunction " << __func__ << "(), line number " \ 28 | << __LINE__ << " at \n" \ 29 | << XSTR(cond) << "\n"; \ 30 | abort(); \ 31 | } \ 32 | } 33 | #endif // defined(HAVE_LFORTRAN_STACKTRACE) 34 | #endif // !defined(LCOMPILERS_ASSERT) 35 | 36 | #if !defined(LCOMPILERS_ASSERT_MSG) 37 | #define LCOMPILERS_ASSERT_MSG(cond, msg) \ 38 | { \ 39 | if (!(cond)) { \ 40 | std::cerr << "LCOMPILERS_ASSERT failed: " << __FILE__ \ 41 | << "\nfunction " << __func__ << "(), line number " \ 42 | << __LINE__ << " at \n" \ 43 | << XSTR(cond) << "\n" \ 44 | << "ERROR MESSAGE:\n" \ 45 | << msg << "\n"; \ 46 | abort(); \ 47 | } \ 48 | } 49 | #endif // !defined(LCOMPILERS_ASSERT_MSG) 50 | 51 | #else // defined(WITH_LFORTRAN_ASSERT) 52 | 53 | #define LCOMPILERS_ASSERT(cond) 54 | #define LCOMPILERS_ASSERT_MSG(cond, msg) 55 | 56 | #endif // defined(WITH_LFORTRAN_ASSERT) 57 | 58 | #define LFORTRAN_ERROR(description) \ 59 | std::cerr << description; \ 60 | std::cerr << "\n"; \ 61 | abort(); 62 | 63 | #endif // LFORTRAN_ASSERT_H 64 | -------------------------------------------------------------------------------- /src/libasr/bigint.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_BIGINT_H 2 | #define LFORTRAN_BIGINT_H 3 | 4 | #include 5 | 6 | #include 7 | 8 | namespace LCompilers { 9 | 10 | namespace BigInt { 11 | 12 | /* 13 | * Arbitrary size integer implementation. 14 | * 15 | * We use tagged signed 64bit integers with no padding bits and using 2's 16 | * complement for negative values (int64_t) as the underlying data structure. 17 | * Little-endian is assumed. 18 | * 19 | * Bits (from the left): 20 | * 1 ..... sign: 0 positive, 1 negative 21 | * 2 ..... tag: bits 1-2 equal to 01: pointer; otherwise integer 22 | * 3-64 .. if the tag is - integer: rest of the signed integer bits in 2's 23 | * complement 24 | * - pointer: 64 bit pointer shifted by 2 25 | * to the right (>> 2) 26 | * 27 | * The pointer must be aligned to 4 bytes (bits 63-64 must be 00). 28 | * Small signed integers are represented directly as integers in int64_t, large 29 | * integers are allocated on heap and a pointer to it is used as "tag pointer" 30 | * in int64_t. 31 | * 32 | * To check if the integer has a pointer tag, we check that the first two bits 33 | * (1-2) are equal to 01. 34 | * 35 | * If the first bit is 0, then it can either be a positive integer or a 36 | * pointer. We check the second bit, if it is 1, then it is a pointer (shifted 37 | * by 2), if it is 0, then is is a positive integer, represented by the rest of 38 | * the 62 bits. If the first bit is 1, then it is a negative integer, 39 | * represented by the full 64 bits in 2's complement representation. 40 | */ 41 | 42 | // Returns true if "i" is a pointer and false if "i" is an integer 43 | inline static bool is_int_ptr(int64_t i) { 44 | return (((uint64_t)i) >> (64 - 2)) == 1; 45 | } 46 | 47 | /* 48 | * A pointer is converted to integer by shifting by 2 to the right and adding 49 | * 01 to the first two bits to tag it as a pointer: 50 | */ 51 | 52 | // Converts a pointer "p" (must be aligned to 4 bytes) to a tagged int64_t 53 | inline static int64_t ptr_to_int(void *p) { 54 | return (int64_t)( (((uint64_t)p) >> 2) | (1ULL << (64 - 2)) ); 55 | } 56 | 57 | /* An integer with the pointer tag is converted to a pointer by shifting by 2 58 | * to the left, which erases the tag and puts 00 to bits 63-64: 59 | */ 60 | 61 | // Converts a tagged int64_t to a pointer (aligned to 4 bytes) 62 | inline static void* int_to_ptr(int64_t i) { 63 | return (void *)(((uint64_t)i) << 2); 64 | } 65 | 66 | /* The maximum small int is 2^62-1 67 | */ 68 | const int64_t MAX_SMALL_INT = (int64_t)((1ULL << 62)-1); 69 | 70 | /* The minimum small int is -2^63 71 | */ 72 | const int64_t MIN_SMALL_INT = (int64_t)(-(1ULL << 63)); 73 | 74 | // Returns true if "i" is a small int 75 | inline static bool is_small_int(int64_t i) { 76 | return (MIN_SMALL_INT <= i && i <= MAX_SMALL_INT); 77 | } 78 | 79 | /* Arbitrary integer implementation 80 | * For now large integers are implemented as strings with decimal digits. The 81 | * only supported operation on this is converting to and from a string. Later 82 | * we will replace with an actual large integer implementation and add other 83 | * operations. 84 | */ 85 | 86 | // Converts a string to a large int (allocated on heap, returns a pointer) 87 | inline static int64_t string_to_largeint(Allocator &al, const Str &s) { 88 | char *cs = s.c_str(al); 89 | return ptr_to_int(cs); 90 | } 91 | 92 | // Converts a large int to a string 93 | inline static char* largeint_to_string(int64_t i) { 94 | LCOMPILERS_ASSERT(is_int_ptr(i)); 95 | void *p = int_to_ptr(i); 96 | char *cs = (char*)p; 97 | return cs; 98 | } 99 | 100 | inline static std::string int_to_str(int64_t i) { 101 | if (is_int_ptr(i)) { 102 | return std::string(largeint_to_string(i)); 103 | } else { 104 | return std::to_string(i); 105 | } 106 | } 107 | 108 | inline static bool is_int64(std::string str_repr) { 109 | std::string str_int64 = "9223372036854775807"; 110 | if( str_repr.size() > str_int64.size() ) { 111 | return false; 112 | } 113 | 114 | if( str_repr.size() < str_int64.size() ) { 115 | return true; 116 | } 117 | 118 | size_t i; 119 | for( i = 0; i < str_repr.size() - 1 && str_repr[i] == str_int64[i]; i++ ) { 120 | } 121 | return i == str_repr.size() - 1 || str_repr[i] < str_int64[i]; 122 | } 123 | 124 | /* BigInt is a thin wrapper over the functionality exposed in the functions 125 | * above. The idea is that one can use the int64_t type directly and just use 126 | * the function above to handle the large integer aspects, and if it is a small 127 | * integer, one can use it directly as int64 integer. 128 | * 129 | * Alternatively, one can use the BigInt class below that exposes the 130 | * functionality via methods. 131 | */ 132 | 133 | struct BigInt { 134 | int64_t n; 135 | 136 | BigInt() = default; 137 | BigInt(const BigInt &) = default; 138 | BigInt& operator=(const BigInt &) = default; 139 | 140 | void from_smallint(int64_t i) { 141 | LCOMPILERS_ASSERT(is_small_int(i)); 142 | n = i; 143 | } 144 | 145 | void from_largeint(Allocator &al, const Str &s) { 146 | n = string_to_largeint(al, s); 147 | } 148 | 149 | bool is_large() const { 150 | return is_int_ptr(n); 151 | } 152 | 153 | int64_t as_smallint() const { 154 | LCOMPILERS_ASSERT(!is_large()); 155 | return n; 156 | } 157 | 158 | std::string str() const { 159 | return int_to_str(n); 160 | } 161 | 162 | }; 163 | 164 | static_assert(std::is_standard_layout::value); 165 | static_assert(std::is_trivial::value); 166 | static_assert(sizeof(BigInt) == sizeof(int64_t)); 167 | static_assert(sizeof(BigInt) == 8); 168 | 169 | 170 | } // BigInt 171 | 172 | } // namespace LCompilers 173 | 174 | #endif // LFORTRAN_BIGINT_H 175 | -------------------------------------------------------------------------------- /src/libasr/bwriter.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_BWRITER_H 2 | #define LFORTRAN_BWRITER_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | 9 | namespace LCompilers { 10 | 11 | std::string static inline uint32_to_string(uint32_t i) { 12 | char bytes[4]; 13 | bytes[0] = (i >> 24) & 0xFF; 14 | bytes[1] = (i >> 16) & 0xFF; 15 | bytes[2] = (i >> 8) & 0xFF; 16 | bytes[3] = i & 0xFF; 17 | return std::string(bytes, 4); 18 | } 19 | 20 | std::string static inline uint64_to_string(uint64_t i) { 21 | char bytes[8]; 22 | bytes[0] = (i >> 56) & 0xFF; 23 | bytes[1] = (i >> 48) & 0xFF; 24 | bytes[2] = (i >> 40) & 0xFF; 25 | bytes[3] = (i >> 32) & 0xFF; 26 | bytes[4] = (i >> 24) & 0xFF; 27 | bytes[5] = (i >> 16) & 0xFF; 28 | bytes[6] = (i >> 8) & 0xFF; 29 | bytes[7] = i & 0xFF; 30 | return std::string(bytes, 8); 31 | } 32 | 33 | uint32_t static inline string_to_uint32(const char *s) { 34 | // The cast from signed char to unsigned char is important, 35 | // otherwise the signed char shifts return wrong value for negative numbers 36 | const uint8_t *p = (const unsigned char*)s; 37 | return (((uint32_t)p[0]) << 24) | 38 | (((uint32_t)p[1]) << 16) | 39 | (((uint32_t)p[2]) << 8) | 40 | p[3]; 41 | } 42 | 43 | uint64_t static inline string_to_uint64(const char *s) { 44 | // The cast from signed char to unsigned char is important, 45 | // otherwise the signed char shifts return wrong value for negative numbers 46 | const uint8_t *p = (const unsigned char*)s; 47 | return (((uint64_t)p[0]) << 56) | 48 | (((uint64_t)p[1]) << 48) | 49 | (((uint64_t)p[2]) << 40) | 50 | (((uint64_t)p[3]) << 32) | 51 | (((uint64_t)p[4]) << 24) | 52 | (((uint64_t)p[5]) << 16) | 53 | (((uint64_t)p[6]) << 8) | 54 | p[7]; 55 | } 56 | 57 | uint32_t static inline string_to_uint32(const std::string &s) { 58 | return string_to_uint32(&s[0]); 59 | } 60 | 61 | uint64_t static inline string_to_uint64(const std::string &s) { 62 | return string_to_uint64(&s[0]); 63 | } 64 | 65 | // BinaryReader / BinaryWriter encapsulate access to the file by providing 66 | // primitives that other classes just use. 67 | class BinaryWriter 68 | { 69 | private: 70 | std::string s; 71 | public: 72 | std::string get_str() { 73 | return s; 74 | } 75 | 76 | void write_int8(uint8_t i) { 77 | char c=i; 78 | s.append(std::string(&c, 1)); 79 | } 80 | 81 | void write_int32(uint32_t i) { 82 | s.append(uint32_to_string(i)); 83 | } 84 | 85 | void write_int64(uint64_t i) { 86 | s.append(uint64_to_string(i)); 87 | } 88 | 89 | void write_string(const std::string &t) { 90 | write_int64(t.size()); 91 | s.append(t); 92 | } 93 | 94 | void write_float64(double d) { 95 | void *p = &d; 96 | uint64_t *ip = (uint64_t*)p; 97 | write_int64(*ip); 98 | } 99 | 100 | }; 101 | 102 | class BinaryReader 103 | { 104 | private: 105 | std::string s; 106 | size_t pos; 107 | public: 108 | BinaryReader(const std::string &s) : s{s}, pos{0} {} 109 | 110 | uint8_t read_int8() { 111 | if (pos+1 > s.size()) { 112 | throw LCompilersException("read_int8: String is too short for deserialization."); 113 | } 114 | uint8_t n = s[pos]; 115 | pos += 1; 116 | return n; 117 | } 118 | 119 | uint32_t read_int32() { 120 | if (pos+4 > s.size()) { 121 | throw LCompilersException("read_int32: String is too short for deserialization."); 122 | } 123 | uint32_t n = string_to_uint32(&s[pos]); 124 | pos += 4; 125 | return n; 126 | } 127 | 128 | uint64_t read_int64() { 129 | if (pos+8 > s.size()) { 130 | throw LCompilersException("read_int64: String is too short for deserialization."); 131 | } 132 | uint64_t n = string_to_uint64(&s[pos]); 133 | pos += 8; 134 | return n; 135 | } 136 | 137 | std::string read_string() { 138 | size_t n = read_int64(); 139 | if (pos+n > s.size()) { 140 | throw LCompilersException("read_string: String is too short for deserialization."); 141 | } 142 | std::string r = std::string(&s[pos], n); 143 | pos += n; 144 | return r; 145 | } 146 | 147 | double read_float64() { 148 | uint64_t x = read_int64(); 149 | uint64_t *ip = &x; 150 | void *p = ip; 151 | double *dp = (double*)p; 152 | return *dp; 153 | } 154 | }; 155 | 156 | // TextReader / TextWriter encapsulate access to the file by providing 157 | // primitives that other classes just use. The file is a human readable 158 | // text file. These classes are useful for debugging. 159 | class TextWriter 160 | { 161 | private: 162 | std::string s; 163 | public: 164 | std::string get_str() { 165 | return s; 166 | } 167 | 168 | void write_int8(uint8_t i) { 169 | s.append(std::to_string(i)); 170 | s += " "; 171 | } 172 | 173 | void write_int64(uint64_t i) { 174 | s.append(std::to_string(i)); 175 | s += " "; 176 | } 177 | 178 | void write_string(const std::string &t) { 179 | write_int64(t.size()); 180 | s.append(t); 181 | s += " "; 182 | } 183 | 184 | void write_float64(double d) { 185 | std::stringstream str; 186 | str << std::fixed << std::setprecision(17) << d; 187 | s.append(str.str()); 188 | s += " "; 189 | } 190 | }; 191 | 192 | class TextReader 193 | { 194 | private: 195 | std::string s; 196 | size_t pos; 197 | public: 198 | TextReader(const std::string &s) : s{s}, pos{0} {} 199 | 200 | uint8_t read_int8() { 201 | uint64_t n = read_int64(); 202 | if (n < 255) { 203 | return n; 204 | } else { 205 | throw LCompilersException("read_int8: Integer too large to fit 8 bits."); 206 | } 207 | } 208 | 209 | uint64_t read_int64() { 210 | std::string tmp; 211 | while (s[pos] != ' ') { 212 | tmp += s[pos]; 213 | if (! (s[pos] >= '0' && s[pos] <= '9')) { 214 | throw LCompilersException("read_int64: Expected integer, got `" + tmp + "`"); 215 | } 216 | pos++; 217 | if (pos >= s.size()) { 218 | throw LCompilersException("read_int64: String is too short for deserialization."); 219 | } 220 | } 221 | pos++; 222 | uint64_t n = std::stoull(tmp); 223 | return n; 224 | } 225 | 226 | double read_float64() { 227 | std::string tmp; 228 | while (s[pos] != ' ') { 229 | tmp += s[pos]; 230 | pos++; 231 | if (pos >= s.size()) { 232 | throw LCompilersException("read_float64: String is too short for deserialization."); 233 | } 234 | } 235 | pos++; 236 | double n = std::stod(tmp); 237 | return n; 238 | } 239 | 240 | std::string read_string() { 241 | size_t n = read_int64(); 242 | if (pos+n > s.size()) { 243 | throw LCompilersException("read_string: String is too short for deserialization."); 244 | } 245 | std::string r = std::string(&s[pos], n); 246 | pos += n; 247 | if (s[pos] != ' ') { 248 | throw LCompilersException("read_string: Space expected."); 249 | } 250 | pos ++; 251 | return r; 252 | } 253 | }; 254 | 255 | } // namespace LCompilers 256 | 257 | #endif // LFORTRAN_BWRITER_H 258 | -------------------------------------------------------------------------------- /src/libasr/casting_utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | 7 | namespace LCompilers::CastingUtil { 8 | 9 | // Data structure which contains priorities for 10 | // intrinsic types defined in ASR 11 | const std::map& type2weight = { 12 | {ASR::ttypeType::Complex, 4}, 13 | {ASR::ttypeType::Real, 3}, 14 | {ASR::ttypeType::Integer, 2}, 15 | {ASR::ttypeType::Logical, 1} 16 | }; 17 | 18 | // Data structure which contains casting rules for non-equal 19 | // intrinsic types defined in ASR 20 | const std::map, ASR::cast_kindType>& type_rules = { 21 | {std::make_pair(ASR::ttypeType::Complex, ASR::ttypeType::Real), ASR::cast_kindType::ComplexToReal}, 22 | {std::make_pair(ASR::ttypeType::Complex, ASR::ttypeType::Logical), ASR::cast_kindType::ComplexToLogical}, 23 | {std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::Complex), ASR::cast_kindType::RealToComplex}, 24 | {std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::Integer), ASR::cast_kindType::RealToInteger}, 25 | {std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::Logical), ASR::cast_kindType::RealToLogical}, 26 | {std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::UnsignedInteger), ASR::cast_kindType::RealToUnsignedInteger}, 27 | {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::Complex), ASR::cast_kindType::IntegerToComplex}, 28 | {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::Real), ASR::cast_kindType::IntegerToReal}, 29 | {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::Logical), ASR::cast_kindType::IntegerToLogical}, 30 | {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::UnsignedInteger), ASR::cast_kindType::IntegerToUnsignedInteger}, 31 | {std::make_pair(ASR::ttypeType::Logical, ASR::ttypeType::Real), ASR::cast_kindType::LogicalToReal}, 32 | {std::make_pair(ASR::ttypeType::Logical, ASR::ttypeType::Integer), ASR::cast_kindType::LogicalToInteger}, 33 | {std::make_pair(ASR::ttypeType::UnsignedInteger, ASR::ttypeType::Integer), ASR::cast_kindType::UnsignedIntegerToInteger}, 34 | {std::make_pair(ASR::ttypeType::UnsignedInteger, ASR::ttypeType::Real), ASR::cast_kindType::UnsignedIntegerToReal}, 35 | {std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::SymbolicExpression), ASR::cast_kindType::IntegerToSymbolicExpression} 36 | }; 37 | 38 | // Data structure which contains casting rules for equal intrinsic 39 | // types but with different kinds. 40 | const std::map& kind_rules = { 41 | {ASR::ttypeType::Complex, ASR::cast_kindType::ComplexToComplex}, 42 | {ASR::ttypeType::Real, ASR::cast_kindType::RealToReal}, 43 | {ASR::ttypeType::Integer, ASR::cast_kindType::IntegerToInteger}, 44 | {ASR::ttypeType::UnsignedInteger, ASR::cast_kindType::UnsignedIntegerToUnsignedInteger} 45 | }; 46 | 47 | int get_type_priority(ASR::ttypeType type) { 48 | if( type2weight.find(type) == type2weight.end() ) { 49 | return -1; 50 | } 51 | 52 | return type2weight.at(type); 53 | } 54 | 55 | int get_src_dest(ASR::expr_t* left_expr, ASR::expr_t* right_expr, 56 | ASR::expr_t*& src_expr, ASR::expr_t*& dest_expr, 57 | ASR::ttype_t*& src_type, ASR::ttype_t*& dest_type, 58 | bool is_assign) { 59 | ASR::ttype_t* left_type = ASRUtils::expr_type(left_expr); 60 | ASR::ttype_t* right_type = ASRUtils::expr_type(right_expr); 61 | if( ASR::is_a(*left_type) ) { 62 | left_type = ASRUtils::get_contained_type(left_type); 63 | } 64 | if( ASR::is_a(*right_type) ) { 65 | right_type = ASRUtils::get_contained_type(right_type); 66 | } 67 | left_type = ASRUtils::type_get_past_pointer(left_type); 68 | right_type = ASRUtils::type_get_past_pointer(right_type); 69 | if( ASRUtils::check_equal_type(left_type, right_type) || 70 | ASRUtils::is_character(*left_type) || ASRUtils::is_character(*right_type) ) { 71 | return 2; 72 | } 73 | if( is_assign ) { 74 | if( ASRUtils::is_real(*left_type) && ASRUtils::is_integer(*right_type)) { 75 | throw SemanticError("Assigning integer to float is not supported", 76 | right_expr->base.loc); 77 | } 78 | if ( ASRUtils::is_complex(*left_type) && !ASRUtils::is_complex(*right_type)) { 79 | throw SemanticError("Assigning non-complex to complex is not supported", 80 | right_expr->base.loc); 81 | } 82 | dest_expr = left_expr, dest_type = left_type; 83 | src_expr = right_expr, src_type = right_type; 84 | return 1; 85 | } 86 | 87 | int casted_expr_signal = 2; 88 | ASR::ttypeType left_Type = left_type->type, right_Type = right_type->type; 89 | int left_kind = ASRUtils::extract_kind_from_ttype_t(left_type); 90 | int right_kind = ASRUtils::extract_kind_from_ttype_t(right_type); 91 | int left_priority = get_type_priority(left_Type); 92 | int right_priority = get_type_priority(right_Type); 93 | if( left_priority > right_priority ) { 94 | src_expr = right_expr, src_type = right_type; 95 | dest_expr = left_expr, dest_type = left_type; 96 | casted_expr_signal = 1; 97 | } else if( left_priority < right_priority ) { 98 | src_expr = left_expr, src_type = left_type; 99 | dest_expr = right_expr, dest_type = right_type; 100 | casted_expr_signal = 0; 101 | } else { 102 | if( left_kind > right_kind ) { 103 | src_expr = right_expr, src_type = right_type; 104 | dest_expr = left_expr, dest_type = left_type; 105 | casted_expr_signal = 1; 106 | } else if( left_kind < right_kind ) { 107 | src_expr = left_expr, src_type = left_type; 108 | dest_expr = right_expr, dest_type = right_type; 109 | casted_expr_signal = 0; 110 | } else { 111 | return 2; 112 | } 113 | } 114 | 115 | return casted_expr_signal; 116 | } 117 | 118 | ASR::expr_t* perform_casting(ASR::expr_t* expr, ASR::ttype_t* src, 119 | ASR::ttype_t* dest, Allocator& al, 120 | const Location& loc) { 121 | ASR::ttypeType src_type = src->type; 122 | ASR::ttypeType dest_type = dest->type; 123 | ASR::cast_kindType cast_kind; 124 | if( src_type == dest_type ) { 125 | if( kind_rules.find(src_type) == kind_rules.end() ) { 126 | return expr; 127 | } 128 | cast_kind = kind_rules.at(src_type); 129 | } else { 130 | std::pair cast_key = std::make_pair(src_type, dest_type); 131 | if( type_rules.find(cast_key) == type_rules.end() ) { 132 | return expr; 133 | } 134 | cast_kind = type_rules.at(cast_key); 135 | } 136 | if( ASRUtils::check_equal_type(src, dest, true) ) { 137 | return expr; 138 | } 139 | // TODO: Fix loc 140 | return ASRUtils::EXPR(ASRUtils::make_Cast_t_value(al, loc, expr, 141 | cast_kind, dest)); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /src/libasr/casting_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_CASTING_UTILS_H 2 | #define LFORTRAN_CASTING_UTILS_H 3 | 4 | 5 | #include 6 | 7 | namespace LCompilers::CastingUtil { 8 | 9 | int get_type_priority(ASR::ttypeType type); 10 | 11 | int get_src_dest(ASR::expr_t* left_expr, ASR::expr_t* right_expr, 12 | ASR::expr_t*& src_expr, ASR::expr_t*& dest_expr, 13 | ASR::ttype_t*& src_type, ASR::ttype_t*& dest_type, 14 | bool is_assign); 15 | 16 | ASR::expr_t* perform_casting(ASR::expr_t* expr, ASR::ttype_t* src, 17 | ASR::ttype_t* dest, Allocator& al, 18 | const Location& loc); 19 | } 20 | 21 | #endif // LFORTRAN_CASTING_UTILS_H 22 | -------------------------------------------------------------------------------- /src/libasr/codegen/KaleidoscopeJIT.h: -------------------------------------------------------------------------------- 1 | //===- KaleidoscopeJIT.h - A simple JIT for Kaleidoscope --------*- C++ -*-===// 2 | // 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 | // See https://llvm.org/LICENSE.txt for license information. 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 | // 7 | //===----------------------------------------------------------------------===// 8 | // 9 | // Contains a simple JIT definition for use in the kaleidoscope tutorials. 10 | // 11 | //===----------------------------------------------------------------------===// 12 | 13 | #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H 14 | #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H 15 | 16 | #include "llvm/ADT/StringRef.h" 17 | #include "llvm/ExecutionEngine/JITSymbol.h" 18 | #include "llvm/ExecutionEngine/Orc/CompileUtils.h" 19 | #include "llvm/ExecutionEngine/Orc/Core.h" 20 | #include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" 21 | #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" 22 | #include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" 23 | #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" 24 | #include "llvm/ExecutionEngine/SectionMemoryManager.h" 25 | #include "llvm/IR/DataLayout.h" 26 | #include "llvm/IR/LLVMContext.h" 27 | #include 28 | 29 | #if LLVM_VERSION_MAJOR >= 16 30 | # define RM_OPTIONAL_TYPE std::optional 31 | #else 32 | # define RM_OPTIONAL_TYPE llvm::Optional 33 | #endif 34 | 35 | namespace llvm { 36 | namespace orc { 37 | 38 | class KaleidoscopeJIT { 39 | private: 40 | ExecutionSession ES; 41 | RTDyldObjectLinkingLayer ObjectLayer; 42 | IRCompileLayer CompileLayer; 43 | 44 | DataLayout DL; 45 | MangleAndInterner Mangle; 46 | ThreadSafeContext Ctx; 47 | JITDylib &JITDL; 48 | 49 | TargetMachine *TM; 50 | 51 | public: 52 | KaleidoscopeJIT(JITTargetMachineBuilder JTMB, DataLayout DL) 53 | : 54 | #if LLVM_VERSION_MAJOR >= 13 55 | ES(cantFail(SelfExecutorProcessControl::Create())), 56 | #endif 57 | ObjectLayer(ES, 58 | []() { return std::make_unique(); }), 59 | CompileLayer(ES, ObjectLayer, std::make_unique(ConcurrentIRCompiler(std::move(JTMB)))), 60 | DL(std::move(DL)), Mangle(ES, this->DL), 61 | Ctx(std::make_unique()), 62 | JITDL( 63 | #if LLVM_VERSION_MAJOR >= 11 64 | cantFail 65 | #endif 66 | (ES.createJITDylib("Main"))) { 67 | JITDL.addGenerator( 68 | cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( 69 | DL.getGlobalPrefix()))); 70 | 71 | std::string Error; 72 | auto TargetTriple = sys::getDefaultTargetTriple(); 73 | auto Target = TargetRegistry::lookupTarget(TargetTriple, Error); 74 | if (!Target) { 75 | throw std::runtime_error("Failed to lookup the target"); 76 | } 77 | auto CPU = "generic"; 78 | auto Features = ""; 79 | TargetOptions opt; 80 | auto RM = RM_OPTIONAL_TYPE(); 81 | TM = Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM); 82 | } 83 | 84 | static Expected> Create() { 85 | auto JTMB = JITTargetMachineBuilder::detectHost(); 86 | 87 | if (!JTMB) 88 | return JTMB.takeError(); 89 | 90 | auto DL = JTMB->getDefaultDataLayoutForTarget(); 91 | if (!DL) 92 | return DL.takeError(); 93 | 94 | return std::make_unique(std::move(*JTMB), std::move(*DL)); 95 | } 96 | 97 | const DataLayout &getDataLayout() const { return DL; } 98 | 99 | LLVMContext &getContext() { return *Ctx.getContext(); } 100 | 101 | Error addModule(std::unique_ptr M) { 102 | return CompileLayer.add(JITDL, 103 | ThreadSafeModule(std::move(M), Ctx)); 104 | } 105 | 106 | Expected lookup(StringRef Name) { 107 | return ES.lookup({&JITDL}, Mangle(Name.str())); 108 | } 109 | 110 | TargetMachine &getTargetMachine() { return *TM; } 111 | }; 112 | 113 | } // end namespace orc 114 | } // end namespace llvm 115 | 116 | #endif // LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H 117 | -------------------------------------------------------------------------------- /src/libasr/codegen/asr_to_c.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_ASR_TO_C_H 2 | #define LFORTRAN_ASR_TO_C_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | Result asr_to_c(Allocator &al, ASR::TranslationUnit_t &asr, 10 | diag::Diagnostics &diagnostics, CompilerOptions &co, 11 | int64_t default_lower_bound); 12 | 13 | } // namespace LCompilers 14 | 15 | #endif // LFORTRAN_ASR_TO_C_H 16 | -------------------------------------------------------------------------------- /src/libasr/codegen/asr_to_cpp.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_ASR_TO_CPP_H 2 | #define LFORTRAN_ASR_TO_CPP_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | Result asr_to_cpp(Allocator &al, ASR::TranslationUnit_t &asr, 10 | diag::Diagnostics &diagnostics, CompilerOptions &co, 11 | int64_t default_lower_bound); 12 | 13 | } // namespace LCompilers 14 | 15 | #endif // LFORTRAN_ASR_TO_CPP_H 16 | -------------------------------------------------------------------------------- /src/libasr/codegen/asr_to_fortran.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_ASR_TO_FORTRAN_H 2 | #define LFORTRAN_ASR_TO_FORTRAN_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | // Converts ASR to Fortran source code 10 | Result asr_to_fortran(ASR::TranslationUnit_t &asr, 11 | diag::Diagnostics &diagnostics, bool color, int indent); 12 | 13 | } // namespace LCompilers 14 | 15 | #endif // LFORTRAN_ASR_TO_FORTRAN_H 16 | -------------------------------------------------------------------------------- /src/libasr/codegen/asr_to_julia.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_ASR_TO_JULIA_H 2 | #define LFORTRAN_ASR_TO_JULIA_H 3 | 4 | #include 5 | #include 6 | #include 7 | // #include 8 | 9 | namespace LCompilers { 10 | 11 | Result 12 | asr_to_julia(Allocator& al, ASR::TranslationUnit_t& asr, diag::Diagnostics& diag); 13 | 14 | } // namespace LCompilers 15 | 16 | #endif // LFORTRAN_ASR_TO_JULIA_H 17 | -------------------------------------------------------------------------------- /src/libasr/codegen/asr_to_llvm.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_ASR_TO_LLVM_H 2 | #define LFORTRAN_ASR_TO_LLVM_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace LCompilers { 9 | 10 | Result> asr_to_llvm(ASR::TranslationUnit_t &asr, 11 | diag::Diagnostics &diagnostics, 12 | llvm::LLVMContext &context, Allocator &al, 13 | LCompilers::PassManager& pass_manager, 14 | CompilerOptions &compiler_options, 15 | const std::string &run_fn, 16 | const std::string &infile); 17 | 18 | } // namespace LCompilers 19 | 20 | #endif // LFORTRAN_ASR_TO_LLVM_H 21 | -------------------------------------------------------------------------------- /src/libasr/codegen/asr_to_py.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_ASR_TO_PY_H 2 | #define LFORTRAN_ASR_TO_PY_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | std::tuple asr_to_py(ASR::TranslationUnit_t &asr, bool c_order, std::string chdr_filename); 10 | 11 | } // namespace LCompilers 12 | 13 | #endif // LFORTRAN_ASR_TO_PY_H 14 | -------------------------------------------------------------------------------- /src/libasr/codegen/asr_to_wasm.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_ASR_TO_WASM_H 2 | #define LFORTRAN_ASR_TO_WASM_H 3 | 4 | #include 5 | 6 | namespace LCompilers { 7 | 8 | // Generates a wasm binary stream from ASR 9 | Result> asr_to_wasm_bytes_stream(ASR::TranslationUnit_t &asr, 10 | Allocator &al, 11 | diag::Diagnostics &diagnostics, 12 | CompilerOptions &co); 13 | 14 | // Generates a wasm binary to `filename` 15 | Result asr_to_wasm(ASR::TranslationUnit_t &asr, Allocator &al, 16 | const std::string &filename, bool time_report, 17 | diag::Diagnostics &diagnostics, CompilerOptions &co); 18 | 19 | } // namespace LCompilers 20 | 21 | #endif // LFORTRAN_ASR_TO_WASM_H 22 | -------------------------------------------------------------------------------- /src/libasr/codegen/asr_to_x86.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_ASR_TO_X86_H 2 | #define LFORTRAN_ASR_TO_X86_H 3 | 4 | #include 5 | 6 | namespace LCompilers { 7 | 8 | // Generates a 32-bit x86 Linux executable binary `filename` 9 | Result asr_to_x86(ASR::TranslationUnit_t &asr, Allocator &al, 10 | const std::string &filename, bool time_report, 11 | diag::Diagnostics &diagnostics); 12 | 13 | } // namespace LCompilers 14 | 15 | #endif // LFORTRAN_ASR_TO_X86_H 16 | -------------------------------------------------------------------------------- /src/libasr/codegen/evaluator.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_EVALUATOR_H 2 | #define LFORTRAN_EVALUATOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | // Forward declare all needed LLVM classes without importing any LLVM header 14 | // files. Those are only imported in evaluator.cpp and nowhere else, to speed 15 | // up compilation. 16 | namespace llvm { 17 | class ExecutionEngine; 18 | class LLVMContext; 19 | class Module; 20 | class Function; 21 | class TargetMachine; 22 | namespace orc { 23 | class KaleidoscopeJIT; 24 | } 25 | } 26 | 27 | namespace LCompilers { 28 | 29 | class LLVMModule 30 | { 31 | public: 32 | std::unique_ptr m_m; 33 | LLVMModule(std::unique_ptr m); 34 | ~LLVMModule(); 35 | std::string str(); 36 | // Return a function return type as a string (real / integer) 37 | std::string get_return_type(const std::string &fn_name); 38 | }; 39 | 40 | class LLVMEvaluator 41 | { 42 | private: 43 | std::unique_ptr jit; 44 | std::unique_ptr context; 45 | std::string target_triple; 46 | llvm::TargetMachine *TM; 47 | public: 48 | LLVMEvaluator(const std::string &t = ""); 49 | ~LLVMEvaluator(); 50 | std::unique_ptr parse_module(const std::string &source); 51 | void add_module(const std::string &source); 52 | void add_module(std::unique_ptr mod); 53 | void add_module(std::unique_ptr m); 54 | intptr_t get_symbol_address(const std::string &name); 55 | int32_t int32fn(const std::string &name); 56 | int64_t int64fn(const std::string &name); 57 | bool boolfn(const std::string &name); 58 | float floatfn(const std::string &name); 59 | double doublefn(const std::string &name); 60 | std::complex complex4fn(const std::string &name); 61 | std::complex complex8fn(const std::string &name); 62 | void voidfn(const std::string &name); 63 | std::string get_asm(llvm::Module &m); 64 | void save_asm_file(llvm::Module &m, const std::string &filename); 65 | void save_object_file(llvm::Module &m, const std::string &filename); 66 | void create_empty_object_file(const std::string &filename); 67 | void opt(llvm::Module &m); 68 | static std::string module_to_string(llvm::Module &m); 69 | static void print_version_message(); 70 | llvm::LLVMContext &get_context(); 71 | static void print_targets(); 72 | static std::string get_default_target_triple(); 73 | }; 74 | 75 | 76 | } // namespace LCompilers 77 | 78 | #endif // LFORTRAN_EVALUATOR_H 79 | -------------------------------------------------------------------------------- /src/libasr/codegen/wasm_to_wat.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_WASM_TO_WAT_H 2 | #define LFORTRAN_WASM_TO_WAT_H 3 | 4 | #include 5 | 6 | namespace LCompilers { 7 | 8 | Result wasm_to_wat(Vec &wasm_bytes, Allocator &al, 9 | diag::Diagnostics &diagnostics); 10 | 11 | } // namespace LCompilers 12 | 13 | #endif // LFORTRAN_WASM_TO_WAT_H 14 | -------------------------------------------------------------------------------- /src/libasr/codegen/wasm_to_x64.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_WASM_TO_X64_H 2 | #define LFORTRAN_WASM_TO_X64_H 3 | 4 | #include 5 | 6 | namespace LCompilers { 7 | 8 | Result wasm_to_x64(Vec &wasm_bytes, Allocator &al, 9 | const std::string &filename, bool time_report, 10 | diag::Diagnostics &diagnostics); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_WASM_TO_X64_H 15 | -------------------------------------------------------------------------------- /src/libasr/codegen/wasm_to_x86.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_WASM_TO_X86_H 2 | #define LFORTRAN_WASM_TO_X86_H 3 | 4 | #include 5 | 6 | namespace LCompilers { 7 | 8 | Result wasm_to_x86(Vec &wasm_bytes, Allocator &al, 9 | const std::string &filename, bool time_report, 10 | diag::Diagnostics &diagnostics); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_WASM_TO_X86_H 15 | -------------------------------------------------------------------------------- /src/libasr/codegen/wasm_utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace LCompilers { 4 | 5 | namespace wasm { 6 | 7 | void encode_leb128_u32(Vec &code, Allocator &al, uint32_t n) { 8 | do { 9 | uint8_t byte = n & 0x7f; 10 | n >>= 7; 11 | if (n != 0) { 12 | byte |= 0x80; 13 | } 14 | code.push_back(al, byte); 15 | } while (n != 0); 16 | } 17 | 18 | uint32_t decode_leb128_u32(Vec &code, uint32_t &offset) { 19 | uint32_t result = 0U; 20 | uint32_t shift = 0U; 21 | while (true) { 22 | uint8_t byte = read_b8(code, offset); 23 | uint32_t slice = byte & 0x7f; 24 | result |= slice << shift; 25 | if ((byte & 0x80) == 0) { 26 | return result; 27 | } 28 | shift += 7; 29 | } 30 | } 31 | 32 | void encode_leb128_i32(Vec &code, Allocator &al, int32_t n) { 33 | bool more = true; 34 | do { 35 | uint8_t byte = n & 0x7f; 36 | n >>= 7; 37 | more = !((((n == 0) && ((byte & 0x40) == 0)) || 38 | ((n == -1) && ((byte & 0x40) != 0)))); 39 | if (more) { 40 | byte |= 0x80; 41 | } 42 | code.push_back(al, byte); 43 | } while (more); 44 | } 45 | 46 | int32_t decode_leb128_i32(Vec &code, uint32_t &offset) { 47 | int32_t result = 0; 48 | uint32_t shift = 0U; 49 | uint8_t byte; 50 | 51 | do { 52 | byte = read_b8(code, offset); 53 | uint32_t slice = byte & 0x7f; 54 | result |= slice << shift; 55 | shift += 7; 56 | } while (byte & 0x80); 57 | 58 | // Sign extend negative numbers if needed. 59 | if ((shift < 32U) && (byte & 0x40)) { 60 | result |= (-1U << shift); 61 | } 62 | 63 | return result; 64 | } 65 | 66 | void encode_leb128_i64(Vec &code, Allocator &al, int64_t n) { 67 | bool more = true; 68 | do { 69 | uint8_t byte = n & 0x7f; 70 | n >>= 7; 71 | more = !((((n == 0) && ((byte & 0x40) == 0)) || 72 | ((n == -1) && ((byte & 0x40) != 0)))); 73 | if (more) { 74 | byte |= 0x80; 75 | } 76 | code.push_back(al, byte); 77 | } while (more); 78 | } 79 | 80 | int64_t decode_leb128_i64(Vec &code, uint32_t &offset) { 81 | int64_t result = 0; 82 | uint32_t shift = 0U; 83 | uint8_t byte; 84 | 85 | do { 86 | byte = read_b8(code, offset); 87 | uint64_t slice = byte & 0x7f; 88 | result |= slice << shift; 89 | shift += 7; 90 | } while (byte & 0x80); 91 | 92 | // Sign extend negative numbers if needed. 93 | if ((shift < 64U) && (byte & 0x40)) { 94 | result |= (-1ULL << shift); 95 | } 96 | 97 | return result; 98 | } 99 | 100 | void encode_ieee754_f32(Vec &code, Allocator &al, float z) { 101 | uint8_t encoded_float[sizeof(z)]; 102 | std::memcpy(&encoded_float, &z, sizeof(z)); 103 | for (auto &byte : encoded_float) { 104 | code.push_back(al, byte); 105 | } 106 | } 107 | 108 | float decode_ieee754_f32(Vec &code, uint32_t &offset) { 109 | float value = 0.0; 110 | std::memcpy(&value, &code.p[offset], sizeof(value)); 111 | offset += sizeof(value); 112 | return value; 113 | } 114 | 115 | void encode_ieee754_f64(Vec &code, Allocator &al, double z) { 116 | uint8_t encoded_float[sizeof(z)]; 117 | std::memcpy(&encoded_float, &z, sizeof(z)); 118 | for (auto &byte : encoded_float) { 119 | code.push_back(al, byte); 120 | } 121 | } 122 | 123 | double decode_ieee754_f64(Vec &code, uint32_t &offset) { 124 | double value = 0.0; 125 | std::memcpy(&value, &code.p[offset], sizeof(value)); 126 | offset += sizeof(value); 127 | return value; 128 | } 129 | 130 | // function to append a given bytecode to the end of the code 131 | void emit_b8(Vec &code, Allocator &al, uint8_t x) { 132 | code.push_back(al, x); 133 | } 134 | 135 | // function to emit unsigned 32 bit integer 136 | void emit_u32(Vec &code, Allocator &al, uint32_t x) { 137 | encode_leb128_u32(code, al, x); 138 | } 139 | 140 | // function to emit signed 32 bit integer 141 | void emit_i32(Vec &code, Allocator &al, int32_t x) { 142 | encode_leb128_i32(code, al, x); 143 | } 144 | 145 | // function to emit signed 64 bit integer 146 | void emit_i64(Vec &code, Allocator &al, int64_t x) { 147 | encode_leb128_i64(code, al, x); 148 | } 149 | 150 | // function to emit 32 bit float 151 | void emit_f32(Vec &code, Allocator &al, float x) { 152 | encode_ieee754_f32(code, al, x); 153 | } 154 | 155 | // function to emit 64 bit float 156 | void emit_f64(Vec &code, Allocator &al, double x) { 157 | encode_ieee754_f64(code, al, x); 158 | } 159 | 160 | uint8_t read_b8(Vec &code, uint32_t &offset) { 161 | LCOMPILERS_ASSERT(offset < code.size()); 162 | return code.p[offset++]; 163 | } 164 | 165 | float read_f32(Vec &code, uint32_t &offset) { 166 | LCOMPILERS_ASSERT(offset + sizeof(float) <= code.size()); 167 | return decode_ieee754_f32(code, offset); 168 | } 169 | 170 | double read_f64(Vec &code, uint32_t &offset) { 171 | LCOMPILERS_ASSERT(offset + sizeof(double) <= code.size()); 172 | return decode_ieee754_f64(code, offset); 173 | } 174 | 175 | uint32_t read_u32(Vec &code, uint32_t &offset) { 176 | return decode_leb128_u32(code, offset); 177 | } 178 | 179 | int32_t read_i32(Vec &code, uint32_t &offset) { 180 | return decode_leb128_i32(code, offset); 181 | } 182 | 183 | int64_t read_i64(Vec &code, uint32_t &offset) { 184 | return decode_leb128_i64(code, offset); 185 | } 186 | 187 | void hexdump(void *ptr, int buflen) { 188 | unsigned char *buf = (unsigned char *)ptr; 189 | int i, j; 190 | for (i = 0; i < buflen; i += 16) { 191 | printf("%06x: ", i); 192 | for (j = 0; j < 16; j++) { 193 | if (i + j < buflen) 194 | printf("%02x ", buf[i + j]); 195 | else 196 | printf(" "); 197 | } 198 | printf(" "); 199 | for (j = 0; j < 16; j++) { 200 | if (i + j < buflen) 201 | printf("%c", isprint(buf[i + j]) ? buf[i + j] : '.'); 202 | } 203 | printf("\n"); 204 | } 205 | } 206 | 207 | } // namespace wasm 208 | 209 | } // namespace LCompilers 210 | -------------------------------------------------------------------------------- /src/libasr/codegen/wasm_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_WASM_UTILS_H 2 | #define LFORTRAN_WASM_UTILS_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | namespace LCompilers { 11 | 12 | namespace wasm { 13 | 14 | enum var_type: uint8_t { 15 | i32 = 0x7F, 16 | i64 = 0x7E, 17 | f32 = 0x7D, 18 | f64 = 0x7C 19 | }; 20 | 21 | enum mem_align : uint8_t { 22 | b8 = 0, 23 | b16 = 1, 24 | b32 = 2, 25 | b64 = 3 26 | }; 27 | 28 | enum wasm_kind: uint8_t { 29 | func = 0x00, 30 | table = 0x01, 31 | memory = 0x02, 32 | global = 0x03 33 | }; 34 | 35 | template 36 | std::string vt2s(T vt) { 37 | switch(vt) { 38 | case var_type::i32: return "i32"; 39 | case var_type::i64: return "i64"; 40 | case var_type::f32: return "f32"; 41 | case var_type::f64: return "f64"; 42 | default: 43 | std::cerr << "Unsupported wasm var_type" << std::endl; 44 | LCOMPILERS_ASSERT(false); 45 | return ""; 46 | 47 | } 48 | } 49 | 50 | template 51 | std::string k2s(T k) { 52 | switch(k) { 53 | case wasm_kind::func: return "func"; 54 | case wasm_kind::table: return "table"; 55 | case wasm_kind::memory: return "memory"; 56 | case wasm_kind::global: return "global"; 57 | default: 58 | std::cerr << "Unsupported wasm kind" << std::endl; 59 | LCOMPILERS_ASSERT(false); 60 | return ""; 61 | } 62 | } 63 | 64 | struct FuncType { 65 | Vec param_types; 66 | Vec result_types; 67 | }; 68 | 69 | struct Global { 70 | uint8_t type; 71 | uint8_t mut; 72 | uint32_t insts_start_idx; 73 | union { 74 | int32_t n32; 75 | int64_t n64; 76 | float r32; 77 | double r64; 78 | }; 79 | }; 80 | 81 | struct Export { 82 | std::string name; 83 | uint8_t kind; 84 | uint32_t index; 85 | }; 86 | 87 | struct Local { 88 | uint32_t count; 89 | uint8_t type; 90 | }; 91 | 92 | struct Code { 93 | int size; 94 | Vec locals; 95 | uint32_t insts_start_index; 96 | }; 97 | 98 | struct Import { 99 | std::string mod_name; 100 | std::string name; 101 | uint8_t kind; 102 | union { 103 | uint32_t type_idx; 104 | std::pair mem_page_size_limits; 105 | }; 106 | }; 107 | 108 | struct Data { 109 | uint32_t insts_start_index; 110 | std::string text; 111 | }; 112 | 113 | void encode_leb128_u32(Vec &code, Allocator &al, uint32_t n); 114 | uint32_t decode_leb128_u32(Vec &code, uint32_t &offset); 115 | 116 | void encode_leb128_i32(Vec &code, Allocator &al, int32_t n); 117 | int32_t decode_leb128_i32(Vec &code, uint32_t &offset); 118 | 119 | void encode_leb128_i64(Vec &code, Allocator &al, int64_t n); 120 | int64_t decode_leb128_i64(Vec &code, uint32_t &offset); 121 | 122 | void encode_ieee754_f32(Vec &code, Allocator &al, float z); 123 | float decode_ieee754_f32(Vec &code, uint32_t &offset); 124 | 125 | void encode_ieee754_f64(Vec &code, Allocator &al, double z); 126 | double decode_ieee754_f64(Vec &code, uint32_t &offset); 127 | 128 | void emit_b8(Vec &code, Allocator &al, uint8_t x); 129 | void emit_u32(Vec &code, Allocator &al, uint32_t x); 130 | void emit_i32(Vec &code, Allocator &al, int32_t x); 131 | void emit_i64(Vec &code, Allocator &al, int64_t x); 132 | void emit_f32(Vec &code, Allocator &al, float x); 133 | void emit_f64(Vec &code, Allocator &al, double x); 134 | 135 | uint8_t read_b8(Vec &code, uint32_t &offset); 136 | float read_f32(Vec &code, uint32_t &offset); 137 | double read_f64(Vec &code, uint32_t &offset); 138 | uint32_t read_u32(Vec &code, uint32_t &offset); 139 | int32_t read_i32(Vec &code, uint32_t &offset); 140 | int64_t read_i64(Vec &code, uint32_t &offset); 141 | 142 | void hexdump(void *ptr, int buflen); 143 | 144 | } // namespace wasm 145 | 146 | } // namespace LCompilers 147 | 148 | #endif // LFORTRAN_WASM_UTILS_H 149 | -------------------------------------------------------------------------------- /src/libasr/colors.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_COLORS_H 2 | #define LFORTRAN_COLORS_H 3 | 4 | namespace LCompilers { 5 | 6 | enum class style { 7 | reset = 0, 8 | bold = 1, 9 | dim = 2, 10 | italic = 3, 11 | underline = 4, 12 | blink = 5, 13 | rblink = 6, 14 | reversed = 7, 15 | conceal = 8, 16 | crossed = 9 17 | }; 18 | 19 | enum class fg { 20 | black = 30, 21 | red = 31, 22 | green = 32, 23 | yellow = 33, 24 | blue = 34, 25 | magenta = 35, 26 | cyan = 36, 27 | gray = 37, 28 | reset = 39 29 | }; 30 | 31 | enum class bg { 32 | black = 40, 33 | red = 41, 34 | green = 42, 35 | yellow = 43, 36 | blue = 44, 37 | magenta = 45, 38 | cyan = 46, 39 | gray = 47, 40 | reset = 49 41 | }; 42 | 43 | enum class fgB { 44 | black = 90, 45 | red = 91, 46 | green = 92, 47 | yellow = 93, 48 | blue = 94, 49 | magenta = 95, 50 | cyan = 96, 51 | gray = 97 52 | }; 53 | 54 | enum class bgB { 55 | black = 100, 56 | red = 101, 57 | green = 102, 58 | yellow = 103, 59 | blue = 104, 60 | magenta = 105, 61 | cyan = 106, 62 | gray = 107 63 | }; 64 | 65 | 66 | template 67 | std::string color(T const value) 68 | { 69 | return "\033[" + std::to_string(static_cast(value)) + "m"; 70 | } 71 | 72 | 73 | } // namespace LCompilers 74 | 75 | #endif // LFORTRAN_COLORS_H 76 | -------------------------------------------------------------------------------- /src/libasr/compiler_tester/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lcompilers/libasr/1846ff617fe93a6e64c0bb0d5a38b9c3c112cf5d/src/libasr/compiler_tester/__init__.py -------------------------------------------------------------------------------- /src/libasr/config.h.in: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_CONFIG_H 2 | #define LFORTRAN_CONFIG_H 3 | 4 | /* Define if you want to enable ASSERT testing in LFortran */ 5 | #cmakedefine WITH_LFORTRAN_ASSERT 6 | 7 | /* LFortran version */ 8 | #cmakedefine LFORTRAN_VERSION "@LFORTRAN_VERSION@" 9 | 10 | /* Define if LLVM is enabled */ 11 | #cmakedefine HAVE_LFORTRAN_LLVM 12 | 13 | /* Define if RAPIDJSON is found */ 14 | #cmakedefine HAVE_LFORTRAN_RAPIDJSON 15 | 16 | /* Define if stacktrace is enabled */ 17 | #cmakedefine HAVE_LFORTRAN_STACKTRACE 18 | #cmakedefine HAVE_RUNTIME_STACKTRACE 19 | #cmakedefine HAVE_LFORTRAN_BFD 20 | #cmakedefine HAVE_LFORTRAN_DWARFDUMP 21 | #cmakedefine HAVE_LFORTRAN_LINK 22 | #cmakedefine HAVE_LFORTRAN_MACHO 23 | #cmakedefine HAVE_LFORTRAN_UNWIND 24 | 25 | /* Define if cxxabi.h is present */ 26 | #cmakedefine HAVE_LFORTRAN_DEMANGLE 27 | 28 | /* Define if XEUS is enabled */ 29 | #cmakedefine HAVE_LFORTRAN_XEUS 30 | 31 | /* Define if we should use binary modfiles */ 32 | #cmakedefine WITH_LFORTRAN_BINARY_MODFILES 33 | 34 | #endif // LFORTRAN_CONFIG_H 35 | -------------------------------------------------------------------------------- /src/libasr/dat_convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from struct import unpack 4 | from sys import argv 5 | from re import sub 6 | 7 | lines = "" 8 | with open(argv[1], "rb") as f: 9 | lines = f.read() 10 | 11 | list = [] 12 | for i in range(0, len(lines), 24): 13 | list.append(sub('[(),]', '', str(unpack("3Q", lines[i:i+24])))) 14 | 15 | with open(argv[1] + ".txt", "w") as f: 16 | j = 0 17 | for i in list: 18 | f.write(i+'\n') 19 | -------------------------------------------------------------------------------- /src/libasr/dwarf_convert.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | This script is used to convert the output of dwarfdump into a file that is easy 5 | to load into lfortran to lookup filenames and line numbers for a given address. 6 | Here is how to use it: 7 | 8 | cd src/bin 9 | llvm-dwarfdump --debug-line lfortran.dSYM > lfortran.dSYM/symbols.txt 10 | ./dwarf_convert.py lfortran.dSYM/symbols.txt lfortran.dSYM/lines.txt lfortran.dSYM/lines.dat 11 | 12 | This is meant to be executed at build time. 13 | 14 | A better solution would be to use the `dwarf` library directly from C++ and 15 | generate the same output directly. Here is the source code of llvm-dwarfdump: 16 | 17 | https://github.com/llvm/llvm-project/blob/91a6ad5ad887a16e361338303d4ff3d29dba5e10/llvm/tools/llvm-dwarfdump/llvm-dwarfdump.cpp 18 | 19 | We just have to do exactly what it does, but generate the output in the format 20 | of lines.txt and lines.dat 21 | 22 | """ 23 | 24 | from collections import namedtuple 25 | from glob import glob 26 | import os 27 | import re 28 | from struct import pack 29 | import sys 30 | 31 | DebugLines = namedtuple("DebugLines", ["lines"]) 32 | DebugLine = namedtuple("DebugLine", ["include_directories", "file_names", "addresses"]) 33 | IncludeDirectory = namedtuple("IncludeDirectory", ["id", "path"]) 34 | FileName = namedtuple("FileName", ["id", "filename", "dir_idx"]) 35 | 36 | ASRDebugLines = namedtuple("ASRDebugLines", ["filenames", "addresses"]) 37 | 38 | class Parser: 39 | """ 40 | Parser for the output generated by dwarfdump. 41 | 42 | On macOS (both Intel and ARM based): 43 | 44 | dwarfdump --debug-line src/bin/lfortran.dSYM > symbols.txt 45 | 46 | Then parse it using: 47 | 48 | p = Parser() 49 | ast = p.parse_file("symbols.txt") 50 | """ 51 | 52 | def parse_file(self, filename): 53 | self.file = open(filename) 54 | self.line = self.file.readline() 55 | while not self.line.startswith(".debug_line contents:"): 56 | self.line = self.file.readline() 57 | 58 | self.line = self.file.readline() 59 | lines = [] 60 | while self.line.startswith("debug_line"): 61 | d = self.parse_debug_line() 62 | lines.append(d) 63 | return DebugLines(lines) 64 | 65 | def parse_debug_line(self): 66 | self.line = self.file.readline() 67 | include_dirs_found = True 68 | while not self.line.startswith("include_directories"): 69 | if self.line.startswith("file_names"): 70 | include_dirs_found = False 71 | break 72 | else: 73 | self.line = self.file.readline() 74 | 75 | include_directories = [] 76 | if include_dirs_found: 77 | while self.line.startswith("include_directories"): 78 | n, path = re.compile(r"include_directories\[[ ]*(\d+)\] = \"([^\"]+)\"").findall(self.line)[0] 79 | n = int(n) 80 | include_directories.append(IncludeDirectory(n, path)) 81 | self.line = self.file.readline() 82 | 83 | file_names = [] 84 | while self.line.startswith("file_names"): 85 | n = re.compile(r"file_names\[[ ]*(\d+)\]:").findall(self.line)[0] 86 | n = int(n) 87 | 88 | self.line = self.file.readline() 89 | filename = re.compile(r"name: \"([^\"]+)\"").findall(self.line)[0] 90 | 91 | self.line = self.file.readline() 92 | dir_idx = re.compile(r"dir_index: (\d+)").findall(self.line)[0] 93 | dir_idx = int(dir_idx) 94 | 95 | self.line = self.file.readline() 96 | self.line = self.file.readline() 97 | 98 | file_names.append(FileName(n, filename, dir_idx)) 99 | 100 | self.line = self.file.readline() 101 | 102 | self.line = self.file.readline() 103 | self.line = self.file.readline() 104 | self.line = self.file.readline() 105 | 106 | addresses = [] 107 | while self.line.startswith("0x"): 108 | address, line, column, file_id = self.line.split()[:4] 109 | address = int(address, base=16) 110 | line = int(line) 111 | column = int(column) 112 | file_id = int(file_id) 113 | addresses.append([address, line, column, file_id]) 114 | self.line = self.file.readline() 115 | 116 | self.line = self.file.readline() 117 | 118 | d = DebugLine(include_directories, file_names, addresses) 119 | return d 120 | 121 | def ast_to_asr(ast): 122 | local_files = glob("../**/*.cpp", recursive=True) + \ 123 | glob("../**/*.h", recursive=True) 124 | for i in range(len(local_files)): 125 | local_files[i] = os.path.abspath(local_files[i]) 126 | def make_abs(end_path): 127 | if end_path[0] != "/": 128 | for f in local_files: 129 | if f.endswith(end_path): 130 | return f 131 | return end_path 132 | lines = [] 133 | last_address = -1 134 | global_filename_id = 0 135 | global_filenames = [] 136 | global_addresses = [] 137 | for line in ast.lines: 138 | include_dirs = {} 139 | for inc in line.include_directories: 140 | include_dirs[inc.id] = inc.path 141 | filenames = {} 142 | for filename in line.file_names: 143 | prefix = "" 144 | if filename.dir_idx != 0: 145 | prefix = include_dirs[filename.dir_idx] + "/" 146 | filenames[filename.id] = global_filename_id 147 | global_filenames.append(make_abs(prefix+filename.filename)) 148 | global_filename_id += 1 149 | for address, line_num, column, file_id in line.addresses: 150 | filename = global_filenames[filenames[file_id]] 151 | assert last_address <= address 152 | last_address = address 153 | if line_num != 0: 154 | global_addresses.append([address, line_num, filenames[file_id]]) 155 | return ASRDebugLines(global_filenames, global_addresses) 156 | 157 | 158 | p = Parser() 159 | ast = p.parse_file(sys.argv[1]) 160 | asr = ast_to_asr(ast) 161 | with open(sys.argv[2], "w") as f: 162 | f.write(str(len(asr.filenames)) + "\n") 163 | for filename in asr.filenames: 164 | f.write(filename + "\n") 165 | f.write(str(len(asr.addresses)) + "\n") 166 | with open(sys.argv[3], "wb") as f: 167 | for addr, line, fileid in asr.addresses: 168 | f.write(pack("3Q", addr, line, fileid)) 169 | -------------------------------------------------------------------------------- /src/libasr/exception.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_EXCEPTION_H 2 | #define LFORTRAN_EXCEPTION_H 3 | 4 | #ifdef __cplusplus 5 | extern "C" { 6 | #endif 7 | 8 | typedef enum { 9 | LFORTRAN_NO_EXCEPTION = 0, 10 | LFORTRAN_RUNTIME_ERROR = 1, 11 | LFORTRAN_EXCEPTION = 2, 12 | LFORTRAN_PARSER_ERROR = 4, 13 | LFORTRAN_ASSERT_FAILED = 7, 14 | LFORTRAN_ASSEMBLER_ERROR = 8, 15 | } lfortran_exceptions_t; 16 | 17 | #ifdef __cplusplus 18 | } 19 | #endif 20 | 21 | 22 | #ifdef __cplusplus 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | namespace LCompilers { 32 | 33 | /* 34 | This Error structure is returned in Result when failure happens. 35 | 36 | The diagnostic messages contain warnings and error(s). In the past when 37 | just one error was returned, it made sense to return it as part of the 38 | Error structure in Result. However now when warnings are also reported, 39 | those we want to return in any case. Also since multiple errors can be 40 | reported, they are now storted independently of the exception that is 41 | internally used to abort the analysis (typically a visitor pattern). 42 | 43 | For the above reasons the diagnostic messages are now returned as an 44 | argument, independently of the Result, and they can contain messages on 45 | success also. On failure they contain at least one error message (and in 46 | addition can contain warnings and more error messages). 47 | 48 | Consequently, we do not currently store anything in the Error structure 49 | below. 50 | */ 51 | struct Error { 52 | }; 53 | 54 | template 55 | struct Result { 56 | bool ok; 57 | union { 58 | T result; 59 | Error error; 60 | }; 61 | // Default constructor 62 | Result() = delete; 63 | // Success result constructor 64 | Result(const T &result) : ok{true}, result{result} {} 65 | // Error result constructor 66 | Result(const Error &error) : ok{false}, error{error} {} 67 | // Destructor 68 | ~Result() { 69 | if (!ok) { 70 | error.~Error(); 71 | } 72 | } 73 | // Copy constructor 74 | Result(const Result &other) : ok{other.ok} { 75 | if (ok) { 76 | new(&result) T(other.result); 77 | } else { 78 | new(&error) Error(other.error); 79 | } 80 | } 81 | // Copy assignment 82 | Result& operator=(const Result &other) { 83 | ok = other.ok; 84 | if (ok) { 85 | new(&result) T(other.result); 86 | } else { 87 | new(&error) Error(other.error); 88 | } 89 | return *this; 90 | } 91 | // Move constructor 92 | Result(T &&result) : ok{true}, result{std::move(result)} {} 93 | // Move assignment 94 | Result&& operator=(T &&other) = delete; 95 | }; 96 | 97 | 98 | const int stacktrace_depth = 4; 99 | 100 | class LCompilersException : public std::exception 101 | { 102 | std::string m_msg; 103 | lfortran_exceptions_t ec; 104 | std::vector m_stacktrace_addresses; 105 | public: 106 | LCompilersException(const std::string &msg, lfortran_exceptions_t error) 107 | : m_msg{msg}, ec{error}, m_stacktrace_addresses{get_stacktrace_addresses()} 108 | { } 109 | LCompilersException(const std::string &msg) 110 | : LCompilersException(msg, LFORTRAN_EXCEPTION) 111 | { 112 | } 113 | const char *what() const throw() 114 | { 115 | return m_msg.c_str(); 116 | } 117 | std::string msg() const 118 | { 119 | return m_msg; 120 | } 121 | std::string name() const 122 | { 123 | switch (ec) { 124 | case (lfortran_exceptions_t::LFORTRAN_EXCEPTION) : 125 | return "LCompilersException"; 126 | case (lfortran_exceptions_t::LFORTRAN_ASSERT_FAILED) : 127 | return "AssertFailed"; 128 | default : return "Unknown Exception"; 129 | } 130 | } 131 | std::vector stacktrace_addresses() const 132 | { 133 | return m_stacktrace_addresses; 134 | } 135 | lfortran_exceptions_t error_code() 136 | { 137 | return ec; 138 | } 139 | }; 140 | 141 | class AssertFailed : public LCompilersException 142 | { 143 | public: 144 | AssertFailed(const std::string &msg) 145 | : LCompilersException(msg, LFORTRAN_ASSERT_FAILED) 146 | { 147 | } 148 | }; 149 | 150 | class AssemblerError : public LCompilersException 151 | { 152 | public: 153 | AssemblerError(const std::string &msg) 154 | : LCompilersException(msg, LFORTRAN_ASSEMBLER_ERROR) 155 | { 156 | } 157 | }; 158 | 159 | template 160 | static inline T TRY(Result result) { 161 | if (result.ok) { 162 | return result.result; 163 | } else { 164 | throw LCompilersException("Internal Compiler Error: TRY failed, error was not handled explicitly"); 165 | } 166 | } 167 | 168 | 169 | } // namespace LCompilers 170 | 171 | #endif // __cplusplus 172 | #endif // LFORTRAN_EXCEPTION_H 173 | -------------------------------------------------------------------------------- /src/libasr/gen_pass.py: -------------------------------------------------------------------------------- 1 | passes = [ 2 | "replace_arr_slice", 3 | "replace_array_op", 4 | "replace_class_constructor", 5 | "dead_code_removal", 6 | "replace_div_to_mul", 7 | "replace_do_loops", 8 | "replace_flip_sign", 9 | "replace_fma", 10 | "replace_for_all", 11 | "wrap_global_stmts", 12 | "replace_implied_do_loops", 13 | "replace_init_expr", 14 | "inline_function_calls", 15 | "replace_symbolic", 16 | "replace_intrinsic_function", 17 | "loop_unroll", 18 | "loop_vectorise", 19 | "nested_vars", 20 | "replace_param_to_const", 21 | "array_by_data", 22 | "compare", 23 | "list_expr", 24 | "replace_print_arr", 25 | "replace_print_list_tuple", 26 | "replace_print_struct_type", 27 | "replace_select_case", 28 | "replace_sign_from_value", 29 | "create_subroutine_from_function", 30 | "transform_optional_argument_functions", 31 | "unused_functions", 32 | "update_array_dim_intrinsic_calls", 33 | "replace_where", 34 | "unique_symbols", 35 | "insert_deallocate" 36 | ] 37 | 38 | 39 | 40 | for name in passes: 41 | print(f"Processing: {name}") 42 | name_up = name.upper() 43 | header = rf"""#ifndef LIBASR_PASS_{name_up}_H 44 | #define LIBASR_PASS_{name_up}_H 45 | 46 | #include 47 | #include 48 | 49 | namespace LCompilers {{ 50 | 51 | void pass_{name}(Allocator &al, ASR::TranslationUnit_t &unit, 52 | const PassOptions &pass_options); 53 | 54 | }} // namespace LCompilers 55 | 56 | #endif // LIBASR_PASS_{name_up}_H 57 | """ 58 | header_filename = f"pass/{name}.h" 59 | f = open(header_filename, "w") 60 | f.write(header) 61 | -------------------------------------------------------------------------------- /src/libasr/lsp_interface.h: -------------------------------------------------------------------------------- 1 | #ifndef MESSAGE_HANDLER_HPP 2 | #define MESSAGE_HANDLER_HPP 3 | 4 | #include 5 | 6 | namespace LCompilers { 7 | 8 | struct error_highlight { 9 | std::string message; 10 | uint32_t first_line; 11 | uint32_t first_column; 12 | uint32_t last_line; 13 | uint32_t last_column; 14 | std::string filename; 15 | uint32_t severity; 16 | }; 17 | struct document_symbols { 18 | std::string symbol_name; 19 | uint32_t first_line; 20 | uint32_t first_column; 21 | uint32_t last_line; 22 | uint32_t last_column; 23 | std::string filename; 24 | }; 25 | 26 | } // namespace LCompilers 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/libasr/modfile.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | 11 | namespace LCompilers { 12 | 13 | const std::string lfortran_modfile_type_string = "LCompilers Modfile"; 14 | 15 | inline void save_asr(const ASR::TranslationUnit_t &m, std::string& asr_string) { 16 | #ifdef WITH_LFORTRAN_BINARY_MODFILES 17 | BinaryWriter b; 18 | #else 19 | TextWriter b; 20 | #endif 21 | // Header 22 | b.write_string(lfortran_modfile_type_string); 23 | b.write_string(LFORTRAN_VERSION); 24 | 25 | // AST section: Original module source code: 26 | // Currently empty. 27 | // Note: in the future we can save here: 28 | // * A path to the original source code 29 | // * Hash of the orig source code 30 | // * AST binary export of it (this AST only changes if the hash changes) 31 | 32 | // ASR section: 33 | 34 | // Export ASR: 35 | // Currently empty. 36 | 37 | // Full ASR: 38 | b.write_string(serialize(m)); 39 | 40 | asr_string = b.get_str(); 41 | } 42 | 43 | // The save_modfile() and load_modfile() must stay consistent. What is saved 44 | // must be loaded in exactly the same order. 45 | 46 | /* 47 | Saves the module into a binary stream. 48 | 49 | That stream can be saved to a mod file by the caller. 50 | The sections in the file/stream are saved using write_string(), so they 51 | can be efficiently read by the loader and ignored if needed. 52 | 53 | Comments below show some possible future improvements to the mod format. 54 | */ 55 | std::string save_modfile(const ASR::TranslationUnit_t &m) { 56 | LCOMPILERS_ASSERT(m.m_symtab->get_scope().size()== 1); 57 | for (auto &a : m.m_symtab->get_scope()) { 58 | LCOMPILERS_ASSERT(ASR::is_a(*a.second)); 59 | if ((bool&)a) { } // Suppress unused warning in Release mode 60 | } 61 | 62 | std::string asr_string; 63 | save_asr(m, asr_string); 64 | return asr_string; 65 | } 66 | 67 | std::string save_pycfile(const ASR::TranslationUnit_t &m) { 68 | std::string asr_string; 69 | save_asr(m, asr_string); 70 | return asr_string; 71 | } 72 | 73 | inline void load_serialised_asr(const std::string &s, std::string& asr_binary) { 74 | #ifdef WITH_LFORTRAN_BINARY_MODFILES 75 | BinaryReader b(s); 76 | #else 77 | TextReader b(s); 78 | #endif 79 | std::string file_type = b.read_string(); 80 | if (file_type != lfortran_modfile_type_string) { 81 | throw LCompilersException("LCompilers Modfile format not recognized"); 82 | } 83 | std::string version = b.read_string(); 84 | if (version != LFORTRAN_VERSION) { 85 | throw LCompilersException("Incompatible format: LFortran Modfile was generated using version '" + version + "', but current LFortran version is '" + LFORTRAN_VERSION + "'"); 86 | } 87 | asr_binary = b.read_string(); 88 | } 89 | 90 | ASR::TranslationUnit_t* load_modfile(Allocator &al, const std::string &s, 91 | bool load_symtab_id, SymbolTable &symtab) { 92 | std::string asr_binary; 93 | load_serialised_asr(s, asr_binary); 94 | ASR::asr_t *asr = deserialize_asr(al, asr_binary, load_symtab_id, symtab); 95 | 96 | ASR::TranslationUnit_t *tu = ASR::down_cast2(asr); 97 | return tu; 98 | } 99 | 100 | ASR::TranslationUnit_t* load_pycfile(Allocator &al, const std::string &s, 101 | bool load_symtab_id) { 102 | std::string asr_binary; 103 | load_serialised_asr(s, asr_binary); 104 | ASR::asr_t *asr = deserialize_asr(al, asr_binary, load_symtab_id); 105 | 106 | ASR::TranslationUnit_t *tu = ASR::down_cast2(asr); 107 | return tu; 108 | } 109 | 110 | } // namespace LCompilers 111 | -------------------------------------------------------------------------------- /src/libasr/modfile.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_MODFILE_H 2 | #define LFORTRAN_MODFILE_H 3 | 4 | #include 5 | 6 | namespace LCompilers { 7 | 8 | // Save a module to a modfile 9 | std::string save_modfile(const ASR::TranslationUnit_t &m); 10 | 11 | std::string save_pycfile(const ASR::TranslationUnit_t &m); 12 | 13 | // Load a module from a modfile 14 | ASR::TranslationUnit_t* load_modfile(Allocator &al, const std::string &s, 15 | bool load_symtab_id, SymbolTable &symtab); 16 | 17 | ASR::TranslationUnit_t* load_pycfile(Allocator &al, const std::string &s, 18 | bool load_symtab_id); 19 | 20 | } // namespace LCompilers 21 | 22 | #endif // LFORTRAN_MODFILE_H 23 | -------------------------------------------------------------------------------- /src/libasr/pass/arr_dims_propagate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace LFortran { 10 | 11 | /* 12 | * This ASR pass replaces ttype for all arrays passed. 13 | * 14 | * Converts: 15 | * integer :: a(:, :) 16 | * 17 | * to: 18 | * integer :: a(2, 3) 19 | */ 20 | 21 | class ArrDimsPropagate : public ASR::StatementsFirstBaseWalkVisitor 22 | { 23 | private: 24 | // Allocator &m_al; 25 | public: 26 | ArrDimsPropagate(Allocator &/*al*/) /*: m_al(al)*/ { } 27 | 28 | void visit_FunctionCall(const ASR::FunctionCall_t &x) { 29 | ASR::Function_t *fn = ASR::down_cast(ASRUtils::symbol_get_past_external(x.m_name)); 30 | 31 | for (size_t i = 0; i < x.n_args; i++) { 32 | if (ASR::is_a(*x.m_args[i].m_value) && ASRUtils::is_array(ASRUtils::expr_type(x.m_args[i].m_value))) { 33 | ASR::Variable_t* v = ASRUtils::EXPR2VAR(x.m_args[i].m_value); 34 | ASR::Variable_t *fn_param = ASRUtils::EXPR2VAR(fn->m_args[i]); 35 | ASR::dimension_t* m_dims; 36 | int n_dims = ASRUtils::extract_dimensions_from_ttype(fn_param->m_type, m_dims); 37 | if (n_dims > 0 && !m_dims[0].m_length && ASRUtils::check_equal_type(v->m_type, fn_param->m_type)) { 38 | fn_param->m_type = v->m_type; 39 | } 40 | } 41 | } 42 | } 43 | 44 | void visit_SubroutineCall(const ASR::SubroutineCall_t &x) { 45 | ASR::Subroutine_t *sb = ASR::down_cast(ASRUtils::symbol_get_past_external(x.m_name)); 46 | for (size_t i = 0; i < x.n_args; i++) { 47 | if (ASR::is_a(*x.m_args[i].m_value) && ASRUtils::is_array(ASRUtils::expr_type(x.m_args[i].m_value))) { 48 | ASR::Variable_t* v = ASRUtils::EXPR2VAR(x.m_args[i].m_value); 49 | ASR::Variable_t *sb_param = ASRUtils::EXPR2VAR(sb->m_args[i]); 50 | ASR::dimension_t* m_dims; 51 | int n_dims = ASRUtils::extract_dimensions_from_ttype(sb_param->m_type, m_dims); 52 | if (n_dims > 0 && !m_dims[0].m_length && ASRUtils::check_equal_type(v->m_type, sb_param->m_type)) { 53 | sb_param->m_type = v->m_type; 54 | } 55 | } 56 | } 57 | } 58 | }; 59 | 60 | void pass_propagate_arr_dims(Allocator &al, ASR::TranslationUnit_t &unit) { 61 | ArrDimsPropagate v(al); 62 | v.visit_TranslationUnit(unit); 63 | LFORTRAN_ASSERT(asr_verify(unit)); 64 | } 65 | 66 | } // namespace LFortran 67 | -------------------------------------------------------------------------------- /src/libasr/pass/arr_dims_propagate.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_ARR_DIMS_PROPAGATE 2 | #define LFORTRAN_PASS_ARR_DIMS_PROPAGATE 3 | 4 | #include 5 | 6 | namespace LFortran { 7 | 8 | void pass_propagate_arr_dims(Allocator &al, ASR::TranslationUnit_t &unit); 9 | 10 | } // namespace LFortran 11 | 12 | #endif // LFORTRAN_PASS_ARR_DIMS_PROPAGATE 13 | -------------------------------------------------------------------------------- /src/libasr/pass/arr_slice.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_ARR_SLICE_H 2 | #define LFORTRAN_PASS_ARR_SLICE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_arr_slice(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_ARR_SLICE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/array_by_data.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_ARRAY_BY_DATA_H 2 | #define LIBASR_PASS_ARRAY_BY_DATA_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_array_by_data(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_ARRAY_BY_DATA_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/array_op.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_ARRAY_OP_H 2 | #define LFORTRAN_PASS_ARRAY_OP_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_array_op(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_ARRAY_OP_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/class_constructor.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | namespace LCompilers { 13 | 14 | using ASR::down_cast; 15 | using ASR::is_a; 16 | 17 | class ReplaceStructTypeConstructor: public ASR::BaseExprReplacer { 18 | 19 | public: 20 | 21 | Allocator& al; 22 | Vec& pass_result; 23 | bool& remove_original_statement; 24 | 25 | SymbolTable* current_scope; 26 | ASR::expr_t* result_var; 27 | 28 | ReplaceStructTypeConstructor(Allocator& al_, Vec& pass_result_, 29 | bool& remove_original_statement_) : 30 | al(al_), pass_result(pass_result_), 31 | remove_original_statement(remove_original_statement_), 32 | current_scope(nullptr), result_var(nullptr) {} 33 | 34 | void replace_StructTypeConstructor(ASR::StructTypeConstructor_t* x) { 35 | Vec* result_vec = &pass_result; 36 | PassUtils::ReplacerUtils::replace_StructTypeConstructor( 37 | x, this, false, remove_original_statement, result_vec); 38 | } 39 | }; 40 | 41 | class StructTypeConstructorVisitor : public ASR::CallReplacerOnExpressionsVisitor 42 | { 43 | private: 44 | 45 | Allocator& al; 46 | bool remove_original_statement; 47 | ReplaceStructTypeConstructor replacer; 48 | Vec pass_result; 49 | 50 | public: 51 | 52 | StructTypeConstructorVisitor(Allocator& al_) : 53 | al(al_), remove_original_statement(false), 54 | replacer(al_, pass_result, remove_original_statement) { 55 | pass_result.n = 0; 56 | pass_result.reserve(al, 0); 57 | } 58 | 59 | void call_replacer() { 60 | replacer.current_expr = current_expr; 61 | replacer.current_scope = current_scope; 62 | replacer.replace_expr(*current_expr); 63 | } 64 | 65 | void transform_stmts(ASR::stmt_t **&m_body, size_t &n_body) { 66 | Vec body; 67 | body.reserve(al, n_body); 68 | 69 | for (size_t i = 0; i < n_body; i++) { 70 | pass_result.n = 0; 71 | pass_result.reserve(al, 1); 72 | remove_original_statement = false; 73 | replacer.result_var = nullptr; 74 | visit_stmt(*m_body[i]); 75 | for (size_t j = 0; j < pass_result.size(); j++) { 76 | body.push_back(al, pass_result[j]); 77 | } 78 | if( !remove_original_statement ) { 79 | body.push_back(al, m_body[i]); 80 | } 81 | remove_original_statement = false; 82 | } 83 | m_body = body.p; 84 | n_body = body.size(); 85 | replacer.result_var = nullptr; 86 | pass_result.n = 0; 87 | pass_result.reserve(al, 0); 88 | } 89 | 90 | void visit_Variable(const ASR::Variable_t& /*x*/) { 91 | // Do nothing, already handled in init_expr pass 92 | } 93 | 94 | void visit_Assignment(const ASR::Assignment_t &x) { 95 | if (x.m_overloaded) { 96 | this->visit_stmt(*x.m_overloaded); 97 | remove_original_statement = false; 98 | return ; 99 | } 100 | 101 | replacer.result_var = x.m_target; 102 | ASR::expr_t** current_expr_copy_9 = current_expr; 103 | current_expr = const_cast(&(x.m_value)); 104 | this->call_replacer(); 105 | current_expr = current_expr_copy_9; 106 | if( !remove_original_statement ) { 107 | this->visit_expr(*x.m_value); 108 | } 109 | } 110 | 111 | }; 112 | 113 | void pass_replace_class_constructor(Allocator &al, 114 | ASR::TranslationUnit_t &unit, 115 | const LCompilers::PassOptions& /*pass_options*/) { 116 | StructTypeConstructorVisitor v(al); 117 | v.visit_TranslationUnit(unit); 118 | PassUtils::UpdateDependenciesVisitor w(al); 119 | w.visit_TranslationUnit(unit); 120 | } 121 | 122 | 123 | } // namespace LCompilers 124 | -------------------------------------------------------------------------------- /src/libasr/pass/class_constructor.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_CLASS_CONSTRUCTOR_H 2 | #define LFORTRAN_PASS_CLASS_CONSTRUCTOR_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_class_constructor(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_CLASS_CONSTRUCTOR_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/compare.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_COMPARE_H 2 | #define LIBASR_PASS_COMPARE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_compare(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_COMPARE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/create_subroutine_from_function.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_CREATE_SUBROUTINE_FROM_FUNCTION_H 2 | #define LIBASR_PASS_CREATE_SUBROUTINE_FROM_FUNCTION_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_create_subroutine_from_function(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_CREATE_SUBROUTINE_FROM_FUNCTION_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/dead_code_removal.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | namespace LCompilers { 15 | 16 | using ASR::down_cast; 17 | using ASR::is_a; 18 | 19 | 20 | class DeadCodeRemovalVisitor : public PassUtils::PassVisitor 21 | { 22 | private: 23 | 24 | std::string rl_path; 25 | 26 | public: 27 | 28 | bool dead_code_removed; 29 | 30 | DeadCodeRemovalVisitor(Allocator &al_, const std::string& rl_path_) : PassVisitor(al_, nullptr), 31 | rl_path(rl_path_), dead_code_removed(false) 32 | { 33 | pass_result.reserve(al, 1); 34 | } 35 | 36 | void visit_If(const ASR::If_t& x) { 37 | ASR::If_t& xx = const_cast(x); 38 | transform_stmts(xx.m_body, xx.n_body); 39 | transform_stmts(xx.m_orelse, xx.n_orelse); 40 | ASR::expr_t* m_test_value = ASRUtils::expr_value(x.m_test); 41 | bool m_test_bool; 42 | if( ASRUtils::is_value_constant(m_test_value, m_test_bool) ) { 43 | ASR::stmt_t** selected_part = nullptr; 44 | size_t n_selected_part = 0; 45 | if( m_test_bool ) { 46 | selected_part = x.m_body; 47 | n_selected_part = x.n_body; 48 | } else { 49 | selected_part = x.m_orelse; 50 | n_selected_part = x.n_orelse; 51 | } 52 | for( size_t i = 0; i < n_selected_part; i++ ) { 53 | pass_result.push_back(al, selected_part[i]); 54 | } 55 | dead_code_removed = true; 56 | } 57 | } 58 | 59 | void visit_Select(const ASR::Select_t& x) { 60 | ASR::Select_t& xx = const_cast(x); 61 | ASR::expr_t* m_test_value = ASRUtils::expr_value(x.m_test); 62 | if( !ASRUtils::is_value_constant(m_test_value) ) { 63 | return ; 64 | } 65 | 66 | for( size_t i = 0; i < x.n_body; i++ ) { 67 | ASR::case_stmt_t* case_body = x.m_body[i]; 68 | switch (case_body->type) { 69 | case ASR::case_stmtType::CaseStmt: { 70 | ASR::CaseStmt_t* casestmt = ASR::down_cast(case_body); 71 | transform_stmts(casestmt->m_body, casestmt->n_body); 72 | xx.m_body[i] = (ASR::case_stmt_t*)(&(casestmt->base)); 73 | for( size_t j = 0; j < casestmt->n_test; j++ ) { 74 | if( ASRUtils::is_value_equal(casestmt->m_test[j], x.m_test) ) { 75 | for( size_t k = 0; k < casestmt->n_body; k++ ) { 76 | pass_result.push_back(al, casestmt->m_body[k]); 77 | } 78 | return ; 79 | } 80 | } 81 | break; 82 | } 83 | case ASR::case_stmtType::CaseStmt_Range: { 84 | ASR::CaseStmt_Range_t* casestmt_range = ASR::down_cast(case_body); 85 | transform_stmts(casestmt_range->m_body, casestmt_range->n_body); 86 | xx.m_body[i] = (ASR::case_stmt_t*)(&(casestmt_range->base)); 87 | if( ASRUtils::is_value_in_range(casestmt_range->m_start, casestmt_range->m_end, x.m_test) ) { 88 | for( size_t k = 0; k < casestmt_range->n_body; k++ ) { 89 | pass_result.push_back(al, casestmt_range->m_body[k]); 90 | } 91 | return ; 92 | } 93 | break; 94 | } 95 | } 96 | } 97 | } 98 | 99 | }; 100 | 101 | void pass_dead_code_removal(Allocator &al, ASR::TranslationUnit_t &unit, 102 | const LCompilers::PassOptions& pass_options) { 103 | std::string rl_path = pass_options.runtime_library_dir; 104 | DeadCodeRemovalVisitor v(al, rl_path); 105 | v.visit_TranslationUnit(unit); 106 | } 107 | 108 | 109 | } // namespace LCompilers 110 | -------------------------------------------------------------------------------- /src/libasr/pass/dead_code_removal.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_DEAD_CODE_REMOVAL_H 2 | #define LIBASR_PASS_DEAD_CODE_REMOVAL_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_dead_code_removal(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_DEAD_CODE_REMOVAL_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/div_to_mul.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | 13 | namespace LCompilers { 14 | 15 | using ASR::down_cast; 16 | using ASR::is_a; 17 | 18 | /* 19 | 20 | This ASR pass replaces division operation with multiplication 21 | if the divisor can be evaluated to a constant at compile time. 22 | 23 | Converts: 24 | 25 | real :: x 26 | real, parameter :: divisor = 2.0 27 | print *, x/divisor 28 | 29 | to: 30 | 31 | real :: x 32 | real, parameter :: divisor = 2.0 33 | print *, x * 0.5 34 | 35 | */ 36 | class DivToMulVisitor : public PassUtils::PassVisitor 37 | { 38 | private: 39 | 40 | std::string rl_path; 41 | 42 | public: 43 | DivToMulVisitor(Allocator &al_, const std::string& rl_path_) : PassVisitor(al_, nullptr), 44 | rl_path(rl_path_) 45 | { 46 | pass_result.reserve(al, 1); 47 | } 48 | 49 | void visit_RealBinOp(const ASR::RealBinOp_t& x) { 50 | visit_expr(*x.m_left); 51 | visit_expr(*x.m_right); 52 | if( x.m_op == ASR::binopType::Div ) { 53 | ASR::expr_t* right_value = ASRUtils::expr_value(x.m_right); 54 | if( right_value ) { 55 | double value; 56 | if( ASRUtils::extract_value(right_value, value) ) { 57 | bool is_feasible = false; 58 | ASR::expr_t* right_inverse = nullptr; 59 | switch( x.m_type->type ) { 60 | case ASR::ttypeType::Real: { 61 | is_feasible = true; 62 | right_inverse = ASRUtils::EXPR(ASR::make_RealConstant_t(al, x.m_right->base.loc, 1.0/value, x.m_type)); 63 | break; 64 | } 65 | default: 66 | break; 67 | } 68 | if( is_feasible ) { 69 | ASR::RealBinOp_t& xx = const_cast(x); 70 | xx.m_op = ASR::binopType::Mul; 71 | xx.m_right = right_inverse; 72 | } 73 | } 74 | } 75 | } 76 | } 77 | 78 | }; 79 | 80 | void pass_replace_div_to_mul(Allocator &al, ASR::TranslationUnit_t &unit, 81 | const LCompilers::PassOptions& pass_options) { 82 | std::string rl_path = pass_options.runtime_library_dir; 83 | DivToMulVisitor v(al, rl_path); 84 | v.visit_TranslationUnit(unit); 85 | } 86 | 87 | 88 | } // namespace LCompilers 89 | -------------------------------------------------------------------------------- /src/libasr/pass/div_to_mul.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_DIV_TO_MUL_H 2 | #define LIBASR_PASS_DIV_TO_MUL_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_div_to_mul(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_DIV_TO_MUL_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/do_loops.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | namespace LCompilers { 11 | 12 | using ASR::down_cast; 13 | using ASR::is_a; 14 | 15 | /* 16 | 17 | This ASR pass replaces do loops with while loops. The function 18 | `pass_replace_do_loops` transforms the ASR tree in-place. 19 | 20 | Converts: 21 | 22 | do i = a, b, c 23 | ... 24 | end do 25 | 26 | to: 27 | 28 | i = a-c 29 | do while (i+c <= b) 30 | i = i+c 31 | ... 32 | end do 33 | 34 | The comparison is >= for c<0. 35 | */ 36 | class DoLoopVisitor : public ASR::StatementWalkVisitor 37 | { 38 | public: 39 | bool use_loop_variable_after_loop = false; 40 | DoLoopVisitor(Allocator &al) : StatementWalkVisitor(al) { 41 | } 42 | 43 | void visit_DoLoop(const ASR::DoLoop_t &x) { 44 | pass_result = PassUtils::replace_doloop(al, x, -1, use_loop_variable_after_loop); 45 | } 46 | }; 47 | 48 | void pass_replace_do_loops(Allocator &al, ASR::TranslationUnit_t &unit, 49 | const LCompilers::PassOptions& pass_options) { 50 | DoLoopVisitor v(al); 51 | // Each call transforms only one layer of nested loops, so we call it twice 52 | // to transform doubly nested loops: 53 | v.asr_changed = true; 54 | v.use_loop_variable_after_loop = pass_options.use_loop_variable_after_loop; 55 | while( v.asr_changed ) { 56 | v.asr_changed = false; 57 | v.visit_TranslationUnit(unit); 58 | } 59 | } 60 | 61 | 62 | } // namespace LCompilers 63 | -------------------------------------------------------------------------------- /src/libasr/pass/do_loops.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_DO_LOOPS_H 2 | #define LFORTRAN_PASS_DO_LOOPS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_do_loops(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_DO_LOOPS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/flip_sign.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_FLIP_SIGN_H 2 | #define LIBASR_PASS_FLIP_SIGN_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_flip_sign(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_FLIP_SIGN_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/fma.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | 13 | namespace LCompilers { 14 | 15 | using ASR::down_cast; 16 | using ASR::is_a; 17 | 18 | /* 19 | 20 | This ASR pass converts fused multiplication and addition (FMA) expressions 21 | with a call to internal optimization routine for FMA. This allows 22 | backend specific code generation for FMA expressions resulting in optimized 23 | code. 24 | 25 | Converts: 26 | 27 | real :: a, b, c, d 28 | d = a + b * c 29 | 30 | to: 31 | 32 | d = fma(a, b, c) 33 | 34 | */ 35 | class FMAVisitor : public PassUtils::SkipOptimizationFunctionVisitor 36 | { 37 | private: 38 | ASR::TranslationUnit_t &unit; 39 | 40 | LCompilers::PassOptions pass_options; 41 | 42 | ASR::expr_t* fma_var; 43 | 44 | // To make sure that FMA is applied only for 45 | // the nodes implemented in this class 46 | bool from_fma; 47 | 48 | public: 49 | FMAVisitor(Allocator &al_, ASR::TranslationUnit_t &unit_, 50 | const LCompilers::PassOptions& pass_options_) : SkipOptimizationFunctionVisitor(al_), 51 | unit(unit_), pass_options(pass_options_), fma_var(nullptr), from_fma(false) 52 | { 53 | pass_result.reserve(al, 1); 54 | } 55 | 56 | bool is_BinOpMul(ASR::expr_t* expr) { 57 | if (ASR::is_a(*expr)) { 58 | ASR::RealBinOp_t* expr_binop = ASR::down_cast(expr); 59 | return expr_binop->m_op == ASR::binopType::Mul; 60 | } 61 | return false; 62 | } 63 | 64 | void visit_IntegerBinOp(const ASR::IntegerBinOp_t& /*x*/) { } 65 | void visit_ComplexBinOp(const ASR::ComplexBinOp_t& /*x*/) { } 66 | void visit_LogicalBinOp(const ASR::LogicalBinOp_t& /*x*/) { } 67 | 68 | void visit_RealBinOp(const ASR::RealBinOp_t& x_const) { 69 | if( !from_fma ) { 70 | return ; 71 | } 72 | 73 | from_fma = true; 74 | LCOMPILERS_ASSERT(ASRUtils::is_real(*x_const.m_type)) 75 | ASR::RealBinOp_t& x = const_cast(x_const); 76 | 77 | fma_var = nullptr; 78 | visit_expr(*x.m_left); 79 | if( fma_var ) { 80 | x.m_left = fma_var; 81 | } 82 | 83 | fma_var = nullptr; 84 | visit_expr(*x.m_right); 85 | if( fma_var ) { 86 | x.m_right = fma_var; 87 | } 88 | fma_var = nullptr; 89 | 90 | if( x.m_op != ASR::binopType::Add && x.m_op != ASR::binopType::Sub ) { 91 | return ; 92 | } 93 | ASR::expr_t *mul_expr = nullptr, *other_expr = nullptr; 94 | bool is_mul_expr_negative = false, is_other_expr_negative = false; 95 | if( is_BinOpMul(x.m_right) ) { 96 | mul_expr = x.m_right; 97 | other_expr = x.m_left; 98 | is_mul_expr_negative = (x.m_op == ASR::binopType::Sub); 99 | } else if( is_BinOpMul(x.m_left) ) { 100 | mul_expr = x.m_left; 101 | other_expr = x.m_right; 102 | is_other_expr_negative = (x.m_op == ASR::binopType::Sub); 103 | } else { 104 | return ; 105 | } 106 | 107 | if( is_other_expr_negative ) { 108 | other_expr = ASRUtils::EXPR(ASR::make_RealUnaryMinus_t(al, other_expr->base.loc, other_expr, 109 | ASRUtils::expr_type(other_expr), nullptr)); 110 | } 111 | 112 | ASR::RealBinOp_t* mul_binop = ASR::down_cast(mul_expr); 113 | ASR::expr_t *first_arg = mul_binop->m_left, *second_arg = mul_binop->m_right; 114 | 115 | if( is_mul_expr_negative ) { 116 | first_arg = ASRUtils::EXPR(ASR::make_RealUnaryMinus_t(al, first_arg->base.loc, first_arg, 117 | ASRUtils::expr_type(first_arg), nullptr)); 118 | } 119 | 120 | fma_var = PassUtils::get_fma(other_expr, first_arg, second_arg, 121 | al, unit, x.base.base.loc, pass_options); 122 | from_fma = false; 123 | } 124 | 125 | void visit_Assignment(const ASR::Assignment_t& x) { 126 | from_fma = true; 127 | ASR::Assignment_t& xx = const_cast(x); 128 | fma_var = nullptr; 129 | visit_expr(*x.m_value); 130 | if( fma_var ) { 131 | xx.m_value = fma_var; 132 | } 133 | fma_var = nullptr; 134 | from_fma = false; 135 | } 136 | 137 | void visit_IntegerUnaryMinus(const ASR::IntegerUnaryMinus_t &x) { 138 | visit_UnaryOp(x); 139 | } 140 | void visit_RealUnaryMinus(const ASR::RealUnaryMinus_t &x) { 141 | visit_UnaryOp(x); 142 | } 143 | void visit_ComplexUnaryMinus(const ASR::ComplexUnaryMinus_t &x) { 144 | visit_UnaryOp(x); 145 | } 146 | void visit_IntegerBitNot(const ASR::IntegerBitNot_t &x) { 147 | visit_UnaryOp(x); 148 | } 149 | void visit_LogicalNot(const ASR::LogicalNot_t &x) { 150 | visit_UnaryOp(x); 151 | } 152 | 153 | template 154 | void visit_UnaryOp(const T& x) { 155 | from_fma = true; 156 | T& xx = const_cast(x); 157 | fma_var = nullptr; 158 | visit_expr(*x.m_arg); 159 | if( fma_var ) { 160 | xx.m_arg = fma_var; 161 | } 162 | fma_var = nullptr; 163 | from_fma = false; 164 | } 165 | 166 | }; 167 | 168 | void pass_replace_fma(Allocator &al, ASR::TranslationUnit_t &unit, 169 | const LCompilers::PassOptions& pass_options) { 170 | FMAVisitor v(al, unit, pass_options); 171 | v.visit_TranslationUnit(unit); 172 | PassUtils::UpdateDependenciesVisitor u(al); 173 | u.visit_TranslationUnit(unit); 174 | } 175 | 176 | 177 | } // namespace LCompilers 178 | -------------------------------------------------------------------------------- /src/libasr/pass/fma.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_FMA_H 2 | #define LIBASR_PASS_FMA_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_fma(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_FMA_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/for_all.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace LCompilers { 10 | 11 | /* 12 | * This ASR pass replaces forall statement with Do Concurrent. 13 | * 14 | * Converts: 15 | * forall(i=start:end:inc) array(i) = i 16 | * 17 | * to: 18 | * do concurrent (i=start:end:inc) 19 | * array(i) = i 20 | * end do 21 | */ 22 | 23 | class ForAllVisitor : public ASR::StatementWalkVisitor 24 | { 25 | public: 26 | ForAllVisitor(Allocator &al) : StatementWalkVisitor(al) { 27 | } 28 | 29 | void visit_ForAllSingle(const ASR::ForAllSingle_t &x) { 30 | Location loc = x.base.base.loc; 31 | ASR::stmt_t *assign_stmt = x.m_assign_stmt; 32 | Vec body; 33 | body.reserve(al, 1); 34 | body.push_back(al, assign_stmt); 35 | 36 | ASR::stmt_t *stmt = ASRUtils::STMT( 37 | ASR::make_DoConcurrentLoop_t(al, loc, x.m_head, body.p, body.size()) 38 | ); 39 | Vec result; 40 | result.reserve(al, 1); 41 | result.push_back(al, stmt); 42 | pass_result = result; 43 | } 44 | }; 45 | 46 | void pass_replace_for_all(Allocator &al, ASR::TranslationUnit_t &unit, 47 | const LCompilers::PassOptions& /*pass_options*/) { 48 | ForAllVisitor v(al); 49 | v.visit_TranslationUnit(unit); 50 | } 51 | 52 | } // namespace LCompilers 53 | -------------------------------------------------------------------------------- /src/libasr/pass/for_all.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_FOR_ALL 2 | #define LFORTRAN_PASS_FOR_ALL 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_forall(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_FOR_ALL 15 | -------------------------------------------------------------------------------- /src/libasr/pass/global_stmts.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace LCompilers { 11 | 12 | using ASR::down_cast; 13 | 14 | using ASRUtils::EXPR; 15 | 16 | /* 17 | * This ASR pass transforms (in-place) the ASR tree and wras all global 18 | * statements and expressions into a function. 19 | * 20 | */ 21 | void pass_wrap_global_stmts(Allocator &al, 22 | ASR::TranslationUnit_t &unit, const LCompilers::PassOptions& pass_options) { 23 | if (unit.n_items == 0) { 24 | return ; 25 | } 26 | 27 | std::string fn_name_s = pass_options.run_fun; 28 | // Add an anonymous function 29 | Str s; 30 | s.from_str_view(fn_name_s); 31 | char *fn_name = s.c_str(al); 32 | SymbolTable *fn_scope = al.make_new(unit.m_symtab); 33 | 34 | ASR::ttype_t *type; 35 | Location loc = unit.base.base.loc; 36 | ASR::asr_t *return_var=nullptr; 37 | ASR::expr_t *return_var_ref=nullptr; 38 | char *var_name; 39 | int idx = 1; 40 | 41 | Vec body; 42 | body.reserve(al, unit.n_items); 43 | for (size_t i=0; itype == ASR::asrType::expr) { 45 | ASR::expr_t *target; 46 | ASR::expr_t *value = EXPR(unit.m_items[i]); 47 | // Create a new variable with the right type 48 | if (ASRUtils::expr_type(value)->type == ASR::ttypeType::Integer) { 49 | s.from_str(al, fn_name_s + std::to_string(idx)); 50 | var_name = s.c_str(al); 51 | 52 | int a_kind = down_cast(ASRUtils::expr_type(value))->m_kind; 53 | 54 | type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc, a_kind)); 55 | return_var = ASR::make_Variable_t(al, loc, 56 | fn_scope, var_name, nullptr, 0, ASRUtils::intent_local, nullptr, nullptr, 57 | ASR::storage_typeType::Default, type, 58 | nullptr, ASR::abiType::BindC, 59 | ASR::Public, ASR::presenceType::Required, false); 60 | return_var_ref = EXPR(ASR::make_Var_t(al, loc, 61 | down_cast(return_var))); 62 | fn_scope->add_symbol(std::string(var_name), down_cast(return_var)); 63 | target = return_var_ref; 64 | idx++; 65 | } else if (ASRUtils::expr_type(value)->type == ASR::ttypeType::Real) { 66 | s.from_str(al, fn_name_s + std::to_string(idx)); 67 | var_name = s.c_str(al); 68 | type = ASRUtils::expr_type(value); 69 | return_var = ASR::make_Variable_t(al, loc, 70 | fn_scope, var_name, nullptr, 0, ASRUtils::intent_local, nullptr, nullptr, 71 | ASR::storage_typeType::Default, type, 72 | nullptr, ASR::abiType::BindC, 73 | ASR::Public, ASR::presenceType::Required, false); 74 | return_var_ref = EXPR(ASR::make_Var_t(al, loc, 75 | down_cast(return_var))); 76 | fn_scope->add_symbol(std::string(var_name), down_cast(return_var)); 77 | target = return_var_ref; 78 | idx++; 79 | } else if (ASRUtils::expr_type(value)->type == ASR::ttypeType::Complex) { 80 | s.from_str(al, fn_name_s + std::to_string(idx)); 81 | var_name = s.c_str(al); 82 | type = ASRUtils::expr_type(value); 83 | return_var = ASR::make_Variable_t(al, loc, 84 | fn_scope, var_name, nullptr, 0, ASRUtils::intent_local, nullptr, nullptr, 85 | ASR::storage_typeType::Default, type, 86 | nullptr, ASR::abiType::BindC, 87 | ASR::Public, ASR::presenceType::Required, false); 88 | return_var_ref = EXPR(ASR::make_Var_t(al, loc, 89 | down_cast(return_var))); 90 | fn_scope->add_symbol(std::string(var_name), down_cast(return_var)); 91 | target = return_var_ref; 92 | idx++; 93 | } else { 94 | throw LCompilersException("Return type not supported in interactive mode"); 95 | } 96 | ASR::stmt_t* asr_stmt = ASRUtils::STMT(ASR::make_Assignment_t(al, loc, target, value, nullptr)); 97 | body.push_back(al, asr_stmt); 98 | } else if (unit.m_items[i]->type == ASR::asrType::stmt) { 99 | ASR::stmt_t* asr_stmt = ASRUtils::STMT(unit.m_items[i]); 100 | body.push_back(al, asr_stmt); 101 | return_var = nullptr; 102 | } else { 103 | throw LCompilersException("Unsupported type of global scope node"); 104 | } 105 | } 106 | 107 | if (return_var) { 108 | // The last defined `return_var` is the actual return value 109 | ASR::down_cast2(return_var)->m_intent = ASRUtils::intent_return_var; 110 | } 111 | 112 | ASR::asr_t *fn = ASRUtils::make_Function_t_util( 113 | al, loc, 114 | /* a_symtab */ fn_scope, 115 | /* a_name */ fn_name, 116 | nullptr, 0, 117 | /* a_args */ nullptr, 118 | /* n_args */ 0, 119 | /* a_body */ body.p, 120 | /* n_body */ body.size(), 121 | /* a_return_var */ (return_var ? return_var_ref : nullptr), 122 | (return_var ? ASR::abiType::BindC : ASR::abiType::Source), 123 | ASR::Public, ASR::Implementation, 124 | nullptr, 125 | false, false, false, false, false, 126 | nullptr, 0, 127 | false, false, false); 128 | std::string sym_name = fn_name; 129 | if (unit.m_symtab->get_symbol(sym_name) != nullptr) { 130 | throw LCompilersException("Function already defined"); 131 | } 132 | unit.m_symtab->add_symbol(sym_name, down_cast(fn)); 133 | unit.m_items = nullptr; 134 | unit.n_items = 0; 135 | PassUtils::UpdateDependenciesVisitor v(al); 136 | v.visit_TranslationUnit(unit); 137 | } 138 | 139 | } // namespace LCompilers 140 | -------------------------------------------------------------------------------- /src/libasr/pass/global_stmts.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_GLOBAL_STMTS_H 2 | #define LFORTRAN_PASS_GLOBAL_STMTS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_wrap_global_stmts_into_function(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_GLOBAL_STMTS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/global_stmts_program.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace LCompilers { 11 | 12 | using ASR::down_cast; 13 | 14 | using ASRUtils::EXPR; 15 | 16 | /* 17 | * This ASR pass transforms (in-place) the ASR tree and wraps all global 18 | * statements and expressions into a program. 19 | * 20 | */ 21 | void pass_wrap_global_stmts_into_program(Allocator &al, 22 | ASR::TranslationUnit_t &unit, const LCompilers::PassOptions& pass_options) { 23 | std::string program_fn_name = pass_options.run_fun; 24 | SymbolTable *current_scope = al.make_new(unit.m_global_scope); 25 | std::string prog_name = "main_program"; 26 | Vec prog_body; 27 | prog_body.reserve(al, 1); 28 | SetChar prog_dep; 29 | prog_dep.reserve(al, 1); 30 | bool call_main_program = unit.n_items > 0; 31 | pass_wrap_global_stmts_into_function(al, unit, pass_options); 32 | pass_wrap_global_syms_into_module(al, unit, pass_options); 33 | if( call_main_program && !pass_options.disable_main ) { 34 | // Call `_lpython_main_program` function 35 | ASR::Module_t *mod = ASR::down_cast( 36 | unit.m_global_scope->get_symbol("_global_symbols")); 37 | ASR::symbol_t *fn_s = mod->m_symtab->get_symbol(program_fn_name); 38 | if (!(ASR::is_a(*fn_s) 39 | && ASR::down_cast(fn_s)->m_return_var == nullptr)) { 40 | throw LCompilersException("Return type not supported yet"); 41 | } 42 | 43 | ASR::Function_t *fn = ASR::down_cast(fn_s); 44 | fn_s = ASR::down_cast(ASR::make_ExternalSymbol_t( 45 | al, fn->base.base.loc, current_scope, s2c(al, program_fn_name), 46 | fn_s, mod->m_name, nullptr, 0, s2c(al, program_fn_name), 47 | ASR::accessType::Public)); 48 | current_scope->add_symbol(program_fn_name, fn_s); 49 | ASR::asr_t *stmt = ASR::make_SubroutineCall_t( 50 | al, unit.base.base.loc, 51 | fn_s, nullptr, 52 | nullptr, 0, 53 | nullptr); 54 | prog_body.push_back(al, ASR::down_cast(stmt)); 55 | prog_dep.push_back(al, s2c(al, "_global_symbols")); 56 | } 57 | 58 | if( !pass_options.disable_main ) { 59 | ASR::asr_t *prog = ASR::make_Program_t( 60 | al, unit.base.base.loc, 61 | /* a_symtab */ current_scope, 62 | /* a_name */ s2c(al, prog_name), 63 | prog_dep.p, 64 | prog_dep.n, 65 | /* a_body */ prog_body.p, 66 | /* n_body */ prog_body.n); 67 | unit.m_global_scope->add_symbol(prog_name, ASR::down_cast(prog)); 68 | } 69 | } 70 | 71 | } // namespace LCompilers 72 | -------------------------------------------------------------------------------- /src/libasr/pass/global_stmts_program.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_GLOBAL_STMTS_PROGRAM_H 2 | #define LIBASR_PASS_GLOBAL_STMTS_PROGRAM_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_wrap_global_stmts_into_program(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_GLOBAL_STMTS_PROGRAM_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/global_symbols.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace LCompilers { 11 | 12 | /* 13 | * This ASR pass transforms (in-place) the ASR tree 14 | * and wraps all global symbols into a module 15 | */ 16 | 17 | void pass_wrap_global_syms_into_module(Allocator &al, 18 | ASR::TranslationUnit_t &unit, 19 | const LCompilers::PassOptions &/*pass_options*/) { 20 | if( unit.m_global_scope->get_scope().size() == 0 ) { 21 | return ; 22 | } 23 | Location loc = unit.base.base.loc; 24 | char *module_name = s2c(al, "_global_symbols"); 25 | SymbolTable *module_scope = al.make_new(unit.m_global_scope); 26 | Vec moved_symbols; 27 | SetChar mod_dependencies; 28 | 29 | // Move all the symbols from global into the module scope 30 | unit.m_global_scope->move_symbols_from_global_scope(al, module_scope, 31 | moved_symbols, mod_dependencies); 32 | 33 | // Erase the symbols that are moved into the module 34 | for (auto &sym: moved_symbols) { 35 | unit.m_global_scope->erase_symbol(sym); 36 | } 37 | 38 | ASR::symbol_t *module = (ASR::symbol_t *) ASR::make_Module_t(al, loc, 39 | module_scope, module_name, mod_dependencies.p, mod_dependencies.n, 40 | false, false); 41 | unit.m_global_scope->add_symbol(module_name, module); 42 | } 43 | 44 | } // namespace LCompilers 45 | -------------------------------------------------------------------------------- /src/libasr/pass/global_symbols.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_GLOBAL_SYMBOLS_H 2 | #define LFORTRAN_PASS_GLOBAL_SYMBOLS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_wrap_global_syms_into_module(Allocator &al, 10 | ASR::TranslationUnit_t &unit, 11 | const LCompilers::PassOptions& pass_options); 12 | 13 | } // namespace LCompilers 14 | 15 | #endif // LFORTRAN_PASS_GLOBAL_SYMBOLS_H 16 | -------------------------------------------------------------------------------- /src/libasr/pass/implied_do_loops.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_IMPLIED_DO_LOOPS_H 2 | #define LFORTRAN_PASS_IMPLIED_DO_LOOPS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_implied_do_loops(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_IMPLIED_DO_LOOPS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/init_expr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_INIT_EXPR_H 2 | #define LFORTRAN_PASS_INIT_EXPR_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_init_expr(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_INIT_EXPR_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/inline_function_calls.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_INLINE_FUNCTION_CALLS_H 2 | #define LIBASR_PASS_INLINE_FUNCTION_CALLS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_inline_function_calls(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_INLINE_FUNCTION_CALLS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/insert_deallocate.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | 12 | namespace LCompilers { 13 | 14 | class InsertDeallocate: public ASR::CallReplacerOnExpressionsVisitor 15 | { 16 | private: 17 | 18 | Allocator& al; 19 | 20 | public: 21 | 22 | InsertDeallocate(Allocator& al_) : al(al_) {} 23 | 24 | template 25 | void visit_Symbol(const T& x) { 26 | Vec to_be_deallocated; 27 | to_be_deallocated.reserve(al, 1); 28 | for( auto& itr: x.m_symtab->get_scope() ) { 29 | if( ASR::is_a(*itr.second) && 30 | ASR::is_a(*ASRUtils::symbol_type(itr.second)) && 31 | ASRUtils::is_array(ASRUtils::symbol_type(itr.second)) && 32 | ASRUtils::symbol_intent(itr.second) == ASRUtils::intent_local ) { 33 | to_be_deallocated.push_back(al, ASRUtils::EXPR( 34 | ASR::make_Var_t(al, x.base.base.loc, itr.second))); 35 | } 36 | } 37 | if( to_be_deallocated.size() > 0 ) { 38 | T& xx = const_cast(x); 39 | Vec body; 40 | body.from_pointer_n_copy(al, xx.m_body, xx.n_body); 41 | body.push_back(al, ASRUtils::STMT(ASR::make_ImplicitDeallocate_t( 42 | al, x.base.base.loc, to_be_deallocated.p, to_be_deallocated.size()))); 43 | xx.m_body = body.p; 44 | xx.n_body = body.size(); 45 | } 46 | } 47 | 48 | void visit_Function(const ASR::Function_t& x) { 49 | visit_Symbol(x); 50 | ASR::CallReplacerOnExpressionsVisitor::visit_Function(x); 51 | } 52 | 53 | void visit_Program(const ASR::Program_t& x) { 54 | visit_Symbol(x); 55 | ASR::CallReplacerOnExpressionsVisitor::visit_Program(x); 56 | } 57 | 58 | }; 59 | 60 | void pass_insert_deallocate(Allocator &al, ASR::TranslationUnit_t &unit, 61 | const PassOptions &/*pass_options*/) { 62 | InsertDeallocate v(al); 63 | v.visit_TranslationUnit(unit); 64 | } 65 | 66 | 67 | } // namespace LCompilers 68 | -------------------------------------------------------------------------------- /src/libasr/pass/insert_deallocate.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_INSERT_DEALLOCATE_H 2 | #define LIBASR_PASS_INSERT_DEALLOCATE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_insert_deallocate(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_INSERT_DEALLOCATE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/instantiate_template.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_INSTANTIATE_TEMPLATE_H 2 | #define LIBASR_PASS_INSTANTIATE_TEMPLATE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | /** 10 | * @brief Instantiate a generic function into a function that does not 11 | * contain any type parameters and restrictions. No type checking 12 | * is executed here 13 | */ 14 | ASR::symbol_t* instantiate_symbol(Allocator &al, 15 | std::map &context_map, 16 | std::map type_subs, 17 | std::map symbol_subs, 18 | SymbolTable *current_scope, SymbolTable *template_scope, 19 | std::string new_sym_name, ASR::symbol_t *sym); 20 | 21 | ASR::symbol_t* instantiate_function_body(Allocator &al, 22 | std::map &context_map, 23 | std::map type_subs, 24 | std::map symbol_subs, 25 | SymbolTable *current_scope, SymbolTable *template_scope, 26 | ASR::Function_t *new_f, ASR::Function_t *f); 27 | 28 | ASR::symbol_t* rename_symbol(Allocator &al, 29 | std::map &type_subs, 30 | SymbolTable *current_scope, 31 | std::string new_sym_name, ASR::symbol_t *sym); 32 | 33 | bool check_restriction(std::map type_subs, 34 | std::map &symbol_subs, 35 | ASR::Function_t *f, ASR::symbol_t *sym_arg); 36 | 37 | void report_check_restriction(std::map type_subs, 38 | std::map &symbol_subs, 39 | ASR::Function_t *f, ASR::symbol_t *sym_arg, const Location &loc, 40 | diag::Diagnostics &diagnostics); 41 | 42 | } // namespace LCompilers 43 | 44 | #endif // LIBASR_PASS_INSTANTIATE_TEMPLATE_H 45 | -------------------------------------------------------------------------------- /src/libasr/pass/intrinsic_function.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_INTRINSIC_FUNCTION_H 2 | #define LIBASR_PASS_INTRINSIC_FUNCTION_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_intrinsic_function(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_INTRINSIC_FUNCTION_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/list_expr.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_LIST_EXPR_H 2 | #define LIBASR_PASS_LIST_EXPR_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_list_expr(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_LIST_EXPR_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/loop_unroll.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | 15 | namespace LCompilers { 16 | 17 | using ASR::down_cast; 18 | using ASR::is_a; 19 | 20 | class LoopUnrollVisitor : public PassUtils::PassVisitor 21 | { 22 | private: 23 | 24 | int64_t unroll_factor; 25 | 26 | ASRUtils::ExprStmtDuplicator node_duplicator; 27 | 28 | public: 29 | 30 | LoopUnrollVisitor(Allocator &al_, size_t unroll_factor_) : 31 | PassVisitor(al_, nullptr), 32 | unroll_factor(unroll_factor_), node_duplicator(al_) 33 | { 34 | pass_result.reserve(al, 1); 35 | } 36 | 37 | void visit_DoLoop(const ASR::DoLoop_t& x) { 38 | ASR::DoLoop_t& xx = const_cast(x); 39 | ASR::do_loop_head_t x_head = x.m_head; 40 | ASR::expr_t* x_start = ASRUtils::expr_value(x_head.m_start); 41 | ASR::expr_t* x_end = ASRUtils::expr_value(x_head.m_end); 42 | ASR::expr_t* x_inc = nullptr; 43 | if( x_head.m_increment ) { 44 | x_inc = ASRUtils::expr_value(x_head.m_increment); 45 | } else { 46 | ASR::ttype_t* int32_type = ASRUtils::TYPE(ASR::make_Integer_t(al, x.base.base.loc, 4)); 47 | x_inc = ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, x_head.m_end->base.loc, 1, int32_type)); 48 | } 49 | 50 | int64_t _start, _end, _inc; 51 | if( !ASRUtils::is_value_constant(x_start, _start) || 52 | !ASRUtils::is_value_constant(x_end, _end) || 53 | !ASRUtils::is_value_constant(x_inc, _inc) ) { 54 | return ; 55 | } 56 | int64_t loop_size = (_end - _start)/_inc + 1; 57 | int64_t unroll_factor_ = std::min(unroll_factor, loop_size); 58 | bool create_unrolled_loop = unroll_factor_ < loop_size; 59 | // Avoid unnecessary loop unrolling 60 | if( !create_unrolled_loop ) { 61 | return ; 62 | } 63 | int64_t groups = loop_size / unroll_factor_; 64 | int64_t new_end = _start + (groups - 1) * _inc * unroll_factor_ + (unroll_factor_ - 1) * _inc; 65 | int64_t remaining_part = loop_size % unroll_factor_; 66 | ASR::ttype_t *int32_type = ASRUtils::TYPE(ASR::make_Integer_t(al, x.base.base.loc, 4)); 67 | xx.m_head.m_end = ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, x_end->base.loc, new_end, int32_type)); 68 | 69 | Vec init_and_whileloop = PassUtils::replace_doloop(al, x); 70 | ASR::stmt_t* whileloop_stmt = init_and_whileloop[1]; 71 | ASR::WhileLoop_t* whileloop = ASR::down_cast(whileloop_stmt); 72 | ASR::stmt_t* init_stmt = init_and_whileloop[0]; 73 | 74 | Vec unrolled_loop; 75 | unrolled_loop.reserve(al, whileloop->n_body * unroll_factor_); 76 | for( size_t i = 0; i < whileloop->n_body; i++ ) { 77 | unrolled_loop.push_back(al, whileloop->m_body[i]); 78 | } 79 | 80 | for( int64_t j = 1; j < unroll_factor_; j++ ) { 81 | for( size_t i = 0; i < whileloop->n_body; i++ ) { 82 | node_duplicator.success = true; 83 | ASR::stmt_t* m_body_copy = node_duplicator.duplicate_stmt(whileloop->m_body[i]); 84 | if( !node_duplicator.success ) { 85 | return ; 86 | } 87 | unrolled_loop.push_back(al, m_body_copy); 88 | } 89 | } 90 | 91 | pass_result.push_back(al, init_stmt); 92 | ASR::stmt_t* unrolled_whileloop = ASRUtils::STMT(ASR::make_WhileLoop_t(al, x.base.base.loc, 93 | whileloop->m_name, whileloop->m_test, unrolled_loop.p, unrolled_loop.size())); 94 | pass_result.push_back(al, unrolled_whileloop); 95 | for( int64_t i = 0; i < remaining_part; i++ ) { 96 | for( size_t i = 0; i < whileloop->n_body; i++ ) { 97 | ASR::stmt_t* m_body_copy = node_duplicator.duplicate_stmt(whileloop->m_body[i]); 98 | pass_result.push_back(al, m_body_copy); 99 | } 100 | } 101 | } 102 | 103 | }; 104 | 105 | void pass_loop_unroll(Allocator &al, ASR::TranslationUnit_t &unit, 106 | const LCompilers::PassOptions& pass_options) { 107 | LoopUnrollVisitor v(al, pass_options.unroll_factor); 108 | v.visit_TranslationUnit(unit); 109 | } 110 | 111 | 112 | } // namespace LCompilers 113 | -------------------------------------------------------------------------------- /src/libasr/pass/loop_unroll.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_LOOP_UNROLL_H 2 | #define LIBASR_PASS_LOOP_UNROLL_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_loop_unroll(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_LOOP_UNROLL_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/loop_vectorise.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_LOOP_VECTORISE_H 2 | #define LIBASR_PASS_LOOP_VECTORISE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_loop_vectorise(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_LOOP_VECTORISE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/nested_vars.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_NESTED_VARS_H 2 | #define LIBASR_PASS_NESTED_VARS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_nested_vars(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_NESTED_VARS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/param_to_const.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | 9 | namespace LCompilers { 10 | 11 | using ASR::down_cast; 12 | using ASR::is_a; 13 | 14 | /* 15 | 16 | This ASR pass replaces initializer expressions with evaluated values. The function 17 | `pass_replace_param_to_const` transforms the ASR tree in-place. 18 | 19 | Converts: 20 | 21 | integer, parameter :: i = 20 22 | integer :: a = i**2 + i 23 | 24 | to: 25 | 26 | integer, parameter :: i = 20 27 | integer :: a = 20**2 + 20 28 | 29 | */ 30 | 31 | class VarVisitor : public ASR::BaseWalkVisitor 32 | { 33 | private: 34 | ASR::expr_t* asr; 35 | 36 | public: 37 | // Currently `al` is not used, but we might need it in the future: 38 | Allocator &al; 39 | 40 | VarVisitor(Allocator &al) : asr{nullptr}, al{al} { 41 | } 42 | 43 | void visit_Program(const ASR::Program_t &x) { 44 | for (auto &item : x.m_symtab->get_scope()) { 45 | if (is_a(*item.second)) { 46 | ASR::Variable_t *v = down_cast(item.second); 47 | visit_Variable(*v); 48 | } 49 | } 50 | } 51 | 52 | void visit_IntegerUnaryMinus(const ASR::IntegerUnaryMinus_t &x) { 53 | visit_UnaryOp(x); 54 | } 55 | void visit_RealUnaryMinus(const ASR::RealUnaryMinus_t &x) { 56 | visit_UnaryOp(x); 57 | } 58 | void visit_ComplexUnaryMinus(const ASR::ComplexUnaryMinus_t &x) { 59 | visit_UnaryOp(x); 60 | } 61 | void visit_IntegerBitNot(const ASR::IntegerBitNot_t &x) { 62 | visit_UnaryOp(x); 63 | } 64 | void visit_LogicalNot(const ASR::LogicalNot_t &x) { 65 | visit_UnaryOp(x); 66 | } 67 | 68 | template 69 | void visit_UnaryOp(const T& x) { 70 | T& x_unconst = const_cast(x); 71 | asr = nullptr; 72 | this->visit_expr(*x.m_arg); 73 | if( asr != nullptr ) { 74 | x_unconst.m_arg = asr; 75 | } 76 | asr = const_cast(&(x.base)); 77 | } 78 | 79 | void visit_IntegerCompare(const ASR::IntegerCompare_t& x) { 80 | handle_Compare(x); 81 | } 82 | 83 | void visit_RealCompare(const ASR::RealCompare_t &x) { 84 | handle_Compare(x); 85 | } 86 | 87 | void visit_ComplexCompare(const ASR::ComplexCompare_t &x) { 88 | handle_Compare(x); 89 | } 90 | 91 | void visit_LogicalCompare(const ASR::LogicalCompare_t &x) { 92 | handle_Compare(x); 93 | } 94 | 95 | void visit_StringCompare(const ASR::StringCompare_t &x) { 96 | handle_Compare(x); 97 | } 98 | 99 | template 100 | void handle_Compare(const T& x) { 101 | T& x_unconst = const_cast(x); 102 | asr = nullptr; 103 | this->visit_expr(*x.m_left); 104 | if( asr != nullptr ) { 105 | x_unconst.m_left = asr; 106 | } 107 | asr = nullptr; 108 | this->visit_expr(*x.m_right); 109 | if( asr != nullptr ) { 110 | x_unconst.m_right = asr; 111 | } 112 | asr = const_cast(&(x.base)); 113 | } 114 | 115 | void visit_IntegerBinOp(const ASR::IntegerBinOp_t& x) { 116 | handle_BinOp(x); 117 | } 118 | 119 | void visit_RealBinOp(const ASR::RealBinOp_t& x) { 120 | handle_BinOp(x); 121 | } 122 | 123 | void visit_ComplexBinOp(const ASR::ComplexBinOp_t& x) { 124 | handle_BinOp(x); 125 | } 126 | 127 | void visit_LogicalBinOp(const ASR::LogicalBinOp_t& x) { 128 | handle_BinOp(x); 129 | } 130 | 131 | template 132 | void handle_BinOp(const T& x) { 133 | T& x_unconst = const_cast(x); 134 | asr = nullptr; 135 | this->visit_expr(*x.m_left); 136 | if( asr != nullptr ) { 137 | x_unconst.m_left = asr; 138 | } 139 | asr = nullptr; 140 | this->visit_expr(*x.m_right); 141 | if( asr != nullptr ) { 142 | x_unconst.m_right = asr; 143 | } 144 | asr = const_cast(&(x.base)); 145 | } 146 | 147 | void visit_Cast(const ASR::Cast_t& x) { 148 | /* 149 | asr = nullptr; 150 | this->visit_expr(*x.m_arg); 151 | ASR::Cast_t& x_unconst = const_cast(x); 152 | if( asr != nullptr ) { 153 | x_unconst.m_arg = asr; 154 | } 155 | */ 156 | asr = const_cast(&(x.base)); 157 | } 158 | 159 | void visit_Var(const ASR::Var_t& x) { 160 | if (is_a(*ASRUtils::symbol_get_past_external(x.m_v))) { 161 | ASR::Variable_t *init_var = ASR::down_cast(ASRUtils::symbol_get_past_external(x.m_v)); 162 | if( init_var->m_storage == ASR::storage_typeType::Parameter ) { 163 | if( init_var->m_symbolic_value == nullptr ) { 164 | asr = init_var->m_symbolic_value; 165 | } else { 166 | switch( init_var->m_symbolic_value->type ) { 167 | case ASR::exprType::IntegerConstant: 168 | case ASR::exprType::RealConstant: 169 | case ASR::exprType::ComplexConstant: 170 | case ASR::exprType::LogicalConstant: 171 | case ASR::exprType::StringConstant: { 172 | asr = init_var->m_symbolic_value; 173 | break; 174 | } 175 | default: { 176 | this->visit_expr(*(init_var->m_symbolic_value)); 177 | } 178 | } 179 | } 180 | } 181 | } 182 | } 183 | 184 | void visit_Variable(const ASR::Variable_t& x) { 185 | ASR::Variable_t& x_unconst = const_cast(x); 186 | if( x.m_symbolic_value != nullptr ) { 187 | asr = nullptr; 188 | visit_expr(*(x.m_symbolic_value)); 189 | if( asr != nullptr ) { 190 | x_unconst.m_symbolic_value = asr; 191 | asr = nullptr; 192 | } 193 | } 194 | } 195 | }; 196 | 197 | void pass_replace_param_to_const(Allocator &al, ASR::TranslationUnit_t &unit, 198 | const LCompilers::PassOptions &/*pass_options*/ 199 | ) { 200 | VarVisitor v(al); 201 | v.visit_TranslationUnit(unit); 202 | } 203 | 204 | } // namespace LCompilers 205 | -------------------------------------------------------------------------------- /src/libasr/pass/param_to_const.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_PARAM_TO_CONST_H 2 | #define LFORTRAN_PASS_PARAM_TO_CONST_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_param_to_const(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options 11 | ); 12 | 13 | } // namespace LCompilers 14 | 15 | #endif // LFORTRAN_PASS_PARAM_TO_CONST_H 16 | -------------------------------------------------------------------------------- /src/libasr/pass/pass_array_by_data.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_ARRAY_BY_DATA_H 2 | #define LFORTRAN_PASS_ARRAY_BY_DATA_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_array_by_data(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_ARRAY_BY_DATA_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/pass_compare.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_COMPARE_H 2 | #define LIBASR_PASS_COMPARE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_compare(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& /*pass_options*/); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_COMPARE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/pass_list_concat.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_LIST_CONCAT_H 2 | #define LIBASR_PASS_LIST_CONCAT_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LFortran { 8 | 9 | void pass_list_concat(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& /*pass_options*/); 11 | 12 | } // namespace LFortran 13 | 14 | #endif // LIBASR_PASS_LIST_CONCAT_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/pass_list_expr.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_LIST_EXPR_H 2 | #define LIBASR_PASS_LIST_EXPR_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_list_expr(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& /*pass_options*/); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_LIST_EXPR_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/print_arr.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_PRINT_ARR_H 2 | #define LFORTRAN_PASS_PRINT_ARR_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_print_arr(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_PRINT_ARR_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/print_list.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_PRINT_LIST_H 2 | #define LFORTRAN_PASS_PRINT_LIST_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_print_list( 10 | Allocator &al, ASR::TranslationUnit_t &unit, 11 | const LCompilers::PassOptions &pass_options); 12 | 13 | } // namespace LCompilers 14 | 15 | #endif // LFORTRAN_PASS_PRINT_LIST_H 16 | -------------------------------------------------------------------------------- /src/libasr/pass/print_list_tuple.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_PRINT_LIST_TUPLE_H 2 | #define LFORTRAN_PASS_PRINT_LIST_TUPLE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_print_list_tuple( 10 | Allocator &al, ASR::TranslationUnit_t &unit, 11 | const LCompilers::PassOptions &pass_options); 12 | 13 | } // namespace LCompilers 14 | 15 | #endif // LFORTRAN_PASS_PRINT_LIST_TUPLE_H 16 | -------------------------------------------------------------------------------- /src/libasr/pass/print_struct_type.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace LCompilers { 11 | 12 | using ASR::down_cast; 13 | using ASR::is_a; 14 | 15 | class PrintStructTypeVisitor : public PassUtils::PassVisitor 16 | { 17 | 18 | private: 19 | 20 | std::string rl_path; 21 | 22 | public: 23 | 24 | PrintStructTypeVisitor(Allocator &al_) : PassVisitor(al_, nullptr) { 25 | pass_result.reserve(al, 1); 26 | } 27 | 28 | void print_struct_type(ASR::expr_t* obj, 29 | ASR::StructType_t* struct_type_t, 30 | Vec& new_values) { 31 | if( struct_type_t->m_parent ) { 32 | ASR::symbol_t* parent = ASRUtils::symbol_get_past_external(struct_type_t->m_parent); 33 | if( ASR::is_a(*parent) ) { 34 | ASR::StructType_t* parent_struct_type_t = ASR::down_cast(parent); 35 | print_struct_type(obj, parent_struct_type_t, new_values); 36 | } else { 37 | LCOMPILERS_ASSERT(false); 38 | } 39 | } 40 | 41 | ASR::symbol_t* obj_v = nullptr; 42 | if( ASR::is_a(*obj) ) { 43 | obj_v = ASR::down_cast(obj)->m_v; 44 | } 45 | for( size_t i = 0; i < struct_type_t->n_members; i++ ) { 46 | ASR::symbol_t* member = struct_type_t->m_symtab->resolve_symbol(struct_type_t->m_members[i]); 47 | new_values.push_back(al, ASRUtils::EXPR(ASRUtils::getStructInstanceMember_t( 48 | al, struct_type_t->base.base.loc, 49 | (ASR::asr_t*) obj, obj_v, member, current_scope))); 50 | } 51 | } 52 | 53 | void visit_Print(const ASR::Print_t& x) { 54 | #define is_struct_type(value) if( ASR::is_a( \ 55 | *ASRUtils::expr_type(value)) ) \ 56 | 57 | bool is_struct_type_present = false; 58 | for( size_t i = 0; i < x.n_values; i++ ) { 59 | is_struct_type(x.m_values[i]) 60 | { 61 | 62 | is_struct_type_present = true; 63 | break; 64 | 65 | } 66 | } 67 | if( !is_struct_type_present ) { 68 | return ; 69 | } 70 | 71 | /* 72 | TODO: Respect fmt. 73 | */ 74 | Vec new_values; 75 | new_values.reserve(al, 1); 76 | for( size_t i = 0; i < x.n_values; i++ ) { 77 | ASR::expr_t* x_m_value = x.m_values[i]; 78 | if( ASR::is_a(*x_m_value) ) { 79 | x_m_value = ASR::down_cast(x_m_value)->m_overloaded; 80 | } 81 | is_struct_type(x_m_value) 82 | { 83 | 84 | ASR::Struct_t* struct_t = ASR::down_cast(ASRUtils::expr_type(x_m_value)); 85 | ASR::symbol_t* struct_t_sym = ASRUtils::symbol_get_past_external(struct_t->m_derived_type); 86 | if( ASR::is_a(*struct_t_sym) ) { 87 | ASR::StructType_t* struct_type_t = ASR::down_cast(struct_t_sym); 88 | print_struct_type(x_m_value, struct_type_t, new_values); 89 | } else { 90 | LCOMPILERS_ASSERT(false); 91 | } 92 | 93 | } else { 94 | 95 | new_values.push_back(al, x.m_values[i]); 96 | 97 | } 98 | } 99 | 100 | ASR::Print_t& xx = const_cast(x); 101 | xx.m_values = new_values.p; 102 | xx.n_values = new_values.size(); 103 | } 104 | 105 | }; 106 | 107 | void pass_replace_print_struct_type( 108 | Allocator &al, ASR::TranslationUnit_t &unit, 109 | const LCompilers::PassOptions& /*pass_options*/) { 110 | PrintStructTypeVisitor v(al); 111 | v.visit_TranslationUnit(unit); 112 | } 113 | 114 | 115 | } // namespace LCompilers 116 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_arr_slice.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_ARR_SLICE_H 2 | #define LIBASR_PASS_REPLACE_ARR_SLICE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_arr_slice(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_ARR_SLICE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_array_op.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_ARRAY_OP_H 2 | #define LIBASR_PASS_REPLACE_ARRAY_OP_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_array_op(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_ARRAY_OP_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_class_constructor.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_CLASS_CONSTRUCTOR_H 2 | #define LIBASR_PASS_REPLACE_CLASS_CONSTRUCTOR_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_class_constructor(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_CLASS_CONSTRUCTOR_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_div_to_mul.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_DIV_TO_MUL_H 2 | #define LIBASR_PASS_REPLACE_DIV_TO_MUL_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_div_to_mul(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_DIV_TO_MUL_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_do_loops.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_DO_LOOPS_H 2 | #define LIBASR_PASS_REPLACE_DO_LOOPS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_do_loops(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_DO_LOOPS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_flip_sign.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_FLIP_SIGN_H 2 | #define LIBASR_PASS_REPLACE_FLIP_SIGN_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_flip_sign(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_FLIP_SIGN_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_fma.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_FMA_H 2 | #define LIBASR_PASS_REPLACE_FMA_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_fma(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_FMA_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_for_all.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_FOR_ALL_H 2 | #define LIBASR_PASS_REPLACE_FOR_ALL_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_for_all(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_FOR_ALL_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_implied_do_loops.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_IMPLIED_DO_LOOPS_H 2 | #define LIBASR_PASS_REPLACE_IMPLIED_DO_LOOPS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_implied_do_loops(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_IMPLIED_DO_LOOPS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_init_expr.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_INIT_EXPR_H 2 | #define LIBASR_PASS_REPLACE_INIT_EXPR_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_init_expr(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_INIT_EXPR_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_intrinsic_function.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_INTRINSIC_FUNCTION_H 2 | #define LIBASR_PASS_REPLACE_INTRINSIC_FUNCTION_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_intrinsic_function(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_INTRINSIC_FUNCTION_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_param_to_const.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_PARAM_TO_CONST_H 2 | #define LIBASR_PASS_REPLACE_PARAM_TO_CONST_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_param_to_const(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_PARAM_TO_CONST_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_print_arr.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_PRINT_ARR_H 2 | #define LIBASR_PASS_REPLACE_PRINT_ARR_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_print_arr(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_PRINT_ARR_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_print_list_tuple.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_PRINT_LIST_TUPLE_H 2 | #define LIBASR_PASS_REPLACE_PRINT_LIST_TUPLE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_print_list_tuple(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_PRINT_LIST_TUPLE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_print_struct_type.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_PRINT_STRUCT_TYPE_H 2 | #define LIBASR_PASS_REPLACE_PRINT_STRUCT_TYPE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_print_struct_type(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_PRINT_STRUCT_TYPE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_select_case.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_SELECT_CASE_H 2 | #define LIBASR_PASS_REPLACE_SELECT_CASE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_select_case(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_SELECT_CASE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_sign_from_value.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_SIGN_FROM_VALUE_H 2 | #define LIBASR_PASS_REPLACE_SIGN_FROM_VALUE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_sign_from_value(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_SIGN_FROM_VALUE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_symbolic.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_SYMBOLIC_H 2 | #define LIBASR_PASS_REPLACE_SYMBOLIC_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_symbolic(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_SYMBOLIC_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/replace_where.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_REPLACE_WHERE_H 2 | #define LIBASR_PASS_REPLACE_WHERE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_where(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_REPLACE_WHERE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/select_case.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | 10 | namespace LCompilers { 11 | 12 | using ASR::down_cast; 13 | using ASR::is_a; 14 | 15 | /* 16 | 17 | This ASR pass replaces select-case construct with if-then-else-if statements. The function 18 | `pass_replace_select_case` transforms the ASR tree in-place. 19 | 20 | Converts: 21 | 22 | select case (a) 23 | 24 | case (b:c) 25 | ... 26 | 27 | case (d:e) 28 | ... 29 | case (f) 30 | ... 31 | 32 | case default 33 | ... 34 | 35 | end select 36 | 37 | to: 38 | 39 | if ( b <= a && a <= c ) then 40 | ... 41 | else if ( d <= a && a <= e ) then 42 | ... 43 | else if (f) then 44 | ... 45 | else 46 | ... 47 | end if 48 | 49 | */ 50 | 51 | inline ASR::expr_t* gen_test_expr_CaseStmt(Allocator& al, const Location& loc, ASR::CaseStmt_t* Case_Stmt, ASR::expr_t* a_test) { 52 | ASR::expr_t* test_expr = nullptr; 53 | if( Case_Stmt->n_test == 1 ) { 54 | test_expr = PassUtils::create_compare_helper(al, loc, a_test, Case_Stmt->m_test[0], ASR::cmpopType::Eq); 55 | } else if( Case_Stmt->n_test == 2 ) { 56 | ASR::expr_t* left = PassUtils::create_compare_helper(al, loc, a_test, Case_Stmt->m_test[0], ASR::cmpopType::Eq); 57 | ASR::expr_t* right = PassUtils::create_compare_helper(al, loc, a_test, Case_Stmt->m_test[1], ASR::cmpopType::Eq); 58 | test_expr = ASRUtils::EXPR(ASR::make_LogicalBinOp_t(al, loc, left, 59 | ASR::logicalbinopType::Or, right, ASRUtils::expr_type(left), nullptr)); 60 | } else { 61 | ASR::expr_t* left = PassUtils::create_compare_helper(al, loc, a_test, Case_Stmt->m_test[0], ASR::cmpopType::Eq); 62 | ASR::expr_t* right = PassUtils::create_compare_helper(al, loc, a_test, Case_Stmt->m_test[1], ASR::cmpopType::Eq); 63 | test_expr = ASRUtils::EXPR(ASR::make_LogicalBinOp_t(al, loc, left, 64 | ASR::logicalbinopType::Or, right, ASRUtils::expr_type(left), nullptr)); 65 | for( std::uint32_t j = 2; j < Case_Stmt->n_test; j++ ) { 66 | ASR::expr_t* newExpr = PassUtils::create_compare_helper(al, loc, a_test, Case_Stmt->m_test[j], ASR::cmpopType::Eq); 67 | test_expr = ASRUtils::EXPR(ASR::make_LogicalBinOp_t(al, loc, test_expr, 68 | ASR::logicalbinopType::Or, newExpr, ASRUtils::expr_type(test_expr), nullptr)); 69 | } 70 | } 71 | return test_expr; 72 | } 73 | 74 | inline ASR::expr_t* gen_test_expr_CaseStmt_Range(Allocator& al, const Location& loc, ASR::CaseStmt_Range_t* Case_Stmt, ASR::expr_t* a_test) { 75 | ASR::expr_t* test_expr = nullptr; 76 | if( Case_Stmt->m_start != nullptr && Case_Stmt->m_end == nullptr ) { 77 | test_expr = PassUtils::create_compare_helper(al, loc, Case_Stmt->m_start, a_test, ASR::cmpopType::LtE); 78 | } else if( Case_Stmt->m_start == nullptr && Case_Stmt->m_end != nullptr ) { 79 | test_expr = PassUtils::create_compare_helper(al, loc, a_test, Case_Stmt->m_end, ASR::cmpopType::LtE); 80 | } else if( Case_Stmt->m_start != nullptr && Case_Stmt->m_end != nullptr ) { 81 | ASR::expr_t* left = PassUtils::create_compare_helper(al, loc, Case_Stmt->m_start, a_test, ASR::cmpopType::LtE); 82 | ASR::expr_t* right = PassUtils::create_compare_helper(al, loc, a_test, Case_Stmt->m_end, ASR::cmpopType::LtE); 83 | test_expr = ASRUtils::EXPR(ASR::make_LogicalBinOp_t(al, loc, left, 84 | ASR::logicalbinopType::And, right, ASRUtils::expr_type(left), nullptr)); 85 | } 86 | return test_expr; 87 | } 88 | 89 | void case_to_if(Allocator& al, const ASR::Select_t& x, ASR::expr_t* a_test, Vec& body) { 90 | int idx = (int) x.n_body - 1; 91 | ASR::case_stmt_t* case_body = x.m_body[idx]; 92 | ASR::stmt_t* last_if_else = nullptr; 93 | switch(case_body->type) { 94 | case ASR::case_stmtType::CaseStmt: { 95 | ASR::CaseStmt_t* Case_Stmt = (ASR::CaseStmt_t*)(&(case_body->base)); 96 | ASR::expr_t* test_expr = gen_test_expr_CaseStmt(al, x.base.base.loc, Case_Stmt, a_test); 97 | last_if_else = ASRUtils::STMT(ASR::make_If_t(al, x.base.base.loc, test_expr, Case_Stmt->m_body, Case_Stmt->n_body, x.m_default, x.n_default)); 98 | break; 99 | } 100 | case ASR::case_stmtType::CaseStmt_Range: { 101 | ASR::CaseStmt_Range_t* Case_Stmt = (ASR::CaseStmt_Range_t*)(&(case_body->base)); 102 | ASR::expr_t* test_expr = gen_test_expr_CaseStmt_Range(al, x.base.base.loc, Case_Stmt, a_test); 103 | last_if_else = ASRUtils::STMT(ASR::make_If_t(al, x.base.base.loc, test_expr, Case_Stmt->m_body, Case_Stmt->n_body, x.m_default, x.n_default)); 104 | break; 105 | } 106 | } 107 | 108 | for( idx = (int) x.n_body - 2; idx >= 0; idx-- ) { 109 | ASR::case_stmt_t* case_body = x.m_body[idx]; 110 | ASR::expr_t* test_expr = nullptr; 111 | ASR::stmt_t** m_body = nullptr; 112 | size_t n_body = 0; 113 | switch(case_body->type) { 114 | case ASR::case_stmtType::CaseStmt: { 115 | ASR::CaseStmt_t* Case_Stmt = (ASR::CaseStmt_t*)(&(case_body->base)); 116 | test_expr = gen_test_expr_CaseStmt(al, x.base.base.loc, Case_Stmt, a_test); 117 | m_body = Case_Stmt->m_body; 118 | n_body = Case_Stmt->n_body; 119 | break; 120 | } 121 | case ASR::case_stmtType::CaseStmt_Range: { 122 | ASR::CaseStmt_Range_t* Case_Stmt = (ASR::CaseStmt_Range_t*)(&(case_body->base)); 123 | test_expr = gen_test_expr_CaseStmt_Range(al, x.base.base.loc, Case_Stmt, a_test); 124 | m_body = Case_Stmt->m_body; 125 | n_body = Case_Stmt->n_body; 126 | break; 127 | } 128 | } 129 | Vec if_body_vec; 130 | if_body_vec.reserve(al, 1); 131 | if_body_vec.push_back(al, last_if_else); 132 | last_if_else = ASRUtils::STMT(ASR::make_If_t(al, x.base.base.loc, test_expr, m_body, n_body, if_body_vec.p, if_body_vec.size())); 133 | } 134 | body.reserve(al, 1); 135 | body.push_back(al, last_if_else); 136 | } 137 | 138 | Vec replace_selectcase(Allocator &al, const ASR::Select_t &select_case) { 139 | ASR::expr_t *a = select_case.m_test; 140 | Vec body; 141 | case_to_if(al, select_case, a, body); 142 | /* 143 | std::cout << "Input:" << std::endl; 144 | std::cout << pickle((ASR::asr_t&)loop); 145 | std::cout << "Output:" << std::endl; 146 | std::cout << pickle((ASR::asr_t&)*stmt1); 147 | std::cout << pickle((ASR::asr_t&)*stmt2); 148 | std::cout << "--------------" << std::endl; 149 | */ 150 | return body; 151 | } 152 | 153 | class SelectCaseVisitor : public PassUtils::PassVisitor 154 | { 155 | 156 | public: 157 | SelectCaseVisitor(Allocator &al) : PassVisitor(al, nullptr) { 158 | } 159 | 160 | void visit_WhileLoop(const ASR::WhileLoop_t &x) { 161 | // FIXME: this is a hack, we need to pass in a non-const `x`, 162 | // which requires to generate a TransformVisitor. 163 | ASR::WhileLoop_t &xx = const_cast(x); 164 | transform_stmts(xx.m_body, xx.n_body); 165 | } 166 | 167 | void visit_Select(const ASR::Select_t &x) { 168 | pass_result = replace_selectcase(al, x); 169 | } 170 | }; 171 | 172 | void pass_replace_select_case(Allocator &al, ASR::TranslationUnit_t &unit, 173 | const LCompilers::PassOptions& /*pass_options*/) { 174 | SelectCaseVisitor v(al); 175 | // Each call transforms only one layer of nested loops, so we call it twice 176 | // to transform doubly nested loops: 177 | v.visit_TranslationUnit(unit); 178 | v.visit_TranslationUnit(unit); 179 | } 180 | 181 | 182 | } // namespace LCompilers 183 | -------------------------------------------------------------------------------- /src/libasr/pass/select_case.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_SELECT_CASE_H 2 | #define LFORTRAN_PASS_SELECT_CASE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_select_case(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LFORTRAN_PASS_SELECT_CASE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/sign_from_value.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | 13 | namespace LCompilers { 14 | 15 | using ASR::down_cast; 16 | using ASR::is_a; 17 | 18 | /* 19 | 20 | This ASR pass converts assigning of sign from a value to 21 | different value with a call to internal optimization routine. 22 | This allows backend specific code generation for better performance. 23 | 24 | Converts: 25 | 26 | real :: a, b, c 27 | c = a*sign(1.0, b) 28 | 29 | to: 30 | 31 | c = sign_from_value(a, b) 32 | 33 | */ 34 | class SignFromValueVisitor : public PassUtils::SkipOptimizationFunctionVisitor 35 | { 36 | private: 37 | ASR::TranslationUnit_t &unit; 38 | 39 | LCompilers::PassOptions pass_options; 40 | 41 | ASR::expr_t* sign_from_value_var; 42 | 43 | // To make sure that SignFromValue is applied only for 44 | // the nodes implemented in this class 45 | bool from_sign_from_value; 46 | 47 | public: 48 | SignFromValueVisitor(Allocator &al_, ASR::TranslationUnit_t &unit_, 49 | const LCompilers::PassOptions& pass_options_) : SkipOptimizationFunctionVisitor(al_), 50 | unit(unit_), pass_options(pass_options_), sign_from_value_var(nullptr), from_sign_from_value(false) 51 | { 52 | pass_result.reserve(al, 1); 53 | } 54 | 55 | bool is_value_one(ASR::expr_t* expr) { 56 | double value; 57 | if( ASRUtils::is_value_constant(expr, value) ) { 58 | return value == 1.0; 59 | } 60 | return false; 61 | } 62 | 63 | ASR::expr_t* is_extract_sign(ASR::expr_t* expr) { 64 | if( !ASR::is_a(*expr) ) { 65 | return nullptr; 66 | } 67 | ASR::FunctionCall_t* func_call = ASR::down_cast(expr); 68 | ASR::symbol_t* func_sym = ASRUtils::symbol_get_past_external(func_call->m_name); 69 | if( !ASR::is_a(*func_sym) ) { 70 | return nullptr; 71 | } 72 | ASR::Function_t* func = ASR::down_cast(func_sym); 73 | if( ASRUtils::is_intrinsic_procedure(func) && 74 | std::string(func->m_name).find("sign") == std::string::npos ) { 75 | return nullptr; 76 | } 77 | ASR::expr_t *arg0 = func_call->m_args[0].m_value, *arg1 = func_call->m_args[1].m_value; 78 | if( !is_value_one(arg0) ) { 79 | return nullptr; 80 | } 81 | return arg1; 82 | } 83 | 84 | void visit_IntegerBinOp(const ASR::IntegerBinOp_t& x) { 85 | handle_BinOp(x); 86 | } 87 | 88 | void visit_RealBinOp(const ASR::RealBinOp_t& x) { 89 | handle_BinOp(x); 90 | } 91 | 92 | void visit_ComplexBinOp(const ASR::ComplexBinOp_t& x) { 93 | handle_BinOp(x); 94 | } 95 | 96 | template 97 | void handle_BinOp(const T& x_const) { 98 | if( !from_sign_from_value ) { 99 | return ; 100 | } 101 | 102 | from_sign_from_value = true; 103 | T& x = const_cast(x_const); 104 | 105 | sign_from_value_var = nullptr; 106 | visit_expr(*x.m_left); 107 | if( sign_from_value_var ) { 108 | x.m_left = sign_from_value_var; 109 | } 110 | 111 | sign_from_value_var = nullptr; 112 | visit_expr(*x.m_right); 113 | if( sign_from_value_var ) { 114 | x.m_right = sign_from_value_var; 115 | } 116 | sign_from_value_var = nullptr; 117 | 118 | if( x.m_op != ASR::binopType::Mul ) { 119 | return ; 120 | } 121 | 122 | ASR::expr_t *first_arg = nullptr, *second_arg = nullptr; 123 | 124 | first_arg = is_extract_sign(x.m_left); 125 | second_arg = is_extract_sign(x.m_right); 126 | 127 | if( second_arg ) { 128 | first_arg = x.m_left; 129 | } else if( first_arg ) { 130 | second_arg = x.m_right; 131 | } else { 132 | return ; 133 | } 134 | 135 | sign_from_value_var = PassUtils::get_sign_from_value(first_arg, second_arg, 136 | al, unit, x.base.base.loc, pass_options); 137 | from_sign_from_value = false; 138 | } 139 | 140 | void visit_Assignment(const ASR::Assignment_t& x) { 141 | from_sign_from_value = true; 142 | ASR::Assignment_t& xx = const_cast(x); 143 | sign_from_value_var = nullptr; 144 | visit_expr(*x.m_value); 145 | if( sign_from_value_var ) { 146 | xx.m_value = sign_from_value_var; 147 | } 148 | sign_from_value_var = nullptr; 149 | from_sign_from_value = false; 150 | } 151 | 152 | }; 153 | 154 | void pass_replace_sign_from_value(Allocator &al, ASR::TranslationUnit_t &unit, 155 | const LCompilers::PassOptions& pass_options) { 156 | SignFromValueVisitor v(al, unit, pass_options); 157 | v.visit_TranslationUnit(unit); 158 | } 159 | 160 | 161 | } // namespace LCompilers 162 | -------------------------------------------------------------------------------- /src/libasr/pass/sign_from_value.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_SIGN_FROM_VALUE_H 2 | #define LIBASR_PASS_SIGN_FROM_VALUE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_sign_from_value(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_SIGN_FROM_VALUE_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/stmt_walk_visitor.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | namespace LCompilers { 4 | 5 | namespace ASR { 6 | template 7 | class StatementWalkVisitor : public PassUtils::PassVisitor 8 | { 9 | 10 | public: 11 | 12 | StatementWalkVisitor(Allocator &al_) : PassUtils::PassVisitor(al_, nullptr) { 13 | } 14 | 15 | void visit_WhileLoop(const ASR::WhileLoop_t &x) { 16 | // FIXME: this is a hack, we need to pass in a non-const `x`, 17 | // which requires to generate a TransformVisitor. 18 | ASR::WhileLoop_t &xx = const_cast(x); 19 | PassUtils::PassVisitor::transform_stmts(xx.m_body, xx.n_body); 20 | } 21 | 22 | void visit_DoLoop(const ASR::DoLoop_t &x) { 23 | // FIXME: this is a hack, we need to pass in a non-const `x`, 24 | // which requires to generate a TransformVisitor. 25 | ASR::DoLoop_t &xx = const_cast(x); 26 | PassUtils::PassVisitor::transform_stmts(xx.m_body, xx.n_body); 27 | } 28 | }; 29 | } // namespace ASR 30 | 31 | } // namespace LCompilers 32 | -------------------------------------------------------------------------------- /src/libasr/pass/subroutine_from_function.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_SUBROUTINE_FROM_FUNCTION_H 2 | #define LIBASR_PASS_SUBROUTINE_FROM_FUNCTION_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_create_subroutine_from_function(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const LCompilers::PassOptions& pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_SUBROUTINE_FROM_FUNCTION_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/transform_optional_argument_functions.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_TRANSFORM_OPTIONAL_ARGUMENT_FUNCTIONS_H 2 | #define LIBASR_PASS_TRANSFORM_OPTIONAL_ARGUMENT_FUNCTIONS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_transform_optional_argument_functions(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_TRANSFORM_OPTIONAL_ARGUMENT_FUNCTIONS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/unique_symbols.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_UNIQUE_SYMBOLS_H 2 | #define LIBASR_PASS_UNIQUE_SYMBOLS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_unique_symbols(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_UNIQUE_SYMBOLS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/unused_functions.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_UNUSED_FUNCTIONS_H 2 | #define LIBASR_PASS_UNUSED_FUNCTIONS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_unused_functions(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_UNUSED_FUNCTIONS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/update_array_dim_intrinsic_calls.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | 12 | 13 | namespace LCompilers { 14 | 15 | /* 16 | 17 | The following class implements replacer methods for replacing 18 | calls to intrinsic functions (which provide dimensional information 19 | of arrays like size) with the actual result. This happens only for arrays 20 | which are input arguments to a procedure, and the dimensional information 21 | in their type is not empty. See the example below, 22 | 23 | subrotuine copy(x, y, n) 24 | integer, intent(in) :: n 25 | integer, intent(in) :: x(n) 26 | integer, intent(in) :: y(n) 27 | do i = 1, size(x) 28 | do j = 1, size(y) 29 | print *, x(i) + y(j) 30 | end do 31 | end do 32 | end subroutine 33 | 34 | converted to, 35 | 36 | subrotuine copy(x, y, n) 37 | integer, intent(in) :: n 38 | integer, intent(in) :: x(n) 39 | integer, intent(in) :: y(n) 40 | do i = 1, n 41 | do j = 1, n 42 | print *, x(i) + y(j) 43 | end do 44 | end do 45 | end subroutine 46 | 47 | */ 48 | class ReplaceArrayDimIntrinsicCalls: public ASR::BaseExprReplacer { 49 | 50 | private: 51 | 52 | Allocator& al; 53 | 54 | public: 55 | 56 | ReplaceArrayDimIntrinsicCalls(Allocator& al_) : al(al_) 57 | {} 58 | 59 | void replace_ArraySize(ASR::ArraySize_t* x) { 60 | if( !ASR::is_a(*x->m_v) || 61 | (x->m_dim != nullptr && !ASRUtils::is_value_constant(x->m_dim)) ) { 62 | return ; 63 | } 64 | 65 | ASR::Variable_t* v = ASRUtils::EXPR2VAR(x->m_v); 66 | ASR::ttype_t* array_type = ASRUtils::expr_type(x->m_v); 67 | ASR::dimension_t* dims = nullptr; 68 | int n = ASRUtils::extract_dimensions_from_ttype(array_type, dims); 69 | bool is_argument = v->m_intent == ASRUtils::intent_in || v->m_intent == ASRUtils::intent_out || v->m_intent == ASRUtils::intent_inout; 70 | if( !(n > 0 && is_argument && 71 | !ASRUtils::is_dimension_empty(dims, n)) ) { 72 | return ; 73 | } 74 | if( x->m_dim != nullptr ) { 75 | int64_t dim = -1; 76 | ASRUtils::extract_value(x->m_dim, dim); 77 | *current_expr = dims[dim - 1].m_length; 78 | return ; 79 | } 80 | 81 | ASR::expr_t* array_size = ASRUtils::EXPR(ASR::make_IntegerConstant_t( 82 | al, x->base.base.loc, 1, x->m_type)); 83 | for( int i = 0; i < n; i++ ) { 84 | array_size = ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, x->base.base.loc, 85 | array_size, ASR::binopType::Mul, dims[i].m_length, x->m_type, 86 | nullptr)); 87 | } 88 | *current_expr = array_size; 89 | } 90 | 91 | void replace_ArrayBound(ASR::ArrayBound_t* x) { 92 | if( !ASR::is_a(*x->m_v) || 93 | !ASRUtils::is_value_constant(x->m_dim) ) { 94 | return ; 95 | } 96 | 97 | ASR::Variable_t* v = ASRUtils::EXPR2VAR(x->m_v); 98 | ASR::ttype_t* array_type = ASRUtils::expr_type(x->m_v); 99 | ASR::dimension_t* dims = nullptr; 100 | int n = ASRUtils::extract_dimensions_from_ttype(array_type, dims); 101 | bool is_argument = ASRUtils::is_arg_dummy(v->m_intent); 102 | if( !(n > 0 && is_argument && 103 | !ASRUtils::is_dimension_empty(dims, n)) ) { 104 | return ; 105 | } 106 | int64_t dim = -1; 107 | ASRUtils::extract_value(x->m_dim, dim); 108 | if( x->m_bound == ASR::arrayboundType::LBound ) { 109 | *current_expr = dims[dim - 1].m_start; 110 | } else { 111 | ASR::expr_t* ub = ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, 112 | x->base.base.loc, dims[dim - 1].m_length, 113 | ASR::binopType::Add, dims[dim - 1].m_start, 114 | x->m_type, nullptr)); 115 | ASR::expr_t* const_1 = ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, 116 | x->base.base.loc, 1, x->m_type)); 117 | *current_expr = ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, x->base.base.loc, 118 | ub, ASR::binopType::Sub, const_1, x->m_type, nullptr)); 119 | } 120 | } 121 | 122 | }; 123 | 124 | /* 125 | This class implements call_replacer method which calls the 126 | ReplaceArrayDimIntrinsicCalls.replace_expr method on all the expressions 127 | present in the ASR. 128 | */ 129 | class ArrayDimIntrinsicCallsVisitor : public ASR::CallReplacerOnExpressionsVisitor 130 | { 131 | private: 132 | 133 | ReplaceArrayDimIntrinsicCalls replacer; 134 | 135 | public: 136 | 137 | ArrayDimIntrinsicCallsVisitor(Allocator& al_) : replacer(al_) {} 138 | 139 | void call_replacer() { 140 | replacer.current_expr = current_expr; 141 | replacer.replace_expr(*current_expr); 142 | } 143 | 144 | }; 145 | 146 | void pass_update_array_dim_intrinsic_calls(Allocator &al, ASR::TranslationUnit_t &unit, 147 | const LCompilers::PassOptions& /*pass_options*/) { 148 | ArrayDimIntrinsicCallsVisitor v(al); 149 | v.visit_TranslationUnit(unit); 150 | PassUtils::UpdateDependenciesVisitor u(al); 151 | u.visit_TranslationUnit(unit); 152 | } 153 | 154 | } // namespace LCompilers 155 | -------------------------------------------------------------------------------- /src/libasr/pass/update_array_dim_intrinsic_calls.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_UPDATE_ARRAY_DIM_INTRINSIC_CALLS_H 2 | #define LIBASR_PASS_UPDATE_ARRAY_DIM_INTRINSIC_CALLS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_update_array_dim_intrinsic_calls(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_UPDATE_ARRAY_DIM_INTRINSIC_CALLS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pass/where.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_PASS_WHERE_H 2 | #define LFORTRAN_PASS_WHERE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_replace_where(Allocator &al, ASR::TranslationUnit_t &unit, const LCompilers::PassOptions& pass_options); 10 | 11 | } // namespace LCompilers 12 | 13 | #endif // LFORTRAN_PASS_WHERE_H 14 | -------------------------------------------------------------------------------- /src/libasr/pass/wrap_global_stmts.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PASS_WRAP_GLOBAL_STMTS_H 2 | #define LIBASR_PASS_WRAP_GLOBAL_STMTS_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | void pass_wrap_global_stmts(Allocator &al, ASR::TranslationUnit_t &unit, 10 | const PassOptions &pass_options); 11 | 12 | } // namespace LCompilers 13 | 14 | #endif // LIBASR_PASS_WRAP_GLOBAL_STMTS_H 15 | -------------------------------------------------------------------------------- /src/libasr/pickle.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_PICKLE_H 2 | #define LIBASR_PICKLE_H 3 | 4 | #include 5 | #include 6 | 7 | namespace LCompilers { 8 | 9 | // Pickle an ASR node 10 | std::string pickle(ASR::asr_t &asr, bool colors=false, bool indent=false, 11 | bool show_intrinsic_modules=false); 12 | std::string pickle(ASR::TranslationUnit_t &asr, bool colors=false, 13 | bool indent=false, bool show_intrinsic_modules=false); 14 | 15 | // Print the tree structure 16 | std::string pickle_tree(ASR::asr_t &asr, bool colors, bool show_intrinsic_modules=false); 17 | std::string pickle_tree(ASR::TranslationUnit_t &asr, bool colors, bool show_intrinsic_modules=false); 18 | 19 | // Print Json structure 20 | std::string pickle_json(ASR::asr_t &asr, LocationManager &lm, bool no_loc, bool show_intrinsic_modules); 21 | std::string pickle_json(ASR::TranslationUnit_t &asr, LocationManager &lm, bool no_loc, bool show_intrinsic_modules); 22 | 23 | } // namespace LCompilers 24 | 25 | #endif // LIBASR_PICKLE_H 26 | -------------------------------------------------------------------------------- /src/libasr/semantic_exception.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_SEMANTICS_SEMANTIC_EXCEPTION_H 2 | #define LFORTRAN_SEMANTICS_SEMANTIC_EXCEPTION_H 3 | 4 | #include 5 | 6 | namespace LCompilers { 7 | 8 | // This exception is only used internally in the lfortran/semantics/ directory 9 | // and in lfortran/asr_utils.h/cpp. Nowhere else. 10 | 11 | class SemanticError 12 | { 13 | public: 14 | diag::Diagnostic d; 15 | public: 16 | SemanticError(const std::string &msg, const Location &loc) 17 | : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::Semantic, { 18 | diag::Label("", {loc}) 19 | })} 20 | { } 21 | 22 | SemanticError(const diag::Diagnostic &d) : d{d} { } 23 | }; 24 | 25 | class SemanticAbort 26 | { 27 | }; 28 | 29 | } // namespace LCompilers 30 | 31 | 32 | #endif 33 | -------------------------------------------------------------------------------- /src/libasr/serialization.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_SERIALIZATION_H 2 | #define LIBASR_SERIALIZATION_H 3 | 4 | #include 5 | 6 | namespace LCompilers { 7 | 8 | std::string serialize(const ASR::asr_t &asr); 9 | std::string serialize(const ASR::TranslationUnit_t &unit); 10 | ASR::asr_t* deserialize_asr(Allocator &al, const std::string &s, 11 | bool load_symtab_id, SymbolTable &symtab); 12 | ASR::asr_t* deserialize_asr(Allocator &al, const std::string &s, 13 | bool load_symtab_id); 14 | 15 | void fix_external_symbols(ASR::TranslationUnit_t &unit, 16 | SymbolTable &external_symtab); 17 | } // namespace LCompilers 18 | 19 | #endif // LIBASR_SERIALIZATION_H 20 | -------------------------------------------------------------------------------- /src/libasr/stacktrace.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_STACKTRACE_H 2 | #define LFORTRAN_STACKTRACE_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | namespace LCompilers { 9 | 10 | /* Returns the current stacktrace as a string. 11 | * 12 | * impl_stacktrace_depth ... The stacktrace depth to remove from the stacktrace 13 | * printout to avoid showing users implementation functions in the 14 | * stacktrace. 15 | */ 16 | std::string get_stacktrace(int impl_stacktrace_depth=0); 17 | 18 | // Prints the current stacktrace to stdout. 19 | void show_stacktrace(); 20 | 21 | // Prints the current stacktrace to stdout on segfault. 22 | void print_stack_on_segfault(); 23 | 24 | // Path to the binary executable 25 | extern std::string binary_executable_path; 26 | 27 | struct StacktraceItem 28 | { 29 | // Always found 30 | uintptr_t pc; 31 | 32 | // The following two are either both found, or not found 33 | uintptr_t local_pc=0; // 0 if not found 34 | std::string binary_filename; // "" if not found 35 | 36 | // This can be found or not 37 | std::string function_name; // "" if not found 38 | 39 | // The following two are either both found, or not found 40 | std::string source_filename; // "" if not found 41 | int line_number=-1; // -1 if not found 42 | }; 43 | 44 | // Returns the stacktrace, fills in the `pc` member 45 | std::vector get_stacktrace_addresses(); 46 | 47 | // Fills in the `local_pc` and `binary_filename` members 48 | void get_local_addresses(std::vector &d); 49 | 50 | // Fills in the `function_name` if available, and if so, also fills in 51 | // `source_filename` and `line_number` if available 52 | void get_local_info(std::vector &d); 53 | 54 | // Converts the information stored in `d` into a string 55 | std::string stacktrace2str(const std::vector &d, 56 | int skip); 57 | 58 | // Returns line number information from address 59 | void address_to_line_number(const std::vector &filenames, 60 | const std::vector &addresses, 61 | uintptr_t address, 62 | std::string &filename, 63 | int &line_number); 64 | 65 | std::string error_stacktrace(const std::vector &stacktrace); 66 | 67 | } // namespace LCompilers 68 | 69 | #endif // LFORTRAN_STACKTRACE_H 70 | -------------------------------------------------------------------------------- /src/libasr/string_utils.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | namespace LCompilers { 14 | 15 | 16 | bool startswith(const std::string &s, const std::string &e) 17 | { 18 | if (s.size() < e.size()) return false; 19 | return s.substr(0, e.size()) == e; 20 | } 21 | 22 | bool endswith(const std::string &s, const std::string &e) 23 | { 24 | if (s.size() < e.size()) return false; 25 | return s.substr(s.size()-e.size()) == e; 26 | } 27 | 28 | std::string to_lower(const std::string &s) { 29 | std::string res = s; 30 | std::transform(res.begin(), res.end(), res.begin(), 31 | [](unsigned char c){ return std::tolower(c); }); 32 | return res; 33 | } 34 | 35 | char *s2c(Allocator &al, const std::string &s) { 36 | Str x; x.from_str_view(s); 37 | return x.c_str(al); 38 | } 39 | 40 | // Splits the string `s` using the separator `split_string` 41 | std::vector string_split(const std::string &s, const std::string &split_string) 42 | { 43 | std::vector result; 44 | size_t old_pos = 0; 45 | size_t new_pos; 46 | while ((new_pos = s.find(split_string, old_pos)) != std::string::npos) { 47 | std::string substr = s.substr(old_pos, new_pos-old_pos); 48 | if (substr.size() > 0) result.push_back(substr); 49 | old_pos = new_pos+split_string.size(); 50 | } 51 | result.push_back(s.substr(old_pos)); 52 | return result; 53 | } 54 | 55 | // Splits the string `s` using any space or newline 56 | std::vector split(const std::string &s) 57 | { 58 | std::vector result; 59 | std::string split_chars = " \n"; 60 | size_t old_pos = 0; 61 | size_t new_pos; 62 | while ((new_pos = s.find_first_of(split_chars, old_pos)) != std::string::npos) { 63 | std::string substr = s.substr(old_pos, new_pos-old_pos); 64 | if (substr.size() > 0) result.push_back(substr); 65 | old_pos = new_pos+1; 66 | } 67 | result.push_back(s.substr(old_pos)); 68 | return result; 69 | } 70 | 71 | std::string join(const std::string j, const std::vector &l) 72 | { 73 | std::string result; 74 | for (size_t i=0; i slice(const std::vector& v, int start, int end) 82 | { 83 | int oldlen = v.size(); 84 | int newlen; 85 | 86 | if ((end == -1) || (end >= oldlen)) { 87 | newlen = oldlen-start; 88 | } else { 89 | newlen = end-start; 90 | } 91 | 92 | std::vector nv(newlen); 93 | 94 | for (int i=0; i bytes(filesize); 117 | ifs.read(&bytes[0], filesize); 118 | 119 | return std::string(&bytes[0], filesize); 120 | } 121 | 122 | std::string parent_path(const std::string &path) { 123 | int pos = path.size()-1; 124 | while (pos >= 0 && path[pos] != '/') pos--; 125 | if (pos == -1) { 126 | return ""; 127 | } else { 128 | return path.substr(0, pos); 129 | } 130 | } 131 | 132 | bool is_relative_path(const std::string &path) { 133 | return !startswith(path, "/"); 134 | } 135 | 136 | std::string join_paths(const std::vector &paths) { 137 | std::string p; 138 | std::string delim = "/"; 139 | for (auto &path : paths) { 140 | if (path.size() > 0) { 141 | if (p.size() > 0 && !endswith(p, delim)) { 142 | p.append(delim); 143 | } 144 | p.append(path); 145 | } 146 | } 147 | return p; 148 | } 149 | 150 | std::string str_escape_c(const std::string &s) { 151 | std::ostringstream o; 152 | for (auto c = s.cbegin(); c != s.cend(); c++) { 153 | switch (*c) { 154 | case '"': o << "\\\""; break; 155 | case '\\': o << "\\\\"; break; 156 | case '\b': o << "\\b"; break; 157 | case '\f': o << "\\f"; break; 158 | case '\n': o << "\\n"; break; 159 | case '\r': o << "\\r"; break; 160 | case '\t': o << "\\t"; break; 161 | case '\v': o << "\\v"; break; 162 | default: 163 | if ('\x00' <= *c && *c <= '\x1f') { 164 | o << "\\u" 165 | << std::hex << std::setw(4) << std::setfill('0') << static_cast(*c); 166 | } else { 167 | o << *c; 168 | } 169 | } 170 | } 171 | return o.str(); 172 | } 173 | 174 | char* str_unescape_c(Allocator &al, LCompilers::Str &s) { 175 | std::string x = ""; 176 | size_t idx = 0; 177 | for (; idx + 1 < s.size(); idx++) { 178 | if (s[idx] == '\\' && s[idx+1] == '\n') { // continuation character 179 | idx++; 180 | } else if (s[idx] == '\\' && s[idx+1] == 'n') { 181 | x += "\n"; 182 | idx++; 183 | } else if (s[idx] == '\\' && s[idx+1] == 't') { 184 | x += "\t"; 185 | idx++; 186 | } else if (s[idx] == '\\' && s[idx+1] == 'r') { 187 | x += "\r"; 188 | idx++; 189 | } else if (s[idx] == '\\' && s[idx+1] == 'b') { 190 | x += "\b"; 191 | idx++; 192 | } else if (s[idx] == '\\' && s[idx+1] == 'v') { 193 | x += "\v"; 194 | idx++; 195 | } else if (s[idx] == '\\' && s[idx+1] == '\\') { 196 | x += "\\"; 197 | idx++; 198 | } else if (s[idx] == '\\' && s[idx+1] == '"') { 199 | x += '"'; 200 | idx++; 201 | } else if (s[idx] == '\\' && s[idx+1] == '\'') { 202 | x += '\''; 203 | idx++; 204 | } else { 205 | x += s[idx]; 206 | } 207 | } 208 | if (idx < s.size()) { 209 | x += s[idx]; 210 | } 211 | return LCompilers::s2c(al, x); 212 | } 213 | 214 | std::string str_escape_fortran_double_quote(const std::string &s) { 215 | std::ostringstream o; 216 | for (auto c = s.cbegin(); c != s.cend(); c++) { 217 | switch (*c) { 218 | case '"': o << "\"\""; break; 219 | } 220 | } 221 | return o.str(); 222 | } 223 | 224 | char* str_unescape_fortran(Allocator &al, LCompilers::Str &s, char ch) { 225 | std::string x = ""; 226 | size_t idx = 0; 227 | for (; idx + 1 < s.size(); idx++) { 228 | if (s[idx] == ch && s[idx + 1] == ch) { 229 | x += s[idx]; 230 | idx++; 231 | } else { 232 | x += s[idx]; 233 | } 234 | } 235 | if (idx < s.size()) { 236 | x += s[idx]; 237 | } 238 | return LCompilers::s2c(al, x); 239 | } 240 | 241 | } // namespace LCompilers 242 | -------------------------------------------------------------------------------- /src/libasr/string_utils.h: -------------------------------------------------------------------------------- 1 | #ifndef LFORTRAN_STRING_UTILS_H 2 | #define LFORTRAN_STRING_UTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | namespace LCompilers { 12 | 13 | 14 | bool startswith(const std::string &s, const std::string &e); 15 | bool endswith(const std::string &s, const std::string &e); 16 | std::string to_lower(const std::string &s); 17 | std::vector string_split(const std::string &s, const std::string &split_string); 18 | std::vector split(const std::string &s); 19 | std::string join(const std::string j, const std::vector &v); 20 | std::vector slice(const std::vector &v, 21 | int start=0, int end=-1); 22 | char *s2c(Allocator &al, const std::string &s); 23 | 24 | // Replaces all occurrences of `regex` (a regular expression, must escape 25 | // special characters) with `replace` 26 | std::string replace(const std::string &s, 27 | const std::string ®ex, const std::string &replace); 28 | 29 | std::string read_file(const std::string &filename); 30 | 31 | // Returns the parent path to the given path 32 | std::string parent_path(const std::string &path); 33 | // Returns true if the path is relative 34 | bool is_relative_path(const std::string &path); 35 | // Joins paths (paths can be empty) 36 | std::string join_paths(const std::vector &paths); 37 | 38 | // Escapes special characters from the given string 39 | // using C style escaping 40 | std::string str_escape_c(const std::string &s); 41 | char* str_unescape_c(Allocator &al, LCompilers::Str &s); 42 | 43 | // Escapes double quote characters from the given string 44 | // given string must be enclosed in double quotes 45 | std::string str_escape_fortran_double_quote(const std::string &s); 46 | char* str_unescape_fortran(Allocator &al, LCompilers::Str &s, char ch); 47 | 48 | } // namespace LCompilers 49 | 50 | #endif // LFORTRAN_STRING_UTILS_H 51 | -------------------------------------------------------------------------------- /src/libasr/utils.h: -------------------------------------------------------------------------------- 1 | #ifndef LIBASR_UTILS_H 2 | #define LIBASR_UTILS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace LCompilers { 10 | 11 | enum Platform { 12 | Linux, 13 | macOS_Intel, 14 | macOS_ARM, 15 | Windows, 16 | FreeBSD, 17 | OpenBSD, 18 | }; 19 | 20 | std::string pf2s(Platform); 21 | Platform get_platform(); 22 | 23 | std::string get_unique_ID(); 24 | int visualize_json(std::string &astr_data_json, LCompilers::Platform os); 25 | std::string generate_visualize_html(std::string &astr_data_json); 26 | 27 | struct PassOptions { 28 | std::filesystem::path mod_files_dir; 29 | std::vector include_dirs; 30 | 31 | std::string run_fun; // for global_stmts pass 32 | // TODO: Convert to std::filesystem::path (also change find_and_load_module()) 33 | std::string runtime_library_dir; 34 | bool always_run = false; // for unused_functions pass 35 | bool inline_external_symbol_calls = true; // for inline_function_calls pass 36 | int64_t unroll_factor = 32; // for loop_unroll pass 37 | bool fast = false; // is fast flag enabled. 38 | bool verbose = false; // For developer debugging 39 | bool dump_all_passes = false; // For developer debugging 40 | bool dump_fortran = false; // For developer debugging 41 | bool pass_cumulative = false; // Apply passes cumulatively 42 | bool disable_main = false; 43 | bool use_loop_variable_after_loop = false; 44 | bool realloc_lhs = false; 45 | std::vector skip_optimization_func_instantiation; 46 | bool module_name_mangling = false; 47 | bool global_symbols_mangling = false; 48 | bool intrinsic_symbols_mangling = false; 49 | bool all_symbols_mangling = false; 50 | bool bindc_mangling = false; 51 | bool fortran_mangling = false; 52 | bool mangle_underscore = false; 53 | bool json = false; 54 | bool no_loc = false; 55 | bool visualize = false; 56 | bool tree = false; 57 | bool with_intrinsic_mods = false; 58 | }; 59 | 60 | struct CompilerOptions { 61 | std::vector runtime_linker_paths; 62 | 63 | // TODO: Convert to std::filesystem::path (also change find_and_load_module()) 64 | PassOptions po; 65 | 66 | bool fixed_form = false; 67 | bool interactive = false; 68 | bool c_preprocessor = false; 69 | std::vector c_preprocessor_defines; 70 | bool prescan = true; 71 | bool disable_main = false; 72 | bool symtab_only = false; 73 | bool show_stacktrace = false; 74 | bool use_colors = true; 75 | bool indent = true; 76 | bool json = false; 77 | bool tree = false; 78 | bool visualize = false; 79 | bool fast = false; 80 | bool openmp = false; 81 | bool generate_object_code = false; 82 | bool no_warnings = false; 83 | bool no_error_banner = false; 84 | bool enable_bounds_checking = false; 85 | std::string error_format = "human"; 86 | bool new_parser = false; 87 | bool implicit_typing = false; 88 | bool implicit_interface = false; 89 | bool implicit_argument_casting = false; 90 | bool print_leading_space = false; 91 | bool rtlib = false; 92 | bool use_loop_variable_after_loop = false; 93 | std::string target = ""; 94 | std::string arg_o = ""; 95 | bool emit_debug_info = false; 96 | bool emit_debug_line_column = false; 97 | bool enable_cpython = false; 98 | bool enable_symengine = false; 99 | bool link_numpy = false; 100 | bool run = false; 101 | bool legacy_array_sections = false; 102 | bool ignore_pragma = false; 103 | bool stack_arrays = false; 104 | std::vector import_paths; 105 | Platform platform; 106 | 107 | CompilerOptions () : platform{get_platform()} {}; 108 | }; 109 | 110 | bool read_file(const std::string &filename, std::string &text); 111 | bool present(Vec &v, const char* name); 112 | bool present(char** const v, size_t n, const std::string name); 113 | int initialize(); 114 | 115 | } // namespace LCompilers 116 | 117 | #endif // LIBASR_UTILS_H 118 | --------------------------------------------------------------------------------