diff --git a/integration_tests/elemental_09.py b/integration_tests/elemental_09.py index a821177463..c879d0e926 100644 --- a/integration_tests/elemental_09.py +++ b/integration_tests/elemental_09.py @@ -36,16 +36,16 @@ def elemental_arcsinh(): arcsinh1d = arcsinh(arcsinh(array1d)) verify1d_arcsinh(array1d, arcsinh1d, 256) - arraynd: f64[256, 64, 16] = empty((256, 64, 16), dtype=float64) - arcsinhnd: f64[256, 64, 16] = empty((256, 64, 16), dtype=float64) + arraynd: f64[256, 64, 4] = empty((256, 64, 4), dtype=float64) + arcsinhnd: f64[256, 64, 4] = empty((256, 64, 4), dtype=float64) for i in range(256): for j in range(64): - for k in range(16): + for k in range(4): arraynd[i, j, k] = float(i + j + k) arcsinhnd = (1.0 + arcsinh(arraynd)) - verifynd_arcsinh(arraynd, arcsinhnd, 256, 64, 16) + verifynd_arcsinh(arraynd, arcsinhnd, 256, 64, 4) def verify2d_arccosh(array: f64[:, :], result: f64[:, :], size1: i32, size2: i32): i: i32 diff --git a/src/libasr/asr_utils.h b/src/libasr/asr_utils.h index cc8f4f53b4..bcab5f631f 100644 --- a/src/libasr/asr_utils.h +++ b/src/libasr/asr_utils.h @@ -237,6 +237,9 @@ static inline ASR::abiType symbol_abi(const ASR::symbol_t *f) case ASR::symbolType::ExternalSymbol: { return symbol_abi(ASR::down_cast(f)->m_external); } + case ASR::symbolType::Function: { + return ASRUtils::get_FunctionType(*ASR::down_cast(f))->m_abi; + } default: { throw LCompilersException("Cannot return ABI of, " + std::to_string(f->type) + " symbol."); @@ -1982,6 +1985,74 @@ static inline bool is_only_upper_bound_empty(ASR::dimension_t& dim) { return (dim.m_start != nullptr && dim.m_length == nullptr); } +class ExprDependentOnlyOnArguments: public ASR::BaseWalkVisitor { + + public: + + bool is_dependent_only_on_argument; + + ExprDependentOnlyOnArguments(): is_dependent_only_on_argument(false) + {} + + void visit_Var(const ASR::Var_t& x) { + if( ASR::is_a(*x.m_v) ) { + ASR::Variable_t* x_m_v = ASR::down_cast(x.m_v); + is_dependent_only_on_argument = is_dependent_only_on_argument && ASRUtils::is_arg_dummy(x_m_v->m_intent); + } else { + is_dependent_only_on_argument = false; + } + } +}; + +static inline bool is_dimension_dependent_only_on_arguments(ASR::dimension_t* m_dims, size_t n_dims) { + ExprDependentOnlyOnArguments visitor; + for( size_t i = 0; i < n_dims; i++ ) { + visitor.is_dependent_only_on_argument = true; + if( m_dims[i].m_length == nullptr ) { + return false; + } + visitor.visit_expr(*m_dims[i].m_length); + if( !visitor.is_dependent_only_on_argument ) { + return false; + } + } + return true; +} + +static inline ASR::asr_t* make_ArraySize_t_util( + Allocator &al, const Location &a_loc, ASR::expr_t* a_v, + ASR::expr_t* a_dim, ASR::ttype_t* a_type, ASR::expr_t* a_value, + bool for_type=true) { + if( ASR::is_a(*a_v) ) { + a_v = ASR::down_cast(a_v)->m_arg; + } + + ASR::dimension_t* m_dims = nullptr; + size_t n_dims = ASRUtils::extract_dimensions_from_ttype(ASRUtils::expr_type(a_v), m_dims); + bool is_dimension_dependent_only_on_arguments_ = is_dimension_dependent_only_on_arguments(m_dims, n_dims); + int dim = -1; + bool is_dimension_constant = (a_dim != nullptr) && ASRUtils::extract_value(ASRUtils::expr_value(a_dim), dim); + + bool compute_size = (is_dimension_dependent_only_on_arguments_ && + (is_dimension_constant || a_dim == nullptr)); + if( compute_size && for_type ) { + ASR::dimension_t* m_dims = nullptr; + size_t n_dims = ASRUtils::extract_dimensions_from_ttype(ASRUtils::expr_type(a_v), m_dims); + if( a_dim == nullptr ) { + ASR::asr_t* size = ASR::make_IntegerConstant_t(al, a_loc, 1, a_type); + for( size_t i = 0; i < n_dims; i++ ) { + size = ASR::make_IntegerBinOp_t(al, a_loc, ASRUtils::EXPR(size), + ASR::binopType::Mul, m_dims[i].m_length, a_type, nullptr); + } + return size; + } else if( is_dimension_constant ) { + return (ASR::asr_t*) m_dims[dim - 1].m_length; + } + } + + return ASR::make_ArraySize_t(al, a_loc, a_v, a_dim, a_type, a_value); +} + inline ASR::ttype_t* make_Array_t_util(Allocator& al, const Location& loc, ASR::ttype_t* type, ASR::dimension_t* m_dims, size_t n_dims, ASR::abiType abi=ASR::abiType::Source, bool is_argument=false, @@ -1991,6 +2062,14 @@ inline ASR::ttype_t* make_Array_t_util(Allocator& al, const Location& loc, return type; } + for( size_t i = 0; i < n_dims; i++ ) { + if( m_dims[i].m_length && ASR::is_a(*m_dims[i].m_length) ) { + ASR::ArraySize_t* as = ASR::down_cast(m_dims[i].m_length); + m_dims[i].m_length = ASRUtils::EXPR(ASRUtils::make_ArraySize_t_util( + al, as->base.base.loc, as->m_v, as->m_dim, as->m_type, nullptr)); + } + } + if( !override_physical_type ) { if( abi == ASR::abiType::BindC ) { physical_type = ASR::array_physical_typeType::PointerToDataArray; @@ -3228,40 +3307,6 @@ class ReplaceFunctionParamVisitor: public ASR::BaseExprReplacer { - - public: - - bool is_dependent_only_on_argument; - - ExprDependentOnlyOnArguments(): is_dependent_only_on_argument(false) - {} - - void visit_Var(const ASR::Var_t& x) { - if( ASR::is_a(*x.m_v) ) { - ASR::Variable_t* x_m_v = ASR::down_cast(x.m_v); - is_dependent_only_on_argument = is_dependent_only_on_argument && ASRUtils::is_arg_dummy(x_m_v->m_intent); - } else { - is_dependent_only_on_argument = false; - } - } -}; - -static inline bool is_dimension_dependent_only_on_arguments(ASR::dimension_t* m_dims, size_t n_dims) { - ExprDependentOnlyOnArguments visitor; - for( size_t i = 0; i < n_dims; i++ ) { - visitor.is_dependent_only_on_argument = true; - if( m_dims[i].m_length == nullptr ) { - return false; - } - visitor.visit_expr(*m_dims[i].m_length); - if( !visitor.is_dependent_only_on_argument ) { - return false; - } - } - return true; -} - inline ASR::asr_t* make_FunctionType_t_util(Allocator &al, const Location &a_loc, ASR::expr_t** a_args, size_t n_args, ASR::expr_t* a_return_var, ASR::abiType a_abi, ASR::deftypeType a_deftype, @@ -3881,16 +3926,6 @@ static inline ASR::expr_t* get_bound(ASR::expr_t* arr_expr, int dim, int32_type, bound_type, bound_value)); } -static inline ASR::asr_t* make_ArraySize_t_util( - Allocator &al, const Location &a_loc, ASR::expr_t* a_v, - ASR::expr_t* a_dim, ASR::ttype_t* a_type, ASR::expr_t* a_value) { - if( ASR::is_a(*a_v) ) { - a_v = ASR::down_cast(a_v)->m_arg; - } - - return ASR::make_ArraySize_t(al, a_loc, a_v, a_dim, a_type, a_value); -} - static inline ASR::expr_t* get_size(ASR::expr_t* arr_expr, int dim, Allocator& al) { ASR::ttype_t* int32_type = ASRUtils::TYPE(ASR::make_Integer_t(al, arr_expr->base.loc, 4)); diff --git a/src/libasr/codegen/llvm_utils.cpp b/src/libasr/codegen/llvm_utils.cpp index dda0c5b97d..3c6d269f54 100644 --- a/src/libasr/codegen/llvm_utils.cpp +++ b/src/libasr/codegen/llvm_utils.cpp @@ -1142,6 +1142,7 @@ namespace LCompilers { break; } case ASR::array_physical_typeType::FixedSizeArray: { + LCOMPILERS_ASSERT(ASRUtils::is_fixed_size_array(v_type->m_dims, v_type->n_dims)); llvm_type = llvm::ArrayType::get(get_el_type(v_type->m_type, module), ASRUtils::get_fixed_size_of_array( v_type->m_dims, v_type->n_dims)); diff --git a/src/libasr/pass/array_op.cpp b/src/libasr/pass/array_op.cpp index cd79f9c132..d0c1ef5970 100644 --- a/src/libasr/pass/array_op.cpp +++ b/src/libasr/pass/array_op.cpp @@ -69,7 +69,6 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { Vec& pass_result; size_t result_counter; bool& use_custom_loop_params; - bool& apply_again; bool& remove_original_statement; Vec& result_lbound; Vec& result_ubound; @@ -87,7 +86,7 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { ReplaceArrayOp(Allocator& al_, Vec& pass_result_, bool& use_custom_loop_params_, - bool& apply_again_, bool& remove_original_statement_, + bool& remove_original_statement_, Vec& result_lbound_, Vec& result_ubound_, Vec& result_inc_, @@ -95,7 +94,7 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { bool realloc_lhs_) : al(al_), pass_result(pass_result_), result_counter(0), use_custom_loop_params(use_custom_loop_params_), - apply_again(apply_again_), remove_original_statement(remove_original_statement_), + remove_original_statement(remove_original_statement_), result_lbound(result_lbound_), result_ubound(result_ubound_), result_inc(result_inc_), op_dims(nullptr), op_n_dims(0), op_expr(nullptr), resultvar2value(resultvar2value_), @@ -207,8 +206,12 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { } const Location& loc = x->base.base.loc; - if( ASR::is_a(*ASRUtils::expr_type(result_var)) && - ASRUtils::is_array(ASRUtils::expr_type(*current_expr)) && realloc_lhs ) { + if( (ASR::is_a(*ASRUtils::expr_type(result_var)) && + ASRUtils::is_array(ASRUtils::expr_type(*current_expr)) && realloc_lhs && + !use_custom_loop_params) || + (ASR::is_a(*ASRUtils::expr_type(result_var)) && + ASRUtils::is_array(ASRUtils::expr_type(*current_expr)) && + ASR::is_a(*ASRUtils::expr_type(*current_expr))) ) { ASR::ttype_t* result_var_type = ASRUtils::expr_type(result_var); Vec result_var_m_dims; size_t result_var_n_dims = ASRUtils::extract_n_dims_from_ttype(result_var_type); @@ -248,6 +251,7 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { } else { ref = *current_expr; } + LCOMPILERS_ASSERT(result_var != nullptr); ASR::expr_t* res = PassUtils::create_array_ref(result_var, idx_vars, al, current_scope); ASR::stmt_t* assign = ASRUtils::STMT(ASR::make_Assignment_t(al, loc, res, ref, nullptr)); doloop_body.push_back(al, assign); @@ -341,6 +345,7 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { loop_vars, idx_vars_value, loop_var_indices, doloop_body, op_expr, 2, [=, &arr_expr, &idx_vars, &idx_vars_value, &doloop_body]() { ASR::expr_t* ref = PassUtils::create_array_ref(arr_expr, idx_vars_value, al); + LCOMPILERS_ASSERT(result_var != nullptr); ASR::expr_t* res = PassUtils::create_array_ref(result_var, idx_vars, al); ASR::expr_t* op_el_wise = ASRUtils::EXPR(ASR::make_StructInstanceMember_t( al, loc, ref, x->m_m, ASRUtils::extract_type(x->m_type), nullptr)); @@ -405,6 +410,7 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { } else { if( ASRUtils::is_array(ASRUtils::expr_type(op_expr)) ) { ASR::expr_t* idx_lb = PassUtils::get_bound(op_expr, i + 1, "lbound", al); + LCOMPILERS_ASSERT(idx_vars_value[i + 1] != nullptr); ASR::stmt_t* set_to_one = ASRUtils::STMT(ASR::make_Assignment_t( al, loc, idx_vars_value[i + 1], idx_lb, nullptr)); doloop_body.push_back(al, set_to_one); @@ -1123,6 +1129,7 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { ASRUtils::expr_type(*current_expr), op_dims); } + Vec idx_vars, loop_vars, idx_vars_value; std::vector loop_var_indices; Vec doloop_body; @@ -1184,255 +1191,121 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { } void replace_FunctionCall(ASR::FunctionCall_t* x) { - // 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 ; - } - if (x->m_value) { - remove_original_statement = false; - *current_expr = x->m_value; - return; - } + // 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 ; + } - const Location& loc = x->base.base.loc; - bool is_return_var_handled = false; - ASR::symbol_t *fn_name = ASRUtils::symbol_get_past_external(x->m_name); - if (ASR::is_a(*fn_name)) { - ASR::Function_t *fn = ASR::down_cast(fn_name); - is_return_var_handled = fn->m_return_var == nullptr; - } - if (is_return_var_handled) { - ASR::ttype_t* result_var_type = x->m_type; - bool is_allocatable = false; - bool is_func_call_allocatable = false; - bool is_result_var_allocatable = false; - ASR::Function_t *fn = ASR::down_cast(fn_name); - { - // Assuming the `m_return_var` is appended to the `args`. - ASR::symbol_t *v_sym = ASR::down_cast( - fn->m_args[fn->n_args-1])->m_v; - if (ASR::is_a(*v_sym)) { - ASR::Variable_t *v = ASR::down_cast(v_sym); - is_func_call_allocatable = ASR::is_a(*v->m_type); - if( result_var != nullptr ) { - is_result_var_allocatable = ASR::is_a(*ASRUtils::expr_type(result_var)); - is_allocatable = is_func_call_allocatable || is_result_var_allocatable; - } - if( is_allocatable ) { - result_var_type = ASRUtils::duplicate_type_with_empty_dims(al, result_var_type); - result_var_type = ASRUtils::TYPE(ASR::make_Allocatable_t( - al, loc, ASRUtils::type_get_past_allocatable(result_var_type))); - } + const Location& loc = x->base.base.loc; + if( PassUtils::is_elemental(x->m_name) ) { + std::vector array_mask(x->n_args, false); + bool at_least_one_array = false; + for( size_t iarg = 0; iarg < x->n_args; iarg++ ) { + array_mask[iarg] = (x->m_args[iarg].m_value != nullptr && + ASRUtils::is_array(ASRUtils::expr_type(x->m_args[iarg].m_value))); + at_least_one_array = at_least_one_array || array_mask[iarg]; } - - // Don't always create this temporary variable - ASR::expr_t* result_var_ = PassUtils::create_var(result_counter, - "_func_call_res", loc, result_var_type, al, current_scope); - result_counter += 1; - if( result_var == nullptr ) { - result_var = result_var_; - *current_expr = result_var; - } else { - *current_expr = result_var_; + if (!at_least_one_array) { + return ; } - } - if( op_expr == &(x->base) ) { - op_dims = nullptr; - op_n_dims = ASRUtils::extract_dimensions_from_ttype( - ASRUtils::expr_type(*current_expr), op_dims); - } - - if( !is_func_call_allocatable && is_result_var_allocatable ) { - Vec vec_alloc; - vec_alloc.reserve(al, 1); - ASR::alloc_arg_t alloc_arg; - alloc_arg.m_len_expr = nullptr; - alloc_arg.m_type = nullptr; - alloc_arg.loc = loc; - alloc_arg.m_a = *current_expr; - - ASR::FunctionType_t* fn_type = ASRUtils::get_FunctionType(fn); - ASR::ttype_t* output_type = fn_type->m_arg_types[fn_type->n_arg_types - 1]; - ASR::dimension_t* m_dims = nullptr; - size_t n_dims = ASRUtils::extract_dimensions_from_ttype(output_type, m_dims); - Vec vec_dims; - vec_dims.reserve(al, n_dims); - ASRUtils::ReplaceFunctionParamVisitor replace_function_param_visitor(x->m_args); - ASRUtils::ExprStmtDuplicator expr_duplicator(al); - for( size_t i = 0; i < n_dims; i++ ) { - ASR::dimension_t dim; - dim.loc = loc; - dim.m_start = expr_duplicator.duplicate_expr(m_dims[i].m_start); - dim.m_length = expr_duplicator.duplicate_expr(m_dims[i].m_length); - replace_function_param_visitor.current_expr = &dim.m_start; - replace_function_param_visitor.replace_expr(dim.m_start); - replace_function_param_visitor.current_expr = &dim.m_length; - replace_function_param_visitor.replace_expr(dim.m_length); - vec_dims.push_back(al, dim); + ASR::expr_t* result_var_copy = result_var; + std::string res_prefix = "_elemental_func_call_res"; + bool is_all_rank_0 = true; + std::vector operands; + ASR::expr_t* operand = nullptr, *first_array_operand = nullptr; + int common_rank = 0; + bool are_all_rank_same = true; + for( size_t iarg = 0; iarg < x->n_args; iarg++ ) { + ASR::expr_t** current_expr_copy_9 = current_expr; + current_expr = &(x->m_args[iarg].m_value); + self().replace_expr(x->m_args[iarg].m_value); + operand = *current_expr; + current_expr = current_expr_copy_9; + operands.push_back(operand); + int rank_operand = PassUtils::get_rank(operand); + if( rank_operand > 0 && first_array_operand == nullptr ) { + first_array_operand = operand; + } + if( common_rank == 0 ) { + common_rank = rank_operand; + } + if( common_rank != rank_operand && + rank_operand > 0 ) { + are_all_rank_same = false; + } + array_mask[iarg] = (rank_operand > 0); + is_all_rank_0 = is_all_rank_0 && (rank_operand <= 0); } - - alloc_arg.m_dims = vec_dims.p; - alloc_arg.n_dims = vec_dims.n; - vec_alloc.push_back(al, alloc_arg); - pass_result.push_back(al, ASRUtils::STMT(ASR::make_Allocate_t( - al, loc, vec_alloc.p, 1, nullptr, nullptr, nullptr))); - } - - Vec s_args; - s_args.reserve(al, x->n_args + 1); - ASR::expr_t* result_var_copy = result_var; - result_var = nullptr; - for( size_t i = 0; i < x->n_args; i++ ) { - ASR::expr_t** current_expr_copy_9 = current_expr; - current_expr = &(x->m_args[i].m_value); - self().replace_expr(x->m_args[i].m_value); - current_expr = current_expr_copy_9; - s_args.push_back(al, x->m_args[i]); - } - result_var = result_var_copy; - ASR::call_arg_t result_arg; - result_arg.loc = result_var->base.loc; - result_arg.m_value = *current_expr; - s_args.push_back(al, result_arg); - ASR::stmt_t* subrout_call = ASRUtils::STMT(ASRUtils::make_SubroutineCall_t_util(al, loc, - x->m_name, nullptr, s_args.p, s_args.size(), nullptr, - nullptr, false)); - pass_result.push_back(al, subrout_call); - - if (is_allocatable && result_var != *current_expr && - ASRUtils::is_allocatable(result_var)) { // Add realloc-lhs later - Vec vec_alloc; - vec_alloc.reserve(al, 1); - ASR::alloc_arg_t alloc_arg; - alloc_arg.m_len_expr = nullptr; - alloc_arg.m_type = nullptr; - alloc_arg.loc = loc; - alloc_arg.m_a = result_var; - - ASR::dimension_t* m_dims = nullptr; - size_t n_dims = ASRUtils::extract_dimensions_from_ttype( - ASRUtils::expr_type(*current_expr), m_dims); - Vec vec_dims; - vec_dims.reserve(al, n_dims); - for( size_t i = 0; i < n_dims; i++ ) { - ASR::dimension_t dim; - dim.loc = loc; - dim.m_start = PassUtils::get_bound(*current_expr, i + 1, "lbound", al); - dim.m_length = ASRUtils::get_size(*current_expr, i + 1, al); - vec_dims.push_back(al, dim); + if( is_all_rank_0 ) { + return ; } - - alloc_arg.m_dims = vec_dims.p; - alloc_arg.n_dims = vec_dims.n; - vec_alloc.push_back(al, alloc_arg); - pass_result.push_back(al, ASRUtils::STMT(ASR::make_Allocate_t( - al, loc, vec_alloc.p, 1, nullptr, nullptr, nullptr))); - } - apply_again = true; - remove_original_statement = false; - } else if( PassUtils::is_elemental(x->m_name) ) { - std::vector array_mask(x->n_args, false); - bool at_least_one_array = false; - for( size_t iarg = 0; iarg < x->n_args; iarg++ ) { - array_mask[iarg] = (x->m_args[iarg].m_value != nullptr && - ASRUtils::is_array(ASRUtils::expr_type(x->m_args[iarg].m_value))); - at_least_one_array = at_least_one_array || array_mask[iarg]; - } - if (!at_least_one_array) { - return ; - } - std::string res_prefix = "_elemental_func_call_res"; - ASR::expr_t* result_var_copy = result_var; - bool is_all_rank_0 = true; - std::vector operands; - ASR::expr_t* operand = nullptr, *first_array_operand = nullptr; - int common_rank = 0; - bool are_all_rank_same = true; - for( size_t iarg = 0; iarg < x->n_args; iarg++ ) { - result_var = nullptr; - ASR::expr_t** current_expr_copy_9 = current_expr; - current_expr = &(x->m_args[iarg].m_value); - self().replace_expr(x->m_args[iarg].m_value); - operand = *current_expr; - current_expr = current_expr_copy_9; - operands.push_back(operand); - int rank_operand = PassUtils::get_rank(operand); - if( rank_operand > 0 && first_array_operand == nullptr ) { - first_array_operand = operand; + if( !are_all_rank_same ) { + throw LCompilersException("Broadcasting support not yet available " + "for different shape arrays."); } - if( common_rank == 0 ) { - common_rank = rank_operand; + result_var = result_var_copy; + bool result_var_created = false; + if( result_var == nullptr ) { + result_var = PassUtils::create_var(result_counter, res_prefix, + loc, operand, al, current_scope); + result_counter += 1; + result_var_created = true; } - if( common_rank != rank_operand && - rank_operand > 0 ) { - are_all_rank_same = false; + *current_expr = result_var; + if( op_expr == &(x->base) ) { + op_dims = nullptr; + op_n_dims = ASRUtils::extract_dimensions_from_ttype( + ASRUtils::expr_type(*current_expr), op_dims); } - array_mask[iarg] = (rank_operand > 0); - is_all_rank_0 = is_all_rank_0 && (rank_operand <= 0); - } - if( is_all_rank_0 ) { - return ; - } - if( !are_all_rank_same ) { - throw LCompilersException("Broadcasting support not yet available " - "for different shape arrays."); - } - result_var = result_var_copy; - bool result_var_created = false; - if( result_var == nullptr ) { - result_var = PassUtils::create_var(result_counter, res_prefix, - loc, operand, al, current_scope); - result_counter += 1; - result_var_created = true; - } - *current_expr = result_var; - if( op_expr == &(x->base) ) { - op_dims = nullptr; - op_n_dims = ASRUtils::extract_dimensions_from_ttype( - ASRUtils::expr_type(*current_expr), op_dims); - } - Vec idx_vars, loop_vars, idx_vars_value; - std::vector loop_var_indices; - Vec doloop_body; - create_do_loop(loc, common_rank, idx_vars, idx_vars_value, - loop_vars, loop_var_indices, doloop_body, first_array_operand, - [=, &operands, &idx_vars, &idx_vars_value, &doloop_body] () { - Vec ref_args; - ref_args.reserve(al, x->n_args); - for( size_t iarg = 0; iarg < x->n_args; iarg++ ) { - ASR::expr_t* ref = operands[iarg]; - if( array_mask[iarg] ) { - ref = PassUtils::create_array_ref(operands[iarg], idx_vars_value, al, current_scope); + ASR::dimension_t* m_dims; + int n_dims = ASRUtils::extract_dimensions_from_ttype( + ASRUtils::expr_type(operand), m_dims); + allocate_result_var(operand, m_dims, n_dims); + *current_expr = result_var; + + Vec idx_vars, loop_vars, idx_vars_value; + std::vector loop_var_indices; + Vec doloop_body; + create_do_loop(loc, common_rank, idx_vars, idx_vars_value, + loop_vars, loop_var_indices, doloop_body, first_array_operand, + [=, &operands, &idx_vars, &idx_vars_value, &doloop_body] () { + Vec ref_args; + ref_args.reserve(al, x->n_args); + for( size_t iarg = 0; iarg < x->n_args; iarg++ ) { + ASR::expr_t* ref = operands[iarg]; + if( array_mask[iarg] ) { + ref = PassUtils::create_array_ref(operands[iarg], idx_vars_value, al, current_scope); + } + ASR::call_arg_t ref_arg; + ref_arg.loc = ref->base.loc; + ref_arg.m_value = ref; + ref_args.push_back(al, ref_arg); } - ASR::call_arg_t ref_arg; - ref_arg.loc = ref->base.loc; - ref_arg.m_value = ref; - ref_args.push_back(al, ref_arg); + Vec empty_dim; + empty_dim.reserve(al, 1); + ASR::ttype_t* dim_less_type = ASRUtils::duplicate_type(al, x->m_type, &empty_dim); + ASR::expr_t* op_el_wise = nullptr; + op_el_wise = ASRUtils::EXPR(ASRUtils::make_FunctionCall_t_util(al, loc, + x->m_name, x->m_original_name, ref_args.p, ref_args.size(), dim_less_type, + nullptr, x->m_dt)); + ASR::expr_t* res = PassUtils::create_array_ref(result_var, idx_vars, al, current_scope); + ASR::stmt_t* assign = ASRUtils::STMT(ASR::make_Assignment_t(al, loc, res, op_el_wise, nullptr)); + doloop_body.push_back(al, assign); + }); + if( !result_var_created ) { + use_custom_loop_params = false; } - Vec empty_dim; - empty_dim.reserve(al, 1); - ASR::ttype_t* dim_less_type = ASRUtils::duplicate_type(al, x->m_type, &empty_dim); - ASR::expr_t* op_el_wise = nullptr; - op_el_wise = ASRUtils::EXPR(ASRUtils::make_FunctionCall_t_util(al, loc, - x->m_name, x->m_original_name, ref_args.p, ref_args.size(), dim_less_type, - nullptr, x->m_dt)); - ASR::expr_t* res = PassUtils::create_array_ref(result_var, idx_vars, al, current_scope); - ASR::stmt_t* assign = ASRUtils::STMT(ASR::make_Assignment_t(al, loc, res, op_el_wise, nullptr)); - doloop_body.push_back(al, assign); - }); - if( !result_var_created ) { - use_custom_loop_params = false; } + result_var = nullptr; } - result_var = nullptr; - } - + void replace_Array(ASR::Array_t* /*x*/) { + } }; class ArrayOpVisitor : public ASR::CallReplacerOnExpressionsVisitor @@ -1447,19 +1320,18 @@ class ArrayOpVisitor : public ASR::CallReplacerOnExpressionsVisitor result_lbound, result_ubound, result_inc; Vec* parent_body; std::map resultvar2value; + bool realloc_lhs; public: - bool apply_again; - ArrayOpVisitor(Allocator& al_, bool realloc_lhs_) : al(al_), use_custom_loop_params(false), remove_original_statement(false), replacer(al_, pass_result, use_custom_loop_params, - apply_again, remove_original_statement, + remove_original_statement, result_lbound, result_ubound, result_inc, resultvar2value, realloc_lhs_), - parent_body(nullptr), apply_again(false) { + parent_body(nullptr), realloc_lhs(realloc_lhs_) { pass_result.n = 0; result_lbound.n = 0; result_ubound.n = 0; @@ -1513,14 +1385,6 @@ class ArrayOpVisitor : public ASR::CallReplacerOnExpressionsVisitorget_scope()) { - if (is_a(*item.second)) { - PassUtils::handle_fn_return_var(al, - ASR::down_cast(item.second), - PassUtils::is_array); - } - } std::vector build_order = ASRUtils::determine_module_dependencies(x); @@ -1544,13 +1408,6 @@ class ArrayOpVisitor : public ASR::CallReplacerOnExpressionsVisitorget_scope()) { - if (is_a(*item.second)) { - PassUtils::handle_fn_return_var(al, - ASR::down_cast(item.second), - PassUtils::is_array); - } - } // Now visit everything else for (auto &item : x.m_symtab->get_scope()) { @@ -1566,14 +1423,6 @@ class ArrayOpVisitor : public ASR::CallReplacerOnExpressionsVisitorget_scope()) { - if (is_a(*item.second)) { - PassUtils::handle_fn_return_var(al, - ASR::down_cast(item.second), - PassUtils::is_array); - } - } - for (auto &item : x.m_symtab->get_scope()) { if (is_a(*item.second)) { ASR::AssociateBlock_t *s = ASR::down_cast(item.second); @@ -1611,13 +1460,48 @@ class ArrayOpVisitor : public ASR::CallReplacerOnExpressionsVisitor(*ASRUtils::expr_type(x.m_target)) && - ASR::is_a(*x.m_value)) || - (ASR::is_a(*x.m_value)) || + bool is_target_struct_member_array_and_value_array = (ASR::is_a(*x.m_target) && ASRUtils::is_array(ASRUtils::expr_type(x.m_value)) && ASRUtils::is_array(ASRUtils::expr_type(x.m_target)) && - !ASR::is_a(*x.m_value)) ) { // TODO: fix for StructInstanceMember targets + !ASR::is_a(*x.m_value)); + if( (ASR::is_a(*ASRUtils::expr_type(x.m_target)) && + ASR::is_a(*x.m_value)) || + (ASR::is_a(*x.m_value)) || + is_target_struct_member_array_and_value_array) { // TODO: fix for StructInstanceMember targets + if( is_target_struct_member_array_and_value_array ) { + if (realloc_lhs && ASRUtils::is_allocatable(x.m_target)) { // Add realloc-lhs later + Vec vec_alloc; + vec_alloc.reserve(al, 1); + ASR::alloc_arg_t alloc_arg; + alloc_arg.m_len_expr = nullptr; + alloc_arg.m_type = nullptr; + alloc_arg.loc = x.m_target->base.loc; + alloc_arg.m_a = x.m_target; + + + ASR::dimension_t* m_dims = nullptr; + size_t n_dims = ASRUtils::extract_dimensions_from_ttype( + ASRUtils::expr_type(x.m_value), m_dims); + Vec vec_dims; + vec_dims.reserve(al, n_dims); + for( size_t i = 0; i < n_dims; i++ ) { + ASR::dimension_t dim; + dim.loc = x.m_value->base.loc; + dim.m_start = PassUtils::get_bound(x.m_value, i + 1, "lbound", al); + dim.m_length = ASRUtils::get_size(x.m_value, i + 1, al); + vec_dims.push_back(al, dim); + } + + + alloc_arg.m_dims = vec_dims.p; + alloc_arg.n_dims = vec_dims.n; + vec_alloc.push_back(al, alloc_arg); + pass_result.push_back(al, ASRUtils::STMT(ASR::make_Allocate_t( + al, x.base.base.loc, vec_alloc.p, 1, nullptr, nullptr, nullptr))); + remove_original_statement = false; + } + } return ; } @@ -1670,15 +1554,16 @@ class ArrayOpVisitor : public ASR::CallReplacerOnExpressionsVisitor { ASR::BaseExprReplacer::replace_ArrayPhysicalCast(x); x->m_old = ASRUtils::extract_physical_type(ASRUtils::expr_type(x->m_arg)); } + + void replace_Array(ASR::Array_t* /*x*/) { + return ; + } }; class ReplaceNestedVisitor: public ASR::CallReplacerOnExpressionsVisitor { @@ -429,6 +433,10 @@ class ReplaceNestedVisitor: public ASR::CallReplacerOnExpressionsVisitor { @@ -602,6 +610,10 @@ class AssignNestedVars: public PassUtils::PassVisitor { if (x.m_dt) visit_expr(*x.m_dt); } + + void visit_Array(const ASR::Array_t& /*x*/) { + return ; + } }; void pass_nested_vars(Allocator &al, ASR::TranslationUnit_t &unit, diff --git a/src/libasr/pass/pass_manager.h b/src/libasr/pass/pass_manager.h index a09d07f552..0983bb8587 100644 --- a/src/libasr/pass/pass_manager.h +++ b/src/libasr/pass/pass_manager.h @@ -212,12 +212,15 @@ namespace LCompilers { "class_constructor", "pass_list_expr", // "arr_slice", TODO: Remove ``arr_slice.cpp`` completely - "subroutine_from_function", "where", + "subroutine_from_function", "array_op", + // "subroutine_from_function", "symbolic", "intrinsic_function", + "subroutine_from_function", "array_op", + // "subroutine_from_function", "pass_array_by_data", "print_struct_type", "print_arr", @@ -243,6 +246,7 @@ namespace LCompilers { "subroutine_from_function", "array_op", "intrinsic_function", + "subroutine_from_function", "array_op", "print_struct_type", "print_arr", diff --git a/src/libasr/pass/pass_utils.h b/src/libasr/pass/pass_utils.h index 1bd2ed5bc4..27c7edea7e 100644 --- a/src/libasr/pass/pass_utils.h +++ b/src/libasr/pass/pass_utils.h @@ -114,6 +114,11 @@ namespace LCompilers { return ASR::is_a(*ASRUtils::expr_type(var)); } + static inline bool is_aggregate_or_array_type(ASR::expr_t* var) { + return (ASR::is_a(*ASRUtils::expr_type(var)) || + ASRUtils::is_array(ASRUtils::expr_type(var))); + } + template class PassVisitor: public ASR::ASRPassBaseWalkVisitor { diff --git a/src/libasr/pass/subroutine_from_function.cpp b/src/libasr/pass/subroutine_from_function.cpp index ba1ded1a34..920b9fdc26 100644 --- a/src/libasr/pass/subroutine_from_function.cpp +++ b/src/libasr/pass/subroutine_from_function.cpp @@ -4,6 +4,8 @@ #include #include #include +#include +#include #include #include @@ -31,7 +33,7 @@ class CreateFunctionFromSubroutine: public PassUtils::PassVisitor(*item.second)) { PassUtils::handle_fn_return_var(al, ASR::down_cast(item.second), - PassUtils::is_aggregate_type); + PassUtils::is_aggregate_or_array_type); } } @@ -56,7 +58,7 @@ class CreateFunctionFromSubroutine: public PassUtils::PassVisitor(*item.second)) { PassUtils::handle_fn_return_var(al, ASR::down_cast(item.second), - PassUtils::is_aggregate_type); + PassUtils::is_aggregate_or_array_type); } } @@ -77,7 +79,7 @@ class CreateFunctionFromSubroutine: public PassUtils::PassVisitor(*item.second)) { PassUtils::handle_fn_return_var(al, ASR::down_cast(item.second), - PassUtils::is_aggregate_type); + PassUtils::is_aggregate_or_array_type); } } @@ -106,16 +108,21 @@ class ReplaceFunctionCallWithSubroutineCall: Allocator& al; int result_counter; Vec& pass_result; + std::map& resultvar2value; public: - ASR::expr_t *result_var; SymbolTable* current_scope; + ASR::expr_t* result_var; + bool& apply_again; ReplaceFunctionCallWithSubroutineCall(Allocator& al_, - Vec& pass_result_): - al(al_), result_counter(0), - pass_result(pass_result_), result_var(nullptr) + Vec& pass_result_, + std::map& resultvar2value_, + bool& apply_again_): + al(al_), result_counter(0), pass_result(pass_result_), + resultvar2value(resultvar2value_), result_var(nullptr), + apply_again(apply_again_) {} void replace_FunctionCall(ASR::FunctionCall_t* x) { @@ -129,39 +136,130 @@ class ReplaceFunctionCallWithSubroutineCall: return ; } + const Location& loc = x->base.base.loc; + if( ASR::is_a(*ASRUtils::symbol_get_past_external(x->m_name)) && + ASRUtils::symbol_abi(x->m_name) == ASR::abiType::Source ) { + for( size_t i = 0; i < x->n_args; i++ ) { + if( x->m_args[i].m_value && ASR::is_a(*x->m_args[i].m_value) && + ASR::is_a(* + ASR::down_cast(x->m_args[i].m_value)->m_arg) ) { + x->m_args[i].m_value = ASR::down_cast(x->m_args[i].m_value)->m_arg; + } + if( x->m_args[i].m_value && ASR::is_a(*x->m_args[i].m_value) && + ASRUtils::is_array(ASRUtils::expr_type(x->m_args[i].m_value)) ) { + ASR::expr_t* arg_var = PassUtils::create_var(result_counter, + "_func_call_arg_tmp_", loc, x->m_args[i].m_value, al, current_scope); + result_counter += 1; + apply_again = true; + pass_result.push_back(al, ASRUtils::STMT(ASR::make_Assignment_t(al, loc, + arg_var, x->m_args[i].m_value, nullptr))); + x->m_args[i].m_value = arg_var; + } + } + } + + if (x->m_value) { + *current_expr = x->m_value; + return; + } + + ASR::expr_t* result_var_ = nullptr; + if( resultvar2value.find(result_var) != resultvar2value.end() && + resultvar2value[result_var] == *current_expr ) { + result_var_ = result_var; + } + bool is_return_var_handled = false; ASR::symbol_t *fn_name = ASRUtils::symbol_get_past_external(x->m_name); if (ASR::is_a(*fn_name)) { ASR::Function_t *fn = ASR::down_cast(fn_name); is_return_var_handled = fn->m_return_var == nullptr; } - if (!is_return_var_handled) { - return ; - } + if (is_return_var_handled) { + ASR::ttype_t* result_var_type = x->m_type; + bool is_allocatable = false; + bool is_func_call_allocatable = false; + bool is_result_var_allocatable = false; + ASR::Function_t *fn = ASR::down_cast(fn_name); + { + // Assuming the `m_return_var` is appended to the `args`. + ASR::symbol_t *v_sym = ASR::down_cast( + fn->m_args[fn->n_args-1])->m_v; + if (ASR::is_a(*v_sym)) { + ASR::Variable_t *v = ASR::down_cast(v_sym); + is_func_call_allocatable = ASR::is_a(*v->m_type); + if( result_var_ != nullptr ) { + is_result_var_allocatable = ASR::is_a(*ASRUtils::expr_type(result_var_)); + is_allocatable = is_func_call_allocatable || is_result_var_allocatable; + } + if( is_allocatable ) { + result_var_type = ASRUtils::duplicate_type_with_empty_dims(al, result_var_type); + result_var_type = ASRUtils::TYPE(ASR::make_Allocatable_t( + al, loc, ASRUtils::type_get_past_allocatable(result_var_type))); + } + } + + // Don't always create this temporary variable + ASR::expr_t* result_var__ = PassUtils::create_var(result_counter, + "_func_call_res", loc, result_var_type, al, current_scope); + result_counter += 1; + *current_expr = result_var__; + } - if( result_var == nullptr || !ASRUtils::is_array(x->m_type) ) { - result_var = PassUtils::create_var(result_counter, - "_libasr_created_return_var_", - x->base.base.loc, x->m_type, al, current_scope); - result_counter += 1; - } - LCOMPILERS_ASSERT(result_var != nullptr); - *current_expr = result_var; - - 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 = ASRUtils::STMT(ASRUtils::make_SubroutineCall_t_util( - al, x->base.base.loc, x->m_name, nullptr, s_args.p, s_args.size(), nullptr, - nullptr, false)); - pass_result.push_back(al, subrout_call); - result_var = nullptr; + if( !is_func_call_allocatable && is_result_var_allocatable ) { + Vec vec_alloc; + vec_alloc.reserve(al, 1); + ASR::alloc_arg_t alloc_arg; + alloc_arg.m_len_expr = nullptr; + alloc_arg.m_type = nullptr; + alloc_arg.loc = loc; + alloc_arg.m_a = *current_expr; + + ASR::FunctionType_t* fn_type = ASRUtils::get_FunctionType(fn); + ASR::ttype_t* output_type = fn_type->m_arg_types[fn_type->n_arg_types - 1]; + ASR::dimension_t* m_dims = nullptr; + size_t n_dims = ASRUtils::extract_dimensions_from_ttype(output_type, m_dims); + Vec vec_dims; + vec_dims.reserve(al, n_dims); + ASRUtils::ReplaceFunctionParamVisitor replace_function_param_visitor(x->m_args); + ASRUtils::ExprStmtDuplicator expr_duplicator(al); + for( size_t i = 0; i < n_dims; i++ ) { + ASR::dimension_t dim; + dim.loc = loc; + dim.m_start = expr_duplicator.duplicate_expr(m_dims[i].m_start); + dim.m_length = expr_duplicator.duplicate_expr(m_dims[i].m_length); + replace_function_param_visitor.current_expr = &dim.m_start; + replace_function_param_visitor.replace_expr(dim.m_start); + replace_function_param_visitor.current_expr = &dim.m_length; + replace_function_param_visitor.replace_expr(dim.m_length); + vec_dims.push_back(al, dim); + } + + alloc_arg.m_dims = vec_dims.p; + alloc_arg.n_dims = vec_dims.n; + vec_alloc.push_back(al, alloc_arg); + pass_result.push_back(al, ASRUtils::STMT(ASR::make_Allocate_t( + al, loc, vec_alloc.p, 1, nullptr, nullptr, nullptr))); + } + + Vec s_args; + s_args.reserve(al, x->n_args + 1); + for( size_t i = 0; i < x->n_args; i++ ) { + ASR::expr_t** current_expr_copy_9 = current_expr; + current_expr = &(x->m_args[i].m_value); + self().replace_expr(x->m_args[i].m_value); + current_expr = current_expr_copy_9; + s_args.push_back(al, x->m_args[i]); + } + ASR::call_arg_t result_arg; + result_arg.loc = loc; + result_arg.m_value = *current_expr; + s_args.push_back(al, result_arg); + ASR::stmt_t* subrout_call = ASRUtils::STMT(ASRUtils::make_SubroutineCall_t_util(al, loc, + x->m_name, nullptr, s_args.p, s_args.size(), nullptr, + nullptr, false)); + pass_result.push_back(al, subrout_call); + } } }; @@ -175,12 +273,15 @@ class ReplaceFunctionCallWithSubroutineCallVisitor: Vec pass_result; ReplaceFunctionCallWithSubroutineCall replacer; Vec* parent_body; + std::map resultvar2value; public: + bool apply_again; + ReplaceFunctionCallWithSubroutineCallVisitor(Allocator& al_): - al(al_), replacer(al, pass_result), - parent_body(nullptr) + al(al_), replacer(al, pass_result, resultvar2value, apply_again), + parent_body(nullptr), apply_again(false) { pass_result.n = 0; } @@ -216,14 +317,31 @@ class ReplaceFunctionCallWithSubroutineCallVisitor: pass_result.n = 0; } - void visit_Assignment(const ASR::Assignment_t& x) { - if( PassUtils::is_aggregate_type(x.m_target) ) { + void visit_Assignment(const ASR::Assignment_t &x) { + bool is_target_struct_member_array_and_value_array = + (ASR::is_a(*x.m_target) && + ASRUtils::is_array(ASRUtils::expr_type(x.m_value)) && + ASRUtils::is_array(ASRUtils::expr_type(x.m_target)) && + !ASR::is_a(*x.m_value)); + if( (ASR::is_a(*ASRUtils::expr_type(x.m_target)) && + ASR::is_a(*x.m_value)) || + (ASR::is_a(*x.m_value)) || + is_target_struct_member_array_and_value_array) { // TODO: fix for StructInstanceMember targets + return ; + } + + if( ASR::is_a(*x.m_value) ) { + ASR::CallReplacerOnExpressionsVisitor::visit_Assignment(x); + return ; + } + + if( PassUtils::is_array(x.m_target) ) { replacer.result_var = x.m_target; + ASR::expr_t* original_value = x.m_value; + resultvar2value[replacer.result_var] = original_value; } ASR::CallReplacerOnExpressionsVisitor::visit_Assignment(x); - replacer.result_var = nullptr; } - }; void pass_create_subroutine_from_function(Allocator &al, ASR::TranslationUnit_t &unit, @@ -231,7 +349,13 @@ void pass_create_subroutine_from_function(Allocator &al, ASR::TranslationUnit_t CreateFunctionFromSubroutine v(al); v.visit_TranslationUnit(unit); ReplaceFunctionCallWithSubroutineCallVisitor u(al); - u.visit_TranslationUnit(unit); + u.apply_again = true; + while( u.apply_again ) { + u.apply_again = false; + u.visit_TranslationUnit(unit); + } + PassUtils::UpdateDependenciesVisitor w(al); + w.visit_TranslationUnit(unit); } diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index f3a3eeea18..96c1fb9ca1 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -7446,7 +7446,7 @@ class BodyVisitor : public CommonVisitor { dim = ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, loc, args[1].m_value, ASR::binopType::Add, const_one, int_type, nullptr)); } - tmp = ASRUtils::make_ArraySize_t_util(al, loc, var, dim, int_type, nullptr); + tmp = ASRUtils::make_ArraySize_t_util(al, loc, var, dim, int_type, nullptr, false); return; } else if (call_name == "empty") { if (x.n_args != 1 || x.n_keywords != 1) { diff --git a/src/lpython/semantics/python_attribute_eval.h b/src/lpython/semantics/python_attribute_eval.h index 8bb8296a8d..d6491dff80 100644 --- a/src/lpython/semantics/python_attribute_eval.h +++ b/src/lpython/semantics/python_attribute_eval.h @@ -118,7 +118,7 @@ struct AttributeHandler { throw SemanticError("array.size() takes no arguments", loc); } ASR::ttype_t *int_type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc, 4)); - return ASRUtils::make_ArraySize_t_util(al, loc, s, nullptr, int_type, nullptr); + return ASRUtils::make_ArraySize_t_util(al, loc, s, nullptr, int_type, nullptr, false); } static ASR::asr_t* eval_list_append(ASR::expr_t *s, Allocator &al, const Location &loc,