-
Notifications
You must be signed in to change notification settings - Fork 170
Support floor division as intrinsic function #2372
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
Merged
Merged
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
450d88a
Move casting_utils to LibASR
ubaidsk 8953abf
IntrinsicFunctions: Support floordiv in intrinsic_function_registry
ubaidsk cdd6a8b
Also support logical types in floordiv
ubaidsk 937726f
Also support constant variables in floordiv
ubaidsk f402c5e
Support throw error for div by 0
ubaidsk 18a2dea
CPP: Support floordiv intrinsic function
ubaidsk 2ecb309
Remove _lpython_floordiv() from lpython_builtin.py
ubaidsk 693b7ef
Remove floordiv support from AST->ASR
ubaidsk 665bade
TEST: Update reference tests
ubaidsk bc4cf51
TEST: Add for floordiv with Const var
ubaidsk 17be47d
WASM: Fix getting kind for Real and Logical Constants
ubaidsk 235117b
WASM: Apply intrinsic_function pass after unused_functions
ubaidsk File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
from lpython import Const, i32, f32, f64 | ||
|
||
foo: Const[i32] = 4 | ||
bar: Const[i32] = foo // 2 | ||
|
||
print(bar) | ||
assert bar == 2 | ||
|
||
def floordiv1(): | ||
a: f64 | ||
b: f64 | ||
c: f64 | ||
a = 5.0 | ||
b = 2.0 | ||
c = a // b | ||
|
||
print(c) | ||
assert c == 2.0 | ||
|
||
def floordiv2(): | ||
a: Const[f32] = f32(5.0) | ||
b: Const[f32] = f32(2.0) | ||
c: f32 | ||
c = a // b | ||
|
||
print(c) | ||
assert c == f32(2.0) | ||
|
||
def floordiv3(): | ||
a: f64 | ||
b: f64 | ||
c: f64 | ||
a = 5.0 | ||
b = -2.0 | ||
c = a // b | ||
|
||
print(c) | ||
assert c == -3.0 | ||
|
||
floordiv1() | ||
floordiv2() | ||
floordiv3() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
#include <libasr/casting_utils.h> | ||
#include <libasr/asr_utils.h> | ||
|
||
#include <map> | ||
|
||
|
||
namespace LCompilers::CastingUtil { | ||
|
||
// Data structure which contains priorities for | ||
// intrinsic types defined in ASR | ||
const std::map<ASR::ttypeType, int>& type2weight = { | ||
{ASR::ttypeType::Complex, 4}, | ||
{ASR::ttypeType::Real, 3}, | ||
{ASR::ttypeType::Integer, 2}, | ||
{ASR::ttypeType::Logical, 1} | ||
}; | ||
|
||
// Data structure which contains casting rules for non-equal | ||
// intrinsic types defined in ASR | ||
const std::map<std::pair<ASR::ttypeType, ASR::ttypeType>, ASR::cast_kindType>& type_rules = { | ||
{std::make_pair(ASR::ttypeType::Complex, ASR::ttypeType::Real), ASR::cast_kindType::ComplexToReal}, | ||
{std::make_pair(ASR::ttypeType::Complex, ASR::ttypeType::Logical), ASR::cast_kindType::ComplexToLogical}, | ||
{std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::Complex), ASR::cast_kindType::RealToComplex}, | ||
{std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::Integer), ASR::cast_kindType::RealToInteger}, | ||
{std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::Logical), ASR::cast_kindType::RealToLogical}, | ||
{std::make_pair(ASR::ttypeType::Real, ASR::ttypeType::UnsignedInteger), ASR::cast_kindType::RealToUnsignedInteger}, | ||
{std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::Complex), ASR::cast_kindType::IntegerToComplex}, | ||
{std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::Real), ASR::cast_kindType::IntegerToReal}, | ||
{std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::Logical), ASR::cast_kindType::IntegerToLogical}, | ||
{std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::UnsignedInteger), ASR::cast_kindType::IntegerToUnsignedInteger}, | ||
{std::make_pair(ASR::ttypeType::Logical, ASR::ttypeType::Real), ASR::cast_kindType::LogicalToReal}, | ||
{std::make_pair(ASR::ttypeType::Logical, ASR::ttypeType::Integer), ASR::cast_kindType::LogicalToInteger}, | ||
{std::make_pair(ASR::ttypeType::UnsignedInteger, ASR::ttypeType::Integer), ASR::cast_kindType::UnsignedIntegerToInteger}, | ||
{std::make_pair(ASR::ttypeType::UnsignedInteger, ASR::ttypeType::Real), ASR::cast_kindType::UnsignedIntegerToReal}, | ||
{std::make_pair(ASR::ttypeType::Integer, ASR::ttypeType::SymbolicExpression), ASR::cast_kindType::IntegerToSymbolicExpression} | ||
}; | ||
|
||
// Data structure which contains casting rules for equal intrinsic | ||
// types but with different kinds. | ||
const std::map<ASR::ttypeType, ASR::cast_kindType>& kind_rules = { | ||
{ASR::ttypeType::Complex, ASR::cast_kindType::ComplexToComplex}, | ||
{ASR::ttypeType::Real, ASR::cast_kindType::RealToReal}, | ||
{ASR::ttypeType::Integer, ASR::cast_kindType::IntegerToInteger}, | ||
{ASR::ttypeType::UnsignedInteger, ASR::cast_kindType::UnsignedIntegerToUnsignedInteger} | ||
}; | ||
|
||
int get_type_priority(ASR::ttypeType type) { | ||
if( type2weight.find(type) == type2weight.end() ) { | ||
return -1; | ||
} | ||
|
||
return type2weight.at(type); | ||
} | ||
|
||
int get_src_dest(ASR::expr_t* left_expr, ASR::expr_t* right_expr, | ||
ASR::expr_t*& src_expr, ASR::expr_t*& dest_expr, | ||
ASR::ttype_t*& src_type, ASR::ttype_t*& dest_type, | ||
bool is_assign) { | ||
ASR::ttype_t* left_type = ASRUtils::expr_type(left_expr); | ||
ASR::ttype_t* right_type = ASRUtils::expr_type(right_expr); | ||
if( ASR::is_a<ASR::Const_t>(*left_type) ) { | ||
left_type = ASRUtils::get_contained_type(left_type); | ||
} | ||
if( ASR::is_a<ASR::Const_t>(*right_type) ) { | ||
right_type = ASRUtils::get_contained_type(right_type); | ||
} | ||
left_type = ASRUtils::type_get_past_pointer(left_type); | ||
right_type = ASRUtils::type_get_past_pointer(right_type); | ||
if( ASRUtils::check_equal_type(left_type, right_type) || | ||
ASRUtils::is_character(*left_type) || ASRUtils::is_character(*right_type) ) { | ||
return 2; | ||
} | ||
if( is_assign ) { | ||
if( ASRUtils::is_real(*left_type) && ASRUtils::is_integer(*right_type)) { | ||
throw SemanticError("Assigning integer to float is not supported", | ||
right_expr->base.loc); | ||
} | ||
if ( ASRUtils::is_complex(*left_type) && !ASRUtils::is_complex(*right_type)) { | ||
throw SemanticError("Assigning non-complex to complex is not supported", | ||
right_expr->base.loc); | ||
} | ||
dest_expr = left_expr, dest_type = left_type; | ||
src_expr = right_expr, src_type = right_type; | ||
return 1; | ||
} | ||
|
||
int casted_expr_signal = 2; | ||
ASR::ttypeType left_Type = left_type->type, right_Type = right_type->type; | ||
int left_kind = ASRUtils::extract_kind_from_ttype_t(left_type); | ||
int right_kind = ASRUtils::extract_kind_from_ttype_t(right_type); | ||
int left_priority = get_type_priority(left_Type); | ||
int right_priority = get_type_priority(right_Type); | ||
if( left_priority > right_priority ) { | ||
src_expr = right_expr, src_type = right_type; | ||
dest_expr = left_expr, dest_type = left_type; | ||
casted_expr_signal = 1; | ||
} else if( left_priority < right_priority ) { | ||
src_expr = left_expr, src_type = left_type; | ||
dest_expr = right_expr, dest_type = right_type; | ||
casted_expr_signal = 0; | ||
} else { | ||
if( left_kind > right_kind ) { | ||
src_expr = right_expr, src_type = right_type; | ||
dest_expr = left_expr, dest_type = left_type; | ||
casted_expr_signal = 1; | ||
} else if( left_kind < right_kind ) { | ||
src_expr = left_expr, src_type = left_type; | ||
dest_expr = right_expr, dest_type = right_type; | ||
casted_expr_signal = 0; | ||
} else { | ||
return 2; | ||
} | ||
} | ||
|
||
return casted_expr_signal; | ||
} | ||
|
||
ASR::expr_t* perform_casting(ASR::expr_t* expr, ASR::ttype_t* src, | ||
ASR::ttype_t* dest, Allocator& al, | ||
const Location& loc) { | ||
ASR::ttypeType src_type = src->type; | ||
ASR::ttypeType dest_type = dest->type; | ||
ASR::cast_kindType cast_kind; | ||
if( src_type == dest_type ) { | ||
if( kind_rules.find(src_type) == kind_rules.end() ) { | ||
return expr; | ||
} | ||
cast_kind = kind_rules.at(src_type); | ||
} else { | ||
std::pair<ASR::ttypeType, ASR::ttypeType> cast_key = std::make_pair(src_type, dest_type); | ||
if( type_rules.find(cast_key) == type_rules.end() ) { | ||
return expr; | ||
} | ||
cast_kind = type_rules.at(cast_key); | ||
} | ||
if( ASRUtils::check_equal_type(src, dest, true) ) { | ||
return expr; | ||
} | ||
// TODO: Fix loc | ||
return ASRUtils::EXPR(ASRUtils::make_Cast_t_value(al, loc, expr, | ||
cast_kind, dest)); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
#ifndef LFORTRAN_CASTING_UTILS_H | ||
#define LFORTRAN_CASTING_UTILS_H | ||
|
||
|
||
#include <libasr/asr.h> | ||
|
||
namespace LCompilers::CastingUtil { | ||
|
||
int get_type_priority(ASR::ttypeType type); | ||
|
||
int get_src_dest(ASR::expr_t* left_expr, ASR::expr_t* right_expr, | ||
ASR::expr_t*& src_expr, ASR::expr_t*& dest_expr, | ||
ASR::ttype_t*& src_type, ASR::ttype_t*& dest_type, | ||
bool is_assign); | ||
|
||
ASR::expr_t* perform_casting(ASR::expr_t* expr, ASR::ttype_t* src, | ||
ASR::ttype_t* dest, Allocator& al, | ||
const Location& loc); | ||
} | ||
|
||
#endif // LFORTRAN_CASTING_UTILS_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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.
What is the idea behind these? I think we do not want to do any kind of automatic casting in ASR, nor be responsible for determining what proper casting must be done.
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.
It is actually not for automatic casting. The floordiv intrinsic we defined in this PR is generalized so that it can work on any type (from the supported types of
int, unsigned int, real, logical
). The casting function is used to cast the intermediate temporary variable to the appropriate return type.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.
It is also used to cast the function arguments to the needed intermediate type.
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.
Is this a helper function to make
make_Cast_t_value
more convenient, but you still tell the initial and final type explicitly?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. The way it helps is we need not worry about what type it currently is and just specify what type we want it to be.