From ea45e4f410662e55000eb9807f18dd2a19e1b2d0 Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Sat, 12 Aug 2023 16:55:22 +0530 Subject: [PATCH 1/4] Sync IntrinsicFunction from LFortran --- src/libasr/ASR.asdl | 2 + src/libasr/asdl_cpp.py | 2 + src/libasr/asr_utils.h | 25 +- src/libasr/asr_verify.cpp | 13 + src/libasr/codegen/asr_to_julia.cpp | 23 +- src/libasr/pass/array_op.cpp | 28 +- .../pass/intrinsic_array_function_registry.h | 1585 ++++++++++++++++ src/libasr/pass/intrinsic_function.cpp | 75 +- src/libasr/pass/intrinsic_function_registry.h | 1659 ++++------------- src/libasr/pass/where.cpp | 2 +- src/lpython/semantics/python_ast_to_asr.cpp | 11 +- 11 files changed, 2119 insertions(+), 1306 deletions(-) create mode 100644 src/libasr/pass/intrinsic_array_function_registry.h diff --git a/src/libasr/ASR.asdl b/src/libasr/ASR.asdl index 3aeefa0028..e038f1ef36 100644 --- a/src/libasr/ASR.asdl +++ b/src/libasr/ASR.asdl @@ -237,6 +237,8 @@ expr ttype type, expr? value, expr? dt) | IntrinsicFunction(int intrinsic_id, expr* args, int overload_id, ttype? type, expr? value) + | IntrinsicArrayFunction(int arr_intrinsic_id, expr* args, int overload_id, + ttype? type, expr? value) | IntrinsicImpureFunction(int impure_intrinsic_id, expr* args, int overload_id, ttype? type, expr? value) | StructTypeConstructor(symbol dt_sym, call_arg* args, ttype type, expr? value) diff --git a/src/libasr/asdl_cpp.py b/src/libasr/asdl_cpp.py index 2a153ed4da..8eb94ef999 100644 --- a/src/libasr/asdl_cpp.py +++ b/src/libasr/asdl_cpp.py @@ -1682,6 +1682,8 @@ def visitField(self, field, cons): self.emit('s.append(self().convert_intrinsic_id(x.m_%s));' % field.name, 2) elif field.name == "impure_intrinsic_id": self.emit('s.append(self().convert_impure_intrinsic_id(x.m_%s));' % field.name, 2) + elif field.name == "arr_intrinsic_id": + self.emit('s.append(self().convert_array_intrinsic_id(x.m_%s));' % field.name, 2) else: self.emit('s.append(std::to_string(x.m_%s));' % field.name, 2) elif field.type == "float" and not field.seq and not field.opt: diff --git a/src/libasr/asr_utils.h b/src/libasr/asr_utils.h index ef96025201..638bc96d00 100644 --- a/src/libasr/asr_utils.h +++ b/src/libasr/asr_utils.h @@ -1738,7 +1738,7 @@ static inline bool is_generic_function(ASR::symbol_t *x) { return true; } } - return func_type->m_return_var_type + return func_type->m_return_var_type && is_type_parameter(*func_type->m_return_var_type); } default: return false; @@ -4184,6 +4184,29 @@ static inline ASR::asr_t* make_IntrinsicFunction_t_util( a_args, n_args, a_overload_id, a_type, a_value); } +static inline ASR::asr_t* make_IntrinsicArrayFunction_t_util( + Allocator &al, const Location &a_loc, int64_t arr_intrinsic_id, + ASR::expr_t** a_args, size_t n_args, int64_t a_overload_id, + ASR::ttype_t* a_type, ASR::expr_t* a_value) { + + for( size_t i = 0; i < n_args; i++ ) { + if( a_args[i] == nullptr || + ASR::is_a(*a_args[i]) ) { + continue; + } + ASR::expr_t* arg = a_args[i]; + ASR::ttype_t* arg_type = ASRUtils::type_get_past_allocatable( + ASRUtils::type_get_past_pointer(ASRUtils::expr_type(arg))); + + if( ASRUtils::is_array(arg_type) ) { + a_args[i] = cast_to_descriptor(al, arg); + } + } + + return ASR::make_IntrinsicArrayFunction_t(al, a_loc, arr_intrinsic_id, + a_args, n_args, a_overload_id, a_type, a_value); +} + static inline ASR::asr_t* make_Associate_t_util( Allocator &al, const Location &a_loc, ASR::expr_t* a_target, ASR::expr_t* a_value) { diff --git a/src/libasr/asr_verify.cpp b/src/libasr/asr_verify.cpp index 34c05e48b1..caa2fcb5e1 100644 --- a/src/libasr/asr_verify.cpp +++ b/src/libasr/asr_verify.cpp @@ -4,6 +4,7 @@ #include #include #include +#include namespace LCompilers { @@ -985,6 +986,18 @@ class VerifyVisitor : public BaseWalkVisitor BaseWalkVisitor::visit_IntrinsicFunction(x); } + void visit_IntrinsicArrayFunction(const ASR::IntrinsicArrayFunction_t& x) { + if( !check_external ) { + BaseWalkVisitor::visit_IntrinsicArrayFunction(x); + return ; + } + ASRUtils::verify_array_function verify_ = ASRUtils::IntrinsicArrayFunctionRegistry + ::get_verify_function(x.m_arr_intrinsic_id); + LCOMPILERS_ASSERT(verify_ != nullptr); + verify_(x, diagnostics); + BaseWalkVisitor::visit_IntrinsicArrayFunction(x); + } + void visit_FunctionCall(const FunctionCall_t &x) { require(x.m_name, "FunctionCall::m_name must be present"); diff --git a/src/libasr/codegen/asr_to_julia.cpp b/src/libasr/codegen/asr_to_julia.cpp index 07c35545aa..c9f67f1b4d 100644 --- a/src/libasr/codegen/asr_to_julia.cpp +++ b/src/libasr/codegen/asr_to_julia.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include #include @@ -1915,7 +1916,6 @@ class ASRToJuliaVisitor : public ASR::BaseVisitor SET_INTRINSIC_NAME(Exp, "exp"); SET_INTRINSIC_NAME(Exp2, "exp2"); SET_INTRINSIC_NAME(Expm1, "expm1"); - SET_INTRINSIC_NAME(Sum, "sum"); default : { throw LCompilersException("IntrinsicFunction: `" + ASRUtils::get_intrinsic_name(x.m_intrinsic_id) @@ -1925,6 +1925,27 @@ class ASRToJuliaVisitor : public ASR::BaseVisitor out += "(" + src + ")"; src = out; } + + #define SET_ARR_INTRINSIC_NAME(X, func_name) \ + case (static_cast(ASRUtils::IntrinsicArrayFunctions::X)) : { \ + out += func_name; break; \ + } + + void visit_IntrinsicArrayFunction(const ASR::IntrinsicArrayFunction_t &x) { + std::string out; + LCOMPILERS_ASSERT(x.n_args == 1); + visit_expr(*x.m_args[0]); + switch (x.m_arr_intrinsic_id) { + SET_ARR_INTRINSIC_NAME(Sum, "sum"); + default : { + throw LCompilersException("IntrinsicFunction: `" + + ASRUtils::get_intrinsic_name(x.m_arr_intrinsic_id) + + "` is not implemented"); + } + } + out += "(" + src + ")"; + src = out; + } }; Result diff --git a/src/libasr/pass/array_op.cpp b/src/libasr/pass/array_op.cpp index 0b27f94d7b..9e31279fd0 100644 --- a/src/libasr/pass/array_op.cpp +++ b/src/libasr/pass/array_op.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -915,10 +916,8 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { replace_ArrayOpCommon(x, "_string_comp_op_res"); } - void replace_IntrinsicFunction(ASR::IntrinsicFunction_t* x) { - if( !ASRUtils::IntrinsicFunctionRegistry::is_elemental(x->m_intrinsic_id) ) { - return ; - } + template + void replace_intrinsic_function(T* x) { LCOMPILERS_ASSERT(current_scope != nullptr); const Location& loc = x->base.base.loc; std::vector array_mask(x->n_args, false); @@ -1003,9 +1002,10 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { 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 = ASRUtils::EXPR(ASRUtils::make_IntrinsicFunction_t_util(al, loc, - x->m_intrinsic_id, ref_args.p, ref_args.size(), x->m_overload_id, - dim_less_type, nullptr)); + x->m_args = ref_args.p; + x->n_args = ref_args.size(); + x->m_type = dim_less_type; + ASR::expr_t* op_el_wise = ASRUtils::EXPR((ASR::asr_t *) ASR::expr_t* res = PassUtils::create_array_ref(result_var, idx_vars, al); ASR::stmt_t* assign = ASRUtils::STMT(ASR::make_Assignment_t(al, loc, res, op_el_wise, nullptr)); doloop_body.push_back(al, assign); @@ -1014,6 +1014,20 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { result_var = nullptr; } + void replace_IntrinsicFunction(ASR::IntrinsicFunction_t* x) { + if(!ASRUtils::IntrinsicFunctionRegistry::is_elemental(x->m_intrinsic_id)) { + return ; + } + replace_intrinsic_function(x); + } + + void replace_IntrinsicArrayFunction(ASR::IntrinsicArrayFunction_t* x) { + if(!ASRUtils::IntrinsicArrayFunctionRegistry::is_elemental(x->m_arr_intrinsic_id)) { + return ; + } + replace_intrinsic_function(x); + } + void replace_ArrayPhysicalCast(ASR::ArrayPhysicalCast_t* x) { ASR::BaseExprReplacer::replace_ArrayPhysicalCast(x); if( ASRUtils::extract_physical_type(ASRUtils::expr_type(x->m_arg)) != x->m_old ) { diff --git a/src/libasr/pass/intrinsic_array_function_registry.h b/src/libasr/pass/intrinsic_array_function_registry.h new file mode 100644 index 0000000000..39a4cda380 --- /dev/null +++ b/src/libasr/pass/intrinsic_array_function_registry.h @@ -0,0 +1,1585 @@ +#ifndef LFORTRAN_PASS_INTRINSIC_ARRAY_FUNCTIONS_H +#define LFORTRAN_PASS_INTRINSIC_ARRAY_FUNCTIONS_H + +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace LCompilers { + +namespace ASRUtils { + +/************************* Intrinsic Array Functions **************************/ +enum class IntrinsicArrayFunctions : int64_t { + Any, + MaxLoc, + MaxVal, + Merge, + MinLoc, + MinVal, + Product, + Shape, + Sum, + // ... +}; + +#define ARRAY_INTRINSIC_NAME_CASE(X) \ + case (static_cast(ASRUtils::IntrinsicArrayFunctions::X)) : { \ + return #X; \ + } + +inline std::string get_array_intrinsic_name(int x) { + switch (x) { + ARRAY_INTRINSIC_NAME_CASE(Any) + ARRAY_INTRINSIC_NAME_CASE(MaxLoc) + ARRAY_INTRINSIC_NAME_CASE(MaxVal) + ARRAY_INTRINSIC_NAME_CASE(Merge) + ARRAY_INTRINSIC_NAME_CASE(MinLoc) + ARRAY_INTRINSIC_NAME_CASE(MinVal) + ARRAY_INTRINSIC_NAME_CASE(Product) + ARRAY_INTRINSIC_NAME_CASE(Shape) + ARRAY_INTRINSIC_NAME_CASE(Sum) + default : { + throw LCompilersException("pickle: intrinsic_id not implemented"); + } + } +} + +typedef ASR::expr_t* (ASRBuilder::*elemental_operation_func)(ASR::expr_t*, + ASR::expr_t*, const Location&, ASR::expr_t*); + +typedef void (*verify_array_func)(ASR::expr_t*, ASR::ttype_t*, + const Location&, diag::Diagnostics&, + ASRUtils::IntrinsicArrayFunctions); + +typedef void (*verify_array_function)( + const ASR::IntrinsicArrayFunction_t&, + diag::Diagnostics&); + +namespace ArrIntrinsic { + +static inline void verify_array_int_real_cmplx(ASR::expr_t* array, ASR::ttype_t* return_type, + const Location& loc, diag::Diagnostics& diagnostics, ASRUtils::IntrinsicArrayFunctions intrinsic_func_id) { + std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); + ASR::ttype_t* array_type = ASRUtils::expr_type(array); + ASRUtils::require_impl(ASRUtils::is_integer(*array_type) || + ASRUtils::is_real(*array_type) || + ASRUtils::is_complex(*array_type), + "Input to " + intrinsic_func_name + " intrinsic must be of integer, real or complex type, found: " + + ASRUtils::get_type_code(array_type), loc, diagnostics); + int array_n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); + ASRUtils::require_impl(array_n_dims > 0, "Input to " + intrinsic_func_name + " intrinsic must always be an array", + loc, diagnostics); + ASRUtils::require_impl(ASRUtils::check_equal_type( + return_type, array_type, false), + intrinsic_func_name + " intrinsic must return an output of the same type as input", loc, diagnostics); + int return_n_dims = ASRUtils::extract_n_dims_from_ttype(return_type); + ASRUtils::require_impl(return_n_dims == 0, + intrinsic_func_name + " intrinsic output for array only input should be a scalar, found an array of " + + std::to_string(return_n_dims), loc, diagnostics); +} + +static inline void verify_array_int_real(ASR::expr_t* array, ASR::ttype_t* return_type, + const Location& loc, diag::Diagnostics& diagnostics, ASRUtils::IntrinsicArrayFunctions intrinsic_func_id) { + std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); + ASR::ttype_t* array_type = ASRUtils::expr_type(array); + ASRUtils::require_impl(ASRUtils::is_integer(*array_type) || + ASRUtils::is_real(*array_type), + "Input to " + intrinsic_func_name + " intrinsic must be of integer or real type, found: " + + ASRUtils::get_type_code(array_type), loc, diagnostics); + int array_n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); + ASRUtils::require_impl(array_n_dims > 0, "Input to " + intrinsic_func_name + " intrinsic must always be an array", + loc, diagnostics); + ASRUtils::require_impl(ASRUtils::check_equal_type( + return_type, array_type, false), + intrinsic_func_name + " intrinsic must return an output of the same type as input", loc, diagnostics); + int return_n_dims = ASRUtils::extract_n_dims_from_ttype(return_type); + ASRUtils::require_impl(return_n_dims == 0, + intrinsic_func_name + " intrinsic output for array only input should be a scalar, found an array of " + + std::to_string(return_n_dims), loc, diagnostics); +} + +static inline void verify_array_dim(ASR::expr_t* array, ASR::expr_t* dim, + ASR::ttype_t* return_type, const Location& loc, diag::Diagnostics& diagnostics, ASRUtils::IntrinsicArrayFunctions intrinsic_func_id) { + std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); + ASR::ttype_t* array_type = ASRUtils::expr_type(array); + ASRUtils::require_impl(ASRUtils::is_integer(*array_type) || + ASRUtils::is_real(*array_type) || + ASRUtils::is_complex(*array_type), + "Input to " + intrinsic_func_name + " intrinsic must be of integer, real or complex type, found: " + + ASRUtils::get_type_code(array_type), loc, diagnostics); + int array_n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); + ASRUtils::require_impl(array_n_dims > 0, "Input to " + intrinsic_func_name + " intrinsic must always be an array", + loc, diagnostics); + + ASRUtils::require_impl(ASRUtils::is_integer(*ASRUtils::expr_type(dim)), + "dim argument must be an integer", loc, diagnostics); + + ASRUtils::require_impl(ASRUtils::check_equal_type( + return_type, array_type, false), + intrinsic_func_name + " intrinsic must return an output of the same type as input", loc, diagnostics); + int return_n_dims = ASRUtils::extract_n_dims_from_ttype(return_type); + ASRUtils::require_impl(array_n_dims == return_n_dims + 1, + intrinsic_func_name + " intrinsic output must return an array with dimension " + "only 1 less than that of input array", + loc, diagnostics); +} + +static inline void verify_args(const ASR::IntrinsicArrayFunction_t& x, diag::Diagnostics& diagnostics, + ASRUtils::IntrinsicArrayFunctions intrinsic_func_id, verify_array_func verify_array) { + std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); + ASRUtils::require_impl(x.n_args >= 1, intrinsic_func_name + " intrinsic must accept at least one argument", + x.base.base.loc, diagnostics); + ASRUtils::require_impl(x.m_args[0] != nullptr, "Array argument to " + intrinsic_func_name + " intrinsic cannot be nullptr", + x.base.base.loc, diagnostics); + const int64_t id_array = 0, id_array_dim = 1, id_array_mask = 2; + const int64_t id_array_dim_mask = 3; + switch( x.m_overload_id ) { + case id_array: + case id_array_mask: { + if( x.m_overload_id == id_array_mask ) { + ASRUtils::require_impl(x.n_args == 2 && x.m_args[1] != nullptr, + "mask argument cannot be nullptr", x.base.base.loc, diagnostics); + } + verify_array(x.m_args[0], x.m_type, x.base.base.loc, diagnostics, intrinsic_func_id); + break; + } + case id_array_dim: + case id_array_dim_mask: { + if( x.m_overload_id == id_array_dim_mask ) { + ASRUtils::require_impl(x.n_args == 3 && x.m_args[2] != nullptr, + "mask argument cannot be nullptr", x.base.base.loc, diagnostics); + } + ASRUtils::require_impl(x.n_args >= 2 && x.m_args[1] != nullptr, + "dim argument to any intrinsic cannot be nullptr", + x.base.base.loc, diagnostics); + verify_array_dim(x.m_args[0], x.m_args[1], x.m_type, x.base.base.loc, diagnostics, intrinsic_func_id); + break; + } + default: { + require_impl(false, "Unrecognised overload id in " + intrinsic_func_name + " intrinsic", + x.base.base.loc, diagnostics); + } + } + if( x.m_overload_id == id_array_mask || + x.m_overload_id == id_array_dim_mask ) { + ASR::expr_t* mask = nullptr; + if( x.m_overload_id == id_array_mask ) { + mask = x.m_args[1]; + } else if( x.m_overload_id == id_array_dim_mask ) { + mask = x.m_args[2]; + } + ASR::dimension_t *array_dims, *mask_dims; + ASR::ttype_t* array_type = ASRUtils::expr_type(x.m_args[0]); + ASR::ttype_t* mask_type = ASRUtils::expr_type(mask); + size_t array_n_dims = ASRUtils::extract_dimensions_from_ttype(array_type, array_dims); + size_t mask_n_dims = ASRUtils::extract_dimensions_from_ttype(mask_type, mask_dims); + ASRUtils::require_impl(ASRUtils::dimensions_equal(array_dims, array_n_dims, mask_dims, mask_n_dims), + "The dimensions of array and mask arguments of " + intrinsic_func_name + " intrinsic must be same", + x.base.base.loc, diagnostics); + } +} + +static inline ASR::expr_t *eval_ArrIntrinsic(Allocator & /*al*/, + const Location & /*loc*/, ASR::ttype_t *, Vec& /*args*/) { + return nullptr; +} + +static inline ASR::asr_t* create_ArrIntrinsic( + Allocator& al, const Location& loc, Vec& args, + const std::function err, + ASRUtils::IntrinsicArrayFunctions intrinsic_func_id) { + std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); + int64_t id_array = 0, id_array_dim = 1, id_array_mask = 2; + int64_t id_array_dim_mask = 3; + int64_t overload_id = id_array; + + ASR::expr_t* array = args[0]; + ASR::expr_t *arg2 = nullptr, *arg3 = nullptr; + if( args.size() >= 2 ) { + arg2 = args[1]; + } + if( args.size() == 3 ) { + arg3 = args[2]; + } + + if( !arg2 && arg3 ) { + std::swap(arg2, arg3); + } + + ASR::ttype_t* array_type = ASRUtils::expr_type(array); + if( arg2 && !arg3 ) { + size_t arg2_rank = ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(arg2)); + if( arg2_rank == 0 ) { + overload_id = id_array_dim; + } else { + overload_id = id_array_mask; + } + } else if( arg2 && arg3 ) { + ASR::expr_t* arg2 = args[1]; + ASR::expr_t* arg3 = args[2]; + size_t arg2_rank = ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(arg2)); + size_t arg3_rank = ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(arg3)); + + if( arg2_rank != 0 ) { + err("dim argument to " + intrinsic_func_name + " must be a scalar and must not be an array", + arg2->base.loc); + } + + if( arg3_rank == 0 ) { + err("mask argument to " + intrinsic_func_name + " must be an array and must not be a scalar", + arg3->base.loc); + } + + overload_id = id_array_dim_mask; + } + + // TODO: Add a check for range of values axis can take + // if axis is available at compile time + + ASR::expr_t *value = nullptr; + Vec arg_values; + arg_values.reserve(al, 3); + ASR::expr_t *array_value = ASRUtils::expr_value(array); + arg_values.push_back(al, array_value); + if( arg2 ) { + ASR::expr_t *arg2_value = ASRUtils::expr_value(arg2); + arg_values.push_back(al, arg2_value); + } + if( arg3 ) { + ASR::expr_t* mask = arg3; + ASR::expr_t *mask_value = ASRUtils::expr_value(mask); + arg_values.push_back(al, mask_value); + } + + ASR::ttype_t* return_type = nullptr; + if( overload_id == id_array || + overload_id == id_array_mask ) { + ASR::ttype_t* type = ASRUtils::type_get_past_allocatable( + ASRUtils::type_get_past_pointer(array_type)); + return_type = ASRUtils::duplicate_type_without_dims( + al, type, loc); + } else if( overload_id == id_array_dim || + overload_id == id_array_dim_mask ) { + Vec dims; + size_t n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); + dims.reserve(al, (int) n_dims - 1); + for( int i = 0; i < (int) n_dims - 1; i++ ) { + ASR::dimension_t dim; + dim.loc = array->base.loc; + dim.m_length = nullptr; + dim.m_start = nullptr; + dims.push_back(al, dim); + } + return_type = ASRUtils::duplicate_type(al, array_type, &dims); + } + value = eval_ArrIntrinsic(al, loc, return_type, arg_values); + + Vec arr_intrinsic_args; + arr_intrinsic_args.reserve(al, 3); + arr_intrinsic_args.push_back(al, array); + if( arg2 ) { + arr_intrinsic_args.push_back(al, arg2); + } + if( arg3 ) { + arr_intrinsic_args.push_back(al, arg3); + } + + return ASRUtils::make_IntrinsicArrayFunction_t_util(al, loc, + static_cast(intrinsic_func_id), + arr_intrinsic_args.p, arr_intrinsic_args.n, overload_id, return_type, value); +} + +static inline void generate_body_for_array_input(Allocator& al, const Location& loc, + ASR::expr_t* array, ASR::expr_t* return_var, SymbolTable* fn_scope, + Vec& fn_body, get_initial_value_func get_initial_value, elemental_operation_func elemental_operation) { + ASRBuilder builder(al, loc); + Vec idx_vars; + Vec doloop_body; + builder.generate_reduction_intrinsic_stmts_for_scalar_output(loc, + array, fn_scope, fn_body, idx_vars, doloop_body, + [=, &al, &fn_body, &builder] { + ASR::ttype_t* array_type = ASRUtils::expr_type(array); + ASR::ttype_t* element_type = ASRUtils::duplicate_type_without_dims(al, array_type, loc); + ASR::expr_t* initial_val = get_initial_value(al, element_type); + ASR::stmt_t* return_var_init = builder.Assignment(return_var, initial_val); + fn_body.push_back(al, return_var_init); + }, + [=, &al, &idx_vars, &doloop_body, &builder] () { + ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); + ASR::expr_t* elemental_operation_val = (builder.*elemental_operation)(return_var, array_ref, loc, nullptr); + ASR::stmt_t* loop_invariant = builder.Assignment(return_var, elemental_operation_val); + doloop_body.push_back(al, loop_invariant); + }); +} + +static inline void generate_body_for_array_mask_input(Allocator& al, const Location& loc, + ASR::expr_t* array, ASR::expr_t* mask, ASR::expr_t* return_var, SymbolTable* fn_scope, + Vec& fn_body, get_initial_value_func get_initial_value, elemental_operation_func elemental_operation) { + ASRBuilder builder(al, loc); + Vec idx_vars; + Vec doloop_body; + builder.generate_reduction_intrinsic_stmts_for_scalar_output(loc, + array, fn_scope, fn_body, idx_vars, doloop_body, + [=, &al, &fn_body, &builder] { + ASR::ttype_t* array_type = ASRUtils::expr_type(array); + ASR::ttype_t* element_type = ASRUtils::duplicate_type_without_dims(al, array_type, loc); + ASR::expr_t* initial_val = get_initial_value(al, element_type); + ASR::stmt_t* return_var_init = builder.Assignment(return_var, initial_val); + fn_body.push_back(al, return_var_init); + }, + [=, &al, &idx_vars, &doloop_body, &builder] () { + ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); + ASR::expr_t* mask_ref = PassUtils::create_array_ref(mask, idx_vars, al); + ASR::expr_t* elemental_operation_val = (builder.*elemental_operation)(return_var, array_ref, loc, nullptr); + ASR::stmt_t* loop_invariant = builder.Assignment(return_var, elemental_operation_val); + Vec if_mask; + if_mask.reserve(al, 1); + if_mask.push_back(al, loop_invariant); + ASR::stmt_t* if_mask_ = ASRUtils::STMT(ASR::make_If_t(al, loc, + mask_ref, if_mask.p, if_mask.size(), + nullptr, 0)); + doloop_body.push_back(al, if_mask_); + }); +} + +static inline void generate_body_for_array_dim_input( + Allocator& al, const Location& loc, + ASR::expr_t* array, ASR::expr_t* dim, ASR::expr_t* result, + SymbolTable* fn_scope, Vec& fn_body, get_initial_value_func get_initial_value, + elemental_operation_func elemental_operation) { + ASRBuilder builder(al, loc); + Vec idx_vars, target_idx_vars; + Vec doloop_body; + builder.generate_reduction_intrinsic_stmts_for_array_output( + loc, array, dim, fn_scope, fn_body, + idx_vars, target_idx_vars, doloop_body, + [=, &al, &fn_body, &builder] () { + ASR::ttype_t* array_type = ASRUtils::expr_type(array); + ASR::expr_t* initial_val = get_initial_value(al, array_type); + ASR::stmt_t* result_init = builder.Assignment(result, initial_val); + fn_body.push_back(al, result_init); + }, + [=, &al, &idx_vars, &target_idx_vars, &doloop_body, &builder, &result] () { + ASR::expr_t* result_ref = PassUtils::create_array_ref(result, target_idx_vars, al); + ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); + ASR::expr_t* elemental_operation_val = (builder.*elemental_operation)(result_ref, array_ref, loc, nullptr); + ASR::stmt_t* loop_invariant = builder.Assignment(result_ref, elemental_operation_val); + doloop_body.push_back(al, loop_invariant); + }); +} + +static inline void generate_body_for_array_dim_mask_input( + Allocator& al, const Location& loc, + ASR::expr_t* array, ASR::expr_t* dim, + ASR::expr_t* mask, ASR::expr_t* result, + SymbolTable* fn_scope, Vec& fn_body, + get_initial_value_func get_initial_value, elemental_operation_func elemental_operation) { + ASRBuilder builder(al, loc); + Vec idx_vars, target_idx_vars; + Vec doloop_body; + builder.generate_reduction_intrinsic_stmts_for_array_output( + loc, array, dim, fn_scope, fn_body, + idx_vars, target_idx_vars, doloop_body, + [=, &al, &fn_body, &builder] () { + ASR::ttype_t* array_type = ASRUtils::expr_type(array); + ASR::expr_t* initial_val = get_initial_value(al, array_type); + ASR::stmt_t* result_init = builder.Assignment(result, initial_val); + fn_body.push_back(al, result_init); + }, + [=, &al, &idx_vars, &target_idx_vars, &doloop_body, &builder, &result] () { + ASR::expr_t* result_ref = PassUtils::create_array_ref(result, target_idx_vars, al); + ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); + ASR::expr_t* mask_ref = PassUtils::create_array_ref(mask, idx_vars, al); + ASR::expr_t* elemental_operation_val = (builder.*elemental_operation)(result_ref, array_ref, loc, nullptr); + ASR::stmt_t* loop_invariant = builder.Assignment(result_ref, elemental_operation_val); + Vec if_mask; + if_mask.reserve(al, 1); + if_mask.push_back(al, loop_invariant); + ASR::stmt_t* if_mask_ = ASRUtils::STMT(ASR::make_If_t(al, loc, + mask_ref, if_mask.p, if_mask.size(), + nullptr, 0)); + doloop_body.push_back(al, if_mask_); + } + ); +} + +static inline ASR::expr_t* instantiate_ArrIntrinsic(Allocator &al, + const Location &loc, SymbolTable *scope, Vec& arg_types, + ASR::ttype_t *return_type, Vec& new_args, + int64_t overload_id, ASRUtils::IntrinsicArrayFunctions intrinsic_func_id, + get_initial_value_func get_initial_value, + elemental_operation_func elemental_operation) { + std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); + ASRBuilder builder(al, loc); + ASRBuilder& b = builder; + int64_t id_array = 0, id_array_dim = 1, id_array_mask = 2; + int64_t id_array_dim_mask = 3; + + ASR::ttype_t* arg_type = ASRUtils::type_get_past_allocatable( + ASRUtils::type_get_past_pointer(arg_types[0])); + int kind = ASRUtils::extract_kind_from_ttype_t(arg_type); + int rank = ASRUtils::extract_n_dims_from_ttype(arg_type); + std::string new_name = intrinsic_func_name + "_" + std::to_string(kind) + + "_" + std::to_string(rank) + + "_" + std::to_string(overload_id); + // Check if Function is already defined. + { + std::string new_func_name = new_name; + int i = 1; + while (scope->get_symbol(new_func_name) != nullptr) { + ASR::symbol_t *s = scope->get_symbol(new_func_name); + ASR::Function_t *f = ASR::down_cast(s); + int orig_array_rank = ASRUtils::extract_n_dims_from_ttype( + ASRUtils::expr_type(f->m_args[0])); + if (ASRUtils::types_equal(ASRUtils::expr_type(f->m_args[0]), + arg_type) && orig_array_rank == rank) { + return builder.Call(s, new_args, return_type, nullptr); + } else { + new_func_name += std::to_string(i); + i++; + } + } + } + + new_name = scope->get_unique_name(new_name, false); + SymbolTable *fn_symtab = al.make_new(scope); + + Vec args; + args.reserve(al, 1); + + ASR::ttype_t* array_type = ASRUtils::duplicate_type_with_empty_dims(al, arg_type); + fill_func_arg("array", array_type) + if( overload_id == id_array_dim || + overload_id == id_array_dim_mask ) { + ASR::ttype_t* dim_type = ASRUtils::TYPE(ASR::make_Integer_t( + al, arg_type->base.loc, 4)); + fill_func_arg("dim", dim_type) + } + if( overload_id == id_array_mask || + overload_id == id_array_dim_mask ) { + Vec mask_dims; + mask_dims.reserve(al, rank); + for( int i = 0; i < rank; i++ ) { + ASR::dimension_t mask_dim; + mask_dim.loc = arg_type->base.loc; + mask_dim.m_start = nullptr; + mask_dim.m_length = nullptr; + mask_dims.push_back(al, mask_dim); + } + ASR::ttype_t* mask_type = ASRUtils::TYPE(ASR::make_Logical_t( + al, arg_type->base.loc, 4)); + if( mask_dims.size() > 0 ) { + mask_type = ASRUtils::make_Array_t_util( + al, arg_type->base.loc, mask_type, + mask_dims.p, mask_dims.size()); + } + fill_func_arg("mask", mask_type) + } + + int result_dims = extract_n_dims_from_ttype(return_type); + ASR::expr_t* return_var = nullptr; + if( result_dims > 0 ) { + fill_func_arg("result", return_type) + } else if( result_dims == 0 ) { + return_var = declare("result", return_type, ReturnVar); + } + + Vec body; + body.reserve(al, 1); + ASR::expr_t* output_var = nullptr; + if( return_var ) { + output_var = return_var; + } else { + output_var = args[(int) args.size() - 1]; + } + if( overload_id == id_array ) { + generate_body_for_array_input(al, loc, args[0], output_var, + fn_symtab, body, get_initial_value, elemental_operation); + } else if( overload_id == id_array_dim ) { + generate_body_for_array_dim_input(al, loc, args[0], args[1], output_var, + fn_symtab, body, get_initial_value, elemental_operation); + } else if( overload_id == id_array_dim_mask ) { + generate_body_for_array_dim_mask_input(al, loc, args[0], args[1], args[2], + output_var, fn_symtab, body, get_initial_value, elemental_operation); + } else if( overload_id == id_array_mask ) { + generate_body_for_array_mask_input(al, loc, args[0], args[1], output_var, + fn_symtab, body, get_initial_value, elemental_operation); + } + + Vec dep; + dep.reserve(al, 1); + // TODO: fill dependencies + + ASR::symbol_t *new_symbol = nullptr; + if( return_var ) { + new_symbol = make_Function_t(new_name, fn_symtab, dep, args, + body, return_var, Source, Implementation, nullptr); + } else { + new_symbol = make_Function_Without_ReturnVar_t( + new_name, fn_symtab, dep, args, + body, Source, Implementation, nullptr); + } + scope->add_symbol(new_name, new_symbol); + return builder.Call(new_symbol, new_args, return_type, nullptr); +} + +static inline void verify_MaxMinLoc_args(const ASR::IntrinsicArrayFunction_t& x, + diag::Diagnostics& diagnostics) { + std::string intrinsic_name = get_intrinsic_name( + static_cast(x.m_arr_intrinsic_id)); + require_impl(x.n_args >= 1, "`"+ intrinsic_name +"` intrinsic " + "must accept at least one argument", x.base.base.loc, diagnostics); + require_impl(x.m_args[0], "`array` argument of `"+ intrinsic_name + + "` intrinsic cannot be nullptr", x.base.base.loc, diagnostics); + require_impl(x.m_args[1], "`dim` argument of `" + intrinsic_name + + "` intrinsic cannot be nullptr", x.base.base.loc, diagnostics); +} + +static inline ASR::expr_t *eval_MaxMinLoc(Allocator &al, const Location &loc, + ASR::ttype_t *type, Vec &args, int intrinsic_id) { + ASRBuilder b(al, loc); + if (all_args_evaluated(args) && + extract_n_dims_from_ttype(expr_type(args[0])) == 1) { + // Only supported for arrays with rank 1 + ASR::ArrayConstant_t *arr = ASR::down_cast(args[0]); + std::vector m_eles; + for (size_t i = 0; i < arr->n_args; i++) { + double ele = 0; + if(extract_value(arr->m_args[i], ele)) { + m_eles.push_back(ele); + } + } + int index = 0; + if (static_cast(IntrinsicArrayFunctions::MaxLoc) == intrinsic_id) { + index = std::distance(m_eles.begin(), + std::max_element(m_eles.begin(), m_eles.end())) + 1; + } else { + index = std::distance(m_eles.begin(), + std::min_element(m_eles.begin(), m_eles.end())) + 1; + } + if (!is_array(type)) { + return i(index, type); + } else { + return b.ArrayConstant({i32(index)}, extract_type(type), false); + } + } else { + return nullptr; + } +} + +static inline ASR::asr_t* create_MaxMinLoc(Allocator& al, const Location& loc, + Vec& args, int intrinsic_id, + const std::function err) { + std::string intrinsic_name = get_intrinsic_name(static_cast(intrinsic_id)); + ASR::ttype_t *array_type = expr_type(args[0]); + if ( !is_array(array_type) ) { + err("`array` argument of `"+ intrinsic_name +"` must be an array", loc); + } else if ( !is_integer(*array_type) && !is_real(*array_type) ) { + err("`array` argument of `"+ intrinsic_name +"` must be integer or " + "real for now", loc); + } else if ( args[2] || args[4] ) { + err("`mask` and `back` keyword argument is not supported yet", loc); + } + ASR::ttype_t *return_type = nullptr; + Vec m_args; m_args.reserve(al, 1); + m_args.push_back(al, args[0]); + Vec result_dims; result_dims.reserve(al, 1); + ASR::dimension_t *m_dims; + int n_dims = extract_dimensions_from_ttype(array_type, m_dims); + int dim = 0, kind = 4; // default kind + if (args[3]) { + if (!extract_value(expr_value(args[3]), kind)) { + err("Runtime value for `kind` argument is not supported yet", loc); + } + } + if ( args[1] ) { + if ( !ASR::is_a(*expr_type(args[1])) ) { + err("`dim` should be a scalar integer type", loc); + } else if (!extract_value(expr_value(args[1]), dim)) { + err("Runtime values for `dim` argument is not supported yet", loc); + } + if ( 1 > dim || dim > n_dims ) { + err("`dim` argument of `"+ intrinsic_name +"` is out of " + "array index range", loc); + } + if ( n_dims == 1 ) { + return_type = TYPE(ASR::make_Integer_t(al, loc, kind)); // 1D + } else { + for ( int i = 1; i <= n_dims; i++ ) { + if ( i == dim ) { + continue; + } + ASR::dimension_t tmp_dim; + tmp_dim.loc = args[0]->base.loc; + tmp_dim.m_start = m_dims[i - 1].m_start; + tmp_dim.m_length = m_dims[i - 1].m_length; + result_dims.push_back(al, tmp_dim); + } + } + m_args.push_back(al, args[1]); + } else { + ASR::dimension_t tmp_dim; + tmp_dim.loc = args[0]->base.loc; + tmp_dim.m_start = i32(1); + tmp_dim.m_length = i32(n_dims); + result_dims.push_back(al, tmp_dim); + } + if ( !return_type ) { + return_type = duplicate_type(al, TYPE( + ASR::make_Integer_t(al, loc, kind)), &result_dims); + } + ASR::expr_t *m_value = eval_MaxMinLoc(al, loc, return_type, m_args, + intrinsic_id); + return make_IntrinsicArrayFunction_t_util(al, loc, + intrinsic_id, m_args.p, m_args.n, 0, return_type, m_value); +} + +static inline ASR::expr_t *instantiate_MaxMinLoc(Allocator &al, + const Location &loc, SymbolTable *scope, int intrinsic_id, + Vec& arg_types, ASR::ttype_t *return_type, + Vec& m_args, int64_t /*overload_id*/) { + std::string intrinsic_name = get_intrinsic_name(static_cast(intrinsic_id)); + declare_basic_variables("_lcompilers_" + intrinsic_name) + /* + * max_index = 1; min_index + * do i = 1, size(arr)) + * do ... + * if (arr[i] > arr[max_index]) then + * max_index = i; + * end if + * ------------------------------------ + * if (arr[i] < arr[max_index]) then + * min_index = i; + * end if + * end ... + * end do + */ + fill_func_arg("array", arg_types[0]); + int n_dims = extract_n_dims_from_ttype(arg_types[0]); + ASR::ttype_t *type = extract_type(return_type); + if (m_args.n > 1) { + // TODO: Use overload_id + fill_func_arg("dim", arg_types[1]); + } + ASR::expr_t *result = declare("result", return_type, ReturnVar); + Vec idx_vars, target_idx_vars; + Vec doloop_body; + if (m_args.n == 1) { + b.generate_reduction_intrinsic_stmts_for_scalar_output( + loc, args[0], fn_symtab, body, idx_vars, doloop_body, + [=, &al, &body, &b] () { + body.push_back(al, b.Assignment(result, i(1, type))); + }, [=, &al, &b, &idx_vars, &doloop_body] () { + std::vector if_body; if_body.reserve(n_dims); + Vec result_idx; result_idx.reserve(al, n_dims); + for (int i = 0; i < n_dims; i++) { + ASR::expr_t *idx = b.ArrayItem_01(result, {i32(i+1)}); + if (extract_kind_from_ttype_t(type) != 4) { + if_body.push_back(b.Assignment(idx, i2i(idx_vars[i], type))); + result_idx.push_back(al, i2i32(idx)); + } else { + if_body.push_back(b.Assignment(idx, idx_vars[i])); + result_idx.push_back(al, idx); + } + } + ASR::expr_t *array_ref_01 = ArrayItem_02(args[0], idx_vars); + ASR::expr_t *array_ref_02 = ArrayItem_02(args[0], result_idx); + if (static_cast(IntrinsicArrayFunctions::MaxLoc) == intrinsic_id) { + doloop_body.push_back(al, b.If(b.Gt(array_ref_01, + array_ref_02), if_body, {})); + } else { + doloop_body.push_back(al, b.If(b.Lt(array_ref_01, + array_ref_02), if_body, {})); + } + }); + } else { + int dim = 0; + extract_value(expr_value(m_args[1].m_value), dim); + b.generate_reduction_intrinsic_stmts_for_array_output( + loc, args[0], args[1], fn_symtab, body, idx_vars, + target_idx_vars, doloop_body, + [=, &al, &body, &b] () { + body.push_back(al, b.Assignment(result, i(1, type))); + }, [=, &al, &b, &idx_vars, &target_idx_vars, &doloop_body] () { + ASR::expr_t *result_ref, *array_ref_02; + if (is_array(return_type)) { + result_ref = ArrayItem_02(result, target_idx_vars); + Vec tmp_idx_vars; + tmp_idx_vars.from_pointer_n_copy(al, idx_vars.p, idx_vars.n); + tmp_idx_vars.p[dim - 1] = i2i32(result_ref); + array_ref_02 = ArrayItem_02(args[0], tmp_idx_vars); + } else { + // 1D scalar output + result_ref = result; + array_ref_02 = b.ArrayItem_01(args[0], {result}); + } + ASR::expr_t *array_ref_01 = ArrayItem_02(args[0], idx_vars); + ASR::expr_t *res_idx = idx_vars.p[dim - 1]; + if (extract_kind_from_ttype_t(type) != 4) { + res_idx = i2i(res_idx, type); + } + if (static_cast(IntrinsicArrayFunctions::MaxLoc) == intrinsic_id) { + doloop_body.push_back(al, b.If(b.Gt(array_ref_01, array_ref_02), { + b.Assignment(result_ref, res_idx) + }, {})); + } else { + doloop_body.push_back(al, b.If(b.Lt(array_ref_01, array_ref_02), { + b.Assignment(result_ref, res_idx) + }, {})); + } + }); + } + body.push_back(al, Return()); + ASR::symbol_t *fn_sym = make_Function_t(fn_name, fn_symtab, dep, args, + body, result, Source, Implementation, nullptr); + scope->add_symbol(fn_name, fn_sym); + return b.Call(fn_sym, m_args, return_type, nullptr); +} + +} // namespace ArrIntrinsic + +namespace Shape { + static inline void verify_args(const ASR::IntrinsicArrayFunction_t &x, + diag::Diagnostics &diagnostics) { + ASRUtils::require_impl(x.n_args == 1 || x.n_args == 2, + "`shape` intrinsic accepts either 1 or 2 arguments", + x.base.base.loc, diagnostics); + ASRUtils::require_impl(x.m_args[0], "`source` argument of `shape` " + "cannot be nullptr", x.base.base.loc, diagnostics); + ASRUtils::require_impl(x.m_args[1], "`kind` argument of `shape` " + "cannot be nullptr", x.base.base.loc, diagnostics); + } + + static ASR::expr_t *eval_Shape(Allocator &al, const Location &loc, + ASR::ttype_t *type, Vec &args) { + ASR::dimension_t *m_dims; + size_t n_dims = extract_dimensions_from_ttype(expr_type(args[0]), m_dims); + Vec m_shapes; m_shapes.reserve(al, n_dims); + for (size_t i = 0; i < n_dims; i++) { + if (m_dims[i].m_length) { + ASR::expr_t *e = nullptr; + if (extract_kind_from_ttype_t(type) != 4) { + e = i2i(m_dims[i].m_length, extract_type(type)); + } else { + e = m_dims[i].m_length; + } + m_shapes.push_back(al, e); + } + } + ASR::expr_t *value = nullptr; + if (m_shapes.n > 0) { + value = EXPR(ASR::make_ArrayConstant_t(al, loc, m_shapes.p, m_shapes.n, + type, ASR::arraystorageType::ColMajor)); + } + return value; + } + + static inline ASR::asr_t* create_Shape(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + ASRBuilder b(al, loc); + Vecm_args; m_args.reserve(al, 1); + m_args.push_back(al, args[0]); + int kind = 4; // default kind + if (args[1]) { + if (!ASR::is_a(*expr_type(args[1]))) { + err("`kind` argument of `shape` must be a scalar integer", loc); + } + if (!extract_value(args[1], kind)) { + err("Only constant value for `kind` is supported for now", loc); + } + } + // TODO: throw error for assumed size array + int n_dims = extract_n_dims_from_ttype(expr_type(args[0])); + ASR::ttype_t *return_type = b.Array({n_dims}, + TYPE(ASR::make_Integer_t(al, loc, kind))); + ASR::expr_t *m_value = eval_Shape(al, loc, return_type, args); + + return ASRUtils::make_IntrinsicArrayFunction_t_util(al, loc, + static_cast(ASRUtils::IntrinsicArrayFunctions::Shape), + m_args.p, m_args.n, 0, return_type, m_value); + } + + static inline ASR::expr_t* instantiate_Shape(Allocator &al, + const Location &loc, SymbolTable *scope, Vec& arg_types, + ASR::ttype_t *return_type, Vec& new_args, + int64_t, ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } + declare_basic_variables("_lcompilers_shape"); + fill_func_arg("source", arg_types[0]); + auto result = declare(fn_name, return_type, ReturnVar); + int iter = extract_n_dims_from_ttype(arg_types[0]) + 1; + auto i = declare("i", int32, Local); + body.push_back(al, b.Assignment(i, i32(1))); + body.push_back(al, b.While(iLt(i, i32(iter)), { + b.Assignment(b.ArrayItem_01(result, {i}), + ArraySize_2(args[0], i, extract_type(return_type))), + b.Assignment(i, iAdd(i, i32(1))) + })); + body.push_back(al, Return()); + + ASR::symbol_t *f_sym = make_Function_t(fn_name, fn_symtab, dep, args, + body, result, Source, Implementation, nullptr); + scope->add_symbol(fn_name, f_sym); + return b.Call(f_sym, new_args, return_type, nullptr); + } + +} // namespace Shape + +namespace Any { + + static inline void verify_array(ASR::expr_t* array, ASR::ttype_t* return_type, + const Location& loc, diag::Diagnostics& diagnostics) { + ASR::ttype_t* array_type = ASRUtils::expr_type(array); + ASRUtils::require_impl(ASRUtils::is_logical(*array_type), + "Input to Any intrinsic must be of logical type, found: " + ASRUtils::get_type_code(array_type), + loc, diagnostics); + int array_n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); + ASRUtils::require_impl(array_n_dims > 0, "Input to Any intrinsic must always be an array", + loc, diagnostics); + ASRUtils::require_impl(ASRUtils::is_logical(*return_type), + "Any intrinsic must return a logical output", loc, diagnostics); + int return_n_dims = ASRUtils::extract_n_dims_from_ttype(return_type); + ASRUtils::require_impl(return_n_dims == 0, + "Any intrinsic output for array only input should be a scalar", + loc, diagnostics); + } + + static inline void verify_array_dim(ASR::expr_t* array, ASR::expr_t* dim, + ASR::ttype_t* return_type, const Location& loc, diag::Diagnostics& diagnostics) { + ASR::ttype_t* array_type = ASRUtils::expr_type(array); + ASRUtils::require_impl(ASRUtils::is_logical(*ASRUtils::type_get_past_pointer(array_type)), + "Input to Any intrinsic must be of logical type, found: " + ASRUtils::get_type_code(array_type), + loc, diagnostics); + int array_n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); + ASRUtils::require_impl(array_n_dims > 0, "Input to Any intrinsic must always be an array", + loc, diagnostics); + + ASRUtils::require_impl(ASR::is_a(*ASRUtils::type_get_past_pointer(ASRUtils::expr_type(dim))), + "dim argument must be an integer", loc, diagnostics); + + ASRUtils::require_impl(ASRUtils::is_logical(*return_type), + "Any intrinsic must return a logical output", loc, diagnostics); + int return_n_dims = ASRUtils::extract_n_dims_from_ttype(return_type); + ASRUtils::require_impl(array_n_dims == return_n_dims + 1, + "Any intrinsic output must return a logical array with dimension " + "only 1 less than that of input array", + loc, diagnostics); + } + + static inline void verify_args(const ASR::IntrinsicArrayFunction_t& x, diag::Diagnostics& diagnostics) { + ASRUtils::require_impl(x.n_args >= 1, "Any intrinsic must accept at least one argument", + x.base.base.loc, diagnostics); + ASRUtils::require_impl(x.m_args[0] != nullptr, "Array argument to any intrinsic cannot be nullptr", + x.base.base.loc, diagnostics); + switch( x.m_overload_id ) { + case 0: { + verify_array(x.m_args[0], x.m_type, x.base.base.loc, diagnostics); + break; + } + case 1: { + ASRUtils::require_impl(x.n_args == 2 && x.m_args[1] != nullptr, + "dim argument to any intrinsic cannot be nullptr", + x.base.base.loc, diagnostics); + verify_array_dim(x.m_args[0], x.m_args[1], x.m_type, x.base.base.loc, diagnostics); + break; + } + default: { + require_impl(false, "Unrecognised overload id in Any intrinsic", + x.base.base.loc, diagnostics); + } + } + } + + static inline ASR::expr_t *eval_Any(Allocator & /*al*/, + const Location & /*loc*/, ASR::ttype_t */*t*/, Vec& /*args*/) { + return nullptr; + } + + static inline ASR::asr_t* create_Any( + Allocator& al, const Location& loc, Vec& args, + const std::function err) { + int64_t overload_id = 0; + Vec any_args; + any_args.reserve(al, 2); + + ASR::expr_t* array = args[0]; + ASR::expr_t* axis = nullptr; + if( args.size() == 2 ) { + axis = args[1]; + } + if( ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(array)) == 0 ) { + err("mask argument to any must be an array and must not be a scalar", + array->base.loc); + } + + // TODO: Add a check for range of values axis can take + // if axis is available at compile time + + ASR::expr_t *value = nullptr; + Vec arg_values; + arg_values.reserve(al, 2); + ASR::expr_t *array_value = ASRUtils::expr_value(array); + arg_values.push_back(al, array_value); + if( axis ) { + ASR::expr_t *axis_value = ASRUtils::expr_value(axis); + arg_values.push_back(al, axis_value); + } + + ASR::ttype_t* logical_return_type = nullptr; + if( axis == nullptr ) { + overload_id = 0; + logical_return_type = ASRUtils::TYPE(ASR::make_Logical_t( + al, loc, 4)); + } else { + overload_id = 1; + Vec dims; + size_t n_dims = ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(array)); + dims.reserve(al, (int) n_dims - 1); + for( int i = 0; i < (int) n_dims - 1; i++ ) { + ASR::dimension_t dim; + dim.loc = array->base.loc; + dim.m_length = nullptr; + dim.m_start = nullptr; + dims.push_back(al, dim); + } + if( dims.size() > 0 ) { + logical_return_type = ASRUtils::make_Array_t_util(al, loc, + ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4)), dims.p, dims.size()); + } else { + logical_return_type = ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4)); + } + } + value = eval_Any(al, loc, logical_return_type, arg_values); + + any_args.push_back(al, array); + if( axis ) { + any_args.push_back(al, axis); + } + + return ASRUtils::make_IntrinsicArrayFunction_t_util(al, loc, + static_cast(ASRUtils::IntrinsicArrayFunctions::Any), + any_args.p, any_args.n, overload_id, logical_return_type, value); + } + + static inline void generate_body_for_scalar_output(Allocator& al, const Location& loc, + ASR::expr_t* array, ASR::expr_t* return_var, SymbolTable* fn_scope, + Vec& fn_body) { + ASRBuilder builder(al, loc); + Vec idx_vars; + Vec doloop_body; + builder.generate_reduction_intrinsic_stmts_for_scalar_output(loc, + array, fn_scope, fn_body, idx_vars, doloop_body, + [=, &al, &fn_body, &builder] () { + ASR::expr_t* logical_false = make_ConstantWithKind( + make_LogicalConstant_t, make_Logical_t, false, 4, loc); + ASR::stmt_t* return_var_init = builder.Assignment(return_var, logical_false); + fn_body.push_back(al, return_var_init); + }, + [=, &al, &idx_vars, &doloop_body, &builder] () { + ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); + ASR::expr_t* logical_or = builder.Or(return_var, array_ref, loc); + ASR::stmt_t* loop_invariant = builder.Assignment(return_var, logical_or); + doloop_body.push_back(al, loop_invariant); + } + ); + } + + static inline void generate_body_for_array_output(Allocator& al, const Location& loc, + ASR::expr_t* array, ASR::expr_t* dim, ASR::expr_t* result, + SymbolTable* fn_scope, Vec& fn_body) { + ASRBuilder builder(al, loc); + Vec idx_vars, target_idx_vars; + Vec doloop_body; + builder.generate_reduction_intrinsic_stmts_for_array_output( + loc, array, dim, fn_scope, fn_body, + idx_vars, target_idx_vars, doloop_body, + [=, &al, &fn_body, &builder] { + ASR::expr_t* logical_false = make_ConstantWithKind( + make_LogicalConstant_t, make_Logical_t, false, 4, loc); + ASR::stmt_t* result_init = builder.Assignment(result, logical_false); + fn_body.push_back(al, result_init); + }, + [=, &al, &idx_vars, &target_idx_vars, &doloop_body, &result, &builder] () { + ASR::expr_t* result_ref = PassUtils::create_array_ref(result, target_idx_vars, al); + ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); + ASR::expr_t* logical_or = builder.ElementalOr(result_ref, array_ref, loc); + ASR::stmt_t* loop_invariant = builder.Assignment(result_ref, logical_or); + doloop_body.push_back(al, loop_invariant); + }); + } + + static inline ASR::expr_t* instantiate_Any(Allocator &al, const Location &loc, + SymbolTable *scope, Vec& arg_types, ASR::ttype_t *logical_return_type, + Vec& new_args, int64_t overload_id, + ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } + ASRBuilder builder(al, loc); + ASRBuilder& b = builder; + ASR::ttype_t* arg_type = arg_types[0]; + int kind = ASRUtils::extract_kind_from_ttype_t(arg_type); + int rank = ASRUtils::extract_n_dims_from_ttype(arg_type); + std::string new_name = "any_" + std::to_string(kind) + + "_" + std::to_string(rank) + + "_" + std::to_string(overload_id); + // Check if Function is already defined. + { + std::string new_func_name = new_name; + int i = 1; + while (scope->get_symbol(new_func_name) != nullptr) { + ASR::symbol_t *s = scope->get_symbol(new_func_name); + ASR::Function_t *f = ASR::down_cast(s); + int orig_array_rank = ASRUtils::extract_n_dims_from_ttype( + ASRUtils::expr_type(f->m_args[0])); + if (ASRUtils::types_equal(ASRUtils::expr_type(f->m_args[0]), + arg_type) && orig_array_rank == rank) { + return builder.Call(s, new_args, logical_return_type, nullptr); + } else { + new_func_name += std::to_string(i); + i++; + } + } + } + + new_name = scope->get_unique_name(new_name, false); + SymbolTable *fn_symtab = al.make_new(scope); + + Vec args; + int result_dims = 0; + { + args.reserve(al, 1); + ASR::ttype_t* mask_type = ASRUtils::duplicate_type_with_empty_dims(al, arg_type); + fill_func_arg("mask", mask_type); + if( overload_id == 1 ) { + ASR::ttype_t* dim_type = ASRUtils::expr_type(new_args[1].m_value); + LCOMPILERS_ASSERT(ASR::is_a(*dim_type)); + [[maybe_unused]] int kind = ASRUtils::extract_kind_from_ttype_t(dim_type); + LCOMPILERS_ASSERT(kind == 4); + fill_func_arg("dim", dim_type); + + Vec dims; + size_t n_dims = ASRUtils::extract_n_dims_from_ttype(arg_type); + dims.reserve(al, (int) n_dims - 1); + for( int i = 0; i < (int) n_dims - 1; i++ ) { + ASR::dimension_t dim; + dim.loc = new_args[0].m_value->base.loc; + dim.m_length = nullptr; + dim.m_start = nullptr; + dims.push_back(al, dim); + } + result_dims = dims.size(); + if( result_dims > 0 ) { + fill_func_arg("result", logical_return_type); + } + } + } + + ASR::expr_t* return_var = nullptr; + if( result_dims == 0 ) { + return_var = declare(new_name, logical_return_type, ReturnVar); + } + + Vec body; + body.reserve(al, 1); + if( overload_id == 0 || return_var ) { + generate_body_for_scalar_output(al, loc, args[0], return_var, fn_symtab, body); + } else if( overload_id == 1 ) { + generate_body_for_array_output(al, loc, args[0], args[1], args[2], fn_symtab, body); + } else { + LCOMPILERS_ASSERT(false); + } + + Vec dep; + dep.reserve(al, 1); + // TODO: fill dependencies + + ASR::symbol_t *new_symbol = nullptr; + if( return_var ) { + new_symbol = make_Function_t(new_name, fn_symtab, dep, args, + body, return_var, Source, Implementation, nullptr); + } else { + new_symbol = make_Function_Without_ReturnVar_t( + new_name, fn_symtab, dep, args, + body, Source, Implementation, nullptr); + } + scope->add_symbol(new_name, new_symbol); + return builder.Call(new_symbol, new_args, logical_return_type, nullptr); + } + +} // namespace Any + +namespace Sum { + + static inline void verify_args(const ASR::IntrinsicArrayFunction_t& x, + diag::Diagnostics& diagnostics) { + ArrIntrinsic::verify_args(x, diagnostics, IntrinsicArrayFunctions::Sum, + &ArrIntrinsic::verify_array_int_real_cmplx); + } + + static inline ASR::expr_t *eval_Sum(Allocator & /*al*/, + const Location & /*loc*/, ASR::ttype_t *, Vec& /*args*/) { + return nullptr; + } + + static inline ASR::asr_t* create_Sum(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + return ArrIntrinsic::create_ArrIntrinsic(al, loc, args, err, + IntrinsicArrayFunctions::Sum); + } + + static inline ASR::expr_t* instantiate_Sum(Allocator &al, + const Location &loc, SymbolTable *scope, Vec& arg_types, + ASR::ttype_t *return_type, Vec& new_args, + int64_t overload_id, ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } + return ArrIntrinsic::instantiate_ArrIntrinsic(al, loc, scope, arg_types, + return_type, new_args, overload_id, IntrinsicArrayFunctions::Sum, + &get_constant_zero_with_given_type, &ASRBuilder::ElementalAdd); + } + +} // namespace Sum + +namespace Product { + + static inline void verify_args(const ASR::IntrinsicArrayFunction_t& x, + diag::Diagnostics& diagnostics) { + ArrIntrinsic::verify_args(x, diagnostics, IntrinsicArrayFunctions::Product, + &ArrIntrinsic::verify_array_int_real_cmplx); + } + + static inline ASR::expr_t *eval_Product(Allocator & /*al*/, + const Location & /*loc*/, ASR::ttype_t *, Vec& /*args*/) { + return nullptr; + } + + static inline ASR::asr_t* create_Product(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + return ArrIntrinsic::create_ArrIntrinsic(al, loc, args, err, + IntrinsicArrayFunctions::Product); + } + + static inline ASR::expr_t* instantiate_Product(Allocator &al, + const Location &loc, SymbolTable *scope, Vec& arg_types, + ASR::ttype_t *return_type, Vec& new_args, + int64_t overload_id, ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } + return ArrIntrinsic::instantiate_ArrIntrinsic(al, loc, scope, arg_types, + return_type, new_args, overload_id, IntrinsicArrayFunctions::Product, + &get_constant_one_with_given_type, &ASRBuilder::ElementalMul); + } + +} // namespace Product + +namespace MaxVal { + + static inline void verify_args(const ASR::IntrinsicArrayFunction_t& x, + diag::Diagnostics& diagnostics) { + ArrIntrinsic::verify_args(x, diagnostics, IntrinsicArrayFunctions::MaxVal, + &ArrIntrinsic::verify_array_int_real); + } + + static inline ASR::expr_t *eval_MaxVal(Allocator & /*al*/, + const Location & /*loc*/, ASR::ttype_t *, Vec& /*args*/) { + return nullptr; + } + + static inline ASR::asr_t* create_MaxVal(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + return ArrIntrinsic::create_ArrIntrinsic(al, loc, args, err, + IntrinsicArrayFunctions::MaxVal); + } + + static inline ASR::expr_t* instantiate_MaxVal(Allocator &al, + const Location &loc, SymbolTable *scope, Vec& arg_types, + ASR::ttype_t *return_type, Vec& new_args, + int64_t overload_id, ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } + return ArrIntrinsic::instantiate_ArrIntrinsic(al, loc, scope, arg_types, + return_type, new_args, overload_id, IntrinsicArrayFunctions::MaxVal, + &get_minimum_value_with_given_type, &ASRBuilder::ElementalMax); + } + +} // namespace MaxVal + +namespace MaxLoc { + + static inline void verify_args(const ASR::IntrinsicArrayFunction_t& x, + diag::Diagnostics& diagnostics) { + ArrIntrinsic::verify_MaxMinLoc_args(x, diagnostics); + } + + static inline ASR::asr_t* create_MaxLoc(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + return ArrIntrinsic::create_MaxMinLoc(al, loc, args, + static_cast(IntrinsicArrayFunctions::MaxLoc), err); + } + + static inline ASR::expr_t *instantiate_MaxLoc(Allocator &al, + const Location &loc, SymbolTable *scope, + Vec& arg_types, ASR::ttype_t *return_type, + Vec& m_args, int64_t overload_id, + ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } + return ArrIntrinsic::instantiate_MaxMinLoc(al, loc, scope, + static_cast(IntrinsicArrayFunctions::MaxLoc), arg_types, return_type, + m_args, overload_id); + } + +} // namespace MaxLoc + +namespace Merge { + + static inline void verify_args(const ASR::IntrinsicArrayFunction_t& x, + diag::Diagnostics& diagnostics) { + const Location& loc = x.base.base.loc; + ASR::expr_t *tsource = x.m_args[0], *fsource = x.m_args[1], *mask = x.m_args[2]; + ASR::ttype_t *tsource_type = ASRUtils::expr_type(tsource); + ASR::ttype_t *fsource_type = ASRUtils::expr_type(fsource); + ASR::ttype_t *mask_type = ASRUtils::expr_type(mask); + int tsource_ndims, fsource_ndims; + ASR::dimension_t *tsource_mdims = nullptr, *fsource_mdims = nullptr; + tsource_ndims = ASRUtils::extract_dimensions_from_ttype(tsource_type, tsource_mdims); + fsource_ndims = ASRUtils::extract_dimensions_from_ttype(fsource_type, fsource_mdims); + if( tsource_ndims > 0 && fsource_ndims > 0 ) { + ASRUtils::require_impl(tsource_ndims == fsource_ndims, + "All arguments of `merge` should be of same rank and dimensions", loc, diagnostics); + + if( ASRUtils::extract_physical_type(tsource_type) == ASR::array_physical_typeType::FixedSizeArray && + ASRUtils::extract_physical_type(fsource_type) == ASR::array_physical_typeType::FixedSizeArray ) { + ASRUtils::require_impl(ASRUtils::get_fixed_size_of_array(tsource_mdims, tsource_ndims) == + ASRUtils::get_fixed_size_of_array(fsource_mdims, fsource_ndims), + "`tsource` and `fsource` arguments should have matching size", loc, diagnostics); + } + } + + ASRUtils::require_impl(ASRUtils::check_equal_type(tsource_type, fsource_type), + "`tsource` and `fsource` arguments to `merge` should be of same type, found " + + ASRUtils::get_type_code(tsource_type) + ", " + + ASRUtils::get_type_code(fsource_type), loc, diagnostics); + ASRUtils::require_impl(ASRUtils::is_logical(*mask_type), + "`mask` argument to `merge` should be of logical type, found " + + ASRUtils::get_type_code(mask_type), loc, diagnostics); + } + + static inline ASR::expr_t* eval_Merge( + Allocator &/*al*/, const Location &/*loc*/, ASR::ttype_t *, + Vec& args) { + LCOMPILERS_ASSERT(args.size() == 3); + ASR::expr_t *tsource = args[0], *fsource = args[1], *mask = args[2]; + if( ASRUtils::is_array(ASRUtils::expr_type(mask)) ) { + return nullptr; + } + + bool mask_value = false; + if( ASRUtils::is_value_constant(mask, mask_value) ) { + if( mask_value ) { + return tsource; + } else { + return fsource; + } + } + return nullptr; + } + + static inline ASR::asr_t* create_Merge(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + if( args.size() != 3 ) { + err("`merge` intrinsic accepts 3 positional arguments, found " + + std::to_string(args.size()), loc); + } + + ASR::expr_t *tsource = args[0], *fsource = args[1], *mask = args[2]; + ASR::ttype_t *tsource_type = ASRUtils::expr_type(tsource); + ASR::ttype_t *fsource_type = ASRUtils::expr_type(fsource); + ASR::ttype_t *mask_type = ASRUtils::expr_type(mask); + ASR::ttype_t* result_type = tsource_type; + int tsource_ndims, fsource_ndims, mask_ndims; + ASR::dimension_t *tsource_mdims = nullptr, *fsource_mdims = nullptr, *mask_mdims = nullptr; + tsource_ndims = ASRUtils::extract_dimensions_from_ttype(tsource_type, tsource_mdims); + fsource_ndims = ASRUtils::extract_dimensions_from_ttype(fsource_type, fsource_mdims); + mask_ndims = ASRUtils::extract_dimensions_from_ttype(mask_type, mask_mdims); + if( tsource_ndims > 0 && fsource_ndims > 0 ) { + if( tsource_ndims != fsource_ndims ) { + err("All arguments of `merge` should be of same rank and dimensions", loc); + } + + if( ASRUtils::extract_physical_type(tsource_type) == ASR::array_physical_typeType::FixedSizeArray && + ASRUtils::extract_physical_type(fsource_type) == ASR::array_physical_typeType::FixedSizeArray && + ASRUtils::get_fixed_size_of_array(tsource_mdims, tsource_ndims) != + ASRUtils::get_fixed_size_of_array(fsource_mdims, fsource_ndims) ) { + err("`tsource` and `fsource` arguments should have matching size", loc); + } + } else { + if( tsource_ndims > 0 && fsource_ndims == 0 ) { + result_type = tsource_type; + } else if( tsource_ndims == 0 && fsource_ndims > 0 ) { + result_type = fsource_type; + } else if( tsource_ndims == 0 && fsource_ndims == 0 && mask_ndims > 0 ) { + Vec mask_mdims_vec; + mask_mdims_vec.from_pointer_n(mask_mdims, mask_ndims); + result_type = ASRUtils::duplicate_type(al, tsource_type, &mask_mdims_vec, + ASRUtils::extract_physical_type(mask_type), true); + if( ASR::is_a(*mask_type) ) { + result_type = ASRUtils::TYPE(ASR::make_Allocatable_t(al, loc, result_type)); + } + } + } + if( !ASRUtils::check_equal_type(tsource_type, fsource_type) ) { + err("`tsource` and `fsource` arguments to `merge` should be of same type, found " + + ASRUtils::get_type_code(tsource_type) + ", " + + ASRUtils::get_type_code(fsource_type), loc); + } + if( !ASRUtils::is_logical(*mask_type) ) { + err("`mask` argument to `merge` should be of logical type, found " + + ASRUtils::get_type_code(mask_type), loc); + } + + return ASR::make_IntrinsicArrayFunction_t(al, loc, + static_cast(ASRUtils::IntrinsicArrayFunctions::Merge), + args.p, args.size(), 0, result_type, nullptr); + } + + static inline ASR::expr_t* instantiate_Merge(Allocator &al, + const Location &loc, SymbolTable *scope, + Vec& arg_types, ASR::ttype_t *return_type, + Vec& new_args, int64_t /*overload_id*/, + ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } + LCOMPILERS_ASSERT(arg_types.size() == 3); + + // Array inputs should be elementalised in array_op pass already + LCOMPILERS_ASSERT( !ASRUtils::is_array(arg_types[2]) ); + ASR::ttype_t *tsource_type = ASRUtils::duplicate_type(al, arg_types[0]); + ASR::ttype_t *fsource_type = ASRUtils::duplicate_type(al, arg_types[1]); + ASR::ttype_t *mask_type = ASRUtils::duplicate_type(al, arg_types[2]); + if( ASR::is_a(*tsource_type) ) { + ASR::Character_t* tsource_char = ASR::down_cast(tsource_type); + ASR::Character_t* fsource_char = ASR::down_cast(fsource_type); + tsource_char->m_len_expr = nullptr; fsource_char->m_len_expr = nullptr; + tsource_char->m_len = -2; fsource_char->m_len = -2; + } + std::string new_name = "_lcompilers_merge_" + get_type_code(tsource_type); + + declare_basic_variables(new_name); + if (scope->get_symbol(new_name)) { + ASR::symbol_t *s = scope->get_symbol(new_name); + ASR::Function_t *f = ASR::down_cast(s); + return b.Call(s, new_args, expr_type(f->m_return_var), nullptr); + } + + auto tsource_arg = declare("tsource", tsource_type, In); + args.push_back(al, tsource_arg); + auto fsource_arg = declare("fsource", fsource_type, In); + args.push_back(al, fsource_arg); + auto mask_arg = declare("mask", mask_type, In); + args.push_back(al, mask_arg); + // TODO: In case of Character type, set len of ReturnVar to len(tsource) expression + auto result = declare("merge", tsource_type, ReturnVar); + + { + Vec if_body; if_body.reserve(al, 1); + if_body.push_back(al, b.Assignment(result, tsource_arg)); + Vec else_body; else_body.reserve(al, 1); + else_body.push_back(al, b.Assignment(result, fsource_arg)); + body.push_back(al, STMT(ASR::make_If_t(al, loc, mask_arg, + if_body.p, if_body.n, else_body.p, else_body.n))); + } + + ASR::symbol_t *new_symbol = make_Function_t(fn_name, fn_symtab, dep, args, + body, result, Source, Implementation, nullptr); + scope->add_symbol(fn_name, new_symbol); + return b.Call(new_symbol, new_args, return_type, nullptr); + } + +} // namespace Merge + +namespace MinVal { + + static inline void verify_args(const ASR::IntrinsicArrayFunction_t& x, + diag::Diagnostics& diagnostics) { + ArrIntrinsic::verify_args(x, diagnostics, IntrinsicArrayFunctions::MinVal, + &ArrIntrinsic::verify_array_int_real); + } + + static inline ASR::expr_t *eval_MinVal(Allocator & /*al*/, + const Location & /*loc*/, ASR::ttype_t *, Vec& /*args*/) { + return nullptr; + } + + static inline ASR::asr_t* create_MinVal(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + return ArrIntrinsic::create_ArrIntrinsic(al, loc, args, err, + IntrinsicArrayFunctions::MinVal); + } + + static inline ASR::expr_t* instantiate_MinVal(Allocator &al, + const Location &loc, SymbolTable *scope, Vec& arg_types, + ASR::ttype_t *return_type, Vec& new_args, + int64_t overload_id, ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } + return ArrIntrinsic::instantiate_ArrIntrinsic(al, loc, scope, arg_types, + return_type, new_args, overload_id, IntrinsicArrayFunctions::MinVal, + &get_maximum_value_with_given_type, &ASRBuilder::ElementalMin); + } + +} // namespace MinVal + +namespace MinLoc { + + static inline void verify_args(const ASR::IntrinsicArrayFunction_t& x, + diag::Diagnostics& diagnostics) { + ArrIntrinsic::verify_MaxMinLoc_args(x, diagnostics); + } + + static inline ASR::asr_t* create_MinLoc(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + return ArrIntrinsic::create_MaxMinLoc(al, loc, args, + static_cast(IntrinsicArrayFunctions::MinLoc), err); + } + + static inline ASR::expr_t *instantiate_MinLoc(Allocator &al, + const Location &loc, SymbolTable *scope, + Vec& arg_types, ASR::ttype_t *return_type, + Vec& m_args, int64_t overload_id, + ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } + return ArrIntrinsic::instantiate_MaxMinLoc(al, loc, scope, + static_cast(IntrinsicArrayFunctions::MinLoc), arg_types, return_type, + m_args, overload_id); + } + +} // namespace MinLoc + +namespace IntrinsicArrayFunctionRegistry { + + static const std::map>& intrinsic_function_by_id_db = { + {static_cast(IntrinsicArrayFunctions::Any), + {&Any::instantiate_Any, &Any::verify_args}}, + {static_cast(IntrinsicArrayFunctions::MaxLoc), + {&MaxLoc::instantiate_MaxLoc, &MaxLoc::verify_args}}, + {static_cast(IntrinsicArrayFunctions::MaxVal), + {&MaxVal::instantiate_MaxVal, &MaxVal::verify_args}}, + {static_cast(IntrinsicArrayFunctions::Merge), + {&Merge::instantiate_Merge, &Merge::verify_args}}, + {static_cast(IntrinsicArrayFunctions::MinLoc), + {&MinLoc::instantiate_MinLoc, &MinLoc::verify_args}}, + {static_cast(IntrinsicArrayFunctions::MinVal), + {&MinVal::instantiate_MinVal, &MinVal::verify_args}}, + {static_cast(IntrinsicArrayFunctions::Product), + {&Product::instantiate_Product, &Product::verify_args}}, + {static_cast(IntrinsicArrayFunctions::Shape), + {&Shape::instantiate_Shape, &Shape::verify_args}}, + {static_cast(IntrinsicArrayFunctions::Sum), + {&Sum::instantiate_Sum, &Sum::verify_args}}, + }; + + static const std::map>& function_by_name_db = { + {"any", {&Any::create_Any, &Any::eval_Any}}, + {"maxloc", {&MaxLoc::create_MaxLoc, nullptr}}, + {"maxval", {&MaxVal::create_MaxVal, &MaxVal::eval_MaxVal}}, + {"merge", {&Merge::create_Merge, &Merge::eval_Merge}}, + {"minloc", {&MinLoc::create_MinLoc, nullptr}}, + {"minval", {&MinVal::create_MinVal, &MinVal::eval_MinVal}}, + {"product", {&Product::create_Product, &Product::eval_Product}}, + {"shape", {&Shape::create_Shape, &Shape::eval_Shape}}, + {"sum", {&Sum::create_Sum, &Sum::eval_Sum}}, + }; + + static inline bool is_intrinsic_function(const std::string& name) { + return function_by_name_db.find(name) != function_by_name_db.end(); + } + + static inline create_intrinsic_function get_create_function(const std::string& name) { + return std::get<0>(function_by_name_db.at(name)); + } + + static inline impl_function get_instantiate_function(int64_t id) { + if( intrinsic_function_by_id_db.find(id) == intrinsic_function_by_id_db.end() ) { + return nullptr; + } + return std::get<0>(intrinsic_function_by_id_db.at(id)); + } + + static inline verify_array_function get_verify_function(int64_t id) { + return std::get<1>(intrinsic_function_by_id_db.at(id)); + } + + /* + The function gives the index of the dim a.k.a axis argument + for the intrinsic with the given id. Most of the time + dim is specified via second argument (i.e., index 1) but + still its better to encapsulate it in the following + function and then call it to get the index of the dim + argument whenever needed. This helps in limiting + the API changes of the intrinsic to this function only. + */ + static inline int get_dim_index(IntrinsicArrayFunctions id) { + if( id == IntrinsicArrayFunctions::Any || + id == IntrinsicArrayFunctions::Sum || + id == IntrinsicArrayFunctions::Product || + id == IntrinsicArrayFunctions::MaxVal || + id == IntrinsicArrayFunctions::MinVal) { + return 1; + } else { + LCOMPILERS_ASSERT(false); + } + return -1; + } + + static inline bool handle_dim(IntrinsicArrayFunctions id) { + // Dim argument is already handled for the following + if( id == IntrinsicArrayFunctions::Shape || + id == IntrinsicArrayFunctions::MaxLoc || + id == IntrinsicArrayFunctions::MinLoc ) { + return false; + } else { + return true; + } + } + + static inline bool is_elemental(int64_t id) { + IntrinsicArrayFunctions id_ = static_cast(id); + return (id_ == IntrinsicArrayFunctions::Merge); + } + +} // namespace IntrinsicArrayFunctionRegistry + +} // namespace ASRUtils + +} // namespace LCompilers + +#endif // LFORTRAN_PASS_INTRINSIC_ARRAY_FUNCTIONS_H diff --git a/src/libasr/pass/intrinsic_function.cpp b/src/libasr/pass/intrinsic_function.cpp index bb7c0e076d..3d0e73a061 100644 --- a/src/libasr/pass/intrinsic_function.cpp +++ b/src/libasr/pass/intrinsic_function.cpp @@ -5,6 +5,7 @@ #include #include #include +#include #include #include @@ -30,12 +31,12 @@ class ReplaceIntrinsicFunction: public ASR::BaseExprReplacer& func2intrinsicid; + std::map& func2intrinsicid; public: ReplaceIntrinsicFunction(Allocator& al_, SymbolTable* global_scope_, - std::map& func2intrinsicid_) : + std::map& func2intrinsicid_) : al(al_), global_scope(global_scope_), func2intrinsicid(func2intrinsicid_) {} @@ -72,7 +73,49 @@ class ReplaceIntrinsicFunction: public ASR::BaseExprReplacerm_args[i])); } ASR::expr_t* current_expr_ = instantiate_function(al, x->base.base.loc, - global_scope, arg_types, new_args, x->m_overload_id, x->m_value); + global_scope, arg_types, x->m_type, new_args, x->m_overload_id, x->m_value); + if( ASR::is_a(*(*current_expr)) ) { + ASR::ArrayPhysicalCast_t* array_physical_cast_t = ASR::down_cast(*current_expr); + array_physical_cast_t->m_arg = current_expr_; + } else { + *current_expr = current_expr_; + } + } + + void replace_IntrinsicArrayFunction(ASR::IntrinsicArrayFunction_t* x) { + Vec new_args; + // Replace any IntrinsicArrayFunctions in the argument first: + { + new_args.reserve(al, x->n_args); + for( size_t i = 0; i < x->n_args; i++ ) { + ASR::expr_t** current_expr_copy_ = current_expr; + current_expr = &(x->m_args[i]); + replace_expr(x->m_args[i]); + ASR::call_arg_t arg0; + arg0.loc = (*current_expr)->base.loc; + arg0.m_value = *current_expr; // Use the converted arg + new_args.push_back(al, arg0); + current_expr = current_expr_copy_; + } + } + // TODO: currently we always instantiate a new function. + // Rather we should reuse the old instantiation if it has + // exactly the same arguments. For that we could use the + // overload_id, and uniquely encode the argument types. + // We could maintain a mapping of type -> id and look it up. + + ASRUtils::impl_function instantiate_function = + ASRUtils::IntrinsicArrayFunctionRegistry::get_instantiate_function(x->m_arr_intrinsic_id); + if( instantiate_function == nullptr ) { + return ; + } + Vec arg_types; + arg_types.reserve(al, x->n_args); + for( size_t i = 0; i < x->n_args; i++ ) { + arg_types.push_back(al, ASRUtils::expr_type(x->m_args[i])); + } + ASR::expr_t* current_expr_ = instantiate_function(al, x->base.base.loc, + global_scope, arg_types, x->m_type, new_args, x->m_overload_id, x->m_value); ASR::expr_t* func_call = current_expr_; if( ASR::is_a(*(*current_expr)) ) { ASR::ArrayPhysicalCast_t* array_physical_cast_t = ASR::down_cast(*current_expr); @@ -80,10 +123,11 @@ class ReplaceIntrinsicFunction: public ASR::BaseExprReplacer(*func_call)); - ASR::FunctionCall_t* function_call_t = ASR::down_cast(func_call); - ASR::symbol_t* function_call_t_symbol = ASRUtils::symbol_get_past_external(function_call_t->m_name); - func2intrinsicid[function_call_t_symbol] = (ASRUtils::IntrinsicFunctions) x->m_intrinsic_id; + if (ASR::is_a(*func_call)) { + ASR::symbol_t *call_sym = ASRUtils::symbol_get_past_external( + ASR::down_cast(func_call)->m_name); + func2intrinsicid[call_sym] = (ASRUtils::IntrinsicArrayFunctions) x->m_arr_intrinsic_id; + } } }; @@ -102,7 +146,7 @@ class ReplaceIntrinsicFunctionVisitor : public ASR::CallReplacerOnExpressionsVis public: ReplaceIntrinsicFunctionVisitor(Allocator& al_, SymbolTable* global_scope_, - std::map& func2intrinsicid_) : + std::map& func2intrinsicid_) : replacer(al_, global_scope_, func2intrinsicid_) {} void call_replacer() { @@ -119,14 +163,14 @@ class ReplaceFunctionCallReturningArray: public ASR::BaseExprReplacer& pass_result; size_t result_counter; - std::map& func2intrinsicid; + std::map& func2intrinsicid; public: SymbolTable* current_scope; ReplaceFunctionCallReturningArray(Allocator& al_, Vec& pass_result_, - std::map& func2intrinsicid_) : + std::map& func2intrinsicid_) : al(al_), pass_result(pass_result_), result_counter(0), func2intrinsicid(func2intrinsicid_), current_scope(nullptr) {} @@ -218,8 +262,8 @@ class ReplaceFunctionCallReturningArray: public ASR::BaseExprReplacerm_name); int n_dims = ASRUtils::extract_n_dims_from_ttype(x->m_type); - if( func2intrinsicid.find(x_m_name) == func2intrinsicid.end() || - n_dims == 0 ) { + if( func2intrinsicid.find(x_m_name) == func2intrinsicid.end() || n_dims == 0 || + !ASRUtils::IntrinsicArrayFunctionRegistry::handle_dim(func2intrinsicid[x_m_name])) { return ; } @@ -238,7 +282,8 @@ class ReplaceFunctionCallReturningArray: public ASR::BaseExprReplacerm_args[dim_index].m_value; if( !ASRUtils::is_value_constant(ASRUtils::expr_value(dim)) ) { @@ -282,7 +327,7 @@ class ReplaceFunctionCallReturningArrayVisitor : public ASR::CallReplacerOnExpre public: ReplaceFunctionCallReturningArrayVisitor(Allocator& al_, - std::map& func2intrinsicid_) : + std::map& func2intrinsicid_) : al(al_), replacer(al_, pass_result, func2intrinsicid_), parent_body(nullptr) { pass_result.n = 0; } @@ -331,7 +376,7 @@ class ReplaceFunctionCallReturningArrayVisitor : public ASR::CallReplacerOnExpre void pass_replace_intrinsic_function(Allocator &al, ASR::TranslationUnit_t &unit, const LCompilers::PassOptions& /*pass_options*/) { - std::map func2intrinsicid; + std::map func2intrinsicid; ReplaceIntrinsicFunctionVisitor v(al, unit.m_global_scope, func2intrinsicid); v.visit_TranslationUnit(unit); ReplaceFunctionCallReturningArrayVisitor u(al, func2intrinsicid); diff --git a/src/libasr/pass/intrinsic_function_registry.h b/src/libasr/pass/intrinsic_function_registry.h index d8fe1d173f..6bdf91c50d 100644 --- a/src/libasr/pass/intrinsic_function_registry.h +++ b/src/libasr/pass/intrinsic_function_registry.h @@ -41,7 +41,6 @@ enum class IntrinsicFunctions : int64_t { Exp, Exp2, Expm1, - Any, ListIndex, Partition, ListReverse, @@ -51,13 +50,9 @@ enum class IntrinsicFunctions : int64_t { DictValues, SetAdd, SetRemove, - Sum, - Product, Max, - MaxVal, Min, - MinVal, - Merge, + Sign, SymbolicSymbol, SymbolicAdd, SymbolicSub, @@ -98,7 +93,6 @@ inline std::string get_intrinsic_name(int x) { INTRINSIC_NAME_CASE(Exp) INTRINSIC_NAME_CASE(Exp2) INTRINSIC_NAME_CASE(Expm1) - INTRINSIC_NAME_CASE(Any) INTRINSIC_NAME_CASE(ListIndex) INTRINSIC_NAME_CASE(Partition) INTRINSIC_NAME_CASE(ListReverse) @@ -108,13 +102,9 @@ inline std::string get_intrinsic_name(int x) { INTRINSIC_NAME_CASE(DictValues) INTRINSIC_NAME_CASE(SetAdd) INTRINSIC_NAME_CASE(SetRemove) - INTRINSIC_NAME_CASE(Sum) INTRINSIC_NAME_CASE(Max) INTRINSIC_NAME_CASE(Min) - INTRINSIC_NAME_CASE(Product) - INTRINSIC_NAME_CASE(MaxVal) - INTRINSIC_NAME_CASE(MinVal) - INTRINSIC_NAME_CASE(Merge) + INTRINSIC_NAME_CASE(Sign) INTRINSIC_NAME_CASE(SymbolicSymbol) INTRINSIC_NAME_CASE(SymbolicAdd) INTRINSIC_NAME_CASE(SymbolicSub) @@ -138,11 +128,11 @@ inline std::string get_intrinsic_name(int x) { typedef ASR::expr_t* (*impl_function)( Allocator&, const Location &, - SymbolTable*, Vec&, + SymbolTable*, Vec&, ASR::ttype_t *, Vec&, int64_t, ASR::expr_t*); typedef ASR::expr_t* (*eval_intrinsic_function)( - Allocator&, const Location &, + Allocator&, const Location &, ASR::ttype_t *, Vec&); typedef ASR::asr_t* (*create_intrinsic_function)( @@ -154,10 +144,6 @@ typedef void (*verify_function)( const ASR::IntrinsicFunction_t&, diag::Diagnostics&); -typedef void (*verify_array_func)(ASR::expr_t*, ASR::ttype_t*, - const Location&, diag::Diagnostics&, - ASRUtils::IntrinsicFunctions); - typedef ASR::expr_t* (*get_initial_value_func)(Allocator&, ASR::ttype_t*); @@ -224,9 +210,13 @@ class ASRBuilder { // Types ------------------------------------------------------------------- #define int32 TYPE(ASR::make_Integer_t(al, loc, 4)) + #define int64 TYPE(ASR::make_Integer_t(al, loc, 8)) + #define real32 TYPE(ASR::make_Real_t(al, loc, 4)) + #define real64 TYPE(ASR::make_Real_t(al, loc, 8)) #define logical TYPE(ASR::make_Logical_t(al, loc, 4)) #define character(x) TYPE(ASR::make_Character_t(al, loc, 1, x, nullptr)) #define List(x) TYPE(ASR::make_List_t(al, loc, x)) + ASR::ttype_t *Tuple(std::vector tuple_type) { Vec m_tuple_type; m_tuple_type.reserve(al, 3); for (auto &x: tuple_type) { @@ -234,11 +224,34 @@ class ASRBuilder { } return TYPE(ASR::make_Tuple_t(al, loc, m_tuple_type.p, m_tuple_type.n)); } + ASR::ttype_t *Array(std::vector dims, ASR::ttype_t *type) { + Vec m_dims; m_dims.reserve(al, 1); + for (auto &x: dims) { + ASR::dimension_t dim; + dim.loc = loc; + if (x == -1) { + dim.m_start = nullptr; + dim.m_length = nullptr; + } else { + dim.m_start = EXPR(ASR::make_IntegerConstant_t(al, loc, 1, int32)); + dim.m_length = EXPR(ASR::make_IntegerConstant_t(al, loc, x, int32)); + } + m_dims.push_back(al, dim); + } + return make_Array_t_util(al, loc, type, m_dims.p, m_dims.n); + } // Expressions ------------------------------------------------------------- + #define i(x, t) EXPR(ASR::make_IntegerConstant_t(al, loc, x, t)) #define i32(x) EXPR(ASR::make_IntegerConstant_t(al, loc, x, int32)) #define i32_n(x) EXPR(ASR::make_IntegerUnaryMinus_t(al, loc, i32(abs(x)), \ int32, i32(x))) + #define i32_neg(x, t) EXPR(ASR::make_IntegerUnaryMinus_t(al, loc, x, t, nullptr)) + + #define f(x, t) EXPR(ASR::make_RealConstant_t(al, loc, x, t)) + #define f32(x) EXPR(ASR::make_RealConstant_t(al, loc, x, real32)) + #define f32_neg(x, t) EXPR(ASR::make_RealUnaryMinus_t(al, loc, x, t, nullptr)) + #define bool32(x) EXPR(ASR::make_LogicalConstant_t(al, loc, x, logical)) #define ListItem(x, pos, type) EXPR(ASR::make_ListItem_t(al, loc, x, pos, \ @@ -253,15 +266,46 @@ class ASRBuilder { s2c(al, s), type)) #define StringLen(s) EXPR(ASR::make_StringLen_t(al, loc, s, int32, nullptr)) + // Cast -------------------------------------------------------------------- + #define r2i32(x) EXPR(ASR::make_Cast_t(al, loc, x, \ + ASR::cast_kindType::RealToInteger, int32, nullptr)) + #define r2i64(x) EXPR(ASR::make_Cast_t(al, loc, x, \ + ASR::cast_kindType::RealToInteger, int64, nullptr)) + #define i2r32(x) EXPR(ASR::make_Cast_t(al, loc, x, \ + ASR::cast_kindType::IntegerToReal, real32, nullptr)) + #define i2r64(x) EXPR(ASR::make_Cast_t(al, loc, x, \ + ASR::cast_kindType::IntegerToReal, real64, nullptr)) + #define i2i(x, t) EXPR(ASR::make_Cast_t(al, loc, x, \ + ASR::cast_kindType::IntegerToInteger, t, nullptr)) + #define i2i64(x) EXPR(ASR::make_Cast_t(al, loc, x, \ + ASR::cast_kindType::IntegerToInteger, int64, nullptr)) + #define i2i32(x) EXPR(ASR::make_Cast_t(al, loc, x, \ + ASR::cast_kindType::IntegerToInteger, int32, nullptr)) + #define r2r32(x) EXPR(ASR::make_Cast_t(al, loc, x, \ + ASR::cast_kindType::RealToReal, real32, nullptr)) + #define r2r64(x) EXPR(ASR::make_Cast_t(al, loc, x, \ + ASR::cast_kindType::RealToReal, real64, nullptr)) + #define r2r(x, t) EXPR(ASR::make_Cast_t(al, loc, x, \ + ASR::cast_kindType::RealToReal, t, nullptr)) + + // Binop ------------------------------------------------------------------- #define iAdd(left, right) EXPR(ASR::make_IntegerBinOp_t(al, loc, left, \ ASR::binopType::Add, right, int32, nullptr)) + #define iMul(left, right) EXPR(ASR::make_IntegerBinOp_t(al, loc, left, \ + ASR::binopType::Mul, right, int32, nullptr)) #define iSub(left, right) EXPR(ASR::make_IntegerBinOp_t(al, loc, left, \ ASR::binopType::Sub, right, int32, nullptr)) + #define iDiv(left, right) r2i32(EXPR(ASR::make_RealBinOp_t(al, loc, i2r32(left),\ + ASR::binopType::Div, i2r32(right), real32, nullptr))) + + #define rDiv(left, right) EXPR(ASR::make_RealBinOp_t(al, loc, left, \ + ASR::binopType::Div, right, real32, nullptr)) #define And(x, y) EXPR(ASR::make_LogicalBinOp_t(al, loc, x, \ ASR::logicalbinopType::And, y, logical, nullptr)) #define Not(x) EXPR(ASR::make_LogicalNot_t(al, loc, x, logical, nullptr)) + // Compare ----------------------------------------------------------------- #define iEq(x, y) EXPR(ASR::make_IntegerCompare_t(al, loc, x, \ ASR::cmpopType::Eq, y, logical, nullptr)) #define sEq(x, y) EXPR(ASR::make_StringCompare_t(al, loc, x, \ @@ -276,6 +320,49 @@ class ASRBuilder { ASR::cmpopType::LtE, y, logical, nullptr)) #define iGtE(x, y) EXPR(ASR::make_IntegerCompare_t(al, loc, x, \ ASR::cmpopType::GtE, y, logical, nullptr)) + #define iGt(x, y) EXPR(ASR::make_IntegerCompare_t(al, loc, x, \ + ASR::cmpopType::Gt, y, logical, nullptr)) + + #define ArraySize_1(x, dim) EXPR(make_ArraySize_t_util(al, loc, x, dim, \ + int32, nullptr)) + #define ArraySize_2(x, dim, t) EXPR(make_ArraySize_t_util(al, loc, x, dim, \ + t, nullptr)) + + #define fGtE(x, y) EXPR(ASR::make_RealCompare_t(al, loc, x, \ + ASR::cmpopType::GtE, y, logical, nullptr)) + #define fLt(x, y) EXPR(ASR::make_RealCompare_t(al, loc, x, \ + ASR::cmpopType::Lt, y, logical, nullptr)) + #define fGt(x, y) EXPR(ASR::make_RealCompare_t(al, loc, x, \ + ASR::cmpopType::Gt, y, logical, nullptr)) + + #define sEq(x, y) EXPR(ASR::make_StringCompare_t(al, loc, x, \ + ASR::cmpopType::Eq, y, logical, nullptr)) + #define sNotEq(x, y) EXPR(ASR::make_StringCompare_t(al, loc, x, \ + ASR::cmpopType::NotEq, y, logical, nullptr)) + + ASR::expr_t *Gt(ASR::expr_t *left, ASR::expr_t *right) { + LCOMPILERS_ASSERT(check_equal_type(expr_type(left), expr_type(right))); + if (is_real(*expr_type(left))) { + return fGt(left, right); + } else if (is_integer(*expr_type(left))) { + return iGt(left, right); + } else { + LCOMPILERS_ASSERT(false); + return nullptr; + } + } + + ASR::expr_t *Lt(ASR::expr_t *left, ASR::expr_t *right) { + LCOMPILERS_ASSERT(check_equal_type(expr_type(left), expr_type(right))); + if (is_real(*expr_type(left))) { + return fLt(left, right); + } else if (is_integer(*expr_type(left))) { + return iLt(left, right); + } else { + LCOMPILERS_ASSERT(false); + return nullptr; + } + } ASR::stmt_t *If(ASR::expr_t *a_test, std::vector if_body, std::vector else_body) { @@ -338,7 +425,7 @@ class ASRBuilder { create_ElementalBinOp(Complex, make_ComplexBinOp_t, Sub, value) default: { throw LCompilersException("Expression type, " + - std::to_string(left->type) + + std::to_string(expr_type(left)->type) + " not yet supported"); } } @@ -352,7 +439,7 @@ class ASRBuilder { create_ElementalBinOp(Complex, make_ComplexBinOp_t, Div, value) default: { throw LCompilersException("Expression type, " + - std::to_string(left->type) + + std::to_string(expr_type(left)->type) + " not yet supported"); } } @@ -366,7 +453,7 @@ class ASRBuilder { create_ElementalBinOp(Complex, make_ComplexBinOp_t, Mul, value) default: { throw LCompilersException("Expression type, " + - std::to_string(left->type) + + std::to_string(expr_type(left)->type) + " not yet supported"); } } @@ -380,7 +467,7 @@ class ASRBuilder { create_ElementalBinOp(Complex, make_ComplexBinOp_t, Pow, value) default: { throw LCompilersException("Expression type, " + - std::to_string(left->type) + + std::to_string(expr_type(left)->type) + " not yet supported"); } } @@ -400,7 +487,7 @@ class ASRBuilder { } default: { throw LCompilersException("Expression type, " + - std::to_string(left->type) + " not yet supported"); + std::to_string(expr_type(left)->type) + " not yet supported"); } } return ASRUtils::EXPR(ASR::make_IfExp_t(al, loc, test_condition, left, right, ASRUtils::expr_type(left), value)); @@ -420,7 +507,7 @@ class ASRBuilder { } default: { throw LCompilersException("Expression type, " + - std::to_string(left->type) + " not yet supported"); + std::to_string(expr_type(left)->type) + " not yet supported"); } } return ASRUtils::EXPR(ASR::make_IfExp_t(al, loc, test_condition, left, right, ASRUtils::expr_type(left), value)); @@ -460,10 +547,40 @@ class ASRBuilder { s, s, args.p, args.size(), return_type, value, nullptr)); } + ASR::expr_t *ArrayItem_01(ASR::expr_t *arr, std::vector idx) { + Vec idx_vars; idx_vars.reserve(al, 1); + for (auto &x: idx) idx_vars.push_back(al, x); + return PassUtils::create_array_ref(arr, idx_vars, al); + } + + #define ArrayItem_02(arr, idx_vars) PassUtils::create_array_ref(arr, \ + idx_vars, al) + + ASR::expr_t *ArrayConstant(std::vector elements, + ASR::ttype_t *base_type, bool cast2descriptor=true) { + // This function only creates array with rank one + // TODO: Support other dimensions + Vec m_eles; m_eles.reserve(al, 1); + for (auto &x: elements) m_eles.push_back(al, x); + + ASR::ttype_t *fixed_size_type = Array({(int64_t) elements.size()}, base_type); + ASR::expr_t *arr_constant = EXPR(ASR::make_ArrayConstant_t(al, loc, + m_eles.p, m_eles.n, fixed_size_type, ASR::arraystorageType::ColMajor)); + + if (cast2descriptor) { + return cast_to_descriptor(al, arr_constant); + } else { + return arr_constant; + } + } + // Statements -------------------------------------------------------------- #define Return() STMT(ASR::make_Return_t(al, loc)) - #define Assignment(lhs, rhs) ASRUtils::STMT(ASR::make_Assignment_t(al, loc, \ - lhs, rhs, nullptr)) + + ASR::stmt_t *Assignment(ASR::expr_t *lhs, ASR::expr_t*rhs) { + LCOMPILERS_ASSERT(check_equal_type(expr_type(lhs), expr_type(rhs))); + return STMT(ASR::make_Assignment_t(al, loc, lhs, rhs, nullptr)); + } template ASR::stmt_t* create_do_loop( @@ -589,8 +706,12 @@ namespace UnaryIntrinsicFunction { static inline ASR::expr_t* instantiate_functions(Allocator &al, const Location &loc, SymbolTable *scope, std::string new_name, - ASR::ttype_t *arg_type, Vec& new_args, int64_t /*overload_id*/, + ASR::ttype_t *arg_type, ASR::ttype_t *return_type, + Vec& new_args, int64_t /*overload_id*/, ASR::expr_t *value) { + if (value) { + return value; + } std::string c_func_name; switch (arg_type->type) { case ASR::ttypeType::Complex : { @@ -618,7 +739,7 @@ static inline ASR::expr_t* instantiate_functions(Allocator &al, return b.Call(s, new_args, expr_type(f->m_return_var), value); } fill_func_arg("x", arg_type); - auto result = declare(new_name, arg_type, ReturnVar); + auto result = declare(new_name, return_type, ReturnVar); { SymbolTable *fn_symtab_1 = al.make_new(fn_symtab); @@ -639,13 +760,13 @@ static inline ASR::expr_t* instantiate_functions(Allocator &al, body_1, return_var_1, BindC, Interface, s2c(al, c_func_name)); fn_symtab->add_symbol(c_func_name, s); dep.push_back(al, s2c(al, c_func_name)); - body.push_back(al, Assignment(result, b.Call(s, args, arg_type))); + body.push_back(al, b.Assignment(result, b.Call(s, args, arg_type))); } ASR::symbol_t *new_symbol = make_Function_t(fn_name, fn_symtab, dep, args, body, result, Source, Implementation, nullptr); scope->add_symbol(fn_name, new_symbol); - return b.Call(new_symbol, new_args, arg_type, value); + return b.Call(new_symbol, new_args, return_type, value); } static inline ASR::asr_t* create_UnaryFunction(Allocator& al, const Location& loc, @@ -657,7 +778,7 @@ static inline ASR::asr_t* create_UnaryFunction(Allocator& al, const Location& lo Vec arg_values; arg_values.reserve(al, 1); arg_values.push_back(al, arg_value); - value = eval_function(al, loc, arg_values); + value = eval_function(al, loc, type, arg_values); } return ASRUtils::make_IntrinsicFunction_t_util(al, loc, intrinsic_id, @@ -687,58 +808,58 @@ static inline ASR::symbol_t *create_KMP_function(Allocator &al, auto flag = declare("flag", logical, Local); auto lps = declare("lps", List(int32), Local); - body.push_back(al, Assignment(s_len, StringLen(args[0]))); - body.push_back(al, Assignment(pat_len, StringLen(args[1]))); - body.push_back(al, Assignment(result, i32_n(-1))); + body.push_back(al, b.Assignment(s_len, StringLen(args[0]))); + body.push_back(al, b.Assignment(pat_len, StringLen(args[1]))); + body.push_back(al, b.Assignment(result, i32_n(-1))); body.push_back(al, b.If(iEq(pat_len, i32(0)), { - Assignment(result, i32(0)), Return() + b.Assignment(result, i32(0)), Return() }, { b.If(iEq(s_len, i32(0)), { Return() }, {}) })); - body.push_back(al, Assignment(lps, + body.push_back(al, b.Assignment(lps, EXPR(ASR::make_ListConstant_t(al, loc, nullptr, 0, List(int32))))); - body.push_back(al, Assignment(i, i32(0))); + body.push_back(al, b.Assignment(i, i32(0))); body.push_back(al, b.While(iLtE(i, iSub(pat_len, i32(1))), { - Assignment(i, iAdd(i, i32(1))), + b.Assignment(i, iAdd(i, i32(1))), ListAppend(lps, i32(0)) })); - body.push_back(al, Assignment(flag, bool32(false))); - body.push_back(al, Assignment(i, i32(1))); - body.push_back(al, Assignment(pi_len, i32(0))); + body.push_back(al, b.Assignment(flag, bool32(false))); + body.push_back(al, b.Assignment(i, i32(1))); + body.push_back(al, b.Assignment(pi_len, i32(0))); body.push_back(al, b.While(iLt(i, pat_len), { b.If(sEq(StringItem(args[1], iAdd(i, i32(1))), StringItem(args[1], iAdd(pi_len, i32(1)))), { - Assignment(pi_len, iAdd(pi_len, i32(1))), - Assignment(ListItem(lps, i, int32), pi_len), - Assignment(i, iAdd(i, i32(1))) + b.Assignment(pi_len, iAdd(pi_len, i32(1))), + b.Assignment(ListItem(lps, i, int32), pi_len), + b.Assignment(i, iAdd(i, i32(1))) }, { b.If(iNotEq(pi_len, i32(0)), { - Assignment(pi_len, ListItem(lps, iSub(pi_len, i32(1)), int32)) + b.Assignment(pi_len, ListItem(lps, iSub(pi_len, i32(1)), int32)) }, { - Assignment(i, iAdd(i, i32(1))) + b.Assignment(i, iAdd(i, i32(1))) }) }) })); - body.push_back(al, Assignment(j, i32(0))); - body.push_back(al, Assignment(i, i32(0))); + body.push_back(al, b.Assignment(j, i32(0))); + body.push_back(al, b.Assignment(i, i32(0))); body.push_back(al, b.While(And(iGtE(iSub(s_len, i), iSub(pat_len, j)), Not(flag)), { b.If(sEq(StringItem(args[1], iAdd(j, i32(1))), StringItem(args[0], iAdd(i, i32(1)))), { - Assignment(i, iAdd(i, i32(1))), - Assignment(j, iAdd(j, i32(1))) + b.Assignment(i, iAdd(i, i32(1))), + b.Assignment(j, iAdd(j, i32(1))) }, {}), b.If(iEq(j, pat_len), { - Assignment(result, iSub(i, j)), - Assignment(flag, bool32(true)), - Assignment(j, ListItem(lps, iSub(j, i32(1)), int32)) + b.Assignment(result, iSub(i, j)), + b.Assignment(flag, bool32(true)), + b.Assignment(j, ListItem(lps, iSub(j, i32(1)), int32)) }, { b.If(And(iLt(i, s_len), sNotEq(StringItem(args[1], iAdd(j, i32(1))), StringItem(args[0], iAdd(i, i32(1))))), { b.If(iNotEq(j, i32(0)), { - Assignment(j, ListItem(lps, iSub(j, i32(1)), int32)) + b.Assignment(j, ListItem(lps, iSub(j, i32(1)), int32)) }, { - Assignment(i, iAdd(i, i32(1))) + b.Assignment(i, iAdd(i, i32(1))) }) }, {}) }) @@ -766,23 +887,12 @@ static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnost } // namespace UnaryIntrinsicFunction -#define instantiate_UnaryFunctionArgs Allocator &al, const Location &loc, \ - SymbolTable *scope, Vec& arg_types, \ - Vec& new_args, int64_t overload_id, ASR::expr_t* compile_time_value \ - -#define instantiate_UnaryFunctionBody(Y) \ - LCOMPILERS_ASSERT(arg_types.size() == 1); \ - ASR::ttype_t* arg_type = arg_types[0]; \ - return UnaryIntrinsicFunction::instantiate_functions( \ - al, loc, scope, #Y, arg_type, new_args, overload_id, \ - compile_time_value); \ - namespace LogGamma { -static inline ASR::expr_t *eval_log_gamma(Allocator &al, const Location &loc, Vec& args) { +static inline ASR::expr_t *eval_log_gamma(Allocator &al, const Location &loc, + ASR::ttype_t *t, Vec& args) { double rv = ASR::down_cast(args[0])->m_r; double val = lgamma(rv); - ASR::ttype_t *t = ASRUtils::expr_type(args[0]); return make_ConstantWithType(make_RealConstant_t, val, t, loc); } @@ -801,8 +911,15 @@ static inline ASR::asr_t* create_LogGamma(Allocator& al, const Location& loc, 0, type); } -static inline ASR::expr_t* instantiate_LogGamma (instantiate_UnaryFunctionArgs) { - instantiate_UnaryFunctionBody(log_gamma) +static inline ASR::expr_t* instantiate_LogGamma (Allocator &al, + const Location &loc, SymbolTable *scope, Vec& arg_types, + ASR::ttype_t *return_type, Vec& new_args, + int64_t overload_id,ASR::expr_t* compile_time_value) { + if (compile_time_value) return compile_time_value; + LCOMPILERS_ASSERT(arg_types.size() == 1); + ASR::ttype_t* arg_type = arg_types[0]; + return UnaryIntrinsicFunction::instantiate_functions(al, loc, scope, + "log_gamma", arg_type, return_type, new_args, overload_id, nullptr); } } // namespace LogGamma @@ -814,14 +931,13 @@ static inline ASR::expr_t* instantiate_LogGamma (instantiate_UnaryFunctionArgs) // `lcompilers_name` is the name that we use in the C runtime library #define create_trig(X, stdeval, lcompilers_name) \ namespace X { \ - static inline ASR::expr_t *eval_##X(Allocator &al, \ - const Location &loc, Vec& args) { \ + static inline ASR::expr_t *eval_##X(Allocator &al, const Location &loc, \ + ASR::ttype_t *t, Vec& args) { \ LCOMPILERS_ASSERT(args.size() == 1); \ double rv; \ - ASR::ttype_t *t = ASRUtils::expr_type(args[0]); \ if( ASRUtils::extract_value(args[0], rv) ) { \ double val = std::stdeval(rv); \ - return make_ConstantWithType(make_RealConstant_t, val, t, loc); \ + return make_ConstantWithType(make_RealConstant_t, val, t, loc); \ } else { \ std::complex crv; \ if( ASRUtils::extract_value(args[0], crv) ) { \ @@ -846,15 +962,16 @@ namespace X { 0, type); \ } \ static inline ASR::expr_t* instantiate_##X (Allocator &al, \ - const Location &loc, SymbolTable *scope, \ - Vec& arg_types, Vec& new_args, \ - int64_t overload_id, ASR::expr_t* compile_time_value) \ - { \ + const Location &loc, SymbolTable *scope, \ + Vec& arg_types, ASR::ttype_t *return_type, \ + Vec& new_args,int64_t overload_id, \ + ASR::expr_t* compile_time_value) { \ + if (compile_time_value) return compile_time_value; \ LCOMPILERS_ASSERT(arg_types.size() == 1); \ ASR::ttype_t* arg_type = arg_types[0]; \ return UnaryIntrinsicFunction::instantiate_functions(al, loc, scope, \ - #lcompilers_name, arg_type, new_args, overload_id, \ - compile_time_value); \ + #lcompilers_name, arg_type, return_type, new_args, overload_id, \ + nullptr); \ } \ } // namespace X @@ -904,19 +1021,18 @@ namespace Abs { } static ASR::expr_t *eval_Abs(Allocator &al, const Location &loc, - Vec &args) { + ASR::ttype_t *t, Vec &args) { LCOMPILERS_ASSERT(ASRUtils::all_args_evaluated(args)); ASR::expr_t* arg = args[0]; - ASR::ttype_t* t = ASRUtils::expr_type(args[0]); - if (ASRUtils::is_real(*t)) { + if (ASRUtils::is_real(*expr_type(arg))) { double rv = ASR::down_cast(arg)->m_r; double val = std::abs(rv); return make_ConstantWithType(make_RealConstant_t, val, t, loc); - } else if (ASRUtils::is_integer(*t)) { + } else if (ASRUtils::is_integer(*expr_type(arg))) { int64_t rv = ASR::down_cast(arg)->m_n; int64_t val = std::abs(rv); return make_ConstantWithType(make_IntegerConstant_t, val, t, loc); - } else if (ASRUtils::is_complex(*t)) { + } else if (ASRUtils::is_complex(*expr_type(arg))) { double re = ASR::down_cast(arg)->m_re; double im = ASR::down_cast(arg)->m_im; std::complex x(re, im); @@ -948,16 +1064,17 @@ namespace Abs { } static inline ASR::expr_t* instantiate_Abs(Allocator &al, const Location &loc, - SymbolTable *scope, Vec& arg_types, + SymbolTable *scope, Vec& arg_types, ASR::ttype_t *return_type, Vec& new_args, int64_t /*overload_id*/, ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } std::string func_name = "_lcompilers_abs_" + type_to_str_python(arg_types[0]); - ASR::ttype_t *return_type = arg_types[0]; declare_basic_variables(func_name); if (scope->get_symbol(func_name)) { ASR::symbol_t *s = scope->get_symbol(func_name); ASR::Function_t *f = ASR::down_cast(s); - return b.Call(s, new_args, expr_type(f->m_return_var), - compile_time_value); + return b.Call(s, new_args, expr_type(f->m_return_var), nullptr); } fill_func_arg("x", arg_types[0]); @@ -986,9 +1103,9 @@ namespace Abs { } Vec if_body; if_body.reserve(al, 1); - if_body.push_back(al, Assignment(result, args[0])); + if_body.push_back(al, b.Assignment(result, args[0])); Vec else_body; else_body.reserve(al, 1); - else_body.push_back(al, Assignment(result, negative_x)); + else_body.push_back(al, b.Assignment(result, negative_x)); body.push_back(al, STMT(ASR::make_If_t(al, loc, test, if_body.p, if_body.n, else_body.p, else_body.n))); } else { @@ -1044,25 +1161,131 @@ namespace Abs { bin_op_1 = b.ElementalAdd(bin_op_1, bin_op_2, loc); - body.push_back(al, Assignment(result, + body.push_back(al, b.Assignment(result, b.ElementalPow(bin_op_1, constant_point_five, loc))); } ASR::symbol_t *f_sym = make_Function_t(func_name, fn_symtab, dep, args, body, result, Source, Implementation, nullptr); scope->add_symbol(func_name, f_sym); - return b.Call(f_sym, new_args, return_type, compile_time_value); + return b.Call(f_sym, new_args, return_type, nullptr); } } // namespace Abs +namespace Sign { + + static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { + ASRUtils::require_impl(x.n_args == 2, + "ASR Verify: Call to sign must have exactly two arguments", + x.base.base.loc, diagnostics); + ASR::ttype_t *type1 = ASRUtils::expr_type(x.m_args[0]); + ASR::ttype_t *type2 = ASRUtils::expr_type(x.m_args[1]); + ASRUtils::require_impl((is_real(*type1) || is_integer(*type2)), + "ASR Verify: Arguments to sign must be of real or integer type", + x.base.base.loc, diagnostics); + ASRUtils::require_impl((ASRUtils::check_equal_type(type1, type2)), + "ASR Verify: All arguments must be of the same type", + x.base.base.loc, diagnostics); + } + + static ASR::expr_t *eval_Sign(Allocator &al, const Location &loc, + ASR::ttype_t* t1, Vec &args) { + if (ASRUtils::is_real(*t1)) { + double rv1 = std::abs(ASR::down_cast(args[0])->m_r); + double rv2 = ASR::down_cast(args[1])->m_r; + if (rv2 < 0) rv1 = -rv1; + return make_ConstantWithType(make_RealConstant_t, rv1, t1, loc); + } else { + int64_t iv1 = std::abs(ASR::down_cast(args[0])->m_n); + int64_t iv2 = ASR::down_cast(args[1])->m_n; + if (iv2 < 0) iv1 = -iv1; + return make_ConstantWithType(make_IntegerConstant_t, iv1, t1, loc); + } + } + + static inline ASR::asr_t* create_Sign(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + if (args.size() != 2) { + err("Intrinsic sign function accepts exactly 2 arguments", loc); + } + ASR::ttype_t *type1 = ASRUtils::expr_type(args[0]); + ASR::ttype_t *type2 = ASRUtils::expr_type(args[1]); + if (!ASRUtils::is_integer(*type1) && !ASRUtils::is_real(*type1)) { + err("Argument of the sign function must be Integer or Real", + args[0]->base.loc); + } + if (!ASRUtils::check_equal_type(type1, type2)) { + err("Type mismatch in statement function: " + "the second argument must have the same type " + "and kind as the first argument.", args[1]->base.loc); + } + ASR::expr_t *m_value = nullptr; + if (all_args_evaluated(args)) { + Vec arg_values; arg_values.reserve(al, 2); + arg_values.push_back(al, expr_value(args[0])); + arg_values.push_back(al, expr_value(args[1])); + m_value = eval_Sign(al, loc, expr_type(args[0]), arg_values); + } + return ASR::make_IntrinsicFunction_t(al, loc, + static_cast(ASRUtils::IntrinsicFunctions::Sign), + args.p, args.n, 0, ASRUtils::expr_type(args[0]), m_value); + } + + static inline ASR::expr_t* instantiate_Sign(Allocator &al, const Location &loc, + SymbolTable *scope, Vec& arg_types, ASR::ttype_t *return_type, + Vec& new_args, int64_t /*overload_id*/, + ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } + declare_basic_variables("_lcompilers_sign_" + type_to_str_python(arg_types[0])); + fill_func_arg("x", arg_types[0]); + fill_func_arg("y", arg_types[0]); + auto result = declare(fn_name, return_type, ReturnVar); + /* + * r = abs(x) + * if (y < 0) then + * r = -r + * end if + */ + if (is_real(*arg_types[0])) { + ASR::expr_t *zero = f(0, arg_types[0]); + body.push_back(al, b.If(fGtE(args[0], zero), { + b.Assignment(result, args[0]) + }, /* else */ { + b.Assignment(result, f32_neg(args[0], arg_types[0])) + })); + body.push_back(al, b.If(fLt(args[1], zero), { + b.Assignment(result, f32_neg(result, arg_types[0])) + }, {})); + } else { + ASR::expr_t *zero = i(0, arg_types[0]); + body.push_back(al, b.If(iGtE(args[0], zero), { + b.Assignment(result, args[0]) + }, /* else */ { + b.Assignment(result, i32_neg(args[0], arg_types[0])) + })); + body.push_back(al, b.If(iLt(args[1], zero), { + b.Assignment(result, i32_neg(result, arg_types[0])) + }, {})); + } + + ASR::symbol_t *f_sym = make_Function_t(fn_name, fn_symtab, dep, args, + body, result, Source, Implementation, nullptr); + scope->add_symbol(fn_name, f_sym); + return b.Call(f_sym, new_args, return_type, nullptr); + } + +} // namespace Sign + #define create_exp_macro(X, stdeval) \ namespace X { \ static inline ASR::expr_t* eval_##X(Allocator &al, const Location &loc, \ - Vec &args) { \ + ASR::ttype_t *t, Vec &args) { \ LCOMPILERS_ASSERT(ASRUtils::all_args_evaluated(args)); \ double rv; \ - ASR::ttype_t* t = ASRUtils::expr_type(args[0]); \ if( ASRUtils::extract_value(args[0], rv) ) { \ double val = std::stdeval(rv); \ return ASRUtils::EXPR(ASR::make_RealConstant_t(al, loc, val, t)); \ @@ -1118,7 +1341,7 @@ static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnost } static inline ASR::expr_t *eval_list_index(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t */*t*/, Vec& /*args*/) { // TODO: To be implemented for ListConstant expression return nullptr; } @@ -1156,8 +1379,8 @@ static inline ASR::asr_t* create_ListIndex(Allocator& al, const Location& loc, for( size_t i = 0; i < args.size(); i++ ) { arg_values.push_back(al, ASRUtils::expr_value(args[i])); } - ASR::expr_t* compile_time_value = eval_list_index(al, loc, arg_values); - ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc, 4)); + ASR::ttype_t *to_type = int32; + ASR::expr_t* compile_time_value = eval_list_index(al, loc, to_type, arg_values); return ASR::make_IntrinsicFunction_t(al, loc, static_cast(ASRUtils::IntrinsicFunctions::ListIndex), args.p, args.size(), overload_id, to_type, compile_time_value); @@ -1179,7 +1402,7 @@ static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnost } static inline ASR::expr_t *eval_list_reverse(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t */*t*/, Vec& /*args*/) { // TODO: To be implemented for ListConstant expression return nullptr; } @@ -1196,7 +1419,7 @@ static inline ASR::asr_t* create_ListReverse(Allocator& al, const Location& loc, for( size_t i = 0; i < args.size(); i++ ) { arg_values.push_back(al, ASRUtils::expr_value(args[i])); } - ASR::expr_t* compile_time_value = eval_list_reverse(al, loc, arg_values); + ASR::expr_t* compile_time_value = eval_list_reverse(al, loc, nullptr, arg_values); return ASR::make_Expr_t(al, loc, ASRUtils::EXPR(ASRUtils::make_IntrinsicFunction_t_util(al, loc, static_cast(ASRUtils::IntrinsicFunctions::ListReverse), @@ -1229,7 +1452,7 @@ static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnost } static inline ASR::expr_t *eval_list_pop(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t */*t*/, Vec& /*args*/) { // TODO: To be implemented for ListConstant expression return nullptr; } @@ -1254,8 +1477,8 @@ static inline ASR::asr_t* create_ListPop(Allocator& al, const Location& loc, for( size_t i = 0; i < args.size(); i++ ) { arg_values.push_back(al, ASRUtils::expr_value(args[i])); } - ASR::expr_t* compile_time_value = eval_list_pop(al, loc, arg_values); ASR::ttype_t *to_type = list_type; + ASR::expr_t* compile_time_value = eval_list_pop(al, loc, to_type, arg_values); int64_t overload_id = (args.size() == 2); return ASR::make_IntrinsicFunction_t(al, loc, static_cast(ASRUtils::IntrinsicFunctions::ListPop), @@ -1503,305 +1726,8 @@ static inline ASR::asr_t* create_SetRemove(Allocator& al, const Location& loc, } // namespace SetRemove -namespace Any { - -static inline void verify_array(ASR::expr_t* array, ASR::ttype_t* return_type, - const Location& loc, diag::Diagnostics& diagnostics) { - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - ASRUtils::require_impl(ASRUtils::is_logical(*array_type), - "Input to Any intrinsic must be of logical type, found: " + ASRUtils::get_type_code(array_type), - loc, diagnostics); - int array_n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); - ASRUtils::require_impl(array_n_dims > 0, "Input to Any intrinsic must always be an array", - loc, diagnostics); - ASRUtils::require_impl(ASRUtils::is_logical(*return_type), - "Any intrinsic must return a logical output", loc, diagnostics); - int return_n_dims = ASRUtils::extract_n_dims_from_ttype(return_type); - ASRUtils::require_impl(return_n_dims == 0, - "Any intrinsic output for array only input should be a scalar", - loc, diagnostics); -} - -static inline void verify_array_dim(ASR::expr_t* array, ASR::expr_t* dim, - ASR::ttype_t* return_type, const Location& loc, diag::Diagnostics& diagnostics) { - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - ASRUtils::require_impl(ASRUtils::is_logical(*ASRUtils::type_get_past_pointer(array_type)), - "Input to Any intrinsic must be of logical type, found: " + ASRUtils::get_type_code(array_type), - loc, diagnostics); - int array_n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); - ASRUtils::require_impl(array_n_dims > 0, "Input to Any intrinsic must always be an array", - loc, diagnostics); - - ASRUtils::require_impl(ASR::is_a(*ASRUtils::type_get_past_pointer(ASRUtils::expr_type(dim))), - "dim argument must be an integer", loc, diagnostics); - - ASRUtils::require_impl(ASRUtils::is_logical(*return_type), - "Any intrinsic must return a logical output", loc, diagnostics); - int return_n_dims = ASRUtils::extract_n_dims_from_ttype(return_type); - ASRUtils::require_impl(array_n_dims == return_n_dims + 1, - "Any intrinsic output must return a logical array with dimension " - "only 1 less than that of input array", - loc, diagnostics); -} - -static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { - ASRUtils::require_impl(x.n_args >= 1, "Any intrinsic must accept at least one argument", - x.base.base.loc, diagnostics); - ASRUtils::require_impl(x.m_args[0] != nullptr, "Array argument to any intrinsic cannot be nullptr", - x.base.base.loc, diagnostics); - switch( x.m_overload_id ) { - case 0: { - verify_array(x.m_args[0], x.m_type, x.base.base.loc, diagnostics); - break; - } - case 1: { - ASRUtils::require_impl(x.n_args == 2 && x.m_args[1] != nullptr, - "dim argument to any intrinsic cannot be nullptr", - x.base.base.loc, diagnostics); - verify_array_dim(x.m_args[0], x.m_args[1], x.m_type, x.base.base.loc, diagnostics); - break; - } - default: { - require_impl(false, "Unrecognised overload id in Any intrinsic", - x.base.base.loc, diagnostics); - } - } -} - -static inline ASR::expr_t *eval_Any(Allocator & /*al*/, - const Location & /*loc*/, Vec& /*args*/) { - return nullptr; -} - -static inline ASR::asr_t* create_Any( - Allocator& al, const Location& loc, Vec& args, - const std::function err) { - int64_t overload_id = 0; - Vec any_args; - any_args.reserve(al, 2); - - ASR::expr_t* array = args[0]; - ASR::expr_t* axis = nullptr; - if( args.size() == 2 ) { - axis = args[1]; - } - if( ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(array)) == 0 ) { - err("mask argument to any must be an array and must not be a scalar", - array->base.loc); - } - - // TODO: Add a check for range of values axis can take - // if axis is available at compile time - - ASR::expr_t *value = nullptr; - Vec arg_values; - arg_values.reserve(al, 2); - ASR::expr_t *array_value = ASRUtils::expr_value(array); - arg_values.push_back(al, array_value); - if( axis ) { - ASR::expr_t *axis_value = ASRUtils::expr_value(axis); - arg_values.push_back(al, axis_value); - } - value = eval_Any(al, loc, arg_values); - - ASR::ttype_t* logical_return_type = nullptr; - if( axis == nullptr ) { - overload_id = 0; - logical_return_type = ASRUtils::TYPE(ASR::make_Logical_t( - al, loc, 4)); - } else { - overload_id = 1; - Vec dims; - size_t n_dims = ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(array)); - dims.reserve(al, (int) n_dims - 1); - for( int i = 0; i < (int) n_dims - 1; i++ ) { - ASR::dimension_t dim; - dim.loc = array->base.loc; - dim.m_length = nullptr; - dim.m_start = nullptr; - dims.push_back(al, dim); - } - if( dims.size() > 0 ) { - logical_return_type = ASRUtils::make_Array_t_util(al, loc, - ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4)), dims.p, dims.size()); - } else { - logical_return_type = ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4)); - } - } - - any_args.push_back(al, array); - if( axis ) { - any_args.push_back(al, axis); - } - - return ASRUtils::make_IntrinsicFunction_t_util(al, loc, - static_cast(ASRUtils::IntrinsicFunctions::Any), - any_args.p, any_args.n, overload_id, logical_return_type, value); -} - -static inline void generate_body_for_scalar_output(Allocator& al, const Location& loc, - ASR::expr_t* array, ASR::expr_t* return_var, SymbolTable* fn_scope, - Vec& fn_body) { - ASRBuilder builder(al, loc); - Vec idx_vars; - Vec doloop_body; - builder.generate_reduction_intrinsic_stmts_for_scalar_output(loc, - array, fn_scope, fn_body, idx_vars, doloop_body, - [=, &al, &fn_body] () { - ASR::expr_t* logical_false = make_ConstantWithKind( - make_LogicalConstant_t, make_Logical_t, false, 4, loc); - ASR::stmt_t* return_var_init = Assignment(return_var, logical_false); - fn_body.push_back(al, return_var_init); - }, - [=, &al, &idx_vars, &doloop_body, &builder] () { - ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); - ASR::expr_t* logical_or = builder.Or(return_var, array_ref, loc); - ASR::stmt_t* loop_invariant = Assignment(return_var, logical_or); - doloop_body.push_back(al, loop_invariant); - } - ); -} - -static inline void generate_body_for_array_output(Allocator& al, const Location& loc, - ASR::expr_t* array, ASR::expr_t* dim, ASR::expr_t* result, - SymbolTable* fn_scope, Vec& fn_body) { - ASRBuilder builder(al, loc); - Vec idx_vars, target_idx_vars; - Vec doloop_body; - builder.generate_reduction_intrinsic_stmts_for_array_output( - loc, array, dim, fn_scope, fn_body, - idx_vars, target_idx_vars, doloop_body, - [=, &al, &fn_body] { - ASR::expr_t* logical_false = make_ConstantWithKind( - make_LogicalConstant_t, make_Logical_t, false, 4, loc); - ASR::stmt_t* result_init = Assignment(result, logical_false); - fn_body.push_back(al, result_init); - }, - [=, &al, &idx_vars, &target_idx_vars, &doloop_body, &result, &builder] () { - ASR::expr_t* result_ref = PassUtils::create_array_ref(result, target_idx_vars, al); - ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); - ASR::expr_t* logical_or = builder.ElementalOr(result_ref, array_ref, loc); - ASR::stmt_t* loop_invariant = Assignment(result_ref, logical_or); - doloop_body.push_back(al, loop_invariant); - }); -} - -static inline ASR::expr_t* instantiate_Any(Allocator &al, const Location &loc, - SymbolTable *scope, Vec& arg_types, - Vec& new_args, int64_t overload_id, - ASR::expr_t* compile_time_value) { - ASRBuilder builder(al, loc); - ASRBuilder& b = builder; - ASR::ttype_t* arg_type = arg_types[0]; - int kind = ASRUtils::extract_kind_from_ttype_t(arg_type); - int rank = ASRUtils::extract_n_dims_from_ttype(arg_type); - std::string new_name = "any_" + std::to_string(kind) + - "_" + std::to_string(rank) + - "_" + std::to_string(overload_id); - // Check if Function is already defined. - { - std::string new_func_name = new_name; - int i = 1; - while (scope->get_symbol(new_func_name) != nullptr) { - ASR::symbol_t *s = scope->get_symbol(new_func_name); - ASR::Function_t *f = ASR::down_cast(s); - int orig_array_rank = ASRUtils::extract_n_dims_from_ttype( - ASRUtils::expr_type(f->m_args[0])); - if (ASRUtils::types_equal(ASRUtils::expr_type(f->m_args[0]), - arg_type) && orig_array_rank == rank) { - ASR::ttype_t* return_type = nullptr; - if( f->m_return_var ) { - return_type = ASRUtils::expr_type(f->m_return_var); - } else { - return_type = ASRUtils::expr_type(f->m_args[(int) f->n_args - 1]); - } - return builder.Call(s, new_args, return_type, compile_time_value); - } else { - new_func_name += std::to_string(i); - i++; - } - } - } - - new_name = scope->get_unique_name(new_name, false); - SymbolTable *fn_symtab = al.make_new(scope); - - ASR::ttype_t* logical_return_type = ASRUtils::TYPE(ASR::make_Logical_t( - al, loc, 4)); - Vec args; - int result_dims = 0; - { - args.reserve(al, 1); - ASR::ttype_t* mask_type = ASRUtils::duplicate_type_with_empty_dims(al, arg_type); - fill_func_arg("mask", mask_type); - if( overload_id == 1 ) { - ASR::ttype_t* dim_type = ASRUtils::expr_type(new_args[1].m_value); - LCOMPILERS_ASSERT(ASR::is_a(*dim_type)); - [[maybe_unused]] int kind = ASRUtils::extract_kind_from_ttype_t(dim_type); - LCOMPILERS_ASSERT(kind == 4); - fill_func_arg("dim", dim_type); - - Vec dims; - size_t n_dims = ASRUtils::extract_n_dims_from_ttype(arg_type); - dims.reserve(al, (int) n_dims - 1); - for( int i = 0; i < (int) n_dims - 1; i++ ) { - ASR::dimension_t dim; - dim.loc = new_args[0].m_value->base.loc; - dim.m_length = nullptr; - dim.m_start = nullptr; - dims.push_back(al, dim); - } - result_dims = dims.size(); - if( result_dims > 0 ) { - logical_return_type = ASRUtils::make_Array_t_util(al, loc, - ASRUtils::TYPE(ASR::make_Logical_t(al, loc, 4)), - dims.p, dims.size()); - } else { - logical_return_type = ASRUtils::TYPE(ASR::make_Logical_t( - al, loc, 4)); - } - if( result_dims > 0 ) { - fill_func_arg("result", logical_return_type); - } - } - } - - ASR::expr_t* return_var = nullptr; - if( result_dims == 0 ) { - return_var = declare(new_name, logical_return_type, ReturnVar); - } - - Vec body; - body.reserve(al, 1); - if( overload_id == 0 || return_var ) { - generate_body_for_scalar_output(al, loc, args[0], return_var, fn_symtab, body); - } else if( overload_id == 1 ) { - generate_body_for_array_output(al, loc, args[0], args[1], args[2], fn_symtab, body); - } else { - LCOMPILERS_ASSERT(false); - } - - Vec dep; - dep.reserve(al, 1); - // TODO: fill dependencies - - ASR::symbol_t *new_symbol = nullptr; - if( return_var ) { - new_symbol = make_Function_t(new_name, fn_symtab, dep, args, - body, return_var, Source, Implementation, nullptr); - } else { - new_symbol = make_Function_Without_ReturnVar_t( - new_name, fn_symtab, dep, args, - body, Source, Implementation, nullptr); - } - scope->add_symbol(new_name, new_symbol); - return builder.Call(new_symbol, new_args, logical_return_type, - compile_time_value); -} - -} // namespace Any - namespace Max { + static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { ASRUtils::require_impl(x.n_args > 1, "ASR Verify: Call to max0 must have at least two arguments", x.base.base.loc, diagnostics); @@ -1819,9 +1745,9 @@ namespace Max { } } - static ASR::expr_t *eval_Max(Allocator &al, const Location &loc, Vec &args) { + static ASR::expr_t *eval_Max(Allocator &al, const Location &loc, + ASR::ttype_t* arg_type, Vec &args) { LCOMPILERS_ASSERT(ASRUtils::all_args_evaluated(args)); - ASR::ttype_t* arg_type = ASRUtils::expr_type(args[0]); if (ASR::is_a(*arg_type)) { double max_val = ASR::down_cast(args[0])->m_r; for (size_t i = 1; i < args.size(); i++) { @@ -1862,7 +1788,7 @@ namespace Max { arg_values.push_back(al, arg_value); } if (is_compile_time) { - ASR::expr_t *value = eval_Max(al, loc, arg_values); + ASR::expr_t *value = eval_Max(al, loc, expr_type(args[0]), arg_values); return ASR::make_IntrinsicFunction_t(al, loc, static_cast(ASRUtils::IntrinsicFunctions::Max), args.p, args.n, 0, ASRUtils::expr_type(args[0]), value); @@ -1874,10 +1800,12 @@ namespace Max { } static inline ASR::expr_t* instantiate_Max(Allocator &al, const Location &loc, - SymbolTable *scope, Vec& arg_types, + SymbolTable *scope, Vec& arg_types, ASR::ttype_t *return_type, Vec& new_args, int64_t /*overload_id*/, ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } std::string func_name = "_lcompilers_max0_" + type_to_str_python(arg_types[0]); - ASR::ttype_t *return_type = arg_types[0]; std::string fn_name = scope->get_unique_name(func_name); SymbolTable *fn_symtab = al.make_new(scope); Vec args; @@ -1888,8 +1816,7 @@ namespace Max { if (scope->get_symbol(fn_name)) { ASR::symbol_t *s = scope->get_symbol(fn_name); ASR::Function_t *f = ASR::down_cast(s); - return b.Call(s, new_args, expr_type(f->m_return_var), - compile_time_value); + return b.Call(s, new_args, expr_type(f->m_return_var), nullptr); } for (size_t i = 0; i < new_args.size(); i++) { fill_func_arg("x" + std::to_string(i), arg_types[0]); @@ -1898,23 +1825,24 @@ namespace Max { auto result = declare(fn_name, return_type, ReturnVar); ASR::expr_t* test; - body.push_back(al, Assignment(result, args[0])); + body.push_back(al, b.Assignment(result, args[0])); for (size_t i = 1; i < args.size(); i++) { test = make_Compare(make_IntegerCompare_t, args[i], Gt, result); Vec if_body; if_body.reserve(al, 1); - if_body.push_back(al, Assignment(result, args[i])); + if_body.push_back(al, b.Assignment(result, args[i])); body.push_back(al, STMT(ASR::make_If_t(al, loc, test, if_body.p, if_body.n, nullptr, 0))); } ASR::symbol_t *f_sym = make_Function_t(fn_name, fn_symtab, dep, args, body, result, Source, Implementation, nullptr); scope->add_symbol(fn_name, f_sym); - return b.Call(f_sym, new_args, return_type, compile_time_value); + return b.Call(f_sym, new_args, return_type, nullptr); } -} // namespace max0 +} // namespace Max namespace Min { + static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { ASRUtils::require_impl(x.n_args > 1, "ASR Verify: Call to min0 must have at least two arguments", x.base.base.loc, diagnostics); @@ -1932,9 +1860,9 @@ namespace Min { } } - static ASR::expr_t *eval_Min(Allocator &al, const Location &loc, Vec &args) { + static ASR::expr_t *eval_Min(Allocator &al, const Location &loc, + ASR::ttype_t *arg_type, Vec &args) { LCOMPILERS_ASSERT(ASRUtils::all_args_evaluated(args)); - ASR::ttype_t* arg_type = ASRUtils::expr_type(args[0]); if (ASR::is_a(*arg_type)) { double min_val = ASR::down_cast(args[0])->m_r; for (size_t i = 1; i < args.size(); i++) { @@ -1975,7 +1903,7 @@ namespace Min { arg_values.push_back(al, arg_value); } if (is_compile_time) { - ASR::expr_t *value = eval_Min(al, loc, arg_values); + ASR::expr_t *value = eval_Min(al, loc, expr_type(args[0]), arg_values); return ASR::make_IntrinsicFunction_t(al, loc, static_cast(ASRUtils::IntrinsicFunctions::Min), args.p, args.n, 0, ASRUtils::expr_type(args[0]), value); @@ -1987,10 +1915,12 @@ namespace Min { } static inline ASR::expr_t* instantiate_Min(Allocator &al, const Location &loc, - SymbolTable *scope, Vec& arg_types, + SymbolTable *scope, Vec& arg_types, ASR::ttype_t *return_type, Vec& new_args, int64_t /*overload_id*/, ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } std::string func_name = "_lcompilers_min0_" + type_to_str_python(arg_types[0]); - ASR::ttype_t *return_type = arg_types[0]; std::string fn_name = scope->get_unique_name(func_name); SymbolTable *fn_symtab = al.make_new(scope); Vec args; @@ -2001,8 +1931,7 @@ namespace Min { if (scope->get_symbol(fn_name)) { ASR::symbol_t *s = scope->get_symbol(fn_name); ASR::Function_t *f = ASR::down_cast(s); - return b.Call(s, new_args, expr_type(f->m_return_var), - compile_time_value); + return b.Call(s, new_args, expr_type(f->m_return_var), nullptr); } for (size_t i = 0; i < new_args.size(); i++) { fill_func_arg("x" + std::to_string(i), arg_types[0]); @@ -2011,12 +1940,12 @@ namespace Min { auto result = declare(fn_name, return_type, ReturnVar); ASR::expr_t* test; - body.push_back(al, Assignment(result, args[0])); + body.push_back(al, b.Assignment(result, args[0])); if (return_type->type == ASR::ttypeType::Integer) { for (size_t i = 1; i < args.size(); i++) { test = make_Compare(make_IntegerCompare_t, args[i], Lt, result); Vec if_body; if_body.reserve(al, 1); - if_body.push_back(al, Assignment(result, args[i])); + if_body.push_back(al, b.Assignment(result, args[i])); body.push_back(al, STMT(ASR::make_If_t(al, loc, test, if_body.p, if_body.n, nullptr, 0))); } @@ -2024,7 +1953,7 @@ namespace Min { for (size_t i = 1; i < args.size(); i++) { test = make_Compare(make_RealCompare_t, args[i], Lt, result); Vec if_body; if_body.reserve(al, 1); - if_body.push_back(al, Assignment(result, args[i])); + if_body.push_back(al, b.Assignment(result, args[i])); body.push_back(al, STMT(ASR::make_If_t(al, loc, test, if_body.p, if_body.n, nullptr, 0))); } @@ -2034,619 +1963,10 @@ namespace Min { ASR::symbol_t *f_sym = make_Function_t(fn_name, fn_symtab, dep, args, body, result, Source, Implementation, nullptr); scope->add_symbol(fn_name, f_sym); - return b.Call(f_sym, new_args, return_type, compile_time_value); - } - -} // namespace min0 - -typedef ASR::expr_t* (ASRBuilder::*elemental_operation_func)(ASR::expr_t*, ASR::expr_t*, const Location&, ASR::expr_t*); - -namespace ArrIntrinsic { - -static inline void verify_array_int_real_cmplx(ASR::expr_t* array, ASR::ttype_t* return_type, - const Location& loc, diag::Diagnostics& diagnostics, ASRUtils::IntrinsicFunctions intrinsic_func_id) { - std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - ASRUtils::require_impl(ASRUtils::is_integer(*array_type) || - ASRUtils::is_real(*array_type) || - ASRUtils::is_complex(*array_type), - "Input to " + intrinsic_func_name + " intrinsic must be of integer, real or complex type, found: " + - ASRUtils::get_type_code(array_type), loc, diagnostics); - int array_n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); - ASRUtils::require_impl(array_n_dims > 0, "Input to " + intrinsic_func_name + " intrinsic must always be an array", - loc, diagnostics); - ASRUtils::require_impl(ASRUtils::check_equal_type( - return_type, array_type, false), - intrinsic_func_name + " intrinsic must return an output of the same type as input", loc, diagnostics); - int return_n_dims = ASRUtils::extract_n_dims_from_ttype(return_type); - ASRUtils::require_impl(return_n_dims == 0, - intrinsic_func_name + " intrinsic output for array only input should be a scalar, found an array of " + - std::to_string(return_n_dims), loc, diagnostics); -} - -static inline void verify_array_int_real(ASR::expr_t* array, ASR::ttype_t* return_type, - const Location& loc, diag::Diagnostics& diagnostics, ASRUtils::IntrinsicFunctions intrinsic_func_id) { - std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - ASRUtils::require_impl(ASRUtils::is_integer(*array_type) || - ASRUtils::is_real(*array_type), - "Input to " + intrinsic_func_name + " intrinsic must be of integer or real type, found: " + - ASRUtils::get_type_code(array_type), loc, diagnostics); - int array_n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); - ASRUtils::require_impl(array_n_dims > 0, "Input to " + intrinsic_func_name + " intrinsic must always be an array", - loc, diagnostics); - ASRUtils::require_impl(ASRUtils::check_equal_type( - return_type, array_type, false), - intrinsic_func_name + " intrinsic must return an output of the same type as input", loc, diagnostics); - int return_n_dims = ASRUtils::extract_n_dims_from_ttype(return_type); - ASRUtils::require_impl(return_n_dims == 0, - intrinsic_func_name + " intrinsic output for array only input should be a scalar, found an array of " + - std::to_string(return_n_dims), loc, diagnostics); -} - -static inline void verify_array_dim(ASR::expr_t* array, ASR::expr_t* dim, - ASR::ttype_t* return_type, const Location& loc, diag::Diagnostics& diagnostics, ASRUtils::IntrinsicFunctions intrinsic_func_id) { - std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - ASRUtils::require_impl(ASRUtils::is_integer(*array_type) || - ASRUtils::is_real(*array_type) || - ASRUtils::is_complex(*array_type), - "Input to " + intrinsic_func_name + " intrinsic must be of integer, real or complex type, found: " + - ASRUtils::get_type_code(array_type), loc, diagnostics); - int array_n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); - ASRUtils::require_impl(array_n_dims > 0, "Input to " + intrinsic_func_name + " intrinsic must always be an array", - loc, diagnostics); - - ASRUtils::require_impl(ASRUtils::is_integer(*ASRUtils::expr_type(dim)), - "dim argument must be an integer", loc, diagnostics); - - ASRUtils::require_impl(ASRUtils::check_equal_type( - return_type, array_type, false), - intrinsic_func_name + " intrinsic must return an output of the same type as input", loc, diagnostics); - int return_n_dims = ASRUtils::extract_n_dims_from_ttype(return_type); - ASRUtils::require_impl(array_n_dims == return_n_dims + 1, - intrinsic_func_name + " intrinsic output must return an array with dimension " - "only 1 less than that of input array", - loc, diagnostics); -} - -static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics, - ASRUtils::IntrinsicFunctions intrinsic_func_id, verify_array_func verify_array) { - std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); - ASRUtils::require_impl(x.n_args >= 1, intrinsic_func_name + " intrinsic must accept at least one argument", - x.base.base.loc, diagnostics); - ASRUtils::require_impl(x.m_args[0] != nullptr, "Array argument to " + intrinsic_func_name + " intrinsic cannot be nullptr", - x.base.base.loc, diagnostics); - const int64_t id_array = 0, id_array_dim = 1, id_array_mask = 2; - const int64_t id_array_dim_mask = 3; - switch( x.m_overload_id ) { - case id_array: - case id_array_mask: { - if( x.m_overload_id == id_array_mask ) { - ASRUtils::require_impl(x.n_args == 2 && x.m_args[1] != nullptr, - "mask argument cannot be nullptr", x.base.base.loc, diagnostics); - } - verify_array(x.m_args[0], x.m_type, x.base.base.loc, diagnostics, intrinsic_func_id); - break; - } - case id_array_dim: - case id_array_dim_mask: { - if( x.m_overload_id == id_array_dim_mask ) { - ASRUtils::require_impl(x.n_args == 3 && x.m_args[2] != nullptr, - "mask argument cannot be nullptr", x.base.base.loc, diagnostics); - } - ASRUtils::require_impl(x.n_args >= 2 && x.m_args[1] != nullptr, - "dim argument to any intrinsic cannot be nullptr", - x.base.base.loc, diagnostics); - verify_array_dim(x.m_args[0], x.m_args[1], x.m_type, x.base.base.loc, diagnostics, intrinsic_func_id); - break; - } - default: { - require_impl(false, "Unrecognised overload id in " + intrinsic_func_name + " intrinsic", - x.base.base.loc, diagnostics); - } - } - if( x.m_overload_id == id_array_mask || - x.m_overload_id == id_array_dim_mask ) { - ASR::expr_t* mask = nullptr; - if( x.m_overload_id == id_array_mask ) { - mask = x.m_args[1]; - } else if( x.m_overload_id == id_array_dim_mask ) { - mask = x.m_args[2]; - } - ASR::dimension_t *array_dims, *mask_dims; - ASR::ttype_t* array_type = ASRUtils::expr_type(x.m_args[0]); - ASR::ttype_t* mask_type = ASRUtils::expr_type(mask); - size_t array_n_dims = ASRUtils::extract_dimensions_from_ttype(array_type, array_dims); - size_t mask_n_dims = ASRUtils::extract_dimensions_from_ttype(mask_type, mask_dims); - ASRUtils::require_impl(ASRUtils::dimensions_equal(array_dims, array_n_dims, mask_dims, mask_n_dims), - "The dimensions of array and mask arguments of " + intrinsic_func_name + " intrinsic must be same", - x.base.base.loc, diagnostics); - } -} - -static inline ASR::expr_t *eval_ArrIntrinsic(Allocator & /*al*/, - const Location & /*loc*/, Vec& /*args*/) { - return nullptr; -} - -static inline ASR::asr_t* create_ArrIntrinsic( - Allocator& al, const Location& loc, Vec& args, - const std::function err, - ASRUtils::IntrinsicFunctions intrinsic_func_id) { - std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); - int64_t id_array = 0, id_array_dim = 1, id_array_mask = 2; - int64_t id_array_dim_mask = 3; - int64_t overload_id = id_array; - - ASR::expr_t* array = args[0]; - ASR::expr_t *arg2 = nullptr, *arg3 = nullptr; - if( args.size() >= 2 ) { - arg2 = args[1]; - } - if( args.size() == 3 ) { - arg3 = args[2]; - } - - if( !arg2 && arg3 ) { - std::swap(arg2, arg3); - } - - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - if( arg2 && !arg3 ) { - size_t arg2_rank = ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(arg2)); - if( arg2_rank == 0 ) { - overload_id = id_array_dim; - } else { - overload_id = id_array_mask; - } - } else if( arg2 && arg3 ) { - ASR::expr_t* arg2 = args[1]; - ASR::expr_t* arg3 = args[2]; - size_t arg2_rank = ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(arg2)); - size_t arg3_rank = ASRUtils::extract_n_dims_from_ttype(ASRUtils::expr_type(arg3)); - - if( arg2_rank != 0 ) { - err("dim argument to " + intrinsic_func_name + " must be a scalar and must not be an array", - arg2->base.loc); - } - - if( arg3_rank == 0 ) { - err("mask argument to " + intrinsic_func_name + " must be an array and must not be a scalar", - arg3->base.loc); - } - - overload_id = id_array_dim_mask; - } - - // TODO: Add a check for range of values axis can take - // if axis is available at compile time - - ASR::expr_t *value = nullptr; - Vec arg_values; - arg_values.reserve(al, 3); - ASR::expr_t *array_value = ASRUtils::expr_value(array); - arg_values.push_back(al, array_value); - if( arg2 ) { - ASR::expr_t *arg2_value = ASRUtils::expr_value(arg2); - arg_values.push_back(al, arg2_value); - } - if( arg3 ) { - ASR::expr_t* mask = arg3; - ASR::expr_t *mask_value = ASRUtils::expr_value(mask); - arg_values.push_back(al, mask_value); - } - value = eval_ArrIntrinsic(al, loc, arg_values); - - ASR::ttype_t* return_type = nullptr; - if( overload_id == id_array || - overload_id == id_array_mask ) { - return_type = ASRUtils::duplicate_type_without_dims( - al, array_type, loc); - } else if( overload_id == id_array_dim || - overload_id == id_array_dim_mask ) { - Vec dims; - size_t n_dims = ASRUtils::extract_n_dims_from_ttype(array_type); - dims.reserve(al, (int) n_dims - 1); - for( int i = 0; i < (int) n_dims - 1; i++ ) { - ASR::dimension_t dim; - dim.loc = array->base.loc; - dim.m_length = nullptr; - dim.m_start = nullptr; - dims.push_back(al, dim); - } - return_type = ASRUtils::duplicate_type(al, array_type, &dims); - } - - Vec arr_intrinsic_args; - arr_intrinsic_args.reserve(al, 3); - arr_intrinsic_args.push_back(al, array); - if( arg2 ) { - arr_intrinsic_args.push_back(al, arg2); - } - if( arg3 ) { - arr_intrinsic_args.push_back(al, arg3); - } - - return ASRUtils::make_IntrinsicFunction_t_util(al, loc, - static_cast(intrinsic_func_id), - arr_intrinsic_args.p, arr_intrinsic_args.n, overload_id, return_type, value); -} - -static inline void generate_body_for_array_input(Allocator& al, const Location& loc, - ASR::expr_t* array, ASR::expr_t* return_var, SymbolTable* fn_scope, - Vec& fn_body, get_initial_value_func get_initial_value, elemental_operation_func elemental_operation) { - ASRBuilder builder(al, loc); - Vec idx_vars; - Vec doloop_body; - builder.generate_reduction_intrinsic_stmts_for_scalar_output(loc, - array, fn_scope, fn_body, idx_vars, doloop_body, - [=, &al, &fn_body] { - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - ASR::ttype_t* element_type = ASRUtils::duplicate_type_without_dims(al, array_type, loc); - ASR::expr_t* initial_val = get_initial_value(al, element_type); - ASR::stmt_t* return_var_init = Assignment(return_var, initial_val); - fn_body.push_back(al, return_var_init); - }, - [=, &al, &idx_vars, &doloop_body, &builder] () { - ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); - ASR::expr_t* elemental_operation_val = (builder.*elemental_operation)(return_var, array_ref, loc, nullptr); - ASR::stmt_t* loop_invariant = Assignment(return_var, elemental_operation_val); - doloop_body.push_back(al, loop_invariant); - }); -} - -static inline void generate_body_for_array_mask_input(Allocator& al, const Location& loc, - ASR::expr_t* array, ASR::expr_t* mask, ASR::expr_t* return_var, SymbolTable* fn_scope, - Vec& fn_body, get_initial_value_func get_initial_value, elemental_operation_func elemental_operation) { - ASRBuilder builder(al, loc); - Vec idx_vars; - Vec doloop_body; - builder.generate_reduction_intrinsic_stmts_for_scalar_output(loc, - array, fn_scope, fn_body, idx_vars, doloop_body, - [=, &al, &fn_body] { - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - ASR::ttype_t* element_type = ASRUtils::duplicate_type_without_dims(al, array_type, loc); - ASR::expr_t* initial_val = get_initial_value(al, element_type); - ASR::stmt_t* return_var_init = Assignment(return_var, initial_val); - fn_body.push_back(al, return_var_init); - }, - [=, &al, &idx_vars, &doloop_body, &builder] () { - ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); - ASR::expr_t* mask_ref = PassUtils::create_array_ref(mask, idx_vars, al); - ASR::expr_t* elemental_operation_val = (builder.*elemental_operation)(return_var, array_ref, loc, nullptr); - ASR::stmt_t* loop_invariant = Assignment(return_var, elemental_operation_val); - Vec if_mask; - if_mask.reserve(al, 1); - if_mask.push_back(al, loop_invariant); - ASR::stmt_t* if_mask_ = ASRUtils::STMT(ASR::make_If_t(al, loc, - mask_ref, if_mask.p, if_mask.size(), - nullptr, 0)); - doloop_body.push_back(al, if_mask_); - }); -} - -static inline void generate_body_for_array_dim_input( - Allocator& al, const Location& loc, - ASR::expr_t* array, ASR::expr_t* dim, ASR::expr_t* result, - SymbolTable* fn_scope, Vec& fn_body, get_initial_value_func get_initial_value, - elemental_operation_func elemental_operation) { - ASRBuilder builder(al, loc); - Vec idx_vars, target_idx_vars; - Vec doloop_body; - builder.generate_reduction_intrinsic_stmts_for_array_output( - loc, array, dim, fn_scope, fn_body, - idx_vars, target_idx_vars, doloop_body, - [=, &al, &fn_body] () { - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - ASR::expr_t* initial_val = get_initial_value(al, array_type); - ASR::stmt_t* result_init = Assignment(result, initial_val); - fn_body.push_back(al, result_init); - }, - [=, &al, &idx_vars, &target_idx_vars, &doloop_body, &builder, &result] () { - ASR::expr_t* result_ref = PassUtils::create_array_ref(result, target_idx_vars, al); - ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); - ASR::expr_t* elemental_operation_val = (builder.*elemental_operation)(result_ref, array_ref, loc, nullptr); - ASR::stmt_t* loop_invariant = Assignment(result_ref, elemental_operation_val); - doloop_body.push_back(al, loop_invariant); - }); -} - -static inline void generate_body_for_array_dim_mask_input( - Allocator& al, const Location& loc, - ASR::expr_t* array, ASR::expr_t* dim, - ASR::expr_t* mask, ASR::expr_t* result, - SymbolTable* fn_scope, Vec& fn_body, - get_initial_value_func get_initial_value, elemental_operation_func elemental_operation) { - ASRBuilder builder(al, loc); - Vec idx_vars, target_idx_vars; - Vec doloop_body; - builder.generate_reduction_intrinsic_stmts_for_array_output( - loc, array, dim, fn_scope, fn_body, - idx_vars, target_idx_vars, doloop_body, - [=, &al, &fn_body] () { - ASR::ttype_t* array_type = ASRUtils::expr_type(array); - ASR::expr_t* initial_val = get_initial_value(al, array_type); - ASR::stmt_t* result_init = Assignment(result, initial_val); - fn_body.push_back(al, result_init); - }, - [=, &al, &idx_vars, &target_idx_vars, &doloop_body, &builder, &result] () { - ASR::expr_t* result_ref = PassUtils::create_array_ref(result, target_idx_vars, al); - ASR::expr_t* array_ref = PassUtils::create_array_ref(array, idx_vars, al); - ASR::expr_t* mask_ref = PassUtils::create_array_ref(mask, idx_vars, al); - ASR::expr_t* elemental_operation_val = (builder.*elemental_operation)(result_ref, array_ref, loc, nullptr); - ASR::stmt_t* loop_invariant = Assignment(result_ref, elemental_operation_val); - Vec if_mask; - if_mask.reserve(al, 1); - if_mask.push_back(al, loop_invariant); - ASR::stmt_t* if_mask_ = ASRUtils::STMT(ASR::make_If_t(al, loc, - mask_ref, if_mask.p, if_mask.size(), - nullptr, 0)); - doloop_body.push_back(al, if_mask_); - } - ); -} - -static inline ASR::expr_t* instantiate_ArrIntrinsic(Allocator &al, const Location &loc, - SymbolTable *scope, Vec& arg_types, - Vec& new_args, int64_t overload_id, - ASR::expr_t* compile_time_value, ASRUtils::IntrinsicFunctions intrinsic_func_id, - get_initial_value_func get_initial_value, elemental_operation_func elemental_operation) { - std::string intrinsic_func_name = ASRUtils::get_intrinsic_name(static_cast(intrinsic_func_id)); - ASRBuilder builder(al, loc); - ASRBuilder& b = builder; - int64_t id_array = 0, id_array_dim = 1, id_array_mask = 2; - int64_t id_array_dim_mask = 3; - - ASR::ttype_t* arg_type = ASRUtils::type_get_past_allocatable( - ASRUtils::type_get_past_pointer(arg_types[0])); - int kind = ASRUtils::extract_kind_from_ttype_t(arg_type); - int rank = ASRUtils::extract_n_dims_from_ttype(arg_type); - std::string new_name = intrinsic_func_name + "_" + std::to_string(kind) + - "_" + std::to_string(rank) + - "_" + std::to_string(overload_id); - // Check if Function is already defined. - { - std::string new_func_name = new_name; - int i = 1; - while (scope->get_symbol(new_func_name) != nullptr) { - ASR::symbol_t *s = scope->get_symbol(new_func_name); - ASR::Function_t *f = ASR::down_cast(s); - int orig_array_rank = ASRUtils::extract_n_dims_from_ttype( - ASRUtils::expr_type(f->m_args[0])); - if (ASRUtils::types_equal(ASRUtils::expr_type(f->m_args[0]), - arg_type) && orig_array_rank == rank) { - ASR::ttype_t* return_type = nullptr; - if( f->m_return_var ) { - return_type = ASRUtils::expr_type(f->m_return_var); - } else { - return_type = ASRUtils::expr_type(f->m_args[(int) f->n_args - 1]); - } - return builder.Call(s, new_args, return_type, compile_time_value); - } else { - new_func_name += std::to_string(i); - i++; - } - } + return b.Call(f_sym, new_args, return_type, nullptr); } - new_name = scope->get_unique_name(new_name, false); - SymbolTable *fn_symtab = al.make_new(scope); - - Vec args; - args.reserve(al, 1); - - ASR::ttype_t* array_type = ASRUtils::duplicate_type_with_empty_dims(al, arg_type); - fill_func_arg("array", array_type) - if( overload_id == id_array_dim || - overload_id == id_array_dim_mask ) { - ASR::ttype_t* dim_type = ASRUtils::TYPE(ASR::make_Integer_t( - al, arg_type->base.loc, 4)); - fill_func_arg("dim", dim_type) - } - if( overload_id == id_array_mask || - overload_id == id_array_dim_mask ) { - Vec mask_dims; - mask_dims.reserve(al, rank); - for( int i = 0; i < rank; i++ ) { - ASR::dimension_t mask_dim; - mask_dim.loc = arg_type->base.loc; - mask_dim.m_start = nullptr; - mask_dim.m_length = nullptr; - mask_dims.push_back(al, mask_dim); - } - ASR::ttype_t* mask_type = ASRUtils::TYPE(ASR::make_Logical_t( - al, arg_type->base.loc, 4)); - if( mask_dims.size() > 0 ) { - mask_type = ASRUtils::make_Array_t_util( - al, arg_type->base.loc, mask_type, - mask_dims.p, mask_dims.size()); - } - fill_func_arg("mask", mask_type) - } - - ASR::ttype_t* return_type = nullptr; - int result_dims = 0; - if( overload_id == id_array_mask || - overload_id == id_array ) { - return_type = ASRUtils::duplicate_type_without_dims(al, arg_type, loc); - } else if( overload_id == id_array_dim_mask || - overload_id == id_array_dim ) { - Vec dims; - size_t n_dims = ASRUtils::extract_n_dims_from_ttype(arg_type); - dims.reserve(al, (int) n_dims - 1); - for( int i = 0; i < (int) n_dims - 1; i++ ) { - ASR::dimension_t dim; - dim.loc = new_args[0].m_value->base.loc; - dim.m_length = nullptr; - dim.m_start = nullptr; - dims.push_back(al, dim); - } - result_dims = dims.size(); - return_type = ASRUtils::duplicate_type(al, arg_type, &dims); - } - LCOMPILERS_ASSERT(return_type != nullptr); - - ASR::expr_t* return_var = nullptr; - if( result_dims > 0 ) { - fill_func_arg("result", return_type) - } else if( result_dims == 0 ) { - return_var = declare("result", return_type, ReturnVar); - } - - Vec body; - body.reserve(al, 1); - ASR::expr_t* output_var = nullptr; - if( return_var ) { - output_var = return_var; - } else { - output_var = args[(int) args.size() - 1]; - } - if( overload_id == id_array ) { - generate_body_for_array_input(al, loc, args[0], output_var, - fn_symtab, body, get_initial_value, elemental_operation); - } else if( overload_id == id_array_dim ) { - generate_body_for_array_dim_input(al, loc, args[0], args[1], output_var, - fn_symtab, body, get_initial_value, elemental_operation); - } else if( overload_id == id_array_dim_mask ) { - generate_body_for_array_dim_mask_input(al, loc, args[0], args[1], args[2], - output_var, fn_symtab, body, get_initial_value, elemental_operation); - } else if( overload_id == id_array_mask ) { - generate_body_for_array_mask_input(al, loc, args[0], args[1], output_var, - fn_symtab, body, get_initial_value, elemental_operation); - } - - Vec dep; - dep.reserve(al, 1); - // TODO: fill dependencies - - ASR::symbol_t *new_symbol = nullptr; - if( return_var ) { - new_symbol = make_Function_t(new_name, fn_symtab, dep, args, - body, return_var, Source, Implementation, nullptr); - } else { - new_symbol = make_Function_Without_ReturnVar_t( - new_name, fn_symtab, dep, args, - body, Source, Implementation, nullptr); - } - scope->add_symbol(new_name, new_symbol); - return builder.Call(new_symbol, new_args, return_type, - compile_time_value); -} - -} // namespace ArrIntrinsic - -namespace Sum { - -static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { - ArrIntrinsic::verify_args(x, diagnostics, ASRUtils::IntrinsicFunctions::Sum, &ArrIntrinsic::verify_array_int_real_cmplx); -} - -static inline ASR::expr_t *eval_Sum(Allocator & /*al*/, - const Location & /*loc*/, Vec& /*args*/) { - return nullptr; -} - -static inline ASR::asr_t* create_Sum( - Allocator& al, const Location& loc, Vec& args, - const std::function err) { - return ArrIntrinsic::create_ArrIntrinsic(al, loc, args, err, ASRUtils::IntrinsicFunctions::Sum); -} - -static inline ASR::expr_t* instantiate_Sum(Allocator &al, const Location &loc, - SymbolTable *scope, Vec& arg_types, - Vec& new_args, int64_t overload_id, - ASR::expr_t* compile_time_value) { - return ArrIntrinsic::instantiate_ArrIntrinsic(al, loc, scope, arg_types, new_args, - overload_id, compile_time_value, ASRUtils::IntrinsicFunctions::Sum, - &ASRUtils::get_constant_zero_with_given_type, &ASRUtils::ASRBuilder::ElementalAdd); -} - -} // namespace Sum - -namespace Product { - -static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { - ArrIntrinsic::verify_args(x, diagnostics, ASRUtils::IntrinsicFunctions::Product, &ArrIntrinsic::verify_array_int_real_cmplx); -} - -static inline ASR::expr_t *eval_Product(Allocator & /*al*/, - const Location & /*loc*/, Vec& /*args*/) { - return nullptr; -} - -static inline ASR::asr_t* create_Product( - Allocator& al, const Location& loc, Vec& args, - const std::function err) { - return ArrIntrinsic::create_ArrIntrinsic(al, loc, args, err, ASRUtils::IntrinsicFunctions::Product); -} - -static inline ASR::expr_t* instantiate_Product(Allocator &al, const Location &loc, - SymbolTable *scope, Vec& arg_types, - Vec& new_args, int64_t overload_id, - ASR::expr_t* compile_time_value) { - return ArrIntrinsic::instantiate_ArrIntrinsic(al, loc, scope, arg_types, new_args, - overload_id, compile_time_value, ASRUtils::IntrinsicFunctions::Product, - &ASRUtils::get_constant_one_with_given_type, &ASRUtils::ASRBuilder::ElementalMul); -} - -} // namespace Product - -namespace MaxVal { - -static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { - ArrIntrinsic::verify_args(x, diagnostics, ASRUtils::IntrinsicFunctions::MaxVal, &ArrIntrinsic::verify_array_int_real); -} - -static inline ASR::expr_t *eval_MaxVal(Allocator & /*al*/, - const Location & /*loc*/, Vec& /*args*/) { - return nullptr; -} - -static inline ASR::asr_t* create_MaxVal( - Allocator& al, const Location& loc, Vec& args, - const std::function err) { - return ArrIntrinsic::create_ArrIntrinsic(al, loc, args, err, ASRUtils::IntrinsicFunctions::MaxVal); -} - -static inline ASR::expr_t* instantiate_MaxVal(Allocator &al, const Location &loc, - SymbolTable *scope, Vec& arg_types, - Vec& new_args, int64_t overload_id, - ASR::expr_t* compile_time_value) { - return ArrIntrinsic::instantiate_ArrIntrinsic(al, loc, scope, arg_types, new_args, - overload_id, compile_time_value, ASRUtils::IntrinsicFunctions::MaxVal, - &ASRUtils::get_minimum_value_with_given_type, &ASRUtils::ASRBuilder::ElementalMax); -} - -} // namespace MaxVal - -namespace MinVal { - -static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { - ArrIntrinsic::verify_args(x, diagnostics, ASRUtils::IntrinsicFunctions::MinVal, &ArrIntrinsic::verify_array_int_real); -} - -static inline ASR::expr_t *eval_MinVal(Allocator & /*al*/, - const Location & /*loc*/, Vec& /*args*/) { - return nullptr; -} - -static inline ASR::asr_t* create_MinVal( - Allocator& al, const Location& loc, Vec& args, - const std::function err) { - return ArrIntrinsic::create_ArrIntrinsic(al, loc, args, err, ASRUtils::IntrinsicFunctions::MinVal); -} - -static inline ASR::expr_t* instantiate_MinVal(Allocator &al, const Location &loc, - SymbolTable *scope, Vec& arg_types, - Vec& new_args, int64_t overload_id, - ASR::expr_t* compile_time_value) { - return ArrIntrinsic::instantiate_ArrIntrinsic(al, loc, scope, arg_types, new_args, - overload_id, compile_time_value, ASRUtils::IntrinsicFunctions::MinVal, - &ASRUtils::get_maximum_value_with_given_type, &ASRUtils::ASRBuilder::ElementalMin); -} - -} // namespace MinVal +} // namespace Min namespace Partition { @@ -2723,33 +2043,35 @@ namespace Partition { value = eval_Partition(al, loc, s_str, s_sep); } - return ASRUtils::make_IntrinsicFunction_t_util(al, loc, + return ASR::make_IntrinsicFunction_t(al, loc, static_cast(ASRUtils::IntrinsicFunctions::Partition), e_args.p, e_args.n, 0, return_type, value); } static inline ASR::expr_t *instantiate_Partition(Allocator &al, - const Location &loc, SymbolTable *scope, - Vec& /*arg_types*/, Vec& new_args, - int64_t /*overload_id*/, ASR::expr_t* compile_time_value) - { + const Location &loc, SymbolTable *scope, + Vec& /*arg_types*/, ASR::ttype_t *return_type, + Vec& new_args, int64_t /*overload_id*/, + ASR::expr_t* compile_time_value) { + if (compile_time_value) { + return compile_time_value; + } // TODO: show runtime error for empty separator or pattern declare_basic_variables("_lpython_str_partition"); fill_func_arg("target_string", character(-2)); fill_func_arg("pattern", character(-2)); - ASR::ttype_t *return_type = b.Tuple({character(-2), character(-2), character(-2)}); auto result = declare("result", return_type, ReturnVar); auto index = declare("index", int32, Local); - body.push_back(al, Assignment(index, b.Call(UnaryIntrinsicFunction:: + body.push_back(al, b.Assignment(index, b.Call(UnaryIntrinsicFunction:: create_KMP_function(al, loc, scope), args, int32))); body.push_back(al, b.If(iEq(index, i32_n(-1)), { - Assignment(result, b.TupleConstant({ args[0], + b.Assignment(result, b.TupleConstant({ args[0], StringConstant("", character(0)), StringConstant("", character(0)) }, b.Tuple({character(-2), character(0), character(0)}))) }, { - Assignment(result, b.TupleConstant({ + b.Assignment(result, b.TupleConstant({ StringSection(args[0], i32(0), index), args[1], StringSection(args[0], iAdd(index, StringLen(args[1])), StringLen(args[0]))}, return_type)) @@ -2758,171 +2080,10 @@ namespace Partition { ASR::symbol_t *fn_sym = make_Function_t(fn_name, fn_symtab, dep, args, body, result, Source, Implementation, nullptr); scope->add_symbol(fn_name, fn_sym); - return b.Call(fn_sym, new_args, return_type, compile_time_value); - } -} // namespace Partition - -namespace Merge { - - static inline ASR::expr_t* eval_Merge( - Allocator &/*al*/, const Location &/*loc*/, Vec& args) { - LCOMPILERS_ASSERT(args.size() == 3); - ASR::expr_t *tsource = args[0], *fsource = args[1], *mask = args[2]; - if( ASRUtils::is_array(ASRUtils::expr_type(mask)) ) { - return nullptr; - } - - bool mask_value = false; - if( ASRUtils::is_value_constant(mask, mask_value) ) { - if( mask_value ) { - return tsource; - } else { - return fsource; - } - } - return nullptr; - } - - static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnostics& diagnostics) { - const Location& loc = x.base.base.loc; - ASR::expr_t *tsource = x.m_args[0], *fsource = x.m_args[1], *mask = x.m_args[2]; - ASR::ttype_t *tsource_type = ASRUtils::expr_type(tsource); - ASR::ttype_t *fsource_type = ASRUtils::expr_type(fsource); - ASR::ttype_t *mask_type = ASRUtils::expr_type(mask); - int tsource_ndims, fsource_ndims; - ASR::dimension_t *tsource_mdims = nullptr, *fsource_mdims = nullptr; - tsource_ndims = ASRUtils::extract_dimensions_from_ttype(tsource_type, tsource_mdims); - fsource_ndims = ASRUtils::extract_dimensions_from_ttype(fsource_type, fsource_mdims); - if( tsource_ndims > 0 && fsource_ndims > 0 ) { - ASRUtils::require_impl(tsource_ndims == fsource_ndims, - "All arguments of `merge` should be of same rank and dimensions", loc, diagnostics); - - if( ASRUtils::extract_physical_type(tsource_type) == ASR::array_physical_typeType::FixedSizeArray && - ASRUtils::extract_physical_type(fsource_type) == ASR::array_physical_typeType::FixedSizeArray ) { - ASRUtils::require_impl(ASRUtils::get_fixed_size_of_array(tsource_mdims, tsource_ndims) == - ASRUtils::get_fixed_size_of_array(fsource_mdims, fsource_ndims), - "`tsource` and `fsource` arguments should have matching size", loc, diagnostics); - } - } - - ASRUtils::require_impl(ASRUtils::check_equal_type(tsource_type, fsource_type), - "`tsource` and `fsource` arguments to `merge` should be of same type, found " + - ASRUtils::get_type_code(tsource_type) + ", " + - ASRUtils::get_type_code(fsource_type), loc, diagnostics); - ASRUtils::require_impl(ASRUtils::is_logical(*mask_type), - "`mask` argument to `merge` should be of logical type, found " + - ASRUtils::get_type_code(mask_type), loc, diagnostics); + return b.Call(fn_sym, new_args, return_type, nullptr); } - static inline ASR::asr_t* create_Merge(Allocator& al, const Location& loc, - Vec& args, - const std::function err) { - if( args.size() != 3 ) { - err("`merge` intrinsic accepts 3 positional arguments, found " + - std::to_string(args.size()), loc); - } - - ASR::expr_t *tsource = args[0], *fsource = args[1], *mask = args[2]; - ASR::ttype_t *tsource_type = ASRUtils::expr_type(tsource); - ASR::ttype_t *fsource_type = ASRUtils::expr_type(fsource); - ASR::ttype_t *mask_type = ASRUtils::expr_type(mask); - ASR::ttype_t* result_type = tsource_type; - int tsource_ndims, fsource_ndims, mask_ndims; - ASR::dimension_t *tsource_mdims = nullptr, *fsource_mdims = nullptr, *mask_mdims = nullptr; - tsource_ndims = ASRUtils::extract_dimensions_from_ttype(tsource_type, tsource_mdims); - fsource_ndims = ASRUtils::extract_dimensions_from_ttype(fsource_type, fsource_mdims); - mask_ndims = ASRUtils::extract_dimensions_from_ttype(mask_type, mask_mdims); - if( tsource_ndims > 0 && fsource_ndims > 0 ) { - if( tsource_ndims != fsource_ndims ) { - err("All arguments of `merge` should be of same rank and dimensions", loc); - } - - if( ASRUtils::extract_physical_type(tsource_type) == ASR::array_physical_typeType::FixedSizeArray && - ASRUtils::extract_physical_type(fsource_type) == ASR::array_physical_typeType::FixedSizeArray && - ASRUtils::get_fixed_size_of_array(tsource_mdims, tsource_ndims) != - ASRUtils::get_fixed_size_of_array(fsource_mdims, fsource_ndims) ) { - err("`tsource` and `fsource` arguments should have matching size", loc); - } - } else { - if( tsource_ndims > 0 && fsource_ndims == 0 ) { - result_type = tsource_type; - } else if( tsource_ndims == 0 && fsource_ndims > 0 ) { - result_type = fsource_type; - } else if( tsource_ndims == 0 && fsource_ndims == 0 && mask_ndims > 0 ) { - Vec mask_mdims_vec; - mask_mdims_vec.from_pointer_n(mask_mdims, mask_ndims); - result_type = ASRUtils::duplicate_type(al, tsource_type, &mask_mdims_vec, - ASRUtils::extract_physical_type(mask_type), true); - if( ASR::is_a(*mask_type) ) { - result_type = ASRUtils::TYPE(ASR::make_Allocatable_t(al, loc, result_type)); - } - } - } - if( !ASRUtils::check_equal_type(tsource_type, fsource_type) ) { - err("`tsource` and `fsource` arguments to `merge` should be of same type, found " + - ASRUtils::get_type_code(tsource_type) + ", " + - ASRUtils::get_type_code(fsource_type), loc); - } - if( !ASRUtils::is_logical(*mask_type) ) { - err("`mask` argument to `merge` should be of logical type, found " + - ASRUtils::get_type_code(mask_type), loc); - } - - return ASR::make_IntrinsicFunction_t(al, loc, - static_cast(ASRUtils::IntrinsicFunctions::Merge), - args.p, args.size(), 0, result_type, nullptr); - } - - static inline ASR::expr_t* instantiate_Merge(Allocator &al, - const Location &loc, SymbolTable *scope, - Vec& arg_types, Vec& new_args, - int64_t /*overload_id*/, ASR::expr_t* compile_time_value) { - LCOMPILERS_ASSERT(arg_types.size() == 3); - - // Array inputs should be elementalised in array_op pass already - LCOMPILERS_ASSERT( !ASRUtils::is_array(arg_types[2]) ); - ASR::ttype_t *tsource_type = ASRUtils::duplicate_type(al, arg_types[0]); - ASR::ttype_t *fsource_type = ASRUtils::duplicate_type(al, arg_types[1]); - ASR::ttype_t *mask_type = ASRUtils::duplicate_type(al, arg_types[2]); - if( ASR::is_a(*tsource_type) ) { - ASR::Character_t* tsource_char = ASR::down_cast(tsource_type); - ASR::Character_t* fsource_char = ASR::down_cast(fsource_type); - tsource_char->m_len_expr = nullptr; fsource_char->m_len_expr = nullptr; - tsource_char->m_len = -2; fsource_char->m_len = -2; - } - std::string new_name = "_lcompilers_merge_" + get_type_code(tsource_type); - - declare_basic_variables(new_name); - if (scope->get_symbol(new_name)) { - ASR::symbol_t *s = scope->get_symbol(new_name); - ASR::Function_t *f = ASR::down_cast(s); - return b.Call(s, new_args, expr_type(f->m_return_var), compile_time_value); - } - - auto tsource_arg = declare("tsource", tsource_type, In); - args.push_back(al, tsource_arg); - auto fsource_arg = declare("fsource", fsource_type, In); - args.push_back(al, fsource_arg); - auto mask_arg = declare("mask", mask_type, In); - args.push_back(al, mask_arg); - // TODO: In case of Character type, set len of ReturnVar to len(tsource) expression - auto result = declare("merge", tsource_type, ReturnVar); - - { - Vec if_body; if_body.reserve(al, 1); - if_body.push_back(al, Assignment(result, tsource_arg)); - Vec else_body; else_body.reserve(al, 1); - else_body.push_back(al, Assignment(result, fsource_arg)); - body.push_back(al, STMT(ASR::make_If_t(al, loc, mask_arg, - if_body.p, if_body.n, else_body.p, else_body.n))); - } - - ASR::symbol_t *new_symbol = make_Function_t(fn_name, fn_symtab, dep, args, - body, result, Source, Implementation, nullptr); - scope->add_symbol(fn_name, new_symbol); - return b.Call(new_symbol, new_args, tsource_type, compile_time_value); - } -} +} // namespace Partition namespace SymbolicSymbol { @@ -2939,7 +2100,7 @@ namespace SymbolicSymbol { } static inline ASR::expr_t *eval_SymbolicSymbol(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t *, Vec& /*args*/) { // TODO return nullptr; } @@ -2964,13 +2125,12 @@ namespace SymbolicSymbol { } // namespace SymbolicSymbol -#define create_symbolic_binary_macro(X) \ +#define create_symbolic_binary_macro(X) \ namespace X{ \ - \ static inline void verify_args(const ASR::IntrinsicFunction_t& x, \ diag::Diagnostics& diagnostics) { \ - ASRUtils::require_impl(x.n_args == 2, "Intrinsic function `"#X"` accepts \ - exactly 2 arguments", x.base.base.loc, diagnostics); \ + ASRUtils::require_impl(x.n_args == 2, "Intrinsic function `"#X"` accepts" \ + "exactly 2 arguments", x.base.base.loc, diagnostics); \ \ ASR::ttype_t* left_type = ASRUtils::expr_type(x.m_args[0]); \ ASR::ttype_t* right_type = ASRUtils::expr_type(x.m_args[1]); \ @@ -2982,7 +2142,7 @@ namespace X{ } \ \ static inline ASR::expr_t* eval_##X(Allocator &/*al*/, const Location &/*loc*/, \ - Vec &/*args*/) { \ + ASR::ttype_t *, Vec &/*args*/) { \ /*TODO*/ \ return nullptr; \ } \ @@ -3007,8 +2167,8 @@ namespace X{ for( size_t i = 0; i < args.size(); i++ ) { \ arg_values.push_back(al, ASRUtils::expr_value(args[i])); \ } \ - ASR::expr_t* compile_time_value = eval_##X(al, loc, arg_values); \ ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); \ + ASR::expr_t* compile_time_value = eval_##X(al, loc, to_type, arg_values); \ return ASR::make_IntrinsicFunction_t(al, loc, \ static_cast(ASRUtils::IntrinsicFunctions::X), \ args.p, args.size(), 0, to_type, compile_time_value); \ @@ -3030,7 +2190,7 @@ namespace SymbolicPi { } static inline ASR::expr_t *eval_SymbolicPi(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t *, Vec& /*args*/) { // TODO return nullptr; } @@ -3038,8 +2198,8 @@ namespace SymbolicPi { static inline ASR::asr_t* create_SymbolicPi(Allocator& al, const Location& loc, Vec& args, const std::function /*err*/) { - ASR::expr_t* compile_time_value = eval_SymbolicPi(al, loc, args); ASR::ttype_t *to_type = ASRUtils::TYPE(ASR::make_SymbolicExpression_t(al, loc)); + ASR::expr_t* compile_time_value = eval_SymbolicPi(al, loc, to_type, args); return ASR::make_IntrinsicFunction_t(al, loc, static_cast(ASRUtils::IntrinsicFunctions::SymbolicPi), nullptr, 0, 0, to_type, compile_time_value); @@ -3061,7 +2221,7 @@ namespace SymbolicInteger { } static inline ASR::expr_t* eval_SymbolicInteger(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t *, Vec& /*args*/) { // TODO return nullptr; } @@ -3073,11 +2233,11 @@ namespace SymbolicInteger { return UnaryIntrinsicFunction::create_UnaryFunction(al, loc, args, eval_SymbolicInteger, static_cast(ASRUtils::IntrinsicFunctions::SymbolicInteger), 0, to_type); } + } // namespace SymbolicInteger #define create_symbolic_unary_macro(X) \ namespace X { \ - \ static inline void verify_args(const ASR::IntrinsicFunction_t& x, \ diag::Diagnostics& diagnostics) { \ const Location& loc = x.base.base.loc; \ @@ -3090,7 +2250,7 @@ namespace X { } \ \ static inline ASR::expr_t* eval_##X(Allocator &/*al*/, const Location &/*loc*/, \ - Vec &/*args*/) { \ + ASR::ttype_t *, Vec &/*args*/) { \ /*TODO*/ \ return nullptr; \ } \ @@ -3112,7 +2272,6 @@ namespace X { return UnaryIntrinsicFunction::create_UnaryFunction(al, loc, args, eval_##X, \ static_cast(ASRUtils::IntrinsicFunctions::X), 0, to_type); \ } \ - \ } // namespace X create_symbolic_unary_macro(SymbolicSin) @@ -3130,7 +2289,6 @@ namespace IntrinsicFunctionRegistry { verify_function>>& intrinsic_function_by_id_db = { {static_cast(ASRUtils::IntrinsicFunctions::LogGamma), {&LogGamma::instantiate_LogGamma, &UnaryIntrinsicFunction::verify_args}}, - {static_cast(ASRUtils::IntrinsicFunctions::Sin), {&Sin::instantiate_Sin, &UnaryIntrinsicFunction::verify_args}}, {static_cast(ASRUtils::IntrinsicFunctions::Cos), @@ -3157,12 +2315,6 @@ namespace IntrinsicFunctionRegistry { {nullptr, &UnaryIntrinsicFunction::verify_args}}, {static_cast(ASRUtils::IntrinsicFunctions::Abs), {&Abs::instantiate_Abs, &Abs::verify_args}}, - {static_cast(ASRUtils::IntrinsicFunctions::Any), - {&Any::instantiate_Any, &Any::verify_args}}, - {static_cast(ASRUtils::IntrinsicFunctions::Sum), - {&Sum::instantiate_Sum, &Sum::verify_args}}, - {static_cast(ASRUtils::IntrinsicFunctions::Product), - {&Product::instantiate_Product, &Product::verify_args}}, {static_cast(ASRUtils::IntrinsicFunctions::Partition), {&Partition::instantiate_Partition, &Partition::verify_args}}, {static_cast(ASRUtils::IntrinsicFunctions::ListIndex), @@ -3183,14 +2335,10 @@ namespace IntrinsicFunctionRegistry { {nullptr, &SetRemove::verify_args}}, {static_cast(ASRUtils::IntrinsicFunctions::Max), {&Max::instantiate_Max, &Max::verify_args}}, - {static_cast(ASRUtils::IntrinsicFunctions::MaxVal), - {&MaxVal::instantiate_MaxVal, &MaxVal::verify_args}}, {static_cast(ASRUtils::IntrinsicFunctions::Min), {&Min::instantiate_Min, &Min::verify_args}}, - {static_cast(ASRUtils::IntrinsicFunctions::MinVal), - {&MinVal::instantiate_MinVal, &MinVal::verify_args}}, - {static_cast(ASRUtils::IntrinsicFunctions::Merge), - {&Merge::instantiate_Merge, &Merge::verify_args}}, + {static_cast(ASRUtils::IntrinsicFunctions::Sign), + {&Sign::instantiate_Sign, &Sign::verify_args}}, {static_cast(ASRUtils::IntrinsicFunctions::SymbolicSymbol), {nullptr, &SymbolicSymbol::verify_args}}, {static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd), @@ -3269,22 +2417,12 @@ namespace IntrinsicFunctionRegistry { "set.add"}, {static_cast(ASRUtils::IntrinsicFunctions::SetRemove), "set.remove"}, - {static_cast(ASRUtils::IntrinsicFunctions::Any), - "any"}, - {static_cast(ASRUtils::IntrinsicFunctions::Sum), - "sum"}, - {static_cast(ASRUtils::IntrinsicFunctions::Product), - "product"}, {static_cast(ASRUtils::IntrinsicFunctions::Max), "max"}, - {static_cast(ASRUtils::IntrinsicFunctions::MaxVal), - "maxval"}, {static_cast(ASRUtils::IntrinsicFunctions::Min), "min"}, - {static_cast(ASRUtils::IntrinsicFunctions::MinVal), - "minval"}, - {static_cast(ASRUtils::IntrinsicFunctions::Merge), - "merge"}, + {static_cast(ASRUtils::IntrinsicFunctions::Sign), + "sign"}, {static_cast(ASRUtils::IntrinsicFunctions::SymbolicSymbol), "Symbol"}, {static_cast(ASRUtils::IntrinsicFunctions::SymbolicAdd), @@ -3315,10 +2453,6 @@ namespace IntrinsicFunctionRegistry { "SymbolicExp"}, {static_cast(ASRUtils::IntrinsicFunctions::SymbolicAbs), "SymbolicAbs"}, - {static_cast(ASRUtils::IntrinsicFunctions::Any), - "any"}, - {static_cast(ASRUtils::IntrinsicFunctions::Sum), - "sum"} }; @@ -3339,9 +2473,6 @@ namespace IntrinsicFunctionRegistry { {"exp", {&Exp::create_Exp, &Exp::eval_Exp}}, {"exp2", {&Exp2::create_Exp2, &Exp2::eval_Exp2}}, {"expm1", {&Expm1::create_Expm1, &Expm1::eval_Expm1}}, - {"any", {&Any::create_Any, &Any::eval_Any}}, - {"sum", {&Sum::create_Sum, &Sum::eval_Sum}}, - {"product", {&Product::create_Product, &Product::eval_Product}}, {"list.index", {&ListIndex::create_ListIndex, &ListIndex::eval_list_index}}, {"list.reverse", {&ListReverse::create_ListReverse, &ListReverse::eval_list_reverse}}, {"list.pop", {&ListPop::create_ListPop, &ListPop::eval_list_pop}}, @@ -3351,11 +2482,9 @@ namespace IntrinsicFunctionRegistry { {"set.add", {&SetAdd::create_SetAdd, &SetAdd::eval_set_add}}, {"set.remove", {&SetRemove::create_SetRemove, &SetRemove::eval_set_remove}}, {"max0", {&Max::create_Max, &Max::eval_Max}}, - {"maxval", {&MaxVal::create_MaxVal, &MaxVal::eval_MaxVal}}, {"min0", {&Min::create_Min, &Min::eval_Min}}, {"min", {&Min::create_Min, &Min::eval_Min}}, - {"minval", {&MinVal::create_MinVal, &MinVal::eval_MinVal}}, - {"merge", {&Merge::create_Merge, &Merge::eval_Merge}}, + {"sign", {&Sign::create_Sign, &Sign::eval_Sign}}, {"Symbol", {&SymbolicSymbol::create_SymbolicSymbol, &SymbolicSymbol::eval_SymbolicSymbol}}, {"SymbolicAdd", {&SymbolicAdd::create_SymbolicAdd, &SymbolicAdd::eval_SymbolicAdd}}, {"SymbolicSub", {&SymbolicSub::create_SymbolicSub, &SymbolicSub::eval_SymbolicSub}}, @@ -3371,7 +2500,6 @@ namespace IntrinsicFunctionRegistry { {"SymbolicLog", {&SymbolicLog::create_SymbolicLog, &SymbolicLog::eval_SymbolicLog}}, {"SymbolicExp", {&SymbolicExp::create_SymbolicExp, &SymbolicExp::eval_SymbolicExp}}, {"SymbolicAbs", {&SymbolicAbs::create_SymbolicAbs, &SymbolicAbs::eval_SymbolicAbs}}, - }; static inline bool is_intrinsic_function(const std::string& name) { @@ -3392,32 +2520,9 @@ namespace IntrinsicFunctionRegistry { id_ == ASRUtils::IntrinsicFunctions::Exp || id_ == ASRUtils::IntrinsicFunctions::Exp2 || id_ == ASRUtils::IntrinsicFunctions::Expm1 || - id_ == ASRUtils::IntrinsicFunctions::Merge || id_ == ASRUtils::IntrinsicFunctions::SymbolicSymbol); } - /* - The function gives the index of the dim a.k.a axis argument - for the intrinsic with the given id. Most of the time - dim is specified via second argument (i.e., index 1) but - still its better to encapsulate it in the following - function and then call it to get the index of the dim - argument whenever needed. This helps in limiting - the API changes of the intrinsic to this function only. - */ - static inline int get_dim_index(ASRUtils::IntrinsicFunctions id) { - if( id == ASRUtils::IntrinsicFunctions::Any || - id == ASRUtils::IntrinsicFunctions::Sum || - id == ASRUtils::IntrinsicFunctions::Product || - id == ASRUtils::IntrinsicFunctions::MaxVal || - id == ASRUtils::IntrinsicFunctions::MinVal) { - return 1; - } else { - LCOMPILERS_ASSERT(false); - } - return -1; - } - static inline create_intrinsic_function get_create_function(const std::string& name) { return std::get<0>(intrinsic_function_by_name_db.at(name)); } @@ -3513,8 +2618,6 @@ inline std::string get_impure_intrinsic_name(int x) { switch (x) { IMPURE_INTRINSIC_NAME_CASE(IsIostatEnd) IMPURE_INTRINSIC_NAME_CASE(IsIostatEor) - INTRINSIC_NAME_CASE(Max) - INTRINSIC_NAME_CASE(Min) default : { throw LCompilersException("pickle: intrinsic_id not implemented"); } diff --git a/src/libasr/pass/where.cpp b/src/libasr/pass/where.cpp index e1ad88c7fc..e1195022b4 100644 --- a/src/libasr/pass/where.cpp +++ b/src/libasr/pass/where.cpp @@ -106,7 +106,7 @@ class ReplaceVar : public ASR::BaseExprReplacer args.push_back(al, *current_expr); } ASR::ttype_t* type = ASRUtils::expr_type(args[0]); - ASR::expr_t* new_expr = ASRUtils::EXPR(ASRUtils::make_IntrinsicFunction_t_util(al, x->base.base.loc, x->m_intrinsic_id, args.p, x->n_args, x->m_overload_id, type, x->m_value)); + ASR::expr_t* new_expr = ASRUtils::EXPR(ASR::make_IntrinsicFunction_t(al, x->base.base.loc, x->m_intrinsic_id, args.p, x->n_args, x->m_overload_id, type, x->m_value)); *current_expr = new_expr; } diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 8de852e00d..33069a63cf 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -7426,11 +7426,16 @@ class BodyVisitor : public CommonVisitor { imported_functions[call_name] == "sympy"){ intrinsic_name = "Symbolic" + std::string(1, std::toupper(call_name[0])) + call_name.substr(1); } - if (ASRUtils::IntrinsicFunctionRegistry::is_intrinsic_function(intrinsic_name) && + if ((ASRUtils::IntrinsicFunctionRegistry::is_intrinsic_function(intrinsic_name) || + ASRUtils::IntrinsicArrayFunctionRegistry::is_intrinsic_function(intrinsic_name)) && (not_cpython_builtin.find(call_name) == not_cpython_builtin.end() || imported_functions.find(call_name) != imported_functions.end() )) { - ASRUtils::create_intrinsic_function create_func = - ASRUtils::IntrinsicFunctionRegistry::get_create_function(intrinsic_name); + ASRUtils::create_intrinsic_function create_func; + if (ASRUtils::IntrinsicFunctionRegistry::is_intrinsic_function(intrinsic_name)) { + create_func = ASRUtils::IntrinsicFunctionRegistry::get_create_function(intrinsic_name); + } else { + create_func = ASRUtils::IntrinsicArrayFunctionRegistry::get_create_function(intrinsic_name); + } Vec args_; args_.reserve(al, x.n_args); visit_expr_list(x.m_args, x.n_args, args_); if (ASRUtils::is_array(ASRUtils::expr_type(args_[0])) && From 33990ad82d4b0b8f51e3e65976046dd9b6c93fdc Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Sat, 12 Aug 2023 17:26:51 +0530 Subject: [PATCH 2/4] Fixes --- src/libasr/asr_utils.h | 6 ++++++ src/libasr/pass/array_op.cpp | 2 +- src/libasr/pass/intrinsic_function_registry.h | 20 +++++++++---------- src/libasr/pass/pass_utils.cpp | 10 +++++----- src/lpython/pickle.cpp | 15 ++++++++++++++ src/lpython/semantics/python_ast_to_asr.cpp | 1 + 6 files changed, 38 insertions(+), 16 deletions(-) diff --git a/src/libasr/asr_utils.h b/src/libasr/asr_utils.h index 638bc96d00..d468ad7d83 100644 --- a/src/libasr/asr_utils.h +++ b/src/libasr/asr_utils.h @@ -1831,6 +1831,12 @@ static inline bool is_fixed_size_array(ASR::dimension_t* m_dims, size_t n_dims) return true; } +static inline ASR::ttype_t *extract_type(ASR::ttype_t *type) { + return type_get_past_array( + type_get_past_allocatable( + type_get_past_pointer(type))); +} + static inline bool is_fixed_size_array(ASR::ttype_t* type) { ASR::dimension_t* m_dims = nullptr; size_t n_dims = ASRUtils::extract_dimensions_from_ttype(type, m_dims); diff --git a/src/libasr/pass/array_op.cpp b/src/libasr/pass/array_op.cpp index 9e31279fd0..8f5d99f3d3 100644 --- a/src/libasr/pass/array_op.cpp +++ b/src/libasr/pass/array_op.cpp @@ -1005,7 +1005,7 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { x->m_args = ref_args.p; x->n_args = ref_args.size(); x->m_type = dim_less_type; - ASR::expr_t* op_el_wise = ASRUtils::EXPR((ASR::asr_t *) + ASR::expr_t* op_el_wise = ASRUtils::EXPR((ASR::asr_t *)x); ASR::expr_t* res = PassUtils::create_array_ref(result_var, idx_vars, al); ASR::stmt_t* assign = ASRUtils::STMT(ASR::make_Assignment_t(al, loc, res, op_el_wise, nullptr)); doloop_body.push_back(al, assign); diff --git a/src/libasr/pass/intrinsic_function_registry.h b/src/libasr/pass/intrinsic_function_registry.h index 6bdf91c50d..be69e2cd90 100644 --- a/src/libasr/pass/intrinsic_function_registry.h +++ b/src/libasr/pass/intrinsic_function_registry.h @@ -1504,7 +1504,7 @@ static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnost } static inline ASR::expr_t *eval_reserve(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t *, Vec& /*args*/) { // TODO: To be implemented for ListConstant expression return nullptr; } @@ -1527,7 +1527,7 @@ static inline ASR::asr_t* create_Reserve(Allocator& al, const Location& loc, for( size_t i = 0; i < args.size(); i++ ) { arg_values.push_back(al, ASRUtils::expr_value(args[i])); } - ASR::expr_t* compile_time_value = eval_reserve(al, loc, arg_values); + ASR::expr_t* compile_time_value = eval_reserve(al, loc, nullptr, arg_values); return ASR::make_Expr_t(al, loc, ASRUtils::EXPR(ASRUtils::make_IntrinsicFunction_t_util(al, loc, static_cast(ASRUtils::IntrinsicFunctions::Reserve), @@ -1552,7 +1552,7 @@ static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnost } static inline ASR::expr_t *eval_dict_keys(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t *, Vec& /*args*/) { // TODO: To be implemented for DictConstant expression return nullptr; } @@ -1573,8 +1573,8 @@ static inline ASR::asr_t* create_DictKeys(Allocator& al, const Location& loc, for( size_t i = 0; i < args.size(); i++ ) { arg_values.push_back(al, ASRUtils::expr_value(args[i])); } - ASR::expr_t* compile_time_value = eval_dict_keys(al, loc, arg_values); ASR::ttype_t *to_type = List(dict_keys_type); + ASR::expr_t* compile_time_value = eval_dict_keys(al, loc, to_type, arg_values); return ASR::make_IntrinsicFunction_t(al, loc, static_cast(ASRUtils::IntrinsicFunctions::DictKeys), args.p, args.size(), 0, to_type, compile_time_value); @@ -1598,7 +1598,7 @@ static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnost } static inline ASR::expr_t *eval_dict_values(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t *, Vec& /*args*/) { // TODO: To be implemented for DictConstant expression return nullptr; } @@ -1619,8 +1619,8 @@ static inline ASR::asr_t* create_DictValues(Allocator& al, const Location& loc, for( size_t i = 0; i < args.size(); i++ ) { arg_values.push_back(al, ASRUtils::expr_value(args[i])); } - ASR::expr_t* compile_time_value = eval_dict_values(al, loc, arg_values); ASR::ttype_t *to_type = List(dict_values_type); + ASR::expr_t* compile_time_value = eval_dict_values(al, loc, to_type, arg_values); return ASR::make_IntrinsicFunction_t(al, loc, static_cast(ASRUtils::IntrinsicFunctions::DictValues), args.p, args.size(), 0, to_type, compile_time_value); @@ -1646,7 +1646,7 @@ static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnost } static inline ASR::expr_t *eval_set_add(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t *, Vec& /*args*/) { // TODO: To be implemented for SetConstant expression return nullptr; } @@ -1668,7 +1668,7 @@ static inline ASR::asr_t* create_SetAdd(Allocator& al, const Location& loc, for( size_t i = 0; i < args.size(); i++ ) { arg_values.push_back(al, ASRUtils::expr_value(args[i])); } - ASR::expr_t* compile_time_value = eval_set_add(al, loc, arg_values); + ASR::expr_t* compile_time_value = eval_set_add(al, loc, nullptr, arg_values); return ASR::make_Expr_t(al, loc, ASRUtils::EXPR(ASR::make_IntrinsicFunction_t(al, loc, static_cast(ASRUtils::IntrinsicFunctions::SetAdd), @@ -1695,7 +1695,7 @@ static inline void verify_args(const ASR::IntrinsicFunction_t& x, diag::Diagnost } static inline ASR::expr_t *eval_set_remove(Allocator &/*al*/, - const Location &/*loc*/, Vec& /*args*/) { + const Location &/*loc*/, ASR::ttype_t *, Vec& /*args*/) { // TODO: To be implemented for SetConstant expression return nullptr; } @@ -1717,7 +1717,7 @@ static inline ASR::asr_t* create_SetRemove(Allocator& al, const Location& loc, for( size_t i = 0; i < args.size(); i++ ) { arg_values.push_back(al, ASRUtils::expr_value(args[i])); } - ASR::expr_t* compile_time_value = eval_set_remove(al, loc, arg_values); + ASR::expr_t* compile_time_value = eval_set_remove(al, loc, nullptr, arg_values); return ASR::make_Expr_t(al, loc, ASRUtils::EXPR(ASR::make_IntrinsicFunction_t(al, loc, static_cast(ASRUtils::IntrinsicFunctions::SetRemove), diff --git a/src/libasr/pass/pass_utils.cpp b/src/libasr/pass/pass_utils.cpp index 9ce7b02798..526746a540 100644 --- a/src/libasr/pass/pass_utils.cpp +++ b/src/libasr/pass/pass_utils.cpp @@ -939,7 +939,7 @@ namespace LCompilers { #define increment_by_one(var, body) ASR::expr_t* inc_by_one = builder.ElementalAdd(var, \ make_ConstantWithType(make_IntegerConstant_t, 1, \ ASRUtils::expr_type(var), loc), loc); \ - ASR::stmt_t* assign_inc = Assignment(var, inc_by_one); \ + ASR::stmt_t* assign_inc = builder.Assignment(var, inc_by_one); \ body->push_back(al, assign_inc); \ const Location& loc = arr_var->base.loc; @@ -962,13 +962,13 @@ namespace LCompilers { [=, &idx_vars, &doloop_body, &builder, &al] () { ASR::expr_t* ref = PassUtils::create_array_ref(curr_init, idx_vars, al, current_scope); ASR::expr_t* res = PassUtils::create_array_ref(arr_var, idx_var, al, current_scope); - ASR::stmt_t* assign = Assignment(res, ref); + ASR::stmt_t* assign = builder.Assignment(res, ref); doloop_body.push_back(al, assign); increment_by_one(idx_var, (&doloop_body)) }, current_scope, result_vec); } else { ASR::expr_t* res = PassUtils::create_array_ref(arr_var, idx_var, al, current_scope); - ASR::stmt_t* assign = Assignment(res, curr_init); + ASR::stmt_t* assign = builder.Assignment(res, curr_init); result_vec->push_back(al, assign); increment_by_one(idx_var, result_vec) } @@ -980,13 +980,13 @@ namespace LCompilers { [=, &idx_vars, &doloop_body, &builder, &al] () { ASR::expr_t* ref = PassUtils::create_array_ref(array_section, idx_vars, al); ASR::expr_t* res = PassUtils::create_array_ref(arr_var, idx_var, al, current_scope); - ASR::stmt_t* assign = Assignment(res, ref); + ASR::stmt_t* assign = builder.Assignment(res, ref); doloop_body.push_back(al, assign); increment_by_one(idx_var, (&doloop_body)) }, current_scope, result_vec); } else { ASR::expr_t* res = PassUtils::create_array_ref(arr_var, idx_var, al, current_scope); - ASR::stmt_t* assign = Assignment(res, curr_init); + ASR::stmt_t* assign = builder.Assignment(res, curr_init); result_vec->push_back(al, assign); increment_by_one(idx_var, result_vec) } diff --git a/src/lpython/pickle.cpp b/src/lpython/pickle.cpp index eeaaf38edf..b2b64244c0 100644 --- a/src/lpython/pickle.cpp +++ b/src/lpython/pickle.cpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace LCompilers::LPython { @@ -120,6 +121,20 @@ class ASRPickleVisitor : } return s; } + + std::string convert_array_intrinsic_id(int x) { + std::string s; + if (use_colors) { + s.append(color(style::bold)); + s.append(color(fg::green)); + } + s.append(ASRUtils::get_array_intrinsic_name(x)); + if (use_colors) { + s.append(color(fg::reset)); + s.append(color(style::reset)); + } + return s; + } }; std::string pickle(ASR::asr_t &asr, bool colors, bool indent, diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 33069a63cf..fef167d873 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include From a2c1ec3af9150865a259a108881bc8fb3881c25f Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Sat, 12 Aug 2023 17:27:00 +0530 Subject: [PATCH 3/4] Update tests --- tests/reference/asr-constants1-5828e8a.json | 2 +- tests/reference/asr-constants1-5828e8a.stdout | 2 +- tests/reference/c-variable_decl_03-fa1823b.json | 2 +- tests/reference/c-variable_decl_03-fa1823b.stdout | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/reference/asr-constants1-5828e8a.json b/tests/reference/asr-constants1-5828e8a.json index c103ddb444..d6b1bb7d3f 100644 --- a/tests/reference/asr-constants1-5828e8a.json +++ b/tests/reference/asr-constants1-5828e8a.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "asr-constants1-5828e8a.stdout", - "stdout_hash": "5972929209ec0acc3a01d5d69cda225b3abf1e1f3852433688a91162", + "stdout_hash": "9ee2a3ca03f116d819095a08b7600931b18ffc887fb3670e65905935", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/asr-constants1-5828e8a.stdout b/tests/reference/asr-constants1-5828e8a.stdout index 08b5b2212b..b60004d11c 100644 --- a/tests/reference/asr-constants1-5828e8a.stdout +++ b/tests/reference/asr-constants1-5828e8a.stdout @@ -231,7 +231,7 @@ (Real 8) (RealConstant 6.577424 - (Complex 8) + (Real 8) ) ) RealToReal diff --git a/tests/reference/c-variable_decl_03-fa1823b.json b/tests/reference/c-variable_decl_03-fa1823b.json index 287da81c28..1060de968b 100644 --- a/tests/reference/c-variable_decl_03-fa1823b.json +++ b/tests/reference/c-variable_decl_03-fa1823b.json @@ -6,7 +6,7 @@ "outfile": null, "outfile_hash": null, "stdout": "c-variable_decl_03-fa1823b.stdout", - "stdout_hash": "db9d4425ea564096988a8799be60a068865d3757cb7c72b44bdcebc5", + "stdout_hash": "b8397cdd7e8998d29574393db30b5638aedd2ecd34a596b8b1c29f7f", "stderr": null, "stderr_hash": null, "returncode": 0 diff --git a/tests/reference/c-variable_decl_03-fa1823b.stdout b/tests/reference/c-variable_decl_03-fa1823b.stdout index 38ad474710..7c25386e04 100644 --- a/tests/reference/c-variable_decl_03-fa1823b.stdout +++ b/tests/reference/c-variable_decl_03-fa1823b.stdout @@ -27,7 +27,7 @@ double _lcompilers_abs_f64(double x) double f() { double _lpython_return_variable; - _lpython_return_variable = _lcompilers_abs_f64(- 5.50000000000000000e+00); + _lpython_return_variable = 5.50000000000000000e+00; return _lpython_return_variable; } From 7fd39caaf9fe8d812d7bb392a0a29432d3da393a Mon Sep 17 00:00:00 2001 From: Thirumalai-Shaktivel Date: Sat, 12 Aug 2023 17:46:05 +0530 Subject: [PATCH 4/4] Revert --- src/libasr/pass/where.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libasr/pass/where.cpp b/src/libasr/pass/where.cpp index e1195022b4..e1ad88c7fc 100644 --- a/src/libasr/pass/where.cpp +++ b/src/libasr/pass/where.cpp @@ -106,7 +106,7 @@ class ReplaceVar : public ASR::BaseExprReplacer args.push_back(al, *current_expr); } ASR::ttype_t* type = ASRUtils::expr_type(args[0]); - ASR::expr_t* new_expr = ASRUtils::EXPR(ASR::make_IntrinsicFunction_t(al, x->base.base.loc, x->m_intrinsic_id, args.p, x->n_args, x->m_overload_id, type, x->m_value)); + ASR::expr_t* new_expr = ASRUtils::EXPR(ASRUtils::make_IntrinsicFunction_t_util(al, x->base.base.loc, x->m_intrinsic_id, args.p, x->n_args, x->m_overload_id, type, x->m_value)); *current_expr = new_expr; }