From bec11efcf9bbc6b94cd1773873c5ecde9c384c34 Mon Sep 17 00:00:00 2001 From: Smit-create Date: Fri, 8 Sep 2023 09:12:18 +0530 Subject: [PATCH 1/4] Register SignFromValue intrinsic --- src/libasr/pass/intrinsic_function_registry.h | 101 ++++++++++++++++++ 1 file changed, 101 insertions(+) diff --git a/src/libasr/pass/intrinsic_function_registry.h b/src/libasr/pass/intrinsic_function_registry.h index 41921114b9..ddf7387cdc 100644 --- a/src/libasr/pass/intrinsic_function_registry.h +++ b/src/libasr/pass/intrinsic_function_registry.h @@ -55,6 +55,7 @@ enum class IntrinsicScalarFunctions : int64_t { Max, Min, Sign, + SignFromValue, SymbolicSymbol, SymbolicAdd, SymbolicSub, @@ -109,6 +110,7 @@ inline std::string get_intrinsic_name(int x) { INTRINSIC_NAME_CASE(Max) INTRINSIC_NAME_CASE(Min) INTRINSIC_NAME_CASE(Sign) + INTRINSIC_NAME_CASE(SignFromValue) INTRINSIC_NAME_CASE(SymbolicSymbol) INTRINSIC_NAME_CASE(SymbolicAdd) INTRINSIC_NAME_CASE(SymbolicSub) @@ -1345,6 +1347,101 @@ namespace FMA { } // namespace FMA +namespace SignFromValue { + + static inline void verify_args(const ASR::IntrinsicScalarFunction_t& x, diag::Diagnostics& diagnostics) { + ASRUtils::require_impl(x.n_args == 2, + "ASR Verify: Call to SignFromValue must have exactly 2 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]); + bool eq_type = ASRUtils::types_equal(type1, type2); + ASRUtils::require_impl(((is_real(*type1) || is_integer(*type1)) && + (is_real(*type2) || is_integer(*type2)) && eq_type), + "ASR Verify: Arguments to SignFromValue must be of equal type and " + "should be either real or integer", + x.base.base.loc, diagnostics); + } + + static ASR::expr_t *eval_SignFromValue(Allocator &al, const Location &loc, + ASR::ttype_t* t1, Vec &args) { + if (is_real(*t1)) { + double a = ASR::down_cast(args[0])->m_r; + double b = ASR::down_cast(args[1])->m_r; + a = (b < 0 ? -a : a); + return make_ConstantWithType(make_RealConstant_t, a, t1, loc); + } + int64_t a = ASR::down_cast(args[0])->m_n; + int64_t b = ASR::down_cast(args[1])->m_n; + a = (b < 0 ? -a : a); + return make_ConstantWithType(make_IntegerConstant_t, a, t1, loc); + + } + + static inline ASR::asr_t* create_SignFromValue(Allocator& al, const Location& loc, + Vec& args, + const std::function err) { + if (args.size() != 2) { + err("Intrinsic SignFromValue function accepts exactly 2 arguments", loc); + } + ASR::ttype_t *type1 = ASRUtils::expr_type(args[0]); + ASR::ttype_t *type2 = ASRUtils::expr_type(args[1]); + bool eq_type = ASRUtils::types_equal(type1, type2); + if (!((is_real(*type1) || is_integer(*type1)) && + (is_real(*type2) || is_integer(*type2)) && eq_type)) { + err("Argument of the SignFromValue function must be either Real or Integer " + "and must be of equal type", + args[0]->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_SignFromValue(al, loc, expr_type(args[0]), arg_values); + } + return ASR::make_IntrinsicScalarFunction_t(al, loc, + static_cast(IntrinsicScalarFunctions::SignFromValue), + args.p, args.n, 0, ASRUtils::expr_type(args[0]), m_value); + } + + static inline ASR::expr_t* instantiate_SignFromValue(Allocator &al, const Location &loc, + SymbolTable *scope, Vec& arg_types, ASR::ttype_t *return_type, + Vec& new_args, int64_t /*overload_id*/) { + declare_basic_variables("_lcompilers_optimization_signfromvalue_" + type_to_str_python(arg_types[0])); + fill_func_arg("a", arg_types[0]); + fill_func_arg("b", arg_types[1]); + auto result = declare(fn_name, return_type, ReturnVar); + /* + elemental real(real32) function signfromvaluer32r32(a, b) result(d) + real(real32), intent(in) :: a, b + d = a * asignr32(1.0_real32, b) + end function + */ + if (is_real(*arg_types[0])) { + ASR::expr_t *zero = f(0.0, arg_types[1]); + body.push_back(al, b.If(fLt(args[1], zero), { + b.Assignment(result, f32_neg(args[0], arg_types[0])) + }, { + b.Assignment(result, args[0]) + })); + } else { + ASR::expr_t *zero = i(0, arg_types[1]); + body.push_back(al, b.If(iLt(args[1], zero), { + b.Assignment(result, i32_neg(args[0], arg_types[0])) + }, { + b.Assignment(result, args[0]) + })); + } + ASR::symbol_t *f_sym = make_ASR_Function_t(fn_name, fn_symtab, dep, args, + body, result, ASR::abiType::Source, ASR::deftypeType::Implementation, nullptr); + scope->add_symbol(fn_name, f_sym); + return b.Call(f_sym, new_args, return_type, nullptr); + } + +} // namespace SignFromValue + + namespace FlipSign { static inline void verify_args(const ASR::IntrinsicScalarFunction_t& x, diag::Diagnostics& diagnostics) { @@ -2452,6 +2549,8 @@ namespace IntrinsicScalarFunctionRegistry { {&FMA::instantiate_FMA, &FMA::verify_args}}, {static_cast(IntrinsicScalarFunctions::FlipSign), {&FlipSign::instantiate_FlipSign, &FlipSign::verify_args}}, + {static_cast(IntrinsicScalarFunctions::SignFromValue), + {&SignFromValue::instantiate_SignFromValue, &SignFromValue::verify_args}}, {static_cast(IntrinsicScalarFunctions::Abs), {&Abs::instantiate_Abs, &Abs::verify_args}}, {static_cast(IntrinsicScalarFunctions::Partition), @@ -2542,6 +2641,8 @@ namespace IntrinsicScalarFunctionRegistry { "fma"}, {static_cast(IntrinsicScalarFunctions::FlipSign), "flipsign"}, + {static_cast(IntrinsicScalarFunctions::SignFromValue), + "signfromvalue"}, {static_cast(IntrinsicScalarFunctions::Expm1), "expm1"}, {static_cast(IntrinsicScalarFunctions::ListIndex), From 03d1d791ae256c3c9aba5ba78f8c908545019f5f Mon Sep 17 00:00:00 2001 From: Smit-create Date: Fri, 8 Sep 2023 09:14:02 +0530 Subject: [PATCH 2/4] Fix declarations --- src/libasr/pass/pass_utils.cpp | 4 ++-- src/libasr/pass/pass_utils.h | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/libasr/pass/pass_utils.cpp b/src/libasr/pass/pass_utils.cpp index fb9c0a867d..7dc966dc67 100644 --- a/src/libasr/pass/pass_utils.cpp +++ b/src/libasr/pass/pass_utils.cpp @@ -600,7 +600,7 @@ namespace LCompilers { ASR::expr_t* get_flipsign(ASR::expr_t* arg0, ASR::expr_t* arg1, Allocator& al, ASR::TranslationUnit_t& unit, const Location& loc, - PassOptions pass_options){ + PassOptions& pass_options){ ASR::ttype_t* type = ASRUtils::expr_type(arg1); int64_t fp_s = static_cast(ASRUtils::IntrinsicScalarFunctions::FlipSign); if (skip_instantiation(pass_options, fp_s)) { @@ -688,7 +688,7 @@ namespace LCompilers { ASR::expr_t* get_fma(ASR::expr_t* arg0, ASR::expr_t* arg1, ASR::expr_t* arg2, Allocator& al, ASR::TranslationUnit_t& unit, Location& loc, - PassOptions pass_options){ + PassOptions& pass_options){ int64_t fma_id = static_cast(ASRUtils::IntrinsicScalarFunctions::FMA); ASR::ttype_t* type = ASRUtils::expr_type(arg0); if (skip_instantiation(pass_options, fma_id)) { diff --git a/src/libasr/pass/pass_utils.h b/src/libasr/pass/pass_utils.h index dfe86cc792..854c5bdd12 100644 --- a/src/libasr/pass/pass_utils.h +++ b/src/libasr/pass/pass_utils.h @@ -75,7 +75,7 @@ namespace LCompilers { ASR::expr_t* get_flipsign(ASR::expr_t* arg0, ASR::expr_t* arg1, Allocator& al, ASR::TranslationUnit_t& unit, const Location& loc, - PassOptions pass_options); + PassOptions& pass_options); ASR::expr_t* to_int32(ASR::expr_t* x, ASR::ttype_t* int32type, Allocator& al); @@ -88,13 +88,11 @@ namespace LCompilers { ASR::expr_t* get_fma(ASR::expr_t* arg0, ASR::expr_t* arg1, ASR::expr_t* arg2, Allocator& al, ASR::TranslationUnit_t& unit, Location& loc, - PassOptions pass_options); + PassOptions& pass_options); ASR::expr_t* get_sign_from_value(ASR::expr_t* arg0, ASR::expr_t* arg1, Allocator& al, ASR::TranslationUnit_t& unit, - LCompilers::PassOptions& pass_options, - SymbolTable*& current_scope, Location& loc, - const std::function err); + Location& loc, PassOptions& pass_options); ASR::stmt_t* get_vector_copy(ASR::expr_t* array0, ASR::expr_t* array1, ASR::expr_t* start, ASR::expr_t* end, ASR::expr_t* step, ASR::expr_t* vector_length, From 5ff964663305cec19cec2c2eadcfcbf3c43efbd2 Mon Sep 17 00:00:00 2001 From: Smit-create Date: Fri, 8 Sep 2023 09:16:18 +0530 Subject: [PATCH 3/4] Check instantiation of sign from value --- src/libasr/pass/pass_utils.cpp | 29 +++++++++++++++++++++-------- src/libasr/pass/sign_from_value.cpp | 3 +-- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/libasr/pass/pass_utils.cpp b/src/libasr/pass/pass_utils.cpp index 7dc966dc67..61061eb09e 100644 --- a/src/libasr/pass/pass_utils.cpp +++ b/src/libasr/pass/pass_utils.cpp @@ -818,11 +818,25 @@ namespace LCompilers { } ASR::expr_t* get_sign_from_value(ASR::expr_t* arg0, ASR::expr_t* arg1, - Allocator& al, ASR::TranslationUnit_t& unit, LCompilers::PassOptions& pass_options, - SymbolTable*& current_scope, Location& loc, - const std::function err) { - ASR::symbol_t *v = import_generic_procedure("sign_from_value", "lfortran_intrinsic_optimization", - al, unit, pass_options, current_scope, arg0->base.loc); + Allocator& al, ASR::TranslationUnit_t& unit, Location& loc, + PassOptions& pass_options) { + int64_t sfv_id = static_cast(ASRUtils::IntrinsicScalarFunctions::SignFromValue); + ASR::ttype_t* type = ASRUtils::expr_type(arg0); + if (skip_instantiation(pass_options, sfv_id)) { + Vec args; + args.reserve(al, 2); + args.push_back(al, arg0); + args.push_back(al, arg1); + return ASRUtils::EXPR(ASRUtils::make_IntrinsicScalarFunction_t_util(al, loc, sfv_id, + args.p, args.n, 0, type, nullptr)); + } + ASRUtils::impl_function instantiate_function = + ASRUtils::IntrinsicScalarFunctionRegistry::get_instantiate_function( + static_cast(ASRUtils::IntrinsicScalarFunctions::FMA)); + Vec arg_types; + arg_types.reserve(al, 2); + arg_types.push_back(al, ASRUtils::expr_type(arg0)); + arg_types.push_back(al, ASRUtils::expr_type(arg1)); Vec args; args.reserve(al, 2); ASR::call_arg_t arg0_, arg1_; @@ -830,9 +844,8 @@ namespace LCompilers { args.push_back(al, arg0_); arg1_.loc = arg1->base.loc, arg1_.m_value = arg1; args.push_back(al, arg1_); - return ASRUtils::EXPR( - ASRUtils::symbol_resolve_external_generic_procedure_without_eval( - loc, v, args, current_scope, al, err)); + return instantiate_function(al, loc, + unit.m_global_scope, arg_types, type, args, 0); } Vec replace_doloop(Allocator &al, const ASR::DoLoop_t &loop, diff --git a/src/libasr/pass/sign_from_value.cpp b/src/libasr/pass/sign_from_value.cpp index 163b870341..ac4a52bb1a 100644 --- a/src/libasr/pass/sign_from_value.cpp +++ b/src/libasr/pass/sign_from_value.cpp @@ -133,8 +133,7 @@ class SignFromValueVisitor : public PassUtils::SkipOptimizationFunctionVisitor Date: Fri, 8 Sep 2023 09:20:49 +0530 Subject: [PATCH 4/4] LLVM: Generate SignFromValue --- src/libasr/codegen/asr_to_llvm.cpp | 20 +++++++++++++++++-- src/libasr/pass/intrinsic_function_registry.h | 4 ++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index abe3756ea0..e2583bd23d 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -1908,6 +1908,17 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor generate_fma(args.p); break; } + case ASRUtils::IntrinsicScalarFunctions::SignFromValue: { + Vec args; + args.reserve(al, 2); + ASR::call_arg_t arg0_, arg1_; + arg0_.loc = x.m_args[0]->base.loc, arg0_.m_value = x.m_args[0]; + args.push_back(al, arg0_); + arg1_.loc = x.m_args[1]->base.loc, arg1_.m_value = x.m_args[1]; + args.push_back(al, arg1_); + generate_sign_from_value(args.p); + break; + } default: { throw CodeGenError( ASRUtils::IntrinsicScalarFunctionRegistry:: get_intrinsic_function_name(x.m_intrinsic_id) + @@ -8325,8 +8336,13 @@ Result> asr_to_llvm(ASR::TranslationUnit_t &asr, pass_options.always_run = false; pass_options.verbose = co.verbose; std::vector skip_optimization_func_instantiation; - skip_optimization_func_instantiation.push_back(static_cast(ASRUtils::IntrinsicScalarFunctions::FlipSign)); - skip_optimization_func_instantiation.push_back(static_cast(ASRUtils::IntrinsicScalarFunctions::FMA)); + skip_optimization_func_instantiation.push_back(static_cast( + ASRUtils::IntrinsicScalarFunctions::FlipSign)); + skip_optimization_func_instantiation.push_back(static_cast( + ASRUtils::IntrinsicScalarFunctions::FMA)); + skip_optimization_func_instantiation.push_back(static_cast( + ASRUtils::IntrinsicScalarFunctions::SignFromValue)); + pass_options.skip_optimization_func_instantiation = skip_optimization_func_instantiation; pass_manager.rtlib = co.rtlib; diff --git a/src/libasr/pass/intrinsic_function_registry.h b/src/libasr/pass/intrinsic_function_registry.h index ddf7387cdc..3e3babab0f 100644 --- a/src/libasr/pass/intrinsic_function_registry.h +++ b/src/libasr/pass/intrinsic_function_registry.h @@ -1433,8 +1433,8 @@ namespace SignFromValue { b.Assignment(result, args[0]) })); } - ASR::symbol_t *f_sym = make_ASR_Function_t(fn_name, fn_symtab, dep, args, - body, result, ASR::abiType::Source, ASR::deftypeType::Implementation, nullptr); + 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); }