-
Notifications
You must be signed in to change notification settings - Fork 170
C/LLVM: Fixes with dict get #1700
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
Conversation
integration_tests/CMakeLists.txt
Outdated
@@ -293,7 +293,8 @@ RUN(NAME test_dict_06 LABELS cpython llvm c) | |||
RUN(NAME test_dict_07 LABELS cpython llvm) | |||
RUN(NAME test_dict_08 LABELS cpython llvm c) | |||
RUN(NAME test_dict_09 LABELS cpython llvm c) | |||
RUN(NAME test_dict_10 LABELS cpython llvm) # TODO: Add support of dict with string in C backend | |||
RUN(NAME test_dict_10 LABELS cpython llvm) # TODO: Add support of dict with string in C backend | |||
RUN(NAME test_dict_11 LABELS cpython c) # TODO: Add LLVM support |
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't move ahead without enabling LLVM backend for any test. Please make it work with LLVM before C.
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.
That's a good point, the LLVM backend is a "lowering" backend, so it ensures our design is good. The C/C++/Julia backends are high level backends, so they don't reveal all issues. WASM is also a lowering backend.
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.
Yep, that sounds right. Thanks, I fixed it.
Did some testing on this branch. The default value should only be considered when the key is not present in the dictionary.
|
Also another strange case I came across -
So should be made robust and tested that it does not give key error sometimes when key is not present in the dictionary. This might be a possible case of #1593 in |
6249f49
to
c935c96
Compare
src/libasr/codegen/llvm_utils.cpp
Outdated
std::pair<std::string, std::string> llvm_key = std::make_pair( | ||
ASRUtils::get_type_code(key_asr_type), | ||
ASRUtils::get_type_code(value_asr_type) | ||
); | ||
llvm::Type* value_type = std::get<2>(typecode2dicttype[llvm_key]).second; | ||
llvm::Value* result = builder->CreateAlloca(value_type, 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.
I think result
should only be allocated when def_value
is not nullptr
. I think you should not mix read_item
with the logic of dict.get
. Make a new method get_item
and call it to implement dict.get
. Direct access via []
should be done by read_item
(which should be left untouched in this PR).
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.
Presently, []
and dict.get
are implemented with the same DictItem
node in the ASR and we can re-use the same implementation just to extend it with default. I am not sure if it is a good idea to re-implement the same logic for get_item
and read_item
which effectively are doing the same job.
I think
result
should only be allocated whendef_value
is notnullptr
.
It's also used on line 1597 which also makes it more generalized in the case when key_hash is matching but not the keys. This was the bug with the previous implementation where it raised an error for the case where key_hash matches but not the key while it didn't raise any error when the key is totally absent. This is also fixed using the current PR. So, I don't think separating two methods for implementing same logic is a good idea.
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.
Well in this PR itself we have seen (as pointed in #1700 (comment) and #1700 (comment)) how read_item
is also affected when you implement dict.get
inside it. So de-coupling if-else-if
checks
I am not sure if it is a good idea to re-implement the same logic for
get_item
andread_item
which effectively are doing the same job.
If code repetition is the issue then you can solve it by using a macro, or a utility method and call it from read_item
and get_item
.
Presently,
[]
anddict.get
are implemented with the sameDictItem
node in the ASR and we can re-use the same implementation just to extend it with default
Won't be the case very soon. We will use IntrinsicFunction
to implement, dict.item
and dict.get
separately.
It's also used on line 1597 which also makes it more generalized in the case when key_hash is matching but not the keys.
In https://github.com/lcompilers/lpython/blob/c935c96b50abeb0553213904a9f96247f6f78421/src/libasr/codegen/llvm_utils.cpp, AFAICT, its only used when def_value != nullptr
,
lpython/src/libasr/codegen/llvm_utils.cpp
Lines 1596 to 1598 in c935c96
if (def_value != nullptr) { | |
LLVM::CreateStore(*builder, LLVM::CreateLoad(*builder, def_value), result); | |
} else { |
Again, my POV is still the same read_item
and get_item
should be different methods. However they can call common utility methods or macros to execute the common logic. if (some_arg_is_present)
and then else
always indicate that de-coupling is needed.
This was the bug with the previous implementation where it raised an error for the case where key_hash matches but not the key while it didn't raise any error when the key is totally absent.
Please add a test for it and fix the read_item
and get_item
methods accordingly.
ba6af20
to
46cde59
Compare
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.
LGTM. Before merging, please ensure our dict benchmarks don't degrade due to this PR.
Slight changes are expected because of an extra if-else check in the last commit which was a bug. |
src/libasr/codegen/llvm_utils.cpp
Outdated
llvm::Value* item = llvm_utils->list_api->read_item(value_list, pos, | ||
false, module, true); | ||
false, module, true);; |
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 should only happen in safe or debug modes of LPython. In fast mode one shouldn't catch these kind of errors. See, #1139.
I think following the same pattern as raising index errors in lists should work.
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.
Thanks, updated this with even dedicated methods for default and bound checking which leaves the original method untouched (removed some if-else checks) and so its performance will be >= existing performance.
No description provided.