From 556267897339126701c34d2931607522ccde94b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20=C4=8Cert=C3=ADk?= Date: Wed, 10 May 2023 17:16:06 -0600 Subject: [PATCH] Implement unsigned arrays support Now most array usage should work with unsigned integers. Added a test. --- integration_tests/CMakeLists.txt | 1 + integration_tests/expr_03u.py | 159 +++++++++++++++++++ src/libasr/asr_utils.h | 21 +++ src/libasr/codegen/asr_to_llvm.cpp | 4 + src/libasr/codegen/c_utils.h | 4 + src/libasr/pass/array_op.cpp | 21 ++- src/libasr/pass/pass_utils.cpp | 17 ++ src/lpython/semantics/python_ast_to_asr.cpp | 15 ++ src/lpython/semantics/python_comptime_eval.h | 4 +- 9 files changed, 244 insertions(+), 2 deletions(-) create mode 100644 integration_tests/expr_03u.py diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index e4543e15a5..3bfaa37676 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -329,6 +329,7 @@ RUN(NAME expr_15 LABELS cpython llvm c) RUN(NAME expr_01u LABELS cpython llvm c) RUN(NAME expr_02u LABELS cpython llvm c) +RUN(NAME expr_03u LABELS cpython llvm c) RUN(NAME loop_01 LABELS cpython llvm c) RUN(NAME loop_02 LABELS cpython llvm c wasm wasm_x86 wasm_x64) diff --git a/integration_tests/expr_03u.py b/integration_tests/expr_03u.py new file mode 100644 index 0000000000..7ab7b16de3 --- /dev/null +++ b/integration_tests/expr_03u.py @@ -0,0 +1,159 @@ +from lpython import u8, u16, u32, u64, i8, i32, TypeVar +from numpy import (empty, uint8, uint16, uint32, uint64, int8, int16, int32, + int64, size) + +n = TypeVar("n") +def add_i8(n: i32, x: i8[n], y: i8[n]) -> i8[n]: + return x + y + +def add_i8_loop(n: i32, x: i8[n], y: i8[n]) -> i8[n]: + z: i8[n] = empty(n, dtype=int8) + i: i32 + for i in range(n): + z[i] = x[i] + y[i] + return z + +def add_u8(n: i32, x: u8[n], y: u8[n]) -> u8[n]: + return x + y + +def add_u8_loop(n: i32, x: u8[n], y: u8[n]) -> u8[n]: + z: u8[n] = empty(n, dtype=uint8) + i: i32 + for i in range(n): + z[i] = x[i] + y[i] + return z + +def add_u16(n: i32, x: u16[n], y: u16[n]) -> u16[n]: + return x + y + +def add_u16_loop(n: i32, x: u16[n], y: u16[n]) -> u16[n]: + z: u16[n] = empty(n, dtype=uint16) + i: i32 + for i in range(n): + z[i] = x[i] + y[i] + return z + +def add_u32(n: i32, x: u32[n], y: u32[n]) -> u32[n]: + return x + y + +def add_u32_loop(n: i32, x: u32[n], y: u32[n]) -> u32[n]: + z: u32[n] = empty(n, dtype=uint32) + i: i32 + for i in range(n): + z[i] = x[i] + y[i] + return z + +def add_u64(n: i32, x: u64[n], y: u64[n]) -> u64[n]: + return x + y + +def add_u64_loop(n: i32, x: u64[n], y: u64[n]) -> u64[n]: + z: u64[n] = empty(n, dtype=uint64) + i: i32 + for i in range(n): + z[i] = x[i] + y[i] + return z + +def main_i8(): + x: i8[3] = empty(3, dtype=int8) + y: i8[3] = empty(3, dtype=int8) + z: i8[3] = empty(3, dtype=int8) + x[0] = i8(1) + x[1] = i8(2) + x[2] = i8(3) + y[0] = i8(2) + y[1] = i8(3) + y[2] = i8(4) + z = add_i8(size(x), x, y) + assert z[0] == i8(3) + assert z[1] == i8(5) + assert z[2] == i8(7) + z = add_i8_loop(size(x), x, y) + assert z[0] == i8(3) + assert z[1] == i8(5) + assert z[2] == i8(7) + +def main_u8(): + x: u8[3] = empty(3, dtype=uint8) + y: u8[3] = empty(3, dtype=uint8) + z: u8[3] = empty(3, dtype=uint8) + x[0] = u8(1) + x[1] = u8(2) + x[2] = u8(3) + y[0] = u8(2) + y[1] = u8(3) + y[2] = u8(4) + z = add_u8(size(x), x, y) + assert z[0] == u8(3) + assert z[1] == u8(5) + assert z[2] == u8(7) + z = add_u8_loop(size(x), x, y) + assert z[0] == u8(3) + assert z[1] == u8(5) + assert z[2] == u8(7) + +def main_u16(): + x: u16[3] = empty(3, dtype=uint16) + y: u16[3] = empty(3, dtype=uint16) + z: u16[3] = empty(3, dtype=uint16) + x[0] = u16(1) + x[1] = u16(2) + x[2] = u16(3) + y[0] = u16(2) + y[1] = u16(3) + y[2] = u16(4) + z = add_u16(size(x), x, y) + assert z[0] == u16(3) + assert z[1] == u16(5) + assert z[2] == u16(7) + z = add_u16_loop(size(x), x, y) + assert z[0] == u16(3) + assert z[1] == u16(5) + assert z[2] == u16(7) + +def main_u32(): + x: u32[3] = empty(3, dtype=uint32) + y: u32[3] = empty(3, dtype=uint32) + z: u32[3] = empty(3, dtype=uint32) + x[0] = u32(1) + x[1] = u32(2) + x[2] = u32(3) + y[0] = u32(2) + y[1] = u32(3) + y[2] = u32(4) + z = add_u32(size(x), x, y) + assert z[0] == u32(3) + assert z[1] == u32(5) + assert z[2] == u32(7) + z = add_u32_loop(size(x), x, y) + assert z[0] == u32(3) + assert z[1] == u32(5) + assert z[2] == u32(7) + +def main_u64(): + x: u64[3] = empty(3, dtype=uint64) + y: u64[3] = empty(3, dtype=uint64) + z: u64[3] = empty(3, dtype=uint64) + x[0] = u64(1) + x[1] = u64(2) + x[2] = u64(3) + y[0] = u64(2) + y[1] = u64(3) + y[2] = u64(4) + z = add_u64(size(x), x, y) + assert z[0] == u64(3) + assert z[1] == u64(5) + assert z[2] == u64(7) + z = add_u64_loop(size(x), x, y) + assert z[0] == u64(3) + assert z[1] == u64(5) + assert z[2] == u64(7) + +main_i8() +main_u8() +main_u16() +main_u32() +main_u64() + +# Not implemented yet in LPython: +#if __name__ == "__main__": +# main() diff --git a/src/libasr/asr_utils.h b/src/libasr/asr_utils.h index 93eaebb6c3..3fb215d1c8 100644 --- a/src/libasr/asr_utils.h +++ b/src/libasr/asr_utils.h @@ -618,6 +618,8 @@ static inline bool is_value_constant(ASR::expr_t *a_value) { } if (ASR::is_a(*a_value)) { // OK + } else if (ASR::is_a(*a_value)) { + // OK } else if (ASR::is_a(*a_value)) { // OK } else if (ASR::is_a(*a_value)) { @@ -1674,6 +1676,12 @@ inline bool ttype_set_dimensions(ASR::ttype_t *x, Integer_type->m_dims = m_dims; return true; } + case ASR::ttypeType::UnsignedInteger: { + ASR::UnsignedInteger_t* Integer_type = ASR::down_cast(x); + Integer_type->n_dims = n_dims; + Integer_type->m_dims = m_dims; + return true; + } case ASR::ttypeType::Real: { ASR::Real_t* Real_type = ASR::down_cast(x); Real_type->n_dims = n_dims; @@ -1737,6 +1745,7 @@ static inline bool is_aggregate_type(ASR::ttype_t* asr_type) { } return ASRUtils::is_array(asr_type) || !(ASR::is_a(*asr_type) || + ASR::is_a(*asr_type) || ASR::is_a(*asr_type) || ASR::is_a(*asr_type) || ASR::is_a(*asr_type)); @@ -1752,6 +1761,13 @@ static inline ASR::ttype_t* duplicate_type(Allocator& al, const ASR::ttype_t* t, return ASRUtils::TYPE(ASR::make_Integer_t(al, t->base.loc, tnew->m_kind, dimsp, dimsn)); } + case ASR::ttypeType::UnsignedInteger: { + ASR::UnsignedInteger_t* tnew = ASR::down_cast(t); + ASR::dimension_t* dimsp = dims ? dims->p : tnew->m_dims; + size_t dimsn = dims ? dims->n : tnew->n_dims; + return ASRUtils::TYPE(ASR::make_UnsignedInteger_t(al, t->base.loc, + tnew->m_kind, dimsp, dimsn)); + } case ASR::ttypeType::Real: { ASR::Real_t* tnew = ASR::down_cast(t); ASR::dimension_t* dimsp = dims ? dims->p : tnew->m_dims; @@ -1841,6 +1857,11 @@ static inline ASR::ttype_t* duplicate_type_without_dims(Allocator& al, const ASR return ASRUtils::TYPE(ASR::make_Integer_t(al, loc, tnew->m_kind, nullptr, 0)); } + case ASR::ttypeType::UnsignedInteger: { + ASR::UnsignedInteger_t* tnew = ASR::down_cast(t); + return ASRUtils::TYPE(ASR::make_UnsignedInteger_t(al, loc, + tnew->m_kind, nullptr, 0)); + } case ASR::ttypeType::Real: { ASR::Real_t* tnew = ASR::down_cast(t); return ASRUtils::TYPE(ASR::make_Real_t(al, loc, diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index ae7d1d4c2d..a5d82b7e63 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -477,6 +477,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor el_type = getIntType(a_kind); break; } + case ASR::ttypeType::UnsignedInteger: { + el_type = getIntType(a_kind); + break; + } case ASR::ttypeType::Real: { el_type = getFPType(a_kind); break; diff --git a/src/libasr/codegen/c_utils.h b/src/libasr/codegen/c_utils.h index 6f2557bf81..3fcf47e797 100644 --- a/src/libasr/codegen/c_utils.h +++ b/src/libasr/codegen/c_utils.h @@ -257,6 +257,10 @@ namespace CUtils { type_src = "int" + std::to_string(kind * 8) + "_t"; break; } + case ASR::ttypeType::UnsignedInteger: { + type_src = "uint" + std::to_string(kind * 8) + "_t"; + break; + } case ASR::ttypeType::Logical: { type_src = "bool"; break; diff --git a/src/libasr/pass/array_op.cpp b/src/libasr/pass/array_op.cpp index 74c0c3e7b7..3a0951d6e8 100644 --- a/src/libasr/pass/array_op.cpp +++ b/src/libasr/pass/array_op.cpp @@ -310,6 +310,11 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { al, loc, left, (ASR::binopType)x->m_op, right, x->m_type, nullptr)); + case ASR::exprType::UnsignedIntegerBinOp: + return ASRUtils::EXPR(ASR::make_UnsignedIntegerBinOp_t( + al, loc, left, (ASR::binopType)x->m_op, + right, x->m_type, nullptr)); + case ASR::exprType::RealBinOp: return ASRUtils::EXPR(ASR::make_RealBinOp_t( al, loc, left, (ASR::binopType)x->m_op, @@ -330,6 +335,11 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { al, loc, left, (ASR::cmpopType)x->m_op, right, x->m_type, nullptr)); + case ASR::exprType::UnsignedIntegerCompare: + return ASRUtils::EXPR(ASR::make_UnsignedIntegerCompare_t( + al, loc, left, (ASR::cmpopType)x->m_op, + right, x->m_type, nullptr)); + case ASR::exprType::RealCompare: return ASRUtils::EXPR(ASR::make_RealCompare_t( al, loc, left, (ASR::cmpopType)x->m_op, @@ -355,7 +365,8 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { case ASR::exprType::RealCompare: case ASR::exprType::ComplexCompare: case ASR::exprType::LogicalCompare: - case ASR::exprType::IntegerCompare: { + case ASR::exprType::IntegerCompare: + case ASR::exprType::UnsignedIntegerCompare: { ASR::ttype_t* arr_expr_type = ASRUtils::expr_type(arr_expr); ASR::dimension_t* m_dims; size_t n_dims = ASRUtils::extract_dimensions_from_ttype(arr_expr_type, m_dims); @@ -647,6 +658,10 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { replace_ArrayOpCommon(x, "_integer_bin_op_res"); } + void replace_UnsignedIntegerBinOp(ASR::UnsignedIntegerBinOp_t* x) { + replace_ArrayOpCommon(x, "_unsigned_integer_bin_op_res"); + } + void replace_ComplexBinOp(ASR::ComplexBinOp_t* x) { replace_ArrayOpCommon(x, "_complex_bin_op_res"); } @@ -659,6 +674,10 @@ class ReplaceArrayOp: public ASR::BaseExprReplacer { replace_ArrayOpCommon(x, "_integer_comp_op_res"); } + void replace_UnsignedIntegerCompare(ASR::UnsignedIntegerCompare_t* x) { + replace_ArrayOpCommon(x, "_unsigned_integer_comp_op_res"); + } + void replace_RealCompare(ASR::RealCompare_t* x) { replace_ArrayOpCommon(x, "_real_comp_op_res"); } diff --git a/src/libasr/pass/pass_utils.cpp b/src/libasr/pass/pass_utils.cpp index 52016f8b3f..f83bf92801 100644 --- a/src/libasr/pass/pass_utils.cpp +++ b/src/libasr/pass/pass_utils.cpp @@ -18,6 +18,12 @@ namespace LCompilers { m_dims = x_type_ref->m_dims; break; } + case ASR::ttypeType::UnsignedInteger: { + ASR::UnsignedInteger_t* x_type_ref = ASR::down_cast(t2); + n_dims = x_type_ref->n_dims; + m_dims = x_type_ref->m_dims; + break; + } case ASR::ttypeType::Real: { ASR::Real_t* x_type_ref = ASR::down_cast(t2); n_dims = x_type_ref->n_dims; @@ -69,6 +75,17 @@ namespace LCompilers { } break; } + case ASR::ttypeType::UnsignedInteger: { + ASR::UnsignedInteger_t* x_type_ref = ASR::down_cast(t2); + if( create_new ) { + new_type = ASRUtils::TYPE(ASR::make_UnsignedInteger_t(*al, x_type->base.loc, x_type_ref->m_kind, + m_dims, n_dims)); + } else { + x_type_ref->n_dims = n_dims; + x_type_ref->m_dims = m_dims; + } + break; + } case ASR::ttypeType::Real: { ASR::Real_t* x_type_ref = ASR::down_cast(t2); if( create_new ) { diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 549b339594..df6cf54bb6 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -733,6 +733,21 @@ class CommonVisitor : public AST::BaseVisitor { } return ASRUtils::TYPE(ASR::make_Integer_t(al, loc, t->m_kind, new_dims.p, new_dims.size())); } + case ASR::ttypeType::UnsignedInteger: { + ASR::UnsignedInteger_t *t = ASR::down_cast(return_type); + fill_expr_in_ttype_t(func_calls, t->m_dims, t->n_dims); + fix_exprs_ttype_t(func_calls, args, f); + Vec new_dims; + new_dims.reserve(al, t->n_dims); + for( size_t i = 0; i < func_calls.size(); i += 2 ) { + ASR::dimension_t new_dim; + new_dim.loc = func_calls[i]->base.loc; + new_dim.m_start = func_calls[i]; + new_dim.m_length = func_calls[i + 1]; + new_dims.push_back(al, new_dim); + } + return ASRUtils::TYPE(ASR::make_UnsignedInteger_t(al, loc, t->m_kind, new_dims.p, new_dims.size())); + } case ASR::ttypeType::Real: { ASR::Real_t *t = ASR::down_cast(return_type); fill_expr_in_ttype_t(func_calls, t->m_dims, t->n_dims); diff --git a/src/lpython/semantics/python_comptime_eval.h b/src/lpython/semantics/python_comptime_eval.h index 21aa0794de..32a58ac47b 100644 --- a/src/lpython/semantics/python_comptime_eval.h +++ b/src/lpython/semantics/python_comptime_eval.h @@ -25,7 +25,9 @@ struct ProceduresDatabase { "float32", "float64", "reshape", "array", "int16", "complex64", "complex128", - "int8", "exp", "exp2"}}, + "int8", "exp", "exp2", + "uint8", "uint16", "uint32", "uint64", + "size"}}, {"math", {"sin", "cos", "tan", "asin", "acos", "atan", "exp", "exp2", "expm1"}},