-
Notifications
You must be signed in to change notification settings - Fork 171
Add String to List cast in LLVM #1098
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
c5244c6
to
598d183
Compare
Applying this diff, made things to work, but the ouput diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp
index be298fb24..9a5ea3488 100644
--- a/src/libasr/codegen/asr_to_llvm.cpp
+++ b/src/libasr/codegen/asr_to_llvm.cpp
@@ -4773,19 +4773,17 @@ public:
break;
}
case (ASR::cast_kindType::CharacterToList) : {
- this->visit_expr_wrapper(x.m_arg, true);
llvm::Value *str = CreateLoad(tmp);
llvm::AllocaInst *parg = builder->CreateAlloca(character_type, nullptr);
- builder->CreateStore(str, parg);
+ LLVM::CreateStore(*builder, str, parg);
llvm::Value *str_len = lfortran_str_len(parg);
+
llvm::Type *type = getIntType(4);
- llvm::Value *ptr = module->getOrInsertGlobal("_character_to_list_itr",
- type);
- ptr = builder->CreateLoad(ptr);
- module->getNamedGlobal("_character_to_list_itr")->setInitializer(
- llvm::ConstantInt::get(context,
- llvm::APInt(32, 0)));
+ llvm::AllocaInst *ptr = builder->CreateAlloca(type, nullptr);
llvm::Value* i32_one = llvm::ConstantInt::get(context, llvm::APInt(32, 1));
+ llvm::Value* i32_zero = llvm::ConstantInt::get(context, llvm::APInt(32, 0));
+ LLVM::CreateStore(*builder, i32_zero, ptr);
ASR::List_t* list_type = ASR::down_cast<ASR::List_t>(x.m_type);
bool is_array_type_local = false, is_malloc_array_type_local = false;
@@ -4815,14 +4813,16 @@ public:
// head
start_new_block(loophead);
- llvm::Value *cond = builder->CreateICmpSLT(ptr, str_len);
+ llvm::Value *cond = builder->CreateICmpSLT(LLVM::CreateLoad(*builder, ptr), str_len);
builder->CreateCondBr(cond, loopbody, loopend);
// body
start_new_block(loopbody);
- llvm::Value* item = lfortran_str_copy(str, ptr, ptr);
+ llvm::Value* item = lfortran_str_copy(str, LLVM::CreateLoad(*builder, ptr), LLVM::CreateLoad(*builder, ptr));
list_api->append(const_list, item, list_type->m_type, *module);
- ptr = builder->CreateAdd(ptr, i32_one);
+ LLVM::CreateStore(*builder, builder->CreateAdd(LLVM::CreateLoad(*builder, ptr), i32_one), ptr);
builder->CreateBr(loophead); def f():
x: list[str]
s: str
s = "lpython"
x = list(s)
i:i32
for i in range(len(x)):
print(x[i], end=", ")
print()
f() $ lpython examples/expr2.py && ./a.out
n, l, p, y, t, h, o, |
I figured it out, the string index starts from 1 to len(str). But I used 0 to len(str) diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp
index be298fb24..9989e4b07 100644
--- a/src/libasr/codegen/asr_to_llvm.cpp
+++ b/src/libasr/codegen/asr_to_llvm.cpp
@@ -4773,20 +4773,18 @@ public:
break;
}
case (ASR::cast_kindType::CharacterToList) : {
- this->visit_expr_wrapper(x.m_arg, true);
llvm::Value *str = CreateLoad(tmp);
llvm::AllocaInst *parg = builder->CreateAlloca(character_type, nullptr);
- builder->CreateStore(str, parg);
+ LLVM::CreateStore(*builder, str, parg);
llvm::Value *str_len = lfortran_str_len(parg);
+
llvm::Type *type = getIntType(4);
- llvm::Value *ptr = module->getOrInsertGlobal("_character_to_list_itr",
- type);
- ptr = builder->CreateLoad(ptr);
- module->getNamedGlobal("_character_to_list_itr")->setInitializer(
- llvm::ConstantInt::get(context,
- llvm::APInt(32, 0)));
+ llvm::AllocaInst *ptr = builder->CreateAlloca(type, nullptr);
llvm::Value* i32_one = llvm::ConstantInt::get(context, llvm::APInt(32, 1));
+ LLVM::CreateStore(*builder, i32_one, ptr);
+ // Empty List Initialization
ASR::List_t* list_type = ASR::down_cast<ASR::List_t>(x.m_type);
bool is_array_type_local = false, is_malloc_array_type_local = false;
bool is_list_local = false;
@@ -4805,8 +4803,8 @@ public:
uint64_t ptr_loads_copy = ptr_loads;
ptr_loads = 1;
+ // Looping statement
dict_api->set_iterators();
-
llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head");
llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body");
llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end");
@@ -4815,15 +4813,16 @@ public:
// head
start_new_block(loophead);
- llvm::Value *cond = builder->CreateICmpSLT(ptr, str_len);
+ llvm::Value *cond = builder->CreateICmpSLE(LLVM::CreateLoad(*builder, ptr), str_len);
builder->CreateCondBr(cond, loopbody, loopend);
// body
start_new_block(loopbody);
- llvm::Value* item = lfortran_str_copy(str, ptr, ptr);
- list_api->append(const_list, item, list_type->m_type, *module);
- ptr = builder->CreateAdd(ptr, i32_one);
-
+ {
+ llvm::Value* item = lfortran_str_copy(str, LLVM::CreateLoad(*builder, ptr), LLVM::CreateLoad(*builder, ptr));
+ list_api->append(const_list, item, list_type->m_type, *module);
+ LLVM::CreateStore(*builder, builder->CreateAdd(LLVM::CreateLoad(*builder, ptr), i32_one), ptr);
+ }
builder->CreateBr(loophead);
// end |
598d183
to
58abda9
Compare
Thanks, that worked. |
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!
58abda9
to
9c760fb
Compare
Correct me if I am wrong, so string to list cast can be implemented as follows at the Python's language level, l: list[str] = []
for char in string:
l.append(char) If so then I think this cast should be handled at ASR pass level so that it can be shared across all the backends at once. |
9c760fb
to
3d5ec07
Compare
I tried to implement this, but I have a question now how we will make it to return |
I think @czgdp1807 is probably right. So effectively this: l: list[str] = list(string) is equivalent to this: l: list[str] = []
for char in string:
l.append(char) But in terms of performance, we might (later) do something like: l: list[str]
l.reserve(len(string))
for i in range(len(string)):
l[i] = string[i] If it is faster but we'll get to these optimizations later. Probably our (future) optimizer might be able to do such optimizations also. How to return Here is one approach: turn def _lcompilers_string_to_list(string: str) -> list[str]:
l: list[str] = []
for char in string:
l.append(char)
return l And make the frontend AST->ASR insert it. That's all that is needed I think. (So you don't even need to create a new pass.) |
3d5ec07
to
16ede28
Compare
16ede28
to
ece6c73
Compare
I have updated the string to list cast in the ASR frontend. Please review. |
I would prefer this approach over others. |
Vec<ASR::expr_t*> list; | ||
list.reserve(al, 1); | ||
return ASR::make_ListConstant_t(al, loc, list.p, | ||
list.size(), list_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 creating an empty list constant?
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
"' object conversion to List is not implemented ", | ||
arg->base.loc); | ||
} | ||
} |
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 is handling compile time list("abcd")
stuff? If so, we need to add tests for that. The above tests seem to test runtime conversion, which is not implemented in this PR yet (I think).
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.
Compile time also works, those tests are present in the same file from line 1-10.
i: i32 | ||
for i in range(len(s)): | ||
l.append(s[i]) | ||
return l |
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.
Ah I see, it's doing the runtime as well. So we should test both compile time and runtime.
For runtime, should we rename this function to _lcompilers_str_to_list
, just to make it clear that this is an internal function?
CC @czgdp1807.
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 list
is more approriate because it is a builtin function or intrinsic in python much like ord
, hex
, bin
etc. and we can handle it the same way.
I think it is doing that approach, but there are a few things to polish, see above. |
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 this is good to go in. Everything is needed in this PR.
No description provided.