diff --git a/src/libasr/ASR.asdl b/src/libasr/ASR.asdl index 8a97455..2c24e22 100644 --- a/src/libasr/ASR.asdl +++ b/src/libasr/ASR.asdl @@ -84,7 +84,7 @@ symbol stmt* body) | Module(symbol_table symtab, identifier name, identifier* dependencies, bool loaded_from_mod, bool intrinsic) - | Function(symbol_table symtab, identifier name, expr* args, stmt* body, + | Function(symbol_table symtab, identifier name, identifier* dependencies, expr* args, stmt* body, expr? return_var, abi abi, access access, deftype deftype, string? bindc_name, bool elemental, bool pure, bool module, bool inline, bool static, ttype* type_params, symbol* restrictions, bool is_restriction) @@ -95,12 +95,14 @@ symbol | ExternalSymbol(symbol_table parent_symtab, identifier name, symbol external, identifier module_name, identifier* scope_names, identifier original_name, access access) - | StructType(symbol_table symtab, identifier name, identifier* members, - abi abi, access access, symbol? parent) - | EnumType(symbol_table symtab, identifier name, identifier* members, - abi abi, access access, enumtype enum_value_type, ttype type, symbol? parent) - | UnionType(symbol_table symtab, identifier name, identifier* members, - abi abi, access access, symbol? parent) + | StructType(symbol_table symtab, identifier name, identifier* dependencies, + identifier* members, abi abi, access access, bool is_packed, + expr? alignment, symbol? parent) + | EnumType(symbol_table symtab, identifier name, identifier* dependencies, + identifier* members, abi abi, access access, enumtype enum_value_type, + ttype type, symbol? parent) + | UnionType(symbol_table symtab, identifier name, identifier* dependencies, + identifier* members, abi abi, access access, symbol? parent) | Variable(symbol_table parent_symtab, identifier name, intent intent, expr? symbolic_value, expr? value, storage_type storage, ttype type, abi abi, access access, presence presence, bool value_attr) @@ -271,8 +273,8 @@ expr | Var(symbol v) - | ArrayConstant(expr* args, ttype type) - | ArrayItem(expr v, array_index* args, ttype type, expr? value) + | ArrayConstant(expr* args, ttype type, arraystorage storage_format) + | ArrayItem(expr v, array_index* args, ttype type, arraystorage storage_format, expr? value) | ArraySection(expr v, array_index* args, ttype type, expr? value) | ArraySize(expr v, expr? dim, ttype type, expr? value) | ArrayBound(expr v, expr? dim, ttype type, arraybound bound, @@ -306,6 +308,8 @@ expr | IntegerBitLen(expr a, ttype type, expr? value) | Ichar(expr arg, ttype type, expr? value) + | SizeOfType(ttype arg, ttype type, expr? value) + -- `len` in Character: -- >=0 ... the length of the string, known at compile time @@ -341,6 +345,7 @@ ttype | Class(symbol class_type, dimension* dims) | Dict(ttype key_type, ttype value_type) | Pointer(ttype type) + | Const(ttype type) | CPtr() | TypeParameter(identifier param, dimension* dims) @@ -356,6 +361,8 @@ integerboz = Binary | Hex | Octal arraybound = LBound | UBound +arraystorage = RowMajor | ColMajor + cast_kind = RealToInteger | IntegerToReal diff --git a/src/libasr/CMakeLists.txt b/src/libasr/CMakeLists.txt index db72e35..fa032b2 100644 --- a/src/libasr/CMakeLists.txt +++ b/src/libasr/CMakeLists.txt @@ -23,6 +23,7 @@ set(SRC codegen/asr_to_x86.cpp codegen/asr_to_wasm.cpp codegen/wasm_to_wat.cpp + codegen/wasm_to_x86.cpp codegen/wasm_utils.cpp pass/param_to_const.cpp @@ -33,6 +34,7 @@ set(SRC pass/select_case.cpp pass/implied_do_loops.cpp pass/array_op.cpp + pass/subroutine_from_function.cpp pass/class_constructor.cpp pass/arr_slice.cpp pass/print_arr.cpp @@ -50,7 +52,7 @@ set(SRC pass/instantiate_template.cpp pass/update_array_dim_intrinsic_calls.cpp pass/pass_array_by_data.cpp - pass/pass_list_concat.cpp + pass/pass_list_expr.cpp asr_verify.cpp asr_utils.cpp diff --git a/src/libasr/asdl_cpp.py b/src/libasr/asdl_cpp.py index fd3ba2c..9b056be 100644 --- a/src/libasr/asdl_cpp.py +++ b/src/libasr/asdl_cpp.py @@ -1998,6 +1998,7 @@ def make_visitor(self, name, fields): ASR::symbol_t *s = ((ASR::%s_t*)f)->m_v; if (s->type == ASR::symbolType::ExternalSymbol) { ASR::ExternalSymbol_t *e = ASR::down_cast(s); + LFORTRAN_ASSERT(e->m_external); LFORTRAN_ASSERT(!ASR::is_a(*e->m_external)); s = e->m_external; } diff --git a/src/libasr/asr_scopes.h b/src/libasr/asr_scopes.h index 8323872..85203d4 100644 --- a/src/libasr/asr_scopes.h +++ b/src/libasr/asr_scopes.h @@ -65,6 +65,7 @@ struct SymbolTable { void erase_symbol(const std::string &name) { //auto it = scope.find(to_lower(name)); + LFORTRAN_ASSERT(scope.find(name) != scope.end()) scope.erase(name); } diff --git a/src/libasr/asr_utils.cpp b/src/libasr/asr_utils.cpp index 0679c71..c47bd8c 100644 --- a/src/libasr/asr_utils.cpp +++ b/src/libasr/asr_utils.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace LFortran { @@ -64,6 +65,23 @@ std::vector determine_module_dependencies( return order_deps(deps); } +std::vector determine_function_definition_order( + SymbolTable* symtab) { + std::map> func_dep_graph; + for( auto itr: symtab->get_scope() ) { + if( ASR::is_a(*itr.second) ) { + std::vector deps; + ASR::Function_t* func = ASR::down_cast(itr.second); + for( size_t i = 0; i < func->n_dependencies; i++ ) { + std::string dep = func->m_dependencies[i]; + deps.push_back(dep); + } + func_dep_graph[itr.first] = deps; + } + } + return ASRUtils::order_deps(func_dep_graph); +} + void extract_module_python(const ASR::TranslationUnit_t &m, std::vector>& children_modules, std::string module_name) { @@ -97,7 +115,7 @@ ASR::Module_t* extract_module(const ASR::TranslationUnit_t &m) { ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, const std::string &module_name, const Location &loc, bool intrinsic, - const std::string &rl_path, + LCompilers::PassOptions& pass_options, bool run_verify, const std::function err) { LFORTRAN_ASSERT(symtab); @@ -111,14 +129,14 @@ ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, } LFORTRAN_ASSERT(symtab->parent == nullptr); ASR::TranslationUnit_t *mod1 = find_and_load_module(al, module_name, - *symtab, intrinsic, rl_path); + *symtab, intrinsic, pass_options); if (mod1 == nullptr && !intrinsic) { // Module not found as a regular module. Try intrinsic module if (module_name == "iso_c_binding" ||module_name == "iso_fortran_env" ||module_name == "ieee_arithmetic") { mod1 = find_and_load_module(al, "lfortran_intrinsic_" + module_name, - *symtab, true, rl_path); + *symtab, true, pass_options); } } if (mod1 == nullptr) { @@ -155,13 +173,13 @@ ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, bool is_intrinsic = startswith(item, "lfortran_intrinsic"); ASR::TranslationUnit_t *mod1 = find_and_load_module(al, item, - *symtab, is_intrinsic, rl_path); + *symtab, is_intrinsic, pass_options); if (mod1 == nullptr && !is_intrinsic) { // Module not found as a regular module. Try intrinsic module if (item == "iso_c_binding" ||item == "iso_fortran_env") { mod1 = find_and_load_module(al, "lfortran_intrinsic_" + item, - *symtab, true, rl_path); + *symtab, true, pass_options); } } @@ -188,8 +206,16 @@ ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, // Fix all external symbols fix_external_symbols(*tu, *symtab); + PassUtils::UpdateDependenciesVisitor v(al); + v.visit_TranslationUnit(*tu); if (run_verify) { - LFORTRAN_ASSERT(asr_verify(*tu)); +#if defined(WITH_LFORTRAN_ASSERT) + diag::Diagnostics diagnostics; + if (!asr_verify(*tu, true, diagnostics)) { + std::cerr << diagnostics.render2(); + throw LCompilersException("Verify failed"); + }; +#endif } symtab->asr_owner = orig_asr_owner; @@ -235,20 +261,29 @@ void set_intrinsic(ASR::TranslationUnit_t* trans_unit) { ASR::TranslationUnit_t* find_and_load_module(Allocator &al, const std::string &msym, SymbolTable &symtab, bool intrinsic, - const std::string &rl_path) { - std::string modfilename = msym + ".mod"; - if (intrinsic) { - modfilename = rl_path + "/" + modfilename; - } + LCompilers::PassOptions& pass_options) { + std::filesystem::path runtime_library_dir { pass_options.runtime_library_dir }; + std::filesystem::path filename {msym + ".mod"}; + std::vector mod_files_dirs; + + mod_files_dirs.push_back( runtime_library_dir ); + mod_files_dirs.push_back( pass_options.mod_files_dir ); + mod_files_dirs.insert(mod_files_dirs.end(), + pass_options.include_dirs.begin(), + pass_options.include_dirs.end()); - std::string modfile; - if (!read_file(modfilename, modfile)) return nullptr; - ASR::TranslationUnit_t *asr = load_modfile(al, modfile, false, - symtab); - if (intrinsic) { - set_intrinsic(asr); + for (auto path : mod_files_dirs) { + std::string modfile; + std::filesystem::path full_path = path / filename; + if (read_file(full_path.string(), modfile)) { + ASR::TranslationUnit_t *asr = load_modfile(al, modfile, false, symtab); + if (intrinsic) { + set_intrinsic(asr); + } + return asr; + } } - return asr; + return nullptr; } ASR::asr_t* getStructInstanceMember_t(Allocator& al, const Location& loc, diff --git a/src/libasr/asr_utils.h b/src/libasr/asr_utils.h index 8b06a10..9b524d0 100644 --- a/src/libasr/asr_utils.h +++ b/src/libasr/asr_utils.h @@ -9,14 +9,20 @@ #include #include #include +#include namespace LFortran { namespace ASRUtils { static inline double extract_real(const char *s) { - return std::atof(s); - } + // TODO: this is inefficient. We should + // convert this in the tokenizer where we know most information + std::string x = s; + x = replace(x, "d", "e"); + x = replace(x, "D", "E"); + return std::atof(x.c_str()); +} static inline ASR::expr_t* EXPR(const ASR::asr_t *f) { @@ -105,6 +111,33 @@ static inline ASR::ttype_t* symbol_type(const ASR::symbol_t *f) return nullptr; } +static inline ASR::ttype_t* get_contained_type(ASR::ttype_t* asr_type) { + switch( asr_type->type ) { + case ASR::ttypeType::List: { + return ASR::down_cast(asr_type)->m_type; + } + case ASR::ttypeType::Set: { + return ASR::down_cast(asr_type)->m_type; + } + case ASR::ttypeType::Enum: { + ASR::Enum_t* enum_asr = ASR::down_cast(asr_type); + ASR::EnumType_t* enum_type = ASR::down_cast(enum_asr->m_enum_type); + return enum_type->m_type; + } + case ASR::ttypeType::Pointer: { + ASR::Pointer_t* pointer_asr = ASR::down_cast(asr_type); + return pointer_asr->m_type; + } + case ASR::ttypeType::Const: { + ASR::Const_t* const_asr = ASR::down_cast(asr_type); + return const_asr->m_type; + } + default: { + return asr_type; + } + } +} + static inline std::string type_to_str(const ASR::ttype_t *t) { switch (t->type) { @@ -148,6 +181,10 @@ static inline std::string type_to_str(const ASR::ttype_t *t) return type_to_str(ASRUtils::type_get_past_pointer( const_cast(t))) + " pointer"; } + case ASR::ttypeType::Const: { + return type_to_str(ASRUtils::get_contained_type( + const_cast(t))) + " const"; + } case ASR::ttypeType::TypeParameter: { ASR::TypeParameter_t* tp = ASR::down_cast(t); return tp->m_param; @@ -239,6 +276,37 @@ static inline char *symbol_name(const ASR::symbol_t *f) } } +static inline std::pair symbol_dependencies(const ASR::symbol_t *f) +{ + switch (f->type) { + case ASR::symbolType::Program: { + ASR::Program_t* sym = ASR::down_cast(f); + return std::make_pair(sym->m_dependencies, sym->n_dependencies); + } + case ASR::symbolType::Module: { + ASR::Module_t* sym = ASR::down_cast(f); + return std::make_pair(sym->m_dependencies, sym->n_dependencies); + } + case ASR::symbolType::Function: { + ASR::Function_t* sym = ASR::down_cast(f); + return std::make_pair(sym->m_dependencies, sym->n_dependencies); + } + case ASR::symbolType::StructType: { + ASR::StructType_t* sym = ASR::down_cast(f); + return std::make_pair(sym->m_dependencies, sym->n_dependencies); + } + case ASR::symbolType::EnumType: { + ASR::EnumType_t* sym = ASR::down_cast(f); + return std::make_pair(sym->m_dependencies, sym->n_dependencies); + } + case ASR::symbolType::UnionType: { + ASR::UnionType_t* sym = ASR::down_cast(f); + return std::make_pair(sym->m_dependencies, sym->n_dependencies); + } + default : throw LCompilersException("Not implemented"); + } +} + static inline SymbolTable *symbol_parent_symtab(const ASR::symbol_t *f) { switch (f->type) { @@ -607,6 +675,11 @@ static inline bool extract_value(ASR::expr_t* value_expr, T& value) { value = (T) const_real->m_r; break; } + case ASR::exprType::LogicalConstant: { + ASR::LogicalConstant_t* const_logical = ASR::down_cast(value_expr); + value = (T) const_logical->m_value; + break; + } default: return false; } @@ -664,35 +737,50 @@ static inline void encode_dimensions(size_t n_dims, std::string& res, } static inline std::string get_type_code(const ASR::ttype_t *t, bool use_underscore_sep=false, - bool encode_dimensions_=true) + bool encode_dimensions_=true, bool set_dimensional_hint=true) { + bool is_dimensional = false; + std::string res = ""; switch (t->type) { case ASR::ttypeType::Integer: { ASR::Integer_t *integer = ASR::down_cast(t); - std::string res = "i" + std::to_string(integer->m_kind * 8); + res = "i" + std::to_string(integer->m_kind * 8); if( encode_dimensions_ ) { encode_dimensions(integer->n_dims, res, use_underscore_sep); + return res; } - return res; + is_dimensional = integer->n_dims > 0; + break; } case ASR::ttypeType::Real: { ASR::Real_t *real = ASR::down_cast(t); - std::string res = "r" + std::to_string(real->m_kind * 8); + res = "r" + std::to_string(real->m_kind * 8); if( encode_dimensions_ ) { encode_dimensions(real->n_dims, res, use_underscore_sep); + return res; } - return res; + is_dimensional = real->n_dims > 0; + break; } case ASR::ttypeType::Complex: { ASR::Complex_t *complx = ASR::down_cast(t); - std::string res = "r" + std::to_string(complx->m_kind * 8); + res = "c" + std::to_string(complx->m_kind * 8); if( encode_dimensions_ ) { encode_dimensions(complx->n_dims, res, use_underscore_sep); + return res; } - return res; + is_dimensional = complx->n_dims > 0; + break; } case ASR::ttypeType::Logical: { - return "bool"; + ASR::Logical_t* bool_ = ASR::down_cast(t); + res = "bool"; + if( encode_dimensions_ ) { + encode_dimensions(bool_->n_dims, res, use_underscore_sep); + return res; + } + is_dimensional = bool_->n_dims > 0; + break; } case ASR::ttypeType::Character: { return "str"; @@ -706,7 +794,8 @@ static inline std::string get_type_code(const ASR::ttype_t *t, bool use_undersco result += "["; } for (size_t i = 0; i < tup->n_type; i++) { - result += get_type_code(tup->m_type[i], use_underscore_sep, encode_dimensions_); + result += get_type_code(tup->m_type[i], use_underscore_sep, + encode_dimensions_, set_dimensional_hint); if (i + 1 != tup->n_type) { if( use_underscore_sep ) { result += "_"; @@ -725,45 +814,84 @@ static inline std::string get_type_code(const ASR::ttype_t *t, bool use_undersco case ASR::ttypeType::Set: { ASR::Set_t *s = ASR::down_cast(t); if( use_underscore_sep ) { - return "set_" + get_type_code(s->m_type, use_underscore_sep, encode_dimensions_) + "_"; + return "set_" + get_type_code(s->m_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + "_"; } - return "set[" + get_type_code(s->m_type, use_underscore_sep, encode_dimensions_) + "]"; + return "set[" + get_type_code(s->m_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + "]"; } case ASR::ttypeType::Dict: { ASR::Dict_t *d = ASR::down_cast(t); if( use_underscore_sep ) { - return "dict_" + get_type_code(d->m_key_type, use_underscore_sep, encode_dimensions_) + - "_" + get_type_code(d->m_value_type, use_underscore_sep, encode_dimensions_) + "_"; + return "dict_" + get_type_code(d->m_key_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + + "_" + get_type_code(d->m_value_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + "_"; } - return "dict[" + get_type_code(d->m_key_type, use_underscore_sep, encode_dimensions_) + - ", " + get_type_code(d->m_value_type, use_underscore_sep, encode_dimensions_) + "]"; + return "dict[" + get_type_code(d->m_key_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + + ", " + get_type_code(d->m_value_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + "]"; } case ASR::ttypeType::List: { ASR::List_t *l = ASR::down_cast(t); if( use_underscore_sep ) { - return "list_" + get_type_code(l->m_type, use_underscore_sep, encode_dimensions_) + "_"; + return "list_" + get_type_code(l->m_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + "_"; } - return "list[" + get_type_code(l->m_type, use_underscore_sep, encode_dimensions_) + "]"; + return "list[" + get_type_code(l->m_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + "]"; } case ASR::ttypeType::CPtr: { return "CPtr"; } case ASR::ttypeType::Struct: { ASR::Struct_t* d = ASR::down_cast(t); - return symbol_name(d->m_derived_type); + res = symbol_name(d->m_derived_type); + if( encode_dimensions_ ) { + encode_dimensions(d->n_dims, res, use_underscore_sep); + return res; + } + is_dimensional = d->n_dims > 0; + break; + } + case ASR::ttypeType::Union: { + ASR::Union_t* d = ASR::down_cast(t); + res = symbol_name(d->m_union_type); + if( encode_dimensions_ ) { + encode_dimensions(d->n_dims, res, use_underscore_sep); + return res; + } + is_dimensional = d->n_dims > 0; + break; } case ASR::ttypeType::Pointer: { ASR::Pointer_t* p = ASR::down_cast(t); if( use_underscore_sep ) { - return "Pointer_" + get_type_code(p->m_type, use_underscore_sep, encode_dimensions_) + "_"; + return "Pointer_" + get_type_code(p->m_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + "_"; + } + return "Pointer[" + get_type_code(p->m_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + "]"; + } + case ASR::ttypeType::Const: { + ASR::Const_t* p = ASR::down_cast(t); + if( use_underscore_sep ) { + return "Const_" + get_type_code(p->m_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + "_"; } - return "Pointer[" + get_type_code(p->m_type, use_underscore_sep, encode_dimensions_) + "]"; + return "Const[" + get_type_code(p->m_type, use_underscore_sep, + encode_dimensions_, set_dimensional_hint) + "]"; } default: { throw LCompilersException("Type encoding not implemented for " + std::to_string(t->type)); } } + if( is_dimensional && set_dimensional_hint ) { + res += "dim"; + } + return res; } static inline std::string get_type_code(ASR::ttype_t** types, size_t n_types, @@ -856,10 +984,18 @@ static inline std::string type_to_str_python(const ASR::ttype_t *t, ASR::Enum_t* d = ASR::down_cast(t); return symbol_name(d->m_enum_type); } + case ASR::ttypeType::Union: { + ASR::Union_t* d = ASR::down_cast(t); + return symbol_name(d->m_union_type); + } case ASR::ttypeType::Pointer: { ASR::Pointer_t* p = ASR::down_cast(t); return "Pointer[" + type_to_str_python(p->m_type) + "]"; } + case ASR::ttypeType::Const: { + ASR::Const_t* p = ASR::down_cast(t); + return "Const[" + type_to_str_python(p->m_type) + "]"; + } case ASR::ttypeType::TypeParameter: { ASR::TypeParameter_t *p = ASR::down_cast(t); return p->m_param; @@ -938,6 +1074,27 @@ static inline Vec get_scope_names(Allocator &al, const SymbolTable *symta return scope_names; } +static inline ASR::expr_t* get_constant_expression_with_given_type(Allocator& al, ASR::ttype_t* asr_type) { + switch (asr_type->type) { + case ASR::ttypeType::Integer: { + return ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, asr_type->base.loc, -1, asr_type)); + } + case ASR::ttypeType::Real: { + return ASRUtils::EXPR(ASR::make_RealConstant_t(al, asr_type->base.loc, 0.0, asr_type)); + } + case ASR::ttypeType::Complex: { + return ASRUtils::EXPR(ASR::make_ComplexConstant_t(al, asr_type->base.loc, 0.0, 0.0, asr_type)); + } + case ASR::ttypeType::Logical: { + return ASRUtils::EXPR(ASR::make_LogicalConstant_t(al, asr_type->base.loc, false, asr_type)); + } + default: { + throw LCompilersException("Not implemented " + std::to_string(asr_type->type)); + } + } + return nullptr; +} + const ASR::intentType intent_local=ASR::intentType::Local; // local variable (not a dummy argument) const ASR::intentType intent_in =ASR::intentType::In; // dummy argument, intent(in) const ASR::intentType intent_out =ASR::intentType::Out; // dummy argument, intent(out) @@ -967,6 +1124,9 @@ std::vector order_deps(std::map determine_module_dependencies( const ASR::TranslationUnit_t &unit); +std::vector determine_function_definition_order( + SymbolTable* symtab); + void extract_module_python(const ASR::TranslationUnit_t &m, std::vector>& children_modules, std::string module_name); @@ -976,13 +1136,13 @@ ASR::Module_t* extract_module(const ASR::TranslationUnit_t &m); ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, const std::string &module_name, const Location &loc, bool intrinsic, - const std::string &rl_path, + LCompilers::PassOptions& pass_options, bool run_verify, const std::function err); ASR::TranslationUnit_t* find_and_load_module(Allocator &al, const std::string &msym, SymbolTable &symtab, bool intrinsic, - const std::string &rl_path); + LCompilers::PassOptions& pass_options); void set_intrinsic(ASR::TranslationUnit_t* trans_unit); @@ -1038,6 +1198,9 @@ static inline int extract_kind_from_ttype_t(const ASR::ttype_t* type) { case ASR::ttypeType::Pointer: { return extract_kind_from_ttype_t(ASR::down_cast(type)->m_type); } + case ASR::ttypeType::Const: { + return extract_kind_from_ttype_t(ASR::down_cast(type)->m_type); + } default : { return -1; } @@ -1161,6 +1324,10 @@ inline int extract_dimensions_from_ttype(ASR::ttype_t *x, n_dims = extract_dimensions_from_ttype(ASR::down_cast(x)->m_type, m_dims); break; } + case ASR::ttypeType::Const: { + n_dims = extract_dimensions_from_ttype(ASR::down_cast(x)->m_type, m_dims); + break; + } case ASR::ttypeType::List: { n_dims = 0; m_dims = nullptr; @@ -1193,6 +1360,11 @@ inline int extract_dimensions_from_ttype(ASR::ttype_t *x, return n_dims; } +inline int extract_n_dims_from_ttype(ASR::ttype_t *x) { + ASR::dimension_t* m_dims_temp = nullptr; + return extract_dimensions_from_ttype(x, m_dims_temp); +} + // Sets the dimension member of `ttype_t`. Returns `true` if dimensions set. // Returns `false` if the `ttype_t` does not have a dimension member. inline bool ttype_set_dimensions(ASR::ttype_t *x, @@ -1313,6 +1485,12 @@ static inline ASR::ttype_t* duplicate_type(Allocator& al, const ASR::ttype_t* t, return ASRUtils::TYPE(ASR::make_Pointer_t(al, ptr->base.base.loc, dup_type)); } + case ASR::ttypeType::Const: { + ASR::Const_t* c = ASR::down_cast(t); + ASR::ttype_t* dup_type = duplicate_type(al, c->m_type, dims); + return ASRUtils::TYPE(ASR::make_Const_t(al, c->base.base.loc, + dup_type)); + } case ASR::ttypeType::TypeParameter: { ASR::TypeParameter_t* tp = ASR::down_cast(t); ASR::dimension_t* dimsp = dims ? dims->p : tp->m_dims; @@ -1326,29 +1504,44 @@ static inline ASR::ttype_t* duplicate_type(Allocator& al, const ASR::ttype_t* t, } } -static inline ASR::ttype_t* duplicate_type_without_dims(Allocator& al, const ASR::ttype_t* t) { +static inline ASR::ttype_t* duplicate_type_without_dims(Allocator& al, const ASR::ttype_t* t, const Location& loc) { switch (t->type) { case ASR::ttypeType::Integer: { ASR::Integer_t* tnew = ASR::down_cast(t); - return ASRUtils::TYPE(ASR::make_Integer_t(al, t->base.loc, + return ASRUtils::TYPE(ASR::make_Integer_t(al, loc, tnew->m_kind, nullptr, 0)); } case ASR::ttypeType::Real: { ASR::Real_t* tnew = ASR::down_cast(t); - return ASRUtils::TYPE(ASR::make_Real_t(al, t->base.loc, + return ASRUtils::TYPE(ASR::make_Real_t(al, loc, + tnew->m_kind, nullptr, 0)); + } + case ASR::ttypeType::Complex: { + ASR::Complex_t* tnew = ASR::down_cast(t); + return ASRUtils::TYPE(ASR::make_Complex_t(al, loc, + tnew->m_kind, nullptr, 0)); + } + case ASR::ttypeType::Logical: { + ASR::Logical_t* tnew = ASR::down_cast(t); + return ASRUtils::TYPE(ASR::make_Logical_t(al, loc, tnew->m_kind, nullptr, 0)); } case ASR::ttypeType::Character: { ASR::Character_t* tnew = ASR::down_cast(t); - return ASRUtils::TYPE(ASR::make_Character_t(al, t->base.loc, + return ASRUtils::TYPE(ASR::make_Character_t(al, loc, tnew->m_kind, tnew->m_len, tnew->m_len_expr, nullptr, 0)); } + case ASR::ttypeType::Struct: { + ASR::Struct_t* tstruct = ASR::down_cast(t); + return ASRUtils::TYPE(ASR::make_Struct_t(al, loc, + tstruct->m_derived_type, nullptr, 0)); + } case ASR::ttypeType::TypeParameter: { ASR::TypeParameter_t* tp = ASR::down_cast(t); //return ASRUtils::TYPE(ASR::make_TypeParameter_t(al, t->base.loc, // tp->m_param, nullptr, 0, tp->m_rt, tp->n_rt)); - return ASRUtils::TYPE(ASR::make_TypeParameter_t(al, t->base.loc, + return ASRUtils::TYPE(ASR::make_TypeParameter_t(al, loc, tp->m_param, nullptr, 0)); } default : throw LCompilersException("Not implemented " + std::to_string(t->type)); @@ -1508,6 +1701,11 @@ inline bool check_equal_type(ASR::ttype_t* x, ASR::ttype_t* y) { x = ASRUtils::type_get_past_pointer(x); y = ASRUtils::type_get_past_pointer(y); return check_equal_type(x, y); + } else if(ASR::is_a(*x) || + ASR::is_a(*y)) { + x = ASRUtils::get_contained_type(x); + y = ASRUtils::get_contained_type(y); + return check_equal_type(x, y); } else if (ASR::is_a(*x) && ASR::is_a(*y)) { x = ASR::down_cast(x)->m_type; y = ASR::down_cast(y)->m_type; @@ -1581,29 +1779,6 @@ static inline bool is_dimension_empty(ASR::dimension_t* dims, size_t n) { return false; } -static inline ASR::ttype_t* get_contained_type(ASR::ttype_t* asr_type) { - switch( asr_type->type ) { - case ASR::ttypeType::List: { - return ASR::down_cast(asr_type)->m_type; - } - case ASR::ttypeType::Set: { - return ASR::down_cast(asr_type)->m_type; - } - case ASR::ttypeType::Enum: { - ASR::Enum_t* enum_asr = ASR::down_cast(asr_type); - ASR::EnumType_t* enum_type = ASR::down_cast(enum_asr->m_enum_type); - return enum_type->m_type; - } - case ASR::ttypeType::Pointer: { - ASR::Pointer_t* pointer_asr = ASR::down_cast(asr_type); - return pointer_asr->m_type; - } - default: { - return asr_type; - } - } -} - static inline ASR::ttype_t* get_type_parameter(ASR::ttype_t* t) { switch (t->type) { case ASR::ttypeType::TypeParameter: { diff --git a/src/libasr/asr_verify.cpp b/src/libasr/asr_verify.cpp index 5969867..9b3e81b 100644 --- a/src/libasr/asr_verify.cpp +++ b/src/libasr/asr_verify.cpp @@ -2,7 +2,13 @@ #include #include #include +#include +namespace { + class VerifyAbort + { + }; +} namespace LFortran { namespace ASR { @@ -33,32 +39,33 @@ class VerifyVisitor : public BaseWalkVisitor private: // For checking correct parent symbtab relationship SymbolTable *current_symtab; + bool check_external; + diag::Diagnostics &diagnostics; // For checking that all symtabs have a unique ID. // We first walk all symtabs, and then we check that everything else // points to them (i.e., that nothing points to some symbol table that // is not part of this ASR). std::map id_symtab_map; - bool check_external; + std::vector function_dependencies; + std::vector module_dependencies; + + std::set> const_assigned; + public: - VerifyVisitor(bool check_external) : check_external{check_external} {} + VerifyVisitor(bool check_external, diag::Diagnostics &diagnostics) : check_external{check_external}, + diagnostics{diagnostics} {} // Requires the condition `cond` to be true. Raise an exception otherwise. - void require(bool cond, const std::string &error_msg) { +#define require(cond, error_msg) require_impl((cond), (error_msg), x.base.base.loc) + void require_impl(bool cond, const std::string &error_msg, const Location &loc) { if (!cond) { - throw LCompilersException("ASR verify failed: " + error_msg); + diagnostics.message_label("ASR verify: " + error_msg, + {loc}, "failed here", + diag::Level::Error, diag::Stage::ASRVerify); + throw VerifyAbort(); } } - void require(bool cond, const std::string &error_msg, - const Location &loc) { - std::string msg = std::to_string(loc.first) + ":" - + std::to_string(loc.last) + ": " + error_msg; - /* - std::string msg = std::to_string(loc.first_line) + ":" - + std::to_string(loc.first_column) + ": " + error_msg; - */ - require(cond, msg); - } // Returns true if the `symtab_ID` (sym->symtab->parent) is the current // symbol table `symtab` or any of its parents *and* if the symbol in the @@ -198,6 +205,8 @@ class VerifyVisitor : public BaseWalkVisitor } void visit_Module(const Module_t &x) { + module_dependencies.clear(); + module_dependencies.reserve(x.n_dependencies); SymbolTable *parent_symtab = current_symtab; current_symtab = x.m_symtab; require(x.m_symtab != nullptr, @@ -218,19 +227,46 @@ class VerifyVisitor : public BaseWalkVisitor } for (size_t i=0; i < x.n_dependencies; i++) { require(x.m_dependencies[i] != nullptr, - "A module dependency must not be a nullptr", - x.base.base.loc); + "A module dependency must not be a nullptr"); require(std::string(x.m_dependencies[i]) != "", - "A module dependency must not be an empty string", - x.base.base.loc); + "A module dependency must not be an empty string"); require(valid_name(x.m_dependencies[i]), - "A module dependency must be a valid string", - x.base.base.loc); + "A module dependency must be a valid string"); + } + for( auto& dep: module_dependencies ) { + require(present(x.m_dependencies, x.n_dependencies, dep), + "Module " + std::string(x.m_name) + + " dependencies must contain " + dep + + " because a function present in it is getting called in " + + std::string(x.m_name) + "."); } current_symtab = parent_symtab; } + void visit_Assignment(const Assignment_t& x) { + ASR::expr_t* target = x.m_target; + if( ASR::is_a(*target) ) { + ASR::Var_t* target_Var = ASR::down_cast(target); + ASR::ttype_t* target_type = nullptr; + if( ASR::is_a(*target_Var->m_v) || + ASR::is_a(*target_Var->m_v)) { + target_type = ASRUtils::expr_type(target); + } + if( target_type && ASR::is_a(*target_type) ) { + std::string variable_name = ASRUtils::symbol_name(target_Var->m_v); + require(const_assigned.find(std::make_pair(current_symtab->counter, + variable_name)) == const_assigned.end(), + "Assignment target with " + ASRUtils::type_to_str_python(target_type) + + " cannot be re-assigned."); + const_assigned.insert(std::make_pair(current_symtab->counter, variable_name)); + } + } + BaseWalkVisitor::visit_Assignment(x); + } + void visit_Function(const Function_t &x) { + function_dependencies.clear(); + function_dependencies.reserve(x.n_dependencies); SymbolTable *parent_symtab = current_symtab; current_symtab = x.m_symtab; require(x.m_symtab != nullptr, @@ -256,6 +292,22 @@ class VerifyVisitor : public BaseWalkVisitor if (x.m_return_var) { visit_expr(*x.m_return_var); } + // Check if there are unnecessary dependencies + // present in the dependency list of the function + for( size_t i = 0; i < x.n_dependencies; i++ ) { + std::string found_dep = x.m_dependencies[i]; + require(std::find(function_dependencies.begin(), function_dependencies.end(), found_dep) != function_dependencies.end(), + "Function " + std::string(x.m_name) + " doesn't depend on " + found_dep + + " but is found in its dependency list."); + } + + // Check if all the dependencies found are + // present in the dependency list of the function + for( auto& found_dep: function_dependencies ) { + require(present(x.m_dependencies, x.n_dependencies, found_dep), + "Function " + std::string(x.m_name) + " depends on " + found_dep + + " but isn't found in its dependency list."); + } current_symtab = parent_symtab; } @@ -274,14 +326,54 @@ class VerifyVisitor : public BaseWalkVisitor require(ASRUtils::symbol_symtab(down_cast(current_symtab->asr_owner)) == current_symtab, "The asr_owner invariant failed"); id_symtab_map[x.m_symtab->counter] = x.m_symtab; + std::vector struct_dependencies; for (auto &a : x.m_symtab->get_scope()) { this->visit_symbol(*a.second); + if( ASR::is_a(*a.second) || + ASR::is_a(*a.second) ) { + continue ; + } + ASR::ttype_t* var_type = ASRUtils::type_get_past_pointer(ASRUtils::symbol_type(a.second)); + char* aggregate_type_name = nullptr; + if( ASR::is_a(*var_type) ) { + ASR::symbol_t* sym = ASR::down_cast(var_type)->m_derived_type; + aggregate_type_name = ASRUtils::symbol_name(sym); + } else if( ASR::is_a(*var_type) ) { + ASR::symbol_t* sym = ASR::down_cast(var_type)->m_enum_type; + aggregate_type_name = ASRUtils::symbol_name(sym); + } else if( ASR::is_a(*var_type) ) { + ASR::symbol_t* sym = ASR::down_cast(var_type)->m_union_type; + aggregate_type_name = ASRUtils::symbol_name(sym); + } + if( aggregate_type_name ) { + struct_dependencies.push_back(std::string(aggregate_type_name)); + require(present(x.m_dependencies, x.n_dependencies, std::string(aggregate_type_name)), + std::string(x.m_name) + " depends on " + std::string(aggregate_type_name) + + " but it isn't found in its dependency list."); + } + } + for( size_t i = 0; i < x.n_dependencies; i++ ) { + require(std::find(struct_dependencies.begin(), struct_dependencies.end(), + std::string(x.m_dependencies[i])) != struct_dependencies.end(), + std::string(x.m_dependencies[i]) + " is not a dependency of " + std::string(x.m_name) + + " but it is present in its dependency list."); } current_symtab = parent_symtab; } void visit_StructType(const StructType_t& x) { visit_StructTypeEnumTypeUnionType(x); + if( !x.m_alignment ) { + return ; + } + ASR::expr_t* aligned_expr_value = ASRUtils::expr_value(x.m_alignment); + std::string msg = "Alignment should always evaluate to a constant expressions."; + require(aligned_expr_value, msg); + int64_t alignment_int; + require(ASRUtils::extract_value(aligned_expr_value, alignment_int), msg); + require(alignment_int != 0 && (alignment_int & (alignment_int - 1)) == 0, + "Alignment " + std::to_string(alignment_int) + + " is not a positive power of 2."); } void visit_EnumType(const EnumType_t& x) { @@ -400,40 +492,74 @@ class VerifyVisitor : public BaseWalkVisitor "Var::m_v `" + std::string(ASRUtils::symbol_name(x.m_v)) + "` cannot point outside of its symbol table"); } + void check_var_external(const ASR::expr_t &x) { + if (ASR::is_a(x)) { + ASR::symbol_t *s = ((ASR::Var_t*)&x)->m_v; + if (ASR::is_a(*s)) { + ASR::ExternalSymbol_t *e = ASR::down_cast(s); + require_impl(e->m_external, "m_external cannot be null here", + x.base.loc); + } + } + } + template - void visit_ArrayItemSection(const T &x) { + void handle_ArrayItemSection(const T &x) { visit_expr(*x.m_v); for (size_t i=0; i(*x.m_type) && n_dims == 0) { + // TODO: This seems like a bug, we should not use ArrayItem with + // strings but StringItem. For now we ignore it, but we should + // fix it + } else { + require(n_dims > 0, + "The variable in ArrayItem must be an array, not a scalar"); + } + } } void visit_ArrayItem(const ArrayItem_t &x) { - visit_ArrayItemSection(x); + handle_ArrayItemSection(x); } void visit_ArraySection(const ArraySection_t &x) { - visit_ArrayItemSection(x); + handle_ArrayItemSection(x); } void visit_SubroutineCall(const SubroutineCall_t &x) { if (x.m_dt) { - SymbolTable *symtab = get_dt_symtab(x.m_dt, x.base.base.loc); + SymbolTable *symtab = get_dt_symtab(x.m_dt); bool result = symtab_in_scope(symtab, x.m_name); - ASR::symbol_t* parent = get_parent_type_dt(x.m_dt, x.base.base.loc); + ASR::symbol_t* parent = get_parent_type_dt(x.m_dt); while( !result && parent ) { - symtab = get_dt_symtab(parent, x.base.base.loc); + symtab = get_dt_symtab(parent); result = symtab_in_scope(symtab, x.m_name); - parent = get_parent_type_dt(parent, x.base.base.loc); + parent = get_parent_type_dt(parent); } require(symtab_in_scope(symtab, x.m_name), - "SubroutineCall::m_name cannot point outside of its symbol table", - x.base.base.loc); + "SubroutineCall::m_name cannot point outside of its symbol table"); } else { require(symtab_in_scope(current_symtab, x.m_name), - "SubroutineCall::m_name '" + std::string(symbol_name(x.m_name)) + "' cannot point outside of its symbol table", - x.base.base.loc); + "SubroutineCall::m_name '" + std::string(symbol_name(x.m_name)) + "' cannot point outside of its symbol table"); + if (check_external) { + ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_name); + require(ASR::is_a(*s), + "SubroutineCall::m_name '" + std::string(symbol_name(x.m_name)) + "' must be a Function"); + } + } + function_dependencies.push_back(std::string(ASRUtils::symbol_name(x.m_name))); + if( ASR::is_a(*x.m_name) ) { + ASR::ExternalSymbol_t* x_m_name = ASR::down_cast(x.m_name); + module_dependencies.push_back(std::string(x_m_name->m_module_name)); } for (size_t i=0; i } } - SymbolTable *get_dt_symtab(ASR::symbol_t *dt, const Location &loc) { + SymbolTable *get_dt_symtab(ASR::symbol_t *dt) { LFORTRAN_ASSERT(dt) SymbolTable *symtab = ASRUtils::symbol_symtab(ASRUtils::symbol_get_past_external(dt)); - require(symtab, + require_impl(symtab, "m_dt::m_v::m_type::class/derived_type must point to a symbol with a symbol table", - loc); + dt->base.loc); return symtab; } - SymbolTable *get_dt_symtab(ASR::expr_t *dt, const Location &loc) { - require(ASR::is_a(*dt), - "m_dt must point to a Var", - loc); + SymbolTable *get_dt_symtab(ASR::expr_t *dt) { + require_impl(ASR::is_a(*dt), + "m_dt must point to a Var", dt->base.loc); ASR::Var_t *var = ASR::down_cast(dt); ASR::Variable_t *v = ASR::down_cast(var->m_v); ASR::ttype_t *t2 = ASRUtils::type_get_past_pointer(v->m_type); @@ -469,14 +594,14 @@ class VerifyVisitor : public BaseWalkVisitor break; } default : - require(false, + require_impl(false, "m_dt::m_v::m_type must point to a type with a symbol table (Struct or Class)", - loc); + dt->base.loc); } - return get_dt_symtab(type_sym, loc); + return get_dt_symtab(type_sym); } - ASR::symbol_t *get_parent_type_dt(ASR::symbol_t *dt, const Location &loc) { + ASR::symbol_t *get_parent_type_dt(ASR::symbol_t *dt) { ASR::symbol_t *parent = nullptr; switch (dt->type) { case (ASR::symbolType::StructType): { @@ -486,17 +611,16 @@ class VerifyVisitor : public BaseWalkVisitor break; } default : - require(false, + require_impl(false, "m_dt::m_v::m_type must point to a Struct type", - loc); + dt->base.loc); } return parent; } - ASR::symbol_t *get_parent_type_dt(ASR::expr_t *dt, const Location &loc) { - require(ASR::is_a(*dt), - "m_dt must point to a Var", - loc); + ASR::symbol_t *get_parent_type_dt(ASR::expr_t *dt) { + require_impl(ASR::is_a(*dt), + "m_dt must point to a Var", dt->base.loc); ASR::Var_t *var = ASR::down_cast(dt); ASR::Variable_t *v = ASR::down_cast(var->m_v); ASR::ttype_t *t2 = ASRUtils::type_get_past_pointer(v->m_type); @@ -520,35 +644,36 @@ class VerifyVisitor : public BaseWalkVisitor break; } default : - require(false, + require_impl(false, "m_dt::m_v::m_type must point to a Struct type", - loc); + dt->base.loc); } return parent; } void visit_FunctionCall(const FunctionCall_t &x) { require(x.m_name, - "FunctionCall::m_name must be present", - x.base.base.loc); + "FunctionCall::m_name must be present"); + function_dependencies.push_back(std::string(ASRUtils::symbol_name(x.m_name))); + if( ASR::is_a(*x.m_name) ) { + ASR::ExternalSymbol_t* x_m_name = ASR::down_cast(x.m_name); + module_dependencies.push_back(std::string(x_m_name->m_module_name)); + } if (x.m_dt) { - SymbolTable *symtab = get_dt_symtab(x.m_dt, x.base.base.loc); + SymbolTable *symtab = get_dt_symtab(x.m_dt); require(symtab_in_scope(symtab, x.m_name), - "FunctionCall::m_name cannot point outside of its symbol table", - x.base.base.loc); + "FunctionCall::m_name cannot point outside of its symbol table"); } else { require(symtab_in_scope(current_symtab, x.m_name), "FunctionCall::m_name `" + std::string(symbol_name(x.m_name)) + - "` cannot point outside of its symbol table", - x.base.base.loc); + "` cannot point outside of its symbol table"); // Check both `name` and `orig_name` that `orig_name` points // to GenericProcedure (if applicable), both external and non // external if (check_external) { const ASR::symbol_t *fn = ASRUtils::symbol_get_past_external(x.m_name); require(ASR::is_a(*fn), - "FunctionCall::m_name must be a Function", - x.base.base.loc); + "FunctionCall::m_name must be a Function"); } } for (size_t i=0; i } // namespace ASR -bool asr_verify(const ASR::TranslationUnit_t &unit, bool check_external) { - ASR::VerifyVisitor v(check_external); - v.visit_TranslationUnit(unit); +bool asr_verify(const ASR::TranslationUnit_t &unit, bool check_external, + diag::Diagnostics &diagnostics) { + ASR::VerifyVisitor v(check_external, diagnostics); + try { + v.visit_TranslationUnit(unit); + } catch (const VerifyAbort &) { + LFORTRAN_ASSERT(diagnostics.has_error()) + return false; + } return true; } diff --git a/src/libasr/asr_verify.h b/src/libasr/asr_verify.h index 5facd8c..a0a72bf 100644 --- a/src/libasr/asr_verify.h +++ b/src/libasr/asr_verify.h @@ -35,8 +35,8 @@ namespace LFortran { // // LFORTRAN_ASSERT(asr_verify(*asr)); // - bool asr_verify(const ASR::TranslationUnit_t &unit, bool - check_external=true); + bool asr_verify(const ASR::TranslationUnit_t &unit, + bool check_external, diag::Diagnostics &diagnostics); } // namespace LFortran diff --git a/src/libasr/codegen/KaleidoscopeJIT.h b/src/libasr/codegen/KaleidoscopeJIT.h index c7022a4..1fe7a05 100644 --- a/src/libasr/codegen/KaleidoscopeJIT.h +++ b/src/libasr/codegen/KaleidoscopeJIT.h @@ -12,126 +12,96 @@ #ifndef LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H #define LLVM_EXECUTIONENGINE_ORC_KALEIDOSCOPEJIT_H -#include -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/iterator_range.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" + +#include "llvm/ADT/StringRef.h" #include "llvm/ExecutionEngine/JITSymbol.h" #include "llvm/ExecutionEngine/Orc/CompileUtils.h" +#include "llvm/ExecutionEngine/Orc/Core.h" +#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h" #include "llvm/ExecutionEngine/Orc/IRCompileLayer.h" -#include "llvm/ExecutionEngine/Orc/LambdaResolver.h" +#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h" #include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h" -#include "llvm/ExecutionEngine/RTDyldMemoryManager.h" #include "llvm/ExecutionEngine/SectionMemoryManager.h" #include "llvm/IR/DataLayout.h" -#include "llvm/IR/Mangler.h" -#include "llvm/Support/DynamicLibrary.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Target/TargetMachine.h" -#include -#include +#include "llvm/IR/LLVMContext.h" #include -#include -#include namespace llvm { namespace orc { class KaleidoscopeJIT { +private: + ExecutionSession ES; + RTDyldObjectLinkingLayer ObjectLayer; + IRCompileLayer CompileLayer; + + DataLayout DL; + MangleAndInterner Mangle; + ThreadSafeContext Ctx; + JITDylib &JITDL; + + TargetMachine *TM; + public: - using ObjLayerT = LegacyRTDyldObjectLinkingLayer; - using CompileLayerT = LegacyIRCompileLayer; - - KaleidoscopeJIT(TargetMachine *TM) - : Resolver(createLegacyLookupResolver( - ES, - [this](llvm::StringRef Name) { - return findMangledSymbol(std::string(Name)); - }, - [](Error Err) { cantFail(std::move(Err), "lookupFlags failed"); })), - TM(TM), DL(TM->createDataLayout()), + KaleidoscopeJIT(JITTargetMachineBuilder JTMB, DataLayout DL) + : +#if LLVM_VERSION_MAJOR >= 13 + ES(cantFail(SelfExecutorProcessControl::Create())), +#endif ObjectLayer(ES, - [this](VModuleKey) { - return ObjLayerT::Resources{ - std::make_shared(), Resolver}; - }), - CompileLayer(ObjectLayer, SimpleCompiler(*TM)) { - llvm::sys::DynamicLibrary::LoadLibraryPermanently(nullptr); + []() { return std::make_unique(); }), + CompileLayer(ES, ObjectLayer, std::make_unique(ConcurrentIRCompiler(std::move(JTMB)))), + DL(std::move(DL)), Mangle(ES, this->DL), + Ctx(std::make_unique()), + JITDL( +#if LLVM_VERSION_MAJOR >= 11 + cantFail +#endif + (ES.createJITDylib("Main"))) { + JITDL.addGenerator( + cantFail(DynamicLibrarySearchGenerator::GetForCurrentProcess( + DL.getGlobalPrefix()))); + + std::string Error; + auto TargetTriple = sys::getDefaultTargetTriple(); + auto Target = TargetRegistry::lookupTarget(TargetTriple, Error); + if (!Target) { + throw std::runtime_error("Failed to lookup the target"); + } + auto CPU = "generic"; + auto Features = ""; + TargetOptions opt; + auto RM = Optional(); + TM = Target->createTargetMachine(TargetTriple, CPU, Features, opt, RM); } - TargetMachine &getTargetMachine() { return *TM; } + static Expected> Create() { + auto JTMB = JITTargetMachineBuilder::detectHost(); - VModuleKey addModule(std::unique_ptr M) { - auto K = ES.allocateVModule(); - cantFail(CompileLayer.addModule(K, std::move(M))); - ModuleKeys.push_back(K); - return K; - } + if (!JTMB) + return JTMB.takeError(); - void removeModule(VModuleKey K) { - ModuleKeys.erase(find(ModuleKeys, K)); - cantFail(CompileLayer.removeModule(K)); - } + auto DL = JTMB->getDefaultDataLayoutForTarget(); + if (!DL) + return DL.takeError(); - JITSymbol findSymbol(const std::string Name) { - return findMangledSymbol(mangle(Name)); + return std::make_unique(std::move(*JTMB), std::move(*DL)); } -private: - std::string mangle(const std::string &Name) { - std::string MangledName; - { - raw_string_ostream MangledNameStream(MangledName); - Mangler::getNameWithPrefix(MangledNameStream, Name, DL); - } - return MangledName; - } + const DataLayout &getDataLayout() const { return DL; } - JITSymbol findMangledSymbol(const std::string &Name) { -#ifdef _WIN32 - // The symbol lookup of ObjectLinkingLayer uses the SymbolRef::SF_Exported - // flag to decide whether a symbol will be visible or not, when we call - // IRCompileLayer::findSymbolIn with ExportedSymbolsOnly set to true. - // - // But for Windows COFF objects, this flag is currently never set. - // For a potential solution see: https://reviews.llvm.org/rL258665 - // For now, we allow non-exported symbols on Windows as a workaround. - const bool ExportedSymbolsOnly = false; -#else - const bool ExportedSymbolsOnly = true; -#endif + LLVMContext &getContext() { return *Ctx.getContext(); } - // Search modules in reverse order: from last added to first added. - // This is the opposite of the usual search order for dlsym, but makes more - // sense in a REPL where we want to bind to the newest available definition. - for (auto H : make_range(ModuleKeys.rbegin(), ModuleKeys.rend())) - if (auto Sym = CompileLayer.findSymbolIn(H, Name, ExportedSymbolsOnly)) - return Sym; - - // If we can't find the symbol in the JIT, try looking in the host process. - if (auto SymAddr = RTDyldMemoryManager::getSymbolAddressInProcess(Name)) - return JITSymbol(SymAddr, JITSymbolFlags::Exported); - -#ifdef _WIN32 - // For Windows retry without "_" at beginning, as RTDyldMemoryManager uses - // GetProcAddress and standard libraries like msvcrt.dll use names - // with and without "_" (for example "_itoa" but "sin"). - if (Name.length() > 2 && Name[0] == '_') - if (auto SymAddr = - RTDyldMemoryManager::getSymbolAddressInProcess(Name.substr(1))) - return JITSymbol(SymAddr, JITSymbolFlags::Exported); -#endif + Error addModule(std::unique_ptr M) { + return CompileLayer.add(JITDL, + ThreadSafeModule(std::move(M), Ctx)); + } - return nullptr; + Expected lookup(StringRef Name) { + return ES.lookup({&JITDL}, Mangle(Name.str())); } - ExecutionSession ES; - std::shared_ptr Resolver; - std::unique_ptr TM; - const DataLayout DL; - ObjLayerT ObjectLayer; - CompileLayerT CompileLayer; - std::vector ModuleKeys; + TargetMachine &getTargetMachine() { return *TM; } }; } // end namespace orc diff --git a/src/libasr/codegen/asr_to_c.cpp b/src/libasr/codegen/asr_to_c.cpp index bb1489b..c2df72e 100644 --- a/src/libasr/codegen/asr_to_c.cpp +++ b/src/libasr/codegen/asr_to_c.cpp @@ -5,12 +5,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include @@ -18,199 +20,37 @@ namespace LFortran { -class CUtilFunctions { - - private: - - SymbolTable* global_scope; - std::map util2func; - - int indentation_level, indentation_spaces; - - public: - - std::string util_func_decls; - std::string util_funcs; - - CUtilFunctions() { - util2func.clear(); - util_func_decls.clear(); - util_funcs.clear(); - } - - void set_indentation(int indendation_level_, int indendation_space_) { - indentation_level = indendation_level_; - indentation_spaces = indendation_space_; - } - - void set_global_scope(SymbolTable* global_scope_) { - global_scope = global_scope_; - } - - std::string get_generated_code() { - return util_funcs; - } - - std::string get_util_func_decls() { - return util_func_decls; - } - - void array_size() { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string array_size_func; - if( util2func.find("array_size") == util2func.end() ) { - array_size_func = global_scope->get_unique_name("array_size"); - util2func["array_size"] = array_size_func; - } else { - return ; - } - array_size_func = util2func["array_size"]; - std::string signature = "static inline int32_t " + array_size_func + "(struct dimension_descriptor dims[], size_t n)"; - util_func_decls += indent + signature + ";\n"; - std::string body = indent + signature + " {\n"; - body += indent + tab + "int32_t size = 1;\n"; - body += indent + tab + "for (size_t i = 0; i < n; i++) {\n"; - body += indent + tab + tab + "size *= dims[i].length;\n"; - body += indent + tab + "}\n"; - body += indent + tab + "return size;\n"; - body += indent + "}\n\n"; - util_funcs += body; - } - - void array_reshape(std::string array_type, std::string shape_type, - std::string return_type, std::string element_type, - std::string array_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string array_reshape_func; - if( util2func.find("array_reshape_" + array_type_code) == util2func.end() ) { - array_reshape_func = global_scope->get_unique_name("array_reshape_" + array_type_code); - util2func["array_reshape_" + array_type_code] = array_reshape_func; - } else { - return ; - } - array_reshape_func = util2func["array_reshape_" + array_type_code]; - std::string signature = "static inline " + return_type + "* " + array_reshape_func + "(" + - array_type + " array" + ", " + shape_type + " shape)"; - util_func_decls += indent + signature + ";\n"; - std::string body = indent + signature + " {\n"; - body += indent + tab + "int32_t n = shape->dims[0].length;\n"; - body += indent + tab + return_type + "* reshaped = (" + return_type + "*) malloc(sizeof(" + return_type + "));\n"; - body += indent + tab + "int32_t array_size_ = " + get_array_size() + "(array->dims, array->n_dims);\n"; - body += indent + tab + "int32_t shape_size_ = " + get_array_size() + "(shape->dims, shape->n_dims);\n"; - body += indent + tab + "int32_t reshaped_size = 1;\n"; - body += indent + tab + "for (int32_t i = 0; i < shape_size_; i++) {\n"; - body += indent + tab + tab + "reshaped_size *= shape->data[i];\n"; - body += indent + tab + "}\n"; - body += indent + tab + "ASSERT(array_size_ == reshaped_size);\n"; - body += indent + tab + "reshaped->data = (" + element_type + "*) malloc(sizeof(" + element_type + ")*array_size_);\n"; - body += indent + tab + "reshaped->data = (" + element_type + "*) memcpy(reshaped->data, array->data, sizeof(" + element_type + ")*array_size_);\n"; - body += indent + tab + "reshaped->n_dims = shape_size_;\n"; - body += indent + tab + "for (int32_t i = 0; i < shape_size_; i++) {\n"; - body += indent + tab + tab + "reshaped->dims[i].lower_bound = 0;\n"; - body += indent + tab + tab + "reshaped->dims[i].length = shape->data[i];\n"; - body += indent + tab + "}\n"; - body += indent + tab + "return reshaped;\n"; - body += indent + "}\n\n"; - util_funcs += body; - } - - void array_constant(std::string return_type, std::string element_type, - std::string array_type_code) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string array_const_func; - if( util2func.find("array_constant_" + array_type_code) == util2func.end() ) { - array_const_func = global_scope->get_unique_name("array_constant_" + array_type_code); - util2func["array_constant_" + array_type_code] = array_const_func; - } else { - return ; - } - array_const_func = util2func["array_constant_" + array_type_code]; - std::string signature = "static inline " + return_type + "* " + array_const_func + "(int32_t n, ...)"; - util_func_decls += indent + signature + ";\n"; - std::string body = indent + signature + " {\n"; - body += indent + tab + return_type + "* const_array = (" + return_type + "*) malloc(sizeof(" + return_type + "));\n"; - body += indent + tab + "va_list ap;\n"; - body += indent + tab + "va_start(ap, n);\n"; - body += indent + tab + "const_array->data = (" + element_type + "*) malloc(sizeof(" + element_type + ")*n);\n"; - body += indent + tab + "const_array->n_dims = 1;\n"; - body += indent + tab + "const_array->dims[0].lower_bound = 0;\n"; - body += indent + tab + "const_array->dims[0].length = n;\n"; - body += indent + tab + "for (int32_t i = 0; i < n; i++) {\n"; - body += indent + tab + tab + "const_array->data[i] = va_arg(ap, " + element_type +");\n"; - body += indent + tab + "}\n"; - body += indent + tab + "va_end(ap);\n"; - body += indent + tab + "return const_array;\n"; - body += indent + "}\n\n"; - util_funcs += body; - } - - std::string get_array_size() { - array_size(); - return util2func["array_size"]; - } - - std::string get_array_reshape( - std::string array_type, std::string shape_type, - std::string return_type, std::string element_type, - std::string array_type_code) { - array_reshape(array_type, shape_type, - return_type, element_type, - array_type_code); - return util2func["array_reshape_" + array_type_code]; - } - - std::string get_array_constant(std::string return_type, - std::string element_type, std::string encoded_type) { - array_constant(return_type, element_type, encoded_type); - return util2func["array_constant_" + encoded_type]; - } -}; - -std::string format_type_c(const std::string &dims, const std::string &type, - const std::string &name, bool use_ref, bool /*dummy*/) -{ - std::string fmt; - std::string ref = ""; - if (use_ref) ref = "*"; - if( dims == "*" ) { - fmt = type + " " + dims + ref + name; - } else { - fmt = type + " " + ref + name + dims; - } - return fmt; -} - class ASRToCVisitor : public BaseCCPPVisitor { public: std::string array_types_decls; - std::map eltypedims2arraytype; - std::unique_ptr c_utils_functions; + std::unique_ptr c_utils_functions; + + int counter; ASRToCVisitor(diag::Diagnostics &diag, Platform &platform, int64_t default_lower_bound) : BaseCCPPVisitor(diag, platform, false, false, true, default_lower_bound), array_types_decls(std::string("\nstruct dimension_descriptor\n" "{\n int32_t lower_bound, length;\n};\n")), - c_utils_functions{std::make_unique()} { + c_utils_functions{std::make_unique()}, + counter{0} { } std::string convert_dims_c(size_t n_dims, ASR::dimension_t *m_dims, ASR::ttype_t* element_type, bool& is_fixed_size, bool convert_to_1d=false) { - std::string dims; + std::string dims = ""; size_t size = 1; std::string array_size = ""; for (size_t i=0; i } } if( size == 0 ) { - std::string element_type_str = get_c_type_from_ttype_t(element_type); + std::string element_type_str = CUtils::get_c_type_from_ttype_t(element_type); dims = "(" + element_type_str + "*)" + " malloc(sizeof(" + element_type_str + ")" + array_size + ")"; is_fixed_size = false; return dims; @@ -238,32 +78,6 @@ class ASRToCVisitor : public BaseCCPPVisitor return dims; } - std::string get_array_type(std::string type_name, std::string encoded_type_name, - bool make_ptr=true) { - if( eltypedims2arraytype.find(encoded_type_name) != eltypedims2arraytype.end() ) { - if( make_ptr ) { - return eltypedims2arraytype[encoded_type_name] + "*"; - } else { - return eltypedims2arraytype[encoded_type_name]; - } - } - - std::string struct_name; - std::string new_array_type; - struct_name = "struct " + encoded_type_name; - std::string array_data = format_type_c("*", type_name, "data", false, false); - new_array_type = struct_name + "\n{\n " + array_data + - ";\n struct dimension_descriptor dims[32];\n" + - " int32_t n_dims;\n" - " bool is_allocated;\n};\n"; - if( make_ptr ) { - type_name = struct_name + "*"; - } - eltypedims2arraytype[encoded_type_name] = struct_name; - array_types_decls += "\n" + new_array_type + "\n"; - return type_name; - } - void generate_array_decl(std::string& sub, std::string v_m_name, std::string& type_name, std::string& dims, std::string& encoded_type_name, @@ -273,8 +87,8 @@ class ASRToCVisitor : public BaseCCPPVisitor bool is_pointer=false) { std::string indent(indentation_level*indentation_spaces, ' '); std::string type_name_copy = type_name; - type_name = get_array_type(type_name, encoded_type_name); - std::string type_name_without_ptr = get_array_type(type_name, encoded_type_name, false); + type_name = c_ds_api->get_array_type(type_name, encoded_type_name, array_types_decls); + std::string type_name_without_ptr = c_ds_api->get_array_type(type_name, encoded_type_name, array_types_decls, false); if( declare_value ) { std::string variable_name = std::string(v_m_name) + "_value"; sub = format_type_c("", type_name_without_ptr, variable_name, use_ref, dummy) + ";\n"; @@ -284,7 +98,11 @@ class ASRToCVisitor : public BaseCCPPVisitor if( !is_fixed_size ) { sub += indent + format_type_c("*", type_name_copy, std::string(v_m_name) + "_data", use_ref, dummy); - sub += " = " + dims + ";\n"; + if( dims.size() > 0 ) { + sub += " = " + dims + ";\n"; + } else { + sub += ";\n"; + } } else { sub += indent + format_type_c(dims, type_name_copy, std::string(v_m_name) + "_data", use_ref, dummy) + ";\n"; @@ -317,27 +135,57 @@ class ASRToCVisitor : public BaseCCPPVisitor } } + void allocate_array_members_of_struct(ASR::StructType_t* der_type_t, std::string& sub, + std::string indent, std::string name) { + for( auto itr: der_type_t->m_symtab->get_scope() ) { + ASR::ttype_t* mem_type = ASRUtils::symbol_type(itr.second); + if( ASRUtils::is_character(*mem_type) ) { + sub += indent + name + "->" + itr.first + " = (char*) malloc(40 * sizeof(char));\n"; + } else if( ASRUtils::is_array(mem_type) && + ASR::is_a(*itr.second) ) { + ASR::Variable_t* mem_var = ASR::down_cast(itr.second); + std::string mem_var_name = current_scope->get_unique_name(itr.first + std::to_string(counter)); + counter += 1; + sub += indent + convert_variable_decl(*mem_var, true, true, true, true, mem_var_name) + ";\n"; + sub += indent + name + "->" + itr.first + " = " + mem_var_name + ";\n"; + } else if( ASR::is_a(*mem_type) ) { + ASR::Struct_t* struct_t = ASR::down_cast(mem_type); + ASR::StructType_t* struct_type_t = ASR::down_cast( + ASRUtils::symbol_get_past_external(struct_t->m_derived_type)); + allocate_array_members_of_struct(struct_type_t, sub, indent, "(&(" + name + "->" + itr.first + "))"); + } + } + } + std::string convert_variable_decl(const ASR::Variable_t &v, bool pre_initialise_derived_type=true, bool use_ptr_for_derived_type=true, - bool use_static=true) + bool use_static=true, + bool force_declare=false, + std::string force_declare_name="") { std::string sub; bool use_ref = (v.m_intent == LFortran::ASRUtils::intent_out || v.m_intent == LFortran::ASRUtils::intent_inout); bool is_array = ASRUtils::is_array(v.m_type); bool dummy = LFortran::ASRUtils::is_arg_dummy(v.m_intent); - if (ASRUtils::is_pointer(v.m_type)) { - ASR::ttype_t *t2 = ASR::down_cast(v.m_type)->m_type; + ASR::ttype_t* v_m_type = v.m_type; + if (ASR::is_a(*v_m_type)) { + if( is_array ) { + v_m_type = ASR::down_cast(v_m_type)->m_type; + } + } + if (ASRUtils::is_pointer(v_m_type)) { + ASR::ttype_t *t2 = ASR::down_cast(v_m_type)->m_type; if (ASRUtils::is_integer(*t2)) { ASR::Integer_t *t = ASR::down_cast(t2); std::string type_name = "int" + std::to_string(t->m_kind * 8) + "_t"; - if( !ASRUtils::is_array(v.m_type) ) { + if( !ASRUtils::is_array(v_m_type) ) { type_name.append(" *"); } if( is_array ) { bool is_fixed_size = true; - std::string dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size, true); + std::string dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); std::string encoded_type_name = "i" + std::to_string(t->m_kind * 8); generate_array_decl(sub, std::string(v.m_name), type_name, dims, encoded_type_name, t->m_dims, t->n_dims, @@ -347,75 +195,97 @@ class ASRToCVisitor : public BaseCCPPVisitor v.m_intent != ASRUtils::intent_out, is_fixed_size, true); } else { bool is_fixed_size = true; - std::string dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size); + std::string dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); sub = format_type_c(dims, type_name, v.m_name, use_ref, dummy); } } else if(ASR::is_a(*t2)) { ASR::Struct_t *t = ASR::down_cast(t2); std::string der_type_name = ASRUtils::symbol_name(t->m_derived_type); - bool is_fixed_size = true; - std::string dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size); - std::string ptr_char = "*"; - if( !use_ptr_for_derived_type ) { - ptr_char.clear(); + if( is_array ) { + bool is_fixed_size = true; + std::string dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); + std::string encoded_type_name = "x" + der_type_name; + std::string type_name = std::string("struct ") + der_type_name; + generate_array_decl(sub, std::string(v.m_name), type_name, dims, + encoded_type_name, t->m_dims, t->n_dims, + use_ref, dummy, + v.m_intent != ASRUtils::intent_in && + v.m_intent != ASRUtils::intent_inout, + is_fixed_size); + } else { + std::string ptr_char = "*"; + if( !use_ptr_for_derived_type ) { + ptr_char.clear(); + } + sub = format_type_c("", "struct " + der_type_name + ptr_char, + v.m_name, use_ref, dummy); } - sub = format_type_c(dims, "struct " + der_type_name + ptr_char, - v.m_name, use_ref, dummy); + } else if(ASR::is_a(*t2)) { + sub = format_type_c("", "void**", v.m_name, false, false); } else { diag.codegen_error_label("Type number '" - + std::to_string(v.m_type->type) + + std::to_string(v_m_type->type) + "' not supported", {v.base.base.loc}, ""); throw Abort(); } } else { std::string dims; use_ref = use_ref && !is_array; - if (ASRUtils::is_integer(*v.m_type)) { + if (ASRUtils::is_integer(*v_m_type)) { headers.insert("inttypes"); - ASR::Integer_t *t = ASR::down_cast(v.m_type); + ASR::Integer_t *t = ASR::down_cast(v_m_type); std::string type_name = "int" + std::to_string(t->m_kind * 8) + "_t"; if( is_array ) { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size, true); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); std::string encoded_type_name = "i" + std::to_string(t->m_kind * 8); + bool is_struct_type_member = ASR::is_a( + *ASR::down_cast(v.m_parent_symtab->asr_owner)); generate_array_decl(sub, std::string(v.m_name), type_name, dims, encoded_type_name, t->m_dims, t->n_dims, use_ref, dummy, - v.m_intent != ASRUtils::intent_in && + (v.m_intent != ASRUtils::intent_in && v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out, is_fixed_size); + v.m_intent != ASRUtils::intent_out && + !is_struct_type_member) || force_declare, is_fixed_size); } else { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); sub = format_type_c(dims, type_name, v.m_name, use_ref, dummy); } - } else if (ASRUtils::is_real(*v.m_type)) { - ASR::Real_t *t = ASR::down_cast(v.m_type); + } else if (ASRUtils::is_real(*v_m_type)) { + ASR::Real_t *t = ASR::down_cast(v_m_type); std::string type_name = "float"; if (t->m_kind == 8) type_name = "double"; if( is_array ) { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size, true); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); std::string encoded_type_name = "r" + std::to_string(t->m_kind * 8); - generate_array_decl(sub, std::string(v.m_name), type_name, dims, + bool is_struct_type_member = ASR::is_a( + *ASR::down_cast(v.m_parent_symtab->asr_owner)); + if( !force_declare ) { + force_declare_name = std::string(v.m_name); + } + generate_array_decl(sub, force_declare_name, type_name, dims, encoded_type_name, t->m_dims, t->n_dims, use_ref, dummy, - v.m_intent != ASRUtils::intent_in && + (v.m_intent != ASRUtils::intent_in && v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out, is_fixed_size); + v.m_intent != ASRUtils::intent_out && + !is_struct_type_member) || force_declare, is_fixed_size); } else { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); sub = format_type_c(dims, type_name, v.m_name, use_ref, dummy); } - } else if (ASRUtils::is_complex(*v.m_type)) { + } else if (ASRUtils::is_complex(*v_m_type)) { headers.insert("complex"); - ASR::Complex_t *t = ASR::down_cast(v.m_type); + ASR::Complex_t *t = ASR::down_cast(v_m_type); std::string type_name = "float complex"; if (t->m_kind == 8) type_name = "double complex"; if( is_array ) { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size, true); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); std::string encoded_type_name = "c" + std::to_string(t->m_kind * 8); generate_array_decl(sub, std::string(v.m_name), type_name, dims, encoded_type_name, t->m_dims, t->n_dims, @@ -425,30 +295,33 @@ class ASRToCVisitor : public BaseCCPPVisitor is_fixed_size); } else { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); sub = format_type_c(dims, type_name, v.m_name, use_ref, dummy); } - } else if (ASRUtils::is_logical(*v.m_type)) { - ASR::Logical_t *t = ASR::down_cast(v.m_type); + } else if (ASRUtils::is_logical(*v_m_type)) { + ASR::Logical_t *t = ASR::down_cast(v_m_type); bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); sub = format_type_c(dims, "bool", v.m_name, use_ref, dummy); - } else if (ASRUtils::is_character(*v.m_type)) { - ASR::Character_t *t = ASR::down_cast(v.m_type); + } else if (ASRUtils::is_character(*v_m_type)) { + ASR::Character_t *t = ASR::down_cast(v_m_type); bool is_fixed_size = true; - std::string dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size); + std::string dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); sub = format_type_c(dims, "char *", v.m_name, use_ref, dummy); - if( v.m_intent == ASRUtils::intent_local ) { + if( v.m_intent == ASRUtils::intent_local && + !(ASR::is_a(*v.m_parent_symtab->asr_owner) && + ASR::is_a( + *ASR::down_cast(v.m_parent_symtab->asr_owner))) ) { sub += " = (char*) malloc(40 * sizeof(char))"; return sub; } - } else if (ASR::is_a(*v.m_type)) { + } else if (ASR::is_a(*v_m_type)) { std::string indent(indentation_level*indentation_spaces, ' '); - ASR::Struct_t *t = ASR::down_cast(v.m_type); + ASR::Struct_t *t = ASR::down_cast(v_m_type); std::string der_type_name = ASRUtils::symbol_name(t->m_derived_type); if( is_array ) { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size, true); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); std::string encoded_type_name = "x" + der_type_name; std::string type_name = std::string("struct ") + der_type_name; generate_array_decl(sub, std::string(v.m_name), type_name, dims, @@ -459,7 +332,7 @@ class ASRToCVisitor : public BaseCCPPVisitor is_fixed_size); } else if( v.m_intent == ASRUtils::intent_local && pre_initialise_derived_type) { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); std::string value_var_name = v.m_parent_symtab->get_unique_name(std::string(v.m_name) + "_value"); sub = format_type_c(dims, "struct " + der_type_name, value_var_name, use_ref, dummy); @@ -477,14 +350,20 @@ class ASRToCVisitor : public BaseCCPPVisitor if( t->n_dims != 0 ) { sub += " = " + value_var_name; } else { - sub += " = &" + value_var_name; + sub += " = &" + value_var_name + ";\n"; + ASR::StructType_t* der_type_t = ASR::down_cast( + ASRUtils::symbol_get_past_external(t->m_derived_type)); + allocate_array_members_of_struct(der_type_t, sub, indent, std::string(v.m_name)); + sub.pop_back(); + sub.pop_back(); } return sub; } else { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); if( v.m_intent == ASRUtils::intent_in || - v.m_intent == ASRUtils::intent_inout ) { + v.m_intent == ASRUtils::intent_inout || + v.m_intent == ASRUtils::intent_out ) { use_ref = false; dims = ""; } @@ -495,13 +374,13 @@ class ASRToCVisitor : public BaseCCPPVisitor sub = format_type_c(dims, "struct " + der_type_name + ptr_char, v.m_name, use_ref, dummy); } - } else if (ASR::is_a(*v.m_type)) { + } else if (ASR::is_a(*v_m_type)) { std::string indent(indentation_level*indentation_spaces, ' '); - ASR::Union_t *t = ASR::down_cast(v.m_type); + ASR::Union_t *t = ASR::down_cast(v_m_type); std::string der_type_name = ASRUtils::symbol_name(t->m_union_type); if( is_array ) { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size, true); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); std::string encoded_type_name = "x" + der_type_name; std::string type_name = std::string("union ") + der_type_name; generate_array_decl(sub, std::string(v.m_name), type_name, dims, @@ -511,7 +390,7 @@ class ASRToCVisitor : public BaseCCPPVisitor v.m_intent != ASRUtils::intent_inout, is_fixed_size); } else { bool is_fixed_size = true; - dims = convert_dims_c(t->n_dims, t->m_dims, v.m_type, is_fixed_size); + dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); if( v.m_intent == ASRUtils::intent_in || v.m_intent == ASRUtils::intent_inout ) { use_ref = false; @@ -520,21 +399,37 @@ class ASRToCVisitor : public BaseCCPPVisitor sub = format_type_c(dims, "union " + der_type_name, v.m_name, use_ref, dummy); } - } else if (ASR::is_a(*v.m_type)) { - ASR::List_t* t = ASR::down_cast(v.m_type); - std::string list_element_type = get_c_type_from_ttype_t(t->m_type); - std::string list_type_c = list_api->get_list_type(t, list_element_type); + } else if (ASR::is_a(*v_m_type)) { + ASR::List_t* t = ASR::down_cast(v_m_type); + std::string list_type_c = c_ds_api->get_list_type(t); sub = format_type_c("", list_type_c, v.m_name, false, false); - } else if (ASR::is_a(*v.m_type)) { + } else if (ASR::is_a(*v_m_type)) { + ASR::Tuple_t* t = ASR::down_cast(v_m_type); + std::string tuple_type_c = c_ds_api->get_tuple_type(t); + sub = format_type_c("", tuple_type_c, v.m_name, + false, false); + } else if (ASR::is_a(*v_m_type)) { sub = format_type_c("", "void*", v.m_name, false, false); - } else if (ASR::is_a(*v.m_type)) { - ASR::Enum_t* enum_ = ASR::down_cast(v.m_type); + } else if (ASR::is_a(*v_m_type)) { + ASR::Enum_t* enum_ = ASR::down_cast(v_m_type); ASR::EnumType_t* enum_type = ASR::down_cast(enum_->m_enum_type); sub = format_type_c("", "enum " + std::string(enum_type->m_name), v.m_name, false, false); + } else if (ASR::is_a(*v_m_type)) { + if( v.m_intent == ASRUtils::intent_local ) { + LFORTRAN_ASSERT(v.m_symbolic_value); + visit_expr(*v.m_symbolic_value); + sub = "#define " + std::string(v.m_name) + " " + src + "\n"; + return sub; + } else { + std::string const_underlying_type = CUtils::get_c_type_from_ttype_t( + ASR::down_cast(v_m_type)->m_type); + sub = format_type_c("", "const " + const_underlying_type + " ", + v.m_name, false, false); + } } else { diag.codegen_error_label("Type number '" - + std::to_string(v.m_type->type) + + std::to_string(v_m_type->type) + "' not supported", {v.base.base.loc}, ""); throw Abort(); } @@ -560,10 +455,11 @@ class ASRToCVisitor : public BaseCCPPVisitor std::string unit_src = ""; indentation_level = 0; indentation_spaces = 4; - list_api->set_indentation(indentation_level, indentation_spaces); - list_api->set_global_scope(global_scope); + c_ds_api->set_indentation(indentation_level, indentation_spaces); + c_ds_api->set_global_scope(global_scope); c_utils_functions->set_indentation(indentation_level, indentation_spaces); c_utils_functions->set_global_scope(global_scope); + c_ds_api->set_c_utils_functions(c_utils_functions.get()); std::string head = R"( @@ -607,46 +503,44 @@ R"( strcat_def += indent + tab + "return strcat(str_tmp, y);\n"; strcat_def += indent + "}\n\n"; - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - array_types_decls += "struct " + item.first + ";\n\n"; - } else if (ASR::is_a(*item.second)) { - array_types_decls += "enum " + item.first + ";\n\n"; - } else if (ASR::is_a(*item.second)) { - array_types_decls += "union " + item.first + ";\n\n"; - } - } - for (auto &item : x.m_global_scope->get_scope()) { if (ASR::is_a(*item.second)) { ASR::Variable_t *v = ASR::down_cast(item.second); - unit_src += convert_variable_decl(*v) + ";\n"; + unit_src += convert_variable_decl(*v); + if( !ASR::is_a(*v->m_type) || + v->m_intent == ASRUtils::intent_return_var ) { + unit_src += ";\n"; + } } } + + std::map> struct_dep_graph; for (auto &item : x.m_global_scope->get_scope()) { if (ASR::is_a(*item.second) || ASR::is_a(*item.second) || ASR::is_a(*item.second)) { - visit_symbol(*item.second); - array_types_decls += src; + std::vector struct_deps_vec; + std::pair struct_deps_ptr = ASRUtils::symbol_dependencies(item.second); + for( size_t i = 0; i < struct_deps_ptr.second; i++ ) { + struct_deps_vec.push_back(std::string(struct_deps_ptr.first[i])); + } + struct_dep_graph[item.first] = struct_deps_vec; } } - // Pre-declare all functions first, then generate code - // Otherwise some function might not be found. - unit_src += "// Forward declarations\n"; - unit_src += declare_all_functions(*x.m_global_scope); - // Now pre-declare all functions from modules and programs - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Module_t *m = ASR::down_cast(item.second); - unit_src += declare_all_functions(*m->m_symtab); - } else if (ASR::is_a(*item.second)) { - ASR::Program_t *p = ASR::down_cast(item.second); - unit_src += declare_all_functions(*p->m_symtab); - } + std::vector struct_deps = ASRUtils::order_deps(struct_dep_graph); + + for (auto &item : struct_deps) { + ASR::symbol_t* struct_sym = x.m_global_scope->get_symbol(item); + visit_symbol(*struct_sym); + array_types_decls += src; } + + // Topologically sort all global functions + // and then define them in the right order + std::vector global_func_order = ASRUtils::determine_function_definition_order(x.m_global_scope); + unit_src += "\n"; unit_src += "// Implementations\n"; @@ -667,17 +561,7 @@ R"( } } - // Process procedures first: - for (auto &item : x.m_global_scope->get_scope()) { - if (ASR::is_a(*item.second)) { - if( ASRUtils::get_body_size(item.second) != 0 ) { - visit_symbol(*item.second); - unit_src += src; - } - } - } - - // Then do all the modules in the right order + // Process modules in the right order std::vector build_order = LFortran::ASRUtils::determine_module_dependencies(x); for (auto &item : build_order) { @@ -690,6 +574,18 @@ R"( } } + // Process global functions + size_t i; + for (i = 0; i < global_func_order.size(); i++) { + ASR::symbol_t* sym = x.m_global_scope->get_symbol(global_func_order[i]); + // Ignore external symbols because they are already defined by the loop above. + if( !sym || ASR::is_a(*sym) ) { + continue ; + } + visit_symbol(*sym); + unit_src += src; + } + // Then the main program: for (auto &item : x.m_global_scope->get_scope()) { if (ASR::is_a(*item.second)) { @@ -701,15 +597,15 @@ R"( for (auto s: headers) { to_include += "#include <" + s + ".h>\n"; } - if( list_api->get_list_func_decls().size() > 0 ) { - array_types_decls += "\n" + list_api->get_list_func_decls() + "\n"; + if( c_ds_api->get_func_decls().size() > 0 ) { + array_types_decls += "\n" + c_ds_api->get_func_decls() + "\n"; } if( c_utils_functions->get_util_func_decls().size() > 0 ) { array_types_decls += "\n" + c_utils_functions->get_util_func_decls() + "\n"; } - std::string list_funcs_defined = ""; - if( list_api->get_generated_code().size() > 0 ) { - list_funcs_defined = "\n" + list_api->get_generated_code() + "\n"; + std::string ds_funcs_defined = ""; + if( c_ds_api->get_generated_code().size() > 0 ) { + ds_funcs_defined = "\n" + c_ds_api->get_generated_code() + "\n"; } std::string util_funcs_defined = ""; if( c_utils_functions->get_generated_code().size() > 0 ) { @@ -719,18 +615,21 @@ R"( head += strcat_def; } src = to_include + head + array_types_decls + unit_src + - list_funcs_defined + util_funcs_defined; + ds_funcs_defined + util_funcs_defined; } void visit_Program(const ASR::Program_t &x) { + // Topologically sort all program functions + // and then define them in the right order + std::vector func_order = ASRUtils::determine_function_definition_order(x.m_symtab); + // Generate code for nested subroutines and functions first: std::string contains; - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Function_t *s = ASR::down_cast(item.second); - visit_Function(*s); - contains += src; - } + for (auto &item : func_order) { + ASR::symbol_t* sym = x.m_symtab->get_symbol(item); + ASR::Function_t *s = ASR::down_cast(sym); + visit_Function(*s); + contains += src; } // Generate code for the main program @@ -741,7 +640,11 @@ R"( if (ASR::is_a(*item.second)) { ASR::Variable_t *v = ASR::down_cast(item.second); decl += indent1; - decl += convert_variable_decl(*v) + ";\n"; + decl += convert_variable_decl(*v); + if( !ASR::is_a(*v->m_type) || + v->m_intent == ASRUtils::intent_return_var ) { + decl += ";\n"; + } } } @@ -769,8 +672,11 @@ R"( LFORTRAN_ASSERT(ASR::is_a(*member)); body += indent + convert_variable_decl( *ASR::down_cast(member), - false, - (c_type_name != "union")) + ";\n"; + false, false); + if( !ASR::is_a(*ASRUtils::symbol_type(member)) || + ASR::down_cast(member)->m_intent == ASRUtils::intent_return_var ) { + body += ";\n"; + } } indentation_level -= 1; std::string end_struct = "};\n\n"; @@ -778,7 +684,24 @@ R"( } void visit_StructType(const ASR::StructType_t& x) { - visit_AggregateTypeUtil(x, "struct"); + src = ""; + std::string c_type_name = "struct"; + if( x.m_is_packed ) { + std::string attr_args = "(packed"; + if( x.m_alignment ) { + LFORTRAN_ASSERT(ASRUtils::expr_value(x.m_alignment)); + ASR::expr_t* alignment_value = ASRUtils::expr_value(x.m_alignment); + int64_t alignment_int = -1; + if( !ASRUtils::extract_value(alignment_value, alignment_int) ) { + LFORTRAN_ASSERT(false); + } + attr_args += ", aligned(" + std::to_string(alignment_int) + ")"; + } + attr_args += ")"; + c_type_name += " __attribute__(" + attr_args + ")"; + } + visit_AggregateTypeUtil(x, c_type_name); + src = ""; } void visit_UnionType(const ASR::UnionType_t& x) { @@ -804,7 +727,6 @@ R"( std::string meta_data = " = {"; std::string open_struct = indent + "enum " + std::string(x.m_name) + " {\n"; std::string body = ""; - std::string src_copy = src; int64_t min_value = INT64_MAX; int64_t max_value = INT64_MIN; size_t max_name_len = 0; @@ -843,7 +765,7 @@ R"( std::string enum_names_type = "char " + global_scope->get_unique_name("enum_names_") + std::string(x.m_name) + "[" + std::to_string(max_names) + "][" + std::to_string(max_name_len + 1) + "] "; array_types_decls += enum_names_type + meta_data + open_struct + body + end_struct; - src = src_copy; + src = ""; } void visit_EnumTypeConstructor(const ASR::EnumTypeConstructor_t& x) { @@ -954,6 +876,9 @@ R"( case ASR::ttypeType::CPtr: { return "%p"; } + case ASR::ttypeType::Complex: { + return "(%f, %f)"; + } case ASR::ttypeType::Pointer: { if( !deref_ptr ) { return "%p"; @@ -966,6 +891,10 @@ R"( ASR::ttype_t* enum_underlying_type = ASRUtils::get_contained_type(t); return get_print_type(enum_underlying_type, deref_ptr); } + case ASR::ttypeType::Const: { + ASR::ttype_t* const_underlying_type = ASRUtils::get_contained_type(t); + return get_print_type(const_underlying_type, deref_ptr); + } default : throw LCompilersException("Not implemented"); } } @@ -989,6 +918,11 @@ R"( ASR::ttype_t* value_type = ASRUtils::expr_type(x.m_values[i]); out += get_print_type(value_type, ASR::is_a(*x.m_values[i])); v.push_back(src); + if (value_type->type == ASR::ttypeType::Complex) { + v.pop_back(); + v.push_back("creal(" + src + ")"); + v.push_back("cimag(" + src + ")"); + } if (i+1!=x.n_values) { out += "\%s"; v.push_back(separator); @@ -1014,7 +948,7 @@ R"( visit_expr(*x.m_v); std::string var_name = src; std::string args = ""; - std::string result_type = get_c_type_from_ttype_t(x.m_type); + std::string result_type = CUtils::get_c_type_from_ttype_t(x.m_type); if (x.m_dim == nullptr) { std::string array_size_func = c_utils_functions->get_array_size(); ASR::dimension_t* m_dims = nullptr; @@ -1034,15 +968,15 @@ R"( std::string shape = src; ASR::ttype_t* array_type_asr = ASRUtils::expr_type(x.m_array); - std::string array_type_name = get_c_type_from_ttype_t(array_type_asr); - std::string array_encoded_type_name = ASRUtils::get_type_code(array_type_asr, true, false); - std::string array_type = get_array_type(array_type_name, array_encoded_type_name, true); - std::string return_type = get_array_type(array_type_name, array_encoded_type_name, false); + std::string array_type_name = CUtils::get_c_type_from_ttype_t(array_type_asr); + std::string array_encoded_type_name = ASRUtils::get_type_code(array_type_asr, true, false, false); + std::string array_type = c_ds_api->get_array_type(array_type_name, array_encoded_type_name, array_types_decls, true); + std::string return_type = c_ds_api->get_array_type(array_type_name, array_encoded_type_name, array_types_decls, false); ASR::ttype_t* shape_type_asr = ASRUtils::expr_type(x.m_shape); - std::string shape_type_name = get_c_type_from_ttype_t(shape_type_asr); - std::string shape_encoded_type_name = ASRUtils::get_type_code(shape_type_asr, true, false); - std::string shape_type = get_array_type(shape_type_name, shape_encoded_type_name, true); + std::string shape_type_name = CUtils::get_c_type_from_ttype_t(shape_type_asr); + std::string shape_encoded_type_name = ASRUtils::get_type_code(shape_type_asr, true, false, false); + std::string shape_type = c_ds_api->get_array_type(shape_type_name, shape_encoded_type_name, array_types_decls, true); std::string array_reshape_func = c_utils_functions->get_array_reshape(array_type, shape_type, return_type, array_type_name, array_encoded_type_name); @@ -1053,7 +987,7 @@ R"( visit_expr(*x.m_v); std::string var_name = src; std::string args = ""; - std::string result_type = get_c_type_from_ttype_t(x.m_type); + std::string result_type = CUtils::get_c_type_from_ttype_t(x.m_type); visit_expr(*x.m_dim); std::string idx = src; if( x.m_bound == ASR::arrayboundType::LBound ) { @@ -1078,9 +1012,9 @@ R"( array_const.pop_back(); ASR::ttype_t* array_type_asr = x.m_type; - std::string array_type_name = get_c_type_from_ttype_t(array_type_asr); + std::string array_type_name = CUtils::get_c_type_from_ttype_t(array_type_asr); std::string array_encoded_type_name = ASRUtils::get_type_code(array_type_asr, true, false); - std::string return_type = get_array_type(array_type_name, array_encoded_type_name, false); + std::string return_type = c_ds_api->get_array_type(array_type_name, array_encoded_type_name,array_types_decls, false); src = c_utils_functions->get_array_constant(return_type, array_type_name, array_encoded_type_name) + "(" + std::to_string(x.n_args) + ", " + array_const + ")"; @@ -1149,6 +1083,7 @@ Result asr_to_c(Allocator &al, ASR::TranslationUnit_t &asr, LCompilers::PassOptions pass_options; pass_options.always_run = true; + pass_create_subroutine_from_function(al, asr, pass_options); pass_replace_array_op(al, asr, pass_options); pass_unused_functions(al, asr, pass_options); pass_replace_class_constructor(al, asr, pass_options); diff --git a/src/libasr/codegen/asr_to_c_cpp.h b/src/libasr/codegen/asr_to_c_cpp.h index 465ed76..455f38e 100644 --- a/src/libasr/codegen/asr_to_c_cpp.h +++ b/src/libasr/codegen/asr_to_c_cpp.h @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -29,29 +30,6 @@ namespace LFortran { -namespace { - - // Local exception that is only used in this file to exit the visitor - // pattern and caught later (not propagated outside) - class CodeGenError - { - public: - diag::Diagnostic d; - public: - CodeGenError(const std::string &msg) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} - { } - - CodeGenError(const std::string &msg, const Location &loc) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen, { - diag::Label("", {loc}) - })} - { } - }; - - class Abort {}; - -} // Platform dependent fast unique hash: static inline uint64_t get_hash(ASR::asr_t *node) @@ -65,372 +43,6 @@ struct SymbolInfo bool intrinsic_function = false; }; -typedef std::string (*DeepCopyFunction)(std::string, std::string, ASR::ttype_t*); - -namespace CUtils { - static inline std::string deepcopy(std::string target, std::string value, ASR::ttype_t* m_type) { - switch (m_type->type) { - case ASR::ttypeType::Character: { - return "strcpy(" + target + ", " + value + ");"; - } - default: { - return target + " = " + value + ";"; - } - } - } -} - -namespace CPPUtils { - static inline std::string deepcopy(std::string target, std::string value, ASR::ttype_t* /*m_type*/) { - return target + " = " + value + ";"; - } -} - -class CCPPList { - private: - - std::map> typecode2listtype; - std::map> typecode2listfuncs; - std::map compare_list_eles; - - int indentation_level, indentation_spaces; - - std::string generated_code; - std::string list_func_decls; - - SymbolTable* global_scope; - DeepCopyFunction deepcopy_function; - - public: - - CCPPList() { - generated_code.clear(); - list_func_decls.clear(); - } - - void set_deepcopy_function(DeepCopyFunction func) { - deepcopy_function = func; - } - - void set_indentation(int indendation_level_, int indendation_space_) { - indentation_level = indendation_level_; - indentation_spaces = indendation_space_; - } - - void set_global_scope(SymbolTable* global_scope_) { - global_scope = global_scope_; - } - - std::string get_list_type(ASR::List_t* list_type, - std::string list_element_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - if( typecode2listtype.find(list_type_code) != typecode2listtype.end() ) { - return typecode2listtype[list_type_code].first; - } - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_struct_type = "struct list_" + list_type_code; - typecode2listtype[list_type_code] = std::make_pair(list_struct_type, list_element_type); - list_func_decls += indent + list_struct_type + " {\n"; - list_func_decls += indent + tab + "int32_t capacity;\n"; - list_func_decls += indent + tab + "int32_t current_end_point;\n"; - list_func_decls += indent + tab + list_element_type + "* data;\n"; - list_func_decls += indent + "};\n\n"; - generate_compare_list_element(list_type->m_type); - list_init(list_struct_type, list_type_code, list_element_type); - list_deepcopy(list_struct_type, list_type_code, list_element_type, list_type->m_type); - resize_if_needed(list_struct_type, list_type_code, list_element_type); - list_append(list_struct_type, list_type_code, list_element_type, list_type->m_type); - list_insert(list_struct_type, list_type_code, list_element_type, list_type->m_type); - list_find_item_position(list_struct_type, list_type_code, list_element_type, list_type->m_type); - list_remove(list_struct_type, list_type_code, list_element_type, list_type->m_type); - list_clear(list_struct_type, list_type_code, list_element_type); - return list_struct_type; - } - - std::string get_list_deepcopy_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecode2listfuncs[list_type_code]["list_deepcopy"]; - } - - std::string get_list_init_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecode2listfuncs[list_type_code]["list_init"]; - } - - std::string get_list_append_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecode2listfuncs[list_type_code]["list_append"]; - } - - std::string get_list_insert_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecode2listfuncs[list_type_code]["list_insert"]; - } - - std::string get_list_resize_func(std::string list_type_code) { - return typecode2listfuncs[list_type_code]["list_resize"]; - } - - std::string get_list_remove_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecode2listfuncs[list_type_code]["list_remove"]; - } - - std::string get_list_find_item_position_function(std::string list_type_code) { - return typecode2listfuncs[list_type_code]["list_find_item"]; - } - - std::string get_list_clear_func(ASR::List_t* list_type) { - std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); - return typecode2listfuncs[list_type_code]["list_clear"]; - } - - std::string get_generated_code() { - return generated_code; - } - - std::string get_list_func_decls() { - return list_func_decls; - } - - void generate_compare_list_element(ASR::ttype_t *t) { - std::string type_code = ASRUtils::get_type_code(t, true); - std::string list_element_type = typecode2listtype[type_code].second; - if (compare_list_eles.find(type_code) != compare_list_eles.end()) { - return; - } - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string cmp_func = global_scope->get_unique_name("compare_" + type_code); - compare_list_eles[type_code] = cmp_func; - std::string tmp_gen = ""; - if (ASR::is_a(*t)) { - std::string signature = "bool " + cmp_func + "(" + list_element_type + " a, " + list_element_type+ " b)"; - list_func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - tmp_gen += indent + signature + " {\n"; - ASR::ttype_t *tt = ASR::down_cast(t)->m_type; - generate_compare_list_element(tt); - std::string ele_func = compare_list_eles[ASRUtils::get_type_code(tt, true)]; - tmp_gen += indent + tab + "if (a.current_end_point != b.current_end_point)\n"; - tmp_gen += indent + tab + tab + "return false;\n"; - tmp_gen += indent + tab + "for (int i=0; iget_unique_name("list_init_" + list_type_code); - typecode2listfuncs[list_type_code]["list_init"] = list_init_func; - std::string signature = "void " + list_init_func + "(" + list_struct_type + "* x, int32_t capacity)"; - list_func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "x->capacity = capacity;\n"; - generated_code += indent + tab + "x->current_end_point = 0;\n"; - generated_code += indent + tab + "x->data = (" + list_element_type + "*) " + - "malloc(capacity * sizeof(" + list_element_type + "));\n"; - generated_code += indent + "}\n\n"; - } - - void list_clear(std::string list_struct_type, - std::string list_type_code, - std::string list_element_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_init_func = global_scope->get_unique_name("list_clear_" + list_type_code); - typecode2listfuncs[list_type_code]["list_clear"] = list_init_func; - std::string signature = "void " + list_init_func + "(" + list_struct_type + "* x)"; - list_func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "free(x->data);\n"; - generated_code += indent + tab + "x->capacity = 4;\n"; - generated_code += indent + tab + "x->current_end_point = 0;\n"; - generated_code += indent + tab + "x->data = (" + list_element_type + "*) " + - "malloc(x->capacity * sizeof(" + list_element_type + "));\n"; - generated_code += indent + "}\n\n"; - } - - void list_deepcopy(std::string list_struct_type, - std::string list_type_code, - std::string list_element_type, ASR::ttype_t *m_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_dc_func = global_scope->get_unique_name("list_deepcopy_" + list_type_code); - typecode2listfuncs[list_type_code]["list_deepcopy"] = list_dc_func; - std::string signature = "void " + list_dc_func + "(" - + list_struct_type + "* src, " - + list_struct_type + "* dest)"; - list_func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "dest->capacity = src->capacity;\n"; - generated_code += indent + tab + "dest->current_end_point = src->current_end_point;\n"; - generated_code += indent + tab + "dest->data = (" + list_element_type + "*) " + - "malloc(src->capacity * sizeof(" + list_element_type + "));\n"; - generated_code += indent + tab + "memcpy(dest->data, src->data, " + - "src->capacity * sizeof(" + list_element_type + "));\n"; - if (ASR::is_a(*m_type)) { - ASR::ttype_t *tt = ASR::down_cast(m_type)->m_type; - std::string deep_copy_func = typecode2listfuncs[ASRUtils::get_type_code(tt, true)]["list_deepcopy"]; - LFORTRAN_ASSERT(deep_copy_func.size() > 0); - generated_code += indent + tab + "for(int i=0; icurrent_end_point; i++)\n"; - generated_code += indent + tab + tab + deep_copy_func + "(&src->data[i], &dest->data[i]);\n"; - } - generated_code += indent + "}\n\n"; - } - - void resize_if_needed(std::string list_struct_type, - std::string list_type_code, - std::string list_element_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_resize_func = global_scope->get_unique_name("resize_if_needed_" + list_type_code); - typecode2listfuncs[list_type_code]["list_resize"] = list_resize_func; - std::string signature = "void " + list_resize_func + "(" + list_struct_type + "* x)"; - list_func_decls += indent + "inline " + signature + ";\n"; - signature = indent + signature; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "if (x->capacity == x->current_end_point) {\n"; - generated_code += indent + tab + tab + "x->capacity = 2 * x->capacity + 1;\n"; - generated_code += indent + tab + tab + "x->data = (" + list_element_type + "*) " + - "realloc(x->data, x->capacity * sizeof(" + list_element_type + "));\n"; - generated_code += indent + tab + "}\n"; - generated_code += indent + "}\n\n"; - } - - void list_append(std::string list_struct_type, - std::string list_type_code, - std::string list_element_type, ASR::ttype_t* m_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_append_func = global_scope->get_unique_name("list_append_" + list_type_code); - typecode2listfuncs[list_type_code]["list_append"] = list_append_func; - std::string signature = "void " + list_append_func + "(" - + list_struct_type + "* x, " - + list_element_type + " element)"; - list_func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - std::string list_resize_func = get_list_resize_func(list_type_code); - generated_code += indent + tab + list_resize_func + "(x);\n"; - if( ASR::is_a(*m_type) ) { - generated_code += indent + tab + "x->data[x->current_end_point] = (char*) malloc(40 * sizeof(char));\n"; - } - if (ASR::is_a(*m_type)) { - ASR::ttype_t *tt = ASR::down_cast(m_type)->m_type; - std::string deep_copy_func = typecode2listfuncs[ASRUtils::get_type_code(tt, true)]["list_deepcopy"]; - LFORTRAN_ASSERT(deep_copy_func.size() > 0); - generated_code += indent + tab + deep_copy_func + "(&element, &x->data[x->current_end_point]);\n"; - } else { - generated_code += indent + tab + deepcopy_function("x->data[x->current_end_point]", "element", m_type) + "\n"; - } - generated_code += indent + tab + "x->current_end_point += 1;\n"; - generated_code += indent + "}\n\n"; - } - - void list_insert(std::string list_struct_type, - std::string list_type_code, std::string list_element_type, - ASR::ttype_t* m_type) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_insert_func = global_scope->get_unique_name("list_insert_" + list_type_code); - typecode2listfuncs[list_type_code]["list_insert"] = list_insert_func; - std::string signature = "void " + list_insert_func + "(" - + list_struct_type + "* x, " - + "int pos, " - + list_element_type + " element)"; - list_func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - std::string list_resize_func = get_list_resize_func(list_type_code); - generated_code += indent + tab + list_resize_func + "(x);\n"; - generated_code += indent + tab + "int pos_ptr = pos;\n"; - generated_code += indent + tab + list_element_type + " tmp_ptr = x->data[pos];\n"; - generated_code += indent + tab + list_element_type + " tmp;\n"; - - generated_code += indent + tab + "while (x->current_end_point > pos_ptr) {\n"; - generated_code += indent + tab + tab + "tmp = x->data[pos_ptr + 1];\n"; - generated_code += indent + tab + tab + "x->data[pos_ptr + 1] = tmp_ptr;\n"; - generated_code += indent + tab + tab + "tmp_ptr = tmp;\n"; - generated_code += indent + tab + tab + "pos_ptr++;\n"; - generated_code += indent + tab + "}\n\n"; - - if( ASR::is_a(*m_type) ) { - generated_code += indent + tab + "x->data[pos] = (char*) malloc(40 * sizeof(char));\n"; - } - generated_code += indent + tab + deepcopy_function("x->data[pos]", "element", m_type) + "\n"; - generated_code += indent + tab + "x->current_end_point += 1;\n"; - generated_code += indent + "}\n\n"; - } - - void list_find_item_position(std::string list_struct_type, - std::string list_type_code, std::string list_element_type, - ASR::ttype_t* /*m_type*/) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_find_item_pos_func = global_scope->get_unique_name("list_find_item_" + list_type_code); - typecode2listfuncs[list_type_code]["list_find_item"] = list_find_item_pos_func; - std::string signature = "int " + list_find_item_pos_func + "(" - + list_struct_type + "* x, " - + list_element_type + " element)"; - std::string cmp_func = compare_list_eles[list_type_code]; - list_func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - generated_code += indent + tab + "int el_pos = 0;\n"; - generated_code += indent + tab + "while (x->current_end_point > el_pos) {\n"; - generated_code += indent + tab + tab + "if (" + cmp_func + "(x->data[el_pos], element)) return el_pos;\n"; - generated_code += indent + tab + tab + "el_pos++;\n"; - generated_code += indent + tab + "}\n"; - generated_code += indent + tab + "return -1;\n"; - generated_code += indent + "}\n\n"; - } - - void list_remove(std::string list_struct_type, - std::string list_type_code, std::string list_element_type, - ASR::ttype_t* /*m_type*/) { - std::string indent(indentation_level * indentation_spaces, ' '); - std::string tab(indentation_spaces, ' '); - std::string list_remove_func = global_scope->get_unique_name("list_remove_" + list_type_code); - typecode2listfuncs[list_type_code]["list_remove"] = list_remove_func; - std::string signature = "void " + list_remove_func + "(" - + list_struct_type + "* x, " - + list_element_type + " element)"; - list_func_decls += "inline " + signature + ";\n"; - generated_code += indent + signature + " {\n"; - std::string find_item_pos_func = get_list_find_item_position_function(list_type_code); - generated_code += indent + tab + "int el_pos = " + find_item_pos_func + "(x, element);\n"; - generated_code += indent + tab + "while (x->current_end_point > el_pos) {\n"; - generated_code += indent + tab + tab + "int tmp = el_pos + 1;\n"; - generated_code += indent + tab + tab + "x->data[el_pos] = x->data[tmp];\n"; - generated_code += indent + tab + tab + "el_pos = tmp;\n"; - generated_code += indent + tab + "}\n"; - - generated_code += indent + tab + "x->current_end_point -= 1;\n"; - generated_code += indent + "}\n\n"; - } - - ~CCPPList() { - typecode2listtype.clear(); - generated_code.clear(); - compare_list_eles.clear(); - } -}; template class BaseCCPPVisitor : public ASR::BaseVisitor @@ -466,7 +78,7 @@ class BaseCCPPVisitor : public ASR::BaseVisitor size_t template_number; std::string from_std_vector_helper; - std::unique_ptr list_api; + std::unique_ptr c_ds_api; std::string const_name; size_t const_list_count; @@ -479,13 +91,9 @@ class BaseCCPPVisitor : public ASR::BaseVisitor platform{platform}, gen_stdstring{gen_stdstring}, gen_stdcomplex{gen_stdcomplex}, is_c{is_c}, global_scope{nullptr}, lower_bound{default_lower_bound}, - template_number{0}, list_api{std::make_unique()}, const_name{"constname"}, + template_number{0}, c_ds_api{std::make_unique(is_c)}, + const_name{"constname"}, const_list_count{0}, is_string_concat_present{false} { - if( is_c ) { - list_api->set_deepcopy_function(&CUtils::deepcopy); - } else { - list_api->set_deepcopy_function(&CPPUtils::deepcopy); - } } void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { @@ -496,8 +104,8 @@ class BaseCCPPVisitor : public ASR::BaseVisitor std::string unit_src = ""; indentation_level = 0; indentation_spaces = 4; - list_api->set_indentation(indentation_level + 1, indentation_spaces); - list_api->set_global_scope(global_scope); + c_ds_api->set_indentation(indentation_level + 1, indentation_spaces); + c_ds_api->set_global_scope(global_scope); std::string headers = R"(#include @@ -563,14 +171,36 @@ R"(#include std::string contains; - // Generate the bodies of subroutines + // Declare the global variables that are imported from the module for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Function_t *s = ASR::down_cast(item.second); - self().visit_Function(*s); - contains += src; + if (ASR::is_a(*item.second)) { + ASR::Variable_t *v = ASR::down_cast( + item.second); + std::string decl = self().convert_variable_decl(*v); + if (v->m_value) { + self().visit_expr(*v->m_value); + decl += " = " + src; + } + decl += ";\n\n"; + contains += decl; + } + } + + // Topologically sort all module functions + // and then define them in the right order + std::vector func_order = ASRUtils::determine_function_definition_order(x.m_symtab); + + // Generate the bodies of subroutines + for (auto &item : func_order) { + ASR::symbol_t* sym = x.m_symtab->get_symbol(item); + if( !sym ) { + continue ; } + ASR::Function_t *s = ASR::down_cast(sym); + self().visit_Function(*s); + contains += src; } + src = contains; intrinsic_module = false; } @@ -597,7 +227,11 @@ R"(#include for (auto &item : x.m_symtab->get_scope()) { if (ASR::is_a(*item.second)) { ASR::Variable_t *v = ASR::down_cast(item.second); - decl += self().convert_variable_decl(*v) + ";\n"; + decl += self().convert_variable_decl(*v); + if( !ASR::is_a(*v->m_type) || + v->m_intent == ASRUtils::intent_return_var ) { + decl += ";\n"; + } } } @@ -627,7 +261,11 @@ R"(#include for (auto &item : block->m_symtab->get_scope()) { if (ASR::is_a(*item.second)) { ASR::Variable_t *v = ASR::down_cast(item.second); - decl += indent + self().convert_variable_decl(*v) + ";\n"; + decl += indent + self().convert_variable_decl(*v); + if( !ASR::is_a(*v->m_type) || + v->m_intent == ASRUtils::intent_return_var ) { + decl += ";\n"; + } } } for (size_t i=0; in_body; i++) { @@ -693,8 +331,18 @@ R"(#include sub = "void* "; } else if (ASR::is_a(*return_var->m_type)) { ASR::List_t* list_type = ASR::down_cast(return_var->m_type); - std::string list_element_type = get_c_type_from_ttype_t(list_type->m_type); - sub = list_api->get_list_type(list_type, list_element_type) + " "; + sub = c_ds_api->get_list_type(list_type) + " "; + } else if (ASR::is_a(*return_var->m_type)) { + ASR::Tuple_t* tup_type = ASR::down_cast(return_var->m_type); + sub = c_ds_api->get_tuple_type(tup_type) + " "; + } else if (ASR::is_a(*return_var->m_type)) { + ASR::Const_t* const_type = ASR::down_cast(return_var->m_type); + std::string const_type_str = CUtils::get_c_type_from_ttype_t(const_type->m_type); + sub = "const " + const_type_str + " "; + } else if (ASR::is_a(*return_var->m_type)) { + ASR::Pointer_t* ptr_type = ASR::down_cast(return_var->m_type); + std::string pointer_type_str = CUtils::get_c_type_from_ttype_t(ptr_type->m_type); + sub = pointer_type_str + "*"; } else { throw CodeGenError("Return type not supported in function '" + std::string(x.m_name) + @@ -785,7 +433,11 @@ R"(#include if (ASR::is_a(*item.second)) { ASR::Variable_t *v = ASR::down_cast(item.second); if (v->m_intent == LFortran::ASRUtils::intent_local || v->m_intent == LFortran::ASRUtils::intent_return_var) { - decl += indent + self().convert_variable_decl(*v) + ";\n"; + decl += indent + self().convert_variable_decl(*v); + if( !ASR::is_a(*v->m_type) || + v->m_intent == ASRUtils::intent_return_var ) { + decl += ";\n"; + } } } } @@ -866,17 +518,21 @@ R"(#include last_expr_precedence = 2; if( ASR::is_a(*x.m_type) ) { ASR::List_t* list_type = ASR::down_cast(x.m_type); - std::string list_element_type = get_c_type_from_ttype_t(list_type->m_type); const_name += std::to_string(const_list_count); const_list_count += 1; const_name = current_scope->get_unique_name(const_name); std::string indent(indentation_level*indentation_spaces, ' '); - current_body += indent + list_api->get_list_type(list_type, - list_element_type) + " " + const_name + " = " + src + ";\n"; + current_body += indent + c_ds_api->get_list_type(list_type) + " " + + const_name + " = " + src + ";\n"; src = const_name; } } + void visit_SizeOfType(const ASR::SizeOfType_t& x) { + std::string c_type = CUtils::get_c_type_from_ttype_t(x.m_arg); + src = "sizeof(" + c_type + ")"; + } + void visit_StringSection(const ASR::StringSection_t& x) { self().visit_expr(*x.m_arg); std::string arg, left, right, step, left_present, rig_present; @@ -914,7 +570,11 @@ R"(#include void visit_StringOrd(const ASR::StringOrd_t& x) { self().visit_expr(*x.m_arg); - src = "(int)" + src + "[0]"; + if (ASR::is_a(*x.m_arg)) { + src = "(int)" + src + "[0]"; + } else { + src = "_lfortran_str_ord_c(" + src + ")"; + } } void visit_StringRepeat(const ASR::StringRepeat_t &x) { @@ -928,10 +588,17 @@ R"(#include void visit_Assignment(const ASR::Assignment_t &x) { std::string target; ASR::ttype_t* m_target_type = ASRUtils::expr_type(x.m_target); + if( ASR::is_a(*m_target_type) ) { + src = ""; + return ; + } ASR::ttype_t* m_value_type = ASRUtils::expr_type(x.m_value); bool is_target_list = ASR::is_a(*m_target_type); bool is_value_list = ASR::is_a(*m_value_type); + bool is_target_tup = ASR::is_a(*m_target_type); + bool is_value_tup = ASR::is_a(*m_value_type); bool alloc_return_var = false; + std::string indent(indentation_level*indentation_spaces, ' '); if (ASR::is_a(*x.m_target)) { visit_Var(*ASR::down_cast(x.m_target)); target = src; @@ -954,6 +621,35 @@ R"(#include } else if (ASR::is_a(*x.m_target)) { self().visit_ListItem(*ASR::down_cast(x.m_target)); target = src; + } else if (ASR::is_a(*x.m_target)) { + self().visit_TupleItem(*ASR::down_cast(x.m_target)); + target = src; + } else if (ASR::is_a(*x.m_target)) { + ASR::TupleConstant_t *tup_c = ASR::down_cast(x.m_target); + std::string src_tmp = "", val_name = ""; + if (ASR::is_a(*x.m_value)) { + self().visit_TupleConstant(*ASR::down_cast(x.m_value)); + src_tmp += src; + val_name = const_name; + } else if (ASR::is_a(*x.m_value)) { + self().visit_FunctionCall(*ASR::down_cast(x.m_value)); + ASR::Tuple_t* t = ASR::down_cast(tup_c->m_type); + std::string tuple_type_c = c_ds_api->get_tuple_type(t); + const_name += std::to_string(const_list_count); + const_list_count += 1; + const_name = current_scope->get_unique_name(const_name); + src_tmp += indent + tuple_type_c + " " + const_name + " = " + src + ";\n"; + val_name = const_name; + } else { + visit_Var(*ASR::down_cast(x.m_value)); + val_name = src; + } + for (size_t i=0; in_elements; i++) { + visit_Var(*ASR::down_cast(tup_c->m_elements[i])); + src_tmp += indent + src + " = " + val_name + ".element_" + std::to_string(i) + ";\n"; + } + src = src_tmp; + return; } else { LFORTRAN_ASSERT(false) } @@ -964,13 +660,21 @@ R"(#include } self().visit_expr(*x.m_value); std::string value = src; - ASR::ttype_t* target_type = ASRUtils::expr_type(x.m_target); - if( ASR::is_a(*x.m_target) && - ASR::is_a(*target_type) && - ASR::is_a(*ASRUtils::get_contained_type(target_type)) ) { - value = "*" + value; + ASR::ttype_t* value_type = ASRUtils::expr_type(x.m_value); + if( ASR::is_a(*value_type) ) { + if (ASR::is_a(*x.m_value) || + ASR::is_a(*x.m_value) || + ASR::is_a(*x.m_value)) { + value = "&" + value; + } + } + if( ASR::is_a(*m_target_type) ) { + if (ASR::is_a(*x.m_target) || + ASR::is_a(*x.m_target) || + ASR::is_a(*x.m_target)) { + target = "&" + target; + } } - std::string indent(indentation_level*indentation_spaces, ' '); if( !from_std_vector_helper.empty() ) { src = from_std_vector_helper; } else { @@ -978,13 +682,24 @@ R"(#include } if( is_target_list && is_value_list ) { ASR::List_t* list_target = ASR::down_cast(ASRUtils::expr_type(x.m_target)); - std::string list_dc_func = list_api->get_list_deepcopy_func(list_target); + std::string list_dc_func = c_ds_api->get_list_deepcopy_func(list_target); if( ASR::is_a(*x.m_value) ) { src += value; src += indent + list_dc_func + "(&" + const_name + ", &" + target + ");\n\n"; + } else if (ASR::is_a(*x.m_value)) { + src += indent + list_dc_func + "(" + value + ", &" + target + ");\n\n"; } else { src += indent + list_dc_func + "(&" + value + ", &" + target + ");\n\n"; } + } else if ( is_target_tup && is_value_tup ) { + ASR::Tuple_t* tup_target = ASR::down_cast(ASRUtils::expr_type(x.m_target)); + std::string dc_func = c_ds_api->get_tuple_deepcopy_func(tup_target); + if( ASR::is_a(*x.m_value) ) { + src += value; + src += indent + dc_func + "(" + const_name + ", &" + target + ");\n"; + } else { + src += indent + dc_func + "(" + value + ", &" + target + ");\n"; + } } else { if( is_c ) { std::string alloc = ""; @@ -993,9 +708,9 @@ R"(#include alloc = indent + target + " = " + "(char *) malloc((strlen(" + value + ") + 1 ) * sizeof(char));\n"; } - src += alloc + indent + CUtils::deepcopy(target, value, m_target_type) + "\n"; + src += alloc + indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; } else { - src += indent + CPPUtils::deepcopy(target, value, m_target_type) + "\n"; + src += indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; } } from_std_vector_helper.clear(); @@ -1055,11 +770,10 @@ R"(#include const_list_count += 1; const_name = current_scope->get_unique_name(const_name); ASR::List_t* t = ASR::down_cast(x.m_type); - std::string list_element_type = get_c_type_from_ttype_t(t->m_type); - std::string list_type_c = list_api->get_list_type(t, list_element_type); + std::string list_type_c = c_ds_api->get_list_type(t); std::string src_tmp = ""; src_tmp += indent + list_type_c + " " + const_name + ";\n"; - std::string list_init_func = list_api->get_list_init_func(t); + std::string list_init_func = c_ds_api->get_list_init_func(t); src_tmp += indent + list_init_func + "(&" + const_name + ", " + std::to_string(x.n_args) + ");\n"; for( size_t i = 0; i < x.n_args; i++ ) { @@ -1067,20 +781,39 @@ R"(#include if( ASR::is_a(*t->m_type) ) { src_tmp += const_name + ".data[" + std::to_string(i) +"] = (char*) malloc(40 * sizeof(char));\n"; } - if( is_c ) { - src_tmp += indent + CUtils::deepcopy(const_name + ".data[" + std::to_string(i) +"]", src, t->m_type) + "\n"; - } else { - src_tmp += indent + CPPUtils::deepcopy(const_name + ".data[" + std::to_string(i) +"]", src, t->m_type) + "\n"; - } + src_tmp += indent + c_ds_api->get_deepcopy(t->m_type, src, + const_name + ".data[" + std::to_string(i) +"]") + "\n"; } src_tmp += indent + const_name + ".current_end_point = " + std::to_string(x.n_args) + ";\n"; src = src_tmp; } + void visit_TupleConstant(const ASR::TupleConstant_t& x) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + const_name += std::to_string(const_list_count); + const_list_count += 1; + const_name = current_scope->get_unique_name(const_name); + ASR::Tuple_t* t = ASR::down_cast(x.m_type); + std::string tuple_type_c = c_ds_api->get_tuple_type(t); + std::string src_tmp = ""; + src_tmp += indent + tuple_type_c + " " + const_name + ";\n"; + for (size_t i = 0; i < x.n_elements; i++) { + self().visit_expr(*x.m_elements[i]); + std::string ele = ".element_" + std::to_string(i); + if (ASR::is_a(*t->m_type[i])) { + src_tmp += indent + const_name + ele + " = (char*) malloc(40 * sizeof(char));\n"; + } + src_tmp += indent + c_ds_api->get_deepcopy(t->m_type[i], src, const_name + ele) + "\n"; + } + src_tmp += indent + const_name + ".length" + " = " + std::to_string(x.n_elements) + ";\n"; + src = src_tmp; + } + void visit_ListAppend(const ASR::ListAppend_t& x) { ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); ASR::List_t* t = ASR::down_cast(t_ttype); - std::string list_append_func = list_api->get_list_append_func(t); + std::string list_append_func = c_ds_api->get_list_append_func(t); self().visit_expr(*x.m_a); std::string list_var = std::move(src); self().visit_expr(*x.m_ele); @@ -1089,10 +822,27 @@ R"(#include src = indent + list_append_func + "(&" + list_var + ", " + element + ");\n"; } + void visit_ListConcat(const ASR::ListConcat_t& x) { + ASR::List_t* t = ASR::down_cast(x.m_type); + std::string list_concat_func = c_ds_api->get_list_concat_func(t); + self().visit_expr(*x.m_left); + std::string left = std::move(src); + if (!ASR::is_a(*x.m_left)) { + left = "&" + left; + } + self().visit_expr(*x.m_right); + std::string rig = std::move(src); + if (!ASR::is_a(*x.m_right)) { + rig = "&" + rig; + } + std::string indent(indentation_level * indentation_spaces, ' '); + src = list_concat_func + "(" + left + ", " + rig + ")"; + } + void visit_ListClear(const ASR::ListClear_t& x) { ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); ASR::List_t* t = ASR::down_cast(t_ttype); - std::string list_clear_func = list_api->get_list_clear_func(t); + std::string list_clear_func = c_ds_api->get_list_clear_func(t); self().visit_expr(*x.m_a); std::string list_var = std::move(src); std::string indent(indentation_level * indentation_spaces, ' '); @@ -1102,7 +852,7 @@ R"(#include void visit_ListInsert(const ASR::ListInsert_t& x) { ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); ASR::List_t* t = ASR::down_cast(t_ttype); - std::string list_insert_func = list_api->get_list_insert_func(t); + std::string list_insert_func = c_ds_api->get_list_insert_func(t); self().visit_expr(*x.m_a); std::string list_var = std::move(src); self().visit_expr(*x.m_ele); @@ -1116,7 +866,7 @@ R"(#include void visit_ListRemove(const ASR::ListRemove_t& x) { ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); ASR::List_t* t = ASR::down_cast(t_ttype); - std::string list_remove_func = list_api->get_list_remove_func(t); + std::string list_remove_func = c_ds_api->get_list_remove_func(t); self().visit_expr(*x.m_a); std::string list_var = std::move(src); self().visit_expr(*x.m_ele); @@ -1134,6 +884,15 @@ R"(#include src = src + ".current_end_point"; } + void visit_TupleLen(const ASR::TupleLen_t& x) { + if (x.m_value) { + self().visit_expr(*x.m_value); + return ; + } + self().visit_expr(*x.m_arg); + src = src + ".length"; + } + void visit_ListItem(const ASR::ListItem_t& x) { if( x.m_value ) { self().visit_expr(*x.m_value); @@ -1147,6 +906,23 @@ R"(#include src = list_var + ".data[" + pos + "]"; } + void visit_TupleItem(const ASR::TupleItem_t& x) { + if (x.m_value) { + self().visit_expr(*x.m_value); + return ; + } + self().visit_expr(*x.m_a); + std::string tup_var = std::move(src); + ASR::expr_t *pos_val = ASRUtils::expr_value(x.m_pos); + if (pos_val == nullptr) { + throw CodeGenError("Compile time constant values are supported in Tuple Item yet"); + } + self().visit_expr(*pos_val); + std::string pos = std::move(src); + // TODO: check for out of bound indices + src = tup_var + ".element_" + pos; + } + void visit_LogicalConstant(const ASR::LogicalConstant_t &x) { if (x.m_value == true) { src = "true"; @@ -1176,7 +952,8 @@ R"(#include der_expr = std::move(src); member = ASRUtils::symbol_name(x.m_m); if( ASR::is_a(*x.m_v) || - ASR::is_a(*x.m_v) ) { + ASR::is_a(*x.m_v) || + ASR::is_a(*x.m_v) ) { src = der_expr + "." + member; } else { src = der_expr + "->" + member; @@ -1462,56 +1239,6 @@ R"(#include } } - std::string get_c_type_from_ttype_t(ASR::ttype_t* t) { - int kind = ASRUtils::extract_kind_from_ttype_t(t); - std::string type_src = ""; - switch( t->type ) { - case ASR::ttypeType::Integer: { - type_src = "int" + std::to_string(kind * 8) + "_t"; - break; - } - case ASR::ttypeType::Real: { - if( kind == 4 ) { - type_src = "float"; - } else if( kind == 8 ) { - type_src = "double"; - } else { - throw CodeGenError(std::to_string(kind * 8) + "-bit floating points not yet supported."); - } - break; - } - case ASR::ttypeType::Character: { - type_src = "char*"; - break; - } - case ASR::ttypeType::Pointer: { - ASR::Pointer_t* ptr_type = ASR::down_cast(t); - type_src = get_c_type_from_ttype_t(ptr_type->m_type) + "*"; - break; - } - case ASR::ttypeType::CPtr: { - type_src = "void*"; - break; - } - case ASR::ttypeType::Struct: { - ASR::Struct_t* der_type = ASR::down_cast(t); - type_src = std::string("struct ") + ASRUtils::symbol_name(der_type->m_derived_type); - break; - } - case ASR::ttypeType::List: { - ASR::List_t* list_type = ASR::down_cast(t); - std::string list_element_type = get_c_type_from_ttype_t(list_type->m_type); - std::string list_type_c = list_api->get_list_type(list_type, list_element_type); - type_src = list_type_c; - break; - } - default: { - throw CodeGenError("Type " + ASRUtils::type_to_str_python(t) + " not supported yet."); - } - } - return type_src; - } - void visit_GetPointer(const ASR::GetPointer_t& x) { self().visit_expr(*x.m_arg); std::string arg_src = std::move(src); @@ -1529,7 +1256,7 @@ R"(#include if( ASRUtils::is_array(ASRUtils::expr_type(x.m_arg)) ) { arg_src += "->data"; } - std::string type_src = get_c_type_from_ttype_t(x.m_type); + std::string type_src = CUtils::get_c_type_from_ttype_t(x.m_type); src = "(" + type_src + ") " + arg_src; } @@ -1541,7 +1268,7 @@ R"(#include if( ASRUtils::is_array(ASRUtils::expr_type(x.m_ptr)) ) { dest_src += "->data"; } - std::string type_src = get_c_type_from_ttype_t(ASRUtils::expr_type(x.m_ptr)); + std::string type_src = CUtils::get_c_type_from_ttype_t(ASRUtils::expr_type(x.m_ptr)); std::string indent(indentation_level*indentation_spaces, ' '); src = indent + dest_src + " = (" + type_src + ") " + source_src + ";\n"; } diff --git a/src/libasr/codegen/asr_to_cpp.cpp b/src/libasr/codegen/asr_to_cpp.cpp index efd7115..ea7a005 100644 --- a/src/libasr/codegen/asr_to_cpp.cpp +++ b/src/libasr/codegen/asr_to_cpp.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include diff --git a/src/libasr/codegen/asr_to_julia.cpp b/src/libasr/codegen/asr_to_julia.cpp index d71c548..aab8b15 100644 --- a/src/libasr/codegen/asr_to_julia.cpp +++ b/src/libasr/codegen/asr_to_julia.cpp @@ -187,7 +187,7 @@ class ASRToJuliaVisitor : public ASR::BaseVisitor const std::string& right, int left_precedence, int right_precedence, - bool is_sub = false) + bool is_sub_div = false) { std::string out; if (is_right_associated_julia(left_precedence)) { @@ -202,7 +202,7 @@ class ASRToJuliaVisitor : public ASR::BaseVisitor out += op; if (is_right_associated_julia(right_precedence)) { out += "(" + right + ")"; - } else if (is_sub) { + } else if (is_sub_div) { if (right_precedence < last_expr_precedence) { out += right; } else { @@ -872,7 +872,8 @@ class ASRToJuliaVisitor : public ASR::BaseVisitor + " operator not implemented yet"); } src = format_binop( - left, op, right, left_precedence, right_precedence, x.m_op == ASR::binopType::Sub); + left, op, right, left_precedence, right_precedence, + x.m_op == ASR::binopType::Sub || x.m_op == ASR::binopType::Div); } void visit_LogicalBinOp(const ASR::LogicalBinOp_t& x) diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index 6995644..5fe41cd 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -159,7 +160,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::LLVMContext &context; std::unique_ptr module; std::unique_ptr> builder; - Platform platform; + std::string infile; Allocator &al; llvm::Value *tmp; @@ -225,16 +226,25 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor std::unique_ptr dict_api_sc; std::unique_ptr arr_descr; - uint64_t ptr_loads; + int64_t ptr_loads; bool lookup_enum_value_for_nonints; bool is_assignment_target; - ASRToLLVMVisitor(Allocator &al, llvm::LLVMContext &context, Platform platform, - diag::Diagnostics &diagnostics) : + CompilerOptions &compiler_options; + + // For handling debug information + std::unique_ptr DBuilder; + llvm::DICompileUnit *debug_CU; + llvm::DIScope *debug_current_scope; + std::map llvm_symtab_fn_discope; + llvm::DIFile *debug_Unit; + + ASRToLLVMVisitor(Allocator &al, llvm::LLVMContext &context, std::string infile, + CompilerOptions &compiler_options_, diag::Diagnostics &diagnostics) : diag{diagnostics}, context(context), builder(std::make_unique>(context)), - platform{platform}, + infile{infile}, al{al}, prototype_only(false), llvm_utils(std::make_unique(context, builder.get())), @@ -248,11 +258,13 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor LLVMArrUtils::DESCR_TYPE::_SimpleCMODescriptor)), ptr_loads(2), lookup_enum_value_for_nonints(false), - is_assignment_target(false) + is_assignment_target(false), + compiler_options(compiler_options_) { llvm_utils->tuple_api = tuple_api.get(); llvm_utils->list_api = list_api.get(); llvm_utils->dict_api = nullptr; + llvm_utils->arr_api = arr_descr.get(); } llvm::Value* CreateLoad(llvm::Value *x) { @@ -282,7 +294,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor // Note: `create_if_else` and `create_loop` are optional APIs // that do not have to be used. Many times, for more complicated // things, it might be more readable to just use the LLVM API - // without any extra layer on top. In some other cases, it might + // without any extra layer on top. In some other cases, it might // be more readable to use this abstraction. template void create_if_else(llvm::Value * cond, IF if_block, ELSE else_block) { @@ -332,6 +344,93 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor dict_api_sc->reset_iterators(); } + void get_type_debug_info(ASR::ttype_t* t, std::string &type_name, + uint32_t &type_size, uint32_t &type_encoding) { + type_size = ASRUtils::extract_kind_from_ttype_t(t)*8; + switch( t->type ) { + case ASR::ttypeType::Integer: { + type_name = "integer"; + type_encoding = llvm::dwarf::DW_ATE_signed; + break; + } + case ASR::ttypeType::Logical: { + type_name = "boolean"; + type_encoding = llvm::dwarf::DW_ATE_boolean; + break; + } + case ASR::ttypeType::Real: { + if( type_size == 32 ) { + type_name = "float"; + } else if( type_size == 64 ) { + type_name = "double"; + } + type_encoding = llvm::dwarf::DW_ATE_float; + break; + } + default : throw LCompilersException("Debug information for the type: `" + + ASRUtils::type_to_str_python(t) + "` is not yet implemented"); + } + } + + void debug_get_line_column(const uint32_t &loc_first, + uint32_t &line, uint32_t &column) { + LocationManager lm; + lm.in_filename = infile; + lm.init_simple(LFortran::read_file(infile)); + lm.pos_to_linecol(lm.output_to_input_pos(loc_first, false), line, column); + } + + template + void debug_emit_loc(const T &x) { + Location loc = x.base.base.loc; + uint32_t line, column; + if (compiler_options.emit_debug_line_column) { + debug_get_line_column(loc.first, line, column); + } else { + line = loc.first; + column = 0; + } + builder->SetCurrentDebugLocation( + llvm::DILocation::get(debug_current_scope->getContext(), + line, column, debug_current_scope)); + } + + template + void debug_emit_function(const T &x, llvm::DISubprogram *&SP) { + debug_Unit = DBuilder->createFile( + debug_CU->getFilename(), + debug_CU->getDirectory()); + llvm::DIScope *FContext = debug_Unit; + uint32_t line, column; + if (compiler_options.emit_debug_line_column) { + debug_get_line_column(x.base.base.loc.first, line, column); + } else { + line = 0; + } + std::string fn_debug_name = x.m_name; + llvm::DIBasicType *return_type_info = nullptr; + if constexpr (std::is_same_v){ + if(x.m_return_var != nullptr) { + std::string type_name; uint32_t type_size, type_encoding; + get_type_debug_info(ASRUtils::expr_type(x.m_return_var), + type_name, type_size, type_encoding); + return_type_info = DBuilder->createBasicType(type_name, + type_size, type_encoding); + } + } else if constexpr (std::is_same_v) { + return_type_info = DBuilder->createBasicType("integer", 32, + llvm::dwarf::DW_ATE_signed); + } + llvm::DISubroutineType *return_type = DBuilder->createSubroutineType( + DBuilder->getOrCreateTypeArray(return_type_info)); + SP = DBuilder->createFunction( + FContext, fn_debug_name, llvm::StringRef(), debug_Unit, + line, return_type, 0, // TODO: ScopeLine + llvm::DINode::FlagPrototyped, + llvm::DISubprogram::SPFlagDefinition); + debug_current_scope = SP; + } + inline bool verify_dimensions_t(ASR::dimension_t* m_dims, int n_dims) { if( n_dims <= 0 ) { return false; @@ -417,8 +516,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor return el_type; } - void fill_array_details(llvm::Value* arr, ASR::dimension_t* m_dims, - int n_dims) { + void fill_array_details(llvm::Value* arr, llvm::Type* llvm_data_type, + ASR::dimension_t* m_dims, int n_dims) { std::vector> llvm_dims; for( int r = 0; r < n_dims; r++ ) { ASR::dimension_t m_dim = m_dims[r]; @@ -428,7 +527,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value* end = tmp; llvm_dims.push_back(std::make_pair(start, end)); } - arr_descr->fill_array_details(arr, n_dims, llvm_dims); + arr_descr->fill_array_details(arr, llvm_data_type, n_dims, llvm_dims); } /* @@ -436,8 +535,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor (pointer to the first element, offset and descriptor of each dimension) of the array which are allocated memory in heap. */ - inline void fill_malloc_array_details(llvm::Value* arr, ASR::dimension_t* m_dims, - int n_dims) { + inline void fill_malloc_array_details(llvm::Value* arr, llvm::Type* llvm_data_type, + ASR::dimension_t* m_dims, int n_dims) { std::vector> llvm_dims; for( int r = 0; r < n_dims; r++ ) { ASR::dimension_t m_dim = m_dims[r]; @@ -447,7 +546,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value* end = tmp; llvm_dims.push_back(std::make_pair(start, end)); } - arr_descr->fill_malloc_array_details(arr, n_dims, llvm_dims, module.get()); + arr_descr->fill_malloc_array_details(arr, llvm_data_type, + n_dims, llvm_dims, module.get()); } inline llvm::Type* getIntType(int a_kind, bool get_pointer=false) { @@ -584,6 +684,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm_mem_type = character_type; break; } + case ASR::ttypeType::CPtr: { + llvm_mem_type = llvm::Type::getVoidTy(context)->getPointerTo(); + break; + } default: throw CodeGenError("Cannot identify the type of member, '" + std::string(member->m_name) + @@ -612,12 +716,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor const std::map& scope = der_type->m_symtab->get_scope(); for( auto itr = scope.begin(); itr != scope.end(); itr++ ) { ASR::Variable_t* member = (ASR::Variable_t*)(&(itr->second->base)); - llvm::Type* llvm_mem_type = getMemberType(member->m_type, member); + llvm::Type* llvm_mem_type = get_type_from_ttype_t_util(member->m_type); member_types.push_back(llvm_mem_type); name2memidx[der_type_name][std::string(member->m_name)] = member_idx; member_idx++; } - der_type_llvm = llvm::StructType::create(context, member_types, der_type_name); + der_type_llvm = llvm::StructType::create(context, + member_types, + der_type_name, + der_type->m_is_packed); name2dertype[der_type_name] = der_type_llvm; } if( is_pointer ) { @@ -642,7 +749,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Type* getUnionType(ASR::UnionType_t* union_type, bool is_pointer=false) { std::string union_type_name = std::string(union_type->m_name); llvm::StructType* union_type_llvm = nullptr; - if( name2dertype.find(der_type_name) != name2dertype.end() ) { + if( name2dertype.find(union_type_name) != name2dertype.end() ) { union_type_llvm = name2dertype[union_type_name]; } else { const std::map& scope = union_type->m_symtab->get_scope(); @@ -658,8 +765,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor type_size = max_type_size; } } - union_type_llvm = llvm::StructType::create(context, {max_sized_type}, der_type_name); - name2dertype[der_type_name] = union_type_llvm; + union_type_llvm = llvm::StructType::create(context, {max_sized_type}, union_type_name); + name2dertype[union_type_name] = union_type_llvm; } if( is_pointer ) { return union_type_llvm->getPointerTo(); @@ -1060,6 +1167,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor module = std::make_unique("LFortran", context); module->setDataLayout(""); + if (compiler_options.emit_debug_info) { + DBuilder = std::make_unique(*module); + debug_CU = DBuilder->createCompileUnit( + llvm::dwarf::DW_LANG_C, DBuilder->createFile(infile, "."), + "LPython Compiler", false, "", 0); + } // All loose statements must be converted to a function, so the items // must be empty: @@ -1159,7 +1272,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor std::uint32_t h = get_hash((ASR::asr_t*)curr_arg.m_a); LFORTRAN_ASSERT(llvm_symtab.find(h) != llvm_symtab.end()); llvm::Value* x_arr = llvm_symtab[h]; - fill_malloc_array_details(x_arr, curr_arg.m_dims, curr_arg.n_dims); + ASR::ttype_t* curr_arg_m_a_type = ASRUtils::symbol_type(curr_arg.m_a); + ASR::ttype_t* asr_data_type = ASRUtils::duplicate_type_without_dims(al, + curr_arg_m_a_type, curr_arg_m_a_type->base.loc); + llvm::Type* llvm_data_type = get_type_from_ttype_t_util(asr_data_type); + fill_malloc_array_details(x_arr, llvm_data_type, curr_arg.m_dims, curr_arg.n_dims); } if (x.m_stat) { ASR::Variable_t *asr_target = EXPR2VAR(x.m_stat); @@ -1255,13 +1372,14 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Type* const_list_type = list_api->get_list_type(llvm_el_type, type_code, type_size); llvm::Value* const_list = builder->CreateAlloca(const_list_type, nullptr, "const_list"); list_api->list_init(type_code, const_list, *module, x.n_args, x.n_args); - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 1; for( size_t i = 0; i < x.n_args; i++ ) { this->visit_expr(*x.m_args[i]); llvm::Value* item = tmp; llvm::Value* pos = llvm::ConstantInt::get(context, llvm::APInt(32, i)); - list_api->write_item(const_list, pos, item, list_type->m_type, *module); + list_api->write_item(const_list, pos, item, list_type->m_type, + false, module.get(), name2memidx); } ptr_loads = ptr_loads_copy; tmp = const_list; @@ -1283,9 +1401,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor std::string key_type_code = ASRUtils::get_type_code(x_dict->m_key_type); std::string value_type_code = ASRUtils::get_type_code(x_dict->m_value_type); llvm_utils->dict_api->dict_init(key_type_code, value_type_code, const_dict, module.get(), x.n_keys); - uint64_t ptr_loads_key = LLVM::is_llvm_struct(x_dict->m_key_type) ? 0 : 2; - uint64_t ptr_loads_value = LLVM::is_llvm_struct(x_dict->m_value_type) ? 0 : 2; - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_key = LLVM::is_llvm_struct(x_dict->m_key_type) ? 0 : 2; + int64_t ptr_loads_value = LLVM::is_llvm_struct(x_dict->m_value_type) ? 0 : 2; + int64_t ptr_loads_copy = ptr_loads; for( size_t i = 0; i < x.n_keys; i++ ) { ptr_loads = ptr_loads_key; visit_expr(*x.m_keys[i]); @@ -1294,7 +1412,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor visit_expr(*x.m_values[i]); llvm::Value* value = tmp; llvm_utils->dict_api->write_item(const_dict, key, value, module.get(), - x_dict->m_key_type, x_dict->m_value_type); + x_dict->m_key_type, x_dict->m_value_type, name2memidx); } ptr_loads = ptr_loads_copy; tmp = const_dict; @@ -1318,7 +1436,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Type* const_tuple_type = tuple_api->get_tuple_type(type_code, llvm_el_types); llvm::Value* const_tuple = builder->CreateAlloca(const_tuple_type, nullptr, "const_tuple"); std::vector init_values; - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 2; for( size_t i = 0; i < x.n_elements; i++ ) { this->visit_expr(*x.m_elements[i]); @@ -1352,7 +1470,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor void visit_ListAppend(const ASR::ListAppend_t& x) { ASR::List_t* asr_list = ASR::down_cast(ASRUtils::expr_type(x.m_a)); - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); llvm::Value* plist = tmp; @@ -1362,11 +1480,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value *item = tmp; ptr_loads = ptr_loads_copy; - list_api->append(plist, item, asr_list->m_type, *module); + list_api->append(plist, item, asr_list->m_type, module.get(), name2memidx); } void visit_UnionRef(const ASR::UnionRef_t& x) { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_v); ptr_loads = ptr_loads_copy; @@ -1380,7 +1498,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor member_type_asr = member_var->m_type; llvm::Type* member_type_llvm = getMemberType(member_type_asr, member_var)->getPointerTo(); tmp = builder->CreateBitCast(union_llvm, member_type_llvm); - if( !is_assignment_target ) { + if( is_assignment_target ) { + return ; + } + if( ptr_loads > 0 ) { tmp = LLVM::CreateLoad(*builder, tmp); } } @@ -1388,7 +1509,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor void visit_ListItem(const ASR::ListItem_t& x) { ASR::ttype_t* el_type = ASRUtils::get_contained_type( ASRUtils::expr_type(x.m_a)); - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); llvm::Value* plist = tmp; @@ -1398,15 +1519,14 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ptr_loads = ptr_loads_copy; llvm::Value *pos = tmp; - tmp = list_api->read_item(plist, pos, - (LLVM::is_llvm_struct(el_type) || - ptr_loads == 0)); + tmp = list_api->read_item(plist, pos, compiler_options.enable_bounds_checking, *module, + (LLVM::is_llvm_struct(el_type) || ptr_loads == 0)); } void visit_DictItem(const ASR::DictItem_t& x) { ASR::Dict_t* dict_type = ASR::down_cast( ASRUtils::expr_type(x.m_a)); - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); llvm::Value* pdict = tmp; @@ -1424,7 +1544,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor void visit_DictPop(const ASR::DictPop_t& x) { ASR::Dict_t* dict_type = ASR::down_cast( ASRUtils::expr_type(x.m_a)); - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); llvm::Value* pdict = tmp; @@ -1443,7 +1563,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor if (x.m_value) { this->visit_expr(*x.m_value); } else { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_arg); ptr_loads = ptr_loads_copy; @@ -1458,7 +1578,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor return ; } - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_arg); ptr_loads = ptr_loads_copy; @@ -1471,7 +1591,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor void visit_ListInsert(const ASR::ListInsert_t& x) { ASR::List_t* asr_list = ASR::down_cast( ASRUtils::expr_type(x.m_a)); - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); llvm::Value* plist = tmp; @@ -1485,13 +1605,13 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value *item = tmp; ptr_loads = ptr_loads_copy; - list_api->insert_item(plist, pos, item, asr_list->m_type, *module); + list_api->insert_item(plist, pos, item, asr_list->m_type, module.get(), name2memidx); } void visit_DictInsert(const ASR::DictInsert_t& x) { ASR::Dict_t* dict_type = ASR::down_cast( ASRUtils::expr_type(x.m_a)); - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); llvm::Value* pdict = tmp; @@ -1507,12 +1627,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor set_dict_api(dict_type); llvm_utils->dict_api->write_item(pdict, key, value, module.get(), dict_type->m_key_type, - dict_type->m_value_type); + dict_type->m_value_type, name2memidx); } void visit_ListRemove(const ASR::ListRemove_t& x) { ASR::ttype_t* asr_el_type = ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_a)); - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); llvm::Value* plist = tmp; @@ -1525,7 +1645,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } void visit_ListClear(const ASR::ListClear_t& x) { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); llvm::Value* plist = tmp; @@ -1540,7 +1660,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } void visit_TupleItem(const ASR::TupleItem_t& x) { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_a); ptr_loads = ptr_loads_copy; @@ -1561,8 +1681,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value* array = nullptr; if( ASR::is_a(*x.m_v) ) { ASR::Variable_t *v = ASRUtils::EXPR2VAR(x.m_v); - if( ASR::is_a(*v->m_type) ) { - ASR::Struct_t* der_type = ASR::down_cast(v->m_type); + if( ASR::is_a(*ASRUtils::get_contained_type(v->m_type)) ) { + ASR::Struct_t* der_type = ASR::down_cast( + ASRUtils::get_contained_type(v->m_type)); der_type_name = ASRUtils::symbol_name(ASRUtils::symbol_get_past_external(der_type->m_derived_type)); } uint32_t v_h = get_hash((ASR::asr_t*)v); @@ -1615,7 +1736,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor std::vector indices; for( size_t r = 0; r < x.n_args; r++ ) { ASR::array_index_t curr_idx = x.m_args[r]; - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 2; this->visit_expr_wrapper(curr_idx.m_right, true); ptr_loads = ptr_loads_copy; @@ -1637,6 +1758,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm_diminfo.push_back(al, dim_size); } } + LFORTRAN_ASSERT(ASRUtils::extract_n_dims_from_ttype( + ASRUtils::expr_type(x.m_v)) > 0); tmp = arr_descr->get_single_element(array, indices, x.n_args, is_data_only, llvm_diminfo.p); } @@ -1688,7 +1811,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value* array = tmp; this->visit_expr(*x.m_shape); llvm::Value* shape = tmp; - tmp = arr_descr->reshape(array, shape, module.get()); + ASR::ttype_t* x_m_array_type = ASRUtils::expr_type(x.m_array); + ASR::ttype_t* asr_data_type = ASRUtils::duplicate_type_without_dims(al, + x_m_array_type, x_m_array_type->base.loc); + ASR::ttype_t* asr_shape_type = ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_shape)); + llvm::Type* llvm_data_type = get_type_from_ttype_t_util(asr_data_type); + tmp = arr_descr->reshape(array, llvm_data_type, shape, asr_shape_type, module.get()); } void lookup_EnumValue(const ASR::EnumValue_t& x) { @@ -1772,6 +1900,14 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor LFORTRAN_ASSERT(x.n_args == 0); } + void visit_SizeOfType(const ASR::SizeOfType_t& x) { + llvm::Type* llvm_type = get_type_from_ttype_t_util(x.m_arg); + llvm::Type* llvm_type_size = get_type_from_ttype_t_util(x.m_type); + llvm::DataLayout data_layout(module.get()); + int64_t type_size = data_layout.getTypeAllocSize(llvm_type); + tmp = llvm::ConstantInt::get(llvm_type_size, llvm::APInt(64, type_size)); + } + void visit_StructInstanceMember(const ASR::StructInstanceMember_t& x) { if (x.m_value) { this->visit_expr_wrapper(x.m_value, true); @@ -1779,8 +1915,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } der_type_name = ""; ASR::ttype_t* x_m_v_type = ASRUtils::expr_type(x.m_v); - uint64_t ptr_loads_copy = ptr_loads; - ptr_loads = ptr_loads_copy - ASR::is_a(*x_m_v_type); + int64_t ptr_loads_copy = ptr_loads; + if( ASR::is_a(*x.m_v) ) { + ptr_loads = 0; + } else { + ptr_loads = 2 - ASR::is_a(*x_m_v_type); + } this->visit_expr(*x.m_v); ptr_loads = ptr_loads_copy; ASR::Variable_t* member = down_cast(symbol_get_past_external(x.m_m)); @@ -1798,10 +1938,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor std::vector idx_vec = { llvm::ConstantInt::get(context, llvm::APInt(32, 0)), llvm::ConstantInt::get(context, llvm::APInt(32, member_idx))}; - if( ASR::is_a(*x.m_v) && - is_nested_pointer(tmp) ) { - tmp = CreateLoad(tmp); - } + // if( (ASR::is_a(*x.m_v) || + // ASR::is_a(*x.m_v)) && + // is_nested_pointer(tmp) ) { + // tmp = CreateLoad(tmp); + // } llvm::Value* tmp1 = CreateGEP(tmp, idx_vec); ASR::ttype_t* member_type = member->m_type; if( ASR::is_a(*member_type) ) { @@ -2133,6 +2274,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Function::ExternalLinkage, "main", module.get()); llvm::BasicBlock *BB = llvm::BasicBlock::Create(context, ".entry", F); + if (compiler_options.emit_debug_info) { + llvm::DISubprogram *SP; + debug_emit_function(x, SP); + F->setSubprogram(SP); + } builder->SetInsertPoint(BB); declare_vars(x); for (size_t i=0; i builder->CreateRet(ret_val2); dict_api_lp->set_is_dict_present(is_dict_present_copy_lp); dict_api_sc->set_is_dict_present(is_dict_present_copy_sc); + + // Finalize the debug info. + if (compiler_options.emit_debug_info) DBuilder->finalize(); } /* @@ -2396,6 +2545,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm_type = llvm::Type::getInt32Ty(context); break ; } + case (ASR::ttypeType::Const) : { + llvm_type = get_type_from_ttype_t(ASRUtils::get_contained_type(asr_type), + m_storage, is_array_type, is_malloc_array_type, is_list, + m_dims, n_dims, a_kind); + break; + } default : throw CodeGenError("Support for type " + ASRUtils::type_to_str(asr_type) + " not yet implemented."); @@ -2414,9 +2569,58 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor m_dims_local, n_dims_local, a_kind_local); } + void fill_array_details_(llvm::Value* ptr, ASR::dimension_t* m_dims, + size_t n_dims, bool is_malloc_array_type, bool is_array_type, + bool is_list, ASR::ttype_t* m_type) { + if( is_malloc_array_type && + m_type->type != ASR::ttypeType::Pointer && + !is_list ) { + arr_descr->fill_dimension_descriptor(ptr, n_dims); + } + if( is_array_type && !is_malloc_array_type && + m_type->type != ASR::ttypeType::Pointer && + !is_list ) { + ASR::ttype_t* asr_data_type = ASRUtils::duplicate_type_without_dims(al, m_type, m_type->base.loc); + llvm::Type* llvm_data_type = get_type_from_ttype_t_util(asr_data_type); + fill_array_details(ptr, llvm_data_type, m_dims, n_dims); + } + if( is_array_type && is_malloc_array_type && + m_type->type != ASR::ttypeType::Pointer && + !is_list ) { + // Set allocatable arrays as unallocated + arr_descr->set_is_allocated_flag(ptr, 0); + } + } + + void allocate_array_members_of_struct(llvm::Value* ptr, ASR::ttype_t* asr_type) { + LFORTRAN_ASSERT(ASR::is_a(*asr_type)); + ASR::Struct_t* struct_t = ASR::down_cast(asr_type); + ASR::StructType_t* struct_type_t = ASR::down_cast( + ASRUtils::symbol_get_past_external(struct_t->m_derived_type)); + std::string struct_type_name = struct_type_t->m_name; + for( auto item: struct_type_t->m_symtab->get_scope() ) { + if( ASR::is_a(*item.second) || + ASR::is_a(*item.second) ) { + continue ; + } + ASR::ttype_t* symbol_type = ASRUtils::symbol_type(item.second); + int idx = name2memidx[struct_type_name][item.first]; + llvm::Value* ptr_member = llvm_utils->create_gep(ptr, idx); + if( ASRUtils::is_array(symbol_type) ) { + // Assume that struct member array is not allocatable + ASR::dimension_t* m_dims = nullptr; + size_t n_dims = ASRUtils::extract_dimensions_from_ttype(symbol_type, m_dims); + fill_array_details_(ptr_member, m_dims, n_dims, false, true, false, symbol_type); + } else if( ASR::is_a(*symbol_type) ) { + allocate_array_members_of_struct(ptr_member, symbol_type); + } + } + } + template void declare_vars(const T &x) { llvm::Value *target_var; + uint32_t debug_arg_count = 0; for (auto &item : x.m_symtab->get_scope()) { if (is_a(*item.second)) { ASR::Variable_t *v = down_cast(item.second); @@ -2468,23 +2672,46 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } } llvm::AllocaInst *ptr = builder->CreateAlloca(type, nullptr, v->m_name); - llvm_symtab[h] = ptr; - if( is_malloc_array_type && - v->m_type->type != ASR::ttypeType::Pointer && - !is_list ) { - arr_descr->fill_dimension_descriptor(ptr, n_dims); + if( ASR::is_a(*v->m_type) && + !(is_array_type || is_malloc_array_type) ) { + allocate_array_members_of_struct(ptr, v->m_type); } - if( is_array_type && !is_malloc_array_type && - v->m_type->type != ASR::ttypeType::Pointer && - !is_list ) { - fill_array_details(ptr, m_dims, n_dims); + if (compiler_options.emit_debug_info) { + // Reset the debug location + builder->SetCurrentDebugLocation(nullptr); + uint32_t line, column; + if (compiler_options.emit_debug_line_column) { + debug_get_line_column(v->base.base.loc.first, line, column); + } else { + line = v->base.base.loc.first; + column = 0; + } + std::string type_name; + uint32_t type_size, type_encoding; + get_type_debug_info(v->m_type, type_name, type_size, + type_encoding); + llvm::DILocalVariable *debug_var = DBuilder->createParameterVariable( + debug_current_scope, v->m_name, ++debug_arg_count, debug_Unit, line, + DBuilder->createBasicType(type_name, type_size, type_encoding), true); + DBuilder->insertDeclare(ptr, debug_var, DBuilder->createExpression(), + llvm::DILocation::get(debug_current_scope->getContext(), + line, 0, debug_current_scope), builder->GetInsertBlock()); } - if( is_array_type && is_malloc_array_type && - v->m_type->type != ASR::ttypeType::Pointer && - !is_list ) { - // Set allocatable arrays as unallocated - arr_descr->set_is_allocated_flag(ptr, 0); + + if( ASR::is_a(*v->m_type) ) { + ASR::Struct_t* struct_t = ASR::down_cast(v->m_type); + ASR::StructType_t* struct_type = ASR::down_cast( + ASRUtils::symbol_get_past_external(struct_t->m_derived_type)); + int64_t alignment_value = -1; + if( ASRUtils::extract_value(struct_type->m_alignment, alignment_value) ) { + llvm::Align align(alignment_value); + ptr->setAlignment(align); + } } + llvm_symtab[h] = ptr; + fill_array_details_(ptr, m_dims, n_dims, + is_malloc_array_type, + is_array_type, is_list, v->m_type); if( v->m_symbolic_value != nullptr && !ASR::is_a(*v->m_type)) { target_var = ptr; @@ -2547,7 +2774,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ASR::storage_typeType m_storage, bool arg_m_value_attr, int& n_dims, int& a_kind, bool& is_array_type, - ASR::intentType arg_intent) { + ASR::intentType arg_intent, bool get_pointer=true) { llvm::Type* type = nullptr; switch (asr_type->type) { case (ASR::ttypeType::Integer) : { @@ -2563,9 +2790,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor is_array_type = true; llvm::Type* el_type = get_el_type(asr_type); if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, true); + type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); } else { - type = arr_descr->get_array_type(asr_type, el_type, true); + type = arr_descr->get_array_type(asr_type, el_type, get_pointer); } } } else { @@ -2582,10 +2809,17 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ASR::ttype_t *t2 = ASRUtils::type_get_past_pointer(asr_type); type = get_arg_type_from_ttype_t(t2, m_abi, arg_m_abi, m_storage, arg_m_value_attr, n_dims, a_kind, - is_array_type, arg_intent); + is_array_type, arg_intent, get_pointer); type = type->getPointerTo(); break; } + case (ASR::ttypeType::Const) : { + ASR::ttype_t *t2 = ASRUtils::get_contained_type(asr_type); + type = get_arg_type_from_ttype_t(t2, m_abi, arg_m_abi, + m_storage, arg_m_value_attr, n_dims, a_kind, + is_array_type, arg_intent, get_pointer); + break; + } case (ASR::ttypeType::Real) : { ASR::Real_t* v_type = down_cast(asr_type); n_dims = v_type->n_dims; @@ -2599,9 +2833,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor is_array_type = true; llvm::Type* el_type = get_el_type(asr_type); if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, true); + type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); } else { - type = arr_descr->get_array_type(asr_type, el_type, true); + type = arr_descr->get_array_type(asr_type, el_type, get_pointer); } } } else { @@ -2625,19 +2859,19 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor is_array_type = true; llvm::Type* el_type = get_el_type(asr_type); if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, true); + type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); } else { - type = arr_descr->get_array_type(asr_type, el_type, true); + type = arr_descr->get_array_type(asr_type, el_type, get_pointer); } } else { if (arg_m_abi == ASR::abiType::BindC && arg_m_value_attr) { if (a_kind == 4) { - if (platform == Platform::Windows) { + if (compiler_options.platform == Platform::Windows) { // type_fx2 is i64 llvm::Type* type_fx2 = llvm::Type::getInt64Ty(context); type = type_fx2; - } else if (platform == Platform::macOS_ARM) { + } else if (compiler_options.platform == Platform::macOS_ARM) { // type_fx2 is [2 x float] llvm::Type* type_fx2 = llvm::ArrayType::get(llvm::Type::getFloatTy(context), 2); type = type_fx2; @@ -2648,7 +2882,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } } else { LFORTRAN_ASSERT(a_kind == 8) - if (platform == Platform::Windows) { + if (compiler_options.platform == Platform::Windows) { // 128 bit aggregate type is passed by reference type = getComplexType(a_kind, true); } else { @@ -2682,13 +2916,18 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor is_array_type = true; llvm::Type* el_type = get_el_type(asr_type); if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, true); + type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); } else { - type = arr_descr->get_array_type(asr_type, el_type, true); + type = arr_descr->get_array_type(asr_type, el_type, get_pointer); } } } else { - type = llvm::Type::getInt1PtrTy(context); + if (arg_m_abi == ASR::abiType::BindC + && arg_m_value_attr) { + type = llvm::Type::getInt1Ty(context); + } else { + type = llvm::Type::getInt1PtrTy(context); + } } break; } @@ -2699,9 +2938,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor is_array_type = true; llvm::Type* el_type = get_el_type(asr_type); if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, true); + type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); } else { - type = arr_descr->get_array_type(asr_type, el_type, true); + type = arr_descr->get_array_type(asr_type, el_type, get_pointer); } } else { type = getStructType(asr_type, true); @@ -2715,9 +2954,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor is_array_type = true; llvm::Type* el_type = get_el_type(asr_type); if( m_storage == ASR::storage_typeType::Allocatable ) { - type = arr_descr->get_malloc_array_type(asr_type, el_type, true); + type = arr_descr->get_malloc_array_type(asr_type, el_type, get_pointer); } else { - type = arr_descr->get_array_type(asr_type, el_type, true); + type = arr_descr->get_array_type(asr_type, el_type, get_pointer); } } else { type = getClassType(asr_type, true); @@ -2793,12 +3032,18 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor LFORTRAN_ASSERT(is_arg_dummy(arg->m_intent)); // We pass all arguments as pointers for now, // except bind(C) value arguments that are passed by value - llvm::Type *type; + llvm::Type *type = nullptr, *type_original = nullptr; int n_dims = 0, a_kind = 4; bool is_array_type = false; - type = get_arg_type_from_ttype_t(arg->m_type, x.m_abi, - arg->m_abi, arg->m_storage, arg->m_value_attr, - n_dims, a_kind, is_array_type, arg->m_intent); + type_original = get_arg_type_from_ttype_t(arg->m_type, x.m_abi, + arg->m_abi, arg->m_storage, arg->m_value_attr, + n_dims, a_kind, is_array_type, arg->m_intent, + false); + if( is_array_type ) { + type = type_original->getPointerTo(); + } else { + type = type_original; + } if( arg->m_intent == ASRUtils::intent_out && ASR::is_a(*arg->m_type) ) { type = type->getPointerTo(); @@ -2811,7 +3056,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } if( is_array_type && arg->m_type->type != ASR::ttypeType::Pointer ) { if( x.m_abi == ASR::abiType::Source ) { - llvm::Type* orig_type = static_cast(type)->getElementType(); + llvm::Type* orig_type = type_original; type = arr_descr->get_argument_type(orig_type, m_h, arg->m_name, arr_arg_type_cache); is_array_type = false; } else if( x.m_abi == ASR::abiType::Intrinsic && @@ -3004,11 +3249,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor parent_function = nullptr; dict_api_lp->set_is_dict_present(is_dict_present_copy_lp); dict_api_sc->set_is_dict_present(is_dict_present_copy_sc); + + // Finalize the debug info. + if (compiler_options.emit_debug_info) DBuilder->finalize(); } void instantiate_function(const ASR::Function_t &x){ uint32_t h = get_hash((ASR::asr_t*)&x); llvm::Function *F = nullptr; + llvm::DISubprogram *SP; std::string sym_name = x.m_name; if (sym_name == "main") { sym_name = "_xx_lcompilers_changed_main_xx"; @@ -3028,6 +3277,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } else { fn_name = sym_name; } + } else if (x.m_deftype == ASR::deftypeType::Interface && + x.m_abi != ASR::abiType::Intrinsic) { + fn_name = sym_name; } else { fn_name = mangle_prefix + sym_name; } @@ -3035,11 +3287,21 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm_symtab_fn_names[fn_name] = h; F = llvm::Function::Create(function_type, llvm::Function::ExternalLinkage, fn_name, module.get()); + + // Add Debugging information to the LLVM function F + if (compiler_options.emit_debug_info) { + debug_emit_function(x, SP); + F->setSubprogram(SP); + } } else { uint32_t old_h = llvm_symtab_fn_names[fn_name]; F = llvm_symtab_fn[old_h]; + if (compiler_options.emit_debug_info) { + SP = (llvm::DISubprogram*) llvm_symtab_fn_discope[old_h]; + } } llvm_symtab_fn[h] = F; + if (compiler_options.emit_debug_info) llvm_symtab_fn_discope[h] = SP; // Instantiate (pre-declare) all nested interfaces for (auto &item : x.m_symtab->get_scope()) { @@ -3073,10 +3335,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor int a_kind = down_cast(return_var_type0)->m_kind; if (a_kind == 4) { if (x.m_abi == ASR::abiType::BindC) { - if (platform == Platform::Windows) { + if (compiler_options.platform == Platform::Windows) { // i64 return_type = llvm::Type::getInt64Ty(context); - } else if (platform == Platform::macOS_ARM) { + } else if (compiler_options.platform == Platform::macOS_ARM) { // {float, float} return_type = getComplexType(a_kind); } else { @@ -3089,7 +3351,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } else { LFORTRAN_ASSERT(a_kind == 8) if (x.m_abi == ASR::abiType::BindC) { - if (platform == Platform::Windows) { + if (compiler_options.platform == Platform::Windows) { // pass as subroutine return_type = getComplexType(a_kind, true); std::vector args = convert_args(x); @@ -3115,6 +3377,14 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor case (ASR::ttypeType::CPtr) : return_type = llvm::Type::getVoidTy(context)->getPointerTo(); break; + case (ASR::ttypeType::Const) : { + return_type = get_type_from_ttype_t_util(ASRUtils::get_contained_type(return_var_type0)); + break; + } + case (ASR::ttypeType::Pointer) : { + return_type = get_type_from_ttype_t_util(ASRUtils::get_contained_type(return_var_type0))->getPointerTo(); + break; + } case (ASR::ttypeType::Struct) : throw CodeGenError("Struct return type not implemented yet"); break; @@ -3163,8 +3433,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor break; } default : - LFORTRAN_ASSERT(false); - throw CodeGenError("Type not implemented"); + throw CodeGenError("Type not implemented " + std::to_string(return_var_type)); } } else { return_type = llvm::Type::getVoidTy(context); @@ -3229,10 +3498,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor parent_function = &x; parent_function_hash = h; llvm::Function* F = llvm_symtab_fn[h]; + if (compiler_options.emit_debug_info) debug_current_scope = llvm_symtab_fn_discope[h]; proc_return = llvm::BasicBlock::Create(context, "return"); llvm::BasicBlock *BB = llvm::BasicBlock::Create(context, ".entry", F); builder->SetInsertPoint(BB); + if (compiler_options.emit_debug_info) debug_emit_loc(x); declare_args(x, *F); declare_local_vars(x); } @@ -3252,7 +3523,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor if (is_a(*arg_type)) { int c_kind = ASRUtils::extract_kind_from_ttype_t(arg_type); if (c_kind == 4) { - if (platform == Platform::Windows) { + if (compiler_options.platform == Platform::Windows) { // tmp is {float, float}* // type_fx2p is i64* llvm::Type* type_fx2p = llvm::Type::getInt64PtrTy(context); @@ -3260,7 +3531,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor tmp = builder->CreateBitCast(tmp, type_fx2p); // Then convert i64* -> i64 tmp = CreateLoad(tmp); - } else if (platform == Platform::macOS_ARM) { + } else if (compiler_options.platform == Platform::macOS_ARM) { // Pass by value tmp = CreateLoad(tmp); } else { @@ -3274,7 +3545,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } } else { LFORTRAN_ASSERT(c_kind == 8) - if (platform == Platform::Windows) { + if (compiler_options.platform == Platform::Windows) { // 128 bit aggregate type is passed by reference } else { // Pass by value @@ -3297,6 +3568,14 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor if (interactive) return; + if (compiler_options.generate_object_code + && (x.m_abi == ASR::abiType::Intrinsic) + && !compiler_options.rtlib) { + // Skip intrinsic functions in generate_object_code mode + // They must be later linked + return; + } + if (!prototype_only) { define_function_entry(x); @@ -3362,14 +3641,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } void visit_CLoc(const ASR::CLoc_t& x) { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_arg); ptr_loads = ptr_loads_copy; if( is_nested_pointer(tmp) ) { tmp = CreateLoad(tmp); } - if( arr_descr->is_array(tmp) ) { + ASR::ttype_t* arg_type = ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_arg)); + if( arr_descr->is_array(arg_type) ) { tmp = CreateLoad(arr_descr->get_pointer_to_data(tmp)); } tmp = builder->CreateBitCast(tmp, @@ -3377,17 +3657,19 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } - llvm::Value* GetPointerCPtrUtil(llvm::Value* llvm_tmp) { + llvm::Value* GetPointerCPtrUtil(llvm::Value* llvm_tmp, ASR::ttype_t* asr_type) { // If the input is a simple variable and not a pointer // then this check will fail and load will not happen // (which is what we want for simple variables). // For pointers, the actual LLVM variable will be a // double pointer, so we need to load one time and then // use it later on. - if( is_nested_pointer(llvm_tmp) ) { + if( is_nested_pointer(llvm_tmp) && + !ASR::is_a(*asr_type)) { llvm_tmp = CreateLoad(llvm_tmp); } - if( arr_descr->is_array(llvm_tmp) ) { + if( arr_descr->is_array(asr_type) && + !ASR::is_a(*asr_type) ) { llvm_tmp = CreateLoad(arr_descr->get_pointer_to_data(llvm_tmp)); } @@ -3408,20 +3690,23 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } void visit_GetPointer(const ASR::GetPointer_t& x) { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_arg); ptr_loads = ptr_loads_copy; - tmp = GetPointerCPtrUtil(tmp); + ASR::ttype_t* arg_type = ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_arg)); + tmp = GetPointerCPtrUtil(tmp, arg_type); } void visit_PointerToCPtr(const ASR::PointerToCPtr_t& x) { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_arg); ptr_loads = ptr_loads_copy; if( !ASR::is_a(*x.m_arg) ) { - tmp = GetPointerCPtrUtil(tmp); + ASR::ttype_t* arg_type = ASRUtils::get_contained_type( + ASRUtils::expr_type(x.m_arg)); + tmp = GetPointerCPtrUtil(tmp, arg_type); } tmp = builder->CreateBitCast(tmp, llvm::Type::getVoidTy(context)->getPointerTo()); @@ -3436,7 +3721,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor reduce_loads = cptr_var->m_intent == ASRUtils::intent_in; } if( ASRUtils::is_array(ASRUtils::expr_type(fptr)) ) { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 1 - reduce_loads; this->visit_expr(*cptr); llvm::Value* llvm_cptr = tmp; @@ -3445,13 +3730,14 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value* llvm_fptr = tmp; ptr_loads = ptr_loads_copy; llvm::Value* llvm_shape = nullptr; + ASR::ttype_t* asr_shape_type = nullptr; if( shape ) { + asr_shape_type = ASRUtils::get_contained_type(ASRUtils::expr_type(shape)); this->visit_expr(*shape); llvm_shape = tmp; } - llvm::Type* llvm_fptr_type = llvm_fptr->getType(); - llvm_fptr_type = static_cast(llvm_fptr_type)->getElementType(); - llvm_fptr_type = static_cast(llvm_fptr_type)->getElementType(); + ASR::ttype_t* fptr_type = ASRUtils::expr_type(fptr); + llvm::Type* llvm_fptr_type = get_type_from_ttype_t_util(ASRUtils::get_contained_type(fptr_type)); llvm::Value* fptr_array = builder->CreateAlloca(llvm_fptr_type); ASR::dimension_t* fptr_dims; int fptr_rank = ASRUtils::extract_dimensions_from_ttype( @@ -3463,14 +3749,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor arr_descr->set_rank(fptr_array, llvm_rank); builder->CreateStore(fptr_array, llvm_fptr); llvm_fptr = fptr_array; + ASR::ttype_t* fptr_data_type = ASRUtils::duplicate_type_without_dims(al, ASRUtils::get_contained_type(fptr_type), fptr_type->base.loc); + llvm::Type* llvm_fptr_data_type = get_type_from_ttype_t_util(fptr_data_type); llvm::Value* fptr_data = arr_descr->get_pointer_to_data(llvm_fptr); llvm::Value* fptr_des = arr_descr->get_pointer_to_dimension_descriptor_array(llvm_fptr); llvm::Value* shape_data = llvm_shape; - if( llvm_shape && arr_descr->is_array(llvm_shape) ) { + if( llvm_shape && !ASR::is_a(*shape) && arr_descr->is_array(asr_shape_type) ) { shape_data = CreateLoad(arr_descr->get_pointer_to_data(llvm_shape)); } - llvm_cptr = builder->CreateBitCast(llvm_cptr, - static_cast(fptr_data->getType())->getElementType()); + llvm_cptr = builder->CreateBitCast(llvm_cptr, llvm_fptr_data_type->getPointerTo()); builder->CreateStore(llvm_cptr, fptr_data); for( int i = 0; i < fptr_rank; i++ ) { llvm::Value* curr_dim = llvm::ConstantInt::get(context, llvm::APInt(32, i)); @@ -3484,7 +3771,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor builder->CreateStore(builder->CreateAdd(builder->CreateSub(new_ub, new_lb), i32_one), desi_size); } } else { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 1 - reduce_loads; this->visit_expr(*cptr); llvm::Value* llvm_cptr = tmp; @@ -3492,8 +3779,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor this->visit_expr(*fptr); llvm::Value* llvm_fptr = tmp; ptr_loads = ptr_loads_copy; - llvm_cptr = builder->CreateBitCast(llvm_cptr, - static_cast(llvm_fptr->getType())->getElementType()); + llvm::Type* llvm_fptr_type = get_type_from_ttype_t_util( + ASRUtils::get_contained_type(ASRUtils::expr_type(fptr))); + llvm_cptr = builder->CreateBitCast(llvm_cptr, llvm_fptr_type->getPointerTo()); builder->CreateStore(llvm_cptr, llvm_fptr); } } @@ -3507,6 +3795,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } void visit_Assignment(const ASR::Assignment_t &x) { + if (compiler_options.emit_debug_info) debug_emit_loc(x); if( x.m_overloaded ) { this->visit_stmt(*x.m_overloaded); return ; @@ -3520,8 +3809,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor bool is_value_tuple = ASR::is_a(*asr_value_type); bool is_target_dict = ASR::is_a(*asr_target_type); bool is_value_dict = ASR::is_a(*asr_value_type); + bool is_target_struct = ASR::is_a(*asr_target_type); + bool is_value_struct = ASR::is_a(*asr_value_type); if( is_target_list && is_value_list ) { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_target); llvm::Value* target_list = tmp; @@ -3532,10 +3823,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ASRUtils::expr_type(x.m_value)); std::string value_type_code = ASRUtils::get_type_code(value_asr_list->m_type); list_api->list_deepcopy(value_list, target_list, - value_asr_list, *module); + value_asr_list, module.get(), + name2memidx); return ; } else if( is_target_tuple && is_value_tuple ) { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; if( ASR::is_a(*x.m_target) && !ASR::is_a(*x.m_value) ) { ptr_loads = 0; @@ -3561,7 +3853,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value* llvm_tuple_i = builder->CreateAlloca(llvm_tuple_i_type, nullptr); ptr_loads = !LLVM::is_llvm_struct(asr_tuple_i_type); visit_expr(*asr_value_tuple->m_elements[i]); - llvm_utils->deepcopy(tmp, llvm_tuple_i, asr_tuple_i_type, *module); + llvm_utils->deepcopy(tmp, llvm_tuple_i, asr_tuple_i_type, module.get(), name2memidx); src_deepcopies.push_back(al, llvm_tuple_i); } ASR::TupleConstant_t* asr_target_tuple = ASR::down_cast(x.m_target); @@ -3585,11 +3877,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor std::string type_code = ASRUtils::get_type_code(value_tuple_type->m_type, value_tuple_type->n_type); tuple_api->tuple_deepcopy(value_tuple, target_tuple, - value_tuple_type, *module); + value_tuple_type, module.get(), + name2memidx); } return ; } else if( is_target_dict && is_value_dict ) { - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_value); llvm::Value* value_dict = tmp; @@ -3599,9 +3892,24 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ASR::Dict_t* value_dict_type = ASR::down_cast(asr_value_type); set_dict_api(value_dict_type); llvm_utils->dict_api->dict_deepcopy(value_dict, target_dict, - value_dict_type, module.get()); + value_dict_type, module.get(), name2memidx); + return ; + } else if( is_target_struct && is_value_struct ) { + int64_t ptr_loads_copy = ptr_loads; + ptr_loads = 0; + this->visit_expr(*x.m_value); + llvm::Value* value_struct = tmp; + bool is_assignment_target_copy = is_assignment_target; + is_assignment_target = true; + this->visit_expr(*x.m_target); + is_assignment_target = is_assignment_target_copy; + llvm::Value* target_struct = tmp; + ptr_loads = ptr_loads_copy; + llvm_utils->deepcopy(value_struct, target_struct, + asr_target_type, module.get(), name2memidx); return ; } + if( ASR::is_a(*ASRUtils::expr_type(x.m_target)) && ASR::is_a(*x.m_value) ) { ASR::Variable_t *asr_target = EXPR2VAR(x.m_target); @@ -3650,21 +3958,25 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } } else if( ASR::is_a(*x.m_target) ) { ASR::ListItem_t* asr_target0 = ASR::down_cast(x.m_target); - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*asr_target0->m_a); ptr_loads = ptr_loads_copy; llvm::Value* list = tmp; this->visit_expr_wrapper(asr_target0->m_pos, true); llvm::Value* pos = tmp; - target = list_api->read_item(list, pos, true); + + target = list_api->read_item(list, pos, compiler_options.enable_bounds_checking, + *module, true); } } else { ASR::Variable_t *asr_target = EXPR2VAR(x.m_target); h = get_hash((ASR::asr_t*)asr_target); if (llvm_symtab.find(h) != llvm_symtab.end()) { target = llvm_symtab[h]; - if (ASR::is_a(*asr_target->m_type)) { + if (ASR::is_a(*asr_target->m_type) && + !ASR::is_a( + *ASR::down_cast(asr_target->m_type)->m_type)) { target = CreateLoad(target); } } else { @@ -3679,7 +3991,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor int idx = std::distance(nested_globals.begin(), finder); target = CreateLoad(llvm_utils->create_gep(ptr, idx)); } - if( arr_descr->is_array(target) ) { + if( arr_descr->is_array(ASRUtils::get_contained_type(asr_target_type)) ) { if( asr_target->m_type->type == ASR::ttypeType::Character ) { target = CreateLoad(arr_descr->get_pointer_to_data(target)); @@ -3689,7 +4001,13 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor if( ASR::is_a(*x.m_value) ) { return ; } + ASR::ttype_t* target_type = ASRUtils::expr_type(x.m_target); + ASR::ttype_t* value_type = ASRUtils::expr_type(x.m_value); this->visit_expr_wrapper(x.m_value, true); + if( ASR::is_a(*x.m_value) && + ASR::is_a(*value_type) ) { + tmp = LLVM::CreateLoad(*builder, tmp); + } value = tmp; if ( is_a(*expr_type(x.m_value)) ) { ASR::Character_t *t = ASR::down_cast(expr_type(x.m_value)); @@ -3699,12 +4017,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } } } - ASR::ttype_t* target_type = ASRUtils::expr_type(x.m_target); - ASR::ttype_t* value_type = ASRUtils::expr_type(x.m_value); if( ASRUtils::is_array(target_type) && ASRUtils::is_array(value_type) && ASRUtils::check_equal_type(target_type, value_type) ) { - arr_descr->copy_array(value, target); + arr_descr->copy_array(value, target, module.get(), + target_type, false, false); } else { builder->CreateStore(value, target); } @@ -4463,7 +4780,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor void visit_IntegerConstant(const ASR::IntegerConstant_t &x) { int64_t val = x.m_n; - int a_kind = ((ASR::Integer_t*)(&(x.m_type->base)))->m_kind; + int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); switch( a_kind ) { case 1: { @@ -4584,10 +4901,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor char* s = ASR::down_cast(x.m_msg)->m_s; llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("AssertionError: %s\n"); llvm::Value *fmt_ptr2 = builder->CreateGlobalStringPtr(s); - printf(context, *module, *builder, {fmt_ptr, fmt_ptr2}); + print_error(context, *module, *builder, {fmt_ptr, fmt_ptr2}); } else { llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("AssertionError\n"); - printf(context, *module, *builder, {fmt_ptr}); + print_error(context, *module, *builder, {fmt_ptr}); } int exit_code_int = 1; llvm::Value *exit_code = llvm::ConstantInt::get(context, @@ -4658,7 +4975,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor uint32_t x_h = get_hash((ASR::asr_t*)x); LFORTRAN_ASSERT(llvm_symtab.find(x_h) != llvm_symtab.end()); llvm::Value* x_v = llvm_symtab[x_h]; - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; tmp = x_v; while( ptr_loads_copy-- ) { tmp = CreateLoad(tmp); @@ -4691,7 +5008,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor return; } } - if( arr_descr->is_array(x_v) ) { + if( arr_descr->is_array(ASRUtils::get_contained_type(x->m_type)) ) { tmp = x_v; } else { tmp = x_v; @@ -5204,7 +5521,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor end = builder->CreateGlobalStringPtr("\n"); } for (size_t i=0; i(*x.m_values[i]) ) { @@ -5224,7 +5541,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor lookup_enum_value_for_nonints = false; ptr_loads = ptr_loads_copy; ASR::expr_t *v = x.m_values[i]; - ASR::ttype_t *t = expr_type(v); + ASR::ttype_t *t = ASRUtils::expr_type(v); + if( ASR::is_a(*t) ) { + t = ASRUtils::get_contained_type(t); + } int a_kind = ASRUtils::extract_kind_from_ttype_t(t); if( ASR::is_a(*t) && ASR::is_a(*v) ) { if( ASRUtils::is_array(ASRUtils::type_get_past_pointer(t)) ) { @@ -5274,13 +5594,13 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor // Cast float to double as a workaround for the fact that // vprintf() seems to cast to double even for %f, which // causes it to print 0.000000. - fmt.push_back("%f"); + fmt.push_back("%13.8e"); d = builder->CreateFPExt(tmp, llvm::Type::getDoubleTy(context)); break; } case 8 : { - fmt.push_back("%23.17f"); + fmt.push_back("%23.17e"); d = builder->CreateFPExt(tmp, llvm::Type::getDoubleTy(context)); break; @@ -5359,7 +5679,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor void visit_Stop(const ASR::Stop_t &x) { llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("STOP\n"); - printf(context, *module, *builder, {fmt_ptr}); + print_error(context, *module, *builder, {fmt_ptr}); llvm::Value *exit_code; if (x.m_code && ASRUtils::expr_type(x.m_code)->type == ASR::ttypeType::Integer) { this->visit_expr(*x.m_code); @@ -5374,7 +5694,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor void visit_ErrorStop(const ASR::ErrorStop_t & /* x */) { llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("ERROR STOP\n"); - printf(context, *module, *builder, {fmt_ptr}); + print_error(context, *module, *builder, {fmt_ptr}); int exit_code_int = 1; llvm::Value *exit_code = llvm::ConstantInt::get(context, llvm::APInt(32, exit_code_int)); @@ -5387,15 +5707,21 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor std::string& orig_arg_name, ASR::intentType& arg_intent, size_t arg_idx) { m_h = get_hash((ASR::asr_t*)func_subrout); - orig_arg = EXPR2VAR(func_subrout->m_args[arg_idx]); - orig_arg_name = orig_arg->m_name; + if( ASR::is_a(*func_subrout->m_args[arg_idx]) ) { + ASR::Var_t* arg_var = ASR::down_cast(func_subrout->m_args[arg_idx]); + ASR::symbol_t* arg_sym = symbol_get_past_external(arg_var->m_v); + if( ASR::is_a(*arg_sym) ) { + orig_arg = ASR::down_cast(arg_sym); + orig_arg_name = orig_arg->m_name; + arg_intent = orig_arg->m_intent; + } + } x_abi = func_subrout->m_abi; - arg_intent = orig_arg->m_intent; } template - std::vector convert_call_args(const T &x, std::string name) { + std::vector convert_call_args(const T &x) { std::vector args; const ASR::symbol_t* func_subrout = symbol_get_past_external(x.m_name); ASR::abiType x_abi = ASR::abiType::Source; @@ -5403,188 +5729,253 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ASR::Function_t* func = down_cast(func_subrout); x_abi = func->m_abi; } - // TODO: Below if check is dead. Remove. - if( x_abi == ASR::abiType::Intrinsic ) { - if( name == "lbound" || name == "ubound" ) { - ASR::Variable_t *arg = EXPR2VAR(x.m_args[0].m_value); - uint32_t h = get_hash((ASR::asr_t*)arg); - tmp = llvm_symtab[h]; - llvm::Value* arg1 = builder->CreateAlloca(fname2arg_type[name].first, nullptr); - llvm::Value* first_ele_ptr = arr_descr->get_pointer_to_dimension_descriptor_array(tmp); - llvm::Value* first_arg_ptr = arg1; - builder->CreateStore(first_ele_ptr, first_arg_ptr); - args.push_back(arg1); - llvm::Value* arg2 = builder->CreateAlloca(getIntType(4), nullptr); - - this->visit_expr_wrapper(x.m_args[1].m_value, true); - builder->CreateStore(tmp, arg2); - args.push_back(arg2); - } - } - if( args.size() == 0 ) { - for (size_t i=0; itype == ASR::exprType::Var) { - if (is_a(*symbol_get_past_external( - ASR::down_cast(x.m_args[i].m_value)->m_v))) { - ASR::Variable_t *arg = EXPR2VAR(x.m_args[i].m_value); - uint32_t h = get_hash((ASR::asr_t*)arg); - if (llvm_symtab.find(h) != llvm_symtab.end()) { - tmp = llvm_symtab[h]; - func_subrout = symbol_get_past_external(x.m_name); - x_abi = (ASR::abiType) 0; - ASR::intentType orig_arg_intent = ASR::intentType::Unspecified; - std::uint32_t m_h; - ASR::Variable_t *orig_arg = nullptr; - std::string orig_arg_name = ""; - if( func_subrout->type == ASR::symbolType::Function ) { - ASR::Function_t* func = down_cast(func_subrout); - set_func_subrout_params(func, x_abi, m_h, orig_arg, orig_arg_name, orig_arg_intent, i); - } else if( func_subrout->type == ASR::symbolType::ClassProcedure ) { - ASR::ClassProcedure_t* clss_proc = ASR::down_cast(func_subrout); - if( clss_proc->m_proc->type == ASR::symbolType::Function ) { - ASR::Function_t* func = down_cast(clss_proc->m_proc); - set_func_subrout_params(func, x_abi, m_h, orig_arg, orig_arg_name, orig_arg_intent, i); + + for (size_t i=0; itype == ASR::symbolType::Function ) { + ASR::Function_t* func = down_cast(func_subrout); + set_func_subrout_params(func, x_abi, m_h, orig_arg, orig_arg_name, orig_arg_intent, i); + } else if( func_subrout->type == ASR::symbolType::ClassProcedure ) { + ASR::ClassProcedure_t* clss_proc = ASR::down_cast(func_subrout); + if( clss_proc->m_proc->type == ASR::symbolType::Function ) { + ASR::Function_t* func = down_cast(clss_proc->m_proc); + set_func_subrout_params(func, x_abi, m_h, orig_arg, orig_arg_name, orig_arg_intent, i); + } + } else { + LFORTRAN_ASSERT(false) + } + if (x.m_args[i].m_value->type == ASR::exprType::Var) { + if (is_a(*symbol_get_past_external( + ASR::down_cast(x.m_args[i].m_value)->m_v))) { + ASR::Variable_t *arg = EXPR2VAR(x.m_args[i].m_value); + uint32_t h = get_hash((ASR::asr_t*)arg); + if (llvm_symtab.find(h) != llvm_symtab.end()) { + tmp = llvm_symtab[h]; + bool is_data_only_array = false; + ASR::dimension_t* dims_arg = nullptr; + size_t n_arg = ASRUtils::extract_dimensions_from_ttype(arg->m_type, dims_arg); + if( ASRUtils::is_arg_dummy(arg->m_intent) && + !ASRUtils::is_dimension_empty(dims_arg, n_arg) ) { + is_data_only_array = true; + } + if( x_abi == ASR::abiType::Source && + arr_descr->is_array(arg->m_type) && + !is_data_only_array ) { + llvm::Type* new_arr_type = arr_arg_type_cache[m_h][orig_arg_name]; + ASR::dimension_t* dims; + size_t n; + n = ASRUtils::extract_dimensions_from_ttype(orig_arg->m_type, dims); + tmp = arr_descr->convert_to_argument(tmp, arg->m_type, new_arr_type, + (!ASRUtils::is_dimension_empty(dims, n))); + } else if (x_abi == ASR::abiType::Source && ASR::is_a(*arg->m_type)) { + if (arg->m_intent == intent_local) { + // Local variable of type + // CPtr is a void**, so we + // have to load it + tmp = CreateLoad(tmp); } + } else if ( x_abi == ASR::abiType::BindC ) { + if( arr_descr->is_array(ASRUtils::get_contained_type(arg->m_type)) ) { + tmp = CreateLoad(arr_descr->get_pointer_to_data(tmp)); } else { - LFORTRAN_ASSERT(false) - } - if( x_abi == ASR::abiType::Source && arr_descr->is_array(tmp) ) { - llvm::Type* new_arr_type = arr_arg_type_cache[m_h][orig_arg_name]; - ASR::dimension_t* dims; - size_t n; - n = ASRUtils::extract_dimensions_from_ttype(orig_arg->m_type, dims); - tmp = arr_descr->convert_to_argument(tmp, new_arr_type, - (!ASRUtils::is_dimension_empty(dims, n))); - } else if ( x_abi == ASR::abiType::BindC ) { - if( arr_descr->is_array(tmp) ) { - tmp = CreateLoad(arr_descr->get_pointer_to_data(tmp)); - llvm::PointerType* tmp_type = static_cast(tmp->getType()); - if( tmp_type->getElementType()->isArrayTy() ) { - tmp = llvm_utils->create_gep(tmp, 0); - } - } else { - if (orig_arg->m_abi == ASR::abiType::BindC - && orig_arg->m_value_attr) { - ASR::ttype_t* arg_type = arg->m_type; - if (is_a(*arg_type)) { - int c_kind = ASRUtils::extract_kind_from_ttype_t(arg_type); - if (c_kind == 4) { - if (platform == Platform::Windows) { - // tmp is {float, float}* - // type_fx2p is i64* - llvm::Type* type_fx2p = llvm::Type::getInt64PtrTy(context); - // Convert {float,float}* to i64* using bitcast - tmp = builder->CreateBitCast(tmp, type_fx2p); - // Then convert i64* -> i64 - tmp = CreateLoad(tmp); - } else if (platform == Platform::macOS_ARM) { - // tmp is {float, float}* - // type_fx2p is [2 x float]* - llvm::Type* type_fx2p = llvm::ArrayType::get(llvm::Type::getFloatTy(context), 2)->getPointerTo(); - // Convert {float,float}* to [2 x float]* using bitcast - tmp = builder->CreateBitCast(tmp, type_fx2p); - // Then convert [2 x float]* -> [2 x float] - tmp = CreateLoad(tmp); - } else { - // tmp is {float, float}* - // type_fx2p is <2 x float>* - llvm::Type* type_fx2p = FIXED_VECTOR_TYPE::get(llvm::Type::getFloatTy(context), 2)->getPointerTo(); - // Convert {float,float}* to <2 x float>* using bitcast - tmp = builder->CreateBitCast(tmp, type_fx2p); - // Then convert <2 x float>* -> <2 x float> - tmp = CreateLoad(tmp); - } + if (orig_arg->m_abi == ASR::abiType::BindC + && orig_arg->m_value_attr) { + ASR::ttype_t* arg_type = arg->m_type; + if (is_a(*arg_type)) { + int c_kind = ASRUtils::extract_kind_from_ttype_t(arg_type); + if (c_kind == 4) { + if (compiler_options.platform == Platform::Windows) { + // tmp is {float, float}* + // type_fx2p is i64* + llvm::Type* type_fx2p = llvm::Type::getInt64PtrTy(context); + // Convert {float,float}* to i64* using bitcast + tmp = builder->CreateBitCast(tmp, type_fx2p); + // Then convert i64* -> i64 + tmp = CreateLoad(tmp); + } else if (compiler_options.platform == Platform::macOS_ARM) { + // tmp is {float, float}* + // type_fx2p is [2 x float]* + llvm::Type* type_fx2p = llvm::ArrayType::get(llvm::Type::getFloatTy(context), 2)->getPointerTo(); + // Convert {float,float}* to [2 x float]* using bitcast + tmp = builder->CreateBitCast(tmp, type_fx2p); + // Then convert [2 x float]* -> [2 x float] + tmp = CreateLoad(tmp); } else { - LFORTRAN_ASSERT(c_kind == 8) - if (platform == Platform::Windows) { - // 128 bit aggregate type is passed by reference - } else { - // Pass by value - tmp = CreateLoad(tmp); - } - } - } else if (is_a(*arg_type)) { - if (arg->m_intent == intent_local) { - // Local variable of type - // CPtr is a void**, so we - // have to load it + // tmp is {float, float}* + // type_fx2p is <2 x float>* + llvm::Type* type_fx2p = FIXED_VECTOR_TYPE::get(llvm::Type::getFloatTy(context), 2)->getPointerTo(); + // Convert {float,float}* to <2 x float>* using bitcast + tmp = builder->CreateBitCast(tmp, type_fx2p); + // Then convert <2 x float>* -> <2 x float> tmp = CreateLoad(tmp); } } else { - if (!arg->m_value_attr) { - // Dereference the pointer argument (unless it is a CPtr) - // to pass by value - // E.g.: - // i32* -> i32 - // {double,double}* -> {double,double} + LFORTRAN_ASSERT(c_kind == 8) + if (compiler_options.platform == Platform::Windows) { + // 128 bit aggregate type is passed by reference + } else { + // Pass by value tmp = CreateLoad(tmp); } } + } else if (is_a(*arg_type)) { + if (arg->m_intent == intent_local) { + // Local variable of type + // CPtr is a void**, so we + // have to load it + tmp = CreateLoad(tmp); + } + } else { + if (!arg->m_value_attr) { + // Dereference the pointer argument (unless it is a CPtr) + // to pass by value + // E.g.: + // i32* -> i32 + // {double,double}* -> {double,double} + tmp = CreateLoad(tmp); + } } - if (!orig_arg->m_value_attr && arg->m_value_attr) { - llvm::Type *target_type = tmp->getType(); - // Create alloca to get a pointer, but do it - // at the beginning of the function to avoid - // using alloca inside a loop, which would - // run out of stack - llvm::BasicBlock &entry_block = builder->GetInsertBlock()->getParent()->getEntryBlock(); - llvm::IRBuilder<> builder0(context); - builder0.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt()); - llvm::AllocaInst *target = builder0.CreateAlloca( - target_type, nullptr, "call_arg_value_ptr"); - builder->CreateStore(tmp, target); - tmp = target; } + if (!orig_arg->m_value_attr && arg->m_value_attr) { + llvm::Type *target_type = tmp->getType(); + // Create alloca to get a pointer, but do it + // at the beginning of the function to avoid + // using alloca inside a loop, which would + // run out of stack + llvm::BasicBlock &entry_block = builder->GetInsertBlock()->getParent()->getEntryBlock(); + llvm::IRBuilder<> builder0(context); + builder0.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt()); + llvm::AllocaInst *target = builder0.CreateAlloca( + target_type, nullptr, "call_arg_value_ptr"); + builder->CreateStore(tmp, target); + tmp = target; } } + } + } else { + auto finder = std::find(nested_globals.begin(), + nested_globals.end(), h); + if (finder == nested_globals.end()) { + if (arg->m_value == nullptr) { + throw CodeGenError(std::string(arg->m_name) + " isn't defined in any scope."); + } + this->visit_expr_wrapper(arg->m_value, true); + if( x_abi != ASR::abiType::BindC ) { + llvm::BasicBlock &entry_block = builder->GetInsertBlock()->getParent()->getEntryBlock(); + llvm::IRBuilder<> builder0(context); + builder0.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt()); + llvm::AllocaInst *target = builder0.CreateAlloca( + get_type_from_ttype_t_util(arg->m_type), nullptr, "call_arg_value"); + builder->CreateStore(tmp, target); + tmp = target; + } } else { - auto finder = std::find(nested_globals.begin(), - nested_globals.end(), h); - LFORTRAN_ASSERT(finder != nested_globals.end()); llvm::Value* ptr = module->getOrInsertGlobal(nested_desc_name, nested_global_struct); int idx = std::distance(nested_globals.begin(), finder); tmp = CreateLoad(llvm_utils->create_gep(ptr, idx)); } - } else if (is_a(*symbol_get_past_external( - ASR::down_cast(x.m_args[i].m_value)->m_v))) { - ASR::Function_t* fn = ASR::down_cast( - symbol_get_past_external(ASR::down_cast( - x.m_args[i].m_value)->m_v)); - uint32_t h = get_hash((ASR::asr_t*)fn); - if (fn->m_deftype == ASR::deftypeType::Implementation) { - tmp = llvm_symtab_fn[h]; - } else { - // Must be an argument/chained procedure pass - tmp = llvm_symtab_fn_arg[h]; - } } - } else { - ASR::ttype_t* arg_type = expr_type(x.m_args[i].m_value); - uint64_t ptr_loads_copy = ptr_loads; - ptr_loads = !LLVM::is_llvm_struct(arg_type); - this->visit_expr_wrapper(x.m_args[i].m_value); - llvm::Value *value=tmp; - ptr_loads = ptr_loads_copy; - llvm::Type *target_type; - bool character_bindc = false; - switch (arg_type->type) { - case (ASR::ttypeType::Integer) : { - int a_kind = down_cast(arg_type)->m_kind; - target_type = getIntType(a_kind); - break; - } - case (ASR::ttypeType::Real) : { - int a_kind = down_cast(arg_type)->m_kind; - target_type = getFPType(a_kind); - break; + } else if (is_a(*symbol_get_past_external( + ASR::down_cast(x.m_args[i].m_value)->m_v))) { + ASR::Function_t* fn = ASR::down_cast( + symbol_get_past_external(ASR::down_cast( + x.m_args[i].m_value)->m_v)); + uint32_t h = get_hash((ASR::asr_t*)fn); + if (fn->m_deftype == ASR::deftypeType::Implementation) { + tmp = llvm_symtab_fn[h]; + } else { + // Must be an argument/chained procedure pass + tmp = llvm_symtab_fn_arg[h]; + } + } + } else { + ASR::ttype_t* arg_type = expr_type(x.m_args[i].m_value); + int64_t ptr_loads_copy = ptr_loads; + ptr_loads = !LLVM::is_llvm_struct(arg_type); + this->visit_expr_wrapper(x.m_args[i].m_value); + if( x_abi == ASR::abiType::BindC ) { + if( ASR::is_a(*x.m_args[i].m_value) || + ASR::is_a(*x.m_args[i].m_value) || + (ASR::is_a(*arg_type) && + ASR::is_a(*x.m_args[i].m_value)) ) { + tmp = LLVM::CreateLoad(*builder, tmp); + } + } + llvm::Value *value = tmp; + ptr_loads = ptr_loads_copy; + llvm::Type *target_type; + bool character_bindc = false; + switch (arg_type->type) { + case (ASR::ttypeType::Integer) : { + int a_kind = down_cast(arg_type)->m_kind; + target_type = getIntType(a_kind); + break; + } + case (ASR::ttypeType::Real) : { + int a_kind = down_cast(arg_type)->m_kind; + target_type = getFPType(a_kind); + break; + } + case (ASR::ttypeType::Complex) : { + int a_kind = down_cast(arg_type)->m_kind; + target_type = getComplexType(a_kind); + break; + } + case (ASR::ttypeType::Character) : { + ASR::Variable_t *orig_arg = nullptr; + if( func_subrout->type == ASR::symbolType::Function ) { + ASR::Function_t* func = down_cast(func_subrout); + orig_arg = EXPR2VAR(func->m_args[i]); + } else { + LFORTRAN_ASSERT(false) } - case (ASR::ttypeType::Complex) : { - int a_kind = down_cast(arg_type)->m_kind; - target_type = getComplexType(a_kind); - break; + if (orig_arg->m_abi == ASR::abiType::BindC) { + character_bindc = true; } - case (ASR::ttypeType::Character) : { + + target_type = character_type; + break; + } + case (ASR::ttypeType::Logical) : + target_type = llvm::Type::getInt1Ty(context); + break; + case (ASR::ttypeType::Enum) : + target_type = llvm::Type::getInt32Ty(context); + break; + case (ASR::ttypeType::Struct) : + break; + case (ASR::ttypeType::CPtr) : + target_type = llvm::Type::getVoidTy(context)->getPointerTo(); + break; + case (ASR::ttypeType::Pointer) : { + target_type = get_type_from_ttype_t_util(ASRUtils::get_contained_type(arg_type)); + target_type = target_type->getPointerTo(); + break; + } + case (ASR::ttypeType::List) : { + target_type = get_type_from_ttype_t_util(arg_type); + break ; + } + default : + throw CodeGenError("Type " + ASRUtils::type_to_str(arg_type) + " not implemented yet."); + } + if( ASR::is_a(*x.m_args[i].m_value) ) { + target_type = llvm::Type::getInt32Ty(context); + } + switch(arg_type->type) { + case ASR::ttypeType::Struct: { + tmp = value; + break; + } + default: { + if (!character_bindc) { + bool use_value = false; ASR::Variable_t *orig_arg = nullptr; if( func_subrout->type == ASR::symbolType::Function ) { ASR::Function_t* func = down_cast(func_subrout); @@ -5592,80 +5983,41 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } else { LFORTRAN_ASSERT(false) } - if (orig_arg->m_abi == ASR::abiType::BindC) { - character_bindc = true; + if (orig_arg->m_abi == ASR::abiType::BindC + && orig_arg->m_value_attr) { + use_value = true; } - - target_type = character_type; - break; - } - case (ASR::ttypeType::Logical) : - target_type = llvm::Type::getInt1Ty(context); - break; - case (ASR::ttypeType::Enum) : - target_type = llvm::Type::getInt32Ty(context); - break; - case (ASR::ttypeType::Struct) : - break; - case (ASR::ttypeType::CPtr) : - target_type = llvm::Type::getVoidTy(context)->getPointerTo(); - break; - case (ASR::ttypeType::List) : { - target_type = get_type_from_ttype_t_util(arg_type); - break ; - } - default : - throw CodeGenError("Type " + ASRUtils::type_to_str(arg_type) + " not implemented yet."); - } - if( ASR::is_a(*x.m_args[i].m_value) ) { - target_type = llvm::Type::getInt32Ty(context); - } - switch(arg_type->type) { - case ASR::ttypeType::Struct: { - tmp = value; - break; - } - default: { - if (!character_bindc) { - bool use_value = false; - ASR::Variable_t *orig_arg = nullptr; - if( func_subrout->type == ASR::symbolType::Function ) { - ASR::Function_t* func = down_cast(func_subrout); - orig_arg = EXPR2VAR(func->m_args[i]); - } else { - LFORTRAN_ASSERT(false) - } - if (orig_arg->m_abi == ASR::abiType::BindC - && orig_arg->m_value_attr) { - use_value = true; + if (!use_value) { + // Create alloca to get a pointer, but do it + // at the beginning of the function to avoid + // using alloca inside a loop, which would + // run out of stack + if( ASR::is_a(*x.m_args[i].m_value) || + ASR::is_a(*x.m_args[i].m_value) ) { + value = CreateLoad(value); } - if (!use_value) { - // Create alloca to get a pointer, but do it - // at the beginning of the function to avoid - // using alloca inside a loop, which would - // run out of stack + if( !ASR::is_a(*arg_type) ) { llvm::BasicBlock &entry_block = builder->GetInsertBlock()->getParent()->getEntryBlock(); llvm::IRBuilder<> builder0(context); builder0.SetInsertPoint(&entry_block, entry_block.getFirstInsertionPt()); llvm::AllocaInst *target = builder0.CreateAlloca( target_type, nullptr, "call_arg_value"); - if( ASR::is_a(*x.m_args[i].m_value) ) { - value = CreateLoad(value); - } if( ASR::is_a(*arg_type) || ASR::is_a(*arg_type) ) { - llvm_utils->deepcopy(value, target, arg_type, *module); + llvm_utils->deepcopy(value, target, arg_type, module.get(), name2memidx); } else { builder->CreateStore(value, target); } tmp = target; + } else { + tmp = value; } } } } } - args.push_back(tmp); } + args.push_back(tmp); } return args; } @@ -5685,8 +6037,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value* shifted_signal = builder->CreateShl(signal, num_shifts); llvm::Value* int_var = builder->CreateBitCast(CreateLoad(variable), shifted_signal->getType()); tmp = builder->CreateXor(shifted_signal, int_var); - llvm::PointerType* variable_type = static_cast(variable->getType()); - builder->CreateStore(builder->CreateBitCast(tmp, variable_type->getElementType()), variable); + llvm::Type* variable_type = get_type_from_ttype_t_util(asr_variable->m_type); + builder->CreateStore(builder->CreateBitCast(tmp, variable_type->getPointerTo()), variable); } void generate_fma(ASR::call_arg_t* m_args) { @@ -5734,6 +6086,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } void visit_SubroutineCall(const ASR::SubroutineCall_t &x) { + if (compiler_options.emit_debug_info) debug_emit_loc(x); if( ASRUtils::is_intrinsic_optimization(x.m_name) ) { ASR::Function_t* routine = ASR::down_cast( ASRUtils::symbol_get_past_external(x.m_name)); @@ -5778,7 +6131,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value* fn = llvm_symtab_fn_arg[h]; llvm::FunctionType* fntype = llvm_symtab_fn[h]->getFunctionType(); std::string m_name = ASR::down_cast(x.m_name)->m_name; - args = convert_call_args(x, m_name); + args = convert_call_args(x); tmp = builder->CreateCall(fntype, fn, args); } else if (llvm_symtab_fn.find(h) == llvm_symtab_fn.end()) { throw CodeGenError("Subroutine code not generated for '" @@ -5786,7 +6139,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } else { llvm::Function *fn = llvm_symtab_fn[h]; std::string m_name = ASRUtils::symbol_name(x.m_name); - std::vector args2 = convert_call_args(x, m_name); + std::vector args2 = convert_call_args(x); args.insert(args.end(), args2.begin(), args2.end()); builder->CreateCall(fn, args); } @@ -5914,7 +6267,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor h = get_hash((ASR::asr_t*)s); } else { if (func_name == "len") { - args = convert_call_args(x, "len"); + args = convert_call_args(x); LFORTRAN_ASSERT(args.size() == 1) tmp = lfortran_str_len(args[0]); return; @@ -5933,7 +6286,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value* fn = llvm_symtab_fn_arg[h]; llvm::FunctionType* fntype = llvm_symtab_fn[h]->getFunctionType(); std::string m_name = std::string(((ASR::Function_t*)(&(x.m_name->base)))->m_name); - args = convert_call_args(x, m_name); + args = convert_call_args(x); tmp = builder->CreateCall(fntype, fn, args); } else if (llvm_symtab_fn.find(h) == llvm_symtab_fn.end()) { throw CodeGenError("Function code not generated for '" @@ -5941,14 +6294,14 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } else { llvm::Function *fn = llvm_symtab_fn[h]; std::string m_name = std::string(((ASR::Function_t*)(&(x.m_name->base)))->m_name); - std::vector args2 = convert_call_args(x, m_name); + std::vector args2 = convert_call_args(x); args.insert(args.end(), args2.begin(), args2.end()); ASR::ttype_t *return_var_type0 = EXPR2VAR(s->m_return_var)->m_type; if (s->m_abi == ASR::abiType::BindC) { if (is_a(*return_var_type0)) { int a_kind = down_cast(return_var_type0)->m_kind; if (a_kind == 8) { - if (platform == Platform::Windows) { + if (compiler_options.platform == Platform::Windows) { tmp = builder->CreateAlloca(complex_type_8, nullptr); args.insert(args.begin(), tmp); builder->CreateCall(fn, args); @@ -5972,7 +6325,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor if (is_a(*return_var_type0)) { int a_kind = down_cast(return_var_type0)->m_kind; if (a_kind == 4) { - if (platform == Platform::Windows) { + if (compiler_options.platform == Platform::Windows) { // tmp is i64, have to convert to {float, float} // i64 @@ -5984,7 +6337,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor tmp = builder->CreateBitCast(p_fx2, complex_type_4->getPointerTo()); // Convert {float,float}* to {float,float} tmp = CreateLoad(tmp); - } else if (platform == Platform::macOS_ARM) { + } else if (compiler_options.platform == Platform::macOS_ARM) { // pass } else { // tmp is <2 x float>, have to convert to {float, float} @@ -6013,7 +6366,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } int output_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type); int dim_kind = 4; - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 2 - // Sync: instead of 2 - , should this be ptr_loads_copy - (ASRUtils::expr_type(x.m_v)->type == ASR::ttypeType::Pointer); @@ -6045,7 +6398,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor tmp = llvm::ConstantInt::get(context, llvm::APInt(kind * 8, bound_value)); return ; } - uint64_t ptr_loads_copy = ptr_loads; + int64_t ptr_loads_copy = ptr_loads; ptr_loads = 2 - // Sync: instead of 2 - , should this be ptr_loads_copy - (ASRUtils::expr_type(x.m_v)->type == ASR::ttypeType::Pointer); @@ -6075,13 +6428,21 @@ Result> asr_to_llvm(ASR::TranslationUnit_t &asr, diag::Diagnostics &diagnostics, llvm::LLVMContext &context, Allocator &al, LCompilers::PassManager& pass_manager, - Platform platform, const std::string &run_fn) + CompilerOptions &co, const std::string &run_fn, + const std::string &infile) { - ASRToLLVMVisitor v(al, context, platform, diagnostics); +#if LLVM_VERSION_MAJOR >= 15 + context.setOpaquePointers(false); +#endif + ASRToLLVMVisitor v(al, context, infile, co, diagnostics); LCompilers::PassOptions pass_options; + pass_options.runtime_library_dir = co.runtime_library_dir; + pass_options.mod_files_dir = co.mod_files_dir; + pass_options.include_dirs = co.include_dirs; pass_options.run_fun = run_fn; pass_options.always_run = false; - pass_manager.apply_passes(al, &asr, pass_options); + pass_manager.rtlib = co.rtlib; + pass_manager.apply_passes(al, &asr, pass_options, diagnostics); // Uncomment for debugging the ASR after the transformation // std::cout << pickle(asr, true, true, true) << std::endl; diff --git a/src/libasr/codegen/asr_to_llvm.h b/src/libasr/codegen/asr_to_llvm.h index 52f370b..4e5a15f 100644 --- a/src/libasr/codegen/asr_to_llvm.h +++ b/src/libasr/codegen/asr_to_llvm.h @@ -11,8 +11,9 @@ namespace LFortran { diag::Diagnostics &diagnostics, llvm::LLVMContext &context, Allocator &al, LCompilers::PassManager& pass_manager, - Platform platform, - const std::string &run_fn); + CompilerOptions &compiler_options, + const std::string &run_fn, + const std::string &infile); } // namespace LFortran diff --git a/src/libasr/codegen/asr_to_wasm.cpp b/src/libasr/codegen/asr_to_wasm.cpp index 734f32d..3571c6b 100644 --- a/src/libasr/codegen/asr_to_wasm.cpp +++ b/src/libasr/codegen/asr_to_wasm.cpp @@ -175,7 +175,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { auto func = ASR::make_Function_t( m_al, global_scope_loc, global_scope, s2c(m_al, import_func.name), - params.data(), params.size(), nullptr, 0, nullptr, + nullptr, 0, params.data(), params.size(), nullptr, 0, nullptr, ASR::abiType::Source, ASR::accessType::Public, ASR::deftypeType::Implementation, nullptr, false, false, false, false, false, nullptr, 0, nullptr, 0, false); @@ -264,13 +264,11 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { for (auto &item : build_order) { LFORTRAN_ASSERT(x.m_global_scope->get_scope().find(item) != x.m_global_scope->get_scope().end()); - if (startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - if (ASR::is_a(*mod)) { - ASR::Module_t *m = - ASR::down_cast(mod); - declare_all_functions(*(m->m_symtab)); - } + ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); + if (ASR::is_a(*mod)) { + ASR::Module_t *m = + ASR::down_cast(mod); + declare_all_functions(*(m->m_symtab)); } } @@ -296,10 +294,8 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { for (auto &item : build_order) { LFORTRAN_ASSERT(x.m_global_scope->get_scope().find(item) != x.m_global_scope->get_scope().end()); - if (startswith(item, "lfortran_intrinsic")) { - ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); - this->visit_symbol(*mod); - } + ASR::symbol_t *mod = x.m_global_scope->get_symbol(item); + this->visit_symbol(*mod); } } @@ -356,7 +352,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { // Generate main program code auto main_func = ASR::make_Function_t( m_al, x.base.base.loc, x.m_symtab, s2c(m_al, "_lcompilers_main"), - nullptr, 0, x.m_body, x.n_body, nullptr, + nullptr, 0, nullptr, 0, x.m_body, x.n_body, nullptr, ASR::abiType::Source, ASR::accessType::Public, ASR::deftypeType::Implementation, nullptr, false, false, false, false, false, nullptr, 0, nullptr, 0, false); @@ -1429,9 +1425,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { wasm::emit_i32_sub(m_code_section, m_al); size_t jmin, jmax; - // TODO: add this flag to ASR for each array: - bool column_major = false; - if (column_major) { + if (x.m_storage_format == ASR::arraystorageType::ColMajor) { // Column-major order jmin = 0; jmax = i; @@ -2050,11 +2044,9 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { for (size_t i = 0; i < x.n_body; i++) { this->visit_stmt(*x.m_body[i]); } - if (x.n_orelse) { - wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else - for (size_t i = 0; i < x.n_orelse; i++) { - this->visit_stmt(*x.m_orelse[i]); - } + wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else + for (size_t i = 0; i < x.n_orelse; i++) { + this->visit_stmt(*x.m_orelse[i]); } nesting_level--; wasm::emit_expr_end(m_code_section, m_al); // emit if end @@ -2088,6 +2080,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { m_code_section, m_al, nesting_level - cur_loop_nesting_level); // emit_branch and label the loop + wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else wasm::emit_expr_end(m_code_section, m_al); // end if nesting_level--; @@ -2121,6 +2114,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor { } wasm::emit_i32_const(m_code_section, m_al, 1); // non-zero exit code exit(); + wasm::emit_b8(m_code_section, m_al, 0x05); // starting of else wasm::emit_expr_end(m_code_section, m_al); // emit if end } }; diff --git a/src/libasr/codegen/asr_to_x86.cpp b/src/libasr/codegen/asr_to_x86.cpp index 37cd590..336c890 100644 --- a/src/libasr/codegen/asr_to_x86.cpp +++ b/src/libasr/codegen/asr_to_x86.cpp @@ -60,28 +60,44 @@ class ASRToX86Visitor : public ASR::BaseVisitor // must be empty: LFORTRAN_ASSERT(x.n_items == 0); + emit_elf32_header(m_a); + + // Add runtime library functions + emit_print_int(m_a, "print_int"); + emit_exit(m_a, "exit", 0); + emit_exit(m_a, "exit_error_stop", 1); + + + std::vector global_func_order = ASRUtils::determine_function_definition_order(x.m_global_scope); + for (size_t i = 0; i < global_func_order.size(); i++) { + ASR::symbol_t* sym = x.m_global_scope->get_symbol(global_func_order[i]); + // Ignore external symbols because they are already defined by the loop above. + if( !sym || ASR::is_a(*sym) ) { + continue; + } + visit_symbol(*sym); + } + + // Then the main program: for (auto &item : x.m_global_scope->get_scope()) { - if (!is_a(*item.second)) { + if (ASR::is_a(*item.second)) { visit_symbol(*item.second); } } + + emit_elf32_footer(m_a); } void visit_Program(const ASR::Program_t &x) { - emit_elf32_header(m_a); - // Add runtime library functions - emit_print_int(m_a, "print_int"); - emit_exit(m_a, "exit", 0); - emit_exit(m_a, "exit_error_stop", 1); + std::vector func_order = ASRUtils::determine_function_definition_order(x.m_symtab); // Generate code for nested subroutines and functions first: - for (auto &item : x.m_symtab->get_scope()) { - if (ASR::is_a(*item.second)) { - ASR::Function_t *s = ASR::down_cast(item.second); - visit_Function(*s); - } + for (auto &item : func_order) { + ASR::symbol_t* sym = x.m_symtab->get_symbol(item); + ASR::Function_t *s = ASR::down_cast(sym); + visit_Function(*s); } // Generate code for the main program @@ -126,7 +142,6 @@ class ASRToX86Visitor : public ASR::BaseVisitor emit_data_string(m_a, s.first, s.second); } - emit_elf32_footer(m_a); } void visit_Function(const ASR::Function_t &x) { @@ -186,7 +201,7 @@ class ASRToX86Visitor : public ASR::BaseVisitor } // Leave return value in eax - { + if (x.m_return_var) { ASR::Variable_t *retv = LFortran::ASRUtils::EXPR2VAR(x.m_return_var); uint32_t h = get_hash((ASR::asr_t*)retv); @@ -204,6 +219,8 @@ class ASRToX86Visitor : public ASR::BaseVisitor m_a.asm_ret(); } + void visit_Return(const ASR::Return_t &/*x*/) { } + // Expressions leave integer values in eax void visit_IntegerConstant(const ASR::IntegerConstant_t &x) { @@ -522,7 +539,8 @@ class ASRToX86Visitor : public ASR::BaseVisitor Result asr_to_x86(ASR::TranslationUnit_t &asr, Allocator &al, - const std::string &filename, bool time_report) + const std::string &filename, bool time_report, + diag::Diagnostics &diagnostics) { int time_pass_global=0; int time_pass_do_loops=0; @@ -554,8 +572,8 @@ Result asr_to_x86(ASR::TranslationUnit_t &asr, Allocator &al, try { v.visit_asr((ASR::asr_t &)asr); } catch (const CodeGenError &e) { - Error error; - return error; + diagnostics.diagnostics.push_back(e.d); + return Error(); } auto t2 = std::chrono::high_resolution_clock::now(); time_visit_asr = std::chrono::duration_cast(t2 - t1).count(); @@ -575,6 +593,9 @@ Result asr_to_x86(ASR::TranslationUnit_t &asr, Allocator &al, time_save = std::chrono::duration_cast(t2 - t1).count(); } + //! Helpful for debugging + // std::cout << v.m_a.get_asm() << std::endl; + if (time_report) { std::cout << "Codegen Time report:" << std::endl; std::cout << "Global: " << std::setw(5) << time_pass_global << std::endl; diff --git a/src/libasr/codegen/asr_to_x86.h b/src/libasr/codegen/asr_to_x86.h index 39b2e58..b4a3bce 100644 --- a/src/libasr/codegen/asr_to_x86.h +++ b/src/libasr/codegen/asr_to_x86.h @@ -7,7 +7,8 @@ namespace LFortran { // Generates a 32-bit x86 Linux executable binary `filename` Result asr_to_x86(ASR::TranslationUnit_t &asr, Allocator &al, - const std::string &filename, bool time_report); + const std::string &filename, bool time_report, + diag::Diagnostics &diagnostics); } // namespace LFortran diff --git a/src/libasr/codegen/c_utils.h b/src/libasr/codegen/c_utils.h new file mode 100644 index 0000000..2a4b74e --- /dev/null +++ b/src/libasr/codegen/c_utils.h @@ -0,0 +1,948 @@ +#ifndef LFORTRAN_C_UTILS_H +#define LFORTRAN_C_UTILS_H + +#include +#include + +namespace LFortran { + + static inline std::string format_type_c(const std::string &dims, const std::string &type, + const std::string &name, bool use_ref, bool /*dummy*/) + { + std::string fmt; + std::string ref = ""; + if (use_ref) ref = "*"; + if( dims == "*" ) { + fmt = type + " " + dims + ref + name; + } else { + fmt = type + " " + ref + name + dims; + } + return fmt; + } + + // Local exception that is only used in this file to exit the visitor + // pattern and caught later (not propagated outside) + class CodeGenError + { + public: + diag::Diagnostic d; + public: + CodeGenError(const std::string &msg) + : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} + { } + + CodeGenError(const std::string &msg, const Location &loc) + : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen, { + diag::Label("", {loc}) + })} + { } + }; + + class Abort {}; + +namespace CUtils { + + static inline bool is_non_primitive_DT(ASR::ttype_t *t) { + return ASR::is_a(*t) || ASR::is_a(*t) || ASR::is_a(*t); + } + + class CUtilFunctions { + + private: + + SymbolTable* global_scope; + std::map util2func; + + int indentation_level, indentation_spaces; + + public: + + std::string util_func_decls; + std::string util_funcs; + + CUtilFunctions() { + util2func.clear(); + util_func_decls.clear(); + util_funcs.clear(); + } + + void set_indentation(int indendation_level_, int indendation_space_) { + indentation_level = indendation_level_; + indentation_spaces = indendation_space_; + } + + void set_global_scope(SymbolTable* global_scope_) { + global_scope = global_scope_; + } + + std::string get_generated_code() { + return util_funcs; + } + + std::string get_util_func_decls() { + return util_func_decls; + } + + void array_size() { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string array_size_func; + if( util2func.find("array_size") == util2func.end() ) { + array_size_func = global_scope->get_unique_name("array_size"); + util2func["array_size"] = array_size_func; + } else { + return ; + } + array_size_func = util2func["array_size"]; + std::string signature = "static inline int32_t " + array_size_func + "(struct dimension_descriptor dims[], size_t n)"; + util_func_decls += indent + signature + ";\n"; + std::string body = indent + signature + " {\n"; + body += indent + tab + "int32_t size = 1;\n"; + body += indent + tab + "for (size_t i = 0; i < n; i++) {\n"; + body += indent + tab + tab + "size *= dims[i].length;\n"; + body += indent + tab + "}\n"; + body += indent + tab + "return size;\n"; + body += indent + "}\n\n"; + util_funcs += body; + } + + void array_deepcopy(ASR::ttype_t* array_type_asr, std::string array_type_name, + std::string array_encoded_type_name, std::string array_type_str) { + LFORTRAN_ASSERT(!is_non_primitive_DT(array_type_asr)); + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string array_dc_func; + if( util2func.find("array_deepcopy_" + array_encoded_type_name) == util2func.end() ) { + array_dc_func = global_scope->get_unique_name("array_deepcopy_" + array_encoded_type_name); + util2func["array_deepcopy_" + array_encoded_type_name] = array_dc_func; + } else { + return ; + } + array_dc_func = util2func["array_deepcopy_" + array_encoded_type_name]; + std::string array_types_decls = ""; + std::string signature = "void " + array_dc_func + "(" + + array_type_str + " src, " + + array_type_str + " dest)"; + util_func_decls += "inline " + signature + ";\n"; + std::string body = indent + signature + " {\n"; + body += indent + tab + "int32_t src_size = " + get_array_size() + "(src->dims, src->n_dims);\n"; + body += indent + tab + "memcpy(dest->data, src->data, src_size * sizeof(" + array_type_name +"));\n"; + body += indent + tab + "memcpy(dest->dims, src->dims, 32 * sizeof(struct dimension_descriptor));\n"; + body += indent + tab + "dest->n_dims = src->n_dims;\n"; + body += indent + tab + "dest->is_allocated = src->is_allocated;\n"; + body += indent + "}\n\n"; + util_funcs += body; + } + + void array_reshape(std::string array_type, std::string shape_type, + std::string return_type, std::string element_type, + std::string array_type_code) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string array_reshape_func; + if( util2func.find("array_reshape_" + array_type_code) == util2func.end() ) { + array_reshape_func = global_scope->get_unique_name("array_reshape_" + array_type_code); + util2func["array_reshape_" + array_type_code] = array_reshape_func; + } else { + return ; + } + array_reshape_func = util2func["array_reshape_" + array_type_code]; + std::string signature = "static inline " + return_type + "* " + array_reshape_func + "(" + + array_type + " array" + ", " + shape_type + " shape)"; + util_func_decls += indent + signature + ";\n"; + std::string body = indent + signature + " {\n"; + body += indent + tab + "int32_t n = shape->dims[0].length;\n"; + body += indent + tab + return_type + "* reshaped = (" + return_type + "*) malloc(sizeof(" + return_type + "));\n"; + body += indent + tab + "int32_t array_size_ = " + get_array_size() + "(array->dims, array->n_dims);\n"; + body += indent + tab + "int32_t shape_size_ = " + get_array_size() + "(shape->dims, shape->n_dims);\n"; + body += indent + tab + "int32_t reshaped_size = 1;\n"; + body += indent + tab + "for (int32_t i = 0; i < shape_size_; i++) {\n"; + body += indent + tab + tab + "reshaped_size *= shape->data[i];\n"; + body += indent + tab + "}\n"; + body += indent + tab + "ASSERT(array_size_ == reshaped_size);\n"; + body += indent + tab + "reshaped->data = (" + element_type + "*) malloc(sizeof(" + element_type + ")*array_size_);\n"; + body += indent + tab + "reshaped->data = (" + element_type + "*) memcpy(reshaped->data, array->data, sizeof(" + element_type + ")*array_size_);\n"; + body += indent + tab + "reshaped->n_dims = shape_size_;\n"; + body += indent + tab + "for (int32_t i = 0; i < shape_size_; i++) {\n"; + body += indent + tab + tab + "reshaped->dims[i].lower_bound = 0;\n"; + body += indent + tab + tab + "reshaped->dims[i].length = shape->data[i];\n"; + body += indent + tab + "}\n"; + body += indent + tab + "return reshaped;\n"; + body += indent + "}\n\n"; + util_funcs += body; + } + + void array_constant(std::string return_type, std::string element_type, + std::string array_type_code) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string array_const_func; + if( util2func.find("array_constant_" + array_type_code) == util2func.end() ) { + array_const_func = global_scope->get_unique_name("array_constant_" + array_type_code); + util2func["array_constant_" + array_type_code] = array_const_func; + } else { + return ; + } + array_const_func = util2func["array_constant_" + array_type_code]; + std::string signature = "static inline " + return_type + "* " + array_const_func + "(int32_t n, ...)"; + util_func_decls += indent + signature + ";\n"; + std::string body = indent + signature + " {\n"; + body += indent + tab + return_type + "* const_array = (" + return_type + "*) malloc(sizeof(" + return_type + "));\n"; + body += indent + tab + "va_list ap;\n"; + body += indent + tab + "va_start(ap, n);\n"; + body += indent + tab + "const_array->data = (" + element_type + "*) malloc(sizeof(" + element_type + ")*n);\n"; + body += indent + tab + "const_array->n_dims = 1;\n"; + body += indent + tab + "const_array->dims[0].lower_bound = 0;\n"; + body += indent + tab + "const_array->dims[0].length = n;\n"; + body += indent + tab + "for (int32_t i = 0; i < n; i++) {\n"; + body += indent + tab + tab + "const_array->data[i] = va_arg(ap, " + element_type +");\n"; + body += indent + tab + "}\n"; + body += indent + tab + "va_end(ap);\n"; + body += indent + tab + "return const_array;\n"; + body += indent + "}\n\n"; + util_funcs += body; + } + + std::string get_array_size() { + array_size(); + return util2func["array_size"]; + } + + std::string get_array_reshape( + std::string array_type, std::string shape_type, + std::string return_type, std::string element_type, + std::string array_type_code) { + array_reshape(array_type, shape_type, + return_type, element_type, + array_type_code); + return util2func["array_reshape_" + array_type_code]; + } + + std::string get_array_constant(std::string return_type, + std::string element_type, std::string encoded_type) { + array_constant(return_type, element_type, encoded_type); + return util2func["array_constant_" + encoded_type]; + } + + std::string get_array_deepcopy(ASR::ttype_t* array_type_asr, + std::string array_type_name, std::string array_encoded_type_name, + std::string array_type_str) { + array_deepcopy(array_type_asr, array_type_name, + array_encoded_type_name, array_type_str); + return util2func["array_deepcopy_" + array_encoded_type_name]; + } + }; + + static inline std::string get_tuple_type_code(ASR::Tuple_t *tup) { + std::string result = "tuple_"; + for (size_t i = 0; i < tup->n_type; i++) { + result += ASRUtils::get_type_code(tup->m_type[i], true); + if (i + 1 != tup->n_type) { + result += "_"; + } + } + return result; + } + + static inline std::string get_struct_type_code(ASR::Struct_t* struct_t) { + return ASRUtils::symbol_name(struct_t->m_derived_type); + } + + static inline std::string get_c_type_from_ttype_t(ASR::ttype_t* t, + bool is_c=true) { + int kind = ASRUtils::extract_kind_from_ttype_t(t); + std::string type_src = ""; + switch( t->type ) { + case ASR::ttypeType::Integer: { + type_src = "int" + std::to_string(kind * 8) + "_t"; + break; + } + case ASR::ttypeType::Logical: { + type_src = "bool"; + break; + } + case ASR::ttypeType::Real: { + if( kind == 4 ) { + type_src = "float"; + } else if( kind == 8 ) { + type_src = "double"; + } else { + throw CodeGenError(std::to_string(kind * 8) + "-bit floating points not yet supported."); + } + break; + } + case ASR::ttypeType::Character: { + type_src = "char*"; + break; + } + case ASR::ttypeType::Pointer: { + ASR::Pointer_t* ptr_type = ASR::down_cast(t); + type_src = get_c_type_from_ttype_t(ptr_type->m_type) + "*"; + break; + } + case ASR::ttypeType::CPtr: { + type_src = "void*"; + break; + } + case ASR::ttypeType::Struct: { + ASR::Struct_t* der_type = ASR::down_cast(t); + type_src = std::string("struct ") + ASRUtils::symbol_name(der_type->m_derived_type); + break; + } + case ASR::ttypeType::List: { + ASR::List_t* list_type = ASR::down_cast(t); + std::string list_element_type = get_c_type_from_ttype_t(list_type->m_type); + std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); + type_src = "struct list_" + list_type_code; + break; + } + case ASR::ttypeType::Tuple: { + ASR::Tuple_t* tup_type = ASR::down_cast(t); + type_src = "struct " + get_tuple_type_code(tup_type); + break; + } + case ASR::ttypeType::Complex: { + if( kind == 4 ) { + if( is_c ) { + type_src = "float complex"; + } else { + type_src = "std::complex"; + } + } else if( kind == 8 ) { + if( is_c ) { + type_src = "double complex"; + } else { + type_src = "std::complex"; + } + } else { + throw CodeGenError(std::to_string(kind * 8) + "-bit floating points not yet supported."); + } + break; + } + default: { + throw CodeGenError("Type " + ASRUtils::type_to_str_python(t) + " not supported yet."); + } + } + return type_src; + } + +} // namespace CUtils + + +class CCPPDSUtils { + private: + + std::map typecodeToDStype; + std::map> typecodeToDSfuncs; + std::map compareTwoDS; + std::map eltypedims2arraytype; + CUtils::CUtilFunctions* c_utils_functions; + + int indentation_level, indentation_spaces; + + std::string generated_code; + std::string func_decls; + + SymbolTable* global_scope; + bool is_c; + + public: + + CCPPDSUtils(bool is_c): is_c{is_c} { + generated_code.clear(); + func_decls.clear(); + } + + void set_c_utils_functions(CUtils::CUtilFunctions* c_utils_functions_) { + c_utils_functions = c_utils_functions_; + } + + void set_indentation(int indendation_level_, int indendation_space_) { + indentation_level = indendation_level_; + indentation_spaces = indendation_space_; + } + + void set_global_scope(SymbolTable* global_scope_) { + global_scope = global_scope_; + } + + std::string get_deepcopy(ASR::ttype_t *t, std::string value, std::string target) { + std::string result; + switch (t->type) { + case ASR::ttypeType::List : { + ASR::List_t* list_type = ASR::down_cast(t); + std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); + std::string func = typecodeToDSfuncs[list_type_code]["list_deepcopy"]; + result = func + "(&" + value + ", &" + target + ");"; + break; + } + case ASR::ttypeType::Tuple : { + ASR::Tuple_t* tup_type = ASR::down_cast(t); + std::string tup_type_code = CUtils::get_tuple_type_code(tup_type); + std::string func = typecodeToDSfuncs[tup_type_code]["tuple_deepcopy"]; + result = func + "(" + value + ", &" + target + ");"; + break; + } + case ASR::ttypeType::Character : { + if (is_c) { + result = "strcpy(" + target + ", " + value + ");"; + } else { + result = target + " = " + value + ";"; + } + break; + } + case ASR::ttypeType::Struct: { + std::string func = get_struct_deepcopy_func(t); + result = func + "(" + value + ", " + target + ");"; + break; + } + case ASR::ttypeType::Integer: + case ASR::ttypeType::Real: + case ASR::ttypeType::Complex: + case ASR::ttypeType::Logical: { + if( !ASRUtils::is_array(t) ) { + result = target + " = " + value + ";"; + } else { + if( is_c ) { + std::string func = get_array_deepcopy_func(t); + result = func + "(" + value + ", " + target + ");"; + } else { + result = target + " = " + value + ";"; + } + } + break; + } + default: { + result = target + " = " + value + ";"; + } + } + return result; + } + + std::string get_type(ASR::ttype_t *t) { + LFORTRAN_ASSERT(CUtils::is_non_primitive_DT(t)); + if (ASR::is_a(*t)) { + ASR::List_t* list_type = ASR::down_cast(t); + return get_list_type(list_type); + } else if (ASR::is_a(*t)) { + ASR::Tuple_t* tup_type = ASR::down_cast(t); + return get_tuple_type(tup_type); + } + LFORTRAN_ASSERT(false); + } + + std::string get_array_type(std::string type_name, std::string encoded_type_name, + std::string& array_types_decls, bool make_ptr=true, + bool create_if_not_present=true) { + if( eltypedims2arraytype.find(encoded_type_name) != eltypedims2arraytype.end() ) { + if( make_ptr ) { + return eltypedims2arraytype[encoded_type_name] + "*"; + } else { + return eltypedims2arraytype[encoded_type_name]; + } + } + + LFORTRAN_ASSERT(create_if_not_present); + + std::string struct_name; + std::string new_array_type; + struct_name = "struct " + encoded_type_name; + std::string array_data = format_type_c("*", type_name, "data", false, false); + new_array_type = struct_name + "\n{\n " + array_data + + ";\n struct dimension_descriptor dims[32];\n" + + " int32_t n_dims;\n" + " bool is_allocated;\n};\n"; + if( make_ptr ) { + type_name = struct_name + "*"; + } + eltypedims2arraytype[encoded_type_name] = struct_name; + array_types_decls += "\n" + new_array_type + "\n"; + return type_name; + } + + std::string get_list_type(ASR::List_t* list_type) { + std::string list_element_type = CUtils::get_c_type_from_ttype_t(list_type->m_type); + if (CUtils::is_non_primitive_DT(list_type->m_type)) { + // Make sure the nested types work + get_type(list_type->m_type); + } + std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); + if( typecodeToDStype.find(list_type_code) != typecodeToDStype.end() ) { + return typecodeToDStype[list_type_code]; + } + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string list_struct_type = "struct list_" + list_type_code; + typecodeToDStype[list_type_code] = list_struct_type; + func_decls += indent + list_struct_type + " {\n"; + func_decls += indent + tab + "int32_t capacity;\n"; + func_decls += indent + tab + "int32_t current_end_point;\n"; + func_decls += indent + tab + list_element_type + "* data;\n"; + func_decls += indent + "};\n\n"; + generate_compare_funcs((ASR::ttype_t *)list_type); + list_init(list_struct_type, list_type_code, list_element_type); + list_deepcopy(list_struct_type, list_type_code, list_element_type, list_type->m_type); + resize_if_needed(list_struct_type, list_type_code, list_element_type); + list_append(list_struct_type, list_type_code, list_element_type, list_type->m_type); + list_insert(list_struct_type, list_type_code, list_element_type, list_type->m_type); + list_find_item_position(list_struct_type, list_type_code, list_element_type, list_type->m_type); + list_remove(list_struct_type, list_type_code, list_element_type, list_type->m_type); + list_clear(list_struct_type, list_type_code, list_element_type); + list_concat(list_struct_type, list_type_code, list_element_type, list_type->m_type); + return list_struct_type; + } + + std::string get_list_deepcopy_func(ASR::List_t* list_type) { + std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); + return typecodeToDSfuncs[list_type_code]["list_deepcopy"]; + } + + std::string get_struct_deepcopy_func(ASR::ttype_t* struct_type_asr) { + ASR::Struct_t* struct_type = ASR::down_cast(struct_type_asr); + std::string struct_type_code = CUtils::get_struct_type_code(struct_type); + if( typecodeToDSfuncs.find(struct_type_code) == typecodeToDSfuncs.end() ) { + struct_deepcopy(struct_type_asr); + } + return typecodeToDSfuncs[struct_type_code]["struct_deepcopy"]; + } + + std::string get_array_deepcopy_func(ASR::ttype_t* array_type_asr) { + LFORTRAN_ASSERT(is_c); + std::string array_type_name = CUtils::get_c_type_from_ttype_t(array_type_asr); + std::string array_encoded_type_name = ASRUtils::get_type_code(array_type_asr, true, false, false); + std::string array_types_decls = ""; + std::string array_type_str = get_array_type(array_type_name, array_encoded_type_name, + array_types_decls, true, false); + return c_utils_functions->get_array_deepcopy(array_type_asr, array_type_name, + array_encoded_type_name, array_type_str); + } + + std::string get_list_init_func(ASR::List_t* list_type) { + std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); + return typecodeToDSfuncs[list_type_code]["list_init"]; + } + + std::string get_list_append_func(ASR::List_t* list_type) { + std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); + return typecodeToDSfuncs[list_type_code]["list_append"]; + } + + std::string get_list_insert_func(ASR::List_t* list_type) { + std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); + return typecodeToDSfuncs[list_type_code]["list_insert"]; + } + + std::string get_list_resize_func(std::string list_type_code) { + return typecodeToDSfuncs[list_type_code]["list_resize"]; + } + + std::string get_list_remove_func(ASR::List_t* list_type) { + std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); + return typecodeToDSfuncs[list_type_code]["list_remove"]; + } + + std::string get_list_concat_func(ASR::List_t* list_type) { + std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); + return typecodeToDSfuncs[list_type_code]["list_concat"]; + } + + std::string get_list_find_item_position_function(std::string list_type_code) { + return typecodeToDSfuncs[list_type_code]["list_find_item"]; + } + + std::string get_list_clear_func(ASR::List_t* list_type) { + std::string list_type_code = ASRUtils::get_type_code(list_type->m_type, true); + return typecodeToDSfuncs[list_type_code]["list_clear"]; + } + + std::string get_generated_code() { + return generated_code; + } + + std::string get_func_decls() { + return func_decls; + } + + void generate_compare_funcs(ASR::ttype_t *t) { + std::string type_code = ASRUtils::get_type_code(t, true); + if (compareTwoDS.find(type_code) != compareTwoDS.end()) { + return; + } + std::string element_type = CUtils::get_c_type_from_ttype_t(t); + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string cmp_func = global_scope->get_unique_name("compare_" + type_code); + compareTwoDS[type_code] = cmp_func; + std::string tmp_gen = ""; + if (ASR::is_a(*t)) { + std::string signature = "bool " + cmp_func + "(" + element_type + " a, " + element_type + " b)"; + func_decls += indent + "inline " + signature + ";\n"; + signature = indent + signature; + tmp_gen += indent + signature + " {\n"; + ASR::ttype_t *tt = ASR::down_cast(t)->m_type; + generate_compare_funcs(tt); + std::string ele_func = compareTwoDS[ASRUtils::get_type_code(tt, true)]; + tmp_gen += indent + tab + "if (a.current_end_point != b.current_end_point)\n"; + tmp_gen += indent + tab + tab + "return false;\n"; + tmp_gen += indent + tab + "for (int i=0; i(*t)) { + ASR::Tuple_t *tt = ASR::down_cast(t); + std::string signature = "bool " + cmp_func + "(" + element_type + " a, " + element_type+ " b)"; + func_decls += indent + "inline " + signature + ";\n"; + signature = indent + signature; + tmp_gen += indent + signature + " {\n"; + tmp_gen += indent + tab + "if (a.length != b.length)\n"; + tmp_gen += indent + tab + tab + "return false;\n"; + tmp_gen += indent + tab + "bool ans = true;\n"; + for (size_t i=0; in_type; i++) { + generate_compare_funcs(tt->m_type[i]); + std::string ele_func = compareTwoDS[ASRUtils::get_type_code(tt->m_type[i], true)]; + std::string num = std::to_string(i); + tmp_gen += indent + tab + "ans &= " + ele_func + "(a.element_" + + num + ", " + "b.element_" + num + ");\n"; + } + tmp_gen += indent + tab + "return ans;\n"; + } else if (ASR::is_a(*t)) { + std::string signature = "bool " + cmp_func + "(" + element_type + " a, " + element_type + " b)"; + func_decls += indent + "inline " + signature + ";\n"; + signature = indent + signature; + tmp_gen += indent + signature + " {\n"; + tmp_gen += indent + tab + "return strcmp(a, b) == 0;\n"; + } else { + std::string signature = "bool " + cmp_func + "(" + element_type + " a, " + element_type + " b)"; + func_decls += indent + "inline " + signature + ";\n"; + signature = indent + signature; + tmp_gen += indent + signature + " {\n"; + tmp_gen += indent + tab + "return a == b;\n"; + } + tmp_gen += indent + "}\n\n"; + generated_code += tmp_gen; + } + + void list_init(std::string list_struct_type, + std::string list_type_code, + std::string list_element_type) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string list_init_func = global_scope->get_unique_name("list_init_" + list_type_code); + typecodeToDSfuncs[list_type_code]["list_init"] = list_init_func; + std::string signature = "void " + list_init_func + "(" + list_struct_type + "* x, int32_t capacity)"; + func_decls += indent + "inline " + signature + ";\n"; + signature = indent + signature; + generated_code += indent + signature + " {\n"; + generated_code += indent + tab + "x->capacity = capacity;\n"; + generated_code += indent + tab + "x->current_end_point = 0;\n"; + generated_code += indent + tab + "x->data = (" + list_element_type + "*) " + + "malloc(capacity * sizeof(" + list_element_type + "));\n"; + generated_code += indent + "}\n\n"; + } + + void list_clear(std::string list_struct_type, + std::string list_type_code, + std::string list_element_type) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string list_init_func = global_scope->get_unique_name("list_clear_" + list_type_code); + typecodeToDSfuncs[list_type_code]["list_clear"] = list_init_func; + std::string signature = "void " + list_init_func + "(" + list_struct_type + "* x)"; + func_decls += indent + "inline " + signature + ";\n"; + signature = indent + signature; + generated_code += indent + signature + " {\n"; + generated_code += indent + tab + "free(x->data);\n"; + generated_code += indent + tab + "x->capacity = 4;\n"; + generated_code += indent + tab + "x->current_end_point = 0;\n"; + generated_code += indent + tab + "x->data = (" + list_element_type + "*) " + + "malloc(x->capacity * sizeof(" + list_element_type + "));\n"; + generated_code += indent + "}\n\n"; + } + + void struct_deepcopy(ASR::ttype_t* struct_type_asr) { + ASR::Struct_t* struct_type = ASR::down_cast(struct_type_asr); + ASR::StructType_t* struct_type_t = ASR::down_cast( + ASRUtils::symbol_get_past_external(struct_type->m_derived_type)); + std::string struct_type_code = CUtils::get_struct_type_code(struct_type); + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string struct_dc_func = global_scope->get_unique_name("struct_deepcopy_" + struct_type_code); + typecodeToDSfuncs[struct_type_code]["struct_deepcopy"] = struct_dc_func; + std::string struct_type_str = CUtils::get_c_type_from_ttype_t(struct_type_asr); + std::string signature = "void " + struct_dc_func + "(" + + struct_type_str + "* src, " + + struct_type_str + "* dest)"; + func_decls += "inline " + signature + ";\n"; + generated_code += indent + signature + " {\n"; + for( auto item: struct_type_t->m_symtab->get_scope() ) { + ASR::ttype_t* member_type_asr = ASRUtils::symbol_type(item.second); + if( CUtils::is_non_primitive_DT(member_type_asr) || + ASR::is_a(*member_type_asr) ) { + generated_code += indent + tab + get_deepcopy(member_type_asr, "&(src->" + item.first + ")", + "&(dest->" + item.first + ")") + ";\n"; + } else if( ASRUtils::is_array(member_type_asr) ) { + generated_code += indent + tab + get_deepcopy(member_type_asr, "src->" + item.first, + "dest->" + item.first) + ";\n"; + } else { + generated_code += indent + tab + "dest->" + item.first + " = " + " src->" + item.first + ";\n"; + } + } + generated_code += indent + "}\n\n"; + } + + void list_deepcopy(std::string list_struct_type, + std::string list_type_code, + std::string list_element_type, ASR::ttype_t *m_type) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string list_dc_func = global_scope->get_unique_name("list_deepcopy_" + list_type_code); + typecodeToDSfuncs[list_type_code]["list_deepcopy"] = list_dc_func; + std::string signature = "void " + list_dc_func + "(" + + list_struct_type + "* src, " + + list_struct_type + "* dest)"; + func_decls += "inline " + signature + ";\n"; + generated_code += indent + signature + " {\n"; + generated_code += indent + tab + "dest->capacity = src->capacity;\n"; + generated_code += indent + tab + "dest->current_end_point = src->current_end_point;\n"; + generated_code += indent + tab + "dest->data = (" + list_element_type + "*) " + + "malloc(src->capacity * sizeof(" + list_element_type + "));\n"; + generated_code += indent + tab + "memcpy(dest->data, src->data, " + + "src->capacity * sizeof(" + list_element_type + "));\n"; + if (ASR::is_a(*m_type)) { + ASR::ttype_t *tt = ASR::down_cast(m_type)->m_type; + std::string deep_copy_func = typecodeToDSfuncs[ASRUtils::get_type_code(tt, true)]["list_deepcopy"]; + LFORTRAN_ASSERT(deep_copy_func.size() > 0); + generated_code += indent + tab + "for(int i=0; icurrent_end_point; i++)\n"; + generated_code += indent + tab + tab + deep_copy_func + "(&src->data[i], &dest->data[i]);\n"; + } + generated_code += indent + "}\n\n"; + } + + void list_concat(std::string list_struct_type, + std::string list_type_code, + std::string list_element_type, ASR::ttype_t *m_type) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string list_con_func = global_scope->get_unique_name("list_concat_" + list_type_code); + typecodeToDSfuncs[list_type_code]["list_concat"] = list_con_func; + std::string init_func = typecodeToDSfuncs[list_type_code]["list_init"]; + std::string signature = list_struct_type + "* " + list_con_func + "(" + + list_struct_type + "* left, " + + list_struct_type + "* right)"; + func_decls += "inline " + signature + ";\n"; + generated_code += indent + signature + " {\n"; + generated_code += indent + tab + list_struct_type + " *result = (" + list_struct_type + "*)malloc(sizeof(" + + list_struct_type + "));\n"; + generated_code += indent + tab + init_func + "(result, left->current_end_point + right->current_end_point);\n"; + if (ASR::is_a(*m_type)) { + ASR::ttype_t *tt = ASR::down_cast(m_type)->m_type; + std::string deep_copy_func = typecodeToDSfuncs[ASRUtils::get_type_code(tt, true)]["list_deepcopy"]; + LFORTRAN_ASSERT(deep_copy_func.size() > 0); + generated_code += indent + tab + "for(int i=0; icurrent_end_point; i++)\n"; + generated_code += indent + tab + tab + deep_copy_func + "(&left->data[i], &result->data[i]);\n"; + generated_code += indent + tab + "for(int i=0; icurrent_end_point; i++)\n"; + generated_code += indent + tab + tab + deep_copy_func + "(&right->data[i], &result->data[i+left->current_end_point]);\n"; + } else { + generated_code += indent + tab + "memcpy(result->data, left->data, " + + "left->current_end_point * sizeof(" + list_element_type + "));\n"; + generated_code += indent + tab + "memcpy(result->data + left->current_end_point, right->data, " + + "right->current_end_point * sizeof(" + list_element_type + "));\n"; + } + generated_code += indent + tab + "result->current_end_point = left->current_end_point + right->current_end_point;\n"; + generated_code += indent + tab + "return result;\n"; + generated_code += indent + "}\n\n"; + } + + void resize_if_needed(std::string list_struct_type, + std::string list_type_code, + std::string list_element_type) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string list_resize_func = global_scope->get_unique_name("resize_if_needed_" + list_type_code); + typecodeToDSfuncs[list_type_code]["list_resize"] = list_resize_func; + std::string signature = "void " + list_resize_func + "(" + list_struct_type + "* x)"; + func_decls += indent + "inline " + signature + ";\n"; + signature = indent + signature; + generated_code += indent + signature + " {\n"; + generated_code += indent + tab + "if (x->capacity == x->current_end_point) {\n"; + generated_code += indent + tab + tab + "x->capacity = 2 * x->capacity + 1;\n"; + generated_code += indent + tab + tab + "x->data = (" + list_element_type + "*) " + + "realloc(x->data, x->capacity * sizeof(" + list_element_type + "));\n"; + generated_code += indent + tab + "}\n"; + generated_code += indent + "}\n\n"; + } + + void list_append(std::string list_struct_type, + std::string list_type_code, + std::string list_element_type, ASR::ttype_t* m_type) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string list_append_func = global_scope->get_unique_name("list_append_" + list_type_code); + typecodeToDSfuncs[list_type_code]["list_append"] = list_append_func; + std::string signature = "void " + list_append_func + "(" + + list_struct_type + "* x, " + + list_element_type + " element)"; + func_decls += "inline " + signature + ";\n"; + generated_code += indent + signature + " {\n"; + std::string list_resize_func = get_list_resize_func(list_type_code); + generated_code += indent + tab + list_resize_func + "(x);\n"; + if( ASR::is_a(*m_type) ) { + generated_code += indent + tab + "x->data[x->current_end_point] = (char*) malloc(40 * sizeof(char));\n"; + } + generated_code += indent + tab + \ + get_deepcopy(m_type, "element", "x->data[x->current_end_point]") + "\n"; + generated_code += indent + tab + "x->current_end_point += 1;\n"; + generated_code += indent + "}\n\n"; + } + + void list_insert(std::string list_struct_type, + std::string list_type_code, std::string list_element_type, + ASR::ttype_t* m_type) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string list_insert_func = global_scope->get_unique_name("list_insert_" + list_type_code); + typecodeToDSfuncs[list_type_code]["list_insert"] = list_insert_func; + std::string signature = "void " + list_insert_func + "(" + + list_struct_type + "* x, " + + "int pos, " + + list_element_type + " element)"; + func_decls += "inline " + signature + ";\n"; + generated_code += indent + signature + " {\n"; + std::string list_resize_func = get_list_resize_func(list_type_code); + generated_code += indent + tab + list_resize_func + "(x);\n"; + generated_code += indent + tab + "int pos_ptr = pos;\n"; + generated_code += indent + tab + list_element_type + " tmp_ptr = x->data[pos];\n"; + generated_code += indent + tab + list_element_type + " tmp;\n"; + + generated_code += indent + tab + "while (x->current_end_point > pos_ptr) {\n"; + generated_code += indent + tab + tab + "tmp = x->data[pos_ptr + 1];\n"; + generated_code += indent + tab + tab + "x->data[pos_ptr + 1] = tmp_ptr;\n"; + generated_code += indent + tab + tab + "tmp_ptr = tmp;\n"; + generated_code += indent + tab + tab + "pos_ptr++;\n"; + generated_code += indent + tab + "}\n\n"; + + if( ASR::is_a(*m_type) ) { + generated_code += indent + tab + "x->data[pos] = (char*) malloc(40 * sizeof(char));\n"; + } + generated_code += indent + tab + get_deepcopy(m_type, "element", "x->data[pos]") + "\n"; + generated_code += indent + tab + "x->current_end_point += 1;\n"; + generated_code += indent + "}\n\n"; + } + + void list_find_item_position(std::string list_struct_type, + std::string list_type_code, std::string list_element_type, + ASR::ttype_t* /*m_type*/) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string list_find_item_pos_func = global_scope->get_unique_name("list_find_item_" + list_type_code); + typecodeToDSfuncs[list_type_code]["list_find_item"] = list_find_item_pos_func; + std::string signature = "int " + list_find_item_pos_func + "(" + + list_struct_type + "* x, " + + list_element_type + " element)"; + std::string cmp_func = compareTwoDS[list_type_code]; + func_decls += "inline " + signature + ";\n"; + generated_code += indent + signature + " {\n"; + generated_code += indent + tab + "int el_pos = 0;\n"; + generated_code += indent + tab + "while (x->current_end_point > el_pos) {\n"; + generated_code += indent + tab + tab + "if (" + cmp_func + "(x->data[el_pos], element)) return el_pos;\n"; + generated_code += indent + tab + tab + "el_pos++;\n"; + generated_code += indent + tab + "}\n"; + generated_code += indent + tab + "return -1;\n"; + generated_code += indent + "}\n\n"; + } + + void list_remove(std::string list_struct_type, + std::string list_type_code, std::string list_element_type, + ASR::ttype_t* /*m_type*/) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string list_remove_func = global_scope->get_unique_name("list_remove_" + list_type_code); + typecodeToDSfuncs[list_type_code]["list_remove"] = list_remove_func; + std::string signature = "void " + list_remove_func + "(" + + list_struct_type + "* x, " + + list_element_type + " element)"; + func_decls += "inline " + signature + ";\n"; + generated_code += indent + signature + " {\n"; + std::string find_item_pos_func = get_list_find_item_position_function(list_type_code); + generated_code += indent + tab + "int el_pos = " + find_item_pos_func + "(x, element);\n"; + generated_code += indent + tab + "while (x->current_end_point > el_pos) {\n"; + generated_code += indent + tab + tab + "int tmp = el_pos + 1;\n"; + generated_code += indent + tab + tab + "x->data[el_pos] = x->data[tmp];\n"; + generated_code += indent + tab + tab + "el_pos = tmp;\n"; + generated_code += indent + tab + "}\n"; + + generated_code += indent + tab + "x->current_end_point -= 1;\n"; + generated_code += indent + "}\n\n"; + } + + std::string get_tuple_deepcopy_func(ASR::Tuple_t* tup_type) { + std::string tuple_type_code = CUtils::get_tuple_type_code(tup_type); + return typecodeToDSfuncs[tuple_type_code]["tuple_deepcopy"]; + } + + + std::string get_tuple_type(ASR::Tuple_t* tuple_type) { + std::string tuple_type_code = CUtils::get_tuple_type_code(tuple_type); + if (typecodeToDStype.find(tuple_type_code) != typecodeToDStype.end()) { + return typecodeToDStype[tuple_type_code]; + } + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string tuple_struct_type = "struct " + tuple_type_code; + typecodeToDStype[tuple_type_code] = tuple_struct_type; + std::string tmp_gen = ""; + tmp_gen += indent + tuple_struct_type + " {\n"; + tmp_gen += indent + tab + "int32_t length;\n"; + for (size_t i = 0; i < tuple_type->n_type; i++) { + if (CUtils::is_non_primitive_DT(tuple_type->m_type[i])) { + // Make sure the nested types work + get_type(tuple_type->m_type[i]); + } + tmp_gen += indent + tab + \ + CUtils::get_c_type_from_ttype_t(tuple_type->m_type[i]) + " element_" + std::to_string(i) + ";\n"; + } + tmp_gen += indent + "};\n\n"; + func_decls += tmp_gen; + generate_compare_funcs((ASR::ttype_t *)tuple_type); + tuple_deepcopy(tuple_type, tuple_type_code); + return tuple_struct_type; + } + + void tuple_deepcopy(ASR::Tuple_t *t, std::string tuple_type_code) { + std::string indent(indentation_level * indentation_spaces, ' '); + std::string tab(indentation_spaces, ' '); + std::string tup_dc_func = global_scope->get_unique_name("tuple_deepcopy_" + tuple_type_code); + typecodeToDSfuncs[tuple_type_code]["tuple_deepcopy"] = tup_dc_func; + std::string tuple_struct_type = typecodeToDStype[tuple_type_code]; + std::string signature = "void " + tup_dc_func + "(" + + tuple_struct_type + " src, " + + tuple_struct_type + "* dest)"; + std::string tmp_def = "", tmp_gen = ""; + tmp_def += "inline " + signature + ";\n"; + tmp_gen += indent + signature + " {\n"; + for (size_t i=0; in_type; i++) { + std::string n = std::to_string(i); + if (ASR::is_a(*t->m_type[i])) { + tmp_gen += indent + tab + "dest->element_" + n + " = " + \ + "(char *) malloc(40*sizeof(char));\n"; + } + tmp_gen += indent + tab + get_deepcopy(t->m_type[i], "src.element_" + n, + "dest->element_" + n) + "\n"; + } + tmp_gen += indent + "}\n\n"; + func_decls += tmp_def; + generated_code += tmp_gen; + } + + ~CCPPDSUtils() { + typecodeToDStype.clear(); + generated_code.clear(); + compareTwoDS.clear(); + } +}; + +} // namespace LFortran + +#endif // LFORTRAN_C_UTILS_H diff --git a/src/libasr/codegen/evaluator.cpp b/src/libasr/codegen/evaluator.cpp index 0fc789d..445ea19 100644 --- a/src/libasr/codegen/evaluator.cpp +++ b/src/libasr/codegen/evaluator.cpp @@ -54,9 +54,7 @@ # include #endif #include -#if LLVM_VERSION_MAJOR <= 11 -# include -#endif +#include #include #include @@ -184,19 +182,14 @@ LLVMEvaluator::LLVMEvaluator(const std::string &t) TM = target->createTargetMachine(target_triple, CPU, features, opt, RM); // For some reason the JIT requires a different TargetMachine - llvm::TargetMachine *TM2 = llvm::EngineBuilder().selectTarget(); -#if LLVM_VERSION_MAJOR <= 11 - jit = std::make_unique(TM2); -#endif + jit = cantFail(llvm::orc::KaleidoscopeJIT::Create()); _lfortran_stan(0.5); } LLVMEvaluator::~LLVMEvaluator() { -#if LLVM_VERSION_MAJOR <= 11 jit.reset(); -#endif context.reset(); } @@ -213,9 +206,7 @@ std::unique_ptr LLVMEvaluator::parse_module(const std::string &sou throw LCompilersException("parse_module(): module failed verification."); }; module->setTargetTriple(target_triple); -#if LLVM_VERSION_MAJOR <= 11 module->setDataLayout(jit->getTargetMachine().createDataLayout()); -#endif return module; } @@ -236,10 +227,17 @@ void LLVMEvaluator::add_module(std::unique_ptr mod) { // These are already set in parse_module(), but we set it here again for // cases when the Module was constructed directly, not via parse_module(). mod->setTargetTriple(target_triple); -#if LLVM_VERSION_MAJOR <= 11 - mod->setDataLayout(jit->getTargetMachine().createDataLayout()); - jit->addModule(std::move(mod)); -#endif + mod->setDataLayout(jit->getDataLayout()); + llvm::Error err = jit->addModule(std::move(mod)); + if (err) { + llvm::SmallVector buf; + llvm::raw_svector_ostream dest(buf); + llvm::logAllUnhandledErrors(std::move(err), dest, ""); + std::string msg = std::string(dest.str().data(), dest.str().size()); + if (msg[msg.size()-1] == '\n') msg = msg.substr(0, msg.size()-1); + throw LCompilersException("addModule() returned an error: " + msg); + } + } void LLVMEvaluator::add_module(std::unique_ptr m) { @@ -247,17 +245,18 @@ void LLVMEvaluator::add_module(std::unique_ptr m) { } intptr_t LLVMEvaluator::get_symbol_address(const std::string &name) { -#if LLVM_VERSION_MAJOR <= 11 - llvm::JITSymbol s = jit->findSymbol(name); -#else - llvm::JITSymbol s = nullptr; -#endif + llvm::Expected s = jit->lookup(name); if (!s) { - throw std::runtime_error("findSymbol() failed to find the symbol '" - + name + "'"); + llvm::Error e = s.takeError(); + llvm::SmallVector buf; + llvm::raw_svector_ostream dest(buf); + llvm::logAllUnhandledErrors(std::move(e), dest, ""); + std::string msg = std::string(dest.str().data(), dest.str().size()); + if (msg[msg.size()-1] == '\n') msg = msg.substr(0, msg.size()-1); + throw LCompilersException("lookup() failed to find the symbol '" + + name + "', error: " + msg); } -#if LLVM_VERSION_MAJOR <= 11 - llvm::Expected addr0 = s.getAddress(); + llvm::Expected addr0 = s->getAddress(); if (!addr0) { llvm::Error e = addr0.takeError(); llvm::SmallVector buf; @@ -268,7 +267,6 @@ intptr_t LLVMEvaluator::get_symbol_address(const std::string &name) { throw LCompilersException("JITSymbol::getAddress() returned an error: " + msg); } return (intptr_t)cantFail(std::move(addr0)); -#endif } int32_t LLVMEvaluator::int32fn(const std::string &name) { @@ -332,11 +330,9 @@ std::string LLVMEvaluator::get_asm(llvm::Module &m) llvm::CodeGenFileType ft = llvm::CGFT_AssemblyFile; llvm::SmallVector buf; llvm::raw_svector_ostream dest(buf); -#if LLVM_VERSION_MAJOR <= 11 if (jit->getTargetMachine().addPassesToEmitFile(pass, dest, nullptr, ft)) { throw std::runtime_error("TargetMachine can't emit a file of this type"); } -#endif pass.run(m); return std::string(dest.str().data(), dest.str().size()); } diff --git a/src/libasr/codegen/evaluator.h b/src/libasr/codegen/evaluator.h index d283d75..05dedf5 100644 --- a/src/libasr/codegen/evaluator.h +++ b/src/libasr/codegen/evaluator.h @@ -19,11 +19,9 @@ namespace llvm { class Module; class Function; class TargetMachine; -#if LLVM_VERSION_MAJOR <= 11 namespace orc { class KaleidoscopeJIT; } -#endif } namespace LFortran { @@ -42,9 +40,7 @@ class LLVMModule class LLVMEvaluator { private: -#if LLVM_VERSION_MAJOR <= 11 std::unique_ptr jit; -#endif std::unique_ptr context; std::string target_triple; llvm::TargetMachine *TM; diff --git a/src/libasr/codegen/llvm_array_utils.cpp b/src/libasr/codegen/llvm_array_utils.cpp index 3fddf5c..0f200c3 100644 --- a/src/libasr/codegen/llvm_array_utils.cpp +++ b/src/libasr/codegen/llvm_array_utils.cpp @@ -115,35 +115,21 @@ namespace LFortran { ) { } - bool SimpleCMODescriptor::is_array(llvm::Value* tmp) { - llvm::Type* tmp_type = nullptr; - if( tmp->getType()->isPointerTy() ) { - tmp_type = static_cast(tmp->getType())->getElementType(); - } else { - tmp_type = tmp->getType(); - } - if( tmp_type->isStructTy() ) { - llvm::StructType* tmp_struct_type = static_cast(tmp_type); - if( tmp_struct_type->getNumElements() > 2 && - tmp_struct_type->getElementType(2) == dim_des->getPointerTo() ) { - return true; - } else { - return false; - } - } else { - return false; - } + bool SimpleCMODescriptor::is_array(ASR::ttype_t* asr_type) { + std::string asr_type_code = ASRUtils::get_type_code(asr_type, false, false); + return tkr2array.find(asr_type_code) != tkr2array.end(); } llvm::Value* SimpleCMODescriptor:: - convert_to_argument(llvm::Value* tmp, llvm::Type* arg_type, bool data_only) { + convert_to_argument(llvm::Value* tmp, ASR::ttype_t* asr_arg_type, + llvm::Type* arg_type, bool data_only) { if( data_only ) { return LLVM::CreateLoad(*builder, get_pointer_to_data(tmp)); } llvm::Value* arg_struct = builder->CreateAlloca(arg_type, nullptr); llvm::Value* first_ele_ptr = nullptr; - llvm::Type* tmp_type = static_cast(tmp->getType())->getElementType(); - llvm::StructType* tmp_struct_type = static_cast(tmp_type); + std::string asr_arg_type_code = ASRUtils::get_type_code(ASRUtils::get_contained_type(asr_arg_type), false, false); + llvm::StructType* tmp_struct_type = tkr2array[asr_arg_type_code].first; if( tmp_struct_type->getElementType(0)->isArrayTy() ) { first_ele_ptr = llvm_utils->create_gep(get_pointer_to_data(tmp), 0); } else if( tmp_struct_type->getNumElements() < 5 ) { @@ -200,12 +186,12 @@ namespace LFortran { llvm::Type* SimpleCMODescriptor::get_array_type (ASR::ttype_t* m_type_, llvm::Type* el_type, bool get_pointer) { - std::string array_key = ASRUtils::get_type_code(m_type_); + std::string array_key = ASRUtils::get_type_code(m_type_, false, false); if( tkr2array.find(array_key) != tkr2array.end() ) { if( get_pointer ) { - return tkr2array[array_key]->getPointerTo(); + return tkr2array[array_key].first->getPointerTo(); } - return tkr2array[array_key]; + return tkr2array[array_key].first; } llvm::Type* dim_des_array = create_dimension_descriptor_array_type(); std::vector array_type_vec; @@ -215,11 +201,11 @@ namespace LFortran { llvm::Type::getInt1Ty(context), llvm::Type::getInt32Ty(context) }; llvm::StructType* new_array_type = llvm::StructType::create(context, array_type_vec, "array"); - tkr2array[array_key] = new_array_type; + tkr2array[array_key] = std::make_pair(new_array_type, el_type); if( get_pointer ) { - return tkr2array[array_key]->getPointerTo(); + return tkr2array[array_key].first->getPointerTo(); } - return (llvm::Type*) tkr2array[array_key]; + return (llvm::Type*) tkr2array[array_key].first; } llvm::Type* SimpleCMODescriptor::create_dimension_descriptor_array_type() { @@ -228,12 +214,12 @@ namespace LFortran { llvm::Type* SimpleCMODescriptor::get_malloc_array_type (ASR::ttype_t* m_type_, llvm::Type* el_type, bool get_pointer) { - std::string array_key = ASRUtils::get_type_code(m_type_); + std::string array_key = ASRUtils::get_type_code(m_type_, false, false); if( tkr2array.find(array_key) != tkr2array.end() ) { if( get_pointer ) { - return tkr2array[array_key]->getPointerTo(); + return tkr2array[array_key].first->getPointerTo(); } - return tkr2array[array_key]; + return tkr2array[array_key].first; } llvm::Type* dim_des_array = create_dimension_descriptor_array_type(); std::vector array_type_vec = { @@ -243,11 +229,11 @@ namespace LFortran { llvm::Type::getInt1Ty(context), llvm::Type::getInt32Ty(context)}; llvm::StructType* new_array_type = llvm::StructType::create(context, array_type_vec, "array"); - tkr2array[array_key] = new_array_type; + tkr2array[array_key] = std::make_pair(new_array_type, el_type); if( get_pointer ) { - return tkr2array[array_key]->getPointerTo(); + return tkr2array[array_key].first->getPointerTo(); } - return (llvm::Type*) tkr2array[array_key]; + return (llvm::Type*) tkr2array[array_key].first; } llvm::Type* SimpleCMODescriptor::get_dimension_descriptor_type @@ -292,7 +278,7 @@ namespace LFortran { } void SimpleCMODescriptor::fill_array_details( - llvm::Value* arr, int n_dims, + llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, std::vector>& llvm_dims) { llvm::Value* offset_val = llvm_utils->create_gep(arr, 1); builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, 0)), offset_val); @@ -324,15 +310,13 @@ namespace LFortran { } builder->CreateStore(prod, llvm_size); llvm::Value* first_ptr = get_pointer_to_data(arr); - llvm::PointerType* first_ptr2ptr_type = static_cast(first_ptr->getType()); - llvm::PointerType* first_ptr_type = static_cast(first_ptr2ptr_type->getElementType()); - llvm::Value* arr_first = builder->CreateAlloca(first_ptr_type->getElementType(), - LLVM::CreateLoad(*builder, llvm_size)); + llvm::Value* arr_first = builder->CreateAlloca(llvm_data_type, + LLVM::CreateLoad(*builder, llvm_size)); builder->CreateStore(arr_first, first_ptr); } void SimpleCMODescriptor::fill_malloc_array_details( - llvm::Value* arr, int n_dims, + llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, std::vector>& llvm_dims, llvm::Module* module) { llvm::Value* num_elements = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); @@ -355,11 +339,8 @@ namespace LFortran { llvm::Value* ptr2firstptr = get_pointer_to_data(arr); llvm::AllocaInst *arg_size = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); llvm::DataLayout data_layout(module); - llvm::Type* ptr2firstptr_type = ptr2firstptr->getType(); - llvm::Type* ptr_type = static_cast(ptr2firstptr_type)->getElementType(); - uint64_t size = data_layout.getTypeAllocSize( - static_cast(ptr_type)-> - getElementType()); + llvm::Type* ptr_type = llvm_data_type->getPointerTo(); + uint64_t size = data_layout.getTypeAllocSize(llvm_data_type); llvm::Value* llvm_size = llvm::ConstantInt::get(context, llvm::APInt(32, size)); num_elements = builder->CreateMul(num_elements, llvm_size); builder->CreateStore(num_elements, arg_size); @@ -529,7 +510,8 @@ namespace LFortran { return tmp; } - llvm::Value* SimpleCMODescriptor::reshape(llvm::Value* array, llvm::Value* shape, + llvm::Value* SimpleCMODescriptor::reshape(llvm::Value* array, llvm::Type* llvm_data_type, + llvm::Value* shape, ASR::ttype_t* asr_shape_type, llvm::Module* module) { llvm::Value* reshaped = builder->CreateAlloca(array->getType()->getContainedType(0), nullptr, "reshaped"); @@ -537,25 +519,19 @@ namespace LFortran { llvm::Value* num_elements = this->get_array_size(array, nullptr, 4); llvm::Value* first_ptr = this->get_pointer_to_data(reshaped); - llvm::PointerType* first_ptr2ptr_type = static_cast(first_ptr->getType()); - llvm::PointerType* first_ptr_type = static_cast(first_ptr2ptr_type->getElementType()); - llvm::Value* arr_first = builder->CreateAlloca(first_ptr_type->getElementType(), num_elements); + llvm::Value* arr_first = builder->CreateAlloca(llvm_data_type, num_elements); builder->CreateStore(arr_first, first_ptr); llvm::Value* ptr2firstptr = this->get_pointer_to_data(array); llvm::DataLayout data_layout(module); - llvm::Type* ptr2firstptr_type = ptr2firstptr->getType(); - llvm::Type* ptr_type = static_cast(ptr2firstptr_type)->getElementType(); - uint64_t size = data_layout.getTypeAllocSize( - static_cast(ptr_type)-> - getElementType()); + uint64_t size = data_layout.getTypeAllocSize(llvm_data_type); llvm::Value* llvm_size = llvm::ConstantInt::get(context, llvm::APInt(32, size)); num_elements = builder->CreateMul(num_elements, llvm_size); builder->CreateMemCpy(LLVM::CreateLoad(*builder, first_ptr), llvm::MaybeAlign(), LLVM::CreateLoad(*builder, ptr2firstptr), llvm::MaybeAlign(), num_elements); - if( this->is_array(shape) ) { + if( this->is_array(asr_shape_type) ) { llvm::Value* n_dims = this->get_array_size(shape, nullptr, 4); llvm::Value* shape_data = LLVM::CreateLoad(*builder, this->get_pointer_to_data(shape)); llvm::Value* dim_des_val = llvm_utils->create_gep(reshaped, 2); @@ -594,14 +570,39 @@ namespace LFortran { } // Shallow copies source array descriptor to destination descriptor - void SimpleCMODescriptor::copy_array(llvm::Value* src, llvm::Value* dest) { - llvm::Value* src_data_ptr = LLVM::CreateLoad(*builder, this->get_pointer_to_data(src)); - builder->CreateStore(src_data_ptr, this->get_pointer_to_data(dest)); + void SimpleCMODescriptor::copy_array(llvm::Value* src, llvm::Value* dest, + llvm::Module* module, ASR::ttype_t* asr_data_type, bool create_dim_des_array, + bool reserve_memory) { + llvm::Value* num_elements = this->get_array_size(src, nullptr, 4); + + llvm::Value* first_ptr = this->get_pointer_to_data(dest); + llvm::Type* llvm_data_type = tkr2array[ASRUtils::get_type_code(asr_data_type, false, false)].second; + if( reserve_memory ) { + llvm::Value* arr_first = builder->CreateAlloca(llvm_data_type, num_elements); + builder->CreateStore(arr_first, first_ptr); + } + + llvm::Value* ptr2firstptr = this->get_pointer_to_data(src); + llvm::DataLayout data_layout(module); + uint64_t size = data_layout.getTypeAllocSize(llvm_data_type); + llvm::Value* llvm_size = llvm::ConstantInt::get(context, llvm::APInt(32, size)); + num_elements = builder->CreateMul(num_elements, llvm_size); + builder->CreateMemCpy(LLVM::CreateLoad(*builder, first_ptr), llvm::MaybeAlign(), + LLVM::CreateLoad(*builder, ptr2firstptr), llvm::MaybeAlign(), + num_elements); + llvm::Value* src_offset_ptr = LLVM::CreateLoad(*builder, llvm_utils->create_gep(src, 1)); builder->CreateStore(src_offset_ptr, llvm_utils->create_gep(dest, 1)); llvm::Value* src_dim_des_val = this->get_pointer_to_dimension_descriptor_array(src, true); - llvm::Value* dest_dim_des_val = this->get_pointer_to_dimension_descriptor_array(dest, true); - llvm::Value* n_dims = this->get_rank(dest, false); + llvm::Value* n_dims = this->get_rank(src, false); + llvm::Value* dest_dim_des_val = nullptr; + if( !create_dim_des_array ) { + dest_dim_des_val = this->get_pointer_to_dimension_descriptor_array(dest, true); + } else { + llvm::Value* dest_dim_des_ptr = this->get_pointer_to_dimension_descriptor_array(dest, false); + dest_dim_des_val = builder->CreateAlloca(dim_des, n_dims); + builder->CreateStore(dest_dim_des_val, dest_dim_des_ptr); + } llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head"); llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body"); llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end"); @@ -618,11 +619,22 @@ namespace LFortran { llvm::Value* r_val = LLVM::CreateLoad(*builder, r); llvm::Value* src_dim_val = llvm_utils->create_ptr_gep(src_dim_des_val, r_val); llvm::Value* src_s_val = llvm_utils->create_gep(src_dim_val, 0); + llvm::Value* src_l_val = nullptr; + if( create_dim_des_array ) { + src_l_val = llvm_utils->create_gep(src_dim_val, 1); + } llvm::Value* src_dim_size_ptr = llvm_utils->create_gep(src_dim_val, 2); llvm::Value* dest_dim_val = llvm_utils->create_ptr_gep(dest_dim_des_val, r_val); llvm::Value* dest_s_val = llvm_utils->create_gep(dest_dim_val, 0); + llvm::Value* dest_l_val = nullptr; + if( create_dim_des_array ) { + dest_l_val = llvm_utils->create_gep(dest_dim_val, 1); + } llvm::Value* dest_dim_size_ptr = llvm_utils->create_gep(dest_dim_val, 2); builder->CreateStore(LLVM::CreateLoad(*builder, src_s_val), dest_s_val); + if( create_dim_des_array ) { + builder->CreateStore(LLVM::CreateLoad(*builder, src_l_val), dest_l_val); + } builder->CreateStore(LLVM::CreateLoad(*builder, src_dim_size_ptr), dest_dim_size_ptr); r_val = builder->CreateAdd(r_val, llvm::ConstantInt::get(context, llvm::APInt(32, 1))); builder->CreateStore(r_val, r); @@ -633,8 +645,7 @@ namespace LFortran { llvm::Value* src_is_allocated_ptr = this->get_is_allocated_flag(src); builder->CreateStore(src_is_allocated_ptr, llvm_utils->create_gep(src, 3)); - llvm::Value* src_rank_ptr = LLVM::CreateLoad(*builder, llvm_utils->create_gep(src, 4)); - builder->CreateStore(src_rank_ptr, llvm_utils->create_gep(dest, 4)); + builder->CreateStore(n_dims, this->get_rank(dest, true)); } } // LLVMArrUtils diff --git a/src/libasr/codegen/llvm_array_utils.h b/src/libasr/codegen/llvm_array_utils.h index b04ae67..30d75ba 100644 --- a/src/libasr/codegen/llvm_array_utils.h +++ b/src/libasr/codegen/llvm_array_utils.h @@ -74,12 +74,12 @@ namespace LFortran { DESCR_TYPE descr_type); /* - * Checks whether the given llvm::Value* is an + * Checks whether the given ASR::ttype_t* is an * array and follows the same structure as * the current descriptor. */ virtual - bool is_array(llvm::Value* tmp) = 0; + bool is_array(ASR::ttype_t* asr_type) = 0; /* * Converts a given array llvm::Value* @@ -87,7 +87,8 @@ namespace LFortran { */ virtual llvm::Value* convert_to_argument(llvm::Value* tmp, - llvm::Type* arg_type, bool data_only=false) = 0; + ASR::ttype_t* asr_arg_type, llvm::Type* arg_type, + bool data_only=false) = 0; /* * Returns the type of the argument to be @@ -139,7 +140,7 @@ namespace LFortran { */ virtual void fill_array_details( - llvm::Value* arr, int n_dims, + llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, std::vector>& llvm_dims) = 0; /* @@ -148,7 +149,7 @@ namespace LFortran { */ virtual void fill_malloc_array_details( - llvm::Value* arr, int n_dims, + llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, std::vector>& llvm_dims, llvm::Module* module) = 0; @@ -252,11 +253,14 @@ namespace LFortran { void set_is_allocated_flag(llvm::Value* array, uint64_t status) = 0; virtual - llvm::Value* reshape(llvm::Value* array, llvm::Value* shape, - llvm::Module* module) = 0; + llvm::Value* reshape(llvm::Value* array, llvm::Type* llvm_data_type, + llvm::Value* shape, ASR::ttype_t* asr_shape_type, + llvm::Module* module) = 0; virtual - void copy_array(llvm::Value* src, llvm::Value* dest) = 0; + void copy_array(llvm::Value* src, llvm::Value* dest, + llvm::Module* module, ASR::ttype_t* asr_data_type, + bool create_dim_des_array, bool reserve_memory) = 0; virtual llvm::Value* get_array_size(llvm::Value* array, llvm::Value* dim, @@ -274,7 +278,7 @@ namespace LFortran { llvm::StructType* dim_des; - std::map tkr2array; + std::map> tkr2array; llvm::Value* cmo_convertor_single_element( llvm::Value* arr, std::vector& m_args, @@ -291,11 +295,12 @@ namespace LFortran { LLVMUtils* _llvm_utils); virtual - bool is_array(llvm::Value* tmp); + bool is_array(ASR::ttype_t* asr_type); virtual llvm::Value* convert_to_argument(llvm::Value* tmp, - llvm::Type* arg_type, bool data_only=false); + ASR::ttype_t* asr_arg_type, llvm::Type* arg_type, + bool data_only=false); virtual llvm::Type* get_argument_type(llvm::Type* type, @@ -322,12 +327,12 @@ namespace LFortran { virtual void fill_array_details( - llvm::Value* arr, int n_dims, + llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, std::vector>& llvm_dims); virtual void fill_malloc_array_details( - llvm::Value* arr, int n_dims, + llvm::Value* arr, llvm::Type* llvm_data_type, int n_dims, std::vector>& llvm_dims, llvm::Module* module); @@ -382,11 +387,14 @@ namespace LFortran { void set_is_allocated_flag(llvm::Value* array, uint64_t status); virtual - llvm::Value* reshape(llvm::Value* array, llvm::Value* shape, - llvm::Module* module); + llvm::Value* reshape(llvm::Value* array, llvm::Type* llvm_data_type, + llvm::Value* shape, ASR::ttype_t* asr_shape_type, + llvm::Module* module); virtual - void copy_array(llvm::Value* src, llvm::Value* dest); + void copy_array(llvm::Value* src, llvm::Value* dest, + llvm::Module* module, ASR::ttype_t* asr_data_type, + bool create_dim_des_array, bool reserve_memory); virtual llvm::Value* get_array_size(llvm::Value* array, llvm::Value* dim, diff --git a/src/libasr/codegen/llvm_utils.cpp b/src/libasr/codegen/llvm_utils.cpp index 3e5c3c2..9a09774 100644 --- a/src/libasr/codegen/llvm_utils.cpp +++ b/src/libasr/codegen/llvm_utils.cpp @@ -1,5 +1,6 @@ #include #include +#include #include namespace LFortran { @@ -298,24 +299,53 @@ namespace LFortran { } void LLVMUtils::deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::ttype_t* asr_type, llvm::Module& module) { + ASR::ttype_t* asr_type, llvm::Module* module, + std::map>& name2memidx) { switch( asr_type->type ) { case ASR::ttypeType::Integer: case ASR::ttypeType::Real: - case ASR::ttypeType::Character: case ASR::ttypeType::Logical: case ASR::ttypeType::Complex: { - LLVM::CreateStore(*builder, src, dest); + if( ASRUtils::is_array(asr_type) ) { + arr_api->copy_array(src, dest, module, asr_type, false, false); + } else { + LLVM::CreateStore(*builder, src, dest); + } break ; }; + case ASR::ttypeType::Character: + case ASR::ttypeType::CPtr: { + LLVM::CreateStore(*builder, src, dest); + break ; + } case ASR::ttypeType::Tuple: { ASR::Tuple_t* tuple_type = ASR::down_cast(asr_type); - tuple_api->tuple_deepcopy(src, dest, tuple_type, module); + tuple_api->tuple_deepcopy(src, dest, tuple_type, module, name2memidx); break ; } case ASR::ttypeType::List: { ASR::List_t* list_type = ASR::down_cast(asr_type); - list_api->list_deepcopy(src, dest, list_type, module); + list_api->list_deepcopy(src, dest, list_type, module, name2memidx); + break ; + } + case ASR::ttypeType::Struct: { + ASR::Struct_t* struct_t = ASR::down_cast(asr_type); + ASR::StructType_t* struct_type_t = ASR::down_cast( + ASRUtils::symbol_get_past_external(struct_t->m_derived_type)); + std::string der_type_name = std::string(struct_type_t->m_name); + for( auto item: struct_type_t->m_symtab->get_scope() ) { + std::string mem_name = item.first; + int mem_idx = name2memidx[der_type_name][mem_name]; + llvm::Value* src_member = create_gep(src, mem_idx); + if( !LLVM::is_llvm_struct(ASRUtils::symbol_type(item.second)) && + !ASRUtils::is_array(ASRUtils::symbol_type(item.second)) ) { + src_member = LLVM::CreateLoad(*builder, src_member); + } + llvm::Value* dest_member = create_gep(dest, mem_idx); + deepcopy(src_member, dest_member, + ASRUtils::symbol_type(item.second), + module, name2memidx); + } break ; } default: { @@ -611,12 +641,14 @@ namespace LFortran { } void LLVMList::list_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::List_t* list_type, llvm::Module& module) { - list_deepcopy(src, dest, list_type->m_type, module); + ASR::List_t* list_type, llvm::Module* module, + std::map>& name2memidx) { + list_deepcopy(src, dest, list_type->m_type, module, name2memidx); } void LLVMList::list_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::ttype_t* element_type, llvm::Module& module) { + ASR::ttype_t* element_type, llvm::Module* module, + std::map>& name2memidx) { LFORTRAN_ASSERT(src->getType() == dest->getType()); std::string src_type_code = ASRUtils::get_type_code(element_type); llvm::Value* src_end_point = LLVM::CreateLoad(*builder, get_pointer_to_current_end_point(src)); @@ -629,7 +661,7 @@ namespace LFortran { int32_t type_size = std::get<1>(typecode2listtype[src_type_code]); llvm::Value* arg_size = builder->CreateMul(llvm::ConstantInt::get(context, llvm::APInt(32, type_size)), src_capacity); - llvm::Value* copy_data = LLVM::lfortran_malloc(context, module, *builder, + llvm::Value* copy_data = LLVM::lfortran_malloc(context, *module, *builder, arg_size); llvm::Type* el_type = std::get<2>(typecode2listtype[src_type_code]); copy_data = builder->CreateBitCast(copy_data, el_type->getPointerTo()); @@ -670,9 +702,9 @@ namespace LFortran { llvm_utils->start_new_block(loopbody); { llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* srci = read_item(src, pos, true); - llvm::Value* desti = read_item(dest, pos, true); - llvm_utils->deepcopy(srci, desti, element_type, module); + llvm::Value* srci = read_item(src, pos, false, *module, true); + llvm::Value* desti = read_item(dest, pos, false, *module, true); + llvm_utils->deepcopy(srci, desti, element_type, module, name2memidx); llvm::Value* tmp = builder->CreateAdd( pos, llvm::ConstantInt::get(context, llvm::APInt(32, 1))); @@ -691,7 +723,8 @@ namespace LFortran { } void LLVMDict::dict_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Dict_t* dict_type, llvm::Module* module) { + ASR::Dict_t* dict_type, llvm::Module* module, + std::map>& name2memidx) { LFORTRAN_ASSERT(src->getType() == dest->getType()); llvm::Value* src_occupancy = LLVM::CreateLoad(*builder, get_pointer_to_occupancy(src)); llvm::Value* dest_occupancy_ptr = get_pointer_to_occupancy(dest); @@ -700,12 +733,13 @@ namespace LFortran { llvm::Value* src_key_list = get_key_list(src); llvm::Value* dest_key_list = get_key_list(dest); llvm_utils->list_api->list_deepcopy(src_key_list, dest_key_list, - dict_type->m_key_type, *module); + dict_type->m_key_type, module, + name2memidx); llvm::Value* src_value_list = get_value_list(src); llvm::Value* dest_value_list = get_value_list(dest); llvm_utils->list_api->list_deepcopy(src_value_list, dest_value_list, - dict_type->m_value_type, *module); + dict_type->m_value_type, module, name2memidx); llvm::Value* src_key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(src)); llvm::Value* dest_key_mask_ptr = get_pointer_to_keymask(dest); @@ -723,7 +757,8 @@ namespace LFortran { void LLVMDictSeparateChaining::deepcopy_key_value_pair_linked_list( llvm::Value* srci, llvm::Value* desti, llvm::Value* dest_key_value_pairs, - llvm::Value* src_capacity, ASR::Dict_t* dict_type, llvm::Module* module) { + llvm::Value* src_capacity, ASR::Dict_t* dict_type, llvm::Module* module, + std::map>& name2memidx) { if( !are_iterators_set ) { src_itr = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); dest_itr = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); @@ -768,8 +803,8 @@ namespace LFortran { } llvm::Value* dest_key_ptr = llvm_utils->create_gep(curr_dest, 0); llvm::Value* dest_value_ptr = llvm_utils->create_gep(curr_dest, 1); - llvm_utils->deepcopy(src_key, dest_key_ptr, dict_type->m_key_type, *module); - llvm_utils->deepcopy(src_value, dest_value_ptr, dict_type->m_value_type, *module); + llvm_utils->deepcopy(src_key, dest_key_ptr, dict_type->m_key_type, module, name2memidx); + llvm_utils->deepcopy(src_value, dest_value_ptr, dict_type->m_value_type, module, name2memidx); llvm::Value* src_next_ptr = LLVM::CreateLoad(*builder, llvm_utils->create_gep(curr_src, 2)); llvm::Value* curr_dest_next_ptr = llvm_utils->create_gep(curr_dest, 2); @@ -811,7 +846,8 @@ namespace LFortran { void LLVMDictSeparateChaining::write_key_value_pair_linked_list( llvm::Value* kv_ll, llvm::Value* dict, llvm::Value* capacity, - ASR::ttype_t* m_key_type, ASR::ttype_t* m_value_type, llvm::Module* module) { + ASR::ttype_t* m_key_type, ASR::ttype_t* m_value_type, llvm::Module* module, + std::map>& name2memidx) { if( !are_iterators_set ) { src_itr = builder->CreateAlloca(llvm::Type::getInt8PtrTy(context), nullptr); } @@ -850,7 +886,8 @@ namespace LFortran { resolve_collision_for_write( dict, key_hash, src_key, src_value, module, - m_key_type, m_value_type); + m_key_type, m_value_type, + name2memidx); llvm::Value* src_next_ptr = LLVM::CreateLoad(*builder, llvm_utils->create_gep(curr_src, 2)); LLVM::CreateStore(*builder, src_next_ptr, src_itr); @@ -864,7 +901,8 @@ namespace LFortran { void LLVMDictSeparateChaining::dict_deepcopy( llvm::Value* src, llvm::Value* dest, - ASR::Dict_t* dict_type, llvm::Module* module) { + ASR::Dict_t* dict_type, llvm::Module* module, + std::map>& name2memidx) { llvm::Value* src_occupancy = LLVM::CreateLoad(*builder, get_pointer_to_occupancy(src)); llvm::Value* src_filled_buckets = LLVM::CreateLoad(*builder, get_pointer_to_number_of_filled_buckets(src)); llvm::Value* src_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(src)); @@ -933,7 +971,7 @@ namespace LFortran { llvm::Value* srci = llvm_utils->create_ptr_gep(src_key_value_pairs, itr); llvm::Value* desti = llvm_utils->create_ptr_gep(dest_key_value_pairs, itr); deepcopy_key_value_pair_linked_list(srci, desti, dest_key_value_pairs, - src_capacity, dict_type, module); + src_capacity, dict_type, module, name2memidx); } builder->CreateBr(mergeBB); llvm_utils->start_new_block(elseBB); @@ -951,25 +989,62 @@ namespace LFortran { LLVM::CreateStore(*builder, dest_key_value_pairs, get_pointer_to_key_value_pairs(dest)); } - void LLVMList::check_index_within_bounds(llvm::Value* /*list*/, llvm::Value* /*pos*/) { + void LLVMList::check_index_within_bounds(llvm::Value* list, + llvm::Value* pos, llvm::Module& module) { + llvm::Value* end_point = LLVM::CreateLoad(*builder, + get_pointer_to_current_end_point(list)); + llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), + llvm::APInt(32, 0)); + + llvm::Function *fn = builder->GetInsertBlock()->getParent(); + llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); + llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); + llvm::BasicBlock *mergeBB = llvm::BasicBlock::Create(context, "ifcont"); + llvm::Value* cond = builder->CreateOr( + builder->CreateICmpSGE(pos, end_point), + builder->CreateICmpSLT(pos, zero)); + builder->CreateCondBr(cond, thenBB, elseBB); + builder->SetInsertPoint(thenBB); + { + std::string index_error = "IndexError: %s%d%s%d\n", + message1 = "List index is out of range. Index range is (0, ", + message2 = "), but the given index is "; + llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr(index_error); + llvm::Value *fmt_ptr1 = builder->CreateGlobalStringPtr(message1); + llvm::Value *fmt_ptr2 = builder->CreateGlobalStringPtr(message2); + llvm::Value *end_minus_one = builder->CreateSub(end_point, + llvm::ConstantInt::get(context, llvm::APInt(32, 1))); + print_error(context, module, *builder, {fmt_ptr, fmt_ptr1, + end_minus_one, fmt_ptr2, pos}); + int exit_code_int = 1; + llvm::Value *exit_code = llvm::ConstantInt::get(context, + llvm::APInt(32, exit_code_int)); + exit(context, module, *builder, exit_code); + } + builder->CreateBr(mergeBB); + + llvm_utils->start_new_block(elseBB); + llvm_utils->start_new_block(mergeBB); } void LLVMList::write_item(llvm::Value* list, llvm::Value* pos, llvm::Value* item, ASR::ttype_t* asr_type, - llvm::Module& module, bool check_index_bound) { - if( check_index_bound ) { - check_index_within_bounds(list, pos); + bool enable_bounds_checking, llvm::Module* module, + std::map>& name2memidx) { + if( enable_bounds_checking ) { + check_index_within_bounds(list, pos, *module); } llvm::Value* list_data = LLVM::CreateLoad(*builder, get_pointer_to_list_data(list)); llvm::Value* element_ptr = llvm_utils->create_ptr_gep(list_data, pos); - llvm_utils->deepcopy(item, element_ptr, asr_type, module); + llvm_utils->deepcopy(item, element_ptr, asr_type, module, name2memidx); } void LLVMList::write_item(llvm::Value* list, llvm::Value* pos, - llvm::Value* item, bool check_index_bound) { - if( check_index_bound ) { - check_index_within_bounds(list, pos); + llvm::Value* item, bool enable_bounds_checking, + llvm::Module& module) { + if( enable_bounds_checking ) { + check_index_within_bounds(list, pos, module); } llvm::Value* list_data = LLVM::CreateLoad(*builder, get_pointer_to_list_data(list)); llvm::Value* element_ptr = llvm_utils->create_ptr_gep(list_data, pos); @@ -1108,7 +1183,7 @@ namespace LFortran { builder->SetInsertPoint(thenBB); { llvm::Value* original_key = llvm_utils->list_api->read_item(key_list, pos, - LLVM::is_llvm_struct(key_asr_type), false); + false, module, LLVM::is_llvm_struct(key_asr_type)); is_key_matching = llvm_utils->is_equal_by_value(key, original_key, module, key_asr_type); LLVM::CreateStore(*builder, is_key_matching, is_key_matching_var); @@ -1196,7 +1271,7 @@ namespace LFortran { builder->SetInsertPoint(thenBB); { llvm::Value* original_key = llvm_utils->list_api->read_item(key_list, pos, - LLVM::is_llvm_struct(key_asr_type), false); + false, module, LLVM::is_llvm_struct(key_asr_type)); is_key_matching = llvm_utils->is_equal_by_value(key, original_key, module, key_asr_type); LLVM::CreateStore(*builder, is_key_matching, is_key_matching_var); @@ -1315,7 +1390,8 @@ namespace LFortran { llvm::Value* dict, llvm::Value* key_hash, llvm::Value* key, llvm::Value* value, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type) { + ASR::ttype_t* value_asr_type, + std::map>& name2memidx) { llvm::Value* key_list = get_key_list(dict); llvm::Value* value_list = get_value_list(dict); llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); @@ -1323,9 +1399,9 @@ namespace LFortran { this->resolve_collision(capacity, key_hash, key, key_list, key_mask, *module, key_asr_type); llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); llvm_utils->list_api->write_item(key_list, pos, key, - key_asr_type, *module, false); + key_asr_type, false, module, name2memidx); llvm_utils->list_api->write_item(value_list, pos, value, - value_asr_type, *module, false); + value_asr_type, false, module, name2memidx); llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, llvm_utils->create_ptr_gep(key_mask, pos)); llvm::Value* is_slot_empty = builder->CreateICmpEQ(key_mask_value, @@ -1344,7 +1420,8 @@ namespace LFortran { llvm::Value* dict, llvm::Value* key_hash, llvm::Value* key, llvm::Value* value, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type) { + ASR::ttype_t* value_asr_type, + std::map>& name2memidx) { llvm::Value* key_list = get_key_list(dict); llvm::Value* value_list = get_value_list(dict); llvm::Value* key_mask = LLVM::CreateLoad(*builder, get_pointer_to_keymask(dict)); @@ -1352,9 +1429,9 @@ namespace LFortran { this->resolve_collision(capacity, key_hash, key, key_list, key_mask, *module, key_asr_type); llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); llvm_utils->list_api->write_item(key_list, pos, key, - key_asr_type, *module, false); + key_asr_type, false, module, name2memidx); llvm_utils->list_api->write_item(value_list, pos, value, - value_asr_type, *module, false); + value_asr_type, false, module, name2memidx); llvm::Value* key_mask_value = LLVM::CreateLoad(*builder, llvm_utils->create_ptr_gep(key_mask, pos)); @@ -1384,7 +1461,8 @@ namespace LFortran { llvm::Value* dict, llvm::Value* key_hash, llvm::Value* key, llvm::Value* value, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type) { + ASR::ttype_t* value_asr_type, + std::map>& name2memidx) { llvm::Value* capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); llvm::Value* key_value_pairs = LLVM::CreateLoad(*builder, get_pointer_to_key_value_pairs(dict)); llvm::Value* key_value_pair_linked_list = llvm_utils->create_ptr_gep(key_value_pairs, key_hash); @@ -1407,8 +1485,8 @@ namespace LFortran { llvm::Value* malloc_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), kv_struct_size); llvm::Value* new_kv_struct_i8 = LLVM::lfortran_malloc(context, *module, *builder, malloc_size); llvm::Value* new_kv_struct = builder->CreateBitCast(new_kv_struct_i8, kv_struct_type->getPointerTo()); - llvm_utils->deepcopy(key, llvm_utils->create_gep(new_kv_struct, 0), key_asr_type, *module); - llvm_utils->deepcopy(value, llvm_utils->create_gep(new_kv_struct, 1), value_asr_type, *module); + llvm_utils->deepcopy(key, llvm_utils->create_gep(new_kv_struct, 0), key_asr_type, module, name2memidx); + llvm_utils->deepcopy(value, llvm_utils->create_gep(new_kv_struct, 1), value_asr_type, module, name2memidx); LLVM::CreateStore(*builder, llvm::ConstantPointerNull::get(llvm::Type::getInt8PtrTy(context)), llvm_utils->create_gep(new_kv_struct, 2)); @@ -1420,8 +1498,8 @@ namespace LFortran { llvm_utils->start_new_block(elseBB); { llvm::Value* kv_struct = builder->CreateBitCast(kv_struct_i8, kv_struct_type->getPointerTo()); - llvm_utils->deepcopy(key, llvm_utils->create_gep(kv_struct, 0), key_asr_type, *module); - llvm_utils->deepcopy(value, llvm_utils->create_gep(kv_struct, 1), value_asr_type, *module); + llvm_utils->deepcopy(key, llvm_utils->create_gep(kv_struct, 0), key_asr_type, module, name2memidx); + llvm_utils->deepcopy(value, llvm_utils->create_gep(kv_struct, 1), value_asr_type, module, name2memidx); } llvm_utils->start_new_block(mergeBB); llvm::Value* occupancy_ptr = get_pointer_to_occupancy(dict); @@ -1455,7 +1533,7 @@ namespace LFortran { llvm::Value* capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); this->resolve_collision(capacity, key_hash, key, key_list, key_mask, module, key_asr_type, true); llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* item = llvm_utils->list_api->read_item(value_list, pos, true, false); + llvm::Value* item = llvm_utils->list_api->read_item(value_list, pos, false, module, true); return item; } @@ -1493,9 +1571,8 @@ namespace LFortran { llvm::BasicBlock *elseBB_single_match = llvm::BasicBlock::Create(context, "else"); llvm::BasicBlock *mergeBB_single_match = llvm::BasicBlock::Create(context, "ifcont"); llvm::Value* is_key_matching = llvm_utils->is_equal_by_value(key, - llvm_utils->list_api->read_item(key_list, key_hash, - LLVM::is_llvm_struct(key_asr_type), false), - module, key_asr_type); + llvm_utils->list_api->read_item(key_list, key_hash, false, module, + LLVM::is_llvm_struct(key_asr_type)), module, key_asr_type); builder->CreateCondBr(is_key_matching, thenBB_single_match, elseBB_single_match); builder->SetInsertPoint(thenBB_single_match); LLVM::CreateStore(*builder, key_hash, pos_ptr); @@ -1505,7 +1582,7 @@ namespace LFortran { std::string message = "The dict does not contain the specified key"; llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("KeyError: %s\n"); llvm::Value *fmt_ptr2 = builder->CreateGlobalStringPtr(message); - printf(context, module, *builder, {fmt_ptr, fmt_ptr2}); + print_error(context, module, *builder, {fmt_ptr, fmt_ptr2}); int exit_code_int = 1; llvm::Value *exit_code = llvm::ConstantInt::get(context, llvm::APInt(32, exit_code_int)); @@ -1521,7 +1598,8 @@ namespace LFortran { } llvm_utils->start_new_block(mergeBB); llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* item = llvm_utils->list_api->read_item(value_list, pos, true, false); + llvm::Value* item = llvm_utils->list_api->read_item(value_list, pos, + false, module, true); return item; } @@ -1575,7 +1653,7 @@ namespace LFortran { std::string message = "The dict does not contain the specified key"; llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("KeyError: %s\n"); llvm::Value *fmt_ptr2 = builder->CreateGlobalStringPtr(message); - printf(context, module, *builder, {fmt_ptr, fmt_ptr2}); + print_error(context, module, *builder, {fmt_ptr, fmt_ptr2}); int exit_code_int = 1; llvm::Value *exit_code = llvm::ConstantInt::get(context, llvm::APInt(32, exit_code_int)); @@ -1688,8 +1766,9 @@ namespace LFortran { } void LLVMDict::rehash(llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type) { + ASR::ttype_t* key_asr_type, + ASR::ttype_t* value_asr_type, + std::map>& name2memidx) { llvm::Value* capacity_ptr = get_pointer_to_capacity(dict); llvm::Value* old_capacity = LLVM::CreateLoad(*builder, capacity_ptr); llvm::Value* capacity = builder->CreateMul(old_capacity, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), @@ -1757,19 +1836,19 @@ namespace LFortran { builder->SetInsertPoint(thenBB); { llvm::Value* key = llvm_utils->list_api->read_item(key_list, idx, - LLVM::is_llvm_struct(key_asr_type), false); - llvm::Value* value = llvm_utils->list_api->read_item(value_list, idx, - LLVM::is_llvm_struct(value_asr_type), false); + false, *module, LLVM::is_llvm_struct(key_asr_type)); + llvm::Value* value = llvm_utils->list_api->read_item(value_list, + idx, false, *module, LLVM::is_llvm_struct(value_asr_type)); llvm::Value* key_hash = get_key_hash(current_capacity, key, key_asr_type, *module); this->resolve_collision(current_capacity, key_hash, key, new_key_list, new_key_mask, *module, key_asr_type); llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr); - llvm::Value* key_dest = llvm_utils->list_api->read_item(new_key_list, pos, - true, false); - llvm_utils->deepcopy(key, key_dest, key_asr_type, *module); - llvm::Value* value_dest = llvm_utils->list_api->read_item(new_value_list, pos, - true, false); - llvm_utils->deepcopy(value, value_dest, value_asr_type, *module); + llvm::Value* key_dest = llvm_utils->list_api->read_item( + new_key_list, pos, false, *module, true); + llvm_utils->deepcopy(key, key_dest, key_asr_type, module, name2memidx); + llvm::Value* value_dest = llvm_utils->list_api->read_item( + new_value_list, pos, false, *module, true); + llvm_utils->deepcopy(value, value_dest, value_asr_type, module, name2memidx); llvm::Value* linear_prob_happened = builder->CreateICmpNE(key_hash, pos); llvm::Value* set_max_2 = builder->CreateSelect(linear_prob_happened, @@ -1804,7 +1883,8 @@ namespace LFortran { void LLVMDictSeparateChaining::rehash( llvm::Value* dict, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type) { + ASR::ttype_t* value_asr_type, + std::map>& name2memidx) { if( !are_iterators_set ) { old_capacity = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); old_occupancy = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); @@ -1883,7 +1963,7 @@ namespace LFortran { { llvm::Value* srci = llvm_utils->create_ptr_gep(old_key_value_pairs_value, itr); - write_key_value_pair_linked_list(srci, dict, capacity, key_asr_type, value_asr_type, module); + write_key_value_pair_linked_list(srci, dict, capacity, key_asr_type, value_asr_type, module, name2memidx); } builder->CreateBr(mergeBB); llvm_utils->start_new_block(elseBB); @@ -1929,7 +2009,8 @@ namespace LFortran { } void LLVMDict::rehash_all_at_once_if_needed(llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type) { + ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, + std::map>& name2memidx) { llvm::Function *fn = builder->GetInsertBlock()->getParent(); llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); @@ -1951,7 +2032,7 @@ namespace LFortran { builder->CreateCondBr(rehash_condition, thenBB, elseBB); builder->SetInsertPoint(thenBB); { - rehash(dict, module, key_asr_type, value_asr_type); + rehash(dict, module, key_asr_type, value_asr_type, name2memidx); } builder->CreateBr(mergeBB); @@ -1961,7 +2042,8 @@ namespace LFortran { void LLVMDictSeparateChaining::rehash_all_at_once_if_needed( llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type) { + ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, + std::map>& name2memidx) { llvm::Function *fn = builder->GetInsertBlock()->getParent(); llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); llvm::BasicBlock *elseBB = llvm::BasicBlock::Create(context, "else"); @@ -1982,7 +2064,7 @@ namespace LFortran { builder->CreateCondBr(rehash_condition, thenBB, elseBB); builder->SetInsertPoint(thenBB); { - rehash(dict, module, key_asr_type, value_asr_type); + rehash(dict, module, key_asr_type, value_asr_type, name2memidx); } builder->CreateBr(mergeBB); @@ -1992,22 +2074,24 @@ namespace LFortran { void LLVMDict::write_item(llvm::Value* dict, llvm::Value* key, llvm::Value* value, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type) { - rehash_all_at_once_if_needed(dict, module, key_asr_type, value_asr_type); + ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, + std::map>& name2memidx) { + rehash_all_at_once_if_needed(dict, module, key_asr_type, value_asr_type, name2memidx); llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); llvm::Value* key_hash = get_key_hash(current_capacity, key, key_asr_type, *module); this->resolve_collision_for_write(dict, key_hash, key, value, module, - key_asr_type, value_asr_type); + key_asr_type, value_asr_type, name2memidx); } void LLVMDictSeparateChaining::write_item(llvm::Value* dict, llvm::Value* key, llvm::Value* value, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type) { - rehash_all_at_once_if_needed(dict, module, key_asr_type, value_asr_type); + ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, + std::map>& name2memidx) { + rehash_all_at_once_if_needed(dict, module, key_asr_type, value_asr_type, name2memidx); llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_capacity(dict)); llvm::Value* key_hash = get_key_hash(current_capacity, key, key_asr_type, *module); this->resolve_collision_for_write(dict, key_hash, key, value, module, - key_asr_type, value_asr_type); + key_asr_type, value_asr_type, name2memidx); } llvm::Value* LLVMDict::read_item(llvm::Value* dict, llvm::Value* key, @@ -2143,10 +2227,11 @@ namespace LFortran { return LLVM::CreateLoad(*builder, value_ptr); } - llvm::Value* LLVMList::read_item(llvm::Value* list, llvm::Value* pos, bool get_pointer, - bool check_index_bound) { - if( check_index_bound ) { - check_index_within_bounds(list, pos); + llvm::Value* LLVMList::read_item(llvm::Value* list, llvm::Value* pos, + bool enable_bounds_checking, + llvm::Module& module, bool get_pointer) { + if( enable_bounds_checking ) { + check_index_within_bounds(list, pos, module); } llvm::Value* list_data = LLVM::CreateLoad(*builder, get_pointer_to_list_data(list)); llvm::Value* element_ptr = llvm_utils->create_ptr_gep(list_data, pos); @@ -2190,7 +2275,7 @@ namespace LFortran { void LLVMList::resize_if_needed(llvm::Value* list, llvm::Value* n, llvm::Value* capacity, int32_t type_size, - llvm::Type* el_type, llvm::Module& module) { + llvm::Type* el_type, llvm::Module* module) { llvm::Value *cond = builder->CreateICmpEQ(n, capacity); llvm::Function *fn = builder->GetInsertBlock()->getParent(); llvm::BasicBlock *thenBB = llvm::BasicBlock::Create(context, "then", fn); @@ -2207,7 +2292,7 @@ namespace LFortran { new_capacity); llvm::Value* copy_data_ptr = get_pointer_to_list_data(list); llvm::Value* copy_data = LLVM::CreateLoad(*builder, copy_data_ptr); - copy_data = LLVM::lfortran_realloc(context, module, *builder, + copy_data = LLVM::lfortran_realloc(context, *module, *builder, copy_data, arg_size); copy_data = builder->CreateBitCast(copy_data, el_type->getPointerTo()); builder->CreateStore(copy_data, copy_data_ptr); @@ -2225,7 +2310,8 @@ namespace LFortran { } void LLVMList::append(llvm::Value* list, llvm::Value* item, - ASR::ttype_t* asr_type, llvm::Module& module) { + ASR::ttype_t* asr_type, llvm::Module* module, + std::map>& name2memidx) { llvm::Value* current_end_point = LLVM::CreateLoad(*builder, get_pointer_to_current_end_point(list)); llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_current_capacity(list)); std::string type_code = ASRUtils::get_type_code(asr_type); @@ -2233,13 +2319,14 @@ namespace LFortran { llvm::Type* el_type = std::get<2>(typecode2listtype[type_code]); resize_if_needed(list, current_end_point, current_capacity, type_size, el_type, module); - write_item(list, current_end_point, item, asr_type, module); + write_item(list, current_end_point, item, asr_type, false, module, name2memidx); shift_end_point_by_one(list); } void LLVMList::insert_item(llvm::Value* list, llvm::Value* pos, llvm::Value* item, ASR::ttype_t* asr_type, - llvm::Module& module) { + llvm::Module* module, + std::map>& name2memidx) { std::string type_code = ASRUtils::get_type_code(asr_type); llvm::Value* current_end_point = LLVM::CreateLoad(*builder, get_pointer_to_current_end_point(list)); @@ -2271,7 +2358,7 @@ namespace LFortran { // LLVMList should treat them as data members and create them // only if they are NULL llvm::AllocaInst *tmp_ptr = builder->CreateAlloca(el_type, nullptr); - LLVM::CreateStore(*builder, read_item(list, pos, false), tmp_ptr); + LLVM::CreateStore(*builder, read_item(list, pos, false, *module, false), tmp_ptr); llvm::Value* tmp = nullptr; // TODO: Should be created outside the user loop and not here. @@ -2300,8 +2387,8 @@ namespace LFortran { llvm::Value* next_index = builder->CreateAdd( LLVM::CreateLoad(*builder, pos_ptr), llvm::ConstantInt::get(context, llvm::APInt(32, 1))); - tmp = read_item(list, next_index, false); - write_item(list, next_index, LLVM::CreateLoad(*builder, tmp_ptr)); + tmp = read_item(list, next_index, false, *module, false); + write_item(list, next_index, LLVM::CreateLoad(*builder, tmp_ptr), false, *module); LLVM::CreateStore(*builder, tmp, tmp_ptr); tmp = builder->CreateAdd( @@ -2314,7 +2401,7 @@ namespace LFortran { // end llvm_utils->start_new_block(loopend); - write_item(list, pos, item, asr_type, module); + write_item(list, pos, item, asr_type, false, module, name2memidx); shift_end_point_by_one(list); } @@ -2350,7 +2437,7 @@ namespace LFortran { llvm_utils->start_new_block(loophead); { llvm::Value* left_arg = read_item(list, LLVM::CreateLoad(*builder, i), - LLVM::is_llvm_struct(item_type)); + false, module, LLVM::is_llvm_struct(item_type)); llvm::Value* is_item_not_equal = builder->CreateNot( llvm_utils->is_equal_by_value( left_arg, item, @@ -2386,12 +2473,10 @@ namespace LFortran { builder->CreateCondBr(cond, thenBB, elseBB); builder->SetInsertPoint(thenBB); { - // TODO: Allow runtime information like the exact element which is - // not found. - std::string message = "The list does not contain the element"; - llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("ValueError: %s\n"); + std::string message = "The list does not contain the element: "; + llvm::Value *fmt_ptr = builder->CreateGlobalStringPtr("ValueError: %s%d\n"); llvm::Value *fmt_ptr2 = builder->CreateGlobalStringPtr(message); - printf(context, module, *builder, {fmt_ptr, fmt_ptr2}); + print_error(context, module, *builder, {fmt_ptr, fmt_ptr2, item}); int exit_code_int = 1; llvm::Value *exit_code = llvm::ConstantInt::get(context, llvm::APInt(32, exit_code_int)); @@ -2445,7 +2530,7 @@ namespace LFortran { LLVM::CreateLoad(*builder, item_pos), llvm::ConstantInt::get(context, llvm::APInt(32, 1))); write_item(list, LLVM::CreateLoad(*builder, item_pos), - read_item(list, tmp, false)); + read_item(list, tmp, false, module, false), false, module); LLVM::CreateStore(*builder, tmp, item_pos); } builder->CreateBr(loophead); @@ -2514,14 +2599,16 @@ namespace LFortran { } void LLVMTuple::tuple_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Tuple_t* tuple_type, llvm::Module& module) { + ASR::Tuple_t* tuple_type, llvm::Module* module, + std::map>& name2memidx) { LFORTRAN_ASSERT(src->getType() == dest->getType()); for( size_t i = 0; i < tuple_type->n_type; i++ ) { llvm::Value* src_item = read_item(src, i, LLVM::is_llvm_struct( tuple_type->m_type[i])); llvm::Value* dest_item_ptr = read_item(dest, i, true); llvm_utils->deepcopy(src_item, dest_item_ptr, - tuple_type->m_type[i], module); + tuple_type->m_type[i], module, + name2memidx); } } diff --git a/src/libasr/codegen/llvm_utils.h b/src/libasr/codegen/llvm_utils.h index 9341360..2e89424 100644 --- a/src/libasr/codegen/llvm_utils.h +++ b/src/libasr/codegen/llvm_utils.h @@ -12,6 +12,10 @@ namespace LFortran { + namespace LLVMArrUtils { + class Descriptor; + } + static inline void printf(llvm::LLVMContext &context, llvm::Module &module, llvm::IRBuilder<> &builder, const std::vector &args) { @@ -25,6 +29,19 @@ namespace LFortran { builder.CreateCall(fn_printf, args); } + static inline void print_error(llvm::LLVMContext &context, llvm::Module &module, + llvm::IRBuilder<> &builder, const std::vector &args) + { + llvm::Function *fn_printf = module.getFunction("_lcompilers_print_error"); + if (!fn_printf) { + llvm::FunctionType *function_type = llvm::FunctionType::get( + llvm::Type::getVoidTy(context), {llvm::Type::getInt8PtrTy(context)}, true); + fn_printf = llvm::Function::Create(function_type, + llvm::Function::ExternalLinkage, "_lcompilers_print_error", &module); + } + builder.CreateCall(fn_printf, args); + } + static inline void exit(llvm::LLVMContext &context, llvm::Module &module, llvm::IRBuilder<> &builder, llvm::Value* exit_code) { @@ -80,6 +97,7 @@ namespace LFortran { LLVMTuple* tuple_api; LLVMList* list_api; LLVMDictInterface* dict_api; + LLVMArrUtils::Descriptor* arr_api; LLVMUtils(llvm::LLVMContext& context, llvm::IRBuilder<>* _builder); @@ -107,7 +125,8 @@ namespace LFortran { void reset_iterators(); void deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::ttype_t* asr_type, llvm::Module& module); + ASR::ttype_t* asr_type, llvm::Module* module, + std::map>& name2memidx); }; // LLVMUtils @@ -122,7 +141,7 @@ namespace LFortran { void resize_if_needed(llvm::Value* list, llvm::Value* n, llvm::Value* capacity, int32_t type_size, - llvm::Type* el_type, llvm::Module& module); + llvm::Type* el_type, llvm::Module* module); void shift_end_point_by_one(llvm::Value* list); @@ -149,33 +168,39 @@ namespace LFortran { llvm::Value* get_pointer_to_current_capacity(llvm::Value* list); void list_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::List_t* list_type, - llvm::Module& module); + ASR::List_t* list_type, llvm::Module* module, + std::map>& name2memidx); void list_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::ttype_t* element_type, - llvm::Module& module); + ASR::ttype_t* element_type, llvm::Module* module, + std::map>& name2memidx); llvm::Value* read_item(llvm::Value* list, llvm::Value* pos, - bool get_pointer=false, bool check_index_bound=true); + bool enable_bounds_checking, + llvm::Module& module, bool get_pointer=false); llvm::Value* len(llvm::Value* list); - void check_index_within_bounds(llvm::Value* list, llvm::Value* pos); + void check_index_within_bounds(llvm::Value* list, llvm::Value* pos, + llvm::Module& module); void write_item(llvm::Value* list, llvm::Value* pos, - llvm::Value* item, ASR::ttype_t* asr_type, - llvm::Module& module, bool check_index_bound=true); + llvm::Value* item, ASR::ttype_t* asr_type, + bool enable_bounds_checking, llvm::Module* module, + std::map>& name2memidx); void write_item(llvm::Value* list, llvm::Value* pos, - llvm::Value* item, bool check_index_bound=true); + llvm::Value* item, bool enable_bounds_checking, + llvm::Module& module); void append(llvm::Value* list, llvm::Value* item, - ASR::ttype_t* asr_type, llvm::Module& module); + ASR::ttype_t* asr_type, llvm::Module* module, + std::map>& name2memidx); void insert_item(llvm::Value* list, llvm::Value* pos, llvm::Value* item, ASR::ttype_t* asr_type, - llvm::Module& module); + llvm::Module* module, + std::map>& name2memidx); void remove(llvm::Value* list, llvm::Value* item, ASR::ttype_t* item_type, llvm::Module& module); @@ -216,7 +241,8 @@ namespace LFortran { bool get_pointer=false); void tuple_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Tuple_t* type_code, llvm::Module& module); + ASR::Tuple_t* type_code, llvm::Module* module, + std::map>& name2memidx); llvm::Value* check_tuple_equality(llvm::Value* t1, llvm::Value* t2, ASR::Tuple_t* tuple_type, llvm::LLVMContext& context, @@ -282,7 +308,8 @@ namespace LFortran { void resolve_collision_for_write(llvm::Value* dict, llvm::Value* key_hash, llvm::Value* key, llvm::Value* value, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type) = 0; + ASR::ttype_t* value_asr_type, + std::map>& name2memidx) = 0; virtual llvm::Value* resolve_collision_for_read(llvm::Value* dict, llvm::Value* key_hash, @@ -291,19 +318,21 @@ namespace LFortran { virtual void rehash(llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type) = 0; + ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, + std::map>& name2memidx) = 0; virtual void rehash_all_at_once_if_needed(llvm::Value* dict, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type) = 0; + ASR::ttype_t* value_asr_type, + std::map>& name2memidx) = 0; virtual void write_item(llvm::Value* dict, llvm::Value* key, llvm::Value* value, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type) = 0; + ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, + std::map>& name2memidx) = 0; virtual llvm::Value* read_item(llvm::Value* dict, llvm::Value* key, @@ -323,7 +352,8 @@ namespace LFortran { virtual void dict_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Dict_t* dict_type, llvm::Module* module) = 0; + ASR::Dict_t* dict_type, llvm::Module* module, + std::map>& name2memidx) = 0; virtual llvm::Value* len(llvm::Value* dict) = 0; @@ -370,24 +400,27 @@ namespace LFortran { void resolve_collision_for_write(llvm::Value* dict, llvm::Value* key_hash, llvm::Value* key, llvm::Value* value, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type); + ASR::ttype_t* value_asr_type, + std::map>& name2memidx); llvm::Value* resolve_collision_for_read(llvm::Value* dict, llvm::Value* key_hash, llvm::Value* key, llvm::Module& module, ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type); void rehash(llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type); + ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, + std::map>& name2memidx); void rehash_all_at_once_if_needed(llvm::Value* dict, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type); + ASR::ttype_t* value_asr_type, + std::map>& name2memidx); void write_item(llvm::Value* dict, llvm::Value* key, llvm::Value* value, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type); + ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, + std::map>& name2memidx); llvm::Value* read_item(llvm::Value* dict, llvm::Value* key, llvm::Module& module, ASR::Dict_t* key_asr_type, @@ -401,7 +434,8 @@ namespace LFortran { llvm::Value* get_pointer_to_keymask(llvm::Value* dict); void dict_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Dict_t* dict_type, llvm::Module* module); + ASR::Dict_t* dict_type, llvm::Module* module, + std::map>& name2memidx); llvm::Value* len(llvm::Value* dict); @@ -424,7 +458,8 @@ namespace LFortran { void resolve_collision_for_write(llvm::Value* dict, llvm::Value* key_hash, llvm::Value* key, llvm::Value* value, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type); + ASR::ttype_t* value_asr_type, + std::map>& name2memidx); llvm::Value* resolve_collision_for_read(llvm::Value* dict, llvm::Value* key_hash, llvm::Value* key, llvm::Module& module, @@ -448,11 +483,11 @@ namespace LFortran { void deepcopy_key_value_pair_linked_list(llvm::Value* srci, llvm::Value* desti, llvm::Value* dest_key_value_pairs, llvm::Value* src_capacity, ASR::Dict_t* dict_type, - llvm::Module* module); + llvm::Module* module, std::map>& name2memidx); void write_key_value_pair_linked_list(llvm::Value* kv_ll, llvm::Value* dict, llvm::Value* capacity, ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, - llvm::Module* module); + llvm::Module* module, std::map>& name2memidx); void resolve_collision(llvm::Value* capacity, llvm::Value* key_hash, llvm::Value* key, llvm::Value* key_value_pair_linked_list, @@ -491,24 +526,27 @@ namespace LFortran { void resolve_collision_for_write(llvm::Value* dict, llvm::Value* key_hash, llvm::Value* key, llvm::Value* value, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type); + ASR::ttype_t* value_asr_type, + std::map>& name2memidx); llvm::Value* resolve_collision_for_read(llvm::Value* dict, llvm::Value* key_hash, llvm::Value* key, llvm::Module& module, ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type); void rehash(llvm::Value* dict, llvm::Module* module, - ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type); + ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, + std::map>& name2memidx); void rehash_all_at_once_if_needed(llvm::Value* dict, llvm::Module* module, ASR::ttype_t* key_asr_type, - ASR::ttype_t* value_asr_type); + ASR::ttype_t* value_asr_type, + std::map>& name2memidx); void write_item(llvm::Value* dict, llvm::Value* key, llvm::Value* value, llvm::Module* module, - ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type); + ASR::ttype_t* key_asr_type, ASR::ttype_t* value_asr_type, + std::map>& name2memidx); llvm::Value* read_item(llvm::Value* dict, llvm::Value* key, llvm::Module& module, ASR::Dict_t* dict_type, @@ -521,7 +559,8 @@ namespace LFortran { llvm::Value* get_pointer_to_keymask(llvm::Value* dict); void dict_deepcopy(llvm::Value* src, llvm::Value* dest, - ASR::Dict_t* dict_type, llvm::Module* module); + ASR::Dict_t* dict_type, llvm::Module* module, + std::map>& name2memidx); llvm::Value* len(llvm::Value* dict); diff --git a/src/libasr/codegen/wasm_decoder.h b/src/libasr/codegen/wasm_decoder.h new file mode 100644 index 0000000..0336071 --- /dev/null +++ b/src/libasr/codegen/wasm_decoder.h @@ -0,0 +1,333 @@ +#ifndef LFORTRAN_WASM_DECODER_H +#define LFORTRAN_WASM_DECODER_H + +#include + +#include +#include +#include +#include + +// #define WAT_DEBUG + +#ifdef WAT_DEBUG +#define DEBUG(s) std::cout << s << std::endl +#else +#define DEBUG(s) +#endif + +namespace LFortran { + +namespace { + +// This exception is used to abort the visitor pattern when an error occurs. +class CodeGenAbort {}; + +// Local exception that is only used in this file to exit the visitor +// pattern and caught later (not propagated outside) +class CodeGenError { + public: + diag::Diagnostic d; + + public: + CodeGenError(const std::string &msg) + : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} {} + + CodeGenError(const std::string &msg, const Location &loc) + : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen, + {diag::Label("", {loc})})} {} +}; + +} // namespace + +namespace wasm { + +template +class WASMDecoder { + private: + Struct &self() { return static_cast(*this); } + + public: + std::unordered_map var_type_to_string; + std::unordered_map kind_to_string; + + Allocator &al; + diag::Diagnostics &diag; + Vec wasm_bytes; + size_t PREAMBLE_SIZE; + + Vec func_types; + Vec imports; + Vec type_indices; + Vec exports; + Vec codes; + Vec data_segments; + + WASMDecoder(Allocator &al, diag::Diagnostics &diagonostics) + : al(al), diag(diagonostics) { + var_type_to_string = { + {0x7F, "i32"}, {0x7E, "i64"}, {0x7D, "f32"}, {0x7C, "f64"}}; + kind_to_string = { + {0x00, "func"}, {0x01, "table"}, {0x02, "mem"}, {0x03, "global"}}; + + PREAMBLE_SIZE = 8 /* BYTES */; + // wasm_bytes.reserve(al, 1024 * 128); + // func_types.reserve(al, 1024 * 128); + // type_indices.reserve(al, 1024 * 128); + // exports.reserve(al, 1024 * 128); + // codes.reserve(al, 1024 * 128); + } + + void load_file(std::string filename) { + std::ifstream file(filename, std::ios::binary); + file.seekg(0, std::ios::end); + size_t size = file.tellg(); + file.seekg(0, std::ios::beg); + wasm_bytes.reserve(al, size); + file.read((char *)wasm_bytes.data(), size); + file.close(); + } + + bool is_preamble_ok(uint32_t offset) { + uint8_t expected_preamble[] = {0x00, 0x61, 0x73, 0x6D, + 0x01, 0x00, 0x00, 0x00}; + for (size_t i = 0; i < PREAMBLE_SIZE; i++) { + uint8_t cur_byte = read_b8(wasm_bytes, offset); + if (cur_byte != expected_preamble[i]) { + return false; + } + } + return true; + } + + void decode_type_section(uint32_t offset) { + // read type section contents + uint32_t no_of_func_types = read_u32(wasm_bytes, offset); + DEBUG("no_of_func_types: " + std::to_string(no_of_func_types)); + func_types.resize(al, no_of_func_types); + + for (uint32_t i = 0; i < no_of_func_types; i++) { + if (wasm_bytes[offset] != 0x60) { + throw CodeGenError("Invalid type section"); + } + offset++; + + // read result type 1 + uint32_t no_of_params = read_u32(wasm_bytes, offset); + func_types.p[i].param_types.resize(al, no_of_params); + + for (uint32_t j = 0; j < no_of_params; j++) { + func_types.p[i].param_types.p[j] = read_b8(wasm_bytes, offset); + } + + uint32_t no_of_results = read_u32(wasm_bytes, offset); + func_types.p[i].result_types.resize(al, no_of_results); + + for (uint32_t j = 0; j < no_of_results; j++) { + func_types.p[i].result_types.p[j] = read_b8(wasm_bytes, offset); + } + } + } + + void decode_imports_section(uint32_t offset) { + // read imports section contents + uint32_t no_of_imports = read_u32(wasm_bytes, offset); + DEBUG("no_of_imports: " + std::to_string(no_of_imports)); + imports.resize(al, no_of_imports); + + for (uint32_t i = 0; i < no_of_imports; i++) { + uint32_t mod_name_size = read_u32(wasm_bytes, offset); + imports.p[i].mod_name.resize( + mod_name_size); // do not pass al to this resize as it is + // std::string.resize() + for (uint32_t j = 0; j < mod_name_size; j++) { + imports.p[i].mod_name[j] = read_b8(wasm_bytes, offset); + } + + uint32_t name_size = read_u32(wasm_bytes, offset); + imports.p[i].name.resize( + name_size); // do not pass al to this resize as it is + // std::string.resize() + for (uint32_t j = 0; j < name_size; j++) { + imports.p[i].name[j] = read_b8(wasm_bytes, offset); + } + + imports.p[i].kind = read_b8(wasm_bytes, offset); + + switch (imports.p[i].kind) { + case 0x00: { + imports.p[i].type_idx = read_u32(wasm_bytes, offset); + break; + } + case 0x02: { + uint8_t byte = read_b8(wasm_bytes, offset); + if (byte == 0x00) { + imports.p[i].mem_page_size_limits.first = + read_u32(wasm_bytes, offset); + imports.p[i].mem_page_size_limits.second = + imports.p[i].mem_page_size_limits.first; + } else { + LFORTRAN_ASSERT(byte == 0x01); + imports.p[i].mem_page_size_limits.first = + read_u32(wasm_bytes, offset); + imports.p[i].mem_page_size_limits.second = + read_u32(wasm_bytes, offset); + } + break; + } + + default: { + throw CodeGenError( + "Only importing functions and memory are currently " + "supported"); + } + } + } + } + + void decode_function_section(uint32_t offset) { + // read function section contents + uint32_t no_of_indices = read_u32(wasm_bytes, offset); + DEBUG("no_of_indices: " + std::to_string(no_of_indices)); + type_indices.resize(al, no_of_indices); + + for (uint32_t i = 0; i < no_of_indices; i++) { + type_indices.p[i] = read_u32(wasm_bytes, offset); + } + } + + void decode_export_section(uint32_t offset) { + // read export section contents + uint32_t no_of_exports = read_u32(wasm_bytes, offset); + DEBUG("no_of_exports: " + std::to_string(no_of_exports)); + exports.resize(al, no_of_exports); + + for (uint32_t i = 0; i < no_of_exports; i++) { + uint32_t name_size = read_u32(wasm_bytes, offset); + exports.p[i].name.resize( + name_size); // do not pass al to this resize as it is + // std::string.resize() + for (uint32_t j = 0; j < name_size; j++) { + exports.p[i].name[j] = read_b8(wasm_bytes, offset); + } + DEBUG("export name: " + exports.p[i].name); + exports.p[i].kind = read_b8(wasm_bytes, offset); + DEBUG("export kind: " + std::to_string(exports.p[i].kind)); + exports.p[i].index = read_u32(wasm_bytes, offset); + DEBUG("export index: " + std::to_string(exports.p[i].index)); + } + } + + void decode_code_section(uint32_t offset) { + // read code section contents + uint32_t no_of_codes = read_u32(wasm_bytes, offset); + DEBUG("no_of_codes: " + std::to_string(no_of_codes)); + codes.resize(al, no_of_codes); + + for (uint32_t i = 0; i < no_of_codes; i++) { + codes.p[i].size = read_u32(wasm_bytes, offset); + uint32_t code_start_offset = offset; + uint32_t no_of_locals = read_u32(wasm_bytes, offset); + DEBUG("no_of_locals: " + std::to_string(no_of_locals)); + codes.p[i].locals.resize(al, no_of_locals); + + DEBUG("Entering loop"); + for (uint32_t j = 0U; j < no_of_locals; j++) { + codes.p[i].locals.p[j].count = read_u32(wasm_bytes, offset); + DEBUG("count: " + std::to_string(codes.p[i].locals.p[j].count)); + codes.p[i].locals.p[j].type = read_b8(wasm_bytes, offset); + DEBUG("type: " + std::to_string(codes.p[i].locals.p[j].type)); + } + DEBUG("Exiting loop"); + + codes.p[i].insts_start_index = offset; + + // skip offset to directly the end of instructions + offset = code_start_offset + codes.p[i].size; + } + } + + void decode_data_section(uint32_t offset) { + // read code section contents + uint32_t no_of_data_segments = read_u32(wasm_bytes, offset); + DEBUG("no_of_data_segments: " + std::to_string(no_of_data_segments)); + data_segments.resize(al, no_of_data_segments); + + for (uint32_t i = 0; i < no_of_data_segments; i++) { + uint32_t num = read_u32(wasm_bytes, offset); + if (num != 0) { + throw CodeGenError( + "Only active default memory (index = 0) is currently " + "supported"); + } + + data_segments.p[i].insts_start_index = offset; + while (read_b8(wasm_bytes, offset) != 0x0B) + ; + + uint32_t text_size = read_u32(wasm_bytes, offset); + data_segments.p[i].text.resize( + text_size); // do not pass al to this resize as it is + // std::string.resize() + for (uint32_t j = 0; j < text_size; j++) { + data_segments.p[i].text[j] = read_b8(wasm_bytes, offset); + } + } + } + void decode_wasm() { + // first 8 bytes are magic number and wasm version number + uint32_t index = 0; + if (!is_preamble_ok(index)) { + std::cerr << "Unexpected Preamble: "; + for (size_t i = 0; i < PREAMBLE_SIZE; i++) { + fprintf(stderr, "0x%.02X, ", wasm_bytes[i]); + } + throw CodeGenError( + "Expected: 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00"); + } + index += PREAMBLE_SIZE; + while (index < wasm_bytes.size()) { + uint32_t section_id = read_u32(wasm_bytes, index); + uint32_t section_size = read_u32(wasm_bytes, index); + switch (section_id) { + case 1U: + decode_type_section(index); + // exit(0); + break; + case 2U: + decode_imports_section(index); + // exit(0); + break; + case 3U: + decode_function_section(index); + // exit(0); + break; + case 7U: + decode_export_section(index); + // exit(0); + break; + case 10U: + decode_code_section(index); + // exit(0) + break; + case 11U: + decode_data_section(index); + // exit(0) + break; + default: + std::cout << "Unknown section id: " << section_id + << std::endl; + break; + } + index += section_size; + } + + LFORTRAN_ASSERT(index == wasm_bytes.size()); + LFORTRAN_ASSERT(type_indices.size() == codes.size()); + } +}; + +} // namespace wasm +} // namespace LFortran + +#endif // LFORTRAN_WASM_DECODER_H diff --git a/src/libasr/codegen/wasm_to_wat.cpp b/src/libasr/codegen/wasm_to_wat.cpp index 4154f60..ea3f528 100644 --- a/src/libasr/codegen/wasm_to_wat.cpp +++ b/src/libasr/codegen/wasm_to_wat.cpp @@ -1,325 +1,17 @@ #include #include +#include #include -// #define WAT_DEBUG - -#ifdef WAT_DEBUG -#define DEBUG(s) std::cout << s << std::endl -#else -#define DEBUG(s) -#endif - namespace LFortran { -namespace { - -// This exception is used to abort the visitor pattern when an error occurs. -class CodeGenAbort {}; - -// Local exception that is only used in this file to exit the visitor -// pattern and caught later (not propagated outside) -class CodeGenError { - public: - diag::Diagnostic d; - - public: - CodeGenError(const std::string &msg) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)} {} - - CodeGenError(const std::string &msg, const Location &loc) - : d{diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen, - {diag::Label("", {loc})})} {} -}; - -} // namespace - namespace wasm { -class WASMDecoder { +class WATGenerator : public WASMDecoder { public: - std::unordered_map var_type_to_string; - std::unordered_map kind_to_string; - - Allocator &al; - diag::Diagnostics &diag; - Vec wasm_bytes; - size_t PREAMBLE_SIZE; - - Vec func_types; - Vec imports; - Vec type_indices; - Vec exports; - Vec codes; - Vec data_segments; - - WASMDecoder(Allocator &al, diag::Diagnostics &diagonostics) - : al(al), diag(diagonostics) { - var_type_to_string = { - {0x7F, "i32"}, {0x7E, "i64"}, {0x7D, "f32"}, {0x7C, "f64"}}; - kind_to_string = { - {0x00, "func"}, {0x01, "table"}, {0x02, "mem"}, {0x03, "global"}}; - - PREAMBLE_SIZE = 8 /* BYTES */; - // wasm_bytes.reserve(al, 1024 * 128); - // func_types.reserve(al, 1024 * 128); - // type_indices.reserve(al, 1024 * 128); - // exports.reserve(al, 1024 * 128); - // codes.reserve(al, 1024 * 128); - } - - void load_file(std::string filename) { - std::ifstream file(filename, std::ios::binary); - file.seekg(0, std::ios::end); - size_t size = file.tellg(); - file.seekg(0, std::ios::beg); - wasm_bytes.reserve(al, size); - file.read((char *)wasm_bytes.data(), size); - file.close(); - } - - bool is_preamble_ok(uint32_t offset) { - uint8_t expected_preamble[] = {0x00, 0x61, 0x73, 0x6D, - 0x01, 0x00, 0x00, 0x00}; - for (size_t i = 0; i < PREAMBLE_SIZE; i++) { - uint8_t cur_byte = read_b8(wasm_bytes, offset); - if (cur_byte != expected_preamble[i]) { - return false; - } - } - return true; - } - - void decode_type_section(uint32_t offset) { - // read type section contents - uint32_t no_of_func_types = read_u32(wasm_bytes, offset); - DEBUG("no_of_func_types: " + std::to_string(no_of_func_types)); - func_types.resize(al, no_of_func_types); - - for (uint32_t i = 0; i < no_of_func_types; i++) { - if (wasm_bytes[offset] != 0x60) { - throw CodeGenError("Invalid type section"); - } - offset++; - - // read result type 1 - uint32_t no_of_params = read_u32(wasm_bytes, offset); - func_types.p[i].param_types.resize(al, no_of_params); - - for (uint32_t j = 0; j < no_of_params; j++) { - func_types.p[i].param_types.p[j] = read_b8(wasm_bytes, offset); - } - - uint32_t no_of_results = read_u32(wasm_bytes, offset); - func_types.p[i].result_types.resize(al, no_of_results); - - for (uint32_t j = 0; j < no_of_results; j++) { - func_types.p[i].result_types.p[j] = read_b8(wasm_bytes, offset); - } - } - } - - void decode_imports_section(uint32_t offset) { - // read imports section contents - uint32_t no_of_imports = read_u32(wasm_bytes, offset); - DEBUG("no_of_imports: " + std::to_string(no_of_imports)); - imports.resize(al, no_of_imports); - - for (uint32_t i = 0; i < no_of_imports; i++) { - uint32_t mod_name_size = read_u32(wasm_bytes, offset); - imports.p[i].mod_name.resize( - mod_name_size); // do not pass al to this resize as it is - // std::string.resize() - for (uint32_t j = 0; j < mod_name_size; j++) { - imports.p[i].mod_name[j] = read_b8(wasm_bytes, offset); - } - - uint32_t name_size = read_u32(wasm_bytes, offset); - imports.p[i].name.resize( - name_size); // do not pass al to this resize as it is - // std::string.resize() - for (uint32_t j = 0; j < name_size; j++) { - imports.p[i].name[j] = read_b8(wasm_bytes, offset); - } - - imports.p[i].kind = read_b8(wasm_bytes, offset); - - switch (imports.p[i].kind) { - case 0x00: { - imports.p[i].type_idx = read_u32(wasm_bytes, offset); - break; - } - case 0x02: { - uint8_t byte = read_b8(wasm_bytes, offset); - if (byte == 0x00) { - imports.p[i].mem_page_size_limits.first = - read_u32(wasm_bytes, offset); - imports.p[i].mem_page_size_limits.second = - imports.p[i].mem_page_size_limits.first; - } else { - LFORTRAN_ASSERT(byte == 0x01); - imports.p[i].mem_page_size_limits.first = - read_u32(wasm_bytes, offset); - imports.p[i].mem_page_size_limits.second = - read_u32(wasm_bytes, offset); - } - break; - } - - default: { - throw CodeGenError( - "Only importing functions and memory are currently " - "supported"); - } - } - } - } - - void decode_function_section(uint32_t offset) { - // read function section contents - uint32_t no_of_indices = read_u32(wasm_bytes, offset); - DEBUG("no_of_indices: " + std::to_string(no_of_indices)); - type_indices.resize(al, no_of_indices); - - for (uint32_t i = 0; i < no_of_indices; i++) { - type_indices.p[i] = read_u32(wasm_bytes, offset); - } - } - - void decode_export_section(uint32_t offset) { - // read export section contents - uint32_t no_of_exports = read_u32(wasm_bytes, offset); - DEBUG("no_of_exports: " + std::to_string(no_of_exports)); - exports.resize(al, no_of_exports); - - for (uint32_t i = 0; i < no_of_exports; i++) { - uint32_t name_size = read_u32(wasm_bytes, offset); - exports.p[i].name.resize( - name_size); // do not pass al to this resize as it is - // std::string.resize() - for (uint32_t j = 0; j < name_size; j++) { - exports.p[i].name[j] = read_b8(wasm_bytes, offset); - } - DEBUG("export name: " + exports.p[i].name); - exports.p[i].kind = read_b8(wasm_bytes, offset); - DEBUG("export kind: " + std::to_string(exports.p[i].kind)); - exports.p[i].index = read_u32(wasm_bytes, offset); - DEBUG("export index: " + std::to_string(exports.p[i].index)); - } - } - - void decode_code_section(uint32_t offset) { - // read code section contents - uint32_t no_of_codes = read_u32(wasm_bytes, offset); - DEBUG("no_of_codes: " + std::to_string(no_of_codes)); - codes.resize(al, no_of_codes); - - for (uint32_t i = 0; i < no_of_codes; i++) { - codes.p[i].size = read_u32(wasm_bytes, offset); - uint32_t code_start_offset = offset; - uint32_t no_of_locals = read_u32(wasm_bytes, offset); - DEBUG("no_of_locals: " + std::to_string(no_of_locals)); - codes.p[i].locals.resize(al, no_of_locals); - - DEBUG("Entering loop"); - for (uint32_t j = 0U; j < no_of_locals; j++) { - codes.p[i].locals.p[j].count = read_u32(wasm_bytes, offset); - DEBUG("count: " + std::to_string(codes.p[i].locals.p[j].count)); - codes.p[i].locals.p[j].type = read_b8(wasm_bytes, offset); - DEBUG("type: " + std::to_string(codes.p[i].locals.p[j].type)); - } - DEBUG("Exiting loop"); - - codes.p[i].insts_start_index = offset; - - // skip offset to directly the end of instructions - offset = code_start_offset + codes.p[i].size; - } - } - - void decode_data_section(uint32_t offset) { - // read code section contents - uint32_t no_of_data_segments = read_u32(wasm_bytes, offset); - DEBUG("no_of_data_segments: " + std::to_string(no_of_data_segments)); - data_segments.resize(al, no_of_data_segments); - - for (uint32_t i = 0; i < no_of_data_segments; i++) { - uint32_t num = read_u32(wasm_bytes, offset); - if (num != 0) { - throw CodeGenError( - "Only active default memory (index = 0) is currently " - "supported"); - } - - { - WASM_INSTS_VISITOR::WATVisitor v = - WASM_INSTS_VISITOR::WATVisitor(wasm_bytes, offset, "", ""); - v.decode_instructions(); - data_segments.p[i].insts = v.src; - offset = v.offset; - } - - uint32_t text_size = read_u32(wasm_bytes, offset); - data_segments.p[i].text.resize( - text_size); // do not pass al to this resize as it is - // std::string.resize() - for (uint32_t j = 0; j < text_size; j++) { - data_segments.p[i].text[j] = read_b8(wasm_bytes, offset); - } - } - } - void decode_wasm() { - // first 8 bytes are magic number and wasm version number - uint32_t index = 0; - if (!is_preamble_ok(index)) { - std::cerr << "Unexpected Preamble: "; - for (size_t i = 0; i < PREAMBLE_SIZE; i++) { - fprintf(stderr, "0x%.02X, ", wasm_bytes[i]); - } - throw CodeGenError( - "Expected: 0x00, 0x61, 0x73, 0x6D, 0x01, 0x00, 0x00, 0x00"); - } - index += PREAMBLE_SIZE; - while (index < wasm_bytes.size()) { - uint32_t section_id = read_u32(wasm_bytes, index); - uint32_t section_size = read_u32(wasm_bytes, index); - switch (section_id) { - case 1U: - decode_type_section(index); - // exit(0); - break; - case 2U: - decode_imports_section(index); - // exit(0); - break; - case 3U: - decode_function_section(index); - // exit(0); - break; - case 7U: - decode_export_section(index); - // exit(0); - break; - case 10U: - decode_code_section(index); - // exit(0) - break; - case 11U: - decode_data_section(index); - // exit(0) - break; - default: - std::cout << "Unknown section id: " << section_id - << std::endl; - break; - } - index += section_size; - } - - LFORTRAN_ASSERT(index == wasm_bytes.size()); - LFORTRAN_ASSERT(type_indices.size() == codes.size()); - } + WATGenerator(Allocator &al, diag::Diagnostics &diagonostics) + : WASMDecoder(al, diagonostics) {} std::string get_wat() { std::string result = "(module"; @@ -401,8 +93,17 @@ class WASMDecoder { } for (uint32_t i = 0; i < data_segments.size(); i++) { + std::string date_segment_insts; + { + WASM_INSTS_VISITOR::WATVisitor v = + WASM_INSTS_VISITOR::WATVisitor( + wasm_bytes, data_segments.p[i].insts_start_index, "", + ""); + v.decode_instructions(); + date_segment_insts = v.src; + } result += indent + "(data (;" + std::to_string(i) + ";) (" + - data_segments[i].insts + ") \"" + data_segments[i].text + + date_segment_insts + ") \"" + data_segments[i].text + "\")"; } @@ -416,20 +117,20 @@ class WASMDecoder { Result wasm_to_wat(Vec &wasm_bytes, Allocator &al, diag::Diagnostics &diagnostics) { - wasm::WASMDecoder wasm_decoder(al, diagnostics); - wasm_decoder.wasm_bytes.from_pointer_n(wasm_bytes.data(), - wasm_bytes.size()); + wasm::WATGenerator wasm_generator(al, diagnostics); + wasm_generator.wasm_bytes.from_pointer_n(wasm_bytes.data(), + wasm_bytes.size()); std::string wat; try { - wasm_decoder.decode_wasm(); + wasm_generator.decode_wasm(); } catch (const CodeGenError &e) { diagnostics.diagnostics.push_back(e.d); return Error(); } - wat = wasm_decoder.get_wat(); + wat = wasm_generator.get_wat(); return wat; } diff --git a/src/libasr/codegen/wasm_to_x86.cpp b/src/libasr/codegen/wasm_to_x86.cpp new file mode 100644 index 0000000..1aaa00f --- /dev/null +++ b/src/libasr/codegen/wasm_to_x86.cpp @@ -0,0 +1,433 @@ +#include +#include +#include + +#include +#include +#include +#include + +namespace LFortran { + +namespace wasm { + +/* + +This X86Visitor uses stack to pass arguments and return values from functions. +Since in X86, instructions operate on registers (and not on stack), +for every instruction we pop elements from top of stack and store them into +registers. After operating on the registers, the result value is then +pushed back onto the stack. + +One of the reasons to use stack to pass function arguments is that, +it allows us to define and call functions with any number of parameters. +As registers are limited in number, if we use them to pass function arugments, +the number of arguments we could pass to a function would get limited by +the number of registers available with the CPU. + +*/ + +class X86Visitor : public WASMDecoder, + public WASM_INSTS_VISITOR::BaseWASMVisitor { + public: + X86Assembler &m_a; + uint32_t cur_func_idx; + std::vector if_unique_id; + std::vector loop_unique_id; + uint32_t cur_nesting_length; + int32_t last_vis_i32_const, last_last_vis_i32_const; + std::unordered_map loc_to_str; + + X86Visitor(X86Assembler &m_a, Allocator &al, + diag::Diagnostics &diagonostics, Vec &code) + : WASMDecoder(al, diagonostics), + BaseWASMVisitor(code, 0U /* temporary offset */), + m_a(m_a) { + wasm_bytes.from_pointer_n(code.data(), code.size()); + cur_nesting_length = 0; + } + + void visit_Unreachable() {} + + void visit_Return() {} + + void call_imported_function(uint32_t func_index) { + switch (func_index) { + case 0: { // print_i32 + m_a.asm_call_label("print_i32"); + break; + } + case 1: { // print_i64 + std::cerr << "Call to print_i64() is not yet supported"; + break; + } + case 2: { // print_f32 + std::cerr << "Call to print_f32() is not yet supported"; + break; + } + case 3: { // print_f64 + std::cerr << "Call to print_f64() is not yet supported"; + break; + } + case 4: { // print_str + { + // pop the string length and string location + // we do not need them at the moment + m_a.asm_pop_r32(X86Reg::eax); + m_a.asm_pop_r32(X86Reg::eax); + } + std::string label = + "string" + std::to_string(last_last_vis_i32_const); + emit_print(m_a, label, + loc_to_str[last_last_vis_i32_const].size()); + break; + } + case 5: { // flush_buf + std::string label = "string-1"; + std::string msg = "\n"; + int32_t loc = -1; // tmp negative index used + emit_print(m_a, label, msg.size()); + loc_to_str[loc] = msg; + break; + } + case 6: { // set_exit_code + m_a.asm_jmp_label("exit"); + break; + } + default: { + std::cerr << "Unsupported func_index"; + } + } + } + + void visit_Call(uint32_t func_index) { + if (func_index <= 6U) { + call_imported_function(func_index); + return; + } + + uint32_t imports_adjusted_func_index = func_index - 7U; + m_a.asm_call_label(exports[imports_adjusted_func_index].name); + + // Pop the passed function arguments + wasm::FuncType func_type = + func_types[type_indices[imports_adjusted_func_index]]; + for (uint32_t i = 0; i < func_type.param_types.size(); i++) { + m_a.asm_pop_r32(X86Reg::eax); + } + + // Adjust the return values of the called function + X86Reg base = X86Reg::esp; + for (uint32_t i = 0; i < func_type.result_types.size(); i++) { + // take value into eax + m_a.asm_mov_r32_m32( + X86Reg::eax, &base, nullptr, 1, + -(4 * (func_type.param_types.size() + 2 + + codes[imports_adjusted_func_index].locals.size() + 1))); + + // push eax value onto stack + m_a.asm_push_r32(X86Reg::eax); + } + } + + void visit_EmtpyBlockType() {} + + void visit_Br(uint32_t label_index) { + // Branch is used to jump to the `loop.head` or `loop.end`. + if (loop_unique_id.size() + if_unique_id.size() - cur_nesting_length + == label_index + 1) { + // cycle/continue or loop.end + m_a.asm_jmp_label(".loop.head_" + loop_unique_id.back()); + } else { + // exit/break + m_a.asm_jmp_label(".loop.end_" + loop_unique_id.back()); + } + } + + void visit_Loop() { + uint32_t prev_nesting_length = cur_nesting_length; + cur_nesting_length = loop_unique_id.size() + if_unique_id.size(); + loop_unique_id.push_back(std::to_string(offset)); + /* + The loop statement starts with `loop.head`. The `loop.body` and + `loop.branch` are enclosed within the `if.block`. If the condition + fails, the loop is exited through `else.block`. + .head + .If + # Statements + .Br + .Else + .endIf + .end + */ + m_a.add_label(".loop.head_" + loop_unique_id.back()); + { + decode_instructions(); + } + // end + m_a.add_label(".loop.end_" + loop_unique_id.back()); + loop_unique_id.pop_back(); + cur_nesting_length = prev_nesting_length; + } + + void visit_If() { + if_unique_id.push_back(std::to_string(offset)); + // `eax` contains the logical value (true = 1, false = 0) + // of the if condition + m_a.asm_pop_r32(X86Reg::eax); + m_a.asm_cmp_r32_imm8(LFortran::X86Reg::eax, 1); + m_a.asm_je_label(".then_" + if_unique_id.back()); + m_a.asm_jmp_label(".else_" + if_unique_id.back()); + m_a.add_label(".then_" + if_unique_id.back()); + { + decode_instructions(); + } + m_a.add_label(".endif_" + if_unique_id.back()); + if_unique_id.pop_back(); + } + + void visit_Else() { + m_a.asm_jmp_label(".endif_" + if_unique_id.back()); + m_a.add_label(".else_" + if_unique_id.back()); + } + + void visit_LocalGet(uint32_t localidx) { + X86Reg base = X86Reg::ebp; + int no_of_params = + (int)func_types[type_indices[cur_func_idx]].param_types.size(); + if ((int)localidx < no_of_params) { + m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, + (4 * localidx + 8)); + m_a.asm_push_r32(X86Reg::eax); + } else { + m_a.asm_mov_r32_m32(X86Reg::eax, &base, nullptr, 1, + -(4 * ((int)localidx - no_of_params + 1))); + m_a.asm_push_r32(X86Reg::eax); + } + } + void visit_LocalSet(uint32_t localidx) { + X86Reg base = X86Reg::ebp; + int no_of_params = + (int)func_types[type_indices[cur_func_idx]].param_types.size(); + if ((int)localidx < no_of_params) { + m_a.asm_pop_r32(X86Reg::eax); + m_a.asm_mov_m32_r32(&base, nullptr, 1, (4 * localidx + 8), + X86Reg::eax); + } else { + m_a.asm_pop_r32(X86Reg::eax); + m_a.asm_mov_m32_r32(&base, nullptr, 1, + -(4 * ((int)localidx - no_of_params + 1)), + X86Reg::eax); + } + } + + void visit_I32Eqz() { + m_a.asm_push_imm32(0U); + handle_I32Compare("Eq"); + } + + void visit_I32Const(int32_t value) { + m_a.asm_push_imm32(value); + // if (value < 0) { + // m_a.asm_pop_r32(X86Reg::eax); + // m_a.asm_neg_r32(X86Reg::eax); + // m_a.asm_push_r32(X86Reg::eax); + // } + + // TODO: Following seems/is hackish. Fix/Improve it. + last_last_vis_i32_const = last_vis_i32_const; + last_vis_i32_const = value; + } + + void visit_I32Add() { + m_a.asm_pop_r32(X86Reg::ebx); + m_a.asm_pop_r32(X86Reg::eax); + m_a.asm_add_r32_r32(X86Reg::eax, X86Reg::ebx); + m_a.asm_push_r32(X86Reg::eax); + } + void visit_I32Sub() { + m_a.asm_pop_r32(X86Reg::ebx); + m_a.asm_pop_r32(X86Reg::eax); + m_a.asm_sub_r32_r32(X86Reg::eax, X86Reg::ebx); + m_a.asm_push_r32(X86Reg::eax); + } + void visit_I32Mul() { + m_a.asm_pop_r32(X86Reg::ebx); + m_a.asm_pop_r32(X86Reg::eax); + m_a.asm_mul_r32(X86Reg::ebx); + m_a.asm_push_r32(X86Reg::eax); + } + void visit_I32DivS() { + m_a.asm_pop_r32(X86Reg::ebx); + m_a.asm_pop_r32(X86Reg::eax); + m_a.asm_div_r32(X86Reg::ebx); + m_a.asm_push_r32(X86Reg::eax); + } + + void handle_I32Compare(const std::string &compare_op) { + std::string label = std::to_string(offset); + m_a.asm_pop_r32(X86Reg::ebx); + m_a.asm_pop_r32(X86Reg::eax); + // `eax` and `ebx` contain the left and right operands, respectively + m_a.asm_cmp_r32_r32(X86Reg::eax, X86Reg::ebx); + if (compare_op == "Eq") { + m_a.asm_je_label(".compare_1" + label); + } else if (compare_op == "Gt") { + m_a.asm_jg_label(".compare_1" + label); + } else if (compare_op == "GtE") { + m_a.asm_jge_label(".compare_1" + label); + } else if (compare_op == "Lt") { + m_a.asm_jl_label(".compare_1" + label); + } else if (compare_op == "LtE") { + m_a.asm_jle_label(".compare_1" + label); + } else if (compare_op == "NotEq") { + m_a.asm_jne_label(".compare_1" + label); + } else { + throw CodeGenError("Comparison operator not implemented"); + } + // if the `compare` condition in `true`, jump to compare_1 + // and assign `1` else assign `0` + m_a.asm_push_imm8(0); + m_a.asm_jmp_label(".compare.end_" + label); + m_a.add_label(".compare_1" + label); + m_a.asm_push_imm8(1); + m_a.add_label(".compare.end_" + label); + } + + void visit_I32Eq() { handle_I32Compare("Eq"); } + void visit_I32GtS() { handle_I32Compare("Gt"); } + void visit_I32GeS() { handle_I32Compare("GtE"); } + void visit_I32LtS() { handle_I32Compare("Lt"); } + void visit_I32LeS() { handle_I32Compare("LtE"); } + void visit_I32Ne() { handle_I32Compare("NotEq"); } + + void gen_x86_bytes() { + emit_elf32_header(m_a); + + // Add runtime library functions + emit_print_int(m_a, "print_i32"); + emit_exit2(m_a, "exit"); + + // declare compile-time strings + for (uint32_t i = 0; i < data_segments.size(); i++) { + offset = data_segments[i].insts_start_index; + decode_instructions(); + loc_to_str[last_vis_i32_const] = data_segments[i].text; + } + + for (uint32_t i = 0; i < type_indices.size(); i++) { + if (i < type_indices.size() - 1U) { + m_a.add_label(exports[i].name); + } else { + m_a.add_label("_start"); + } + + { + // Initialize the stack + m_a.asm_push_r32(X86Reg::ebp); + m_a.asm_mov_r32_r32(X86Reg::ebp, X86Reg::esp); + + // Initialze local variables to zero and thus allocate space + m_a.asm_mov_r32_imm32(X86Reg::eax, 0U); + for (uint32_t j = 0; j < codes.p[i].locals.size(); j++) { + for (uint32_t k = 0; k < codes.p[i].locals.p[j].count; + k++) { + m_a.asm_push_r32(X86Reg::eax); + } + } + + offset = codes.p[i].insts_start_index; + cur_func_idx = i; + decode_instructions(); + + // Restore stack + m_a.asm_mov_r32_r32(X86Reg::esp, X86Reg::ebp); + m_a.asm_pop_r32(X86Reg::ebp); + m_a.asm_ret(); + } + } + + for (auto &s : loc_to_str) { + std::string label = "string" + std::to_string(s.first); + emit_data_string(m_a, label, s.second); + } + + emit_elf32_footer(m_a); + } +}; + +} // namespace wasm + +Result wasm_to_x86(Vec &wasm_bytes, Allocator &al, + const std::string &filename, bool time_report, + diag::Diagnostics &diagnostics) { + int time_decode_wasm = 0; + int time_gen_x86_bytes = 0; + int time_save = 0; + int time_verify = 0; + + X86Assembler m_a(al); + + wasm::X86Visitor x86_visitor(m_a, al, diagnostics, wasm_bytes); + + { + auto t1 = std::chrono::high_resolution_clock::now(); + try { + x86_visitor.decode_wasm(); + } catch (const CodeGenError &e) { + diagnostics.diagnostics.push_back(e.d); + return Error(); + } + auto t2 = std::chrono::high_resolution_clock::now(); + time_decode_wasm = + std::chrono::duration_cast(t2 - t1) + .count(); + } + + { + auto t1 = std::chrono::high_resolution_clock::now(); + x86_visitor.gen_x86_bytes(); + auto t2 = std::chrono::high_resolution_clock::now(); + time_gen_x86_bytes = + std::chrono::duration_cast(t2 - t1) + .count(); + } + + { + auto t1 = std::chrono::high_resolution_clock::now(); + m_a.verify(); + auto t2 = std::chrono::high_resolution_clock::now(); + time_verify = + std::chrono::duration_cast(t2 - t1) + .count(); + } + + { + auto t1 = std::chrono::high_resolution_clock::now(); + m_a.save_binary(filename); + auto t2 = std::chrono::high_resolution_clock::now(); + time_save = + std::chrono::duration_cast(t2 - t1) + .count(); + } + + //! Helpful for debugging + // std::cout << x86_visitor.m_a.get_asm() << std::endl; + + if (time_report) { + std::cout << "Codegen Time report:" << std::endl; + std::cout << "Decode wasm: " << std::setw(5) << time_decode_wasm + << std::endl; + std::cout << "Generate asm: " << std::setw(5) << time_gen_x86_bytes + << std::endl; + std::cout << "Verify: " << std::setw(5) << time_verify + << std::endl; + std::cout << "Save: " << std::setw(5) << time_save << std::endl; + int total = + time_decode_wasm + time_gen_x86_bytes + time_verify + time_save; + std::cout << "Total: " << std::setw(5) << total << std::endl; + } + return 0; +} + +} // namespace LFortran diff --git a/src/libasr/codegen/wasm_to_x86.h b/src/libasr/codegen/wasm_to_x86.h new file mode 100644 index 0000000..17ebee2 --- /dev/null +++ b/src/libasr/codegen/wasm_to_x86.h @@ -0,0 +1,14 @@ +#ifndef LFORTRAN_WASM_TO_X86_H +#define LFORTRAN_WASM_TO_X86_H + +#include + +namespace LFortran { + +Result wasm_to_x86(Vec &wasm_bytes, Allocator &al, + const std::string &filename, bool time_report, + diag::Diagnostics &diagnostics); + +} // namespace LFortran + +#endif // LFORTRAN_WASM_TO_X86_H diff --git a/src/libasr/codegen/wasm_utils.h b/src/libasr/codegen/wasm_utils.h index 88e61c7..c677026 100644 --- a/src/libasr/codegen/wasm_utils.h +++ b/src/libasr/codegen/wasm_utils.h @@ -44,7 +44,7 @@ struct Import { }; struct Data { - std::string insts; + uint32_t insts_start_index; std::string text; }; diff --git a/src/libasr/codegen/x86_assembler.cpp b/src/libasr/codegen/x86_assembler.cpp index d246bda..1237338 100644 --- a/src/libasr/codegen/x86_assembler.cpp +++ b/src/libasr/codegen/x86_assembler.cpp @@ -94,6 +94,15 @@ void emit_exit(X86Assembler &a, const std::string &name, a.asm_int_imm8(0x80); // syscall } +void emit_exit2(X86Assembler &a, const std::string &name) +{ + a.add_label(name); + // void exit(); + a.asm_mov_r32_imm32(LFortran::X86Reg::eax, 1); // sys_exit + a.asm_pop_r32(X86Reg::ebx); // exit code on stack, move to register + a.asm_int_imm8(0x80); // syscall +} + void emit_data_string(X86Assembler &a, const std::string &label, const std::string &s) { @@ -145,11 +154,11 @@ void emit_print_int(X86Assembler &a, const std::string &name) a.asm_je_label(".print"); // jmp .loop a.asm_jmp_label(".loop"); - + a.add_label(".print"); // cmp esi, 0 a.asm_cmp_r32_imm8(X86Reg::esi, 0); -// jz end +// jz end a.asm_je_label(".end"); // dec esi a.asm_dec_r32(X86Reg::esi); diff --git a/src/libasr/codegen/x86_assembler.h b/src/libasr/codegen/x86_assembler.h index aba882c..6947b11 100644 --- a/src/libasr/codegen/x86_assembler.h +++ b/src/libasr/codegen/x86_assembler.h @@ -815,6 +815,14 @@ void emit_elf32_footer(X86Assembler &a); void emit_exit(X86Assembler &a, const std::string &name, uint32_t exit_code); + +// this is similar to emit_exit() but takes the argument (i.e. exit code) +// from top of stack. To call this exit2, one needs to jump to it +// instead of call it. (Because calling pushes the instruction address and +// base pointer value (ebp) of previous function and thus makes the +// exit code parameter less reachable) +void emit_exit2(X86Assembler &a, const std::string &name); + void emit_data_string(X86Assembler &a, const std::string &label, const std::string &s); void emit_print(X86Assembler &a, const std::string &msg_label, diff --git a/src/libasr/diagnostics.cpp b/src/libasr/diagnostics.cpp index 2684466..0fba593 100644 --- a/src/libasr/diagnostics.cpp +++ b/src/libasr/diagnostics.cpp @@ -8,8 +8,8 @@ namespace LFortran::diag { -const static std::string redon = "\033[0;31m"; -const static std::string redoff = "\033[0;00m"; +const static std::string redon = ColorsANSI::RED; +const static std::string redoff = ColorsANSI::RESET; std::string highlight_line(const std::string &line, const size_t first_column, @@ -82,8 +82,8 @@ std::string Diagnostics::render(const std::string &input, if (compiler_options.error_format == "human") { if (this->diagnostics.size() > 0 && !compiler_options.no_error_banner) { if (!compiler_options.no_warnings || has_error()) { - std::string bold = "\033[0;1m"; - std::string reset = "\033[0;00m"; + std::string bold = ColorsANSI::BOLD; + std::string reset = ColorsANSI::RESET; if (!compiler_options.use_colors) { bold = ""; reset = ""; @@ -98,6 +98,17 @@ std::string Diagnostics::render(const std::string &input, return out; } +std::string render_diagnostic_short_nospan(const Diagnostic &d); + +std::string Diagnostics::render2() { + std::string out; + for (auto &d : this->diagnostics) { + out += render_diagnostic_short_nospan(d); + if (&d != &this->diagnostics.back()) out += "\n"; + } + return out; +} + std::string get_line(std::string str, int n) { std::string line; @@ -157,12 +168,12 @@ std::string render_diagnostic_short(Diagnostic &d, const std::string &input, } std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) { - std::string bold = "\033[0;1m"; - std::string red_bold = "\033[0;31;1m"; - std::string yellow_bold = "\033[0;33;1m"; - std::string green_bold = "\033[0;32;1m"; - std::string blue_bold = "\033[0;34;1m"; - std::string reset = "\033[0;00m"; + std::string bold = ColorsANSI::BOLD; + std::string red_bold = ColorsANSI::BOLDCYAN; + std::string yellow_bold = ColorsANSI::BOLDYELLOW; + std::string green_bold = ColorsANSI::BOLDGREEN; + std::string blue_bold = ColorsANSI::BOLDBLUE; + std::string reset = ColorsANSI::RESET; if (!use_colors) { bold = ""; red_bold = ""; @@ -173,59 +184,7 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) { } std::stringstream out; - std::string message_type = ""; - std::string primary_color = ""; - std::string type_color = ""; - switch (d.level) { - case (Level::Error): - primary_color = red_bold; - type_color = primary_color; - switch (d.stage) { - case (Stage::CPreprocessor): - message_type = "C preprocessor error"; - break; - case (Stage::Prescanner): - message_type = "prescanner error"; - break; - case (Stage::Tokenizer): - message_type = "tokenizer error"; - break; - case (Stage::Parser): - message_type = "syntax error"; - break; - case (Stage::Semantic): - message_type = "semantic error"; - break; - case (Stage::ASRPass): - message_type = "ASR pass error"; - break; - case (Stage::CodeGen): - message_type = "code generation error"; - break; - } - break; - case (Level::Warning): - primary_color = yellow_bold; - type_color = primary_color; - message_type = "warning"; - break; - case (Level::Note): - primary_color = bold; - type_color = primary_color; - message_type = "note"; - break; - case (Level::Help): - primary_color = bold; - type_color = primary_color; - message_type = "help"; - break; - case (Level::Style): - primary_color = green_bold; - type_color = yellow_bold; - message_type = "style suggestion"; - break; - } - + auto [message_type, primary_color, type_color] = diag_level_to_str(d, use_colors); out << type_color << message_type << reset << bold << ": " << d.message << reset << std::endl; if (d.labels.size() > 0) { @@ -345,9 +304,37 @@ std::string render_diagnostic_human(const Diagnostic &d, bool use_colors) { std::string render_diagnostic_short(const Diagnostic &d) { std::stringstream out; + // Message anatomy: + // :-:-: : + if (d.labels.size() > 0) { + Label l = d.labels[0]; + Span s = l.spans[0]; + // TODO: print the primary line+column here, not the first label: + out << s.filename << ":" << s.first_line << "-" << s.last_line << ":"; + out << s.first_column << "-" << s.last_column << ": "; + } + auto [message_type, primary, type] = diag_level_to_str(d, false); + out << message_type << ": " << d.message << std::endl; + + return out.str(); +} + +std::string render_diagnostic_short_nospan(const Diagnostic &d) { + std::stringstream out; + auto [message_type, primary, type] = diag_level_to_str(d, false); + out << message_type << ": " << d.message << std::endl; + return out.str(); +} + +std::tuple diag_level_to_str( + const Diagnostic &d, const bool use_color) { std::string message_type = ""; + std::string primary_color = ""; + std::string type_color = ""; switch (d.level) { case (Level::Error): + primary_color = use_color ? ColorsANSI::BOLDRED : ""; + type_color = primary_color; switch (d.stage) { case (Stage::CPreprocessor): message_type = "C preprocessor error"; @@ -367,39 +354,36 @@ std::string render_diagnostic_short(const Diagnostic &d) { case (Stage::ASRPass): message_type = "ASR pass error"; break; + case (Stage::ASRVerify): + message_type = "ASR verify pass error"; + break; case (Stage::CodeGen): message_type = "code generation error"; break; } break; case (Level::Warning): + primary_color = use_color ? ColorsANSI::BOLDYELLOW : ""; + type_color = primary_color; message_type = "warning"; break; case (Level::Note): + primary_color = use_color ? ColorsANSI::BOLD : ""; + type_color = primary_color; message_type = "note"; break; case (Level::Help): + primary_color = use_color ? ColorsANSI::BOLD : ""; + type_color = primary_color; message_type = "help"; break; case (Level::Style): + primary_color = use_color ? ColorsANSI::BOLDGREEN : ""; + type_color = use_color ? ColorsANSI::BOLDYELLOW : ""; message_type = "style suggestion"; break; } - - if (d.labels.size() > 0) { - Label l = d.labels[0]; - Span s = l.spans[0]; - // TODO: print the primary line+column here, not the first label: - out << s.filename << ":" << s.first_line << ":" << s.first_column; - if (s.first_line != s.last_line) { - out << " - " << s.last_line << ":" << s.last_column; - } - out << " "; - } - - out << message_type << ": " << d.message << std::endl; - - return out.str(); + return std::make_tuple(message_type, primary_color, type_color); } } // namespace LFortran::diag diff --git a/src/libasr/diagnostics.h b/src/libasr/diagnostics.h index 2116a01..9f79eba 100644 --- a/src/libasr/diagnostics.h +++ b/src/libasr/diagnostics.h @@ -1,6 +1,7 @@ #ifndef LFORTRAN_DIAGNOSTICS_H #define LFORTRAN_DIAGNOSTICS_H +#include #include #include @@ -68,7 +69,8 @@ enum Level { * Which stage of the compiler the error is coming from */ enum Stage { - CPreprocessor, Prescanner, Tokenizer, Parser, Semantic, ASRPass, CodeGen + CPreprocessor, Prescanner, Tokenizer, Parser, Semantic, ASRPass, + ASRVerify, CodeGen }; /* @@ -113,9 +115,13 @@ struct Diagnostic { struct Diagnostics { std::vector diagnostics; + // Render nice error messages using all the information we have std::string render(const std::string &input, const LocationManager &lm, const CompilerOptions &compiler_options); + // Renders the error message using only the information in Diagnostics + std::string render2(); + // Returns true iff diagnostics contains at least one error message bool has_error() const; @@ -183,6 +189,27 @@ struct Diagnostics { } }; +struct ColorsANSI { + inline static const std::string RESET = "\033[0;0m"; + inline static const std::string BLACK = "\033[0;30m"; /* Black */ + inline static const std::string RED = "\033[0;31m"; /* Red */ + inline static const std::string GREEN = "\033[0;32m"; /* Green */ + inline static const std::string YELLOW = "\033[0;33m"; /* Yellow */ + inline static const std::string BLUE = "\033[0;34m"; /* Blue */ + inline static const std::string MAGENTA = "\033[0;35m"; /* Magenta */ + inline static const std::string CYAN = "\033[0;36m"; /* Cyan */ + inline static const std::string WHITE = "\033[0;37m"; /* White */ + inline static const std::string BOLD = "\033[0;1m"; /* Bold */ + inline static const std::string BOLDBLACK = "\033[0;30;1m"; /* Bold Black */ + inline static const std::string BOLDRED = "\033[0;31;1m"; /* Bold Red */ + inline static const std::string BOLDGREEN = "\033[0;32;1m"; /* Bold Green */ + inline static const std::string BOLDYELLOW = "\033[0;33;1m"; /* Bold Yellow */ + inline static const std::string BOLDBLUE = "\033[0;34;1m"; /* Bold Blue */ + inline static const std::string BOLDMAGENTA = "\033[0;35;1m"; /* Bold Magenta */ + inline static const std::string BOLDCYAN = "\033[0;36;1m"; /* Bold Cyan */ + inline static const std::string BOLDWHITE = "\033[0;37;1m"; /* Bold White */ +}; + std::string render_diagnostic_human(const Diagnostic &d, bool use_colors); std::string render_diagnostic_short(const Diagnostic &d); @@ -190,7 +217,43 @@ std::string render_diagnostic_short(const Diagnostic &d); std::string render_diagnostic_human(Diagnostic &d, const std::string &input, const LocationManager &lm, bool use_colors, bool show_stacktrace); std::string render_diagnostic_short(Diagnostic &d, const std::string &input, - const LocationManager &lm); + const LocationManager &lm); +/** + * @brief Convert diagnostic `Level` i.e. severity to string and color accordingly. + * + * This method defines the Severity part of the REGEX linters must implement. + * Any changes to this method must be reflected in the linters. + * + * @param d Diagnostic object. + * @param use_colors Include ANSI color codes in the return tuple. + * @return std::tuple + * message_type, primary color & type color + * + * Possible `messages_types` and their severities are: + * - Severity: Error + * + C preprocessor error + * + prescanner error + * + tokenizer error + * + syntax error + * + semantic error + * + ASR pass error + * + ASR verify pass error + * + code generation error + * + * - Severity: Warning + * + warning + * + * - Severity: Note + * + note + * + * - Severity: Help + * + help + * + * - Severity: Style + * + style suggestion + */ +std::tuple diag_level_to_str(const Diagnostic &d, + const bool use_colors = true); } // namespace diag } // namespace LFortran diff --git a/src/libasr/pass/arr_slice.cpp b/src/libasr/pass/arr_slice.cpp index 8c3a3bc..9890104 100644 --- a/src/libasr/pass/arr_slice.cpp +++ b/src/libasr/pass/arr_slice.cpp @@ -278,7 +278,6 @@ void pass_replace_arr_slice(Allocator &al, ASR::TranslationUnit_t &unit, std::string rl_path = pass_options.runtime_library_dir; ArrSliceVisitor v(al, rl_path); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/array_op.cpp b/src/libasr/pass/array_op.cpp index d0366c9..b687b02 100644 --- a/src/libasr/pass/array_op.cpp +++ b/src/libasr/pass/array_op.cpp @@ -129,7 +129,8 @@ class ArrayOpVisitor : public PassUtils::PassVisitor a_args.push_back(al, s->m_return_var); ASR::asr_t* s_sub_asr = ASR::make_Function_t(al, s->base.base.loc, s->m_symtab, - s->m_name, a_args.p, a_args.size(), s->m_body, s->n_body, + s->m_name, s->m_dependencies, s->n_dependencies, + a_args.p, a_args.size(), s->m_body, s->n_body, nullptr, s->m_abi, s->m_access, s->m_deftype, nullptr, false, false, false, s->m_inline, s->m_static, @@ -977,7 +978,6 @@ void pass_replace_array_op(Allocator &al, ASR::TranslationUnit_t &unit, std::string rl_path = pass_options.runtime_library_dir; ArrayOpVisitor v(al, rl_path); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/class_constructor.cpp b/src/libasr/pass/class_constructor.cpp index 4f9916f..62921ab 100644 --- a/src/libasr/pass/class_constructor.cpp +++ b/src/libasr/pass/class_constructor.cpp @@ -61,7 +61,6 @@ void pass_replace_class_constructor(Allocator &al, ASR::TranslationUnit_t &unit, v.is_constructor_present = false; v.visit_TranslationUnit(unit); } while( v.is_constructor_present ); - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/dead_code_removal.cpp b/src/libasr/pass/dead_code_removal.cpp index d1dda81..16d92e2 100644 --- a/src/libasr/pass/dead_code_removal.cpp +++ b/src/libasr/pass/dead_code_removal.cpp @@ -103,7 +103,6 @@ void pass_dead_code_removal(Allocator &al, ASR::TranslationUnit_t &unit, std::string rl_path = pass_options.runtime_library_dir; DeadCodeRemovalVisitor v(al, rl_path); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/div_to_mul.cpp b/src/libasr/pass/div_to_mul.cpp index 72f4876..917b645 100644 --- a/src/libasr/pass/div_to_mul.cpp +++ b/src/libasr/pass/div_to_mul.cpp @@ -82,7 +82,6 @@ void pass_replace_div_to_mul(Allocator &al, ASR::TranslationUnit_t &unit, std::string rl_path = pass_options.runtime_library_dir; DivToMulVisitor v(al, rl_path); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/do_loops.cpp b/src/libasr/pass/do_loops.cpp index 42365ff..cf0756c 100644 --- a/src/libasr/pass/do_loops.cpp +++ b/src/libasr/pass/do_loops.cpp @@ -54,7 +54,6 @@ void pass_replace_do_loops(Allocator &al, ASR::TranslationUnit_t &unit, v.asr_changed = false; v.visit_TranslationUnit(unit); } - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/flip_sign.cpp b/src/libasr/pass/flip_sign.cpp index 885076b..2edb0a5 100644 --- a/src/libasr/pass/flip_sign.cpp +++ b/src/libasr/pass/flip_sign.cpp @@ -60,7 +60,7 @@ class FlipSignVisitor : public PassUtils::SkipOptimizationFunctionVisitor private: ASR::TranslationUnit_t &unit; - std::string rl_path; + LCompilers::PassOptions pass_options; ASR::expr_t* fma_var; @@ -46,8 +46,9 @@ class FMAVisitor : public PassUtils::SkipOptimizationFunctionVisitor bool from_fma; public: - FMAVisitor(Allocator &al_, ASR::TranslationUnit_t &unit_, const std::string& rl_path_) : SkipOptimizationFunctionVisitor(al_), - unit(unit_), rl_path(rl_path_), fma_var(nullptr), from_fma(false) + FMAVisitor(Allocator &al_, ASR::TranslationUnit_t &unit_, + const LCompilers::PassOptions& pass_options_) : SkipOptimizationFunctionVisitor(al_), + unit(unit_), pass_options(pass_options_), fma_var(nullptr), from_fma(false) { pass_result.reserve(al, 1); } @@ -117,7 +118,7 @@ class FMAVisitor : public PassUtils::SkipOptimizationFunctionVisitor } fma_var = PassUtils::get_fma(other_expr, first_arg, second_arg, - al, unit, rl_path, current_scope, x.base.base.loc, + al, unit, pass_options, current_scope, x.base.base.loc, [&](const std::string &msg, const Location &) { throw LCompilersException(msg); }); from_fma = false; } @@ -167,10 +168,8 @@ class FMAVisitor : public PassUtils::SkipOptimizationFunctionVisitor void pass_replace_fma(Allocator &al, ASR::TranslationUnit_t &unit, const LCompilers::PassOptions& pass_options) { - std::string rl_path = pass_options.runtime_library_dir; - FMAVisitor v(al, unit, rl_path); + FMAVisitor v(al, unit, pass_options); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/for_all.cpp b/src/libasr/pass/for_all.cpp index b467e4a..1356a5f 100644 --- a/src/libasr/pass/for_all.cpp +++ b/src/libasr/pass/for_all.cpp @@ -47,7 +47,6 @@ void pass_replace_forall(Allocator &al, ASR::TranslationUnit_t &unit, const LCompilers::PassOptions& /*pass_options*/) { ForAllVisitor v(al); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } } // namespace LFortran diff --git a/src/libasr/pass/global_stmts.cpp b/src/libasr/pass/global_stmts.cpp index 1afb730..5a604ed 100644 --- a/src/libasr/pass/global_stmts.cpp +++ b/src/libasr/pass/global_stmts.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace LFortran { @@ -28,7 +29,7 @@ void pass_wrap_global_stmts_into_function(Allocator &al, SymbolTable *fn_scope = al.make_new(unit.m_global_scope); ASR::ttype_t *type; - Location loc; + Location loc = unit.base.base.loc; ASR::asr_t *return_var=nullptr; ASR::expr_t *return_var_ref=nullptr; char *var_name; @@ -111,6 +112,7 @@ void pass_wrap_global_stmts_into_function(Allocator &al, al, loc, /* a_symtab */ fn_scope, /* a_name */ fn_name, + nullptr, 0, /* a_args */ nullptr, /* n_args */ 0, /* a_body */ body.p, @@ -135,6 +137,7 @@ void pass_wrap_global_stmts_into_function(Allocator &al, al, loc, /* a_symtab */ fn_scope, /* a_name */ fn_name, + nullptr, 0, /* a_args */ nullptr, /* n_args */ 0, /* a_body */ body.p, @@ -154,7 +157,8 @@ void pass_wrap_global_stmts_into_function(Allocator &al, } unit.m_items = nullptr; unit.n_items = 0; - LFORTRAN_ASSERT(asr_verify(unit)); + PassUtils::UpdateDependenciesVisitor v(al); + v.visit_TranslationUnit(unit); } } diff --git a/src/libasr/pass/global_stmts_program.cpp b/src/libasr/pass/global_stmts_program.cpp index 4ced080..dc91d81 100644 --- a/src/libasr/pass/global_stmts_program.cpp +++ b/src/libasr/pass/global_stmts_program.cpp @@ -48,7 +48,6 @@ void pass_wrap_global_stmts_into_program(Allocator &al, /* a_body */ prog_body.p, /* n_body */ prog_body.n); unit.m_global_scope->add_symbol(prog_name, ASR::down_cast(prog)); - LFORTRAN_ASSERT(asr_verify(unit)); } } // namespace LFortran diff --git a/src/libasr/pass/implied_do_loops.cpp b/src/libasr/pass/implied_do_loops.cpp index e0024f5..485da70 100644 --- a/src/libasr/pass/implied_do_loops.cpp +++ b/src/libasr/pass/implied_do_loops.cpp @@ -135,7 +135,8 @@ class ImpliedDoLoopVisitor : public PassUtils::PassVisitor ASR::expr_t* array_ref = LFortran::ASRUtils::EXPR(ASR::make_ArrayItem_t(al, arr_var->base.base.loc, ASRUtils::EXPR((ASR::asr_t*)arr_var), args.p, args.size(), - array_ref_type, nullptr)); + array_ref_type, ASR::arraystorageType::RowMajor, + nullptr)); if( idoloop->m_values[i]->type == ASR::exprType::ImpliedDoLoop ) { throw LCompilersException("Pass for nested ImpliedDoLoop nodes isn't implemented yet."); // idoloop->m_values[i]->base.loc } @@ -199,7 +200,8 @@ class ImpliedDoLoopVisitor : public PassUtils::PassVisitor ASR::expr_t* array_ref = LFortran::ASRUtils::EXPR(ASR::make_ArrayItem_t(al, arr_var->base.base.loc, ASRUtils::EXPR((ASR::asr_t*)arr_var), args.p, args.size(), - array_ref_type, nullptr)); + array_ref_type, ASR::arraystorageType::RowMajor, + nullptr)); ASR::stmt_t* assign_stmt = LFortran::ASRUtils::STMT(ASR::make_Assignment_t(al, arr_var->base.base.loc, array_ref, arr_init->m_args[k], nullptr)); pass_result.push_back(al, assign_stmt); ASR::expr_t* increment = LFortran::ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, arr_var->base.base.loc, idx_var, ASR::binopType::Add, const_1, LFortran::ASRUtils::expr_type(idx_var), nullptr)); @@ -248,7 +250,6 @@ void pass_replace_implied_do_loops(Allocator &al, ASR::TranslationUnit_t &unit, std::string rl_path = pass_options.runtime_library_dir; ImpliedDoLoopVisitor v(al, unit, rl_path); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/inline_function_calls.cpp b/src/libasr/pass/inline_function_calls.cpp index e5e24ed..6d1db2d 100644 --- a/src/libasr/pass/inline_function_calls.cpp +++ b/src/libasr/pass/inline_function_calls.cpp @@ -460,7 +460,8 @@ void pass_inline_function_calls(Allocator &al, ASR::TranslationUnit_t &unit, v.visit_TranslationUnit(unit); v.configure_node_duplicator(true); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); + PassUtils::UpdateDependenciesVisitor u(al); + u.visit_TranslationUnit(unit); } diff --git a/src/libasr/pass/instantiate_template.cpp b/src/libasr/pass/instantiate_template.cpp index 08f4d7f..57dd1d8 100644 --- a/src/libasr/pass/instantiate_template.cpp +++ b/src/libasr/pass/instantiate_template.cpp @@ -10,24 +10,26 @@ namespace LFortran { class FunctionInstantiator : public ASR::BaseExprStmtDuplicator { public: + SymbolTable *func_scope; SymbolTable *current_scope; std::map subs; std::map rt_subs; std::string new_func_name; std::vector rts; + std::set dependencies; FunctionInstantiator(Allocator &al, std::map subs, - std::map rt_subs, SymbolTable *current_scope, + std::map rt_subs, SymbolTable *func_scope, std::string new_func_name): BaseExprStmtDuplicator(al), - current_scope{current_scope}, + func_scope{func_scope}, subs{subs}, rt_subs{rt_subs}, new_func_name{new_func_name} {} ASR::asr_t* instantiate_Function(ASR::Function_t *x) { - SymbolTable *parent_scope = current_scope; + dependencies.clear(); current_scope = al.make_new(x->m_symtab->parent); Vec args; @@ -114,9 +116,16 @@ class FunctionInstantiator : public ASR::BaseExprStmtDuplicatorm_pure; bool func_module = x->m_module; + Vec deps_vec; + deps_vec.reserve(al, dependencies.size()); + for( auto& dep: dependencies ) { + deps_vec.push_back(al, s2c(al, dep)); + } + ASR::asr_t *result = ASR::make_Function_t( al, x->base.base.loc, current_scope, s2c(al, new_func_name), + deps_vec.p, deps_vec.size(), args.p, args.size(), body.p, body.size(), new_return_var_ref, @@ -126,7 +135,6 @@ class FunctionInstantiator : public ASR::BaseExprStmtDuplicator(result); x->m_symtab->parent->add_symbol(new_func_name, t); - current_scope = parent_scope; return result; } @@ -149,7 +157,7 @@ class FunctionInstantiator : public ASR::BaseExprStmtDuplicatorm_type); - return ASR::make_ArrayItem_t(al, x->base.base.loc, m_v, args.p, x->n_args, type, m_value); + return ASR::make_ArrayItem_t(al, x->base.base.loc, m_v, args.p, x->n_args, type, ASR::arraystorageType::RowMajor, m_value); } ASR::asr_t* duplicate_ListItem(ASR::ListItem_t *x) { @@ -188,6 +196,12 @@ class FunctionInstantiator : public ASR::BaseExprStmtDuplicatorbase.base.loc, target, value, overloaded); } + ASR::asr_t* duplicate_TemplateBinOp(ASR::TemplateBinOp_t *x) { + ASR::expr_t *left = duplicate_expr(x->m_left); + ASR::expr_t *right = duplicate_expr(x->m_right); + return make_BinOp_helper(left, right, x->m_op, x->base.base.loc); + } + ASR::asr_t* duplicate_DoLoop(ASR::DoLoop_t *x) { Vec m_body; m_body.reserve(al, x->n_body); @@ -214,7 +228,7 @@ class FunctionInstantiator : public ASR::BaseExprStmtDuplicatorm_name); - ASR::symbol_t *name = current_scope->get_symbol(sym_name); + ASR::symbol_t *name = func_scope->get_symbol(sym_name); Vec args; args.reserve(al, x->n_args); for (size_t i=0; in_args; i++) { @@ -227,8 +241,8 @@ class FunctionInstantiator : public ASR::BaseExprStmtDuplicatorm_value); ASR::expr_t* dt = duplicate_expr(x->m_dt); std::string call_name = ASRUtils::symbol_name(x->m_name); - for (ASR::Function_t* rt: rts) { - if (call_name.compare(rt->m_name) == 0) { + //for (ASR::Function_t* rt: rts) { + // if (call_name.compare(rt->m_name) == 0) { if (rt_subs.find(call_name) == rt_subs.end()) { if (call_name.compare("add") == 0) { ASR::expr_t* left_arg = duplicate_expr(x->m_args[0].m_value); @@ -257,8 +271,10 @@ class FunctionInstantiator : public ASR::BaseExprStmtDuplicatorbase.base.loc, name, x->m_original_name, args.p, args.size(), type, value, dt); } @@ -391,6 +407,7 @@ class FunctionInstantiator : public ASR::BaseExprStmtDuplicator subs, diff --git a/src/libasr/pass/loop_unroll.cpp b/src/libasr/pass/loop_unroll.cpp index 139daa5..a1e6676 100644 --- a/src/libasr/pass/loop_unroll.cpp +++ b/src/libasr/pass/loop_unroll.cpp @@ -112,7 +112,6 @@ void pass_loop_unroll(Allocator &al, ASR::TranslationUnit_t &unit, int64_t unroll_factor = pass_options.unroll_factor; LoopUnrollVisitor v(al, rl_path, unroll_factor); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/loop_vectorise.cpp b/src/libasr/pass/loop_vectorise.cpp index f8127cc..2badc9a 100644 --- a/src/libasr/pass/loop_vectorise.cpp +++ b/src/libasr/pass/loop_vectorise.cpp @@ -193,7 +193,8 @@ void pass_loop_vectorise(Allocator &al, ASR::TranslationUnit_t &unit, std::string rl_path = pass_options.runtime_library_dir; LoopVectoriseVisitor v(al, unit, rl_path); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); + PassUtils::UpdateDependenciesVisitor u(al); + u.visit_TranslationUnit(unit); } diff --git a/src/libasr/pass/nested_vars.cpp b/src/libasr/pass/nested_vars.cpp index 04f4777..9d06683 100644 --- a/src/libasr/pass/nested_vars.cpp +++ b/src/libasr/pass/nested_vars.cpp @@ -307,13 +307,12 @@ class NestedVarVisitor : public ASR::BaseWalkVisitor }; std::map> pass_find_nested_vars( - ASR::TranslationUnit_t &unit, llvm::LLVMContext &context, + const ASR::TranslationUnit_t &unit, llvm::LLVMContext &context, std::vector &needed_globals, std::vector &nested_call_out, std::map> &nesting_map) { NestedVarVisitor v(context, needed_globals, nested_call_out, nesting_map); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); return v.nested_func_types; } diff --git a/src/libasr/pass/nested_vars.h b/src/libasr/pass/nested_vars.h index 765edd0..de66915 100644 --- a/src/libasr/pass/nested_vars.h +++ b/src/libasr/pass/nested_vars.h @@ -7,7 +7,7 @@ namespace LFortran { std::map> pass_find_nested_vars( - ASR::TranslationUnit_t &unit, llvm::LLVMContext &context, + const ASR::TranslationUnit_t &unit, llvm::LLVMContext &context, std::vector &needed_globals, std::vector &nested_call_out, std::map> &nesting_map); diff --git a/src/libasr/pass/param_to_const.cpp b/src/libasr/pass/param_to_const.cpp index 043eed0..2c45fb3 100644 --- a/src/libasr/pass/param_to_const.cpp +++ b/src/libasr/pass/param_to_const.cpp @@ -195,10 +195,10 @@ class VarVisitor : public ASR::BaseWalkVisitor }; void pass_replace_param_to_const(Allocator &al, ASR::TranslationUnit_t &unit, - const LCompilers::PassOptions& /*pass_options*/) { + const LCompilers::PassOptions &/*pass_options*/ + ) { VarVisitor v(al); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } } // namespace LFortran diff --git a/src/libasr/pass/param_to_const.h b/src/libasr/pass/param_to_const.h index b5117cd..03c8339 100644 --- a/src/libasr/pass/param_to_const.h +++ b/src/libasr/pass/param_to_const.h @@ -7,7 +7,8 @@ namespace LFortran { void pass_replace_param_to_const(Allocator &al, ASR::TranslationUnit_t &unit, - const LCompilers::PassOptions& pass_options); + const LCompilers::PassOptions& pass_options + ); } // namespace LFortran diff --git a/src/libasr/pass/pass_array_by_data.cpp b/src/libasr/pass/pass_array_by_data.cpp index 76b0588..b5c28f1 100644 --- a/src/libasr/pass/pass_array_by_data.cpp +++ b/src/libasr/pass/pass_array_by_data.cpp @@ -149,8 +149,8 @@ class PassArrayByDataProcedureVisitor : public PassUtils::PassVisitorm_bindc_name) + suffix; } ASR::asr_t* new_subrout = ASR::make_Function_t(al, x->base.base.loc, - new_symtab, s2c(al, new_name), new_args.p, - new_args.size(), new_body.p, new_body.size(), + new_symtab, s2c(al, new_name), x->m_dependencies, x->n_dependencies, + new_args.p, new_args.size(), new_body.p, new_body.size(), return_var, x->m_abi, x->m_access, x->m_deftype, s2c(al, new_bindc_name), x->m_elemental, x->m_pure, x->m_module, x->m_inline, @@ -421,7 +421,8 @@ void pass_array_by_data(Allocator &al, ASR::TranslationUnit_t &unit, w.visit_TranslationUnit(unit); RemoveArrayByDescriptorProceduresVisitor x(al,v); x.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); + PassUtils::UpdateDependenciesVisitor y(al); + y.visit_TranslationUnit(unit); } } // namespace LFortran diff --git a/src/libasr/pass/pass_list_concat.cpp b/src/libasr/pass/pass_list_concat.cpp index 1780127..7cfed85 100644 --- a/src/libasr/pass/pass_list_concat.cpp +++ b/src/libasr/pass/pass_list_concat.cpp @@ -237,9 +237,7 @@ void pass_list_concat(Allocator &al, ASR::TranslationUnit_t &unit, const LCompilers::PassOptions& /*pass_options*/) { ListConcatVisitor v(al, unit); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } } // namespace LFortran - diff --git a/src/libasr/pass/pass_list_expr.cpp b/src/libasr/pass/pass_list_expr.cpp new file mode 100644 index 0000000..e8f203a --- /dev/null +++ b/src/libasr/pass/pass_list_expr.cpp @@ -0,0 +1,404 @@ +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +namespace LFortran { + +using ASR::down_cast; + +/* + * This ASR pass handles all the high level list features. + */ + + +class ListExprReplacer : public ASR::BaseExprReplacer +{ +private: + + Allocator& al; + ASR::TranslationUnit_t &unit; + ASR::symbol_t* &list_concat_func_name; + ASR::symbol_t* &list_section_func_name; + +public: + ListExprReplacer(Allocator &al_, ASR::TranslationUnit_t &unit_, + ASR::symbol_t* &list_concat_func_name_, + ASR::symbol_t* &list_section_func_name_) : + al(al_), unit(unit_), + list_concat_func_name(list_concat_func_name_), + list_section_func_name(list_section_func_name_) + { } + + void create_while_loop(Location &loc, SymbolTable* symtab, + ASR::expr_t* a_list, ASR::expr_t* start, + ASR::expr_t* end, ASR::expr_t* step, + ASR::expr_t* res_list, + Vec& body, ASR::ttype_t* item_type) { + Vec idx_vars; + PassUtils::create_idx_vars(idx_vars, 1, loc, al, symtab); + ASR::stmt_t* loop_stmt = ASRUtils::STMT(ASR::make_Assignment_t( + al, loc, idx_vars[0], start, nullptr)); + body.push_back(al, loop_stmt); + + ASR::ttype_t* bool_type = ASRUtils::TYPE(ASR::make_Logical_t( + al, loc, 4, nullptr, 0)); + ASR::ttype_t* int_type = ASRUtils::TYPE(ASR::make_Integer_t( + al, loc, 4, nullptr, 0)); + ASR::expr_t* loop_test = ASRUtils::EXPR(ASR::make_IntegerCompare_t( + al, loc, end, ASR::cmpopType::Gt, idx_vars[0], bool_type, nullptr)); + + Vec loop_body; + loop_body.reserve(al, 2); + loop_stmt = ASRUtils::STMT(ASR::make_ListAppend_t( + al, loc, res_list, ASRUtils::EXPR(ASR::make_ListItem_t( + al, loc, a_list, idx_vars[0], item_type, nullptr)))); + loop_body.push_back(al, loop_stmt); + + loop_stmt = ASRUtils::STMT(ASR::make_Assignment_t( + al, loc, idx_vars[0], ASRUtils::EXPR(ASR::make_IntegerBinOp_t( + al, loc, idx_vars[0], ASR::binopType::Add, step, + int_type, nullptr)), nullptr)); + loop_body.push_back(al, loop_stmt); + + loop_stmt = ASRUtils::STMT(ASR::make_WhileLoop_t( + al, loc, loop_test, loop_body.p, loop_body.n)); + body.push_back(al, loop_stmt); + } + + #define create_args(x, type, symtab) { \ + ASR::symbol_t* arg = ASR::down_cast( \ + ASR::make_Variable_t(al, loc, symtab, \ + s2c(al, x), ASR::intentType::In, nullptr, nullptr, \ + ASR::storage_typeType::Default, type, \ + ASR::abiType::Source, ASR::accessType::Public, \ + ASR::presenceType::Required, false)); \ + ASR::expr_t* arg_expr = ASRUtils::EXPR(ASR::make_Var_t(al, loc, arg)); \ + arg_exprs.push_back(al, arg_expr); \ + symtab->add_symbol(x, arg); \ + } + + ASR::symbol_t* create_list_section_func(Location& loc, + SymbolTable*& global_scope, ASR::ttype_t* list_type) { + /* + def _lcompilers_list_section(a_list: list[i32], start: i32, + end: i32, step: i32) -> list[i32]: + result_list: list[i32] + result_list = [] + if (end > len(a_list)): + end = len(a_list) + __1_k: i32 = start + while end > __1_k: + result_list.append(a_list[__1_k]) + __1_k = __1_k + step + return result_list + */ + SymbolTable* list_section_symtab = al.make_new(global_scope); + std::string fn_name = global_scope->get_unique_name("_lcompilers_list_section"); + ASR::ttype_t* item_type = ASR::down_cast(list_type)->m_type; + ASR::ttype_t* int_type = ASRUtils::TYPE(ASR::make_Integer_t( + al, loc, 4, nullptr, 0)); + ASR::ttype_t* bool_type = ASRUtils::TYPE(ASR::make_Logical_t( + al, loc, 4, nullptr, 0)); + + Vec arg_exprs; + arg_exprs.reserve(al, 4); + + Vec body; + body.reserve(al, 4); + + // Declare `a_list`, `start`, `end` and `step` + create_args("a_list", list_type, list_section_symtab) + create_args("start", item_type, list_section_symtab) + create_args("end", item_type, list_section_symtab) + create_args("step", item_type, list_section_symtab) + + // Declare `result_list` + ASR::symbol_t* arg = ASR::down_cast( + ASR::make_Variable_t(al, loc, list_section_symtab, + s2c(al, "result_list"), ASR::intentType::Local, nullptr, nullptr, + ASR::storage_typeType::Default, list_type, + ASR::abiType::Source, ASR::accessType::Public, + ASR::presenceType::Required, false)); + ASR::expr_t* res_list = ASRUtils::EXPR(ASR::make_Var_t(al, loc, arg)); + list_section_symtab->add_symbol("result_list", arg); + + // Empty List + ASR::expr_t* value = ASRUtils::EXPR(ASR::make_ListConstant_t( + al, loc, nullptr, 0, list_type)); + // Initialize `result_list` with `empty value` + ASR::stmt_t* list_section_stmt = ASRUtils::STMT(ASR::make_Assignment_t( + al, loc, res_list, value, nullptr)); + body.push_back(al, list_section_stmt); + + // If statement + { + ASR::expr_t* a_test = ASRUtils::EXPR(ASR::make_IntegerCompare_t( + al, loc, arg_exprs[2], ASR::cmpopType::Gt, ASRUtils::EXPR( + ASR::make_ListLen_t(al, loc, arg_exprs[0], int_type, nullptr)), + bool_type, nullptr)); + + Vec if_body; + if_body.reserve(al, 1); + ASR::stmt_t* if_body_stmt = ASRUtils::STMT(ASR::make_Assignment_t( + al, loc, arg_exprs[2], ASRUtils::EXPR(ASR::make_ListLen_t( + al, loc, arg_exprs[0], int_type, nullptr)), nullptr)); + if_body.push_back(al, if_body_stmt); + + list_section_stmt = ASRUtils::STMT(ASR::make_If_t(al, loc, a_test, + if_body.p, if_body.n, nullptr, 0)); + body.push_back(al, list_section_stmt); + } + + + // Copy a section from the list + // Declare `__1_k` for iterations and assign `start` value + create_while_loop(loc, list_section_symtab, arg_exprs[0], arg_exprs[1], + arg_exprs[2], arg_exprs[3], res_list, body, item_type); + + // Return + list_section_stmt = ASRUtils::STMT(ASR::make_Return_t(al, loc)); + body.push_back(al, list_section_stmt); + + ASR::asr_t *fn = ASR::make_Function_t( + al, loc, + /* a_symtab */ list_section_symtab, + /* a_name */ s2c(al, fn_name), + nullptr, 0, + /* a_args */ arg_exprs.p, + /* n_args */ arg_exprs.n, + /* a_body */ body.p, + /* n_body */ body.n, + /* a_return_var */ res_list, + ASR::abiType::Source, + ASR::accessType::Public, ASR::deftypeType::Implementation, + nullptr, + false, false, false, false, false, + nullptr, 0, + nullptr, 0, + false); + global_scope->add_symbol(fn_name, down_cast(fn)); + return ASR::down_cast(fn); + } + +/* + This function replaces `ListSection` with a `FunctionCall` where + the a list along with left, right and step of the `array_index` node + are passed as arguments to the function. + Then, the function returns the section of the list as a result. + + Converts: + y = x[1:3] // lists + + to: + y = _lcompilers_list_section(x, 1, 3, 1) +*/ + + void replace_ListSection(const ASR::ListSection_t* x) { + Location loc = x->base.base.loc; + ASR::ttype_t* int_type = ASRUtils::TYPE(ASR::make_Integer_t( + al, loc, 4, nullptr, 0)); + Vec args; + args.reserve(al, 4); + ASR::call_arg_t call_arg; + call_arg.loc = x->m_a->base.loc; + call_arg.m_value = x->m_a; + args.push_back(al, call_arg); + if (x->m_section.m_left != nullptr) { + call_arg.loc = x->m_section.m_left->base.loc; + call_arg.m_value = x->m_section.m_left; + } else { + call_arg.loc = loc; + call_arg.m_value = ASRUtils::EXPR(make_IntegerConstant_t( + al, loc, 0, int_type)); + } + args.push_back(al, call_arg); + if (x->m_section.m_right != nullptr) { + call_arg.loc = x->m_section.m_right->base.loc; + call_arg.m_value = x->m_section.m_right; + } else { + call_arg.loc = loc; + call_arg.m_value = ASRUtils::EXPR(ASR::make_ListLen_t( + al, loc, x->m_a, int_type, nullptr)); + } + args.push_back(al, call_arg); + if (x->m_section.m_step != nullptr) { + call_arg.loc = x->m_section.m_step->base.loc; + call_arg.m_value = x->m_section.m_step; + } else { + call_arg.loc = loc; + call_arg.m_value = ASRUtils::EXPR(make_IntegerConstant_t( + al, loc, 1, int_type)); + } + args.push_back(al, call_arg); + if (list_section_func_name == nullptr) { + list_section_func_name = create_list_section_func(unit.base.base.loc, + unit.m_global_scope, x->m_type); + } + *current_expr = ASRUtils::EXPR(ASR::make_FunctionCall_t(al, loc, + list_section_func_name, nullptr, args.p, args.n, + x->m_type, nullptr, nullptr)); + } + + ASR::symbol_t* create_concat_function(Location& loc, + SymbolTable*& global_scope, ASR::ttype_t* list_type) { + /* + def _lcompilers_list_concat(left_list: list[i32], + right_list: list[i32]) -> list[i32]: + result_list: list[i32] + result_list = [] + __1_k: i32 = 0 + while len(left_list) > __1_k: + result_list.append(left_list[__1_k]) + __1_k += 1 + __1_k = 0 + while len(right_list) > __1_k: + result_list.append(right_list[__1_k]) + __1_k += 1 + return result_list + */ + SymbolTable* list_concat_symtab = al.make_new(global_scope); + std::string fn_name = global_scope->get_unique_name("_lcompilers_list_concat"); + + Vec arg_exprs; + arg_exprs.reserve(al, 2); + + Vec body; + body.reserve(al, 4); + + // Declare `left_list` and `right_list` + create_args("left_list", list_type, list_concat_symtab) + create_args("right_list", list_type, list_concat_symtab) + + // Declare `result_list` + ASR::symbol_t* arg = ASR::down_cast( + ASR::make_Variable_t(al, loc, list_concat_symtab, + s2c(al, "result_list"), ASR::intentType::Local, nullptr, nullptr, + ASR::storage_typeType::Default, list_type, + ASR::abiType::Source, ASR::accessType::Public, + ASR::presenceType::Required, false)); + ASR::expr_t* res_list = ASRUtils::EXPR(ASR::make_Var_t(al, loc, arg)); + list_concat_symtab->add_symbol("result_list", arg); + + // Empty List + ASR::expr_t* value = ASRUtils::EXPR(ASR::make_ListConstant_t( + al, loc, nullptr, 0, list_type)); + // Initialize `result_list` with `empty value` + ASR::stmt_t* list_concat_stmt = ASRUtils::STMT(ASR::make_Assignment_t( + al, loc, res_list, value, nullptr)); + body.push_back(al, list_concat_stmt); + ASR::ttype_t* int_type = ASRUtils::TYPE(ASR::make_Integer_t( + al, loc, 4, nullptr, 0)); + ASR::ttype_t* item_type = ASR::down_cast(list_type)->m_type; + + // Declare `__1_k` for iterations and assign `0` + // Copy `left_list` contents + create_while_loop(loc, list_concat_symtab, arg_exprs[0], ASRUtils::EXPR( + make_IntegerConstant_t(al, loc, 0, int_type)), ASRUtils::EXPR( + ASR::make_ListLen_t(al, loc, arg_exprs[0], int_type, nullptr) + ), ASRUtils::EXPR(make_IntegerConstant_t(al, loc, 1, int_type)), + res_list, body, item_type); + + // Copy `right_list` contents + create_while_loop(loc, list_concat_symtab, arg_exprs[1], ASRUtils::EXPR( + make_IntegerConstant_t(al, loc, 0, int_type)), ASRUtils::EXPR( + ASR::make_ListLen_t(al, loc, arg_exprs[1], int_type, nullptr) + ), ASRUtils::EXPR(make_IntegerConstant_t(al, loc, 1, int_type)), + res_list, body, item_type); + + // Return + list_concat_stmt = ASRUtils::STMT(ASR::make_Return_t(al, loc)); + body.push_back(al, list_concat_stmt); + + ASR::asr_t *fn = ASR::make_Function_t( + al, loc, + /* a_symtab */ list_concat_symtab, + /* a_name */ s2c(al, fn_name), + nullptr, 0, + /* a_args */ arg_exprs.p, + /* n_args */ arg_exprs.n, + /* a_body */ body.p, + /* n_body */ body.n, + /* a_return_var */ res_list, + ASR::abiType::Source, + ASR::accessType::Public, ASR::deftypeType::Implementation, + nullptr, + false, false, false, false, false, + nullptr, 0, + nullptr, 0, + false); + global_scope->add_symbol(fn_name, down_cast(fn)); + return ASR::down_cast(fn); + } + +/* + This function replaces ListConcat with a FunctionCall where + the two lists are passed as arguments to the function. + Then, the function returns the concatenated list as a result. + + Converts: + x = i + j // lists + + to: + x = _lcompilers_list_concat(i, j) +*/ + + void replace_ListConcat(const ASR::ListConcat_t* x) { + Location loc = x->base.base.loc; + Vec args; + args.reserve(al, 2); + ASR::call_arg_t left_list, right_list; + left_list.loc = x->m_left->base.loc; + left_list.m_value = x->m_left; + args.push_back(al, left_list); + right_list.loc = x->m_right->base.loc; + right_list.m_value = x->m_right; + args.push_back(al, right_list); + if (list_concat_func_name == nullptr) { + list_concat_func_name = create_concat_function(unit.base.base.loc, + unit.m_global_scope, x->m_type); + } + *current_expr = ASRUtils::EXPR(ASR::make_FunctionCall_t(al, loc, + list_concat_func_name, nullptr, args.p, 2, x->m_type, nullptr, nullptr)); + } + +}; + +class ListExprVisitor : public ASR::CallReplacerOnExpressionsVisitor +{ +private: + + ListExprReplacer replacer; + ASR::symbol_t* list_concat_func = nullptr; + ASR::symbol_t* list_section_func = nullptr; + +public: + + ListExprVisitor(Allocator& al_, ASR::TranslationUnit_t &unit_) : + replacer(al_, unit_, list_concat_func, list_section_func) + { } + + void call_replacer() { + replacer.current_expr = current_expr; + replacer.replace_expr(*current_expr); + } + +}; + +void pass_list_expr(Allocator &al, ASR::TranslationUnit_t &unit, + const LCompilers::PassOptions& /*pass_options*/) { + ListExprVisitor v(al, unit); + v.visit_TranslationUnit(unit); + PassUtils::UpdateDependenciesVisitor u(al); + u.visit_TranslationUnit(unit); +} + + +} // namespace LFortran diff --git a/src/libasr/pass/pass_list_expr.h b/src/libasr/pass/pass_list_expr.h new file mode 100644 index 0000000..f0be841 --- /dev/null +++ b/src/libasr/pass/pass_list_expr.h @@ -0,0 +1,14 @@ +#ifndef LIBASR_PASS_LIST_EXPR_H +#define LIBASR_PASS_LIST_EXPR_H + +#include +#include + +namespace LFortran { + + void pass_list_expr(Allocator &al, ASR::TranslationUnit_t &unit, + const LCompilers::PassOptions& /*pass_options*/); + +} // namespace LFortran + +#endif // LIBASR_PASS_LIST_EXPR_H diff --git a/src/libasr/pass/pass_manager.h b/src/libasr/pass/pass_manager.h index 0ec6237..a925d45 100644 --- a/src/libasr/pass/pass_manager.h +++ b/src/libasr/pass/pass_manager.h @@ -38,7 +38,9 @@ #include #include #include -#include +#include +#include +#include #include #include @@ -75,31 +77,42 @@ namespace LCompilers { {"select_case", &LFortran::pass_replace_select_case}, {"loop_vectorise", &LFortran::pass_loop_vectorise}, {"array_dim_intrinsics_update", &LFortran::pass_update_array_dim_intrinsic_calls}, - {"pass_list_concat", &LFortran::pass_list_concat}, - {"pass_array_by_data", &LFortran::pass_array_by_data} + {"pass_list_expr", &LFortran::pass_list_expr}, + {"pass_array_by_data", &LFortran::pass_array_by_data}, + {"subroutine_from_function", &LFortran::pass_create_subroutine_from_function} }; bool is_fast; bool apply_default_passes; void _apply_passes(Allocator& al, LFortran::ASR::TranslationUnit_t* asr, - std::vector& passes, PassOptions pass_options) { - pass_options.runtime_library_dir = LFortran::get_runtime_library_dir(); + std::vector& passes, PassOptions &pass_options, + LFortran::diag::Diagnostics &diagnostics) { for (size_t i = 0; i < passes.size(); i++) { + // TODO: rework the whole pass manager: construct the passes + // ahead of time (not at the last minute), and remove this much + // earlier + // Note: this is not enough for rtlib, we also need to include + // it + if (rtlib && passes[i] == "unused_functions") continue; _passes_db[passes[i]](al, *asr, pass_options); + LFORTRAN_ASSERT(LFortran::asr_verify(*asr, true, diagnostics)); } } public: + bool rtlib=false; + PassManager(): is_fast{false}, apply_default_passes{false} { _passes = { "global_stmts", "class_constructor", "implied_do_loops", "pass_array_by_data", - "pass_list_concat", + "pass_list_expr", "arr_slice", + "subroutine_from_function", "array_op", "print_arr", "print_list", @@ -117,6 +130,7 @@ namespace LCompilers { "implied_do_loops", "pass_array_by_data", "arr_slice", + "subroutine_from_function", "array_op", "print_arr", "print_list", @@ -167,16 +181,19 @@ namespace LCompilers { } void apply_passes(Allocator& al, LFortran::ASR::TranslationUnit_t* asr, - PassOptions& pass_options) { + PassOptions& pass_options, + LFortran::diag::Diagnostics &diagnostics) { if( !_user_defined_passes.empty() ) { pass_options.fast = true; - _apply_passes(al, asr, _user_defined_passes, pass_options); + _apply_passes(al, asr, _user_defined_passes, pass_options, + diagnostics); } else if( apply_default_passes ) { pass_options.fast = is_fast; if( is_fast ) { - _apply_passes(al, asr, _with_optimization_passes, pass_options); + _apply_passes(al, asr, _with_optimization_passes, pass_options, + diagnostics); } else { - _apply_passes(al, asr, _passes, pass_options); + _apply_passes(al, asr, _passes, pass_options, diagnostics); } } } diff --git a/src/libasr/pass/pass_utils.cpp b/src/libasr/pass/pass_utils.cpp index f7c17ec..27e2ba2 100644 --- a/src/libasr/pass/pass_utils.cpp +++ b/src/libasr/pass/pass_utils.cpp @@ -173,7 +173,8 @@ namespace LFortran { ASR::expr_t* array_ref = LFortran::ASRUtils::EXPR(ASR::make_ArrayItem_t(al, arr_expr->base.loc, arr_expr, args.p, args.size(), - _type, nullptr)); + _type, ASR::arraystorageType::RowMajor, + nullptr)); return array_ref; } @@ -195,7 +196,8 @@ namespace LFortran { ASR::expr_t* arr_var = ASRUtils::EXPR(ASR::make_Var_t(al, loc, arr)); ASR::expr_t* array_ref = LFortran::ASRUtils::EXPR(ASR::make_ArrayItem_t(al, loc, arr_var, args.p, args.size(), - _type, nullptr)); + _type, ASR::arraystorageType::RowMajor, + nullptr)); return array_ref; } @@ -242,7 +244,7 @@ namespace LFortran { ASR::symbol_t* import_generic_procedure(std::string func_name, std::string module_name, Allocator& al, ASR::TranslationUnit_t& unit, - const std::string &rl_path, + LCompilers::PassOptions& pass_options, SymbolTable*& current_scope, Location& loc) { ASR::symbol_t *v; std::string remote_sym = func_name; @@ -253,7 +255,7 @@ namespace LFortran { // anyway, so verify will be run no matter what. ASR::Module_t *m = LFortran::ASRUtils::load_module(al, current_scope, module_name, loc, true, - rl_path, false, + pass_options, false, [&](const std::string &msg, const Location &) { throw LCompilersException(msg); } ); ASR::symbol_t *t = m->m_symtab->resolve_symbol(remote_sym); @@ -280,7 +282,7 @@ namespace LFortran { ASR::symbol_t* import_function(std::string func_name, std::string module_name, Allocator& al, ASR::TranslationUnit_t& unit, - const std::string &rl_path, + LCompilers::PassOptions& pass_options, SymbolTable*& current_scope, Location& loc) { ASR::symbol_t *v; std::string remote_sym = func_name; @@ -291,7 +293,7 @@ namespace LFortran { // anyway, so verify will be run no matter what. ASR::Module_t *m = LFortran::ASRUtils::load_module(al, current_scope, module_name, loc, true, - rl_path, false, + pass_options, false, [&](const std::string &msg, const Location &) { throw LCompilersException(msg); }); ASR::symbol_t *t = m->m_symtab->resolve_symbol(remote_sym); @@ -398,11 +400,11 @@ namespace LFortran { ASR::stmt_t* get_flipsign(ASR::expr_t* arg0, ASR::expr_t* arg1, Allocator& al, ASR::TranslationUnit_t& unit, - const std::string& rl_path, + LCompilers::PassOptions& pass_options, SymbolTable*& current_scope, const std::function err) { ASR::symbol_t *v = import_generic_procedure("flipsign", "lfortran_intrinsic_optimization", - al, unit, rl_path, current_scope, arg0->base.loc); + al, unit, pass_options, current_scope, arg0->base.loc); Vec args; args.reserve(al, 2); ASR::call_arg_t arg0_, arg1_; @@ -473,11 +475,11 @@ namespace LFortran { } ASR::expr_t* get_fma(ASR::expr_t* arg0, ASR::expr_t* arg1, ASR::expr_t* arg2, - Allocator& al, ASR::TranslationUnit_t& unit, std::string& rl_path, + Allocator& al, ASR::TranslationUnit_t& unit, LCompilers::PassOptions& pass_options, SymbolTable*& current_scope, Location& loc, const std::function err) { ASR::symbol_t *v = import_generic_procedure("fma", "lfortran_intrinsic_optimization", - al, unit, rl_path, current_scope, arg0->base.loc); + al, unit, pass_options, current_scope, arg0->base.loc); Vec args; args.reserve(al, 3); ASR::call_arg_t arg0_, arg1_, arg2_; @@ -545,7 +547,7 @@ namespace LFortran { ASR::asr_t* vector_copy_asr = ASR::make_Function_t(al, unit.base.base.loc, vector_copy_symtab, - s2c(al, vector_copy_name), arg_exprs.p, arg_exprs.size(), + s2c(al, vector_copy_name), nullptr, 0, arg_exprs.p, arg_exprs.size(), /* nullptr, 0, */ body.p, body.size(), nullptr, ASR::abiType::Source, ASR::accessType::Public, ASR::deftypeType::Implementation, @@ -589,11 +591,11 @@ namespace LFortran { } ASR::expr_t* get_sign_from_value(ASR::expr_t* arg0, ASR::expr_t* arg1, - Allocator& al, ASR::TranslationUnit_t& unit, std::string& rl_path, + Allocator& al, ASR::TranslationUnit_t& unit, LCompilers::PassOptions& pass_options, SymbolTable*& current_scope, Location& loc, const std::function err) { ASR::symbol_t *v = import_generic_procedure("sign_from_value", "lfortran_intrinsic_optimization", - al, unit, rl_path, current_scope, arg0->base.loc); + al, unit, pass_options, current_scope, arg0->base.loc); Vec args; args.reserve(al, 2); ASR::call_arg_t arg0_, arg1_; @@ -632,17 +634,65 @@ namespace LFortran { } LFORTRAN_ASSERT(c); ASR::cmpopType cmp_op; + if( comp == -1 ) { int increment; + bool not_constant_inc = false; + if (!ASRUtils::is_integer(*ASRUtils::expr_type(c))) { + throw LCompilersException("Do loop increment type should be an integer"); + } if (c->type == ASR::exprType::IntegerConstant) { increment = ASR::down_cast(c)->m_n; } else if (c->type == ASR::exprType::IntegerUnaryMinus) { ASR::IntegerUnaryMinus_t *u = ASR::down_cast(c); increment = - ASR::down_cast(u->m_arg)->m_n; } else { - throw LCompilersException("Do loop increment type not supported"); + // This is the case when increment operator is not a + // constant, and so we need some conditions to check + // in the backend and generate while loop according + // to avoid infinite loops. + not_constant_inc = true; } - if (increment > 0) { + + if (not_constant_inc) { + ASR::expr_t *target = loop.m_head.m_v; + int a_kind = ASRUtils::extract_kind_from_ttype_t(ASRUtils::expr_type(target)); + ASR::ttype_t *int_type = LFortran::ASRUtils::TYPE(ASR::make_Integer_t(al, loc, a_kind, nullptr, 0)); + + ASR::ttype_t *log_type = ASRUtils::TYPE( + ASR::make_Logical_t(al, loc, 4, nullptr, 0)); + ASR::expr_t *const_zero = ASRUtils::EXPR(ASR::make_IntegerConstant_t(al, + loc, 0, int_type)); + + // test1: c > 0 + ASR::expr_t *test1 = ASRUtils::EXPR(ASR::make_IntegerCompare_t(al, loop.base.base.loc, + c, ASR::cmpopType::Gt, const_zero, log_type, nullptr)); + // test2: c <= 0 + ASR::expr_t *test2 = ASRUtils::EXPR(ASR::make_IntegerCompare_t(al, loop.base.base.loc, + c, ASR::cmpopType::LtE, const_zero, log_type, nullptr)); + + // test11: target + c <= b + ASR::expr_t *test11 = LFortran::ASRUtils::EXPR(ASR::make_IntegerCompare_t(al, loc, + LFortran::ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, loc, target, + ASR::binopType::Add, c, int_type, nullptr)), ASR::cmpopType::LtE, b, log_type, nullptr)); + + // test22: target + c >= b + ASR::expr_t *test22 = LFortran::ASRUtils::EXPR(ASR::make_IntegerCompare_t(al, loc, + LFortran::ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, loc, target, + ASR::binopType::Add, c, int_type, nullptr)), ASR::cmpopType::GtE, b, log_type, nullptr)); + + // cond1: test1 && test11 + ASR::expr_t *cond1 = LFortran::ASRUtils::EXPR(make_LogicalBinOp_t(al, loc, + test1, ASR::logicalbinopType::And, test11, log_type, nullptr)); + + // cond2: test2 && test22 + ASR::expr_t *cond2 = LFortran::ASRUtils::EXPR(make_LogicalBinOp_t(al, loc, + test2, ASR::logicalbinopType::And, test22, log_type, nullptr)); + + // cond: cond1 || cond2 + cond = LFortran::ASRUtils::EXPR(make_LogicalBinOp_t(al, loc, + cond1, ASR::logicalbinopType::Or, cond2, log_type, nullptr)); + } else if (increment > 0) { cmp_op = ASR::cmpopType::LtE; } else { cmp_op = ASR::cmpopType::GtE; @@ -650,18 +700,26 @@ namespace LFortran { } else { cmp_op = (ASR::cmpopType) comp; } + ASR::expr_t *target = loop.m_head.m_v; int a_kind = ASRUtils::extract_kind_from_ttype_t(ASRUtils::expr_type(target)); - ASR::ttype_t *type = LFortran::ASRUtils::TYPE(ASR::make_Integer_t(al, loc, a_kind, nullptr, 0)); - stmt1 = LFortran::ASRUtils::STMT(ASR::make_Assignment_t(al, loc, target, - LFortran::ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, loc, a, ASR::binopType::Sub, c, type, nullptr)), nullptr)); + ASR::ttype_t *type = LFortran::ASRUtils::TYPE(ASR::make_Integer_t(al, loc, + a_kind, nullptr, 0)); - cond = LFortran::ASRUtils::EXPR(ASR::make_IntegerCompare_t(al, loc, - LFortran::ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, loc, target, ASR::binopType::Add, c, type, nullptr)), - cmp_op, b, type, nullptr)); + stmt1 = LFortran::ASRUtils::STMT(ASR::make_Assignment_t(al, loc, target, + LFortran::ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, loc, a, + ASR::binopType::Sub, c, type, nullptr)), nullptr)); inc_stmt = LFortran::ASRUtils::STMT(ASR::make_Assignment_t(al, loc, target, - LFortran::ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, loc, target, ASR::binopType::Add, c, type, nullptr)), nullptr)); + LFortran::ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, loc, target, + ASR::binopType::Add, c, type, nullptr)), nullptr)); + if (cond == nullptr) { + ASR::ttype_t *log_type = ASRUtils::TYPE( + ASR::make_Logical_t(al, loc, 4, nullptr, 0)); + cond = LFortran::ASRUtils::EXPR(ASR::make_IntegerCompare_t(al, loc, + LFortran::ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, loc, target, + ASR::binopType::Add, c, type, nullptr)), cmp_op, b, log_type, nullptr)); + } } Vec body; body.reserve(al, loop.n_body + (inc_stmt != nullptr)); diff --git a/src/libasr/pass/pass_utils.h b/src/libasr/pass/pass_utils.h index 31a9b8a..caad3cf 100644 --- a/src/libasr/pass/pass_utils.h +++ b/src/libasr/pass/pass_utils.h @@ -41,7 +41,7 @@ namespace LFortran { ASR::stmt_t* get_flipsign(ASR::expr_t* arg0, ASR::expr_t* arg1, Allocator& al, ASR::TranslationUnit_t& unit, - const std::string &rl_path, + LCompilers::PassOptions& pass_options, SymbolTable*& current_scope, const std::function err); @@ -54,12 +54,13 @@ namespace LFortran { Allocator& al, SymbolTable*& current_scope, ASR::ttype_t* var_type); ASR::expr_t* get_fma(ASR::expr_t* arg0, ASR::expr_t* arg1, ASR::expr_t* arg2, - Allocator& al, ASR::TranslationUnit_t& unit, std::string& rl_path, + Allocator& al, ASR::TranslationUnit_t& unit, LCompilers::PassOptions& pass_options, SymbolTable*& current_scope,Location& loc, const std::function err); ASR::expr_t* get_sign_from_value(ASR::expr_t* arg0, ASR::expr_t* arg1, - Allocator& al, ASR::TranslationUnit_t& unit, std::string& rl_path, + Allocator& al, ASR::TranslationUnit_t& unit, + LCompilers::PassOptions& pass_options, SymbolTable*& current_scope, Location& loc, const std::function err); @@ -71,6 +72,10 @@ namespace LFortran { Vec replace_doloop(Allocator &al, const ASR::DoLoop_t &loop, int comp=-1); + static inline bool is_aggregate_type(ASR::expr_t* var) { + return ASR::is_a(*ASRUtils::expr_type(var)); + } + template class PassVisitor: public ASR::BaseWalkVisitor { @@ -180,6 +185,12 @@ namespace LFortran { } } + void visit_DoLoop(const ASR::DoLoop_t& x) { + self().visit_do_loop_head(x.m_head); + ASR::DoLoop_t& xx = const_cast(x); + transform_stmts(xx.m_body, xx.n_body); + } + }; template @@ -199,6 +210,77 @@ namespace LFortran { }; + class UpdateDependenciesVisitor : public ASR::BaseWalkVisitor { + + private: + + Vec function_dependencies; + Vec module_dependencies; + Allocator& al; + bool fill_function_dependencies; + bool fill_module_dependencies; + + public: + + UpdateDependenciesVisitor(Allocator &al_) + : al(al_), fill_function_dependencies(false), + fill_module_dependencies(false) + {} + + void visit_Function(const ASR::Function_t& x) { + ASR::Function_t& xx = const_cast(x); + function_dependencies.n = 0; + function_dependencies.reserve(al, 1); + bool fill_function_dependencies_copy = fill_function_dependencies; + fill_function_dependencies = true; + BaseWalkVisitor::visit_Function(x); + // std::cout<<"dependencies of "<(x); + module_dependencies.n = 0; + module_dependencies.from_pointer_n_copy(al, xx.m_dependencies, xx.n_dependencies); + bool fill_module_dependencies_copy = fill_module_dependencies; + fill_module_dependencies = true; + BaseWalkVisitor::visit_Module(x); + xx.n_dependencies = module_dependencies.size(); + xx.m_dependencies = module_dependencies.p; + fill_module_dependencies = fill_module_dependencies_copy; + } + + void visit_FunctionCall(const ASR::FunctionCall_t& x) { + if( fill_function_dependencies ) { + function_dependencies.push_back(al, ASRUtils::symbol_name(x.m_name)); + } + if( ASR::is_a(*x.m_name) && + fill_module_dependencies ) { + ASR::ExternalSymbol_t* x_m_name = ASR::down_cast(x.m_name); + module_dependencies.push_back(al, x_m_name->m_module_name); + } + BaseWalkVisitor::visit_FunctionCall(x); + } + + void visit_SubroutineCall(const ASR::SubroutineCall_t& x) { + if( fill_function_dependencies ) { + function_dependencies.push_back(al, ASRUtils::symbol_name(x.m_name)); + } + if( ASR::is_a(*x.m_name) && + fill_module_dependencies ) { + ASR::ExternalSymbol_t* x_m_name = ASR::down_cast(x.m_name); + module_dependencies.push_back(al, x_m_name->m_module_name); + } + BaseWalkVisitor::visit_SubroutineCall(x); + } + }; + } } // namespace LFortran diff --git a/src/libasr/pass/print_arr.cpp b/src/libasr/pass/print_arr.cpp index 1cfb37f..ec271c0 100644 --- a/src/libasr/pass/print_arr.cpp +++ b/src/libasr/pass/print_arr.cpp @@ -83,7 +83,6 @@ void pass_replace_print_arr(Allocator &al, ASR::TranslationUnit_t &unit, std::string rl_path = pass_options.runtime_library_dir; PrintArrVisitor v(al, rl_path); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/print_list.cpp b/src/libasr/pass/print_list.cpp index 3e0469b..e853c20 100644 --- a/src/libasr/pass/print_list.cpp +++ b/src/libasr/pass/print_list.cpp @@ -204,7 +204,6 @@ void pass_replace_print_list( std::string rl_path = pass_options.runtime_library_dir; PrintListVisitor v(al, rl_path); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } } // namespace LFortran diff --git a/src/libasr/pass/select_case.cpp b/src/libasr/pass/select_case.cpp index d50ca25..e809a6c 100644 --- a/src/libasr/pass/select_case.cpp +++ b/src/libasr/pass/select_case.cpp @@ -172,7 +172,6 @@ void pass_replace_select_case(Allocator &al, ASR::TranslationUnit_t &unit, // to transform doubly nested loops: v.visit_TranslationUnit(unit); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } diff --git a/src/libasr/pass/sign_from_value.cpp b/src/libasr/pass/sign_from_value.cpp index 49aab9a..2c6691e 100644 --- a/src/libasr/pass/sign_from_value.cpp +++ b/src/libasr/pass/sign_from_value.cpp @@ -36,7 +36,7 @@ class SignFromValueVisitor : public PassUtils::SkipOptimizationFunctionVisitor +#include +#include +#include +#include +#include +#include + +#include +#include + + +namespace LFortran { + +using ASR::down_cast; +using ASR::is_a; + +class CreateFunctionFromSubroutine: public PassUtils::PassVisitor { + + public: + + CreateFunctionFromSubroutine(Allocator &al_) : + PassVisitor(al_, nullptr) + { + pass_result.reserve(al, 1); + } + + ASR::symbol_t* create_subroutine_from_function(ASR::Function_t* s) { + for( auto& s_item: s->m_symtab->get_scope() ) { + ASR::symbol_t* curr_sym = s_item.second; + if( curr_sym->type == ASR::symbolType::Variable ) { + ASR::Variable_t* var = ASR::down_cast(curr_sym); + if( var->m_intent == ASR::intentType::Unspecified ) { + var->m_intent = ASR::intentType::In; + } else if( var->m_intent == ASR::intentType::ReturnVar ) { + var->m_intent = ASR::intentType::Out; + } + } + } + Vec a_args; + a_args.reserve(al, s->n_args + 1); + for( size_t i = 0; i < s->n_args; i++ ) { + a_args.push_back(al, s->m_args[i]); + } + LFORTRAN_ASSERT(s->m_return_var) + a_args.push_back(al, s->m_return_var); + ASR::asr_t* s_sub_asr = ASR::make_Function_t(al, s->base.base.loc, + s->m_symtab, + s->m_name, s->m_dependencies, s->n_dependencies, + a_args.p, a_args.size(), s->m_body, s->n_body, + nullptr, + s->m_abi, s->m_access, s->m_deftype, nullptr, false, false, + false, s->m_inline, s->m_static, + s->m_type_params, s->n_type_params, + s->m_restrictions, s->n_restrictions, + s->m_is_restriction); + ASR::symbol_t* s_sub = ASR::down_cast(s_sub_asr); + return s_sub; + } + + void visit_TranslationUnit(const ASR::TranslationUnit_t &x) { + std::vector> replace_vec; + // Transform functions returning arrays to subroutines + for (auto &item : x.m_global_scope->get_scope()) { + if (is_a(*item.second)) { + ASR::Function_t *s = down_cast(item.second); + if (s->m_return_var) { + /* + * A function which returns a aggregate type like array, struct will be converted + * to a subroutine with the destination array as the last + * argument. This helps in avoiding deep copies and the + * destination memory directly gets filled inside the subroutine. + */ + if( PassUtils::is_aggregate_type(s->m_return_var) ) { + ASR::symbol_t* s_sub = create_subroutine_from_function(s); + replace_vec.push_back(std::make_pair(item.first, s_sub)); + } + } + } + } + + // FIXME: this is a hack, we need to pass in a non-const `x`, + // which requires to generate a TransformVisitor. + ASR::TranslationUnit_t &xx = const_cast(x); + // Updating the symbol table so that now the name + // of the function (which returned array) now points + // to the newly created subroutine. + for( auto& item: replace_vec ) { + xx.m_global_scope->add_symbol(item.first, item.second); + } + + // Now visit everything else + for (auto &item : x.m_global_scope->get_scope()) { + this->visit_symbol(*item.second); + } + } + + void visit_Program(const ASR::Program_t &x) { + std::vector > replace_vec; + // FIXME: this is a hack, we need to pass in a non-const `x`, + // which requires to generate a TransformVisitor. + ASR::Program_t &xx = const_cast(x); + current_scope = xx.m_symtab; + + for (auto &item : x.m_symtab->get_scope()) { + if (is_a(*item.second)) { + ASR::Function_t *s = ASR::down_cast(item.second); + if (s->m_return_var) { + /* + * A function which returns an array will be converted + * to a subroutine with the destination array as the last + * argument. This helps in avoiding deep copies and the + * destination memory directly gets filled inside the subroutine. + */ + if( PassUtils::is_aggregate_type(s->m_return_var) ) { + ASR::symbol_t* s_sub = create_subroutine_from_function(s); + replace_vec.push_back(std::make_pair(item.first, s_sub)); + } + } + } + } + + // Updating the symbol table so that now the name + // of the function (which returned array) now points + // to the newly created subroutine. + for( auto& item: replace_vec ) { + current_scope->add_symbol(item.first, item.second); + } + + for (auto &item : x.m_symtab->get_scope()) { + if (is_a(*item.second)) { + ASR::AssociateBlock_t *s = ASR::down_cast(item.second); + visit_AssociateBlock(*s); + } + if (is_a(*item.second)) { + ASR::Function_t *s = ASR::down_cast(item.second); + visit_Function(*s); + } + } + + current_scope = xx.m_symtab; + transform_stmts(xx.m_body, xx.n_body); + + } + +}; + +class ReplaceFunctionCallWithSubroutineCall: public PassUtils::PassVisitor { + + private: + + ASR::expr_t *result_var; + + public: + + ReplaceFunctionCallWithSubroutineCall(Allocator& al_): + PassVisitor(al_, nullptr), result_var(nullptr) + { + pass_result.reserve(al, 1); + } + + void visit_Assignment(const ASR::Assignment_t& x) { + if( PassUtils::is_aggregate_type(x.m_target) ) { + result_var = x.m_target; + this->visit_expr(*(x.m_value)); + } + result_var = nullptr; + } + + void visit_FunctionCall(const ASR::FunctionCall_t& x) { + std::string x_name; + if( x.m_name->type == ASR::symbolType::ExternalSymbol ) { + x_name = down_cast(x.m_name)->m_name; + } else if( x.m_name->type == ASR::symbolType::Function ) { + x_name = down_cast(x.m_name)->m_name; + } + // The following checks if the name of a function actually + // points to a subroutine. If true this would mean that the + // original function returned an array and is now a subroutine. + // So the current function call will be converted to a subroutine + // call. In short, this check acts as a signal whether to convert + // a function call to a subroutine call. + if (current_scope == nullptr) { + return ; + } + + ASR::symbol_t *sub = current_scope->resolve_symbol(x_name); + if (sub && ASR::is_a(*sub) + && ASR::down_cast(sub)->m_return_var == nullptr) { + LFORTRAN_ASSERT(result_var != nullptr); + Vec s_args; + s_args.reserve(al, x.n_args + 1); + for( size_t i = 0; i < x.n_args; i++ ) { + s_args.push_back(al, x.m_args[i]); + } + ASR::call_arg_t result_arg; + result_arg.loc = result_var->base.loc; + result_arg.m_value = result_var; + s_args.push_back(al, result_arg); + ASR::stmt_t* subrout_call = LFortran::ASRUtils::STMT(ASR::make_SubroutineCall_t(al, x.base.base.loc, + sub, nullptr, + s_args.p, s_args.size(), nullptr)); + pass_result.push_back(al, subrout_call); + } + result_var = nullptr; + } + +}; + +void pass_create_subroutine_from_function(Allocator &al, ASR::TranslationUnit_t &unit, + const LCompilers::PassOptions& /*pass_options*/) { + CreateFunctionFromSubroutine v(al); + v.visit_TranslationUnit(unit); + ReplaceFunctionCallWithSubroutineCall u(al); + u.visit_TranslationUnit(unit); +} + + +} // namespace LFortran diff --git a/src/libasr/pass/subroutine_from_function.h b/src/libasr/pass/subroutine_from_function.h new file mode 100644 index 0000000..9dc0afa --- /dev/null +++ b/src/libasr/pass/subroutine_from_function.h @@ -0,0 +1,14 @@ +#ifndef LIBASR_PASS_SUBROUTINE_FROM_FUNCTION_H +#define LIBASR_PASS_SUBROUTINE_FROM_FUNCTION_H + +#include +#include + +namespace LFortran { + + void pass_create_subroutine_from_function(Allocator &al, ASR::TranslationUnit_t &unit, + const LCompilers::PassOptions& pass_options); + +} // namespace LFortran + +#endif // LIBASR_PASS_SUBROUTINE_FROM_FUNCTION_H diff --git a/src/libasr/pass/unused_functions.cpp b/src/libasr/pass/unused_functions.cpp index b2de852..b0800eb 100644 --- a/src/libasr/pass/unused_functions.cpp +++ b/src/libasr/pass/unused_functions.cpp @@ -262,7 +262,6 @@ void pass_unused_functions(Allocator &al, ASR::TranslationUnit_t &unit, UnusedFunctionsVisitor v(al); v.fn_unused = fn_unused; v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } } } diff --git a/src/libasr/pass/update_array_dim_intrinsic_calls.cpp b/src/libasr/pass/update_array_dim_intrinsic_calls.cpp index 6806eb8..9d76c7b 100644 --- a/src/libasr/pass/update_array_dim_intrinsic_calls.cpp +++ b/src/libasr/pass/update_array_dim_intrinsic_calls.cpp @@ -98,7 +98,7 @@ class ReplaceArrayDimIntrinsicCalls: public ASR::BaseExprReplacerm_v); ASR::dimension_t* dims = nullptr; int n = ASRUtils::extract_dimensions_from_ttype(array_type, dims); - bool is_argument = v->m_intent == ASRUtils::intent_in || v->m_intent == ASRUtils::intent_out; + bool is_argument = ASRUtils::is_arg_dummy(v->m_intent); if( !(n > 0 && is_argument && !ASRUtils::is_dimension_empty(dims, n)) ) { return ; @@ -147,7 +147,6 @@ void pass_update_array_dim_intrinsic_calls(Allocator &al, ASR::TranslationUnit_t const LCompilers::PassOptions& /*pass_options*/) { ArrayDimIntrinsicCallsVisitor v(al); v.visit_TranslationUnit(unit); - LFORTRAN_ASSERT(asr_verify(unit)); } } // namespace LFortran diff --git a/src/libasr/runtime/lfortran_intrinsics.c b/src/libasr/runtime/lfortran_intrinsics.c index 3abd0f6..490a356 100644 --- a/src/libasr/runtime/lfortran_intrinsics.c +++ b/src/libasr/runtime/lfortran_intrinsics.c @@ -56,6 +56,15 @@ LFORTRAN_API void _lfortran_printf(const char* format, ...) va_end(args); } +LFORTRAN_API void _lcompilers_print_error(const char* format, ...) +{ + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + fflush(stderr); + va_end(args); +} + LFORTRAN_API void _lfortran_complex_add_32(struct _lfortran_complex_32* a, struct _lfortran_complex_32* b, struct _lfortran_complex_32 *result) { @@ -864,6 +873,11 @@ LFORTRAN_API int _lfortran_str_ord(char** s) return (*s)[0]; } +LFORTRAN_API int _lfortran_str_ord_c(char* s) +{ + return s[0]; +} + LFORTRAN_API char* _lfortran_str_chr(int val) { char* dest_char = (char*)malloc(2); @@ -1063,7 +1077,7 @@ LFORTRAN_API void _lfortran_cpu_time(double *t) { LFORTRAN_API void _lfortran_i32sys_clock( int32_t *count, int32_t *rate, int32_t *max) { -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__MACH__) *count = - INT_MAX; *rate = 0; *max = 0; @@ -1083,7 +1097,7 @@ LFORTRAN_API void _lfortran_i32sys_clock( LFORTRAN_API void _lfortran_i64sys_clock( uint64_t *count, int64_t *rate, int64_t *max) { -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__MACH__) *count = - INT_MAX; *rate = 0; *max = 0; diff --git a/src/libasr/runtime/lfortran_intrinsics.h b/src/libasr/runtime/lfortran_intrinsics.h index 9198cb1..05e4c15 100644 --- a/src/libasr/runtime/lfortran_intrinsics.h +++ b/src/libasr/runtime/lfortran_intrinsics.h @@ -40,7 +40,7 @@ LFORTRAN_API double _lfortran_random(); LFORTRAN_API int _lfortran_randrange(int lower, int upper); LFORTRAN_API int _lfortran_random_int(int lower, int upper); LFORTRAN_API void _lfortran_printf(const char* format, ...); - +LFORTRAN_API void _lcompilers_print_error(const char* format, ...); LFORTRAN_API void _lfortran_complex_add_32(struct _lfortran_complex_32* a, struct _lfortran_complex_32* b, struct _lfortran_complex_32 *result); LFORTRAN_API void _lfortran_complex_sub(struct _lfortran_complex_32* a, @@ -158,6 +158,7 @@ LFORTRAN_API char* _lfortran_strrepeat_c(char* s, int32_t n); LFORTRAN_API void _lfortran_strcat(char** s1, char** s2, char** dest); LFORTRAN_API int _lfortran_str_len(char** s); LFORTRAN_API int _lfortran_str_ord(char** s); +LFORTRAN_API int _lfortran_str_ord_c(char* s); LFORTRAN_API char* _lfortran_str_chr(int c); LFORTRAN_API int _lfortran_str_to_int(char** s); LFORTRAN_API char* _lfortran_malloc(int size); diff --git a/src/libasr/serialization.cpp b/src/libasr/serialization.cpp index 7e61f59..7b7d528 100644 --- a/src/libasr/serialization.cpp +++ b/src/libasr/serialization.cpp @@ -322,7 +322,8 @@ ASR::asr_t* deserialize_asr(Allocator &al, const std::string &s, ASR::FixParentSymtabVisitor p; p.visit_TranslationUnit(*tu); - LFORTRAN_ASSERT(asr_verify(*tu, false)); + diag::Diagnostics diagnostics; + LFORTRAN_ASSERT(asr_verify(*tu, false, diagnostics)); return node; } diff --git a/src/libasr/utils.h b/src/libasr/utils.h index b7bccc8..bdec5e0 100644 --- a/src/libasr/utils.h +++ b/src/libasr/utils.h @@ -2,6 +2,8 @@ #define LIBASR_UTILS_H #include +#include +#include #include namespace LFortran { @@ -11,12 +13,19 @@ enum Platform { macOS_Intel, macOS_ARM, Windows, - FreeBSD + FreeBSD, + OpenBSD, }; Platform get_platform(); struct CompilerOptions { + std::filesystem::path mod_files_dir; + std::vector include_dirs; + + // TODO: Convert to std::filesystem::path (also change find_and_load_module()) + std::string runtime_library_dir; + bool fixed_form = false; bool c_preprocessor = false; std::vector c_preprocessor_defines; @@ -32,11 +41,17 @@ struct CompilerOptions { bool generate_object_code = false; bool no_warnings = false; bool no_error_banner = false; + bool enable_bounds_checking = false; std::string error_format = "human"; bool new_parser = false; bool implicit_typing = false; bool implicit_interface = false; + bool rtlib = false; std::string target = ""; + std::string arg_o = ""; + bool emit_debug_info = false; + bool emit_debug_line_column = false; + std::string import_path = ""; Platform platform; CompilerOptions () : platform{get_platform()} {}; @@ -44,6 +59,7 @@ struct CompilerOptions { bool read_file(const std::string &filename, std::string &text); bool present(Vec &v, const char* name); +bool present(char** const v, size_t n, const std::string name); int initialize(); } // LFortran @@ -51,16 +67,16 @@ int initialize(); namespace LCompilers { struct PassOptions { + std::filesystem::path mod_files_dir; + std::vector include_dirs; + std::string run_fun; // for global_stmts pass + // TODO: Convert to std::filesystem::path (also change find_and_load_module()) std::string runtime_library_dir; - bool always_run; // for unused_functions pass - bool inline_external_symbol_calls; // for inline_function_calls pass - int64_t unroll_factor; // for loop_unroll pass - bool fast; // is fast flag enabled. - - PassOptions(): always_run(false), inline_external_symbol_calls(true), - unroll_factor(32), fast(false) - {} + bool always_run = false; // for unused_functions pass + bool inline_external_symbol_calls = true; // for inline_function_calls pass + int64_t unroll_factor = 32; // for loop_unroll pass + bool fast = false; // is fast flag enabled. }; } diff --git a/src/libasr/utils2.cpp b/src/libasr/utils2.cpp index 4b6902d..f38c5b4 100644 --- a/src/libasr/utils2.cpp +++ b/src/libasr/utils2.cpp @@ -37,24 +37,31 @@ bool present(Vec &v, const char* name) { return false; } +bool present(char** const v, size_t n, const std::string name) { + for (size_t i = 0; i < n; i++) { + if (std::string(v[i]) == name) { + return true; + } + } + return false; +} + Platform get_platform() { -#ifdef _WIN32 +#if defined(_WIN32) return Platform::Windows; -#else -# ifdef __APPLE__ -# ifdef __aarch64__ +#elif defined(__APPLE__) +# ifdef __aarch64__ return Platform::macOS_ARM; -# else - return Platform::macOS_Intel; -# endif # else -# ifdef __FreeBSD__ + return Platform::macOS_Intel; +# endif +#elif defined(__FreeBSD__) return Platform::FreeBSD; -# else +#elif defined(__OpenBSD__) + return Platform::OpenBSD; +#else return Platform::Linux; -# endif -# endif #endif }