Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions integration_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,7 @@ RUN(NAME test_vars_01 LABELS cpython llvm)
RUN(NAME test_version LABELS cpython llvm)
RUN(NAME vec_01 LABELS cpython llvm)
RUN(NAME test_str_comparison LABELS cpython llvm)
RUN(NAME test_bit_length LABELS cpython llvm)

RUN(NAME generics_01 LABELS cpython llvm)
RUN(NAME generics_array_01 LABELS llvm)
Expand Down
29 changes: 29 additions & 0 deletions integration_tests/test_bit_length.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from math import floor, log2
def ff():
assert -8 .bit_length() == -4
#TODO:(1 << 12).bit_length()
#TODO:(anything return integeri).bit_length()
assert 121212 .bit_length() == 17

def ff1():
x: i32
x = 1 << 30
assert x.bit_length() == 31

def ff2():
x: i8
x = 1 << 6
assert x.bit_length() == 7

def ff3():
x: i16
one: i16
one = 1
x = -(one << 13)
assert x.bit_length() == 14


ff()
ff1()
ff2()
ff3()
1 change: 1 addition & 0 deletions src/libasr/ASR.asdl
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ expr
| ListPop(expr a, expr? index, ttype type, expr? value)
| DictPop(expr a, expr key, ttype type, expr? value)
| SetPop(expr a, ttype type, expr? value)
| IntegerBitLen(expr a, ttype type, expr? value)


-- `len` in Character:
Expand Down
20 changes: 20 additions & 0 deletions src/libasr/codegen/asr_to_llvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1182,6 +1182,26 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
tmp = const_tuple;
}

void visit_IntegerBitLen(const ASR::IntegerBitLen_t& x) {
if (x.m_value) {
this->visit_expr_wrapper(x.m_value, true);
return;
}
llvm::Value *int_val = tmp;
int int_kind = ASRUtils::extract_kind_from_ttype_t(x.m_type);
std::string runtime_func_name = "_lpython_bit_length" + std::to_string(int_kind);
llvm::Function *fn = module->getFunction(runtime_func_name);
if (!fn) {
llvm::FunctionType *function_type = llvm::FunctionType::get(
llvm::Type::getInt32Ty(context), {
getIntType(int_kind)
}, false);
fn = llvm::Function::Create(function_type,
llvm::Function::ExternalLinkage, runtime_func_name, *module);
}
tmp = builder->CreateCall(fn, {int_val});
}

void visit_ListAppend(const ASR::ListAppend_t& x) {
uint64_t ptr_loads_copy = ptr_loads;
ptr_loads = 0;
Expand Down
32 changes: 32 additions & 0 deletions src/libasr/runtime/lfortran_intrinsics.c
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,38 @@ LFORTRAN_API char* _lfortran_int_to_str8(int64_t num)
return res;
}

LFORTRAN_API int32_t _lpython_bit_length1(int8_t num)
{
int32_t res = 0;
num = abs(num);
for(; num; num >>= 1, res++);
return res;
}

LFORTRAN_API int32_t _lpython_bit_length2(int16_t num)
{
int32_t res = 0;
num = abs(num);
for(; num; num >>= 1, res++);
return res;
}

LFORTRAN_API int32_t _lpython_bit_length4(int32_t num)
{
int32_t res = 0;
num = abs(num);
for(; num; num >>= 1, res++);
return res;
}

LFORTRAN_API int32_t _lpython_bit_length8(int64_t num)
{
int32_t res = 0;
num = abs(num);
for(; num; num >>= 1, res++);
return res;
}

//repeat str for n time
LFORTRAN_API void _lfortran_strrepeat(char** s, int32_t n, char** dest)
{
Expand Down
4 changes: 4 additions & 0 deletions src/libasr/runtime/lfortran_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,10 @@ LFORTRAN_API char* _lfortran_int_to_str1(int8_t num);
LFORTRAN_API char* _lfortran_int_to_str2(int16_t num);
LFORTRAN_API char* _lfortran_int_to_str4(int32_t num);
LFORTRAN_API char* _lfortran_int_to_str8(int64_t num);
LFORTRAN_API int32_t _lpython_bit_length1(int8_t num);
LFORTRAN_API int32_t _lpython_bit_length2(int16_t num);
LFORTRAN_API int32_t _lpython_bit_length4(int32_t num);
LFORTRAN_API int32_t _lpython_bit_length8(int64_t num);
LFORTRAN_API void _lfortran_strrepeat(char** s, int32_t n, char** dest);
LFORTRAN_API void _lfortran_strcat(char** s1, char** s2, char** dest);
LFORTRAN_API int _lfortran_str_len(char** s);
Expand Down
21 changes: 20 additions & 1 deletion src/lpython/semantics/python_ast_to_asr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4182,8 +4182,27 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
}
tmp = make_call_helper(al, st, current_scope, args, call_name, x.base.base.loc);
return;
} else if (AST::is_a<AST::ConstantInt_t>(*at->m_value)) {
if (std::string(at->m_attr) == std::string("bit_length")) {
//bit_length() attribute:
if(args.size() != 0) {
throw SemanticError("int.bit_length() takes no arguments",
x.base.base.loc);
}
AST::ConstantInt_t *n = AST::down_cast<AST::ConstantInt_t>(at->m_value);
int64_t int_val = std::abs(n->m_value);
int32_t res = 0;
for(; int_val; int_val >>= 1, res++);
ASR::ttype_t *int_type = ASRUtils::TYPE(ASR::make_Integer_t(al, x.base.base.loc,
4, nullptr, 0));
tmp = ASR::make_IntegerConstant_t(al, x.base.base.loc, res, int_type);
return;
} else {
throw SemanticError("'int' object has no attribute '" + std::string(at->m_attr) + "'",
x.base.base.loc);
}
} else {
throw SemanticError("Only Name type supported in Call",
throw SemanticError("Only Name type and constant integers supported in Call",
x.base.base.loc);
}
} else {
Expand Down
14 changes: 14 additions & 0 deletions src/lpython/semantics/python_attribute_eval.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ struct AttributeHandler {

AttributeHandler() {
attribute_map = {
{"int@bit_length", &eval_int_bit_length},
{"list@append", &eval_list_append},
{"list@remove", &eval_list_remove},
{"list@insert", &eval_list_insert},
Expand All @@ -37,6 +38,8 @@ struct AttributeHandler {
return "set";
} else if (ASR::is_a<ASR::Dict_t>(*t)) {
return "dict";
} else if (ASR::is_a<ASR::Integer_t>(*t)) {
return "int";
}
return "";
}
Expand All @@ -59,6 +62,17 @@ struct AttributeHandler {
}
}

static ASR::asr_t* eval_int_bit_length(ASR::expr_t *s, Allocator &al, const Location &loc,
Vec<ASR::expr_t*> &args, diag::Diagnostics &/*diag*/) {
if (args.size() != 0) {
throw SemanticError("int.bit_length() takes no arguments", loc);
}
int int_kind = ASRUtils::extract_kind_from_ttype_t(ASRUtils::expr_type(s));
ASR::ttype_t *int_type = ASRUtils::TYPE(ASR::make_Integer_t(al, loc,
int_kind, nullptr, 0));
return ASR::make_IntegerBitLen_t(al, loc, s, int_type, nullptr);
}

static ASR::asr_t* eval_list_append(ASR::expr_t *s, Allocator &al, const Location &loc,
Vec<ASR::expr_t*> &args, diag::Diagnostics &diag) {
if (args.size() != 1) {
Expand Down
6 changes: 6 additions & 0 deletions tests/errors/test_bit_length.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
def ff():
x: i32
x = 2323
print(x.bit_length(23))
ff()

13 changes: 13 additions & 0 deletions tests/reference/asr-test_bit_length-da3a264.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"basename": "asr-test_bit_length-da3a264",
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
"infile": "tests/errors/test_bit_length.py",
"infile_hash": "877db12847eccaf31564c6a969e7703f16c9e03bc9c326e72c74f1e0",
"outfile": null,
"outfile_hash": null,
"stdout": null,
"stdout_hash": null,
"stderr": "asr-test_bit_length-da3a264.stderr",
"stderr_hash": "0f371300055a9e3f6c01f73b1e276d9ae8007fd507eb0c75e1bda3ef",
"returncode": 2
}
5 changes: 5 additions & 0 deletions tests/reference/asr-test_bit_length-da3a264.stderr
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
semantic error: int.bit_length() takes no arguments
--> tests/errors/test_bit_length.py:4:11
|
4 | print(x.bit_length(23))
| ^^^^^^^^^^^^^^^^
4 changes: 4 additions & 0 deletions tests/tests.toml
Original file line number Diff line number Diff line change
Expand Up @@ -528,6 +528,10 @@ ast_new = true
filename = "parser/tuple1.py"
ast_new = true

[[test]]
filename = "errors/test_bit_length.py"
asr = true

[[test]]
filename = "parser/type_comment1.py"
ast_new = true
Expand Down