From 05f5ed48f4116711c654d56a7c488f1e3bc7ad78 Mon Sep 17 00:00:00 2001 From: Gagandeep Singh Date: Wed, 27 Mar 2024 23:21:30 +0530 Subject: [PATCH] DEV: Sync libasr with LC --- src/libasr/asr_utils.h | 21 +++ src/libasr/asr_verify.cpp | 2 + src/libasr/casting_utils.cpp | 6 + src/libasr/casting_utils.h | 2 - src/libasr/codegen/asr_to_c_cpp.h | 3 + src/libasr/codegen/asr_to_fortran.cpp | 1 + src/libasr/codegen/asr_to_julia.cpp | 1 + src/libasr/codegen/asr_to_llvm.cpp | 129 ++++++++++-------- .../intrinsic_func_registry_util_gen.py | 6 + src/libasr/pass/array_op.cpp | 3 + src/libasr/pass/flip_sign.cpp | 1 + .../pass/intrinsic_array_function_registry.h | 7 +- src/libasr/pass/intrinsic_function.cpp | 5 +- src/libasr/pass/intrinsic_function_registry.h | 6 + .../pass/intrinsic_function_registry_util.h | 45 ++++++ src/libasr/pass/intrinsic_functions.h | 66 +++++++++ src/libasr/pass/pass_manager.h | 4 +- src/libasr/pass/pass_utils.h | 29 ++++ .../promote_allocatable_to_nonallocatable.cpp | 21 +++ 19 files changed, 293 insertions(+), 65 deletions(-) diff --git a/src/libasr/asr_utils.h b/src/libasr/asr_utils.h index 4b43435fdd..924298a840 100644 --- a/src/libasr/asr_utils.h +++ b/src/libasr/asr_utils.h @@ -2013,6 +2013,12 @@ static inline bool is_pointer(ASR::ttype_t *x) { } static inline bool is_integer(ASR::ttype_t &x) { + // return ASR::is_a( + // *type_get_past_const( + // type_get_past_array( + // type_get_past_allocatable( + // type_get_past_pointer( + // type_get_past_const(&x)))))); return ASR::is_a( *type_get_past_const( type_get_past_array( @@ -2028,6 +2034,11 @@ static inline bool is_unsigned_integer(ASR::ttype_t &x) { } static inline bool is_real(ASR::ttype_t &x) { + // return ASR::is_a( + // *type_get_past_const( + // type_get_past_array( + // type_get_past_allocatable( + // type_get_past_pointer(&x))))); return ASR::is_a( *type_get_past_array( type_get_past_allocatable( @@ -2196,6 +2207,10 @@ inline size_t extract_dimensions_from_ttype(ASR::ttype_t *x, } static inline ASR::ttype_t *extract_type(ASR::ttype_t *type) { + // return type_get_past_const( + // type_get_past_array( + // type_get_past_allocatable( + // type_get_past_pointer(type)))); return type_get_past_array( type_get_past_allocatable( type_get_past_pointer(type))); @@ -3035,6 +3050,12 @@ inline bool types_equal(ASR::ttype_t *a, ASR::ttype_t *b, if( a == nullptr && b == nullptr ) { return true; } + // a = ASRUtils::type_get_past_const( + // ASRUtils::type_get_past_allocatable( + // ASRUtils::type_get_past_pointer(a))); + // b = ASRUtils::type_get_past_const( + // ASRUtils::type_get_past_allocatable( + // ASRUtils::type_get_past_pointer(b))); a = ASRUtils::type_get_past_allocatable(ASRUtils::type_get_past_pointer(a)); b = ASRUtils::type_get_past_allocatable(ASRUtils::type_get_past_pointer(b)); if( !check_for_dimensions ) { diff --git a/src/libasr/asr_verify.cpp b/src/libasr/asr_verify.cpp index 670d0a1f9e..f8f346b58e 100644 --- a/src/libasr/asr_verify.cpp +++ b/src/libasr/asr_verify.cpp @@ -525,6 +525,8 @@ class VerifyVisitor : public BaseWalkVisitor ASR::is_a(*a.second) ) { continue ; } + // TODO: Uncomment the following line + // ASR::ttype_t* var_type = ASRUtils::extract_type(ASRUtils::symbol_type(a.second)); ASR::ttype_t* var_type = ASRUtils::type_get_past_pointer(ASRUtils::symbol_type(a.second)); char* aggregate_type_name = nullptr; ASR::symbol_t* sym = nullptr; diff --git a/src/libasr/casting_utils.cpp b/src/libasr/casting_utils.cpp index 33537971e9..35268a3626 100644 --- a/src/libasr/casting_utils.cpp +++ b/src/libasr/casting_utils.cpp @@ -84,6 +84,9 @@ namespace LCompilers::CastingUtil { } int casted_expr_signal = 2; + // TODO: Uncomment the following + // ASR::ttypeType left_Type = ASRUtils::extract_type(left_type)->type, + // right_Type = ASRUtils::extract_type(right_type)->type; ASR::ttypeType left_Type = left_type->type, right_Type = right_type->type; int left_kind = ASRUtils::extract_kind_from_ttype_t(left_type); int right_kind = ASRUtils::extract_kind_from_ttype_t(right_type); @@ -121,6 +124,9 @@ namespace LCompilers::CastingUtil { if( ASR::is_a(*src) ) { src = ASRUtils::get_contained_type(src); } + // TODO: Uncomment the following + // ASR::ttypeType src_type = ASRUtils::extract_type(src)->type; + // ASR::ttypeType dest_type = ASRUtils::extract_type(dest)->type; ASR::ttypeType src_type = src->type; ASR::ttypeType dest_type = dest->type; ASR::cast_kindType cast_kind; diff --git a/src/libasr/casting_utils.h b/src/libasr/casting_utils.h index 695e2951fb..74bd669e2a 100644 --- a/src/libasr/casting_utils.h +++ b/src/libasr/casting_utils.h @@ -2,8 +2,6 @@ #define LFORTRAN_CASTING_UTILS_H -#include - #include namespace LCompilers::CastingUtil { diff --git a/src/libasr/codegen/asr_to_c_cpp.h b/src/libasr/codegen/asr_to_c_cpp.h index f4dbdd48ce..cd8d0cb176 100644 --- a/src/libasr/codegen/asr_to_c_cpp.h +++ b/src/libasr/codegen/asr_to_c_cpp.h @@ -1157,6 +1157,9 @@ PyMODINIT_FUNC PyInit_lpython_module_)" + fn_name + R"((void) { + "' not implemented"); } } else { + if (fn_name == "main") { + fn_name = "_xx_lcompilers_changed_main_xx"; + } src = fn_name + "(" + construct_call_args(fn, x.n_args, x.m_args) + ")"; } last_expr_precedence = 2; diff --git a/src/libasr/codegen/asr_to_fortran.cpp b/src/libasr/codegen/asr_to_fortran.cpp index 04a0942ca5..a9964c7524 100644 --- a/src/libasr/codegen/asr_to_fortran.cpp +++ b/src/libasr/codegen/asr_to_fortran.cpp @@ -1267,6 +1267,7 @@ class ASRToFortranVisitor : public ASR::BaseVisitor SET_INTRINSIC_NAME(StringContainsSet, "verify"); SET_INTRINSIC_NAME(StringFindSet, "scan"); SET_INTRINSIC_NAME(SubstrIndex, "index"); + SET_INTRINSIC_NAME(Modulo, "modulo"); default : { throw LCompilersException("IntrinsicElementalFunction: `" + ASRUtils::get_intrinsic_name(x.m_intrinsic_id) diff --git a/src/libasr/codegen/asr_to_julia.cpp b/src/libasr/codegen/asr_to_julia.cpp index 588d4b5e1e..5583990fe7 100644 --- a/src/libasr/codegen/asr_to_julia.cpp +++ b/src/libasr/codegen/asr_to_julia.cpp @@ -1905,6 +1905,7 @@ class ASRToJuliaVisitor : public ASR::BaseVisitor SET_INTRINSIC_NAME(StringContainsSet, "verify"); SET_INTRINSIC_NAME(StringFindSet, "scan"); SET_INTRINSIC_NAME(SubstrIndex, "index"); + SET_INTRINSIC_NAME(Modulo, "modulo"); default : { throw LCompilersException("IntrinsicFunction: `" + ASRUtils::get_intrinsic_name(x.m_intrinsic_id) diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index 4e8de1d9d4..4e2c35c5cf 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -1505,7 +1505,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor this->visit_expr(*x.m_v); ptr_loads = ptr_loads_copy; llvm::Value* union_llvm = tmp; - ASR::Variable_t* member_var = ASR::down_cast(x.m_m); + ASR::Variable_t* member_var = ASR::down_cast( + ASRUtils::symbol_get_past_external(x.m_m)); ASR::ttype_t* member_type_asr = ASRUtils::get_contained_type(member_var->m_type); if( ASR::is_a(*member_type_asr) ) { ASR::Struct_t* d = ASR::down_cast(member_type_asr); @@ -2424,7 +2425,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor this->visit_expr(*x.m_shape); llvm::Value* shape = tmp; ASR::ttype_t* x_m_array_type = ASRUtils::expr_type(x.m_array); - ASR::array_physical_typeType array_physical_type = ASRUtils::extract_physical_type(x_m_array_type); + ASR::array_physical_typeType array_physical_type = ASRUtils::extract_physical_type(x_m_array_type); switch( array_physical_type ) { case ASR::array_physical_typeType::DescriptorArray: { ASR::ttype_t* asr_data_type = ASRUtils::duplicate_type_without_dims(al, @@ -4549,6 +4550,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor bool is_value_set = 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); + bool is_value_list_to_array = (ASR::is_a(*x.m_value) && + ASR::down_cast(x.m_value)->m_kind == ASR::cast_kindType::ListToArray); if (ASR::is_a(*x.m_target)) { handle_StringSection_Assignment(x.m_target, x.m_value); if (tmp == strings_to_be_deallocated.back()) { @@ -4767,7 +4770,37 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor target = CreateLoad(target); } ASR::ttype_t *cont_type = ASRUtils::get_contained_type(asr_target_type); - if (ASRUtils::is_array(cont_type) && ASRUtils::is_array(cont_type) ) { + if ( ASRUtils::is_array(cont_type) ) { + if( is_value_list_to_array ) { + this->visit_expr_wrapper(x.m_value, true); + llvm::Value* list_data = tmp; + int64_t ptr_loads_copy = ptr_loads; + ptr_loads = 0; + this->visit_expr(*ASR::down_cast(x.m_value)->m_arg); + llvm::Value* plist = tmp; + ptr_loads = ptr_loads_copy; + llvm::Value* array_data = nullptr; + if( ASRUtils::extract_physical_type(asr_target_type) == + ASR::array_physical_typeType::DescriptorArray ) { + array_data = LLVM::CreateLoad(*builder, + arr_descr->get_pointer_to_data(LLVM::CreateLoad(*builder, target))); + } else if( ASRUtils::extract_physical_type(asr_target_type) == + ASR::array_physical_typeType::FixedSizeArray ) { + array_data = llvm_utils->create_gep(target, 0); + } else { + LCOMPILERS_ASSERT(false); + } + llvm::Value* size = list_api->len(plist); + llvm::Type* el_type = llvm_utils->get_type_from_ttype_t_util( + ASRUtils::extract_type(ASRUtils::expr_type(x.m_value)), module.get()); + llvm::DataLayout data_layout(module.get()); + uint64_t size_ = data_layout.getTypeAllocSize(el_type); + size = builder->CreateMul(size, llvm::ConstantInt::get( + llvm::Type::getInt32Ty(context), llvm::APInt(32, size_))); + builder->CreateMemCpy(array_data, llvm::MaybeAlign(), + list_data, llvm::MaybeAlign(), size); + return ; + } if( asr_target->m_type->type == ASR::ttypeType::Character) { target = CreateLoad(arr_descr->get_pointer_to_data(target)); } @@ -5030,17 +5063,19 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } else if( m_new == ASR::array_physical_typeType::PointerToDataArray && m_old == ASR::array_physical_typeType::FixedSizeArray) { - if( (ASRUtils::expr_value(m_arg) && + if( ((ASRUtils::expr_value(m_arg) && !ASR::is_a(*ASRUtils::expr_value(m_arg))) || - ASRUtils::expr_value(m_arg) == nullptr ) { + ASRUtils::expr_value(m_arg) == nullptr ) && + !ASR::is_a(*m_arg) ) { tmp = llvm_utils->create_gep(tmp, 0); } } else if( m_new == ASR::array_physical_typeType::UnboundedPointerToDataArray && m_old == ASR::array_physical_typeType::FixedSizeArray) { - if( (ASRUtils::expr_value(m_arg) && + if( ((ASRUtils::expr_value(m_arg) && !ASR::is_a(*ASRUtils::expr_value(m_arg))) || - ASRUtils::expr_value(m_arg) == nullptr ) { + ASRUtils::expr_value(m_arg) == nullptr) && + !ASR::is_a(*m_arg) ) { tmp = llvm_utils->create_gep(tmp, 0); } } else if ( @@ -5054,9 +5089,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } else if( m_new == ASR::array_physical_typeType::DescriptorArray && m_old == ASR::array_physical_typeType::FixedSizeArray) { - if( (ASRUtils::expr_value(m_arg) && + if( ((ASRUtils::expr_value(m_arg) && !ASR::is_a(*ASRUtils::expr_value(m_arg))) || - ASRUtils::expr_value(m_arg) == nullptr ) { + ASRUtils::expr_value(m_arg) == nullptr) && + !ASR::is_a(*m_arg) ) { tmp = llvm_utils->create_gep(tmp, 0); } PointerToData_to_Descriptor(m_type, m_type_for_dimensions); @@ -5094,9 +5130,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor m_old == ASR::array_physical_typeType::CharacterArraySinglePointer) { // if (ASRUtils::is_fixed_size_array(m_type)) { - if( (ASRUtils::expr_value(m_arg) && + if( ((ASRUtils::expr_value(m_arg) && !ASR::is_a(*ASRUtils::expr_value(m_arg))) || - ASRUtils::expr_value(m_arg) == nullptr ) { + ASRUtils::expr_value(m_arg) == nullptr) && + !ASR::is_a(*m_arg) ) { tmp = llvm_utils->create_gep(tmp, 0); } } else { @@ -6396,7 +6433,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } - void visit_ArrayConstructor(const ASR::ArrayConstructor_t &x) { + template + void visit_ArrayConstructorUtil(const T& x) { llvm::Type* el_type = nullptr; ASR::ttype_t* x_m_type = ASRUtils::type_get_past_array(x.m_type); if (ASR::is_a(*x_m_type)) { @@ -6444,52 +6482,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor tmp = llvm_utils->create_gep(p_fxn, 0); } + void visit_ArrayConstructor(const ASR::ArrayConstructor_t &x) { + visit_ArrayConstructorUtil(x); + } + void visit_ArrayConstant(const ASR::ArrayConstant_t &x) { - llvm::Type* el_type = nullptr; - ASR::ttype_t* x_m_type = ASRUtils::type_get_past_array(x.m_type); - if (ASR::is_a(*x_m_type)) { - el_type = llvm_utils->getIntType(ASR::down_cast(x_m_type)->m_kind); - } else if (ASR::is_a(*x_m_type)) { - switch (ASR::down_cast(x_m_type)->m_kind) { - case (4) : - el_type = llvm::Type::getFloatTy(context); break; - case (8) : - el_type = llvm::Type::getDoubleTy(context); break; - default : - throw CodeGenError("ConstArray real kind not supported yet"); - } - } else if (ASR::is_a(*x_m_type)) { - el_type = llvm::Type::getInt1Ty(context); - } else if (ASR::is_a(*x_m_type)) { - el_type = character_type; - } else if (ASR::is_a(*x_m_type)) { - int complex_kind = ASR::down_cast(x_m_type)->m_kind; - if( complex_kind == 4 ) { - el_type = llvm_utils->complex_type_4; - } else if( complex_kind == 8 ) { - el_type = llvm_utils->complex_type_8; - } else { - LCOMPILERS_ASSERT(false); - } - } else { - throw CodeGenError("ConstArray type not supported yet"); - } - // Create type, where `n` is the length of the `x` constant array - llvm::Type* type_fxn = FIXED_VECTOR_TYPE::get(el_type, x.n_args); - // Create a pointer * to a stack allocated - llvm::AllocaInst *p_fxn = builder->CreateAlloca(type_fxn, nullptr); - // Assign the array elements to `p_fxn`. - for (size_t i=0; i < x.n_args; i++) { - llvm::Value *llvm_el = llvm_utils->create_gep(p_fxn, i); - ASR::expr_t *el = x.m_args[i]; - int64_t ptr_loads_copy = ptr_loads; - ptr_loads = 2; - this->visit_expr_wrapper(el, true); - ptr_loads = ptr_loads_copy; - builder->CreateStore(tmp, llvm_el); - } - // Return the vector as float* type: - tmp = llvm_utils->create_gep(p_fxn, 0); + visit_ArrayConstructorUtil(x); } void visit_Assert(const ASR::Assert_t &x) { @@ -6654,7 +6652,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor this->visit_expr_wrapper(x->m_value, true); return; } - ASR::ttype_t *t2_ = ASRUtils::type_get_past_array(x->m_type); + ASR::ttype_t *t2_ = ASRUtils::type_get_past_const( + ASRUtils::type_get_past_array(x->m_type)); switch( t2_->type ) { case ASR::ttypeType::Pointer: case ASR::ttypeType::Allocatable: { @@ -7248,6 +7247,19 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor tmp = builder->CreateSelect(cmp, zero_str, one_str); break; } + case (ASR::cast_kindType::ListToArray) : { + if( !ASR::is_a(*ASRUtils::expr_type(x.m_arg)) ) { + throw CodeGenError("The argument of ListToArray cast should " + "be a list/std::vector, found, " + ASRUtils::type_to_str( + ASRUtils::expr_type(x.m_arg))); + } + int64_t ptr_loads_copy = ptr_loads; + ptr_loads = 0; + this->visit_expr(*x.m_arg); + ptr_loads = ptr_loads_copy; + tmp = LLVM::CreateLoad(*builder, list_api->get_pointer_to_list_data(tmp)); + break; + } default : throw CodeGenError("Cast kind not implemented"); } } @@ -9792,6 +9804,7 @@ Result> asr_to_llvm(ASR::TranslationUnit_t &asr, v.module->print(os, nullptr); std::cout << os.str(); msg = "asr_to_llvm: module failed verification. Error:\n" + err.str(); + std::cout << msg << std::endl; diagnostics.diagnostics.push_back(diag::Diagnostic(msg, diag::Level::Error, diag::Stage::CodeGen)); Error error; diff --git a/src/libasr/intrinsic_func_registry_util_gen.py b/src/libasr/intrinsic_func_registry_util_gen.py index 32a9f494e3..160179cb38 100644 --- a/src/libasr/intrinsic_func_registry_util_gen.py +++ b/src/libasr/intrinsic_func_registry_util_gen.py @@ -38,6 +38,12 @@ "ret_type_arg_idx": 0 }, ], + "Modulo": [ + { + "args": [("int", "int"), ("real", "real")], + "ret_type_arg_idx": 0 + }, + ], "BesselJ0": [ { "args": [("real",)], diff --git a/src/libasr/pass/array_op.cpp b/src/libasr/pass/array_op.cpp index 6a733211c1..ee313777db 100644 --- a/src/libasr/pass/array_op.cpp +++ b/src/libasr/pass/array_op.cpp @@ -1017,6 +1017,9 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { void replace_Cast(ASR::Cast_t* x) { + if( x->m_kind == ASR::cast_kindType::ListToArray ) { + return ; + } const Location& loc = x->base.base.loc; ASR::Cast_t* x_ = x; if( ASR::is_a(*x->m_arg) ) { diff --git a/src/libasr/pass/flip_sign.cpp b/src/libasr/pass/flip_sign.cpp index 7b054a7970..518fba22e9 100644 --- a/src/libasr/pass/flip_sign.cpp +++ b/src/libasr/pass/flip_sign.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include diff --git a/src/libasr/pass/intrinsic_array_function_registry.h b/src/libasr/pass/intrinsic_array_function_registry.h index ca21031751..d4ccba7231 100644 --- a/src/libasr/pass/intrinsic_array_function_registry.h +++ b/src/libasr/pass/intrinsic_array_function_registry.h @@ -1826,6 +1826,8 @@ namespace Count { dim_ = args[1]; kind = args[2]; } + ASR::dimension_t* array_dims = nullptr; + int array_rank = extract_dimensions_from_ttype(ASRUtils::expr_type(args[0]), array_dims); ASR::ttype_t* mask_type = ASRUtils::expr_type(mask); if ( dim_ != nullptr ) { @@ -1838,6 +1840,9 @@ namespace Count { overload_id = id_mask_dim; } + if (array_rank == 1) { + overload_id = id_mask; + } if ( kind != nullptr) { size_t kind_rank = ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(kind)); if (kind_rank != 0) { @@ -1881,7 +1886,7 @@ namespace Count { Vec arr_intrinsic_args; arr_intrinsic_args.reserve(al, 1); arr_intrinsic_args.push_back(al, mask); - if( dim_ ) { + if( dim_ && array_rank != 1 ) { arr_intrinsic_args.push_back(al, dim_); } return make_IntrinsicArrayFunction_t_util(al, loc, diff --git a/src/libasr/pass/intrinsic_function.cpp b/src/libasr/pass/intrinsic_function.cpp index 8a1a4aa552..43f5ab1794 100644 --- a/src/libasr/pass/intrinsic_function.cpp +++ b/src/libasr/pass/intrinsic_function.cpp @@ -290,7 +290,8 @@ class ReplaceFunctionCallReturningArray: public ASR::BaseExprReplacerm_name)) + "_res", x->base.base.loc, x->m_type, al, current_scope); - if (func2intrinsicid[x_m_name] == ASRUtils::IntrinsicArrayFunctions::Sum) { + if (ASRUtils::is_allocatable(ASRUtils::expr_type(result_var_)) && + func2intrinsicid[x_m_name] == ASRUtils::IntrinsicArrayFunctions::Sum) { PassUtils::allocate_res_var(al, x, new_args, result_var_, pass_result, {0, 0, 1}); } } else { @@ -347,7 +348,7 @@ class ReplaceFunctionCallReturningArray: public ASR::BaseExprReplacerbase.base.loc, alloc_args.p, alloc_args.n, nullptr, nullptr, nullptr)); pass_result.push_back(al, allocate_stmt); } diff --git a/src/libasr/pass/intrinsic_function_registry.h b/src/libasr/pass/intrinsic_function_registry.h index 21636cfeae..6b730fcea6 100644 --- a/src/libasr/pass/intrinsic_function_registry.h +++ b/src/libasr/pass/intrinsic_function_registry.h @@ -52,6 +52,7 @@ inline std::string get_intrinsic_name(int x) { INTRINSIC_NAME_CASE(FloorDiv) INTRINSIC_NAME_CASE(Mod) INTRINSIC_NAME_CASE(Trailz) + INTRINSIC_NAME_CASE(Modulo) INTRINSIC_NAME_CASE(BesselJ0) INTRINSIC_NAME_CASE(BesselJ1) INTRINSIC_NAME_CASE(BesselY0) @@ -228,6 +229,8 @@ namespace IntrinsicElementalFunctionRegistry { {&Mod::instantiate_Mod, &Mod::verify_args}}, {static_cast(IntrinsicElementalFunctions::Trailz), {&Trailz::instantiate_Trailz, &Trailz::verify_args}}, + {static_cast(IntrinsicElementalFunctions::Modulo), + {&Modulo::instantiate_Modulo, &Modulo::verify_args}}, {static_cast(IntrinsicElementalFunctions::BesselJ0), {&BesselJ0::instantiate_BesselJ0, &BesselJ0::verify_args}}, {static_cast(IntrinsicElementalFunctions::BesselJ1), @@ -513,6 +516,8 @@ namespace IntrinsicElementalFunctionRegistry { "mod"}, {static_cast(IntrinsicElementalFunctions::Trailz), "trailz"}, + {static_cast(IntrinsicElementalFunctions::Modulo), + "modulo"}, {static_cast(IntrinsicElementalFunctions::BesselJ0), "bessel_j0"}, {static_cast(IntrinsicElementalFunctions::BesselY0), @@ -764,6 +769,7 @@ namespace IntrinsicElementalFunctionRegistry { {"floordiv", {&FloorDiv::create_FloorDiv, &FloorDiv::eval_FloorDiv}}, {"mod", {&Mod::create_Mod, &Mod::eval_Mod}}, {"trailz", {&Trailz::create_Trailz, &Trailz::eval_Trailz}}, + {"modulo", {&Modulo::create_Modulo, &Modulo::eval_Modulo}}, {"bessel_j0", {&BesselJ0::create_BesselJ0, &BesselJ0::eval_BesselJ0}}, {"bessel_j1", {&BesselJ1::create_BesselJ1, &BesselJ1::eval_BesselJ1}}, {"bessel_y0", {&BesselY0::create_BesselY0, &BesselY0::eval_BesselY0}}, diff --git a/src/libasr/pass/intrinsic_function_registry_util.h b/src/libasr/pass/intrinsic_function_registry_util.h index f8b60174bd..2a30e56b3b 100644 --- a/src/libasr/pass/intrinsic_function_registry_util.h +++ b/src/libasr/pass/intrinsic_function_registry_util.h @@ -271,6 +271,51 @@ namespace Trailz { } } +namespace Modulo { + + static inline void verify_args(const ASR::IntrinsicElementalFunction_t& x, diag::Diagnostics& diagnostics) { + if (x.n_args == 2) { + ASRUtils::require_impl(x.m_overload_id == 0, "Overload Id for Modulo expected to be 0, found " + std::to_string(x.m_overload_id), x.base.base.loc, diagnostics); + ASR::ttype_t *arg_type0 = ASRUtils::type_get_past_const(ASRUtils::expr_type(x.m_args[0])); + ASR::ttype_t *arg_type1 = ASRUtils::type_get_past_const(ASRUtils::expr_type(x.m_args[1])); + ASRUtils::require_impl((is_integer(*arg_type0) && is_integer(*arg_type1)) || (is_real(*arg_type0) && is_real(*arg_type1)), "Unexpected args, Modulo expects (int, int) or (real, real) as arguments", x.base.base.loc, diagnostics); + } + else { + ASRUtils::require_impl(false, "Unexpected number of args, Modulo takes 2 arguments, found " + std::to_string(x.n_args), x.base.base.loc, diagnostics); + } + } + + static inline ASR::asr_t* create_Modulo(Allocator& al, const Location& loc, Vec& args, diag::Diagnostics& diag) { + if (args.size() == 2) { + ASR::ttype_t *arg_type0 = ASRUtils::type_get_past_const(ASRUtils::expr_type(args[0])); + ASR::ttype_t *arg_type1 = ASRUtils::type_get_past_const(ASRUtils::expr_type(args[1])); + if(!((is_integer(*arg_type0) && is_integer(*arg_type1)) || (is_real(*arg_type0) && is_real(*arg_type1)))) { + append_error(diag, "Unexpected args, Modulo expects (int, int) or (real, real) as arguments", loc); + return nullptr; + } + } + else { + append_error(diag, "Unexpected number of args, Modulo takes 2 arguments, found " + std::to_string(args.size()), loc); + return nullptr; + } + ASRUtils::ExprStmtDuplicator expr_duplicator(al); + expr_duplicator.allow_procedure_calls = true; + ASR::ttype_t* type_ = expr_duplicator.duplicate_ttype(expr_type(args[0])); + ASR::ttype_t *return_type = type_; + ASR::expr_t *m_value = nullptr; + Vec m_args; m_args.reserve(al, 2); + m_args.push_back(al, args[0]); + m_args.push_back(al, args[1]); + if (all_args_evaluated(m_args)) { + Vec args_values; args_values.reserve(al, 2); + args_values.push_back(al, expr_value(m_args[0])); + args_values.push_back(al, expr_value(m_args[1])); + m_value = eval_Modulo(al, loc, return_type, args_values, diag); + } + return ASR::make_IntrinsicElementalFunction_t(al, loc, static_cast(IntrinsicElementalFunctions::Modulo), m_args.p, m_args.n, 0, return_type, m_value); + } +} + namespace BesselJ0 { static inline void verify_args(const ASR::IntrinsicElementalFunction_t& x, diag::Diagnostics& diagnostics) { diff --git a/src/libasr/pass/intrinsic_functions.h b/src/libasr/pass/intrinsic_functions.h index af48083ef2..8d299a5a58 100644 --- a/src/libasr/pass/intrinsic_functions.h +++ b/src/libasr/pass/intrinsic_functions.h @@ -51,6 +51,7 @@ enum class IntrinsicElementalFunctions : int64_t { FlipSign, Mod, Trailz, + Modulo, BesselJ0, BesselJ1, BesselY0, @@ -2806,6 +2807,7 @@ namespace Maskr { scope->add_symbol(fn_name, f_sym); return b.Call(f_sym, new_args, return_type, nullptr); } + } // namespace Maskr namespace Trailz { @@ -2867,6 +2869,70 @@ namespace Trailz { } // namespace Trailz +namespace Modulo { + + static ASR::expr_t *eval_Modulo(Allocator &al, const Location &loc, + ASR::ttype_t* t1, Vec &args, diag::Diagnostics& /*diag*/) { + + if (is_integer(*ASRUtils::expr_type(args[0])) && is_integer(*ASRUtils::expr_type(args[1]))) { + int64_t a = ASR::down_cast(args[0])->m_n; + int64_t b = ASR::down_cast(args[1])->m_n; + if ( a*b >= 0 ) { + return make_ConstantWithType(make_IntegerConstant_t, a % b, t1, loc); + } else { + return make_ConstantWithType(make_IntegerConstant_t, a % b + b, t1, loc); + } + } else if (is_real(*ASRUtils::expr_type(args[0])) && is_real(*ASRUtils::expr_type(args[1]))) { + double a = ASR::down_cast(args[0])->m_r; + double b = ASR::down_cast(args[1])->m_r; + if ( a*b > 0 ) { + return make_ConstantWithType(make_RealConstant_t, std::fmod(a, b), t1, loc); + } else { + return make_ConstantWithType(make_RealConstant_t, std::fmod(a, b) + b, t1, loc); + } + } + return nullptr; + } + + static inline ASR::expr_t* instantiate_Modulo(Allocator &al, const Location &loc, + SymbolTable *scope, Vec& arg_types, ASR::ttype_t *return_type, + Vec& new_args, int64_t /*overload_id*/) { + declare_basic_variables("_lcompilers_optimization_modulo_" + type_to_str_python(arg_types[0])); + fill_func_arg("a", arg_types[0]); + fill_func_arg("p", arg_types[1]); + auto result = declare(fn_name, return_type, ReturnVar); + /* + function modulo(a, p) result(d) + if ( a*p >= 0 ) then + d = mod(a, p) + else + d = mod(a, p) + p + end if + end function + */ + + if (is_real(*arg_types[0])) { + body.push_back(al, b.If(b.fGtE(b.r_tMul(args[0], args[1], arg_types[0]), b.f(0.0, arg_types[0])), { + b.Assignment(result, Mod::MOD(b, args[0], args[1], scope)) + }, { + b.Assignment(result, b.r_tAdd(Mod::MOD(b, args[0], args[1], scope), args[1], arg_types[0])) + })); + } else { + body.push_back(al, b.If(b.iGtE(b.i_tMul(args[0], args[1], arg_types[0]), b.i(0, arg_types[0])), { + b.Assignment(result, Mod::MOD(b, args[0], args[1], scope)) + }, { + b.Assignment(result, b.i_tAdd(Mod::MOD(b, args[0], args[1], scope), args[1], arg_types[0])) + })); + } + + ASR::symbol_t *f_sym = make_ASR_Function_t(fn_name, fn_symtab, dep, args, + body, result, ASR::abiType::Source, ASR::deftypeType::Implementation, nullptr); + scope->add_symbol(fn_name, f_sym); + return b.Call(f_sym, new_args, return_type, nullptr); + } + +} // namespace Modulo + namespace BesselJ0 { static ASR::expr_t *eval_BesselJ0(Allocator &/*al*/, const Location &/*loc*/, diff --git a/src/libasr/pass/pass_manager.h b/src/libasr/pass/pass_manager.h index 9bd470a7a9..c76c4a4126 100644 --- a/src/libasr/pass/pass_manager.h +++ b/src/libasr/pass/pass_manager.h @@ -82,6 +82,7 @@ namespace LCompilers { {"implied_do_loops", &pass_replace_implied_do_loops}, {"array_op", &pass_replace_array_op}, {"symbolic", &pass_replace_symbolic}, + {"flip_sign", &pass_replace_flip_sign}, {"intrinsic_function", &pass_replace_intrinsic_function}, {"intrinsic_subroutine", &pass_replace_intrinsic_subroutine}, {"arr_slice", &pass_replace_arr_slice}, @@ -89,7 +90,6 @@ namespace LCompilers { {"print_list_tuple", &pass_replace_print_list_tuple}, {"class_constructor", &pass_replace_class_constructor}, {"unused_functions", &pass_unused_functions}, - {"flip_sign", &pass_replace_flip_sign}, {"div_to_mul", &pass_replace_div_to_mul}, {"fma", &pass_replace_fma}, {"sign_from_value", &pass_replace_sign_from_value}, @@ -251,6 +251,7 @@ namespace LCompilers { "subroutine_from_function", "array_op", "symbolic", + "flip_sign", "intrinsic_function", "intrinsic_subroutine", "subroutine_from_function", @@ -268,7 +269,6 @@ namespace LCompilers { "dead_code_removal", "select_case", "unused_functions", - "flip_sign", "sign_from_value", "div_to_mul", "fma", diff --git a/src/libasr/pass/pass_utils.h b/src/libasr/pass/pass_utils.h index 2260ac51ed..e5229e276a 100644 --- a/src/libasr/pass/pass_utils.h +++ b/src/libasr/pass/pass_utils.h @@ -539,6 +539,35 @@ namespace LCompilers { } current_scope = parent_symtab; } + // TODO: Uncomment the following in LFortran + /* + template + void visit_UserDefinedType(const T& x) { + T& xx = const_cast(x); + SetChar vec; vec.reserve(al, 1); + for( auto itr: x.m_symtab->get_scope() ) { + ASR::ttype_t* type = ASRUtils::extract_type( + ASRUtils::symbol_type(itr.second)); + if( ASR::is_a(*type) ) { + ASR::Struct_t* struct_t = ASR::down_cast(type); + vec.push_back(al, ASRUtils::symbol_name(struct_t->m_derived_type)); + } else if( ASR::is_a(*type) ) { + ASR::Enum_t* enum_t = ASR::down_cast(type); + vec.push_back(al, ASRUtils::symbol_name(enum_t->m_enum_type)); + } + } + xx.m_dependencies = vec.p; + xx.n_dependencies = vec.size(); + } + + void visit_StructType(const ASR::StructType_t& x) { + visit_UserDefinedType(x); + } + + void visit_UnionType(const ASR::UnionType_t& x) { + visit_UserDefinedType(x); + } + */ }; namespace ReplacerUtils { diff --git a/src/libasr/pass/promote_allocatable_to_nonallocatable.cpp b/src/libasr/pass/promote_allocatable_to_nonallocatable.cpp index 740bf0ae74..d7aba6ce3a 100644 --- a/src/libasr/pass/promote_allocatable_to_nonallocatable.cpp +++ b/src/libasr/pass/promote_allocatable_to_nonallocatable.cpp @@ -212,6 +212,27 @@ class FixArrayPhysicalCast: public ASR::BaseExprReplacer { x->m_args = function_call->m_args; x->n_args = function_call->n_args; } + + void replace_ArrayReshape(ASR::ArrayReshape_t* x) { + ASR::BaseExprReplacer::replace_ArrayReshape(x); + if( ASRUtils::extract_physical_type(ASRUtils::expr_type(x->m_array)) == + ASR::array_physical_typeType::FixedSizeArray && + ASRUtils::extract_physical_type(x->m_type) != + ASR::array_physical_typeType::FixedSizeArray ) { + size_t n_dims = ASRUtils::extract_n_dims_from_ttype(x->m_type); + Vec empty_dims; empty_dims.reserve(al, n_dims); + for( size_t i = 0; i < n_dims; i++ ) { + ASR::dimension_t empty_dim; + empty_dim.loc = x->base.base.loc; + empty_dim.m_start = nullptr; + empty_dim.m_length = nullptr; + empty_dims.push_back(al, empty_dim); + } + x->m_type = ASRUtils::TYPE(ASR::make_Array_t(al, x->base.base.loc, + ASRUtils::extract_type(x->m_type), empty_dims.p, empty_dims.size(), + ASR::array_physical_typeType::FixedSizeArray)); + } + } }; class FixArrayPhysicalCastVisitor: public ASR::CallReplacerOnExpressionsVisitor {