Skip to content

Commit 8bd6143

Browse files
authored
Merge pull request #1538 from Smit-create/i-1536
ASR/LLVM: Fix issues with string item
2 parents ac56812 + 37265f2 commit 8bd6143

12 files changed

+74
-39
lines changed

src/libasr/codegen/asr_to_c.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1211,8 +1211,7 @@ R"(
12111211
std::string idx = std::move(src);
12121212
this->visit_expr(*x.m_arg);
12131213
std::string str = std::move(src);
1214-
src = "(char *)memcpy((char *)calloc(2U, sizeof(char)), "
1215-
+ str + " + " + idx + " - 1, 1U)";
1214+
src = "_lfortran_str_item(" + str + ", " + idx + ")";
12161215
}
12171216

12181217
void visit_StringLen(const ASR::StringLen_t &x) {

src/libasr/codegen/asr_to_llvm.cpp

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1060,19 +1060,19 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
10601060
return builder->CreateCall(fn, {str});
10611061
}
10621062

1063-
llvm::Value* lfortran_str_copy(llvm::Value* str, llvm::Value* idx1, llvm::Value* idx2)
1063+
llvm::Value* lfortran_str_item(llvm::Value* str, llvm::Value* idx1)
10641064
{
1065-
std::string runtime_func_name = "_lfortran_str_copy";
1065+
std::string runtime_func_name = "_lfortran_str_item";
10661066
llvm::Function *fn = module->getFunction(runtime_func_name);
10671067
if (!fn) {
10681068
llvm::FunctionType *function_type = llvm::FunctionType::get(
10691069
character_type, {
1070-
character_type, llvm::Type::getInt32Ty(context), llvm::Type::getInt32Ty(context)
1070+
character_type, llvm::Type::getInt32Ty(context)
10711071
}, false);
10721072
fn = llvm::Function::Create(function_type,
10731073
llvm::Function::ExternalLinkage, runtime_func_name, *module);
10741074
}
1075-
return builder->CreateCall(fn, {str, idx1, idx2});
1075+
return builder->CreateCall(fn, {str, idx1});
10761076
}
10771077

10781078
llvm::Value* lfortran_str_slice(llvm::Value* str, llvm::Value* idx1, llvm::Value* idx2,
@@ -1907,7 +1907,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
19071907
std::vector<llvm::Value*> idx_vec = {idx};
19081908
p = CreateGEP(str, idx_vec);
19091909
} else {
1910-
p = lfortran_str_copy(str, idx, idx);
1910+
p = lfortran_str_item(str, idx);
19111911
}
19121912
// TODO: Currently the string starts at the right location, but goes to the end of the original string.
19131913
// We have to allocate a new string, copy it and add null termination.
@@ -1990,7 +1990,9 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
19901990
// llvm::Value *p = CreateGEP(str, idx_vec);
19911991
// TODO: Currently the string starts at the right location, but goes to the end of the original string.
19921992
// We have to allocate a new string, copy it and add null termination.
1993-
llvm::Value *p = lfortran_str_copy(str, idx1, idx2);
1993+
llvm::Value *step = llvm::ConstantInt::get(context, llvm::APInt(32, 1));
1994+
llvm::Value *present = llvm::ConstantInt::get(context, llvm::APInt(1, 1));
1995+
llvm::Value *p = lfortran_str_slice(str, idx1, idx2, step, present, present);
19941996

19951997
tmp = builder->CreateAlloca(character_type, nullptr);
19961998
builder->CreateStore(p, tmp);
@@ -4945,7 +4947,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
49454947
llvm::Value *idx = tmp;
49464948
this->visit_expr_wrapper(x.m_arg, true);
49474949
llvm::Value *str = tmp;
4948-
tmp = lfortran_str_copy(str, idx, idx);
4950+
tmp = lfortran_str_item(str, idx);
49494951
}
49504952

49514953
void visit_StringSection(const ASR::StringSection_t& x) {

src/libasr/runtime/lfortran_intrinsics.c

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -849,27 +849,20 @@ LFORTRAN_API char* _lfortran_strrepeat_c(char* s, int32_t n)
849849
return dest_char;
850850
}
851851

852-
// idx1 and idx2 both start from 1
853-
LFORTRAN_API char* _lfortran_str_copy(char* s, int32_t idx1, int32_t idx2) {
852+
// idx starts from 1
853+
LFORTRAN_API char* _lfortran_str_item(char* s, int32_t idx) {
854854

855855
int s_len = strlen(s);
856-
if(idx1 > s_len || idx1 <= (-1*s_len)){
857-
printf("String index out of Bounds\n");
856+
int original_idx = idx - 1;
857+
if (idx < 1) idx += s_len;
858+
if (idx < 1 || idx >= s_len + 1) {
859+
printf("String index: %d is out of Bounds\n", original_idx);
858860
exit(1);
859861
}
860-
if(idx1 <= 0) {
861-
idx1 = s_len + idx1;
862-
}
863-
if(idx2 <= 0) {
864-
idx2 = s_len + idx2;
865-
}
866-
char* dest_char = (char*)malloc(idx2-idx1+2);
867-
for (int i=idx1; i <= idx2; i++)
868-
{
869-
dest_char[i-idx1] = s[i-1];
870-
}
871-
dest_char[idx2-idx1+1] = '\0';
872-
return dest_char;
862+
char* res = (char*)malloc(2);
863+
res[0] = s[idx-1];
864+
res[1] = '\0';
865+
return res;
873866
}
874867

875868
LFORTRAN_API char* _lfortran_str_slice(char* s, int32_t idx1, int32_t idx2, int32_t step,

src/libasr/runtime/lfortran_intrinsics.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,7 @@ LFORTRAN_API int8_t* _lfortran_realloc(int8_t* ptr, int32_t size);
168168
LFORTRAN_API int8_t* _lfortran_calloc(int32_t count, int32_t size);
169169
LFORTRAN_API void _lfortran_free(char* ptr);
170170
LFORTRAN_API void _lfortran_string_init(int size_plus_one, char *s);
171+
LFORTRAN_API char* _lfortran_str_item(char* s, int32_t idx);
171172
LFORTRAN_API char* _lfortran_str_slice(char* s, int32_t idx1, int32_t idx2, int32_t step,
172173
bool idx1_present, bool idx2_present);
173174
LFORTRAN_API int32_t _lfortran_iand32(int32_t x, int32_t y);

src/lpython/semantics/python_ast_to_asr.cpp

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3135,19 +3135,6 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {
31353135
}
31363136
ai.m_right = index;
31373137
if (ASRUtils::is_character(*type)) {
3138-
ASR::expr_t* val = ASRUtils::expr_value(index);
3139-
if (val && ASR::is_a<ASR::IntegerConstant_t>(*val)) {
3140-
if (ASR::down_cast<ASR::IntegerConstant_t>(val)->m_n < 0) {
3141-
// Replace `x[-1]` to `x[len(x)+(-1)]`
3142-
ASR::ttype_t *int_type = ASRUtils::TYPE(ASR::make_Integer_t(
3143-
al, loc, 4, nullptr, 0));
3144-
ASR::expr_t *list_len = ASRUtils::EXPR(ASR::make_StringLen_t(
3145-
al, loc, value, int_type, nullptr));
3146-
ASR::expr_t *neg_idx = ASRUtils::expr_value(index);
3147-
index = ASRUtils::EXPR(ASR::make_IntegerBinOp_t(al, loc,
3148-
list_len, ASR::binopType::Add, neg_idx, int_type, nullptr));
3149-
}
3150-
}
31513138
index = index_add_one(loc, index);
31523139
ai.m_right = index;
31533140
tmp = ASR::make_StringItem_t(al, loc, value, index, type, nullptr);
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"basename": "runtime-test_str_01-50bdf2f",
3+
"cmd": "lpython {infile}",
4+
"infile": "tests/runtime_errors/test_str_01.py",
5+
"infile_hash": "5f1245b9162a004ea90aee813606b7a14a2d06802c8eb2ebd6220f9b",
6+
"outfile": null,
7+
"outfile_hash": null,
8+
"stdout": "runtime-test_str_01-50bdf2f.stdout",
9+
"stdout_hash": "ae5584858d62f3df08abdd365ea09fed0a7aa75f0f10698a7f7c2508",
10+
"stderr": null,
11+
"stderr_hash": null,
12+
"returncode": 1
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
String index: -4 is out of Bounds
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"basename": "runtime-test_str_02-c38ba27",
3+
"cmd": "lpython {infile}",
4+
"infile": "tests/runtime_errors/test_str_02.py",
5+
"infile_hash": "63853d644565a26ea82a41221d8fe11d9fc20d9132a36a76e6aba5e6",
6+
"outfile": null,
7+
"outfile_hash": null,
8+
"stdout": "runtime-test_str_02-c38ba27.stdout",
9+
"stdout_hash": "59f7b180db70f25c853c552c014ae09c1ee0671dfa0cbe205815c6b9",
10+
"stderr": null,
11+
"stderr_hash": null,
12+
"returncode": 1
13+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
String index: -8 is out of Bounds

tests/runtime_errors/test_str_01.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from ltypes import i32
2+
3+
4+
def test_issue_1536():
5+
x: str
6+
x = "ABC"
7+
l: i32
8+
l = -4
9+
print(x[l])
10+
11+
test_issue_1536()

0 commit comments

Comments
 (0)