From f6aadac1b9d8087829258e626e98f82185365e40 Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Date: Tue, 9 Apr 2024 19:23:49 +0530 Subject: [PATCH 1/2] Implement `reversed()` --- src/libasr/codegen/asr_to_llvm.cpp | 10 ++++- src/libasr/pass/intrinsic_function_registry.h | 6 +++ src/libasr/pass/intrinsic_functions.h | 42 +++++++++++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index c23f2f616c..87680515d1 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -1792,7 +1792,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor tmp = builder->CreateFSub(exp, one); } - void generate_ListReverse(ASR::expr_t* m_arg) { + void generate_ListReverse(ASR::expr_t* m_arg, bool is_intrinsic_function) { ASR::ttype_t* asr_el_type = ASRUtils::get_contained_type(ASRUtils::expr_type(m_arg)); int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; @@ -1802,6 +1802,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ptr_loads = !LLVM::is_llvm_struct(asr_el_type); ptr_loads = ptr_loads_copy; list_api->reverse(plist, *module); + + if (is_intrinsic_function) tmp = plist; } void generate_ListPop_0(ASR::expr_t* m_arg) { @@ -1954,8 +1956,12 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor generate_ListIndex(m_arg, m_ele, m_start, m_end); break ; } + case ASRUtils::IntrinsicElementalFunctions::Reversed: { + generate_ListReverse(x.m_args[0], true); + break; + } case ASRUtils::IntrinsicElementalFunctions::ListReverse: { - generate_ListReverse(x.m_args[0]); + generate_ListReverse(x.m_args[0], false); break; } case ASRUtils::IntrinsicElementalFunctions::ListPop: { diff --git a/src/libasr/pass/intrinsic_function_registry.h b/src/libasr/pass/intrinsic_function_registry.h index 65437a6518..998ab142e5 100644 --- a/src/libasr/pass/intrinsic_function_registry.h +++ b/src/libasr/pass/intrinsic_function_registry.h @@ -19,6 +19,7 @@ namespace ASRUtils { inline std::string get_intrinsic_name(int x) { switch (x) { INTRINSIC_NAME_CASE(ObjectType) + INTRINSIC_NAME_CASE(Reversed) INTRINSIC_NAME_CASE(Kind) INTRINSIC_NAME_CASE(Rank) INTRINSIC_NAME_CASE(Sin) @@ -172,6 +173,8 @@ namespace IntrinsicElementalFunctionRegistry { verify_function>>& intrinsic_function_by_id_db = { {static_cast(IntrinsicElementalFunctions::ObjectType), {nullptr, &ObjectType::verify_args}}, + {static_cast(IntrinsicElementalFunctions::Reversed), + {nullptr, &Reversed::verify_args}}, {static_cast(IntrinsicElementalFunctions::Gamma), {&Gamma::instantiate_Gamma, &UnaryIntrinsicFunction::verify_args}}, {static_cast(IntrinsicElementalFunctions::Log10), @@ -459,6 +462,8 @@ namespace IntrinsicElementalFunctionRegistry { static const std::map& intrinsic_function_id_to_name = { {static_cast(IntrinsicElementalFunctions::ObjectType), "type"}, + {static_cast(IntrinsicElementalFunctions::Reversed), + "reversed"}, {static_cast(IntrinsicElementalFunctions::Gamma), "gamma"}, {static_cast(IntrinsicElementalFunctions::Log), @@ -744,6 +749,7 @@ namespace IntrinsicElementalFunctionRegistry { std::tuple>& intrinsic_function_by_name_db = { {"type", {&ObjectType::create_ObjectType, &ObjectType::eval_ObjectType}}, + {"reversed", {&Reversed::create_Reversed, &Reversed::eval_Reversed}}, {"gamma", {&Gamma::create_Gamma, &Gamma::eval_Gamma}}, {"log", {&Log::create_Log, &Log::eval_Log}}, {"log10", {&Log10::create_Log10, &Log10::eval_Log10}}, diff --git a/src/libasr/pass/intrinsic_functions.h b/src/libasr/pass/intrinsic_functions.h index a78175bd28..411ecbaa7c 100644 --- a/src/libasr/pass/intrinsic_functions.h +++ b/src/libasr/pass/intrinsic_functions.h @@ -19,6 +19,7 @@ the code size. enum class IntrinsicElementalFunctions : int64_t { ObjectType, + Reversed, Kind, // if kind is reordered, update `extract_kind` in `asr_utils.h` Rank, Sin, @@ -568,6 +569,47 @@ namespace ObjectType { } // namespace ObjectType +namespace Reversed { + + static inline void verify_args(const ASR::IntrinsicElementalFunction_t& x, diag::Diagnostics& diagnostics) { + ASRUtils::require_impl(x.n_args == 1, "Call to reversed() must have atleast one argument", + x.base.base.loc, diagnostics); + ASR::ttype_t* arg_type = ASRUtils::expr_type(x.m_args[0]); + ASRUtils::require_impl(ASR::is_a(*arg_type), + "Argument to reversed() must be of list type.", + x.base.base.loc, diagnostics); + } + + static inline ASR::expr_t *eval_Reversed(Allocator &/*al*/, + const Location &/*loc*/, ASR::ttype_t */*t*/, Vec& /*args*/, diag::Diagnostics& /*diag*/) { + // TODO: To be implemented for ListConstant expression + return nullptr; + } + + + static inline ASR::asr_t* create_Reversed(Allocator& al, const Location& loc, + Vec& args, + diag::Diagnostics& diag) { + if (!ASR::is_a(*ASRUtils::expr_type(args[0]))) { + append_error(diag, + "reversed() currently only accepts an object of type `list`", loc); + return nullptr; + } + + Vec arg_values; + arg_values.reserve(al, args.size()); + for( size_t i = 0; i < args.size(); i++ ) { + arg_values.push_back(al, ASRUtils::expr_value(args[i])); + } + ASR::ttype_t *to_type = ASRUtils::expr_type(args[0]); + ASR::expr_t* compile_time_value = eval_Reversed(al, loc, to_type, arg_values, diag); + return ASR::make_IntrinsicElementalFunction_t(al, loc, + static_cast(IntrinsicElementalFunctions::Reversed), + args.p, args.n, 0, to_type, compile_time_value); + } + +} // namespace Reversed + namespace Fix { static inline ASR::expr_t *eval_Fix(Allocator &al, const Location &loc, ASR::ttype_t *t, Vec& args, diag::Diagnostics& /*diag*/) { From 169350e6f77022aa20258d931476d50d2bf170ab Mon Sep 17 00:00:00 2001 From: Saurabh Kumar Date: Tue, 9 Apr 2024 20:03:21 +0530 Subject: [PATCH 2/2] Tests: Add test --- integration_tests/CMakeLists.txt | 1 + integration_tests/test_builtin_reversed.py | 40 ++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 integration_tests/test_builtin_reversed.py diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index e5f6ff3aa8..f8d696b879 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -830,6 +830,7 @@ RUN(NAME callback_04 IMPORT_PATH .. LABELS cpython) RUN(NAME intrinsics_01 LABELS cpython llvm NOFAST) # any RUN(NAME intrinsics_02 LABELS cpython llvm c) # floordiv RUN(NAME test_builtin_type LABELS cpython llvm c) # type +RUN(NAME test_builtin_reversed LABELS llvm) # reversed # lpython decorator RUN(NAME lpython_decorator_01 LABELS cpython) diff --git a/integration_tests/test_builtin_reversed.py b/integration_tests/test_builtin_reversed.py new file mode 100644 index 0000000000..51cf3607f7 --- /dev/null +++ b/integration_tests/test_builtin_reversed.py @@ -0,0 +1,40 @@ +from lpython import i32, f64 + + +def test_builtin_reversed(): + # list of strings + alphabets: list[str] = ["a", "b", "c", "d", "e"] + + reversed_alphabets: list[str] = reversed(alphabets) + print(reversed_alphabets) + assert reversed_alphabets == ["e", "d", "c", "b", "a"] + + # list of numbers + numbers: list[i32] = [1, 2, 3, 4, 5] + + reversed_numbers: list[i32] = reversed(numbers) + print(reversed_numbers) + assert reversed_numbers == [5, 4, 3, 2, 1] + + # list returned through function call + alphabet_dictionary: dict[str, i32] = { + "a": 1, + "b": 2, + "c": 3, + "d": 4, + "e": 5, + } + reversed_keys: list[str] = reversed(alphabet_dictionary.keys()) + print(reversed_keys) + + assert reversed_keys == ["e", "d", "c", "b", "a"] + + # list of another object + points: list[tuple[f64, f64]] = [(1.0, 0.0), (2.3, 5.9), (78.1, 23.2)] + reversed_points: list[tuple[f64, f64]] = reversed(points) + print(reversed_points) + + assert reversed_points == [(78.1, 23.2), (2.3, 5.9), (1.0, 0.0)] + + +test_builtin_reversed()