Skip to content

Commit

Permalink
Merge pull request #2372 from Shaikh-Ubaid/intrinsic_floor_div
Browse files Browse the repository at this point in the history
Support floor division as intrinsic function
  • Loading branch information
Shaikh-Ubaid authored Oct 8, 2023
2 parents e97aa69 + 235117b commit 670b12f
Show file tree
Hide file tree
Showing 82 changed files with 2,377 additions and 2,236 deletions.
1 change: 1 addition & 0 deletions integration_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,7 @@ RUN(NAME callback_04 IMPORT_PATH .. LABELS cpython)

# Intrinsic Functions
RUN(NAME intrinsics_01 LABELS cpython llvm NOFAST) # any
RUN(NAME intrinsics_02 LABELS cpython llvm c) # floordiv

# lpython decorator
RUN(NAME lpython_decorator_01 LABELS cpython)
Expand Down
42 changes: 42 additions & 0 deletions integration_tests/intrinsics_02.py
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()
1 change: 1 addition & 0 deletions src/libasr/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ set(SRC

asr_verify.cpp
asr_utils.cpp
casting_utils.cpp
diagnostics.cpp
stacktrace.cpp
string_utils.cpp
Expand Down
143 changes: 143 additions & 0 deletions src/libasr/casting_utils.cpp
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));
}
}
21 changes: 21 additions & 0 deletions src/libasr/casting_utils.h
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
1 change: 1 addition & 0 deletions src/libasr/codegen/asr_to_c_cpp.h
Original file line number Diff line number Diff line change
Expand Up @@ -2800,6 +2800,7 @@ PyMODINIT_FUNC PyInit_lpython_module_)" + fn_name + R"((void) {
SET_INTRINSIC_NAME(Expm1, "expm1");
SET_INTRINSIC_NAME(Trunc, "trunc");
SET_INTRINSIC_NAME(Fix, "fix");
SET_INTRINSIC_NAME(FloorDiv, "floordiv");
default : {
throw LCompilersException("IntrinsicScalarFunction: `"
+ ASRUtils::get_intrinsic_name(x.m_intrinsic_id)
Expand Down
6 changes: 3 additions & 3 deletions src/libasr/codegen/asr_to_wasm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2299,7 +2299,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor<ASRToWASMVisitor> {

void visit_RealConstant(const ASR::RealConstant_t &x) {
double val = x.m_r;
int a_kind = ((ASR::Real_t *)(&(x.m_type->base)))->m_kind;
int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type);
switch (a_kind) {
case 4: {
m_wa.emit_f32_const(val);
Expand All @@ -2318,7 +2318,7 @@ class ASRToWASMVisitor : public ASR::BaseVisitor<ASRToWASMVisitor> {

void visit_LogicalConstant(const ASR::LogicalConstant_t &x) {
bool val = x.m_value;
int a_kind = ((ASR::Logical_t *)(&(x.m_type->base)))->m_kind;
int a_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type);
switch (a_kind) {
case 4: {
m_wa.emit_i32_const(val);
Expand Down Expand Up @@ -3222,7 +3222,7 @@ Result<Vec<uint8_t>> asr_to_wasm_bytes_stream(ASR::TranslationUnit_t &asr,
pass_options.dump_all_passes = co.dump_all_passes;
std::vector<std::string> passes = {"pass_array_by_data", "array_op",
"implied_do_loops", "print_arr", "do_loops", "select_case",
"intrinsic_function", "nested_vars", "unused_functions"};
"nested_vars", "unused_functions", "intrinsic_function"};
LCompilers::PassManager pass_manager;
pass_manager.apply_passes(al, &asr, passes, pass_options, diagnostics);

Expand Down
Loading

0 comments on commit 670b12f

Please sign in to comment.