-
-
Notifications
You must be signed in to change notification settings - Fork 129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
enh: support compiletime_broadcast_elemental_intrinsic
for multiple arguments
#3684
enh: support compiletime_broadcast_elemental_intrinsic
for multiple arguments
#3684
Conversation
src/libasr/asr_utils.h
Outdated
for (auto &a : args) { | ||
if (allow_nullptr && !a) continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure about this change --- when can an argument here in the vector be null?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For something like: floor(1.2)
where the second optional argument is set to nullptr
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok. Let's get all tests passing, then I'll review one more time.
eb6ff65
to
d8faf29
Compare
@certik , could you help me understand if the failing CI jobs are related to my changes? the error says: std::allocator<unsigned char> >, void>, bool)':
2024-03-20T10:25:01.8765884Z /home/runner/work/lfortran/lfortran/lfortran-0.33.1-866-ged79bd5c3/src/lfortran/fortran_kernel.cpp:346: undefined reference to `xeus::xinterpreter::publish_execution_result(int, nlohmann::json_abi_v3_11_3::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>,
std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void>, nlohmann::json_abi_v3_11_3::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long,
double, std::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void>)' Not able to understand how to go about this. while the failing documentation job gives the error: /usr/bin/ld: /home/runner/work/lfortran/lfortran/src/lfortran/fortran_kernel.cpp:511: undefined reference to `xeus::xkernel::xkernel(xeus::xconfiguration const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::unique_ptr<xeus::xcontext, std::default_delete<xeus::xcontext> >,
std::unique_ptr<xeus::xinterpreter, std::default_delete<xeus::xinterpreter> >, std::unique_ptr<xeus::xserver, std::default_delete<xeus::xserver> > (*)(xeus::xcontext&, xeus::xconfiguration const&,
nlohmann::json_abi_v3_11_3::detail::error_handler_t), std::unique_ptr<xeus::xhistory_manager, std::default_delete<xeus::xhistory_manager> >, std::unique_ptr<xeus::xlogger, std::default_delete<xeus::xlogger> >, std::unique_ptr<xeus::xdebugger, std::default_delete<xeus::xdebugger> > (*)(xeus::xcontext&, xeus::xconfiguration
const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, nlohmann::json_abi_v3_11_3::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_11_3::adl_serializer,
std::vector<unsigned char, std::allocator<unsigned char> >, void> const&), nlohmann::json_abi_v3_11_3::basic_json<std::map, std::vector, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, bool, long, unsigned long, double, std::allocator, nlohmann::json_abi_v3_11_3::adl_serializer, std::vector<unsigned char, std::allocator<unsigned char> >, void>, nlohmann::json_abi_v3_11_3::detail::error_handler_t)' |
It doesn't seem like triggered by your PR, but something is wrong, it's the same error on all 3 platforms. Can you try submitting a simple PR to check if master passes? |
The CI failure is unrelated: #3687. |
c1e0b6a
to
4772a8a
Compare
This is ready for a review. |
// 2. or arg.size() is 2 and first arg is an array, and second arg "kind" is | ||
// distributed to each broadcasted call | ||
// | ||
if ((args.size() == 2 || args.size() == 1) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think we need this now, we shall go ahead and modify signature to
- void compiletime_broadcast_elemental_intrinsic(ASR::ArrayConstant_t* array, ASRUtils::create_intrinsic_function create_func, const Location& loc, Allocator& al)
+ void compiletime_broadcast_elemental_intrinsic(ASR::expr_t** args, ASRUtils::create_intrinsic_function const Location& loc, Allocator& al)
Now iterate over args, and store in std::vector<int> array_arg_indices
. Once we populate array_arg_indices
, for example it has {1, 2, 4}
and index {0, 3, 5}
are scalar. We will create a helper funciton that takes array_arg_indices
and all other necessary parameters and broadcast X(s0, a1, a2, s3, a4, s5
as [X(s0, a1[0], a2[0], s3, a4[0], s5), ...., ]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The current approach handles only kind
parameter and limits us to only two arguments ( same as main with 1 argument ).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could you please give an example of an intrinsic function where broadcasting in this way would be needed? i.e. some being arrays, others being scalars, and it's an elemental intrinsic procedure? I'm just not able to think of something.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can also have multiple array arguments
program main
print *, max([1.0, 2.0, 3.0], [4.0, 5.0, 6.0])
end program
for (auto &a : args) { | ||
if (ignore_null && !a) continue; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We do not need this because in intrinsic_functions.h
it is already taken care that there will not be any nullptr. For frontend this happens because we fill_optional_kind_arg
and cases like max
, min
, etc which has multiple arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, you are saying that we can remove call to fill_optional_kind_arg
as well as remove the ignore_null
extra added keyword argument as well from all_args_evaluated
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, no, we need fill_optional_kind_arg
, just check all_args_evaluated
before filling optional arguments with nullptr.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, no, we need fill_optional_kind_arg, just check all_args_evaluated before filling optional arguments with nullptr.
I thought about this, and even if I do it before fill_optional_kind_arg
as you mentioned that it would be filled with nullptr
(for e.g. for min
) that will happen even before fill_optional_kind_arg
, as args
is populated with nullptr
in handle_intrinsic_node_args
itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Left some comments above, let me know if you wish more information about anything. I am marking this as draft.
The approach in this PR works well, no doubts, that looks good as well. Just if we are fixing it, and there is no hurry at moment ( it is not a blocker afaik ), let us do it correctly. I'll be happy to help. |
…asting fixes lfortran#3673 and write test broadcasting test cases for elemental functions
db2f763
to
cdf5193
Compare
Let me know how it looks now @Pranavchiku |
print *, max(1, [-1, 2, 20]) | ||
print *, max([1, 2, 3], [1, 1, [2]]) | ||
print *, max([1, 2], -1, -4) | ||
end program |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These need to have tests like if (...) error stop
to ensure the answer is correct.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Test shape and size of the resulting array also.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, I should've added it in the correct way, I'll change that.
integration_tests/intrinsics_194.f90
Outdated
print *, min([-1, 2, 3], 2, 5, [4, 4, 5], [5, -8, 7]) | ||
print *, min(1, [-1, 2, 20]) | ||
print *, min([1, 2, 3], [1, 1, [2]]) | ||
print *, min([1, 2], -1, -4) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This prints with GFortran:
-1 -8 2
-1 1 1
1 1 2
-4 -4
How does this work? I don't understand what min
does with a combination of array and scalar arguments like this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it extends all arguments to be arrays like this:
min([-1, 2, 3], 2, 5, [4, 4, 5], [5, -8, 7])
->
min([-1, 2, 3], [2, 2, 2], [5, 5, 5], [4, 4, 5], [5, -8, 7])
And then it computes the minimum element-wise, so we get [-1, -8, 2]
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's correct.
@gxyd thanks for working on this. I think there are many bugs like these and we need to fix them all, so this is extremely useful. |
@certik are there open issues for such bugs? (couldn't find any similar to this), let me know if there are more similar issues which need attention, I could take a look at those if needed. |
I’ll review this PR in a while, around 11:30 IST. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is good, thanks for doing this!
compiletime_broadcast_elemental_intrinsic
for multiple arguments
fixes #3673