Skip to content

Commit 7727de2

Browse files
Add list.reverse intrinsic function (#1758)
``Expr(expression)`` has also been added. Co-authored-by: kabra1110 <diffusion.kv@gmail.com>
1 parent 9941f2c commit 7727de2

File tree

8 files changed

+190
-2
lines changed

8 files changed

+190
-2
lines changed

integration_tests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,7 @@ RUN(NAME test_list_10 LABELS cpython llvm c)
360360
RUN(NAME test_list_section LABELS cpython llvm c)
361361
RUN(NAME test_list_count LABELS cpython llvm)
362362
RUN(NAME test_list_index LABELS cpython llvm)
363+
RUN(NAME test_list_reverse LABELS cpython llvm)
363364
RUN(NAME test_tuple_01 LABELS cpython llvm c)
364365
RUN(NAME test_tuple_02 LABELS cpython llvm c)
365366
RUN(NAME test_tuple_03 LABELS cpython llvm c)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
from lpython import i32, f64
2+
3+
def test_list_reverse():
4+
l1: list[i32] = []
5+
l2: list[i32] = []
6+
l3: list[f64] = []
7+
l4: list[f64] = []
8+
l5: list[str] = []
9+
l6: list[str] = []
10+
l7: list[str] = []
11+
i: i32
12+
j: f64
13+
s: str
14+
15+
l1 = [1, 2, 3]
16+
l1.reverse()
17+
assert l1 == [3, 2, 1]
18+
19+
l1 = []
20+
for i in range(10):
21+
l1.reverse()
22+
l1.append(i)
23+
l2.insert(0, i)
24+
l1.reverse()
25+
assert l1 == l2
26+
27+
j = 0.0
28+
while j < 2.1:
29+
l3.reverse()
30+
l3.append(j)
31+
l4.insert(0, j)
32+
l3.insert(0, j + 1.0)
33+
l4.append(j + 1.0)
34+
l3.reverse()
35+
assert l3 == l4
36+
j += 0.1
37+
38+
l5 = ["abcd", "efgh", "ijkl"]
39+
for s in l5:
40+
l6.reverse()
41+
l6.insert(0, s)
42+
l7.append(s)
43+
l6.reverse()
44+
assert l6 == l7
45+
46+
47+
test_list_reverse()

src/libasr/ASR.asdl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ stmt
215215
| ListRemove(expr a, expr ele)
216216
| ListClear(expr a)
217217
| DictInsert(expr a, expr key, expr value)
218+
| Expr(expr expression)
218219

219220

220221
expr
@@ -225,7 +226,7 @@ expr
225226
| FunctionCall(symbol name, symbol? original_name, call_arg* args,
226227
ttype type, expr? value, expr? dt)
227228
| IntrinsicFunction(int intrinsic_id, expr* args, int overload_id,
228-
ttype type, expr? value)
229+
ttype? type, expr? value)
229230
| StructTypeConstructor(symbol dt_sym, call_arg* args, ttype type, expr? value)
230231
| EnumTypeConstructor(symbol dt_sym, expr* args, ttype type, expr? value)
231232
| UnionTypeConstructor(symbol dt_sym, expr* args, ttype type, expr? value)

src/libasr/codegen/asr_to_llvm.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1891,6 +1891,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
18911891
dict_type->m_value_type, name2memidx);
18921892
}
18931893

1894+
void visit_Expr(const ASR::Expr_t& x) {
1895+
this->visit_expr_wrapper(x.m_expression, false);
1896+
}
1897+
18941898
void visit_ListRemove(const ASR::ListRemove_t& x) {
18951899
ASR::ttype_t* asr_el_type = ASRUtils::get_contained_type(ASRUtils::expr_type(x.m_a));
18961900
int64_t ptr_loads_copy = ptr_loads;
@@ -1953,6 +1957,18 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
19531957
tmp = builder->CreateFSub(exp, one);
19541958
}
19551959

1960+
void generate_ListReverse(ASR::expr_t* m_arg) {
1961+
ASR::ttype_t* asr_el_type = ASRUtils::get_contained_type(ASRUtils::expr_type(m_arg));
1962+
int64_t ptr_loads_copy = ptr_loads;
1963+
ptr_loads = 0;
1964+
this->visit_expr(*m_arg);
1965+
llvm::Value* plist = tmp;
1966+
1967+
ptr_loads = !LLVM::is_llvm_struct(asr_el_type);
1968+
ptr_loads = ptr_loads_copy;
1969+
list_api->reverse(plist, asr_el_type, *module);
1970+
}
1971+
19561972
void visit_IntrinsicFunction(const ASR::IntrinsicFunction_t& x) {
19571973
switch (static_cast<ASRUtils::IntrinsicFunctions>(x.m_intrinsic_id)) {
19581974
case ASRUtils::IntrinsicFunctions::ListIndex: {
@@ -2012,6 +2028,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
20122028
}
20132029
break ;
20142030
}
2031+
case ASRUtils::IntrinsicFunctions::ListReverse: {
2032+
generate_ListReverse(x.m_args[0]);
2033+
break;
2034+
}
20152035
default: {
20162036
throw CodeGenError( ASRUtils::IntrinsicFunctionRegistry::
20172037
get_intrinsic_function_name(x.m_intrinsic_id) +

src/libasr/codegen/llvm_utils.cpp

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2629,6 +2629,74 @@ namespace LCompilers {
26292629
shift_end_point_by_one(list);
26302630
}
26312631

2632+
void LLVMList::reverse(llvm::Value* list, ASR::ttype_t* list_type, llvm::Module& module) {
2633+
2634+
/* Equivalent in C++:
2635+
*
2636+
* int i = 0;
2637+
* int j = end_point - 1;
2638+
*
2639+
* tmp;
2640+
*
2641+
* while(j > i) {
2642+
* tmp = list[i];
2643+
* list[i] = list[j];
2644+
* list[j] = tmp;
2645+
* i = i + 1;
2646+
* j = j - 1;
2647+
* }
2648+
*/
2649+
2650+
llvm::Value* end_point = LLVM::CreateLoad(*builder,
2651+
get_pointer_to_current_end_point(list));
2652+
2653+
llvm::Type* pos_type = llvm::Type::getInt32Ty(context);
2654+
llvm::AllocaInst *i = builder->CreateAlloca(pos_type, nullptr);
2655+
LLVM::CreateStore(*builder, llvm::ConstantInt::get(
2656+
context, llvm::APInt(32, 0)), i); // i = 0
2657+
llvm::AllocaInst *j = builder->CreateAlloca(pos_type, nullptr);
2658+
llvm::Value* tmp = nullptr;
2659+
tmp = builder->CreateSub(end_point, llvm::ConstantInt::get(context, llvm::APInt(32, 1)));
2660+
LLVM::CreateStore(*builder, tmp, j); // j = end_point - 1
2661+
2662+
llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head");
2663+
llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body");
2664+
llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end");
2665+
2666+
// head
2667+
llvm_utils->start_new_block(loophead);
2668+
{
2669+
llvm::Value *cond = builder->CreateICmpSGT(LLVM::CreateLoad(*builder, j), LLVM::CreateLoad(*builder, i));
2670+
builder->CreateCondBr(cond, loopbody, loopend);
2671+
}
2672+
2673+
// body
2674+
llvm_utils->start_new_block(loopbody);
2675+
{
2676+
tmp = read_item(list, LLVM::CreateLoad(*builder, i),
2677+
false, module, LLVM::is_llvm_struct(list_type)); // tmp = list[i]
2678+
write_item(list, LLVM::CreateLoad(*builder, i),
2679+
read_item(list, LLVM::CreateLoad(*builder, j),
2680+
false, module, LLVM::is_llvm_struct(list_type)),
2681+
false, module); // list[i] = list[j]
2682+
write_item(list, LLVM::CreateLoad(*builder, j),
2683+
tmp, false, module); // list[j] = tmp
2684+
2685+
tmp = builder->CreateAdd(
2686+
LLVM::CreateLoad(*builder, i),
2687+
llvm::ConstantInt::get(context, llvm::APInt(32, 1)));
2688+
LLVM::CreateStore(*builder, tmp, i);
2689+
tmp = builder->CreateSub(
2690+
LLVM::CreateLoad(*builder, j),
2691+
llvm::ConstantInt::get(context, llvm::APInt(32, 1)));
2692+
LLVM::CreateStore(*builder, tmp, j);
2693+
}
2694+
builder->CreateBr(loophead);
2695+
2696+
// end
2697+
llvm_utils->start_new_block(loopend);
2698+
}
2699+
26322700
llvm::Value* LLVMList::find_item_position(llvm::Value* list,
26332701
llvm::Value* item, ASR::ttype_t* item_type, llvm::Module& module) {
26342702
llvm::Type* pos_type = llvm::Type::getInt32Ty(context);

src/libasr/codegen/llvm_utils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,8 @@ namespace LCompilers {
258258

259259
void list_clear(llvm::Value* list);
260260

261+
void reverse(llvm::Value* list, ASR::ttype_t* list_type, llvm::Module& module);
262+
261263
llvm::Value* find_item_position(llvm::Value* list,
262264
llvm::Value* item, ASR::ttype_t* item_type,
263265
llvm::Module& module);

src/libasr/pass/intrinsic_function_registry.h

Lines changed: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ enum class IntrinsicFunctions : int64_t {
5757
Any,
5858
ListIndex,
5959
Partition,
60+
ListReverse,
6061
// ...
6162
};
6263

@@ -905,6 +906,35 @@ static inline ASR::asr_t* create_ListIndex(Allocator& al, const Location& loc,
905906

906907
} // namespace ListIndex
907908

909+
namespace ListReverse {
910+
911+
static inline ASR::expr_t *eval_list_reverse(Allocator &/*al*/,
912+
const Location &/*loc*/, Vec<ASR::expr_t*>& /*args*/) {
913+
// TODO: To be implemented for ListConstant expression
914+
return nullptr;
915+
}
916+
917+
static inline ASR::asr_t* create_ListReverse(Allocator& al, const Location& loc,
918+
Vec<ASR::expr_t*>& args,
919+
const std::function<void (const std::string &, const Location &)> err) {
920+
if (args.size() != 1) {
921+
err("list.reverse() takes no arguments", loc);
922+
}
923+
924+
Vec<ASR::expr_t*> arg_values;
925+
arg_values.reserve(al, args.size());
926+
for( size_t i = 0; i < args.size(); i++ ) {
927+
arg_values.push_back(al, ASRUtils::expr_value(args[i]));
928+
}
929+
ASR::expr_t* compile_time_value = eval_list_reverse(al, loc, arg_values);
930+
return ASR::make_Expr_t(al, loc,
931+
ASRUtils::EXPR(ASR::make_IntrinsicFunction_t(al, loc,
932+
static_cast<int64_t>(ASRUtils::IntrinsicFunctions::ListReverse),
933+
args.p, args.size(), 0, nullptr, compile_time_value)));
934+
}
935+
936+
} // namespace ListReverse
937+
908938
namespace Any {
909939

910940
static inline ASR::expr_t *eval_Any(Allocator & /*al*/,
@@ -1276,7 +1306,9 @@ namespace IntrinsicFunctionRegistry {
12761306
{static_cast<int64_t>(ASRUtils::IntrinsicFunctions::Expm1),
12771307
"expm1"},
12781308
{static_cast<int64_t>(ASRUtils::IntrinsicFunctions::ListIndex),
1279-
"list.index"}
1309+
"list.index"},
1310+
{static_cast<int64_t>(ASRUtils::IntrinsicFunctions::ListReverse),
1311+
"list.reverse"}
12801312
};
12811313

12821314
static const std::map<std::string,
@@ -1298,6 +1330,7 @@ namespace IntrinsicFunctionRegistry {
12981330
{"expm1", {&Expm1::create_Expm1, &Expm1::eval_Expm1}},
12991331
{"any", {&Any::create_Any, &Any::eval_Any}},
13001332
{"list.index", {&ListIndex::create_ListIndex, &ListIndex::eval_list_index}},
1333+
{"list.reverse", {&ListReverse::create_ListReverse, &ListReverse::eval_list_reverse}},
13011334
};
13021335

13031336
static inline bool is_intrinsic_function(const std::string& name) {
@@ -1384,6 +1417,7 @@ inline std::string get_intrinsic_name(int x) {
13841417
INTRINSIC_NAME_CASE(Any)
13851418
INTRINSIC_NAME_CASE(ListIndex)
13861419
INTRINSIC_NAME_CASE(Partition)
1420+
INTRINSIC_NAME_CASE(ListReverse)
13871421
default : {
13881422
throw LCompilersException("pickle: intrinsic_id not implemented");
13891423
}

src/lpython/semantics/python_attribute_eval.h

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ struct AttributeHandler {
2525
{"list@remove", &eval_list_remove},
2626
{"list@count", &eval_list_count},
2727
{"list@index", &eval_list_index},
28+
{"list@reverse", &eval_list_reverse},
2829
{"list@clear", &eval_list_clear},
2930
{"list@insert", &eval_list_insert},
3031
{"list@pop", &eval_list_pop},
@@ -177,6 +178,20 @@ struct AttributeHandler {
177178
{ throw SemanticError(msg, loc); });
178179
}
179180

181+
static ASR::asr_t* eval_list_reverse(ASR::expr_t *s, Allocator &al, const Location &loc,
182+
Vec<ASR::expr_t*> &args, diag::Diagnostics &/*diag*/) {
183+
Vec<ASR::expr_t*> args_with_list;
184+
args_with_list.reserve(al, args.size() + 1);
185+
args_with_list.push_back(al, s);
186+
for(size_t i = 0; i < args.size(); i++) {
187+
args_with_list.push_back(al, args[i]);
188+
}
189+
ASRUtils::create_intrinsic_function create_function =
190+
ASRUtils::IntrinsicFunctionRegistry::get_create_function("list.reverse");
191+
return create_function(al, loc, args_with_list, [&](const std::string &msg, const Location &loc)
192+
{ throw SemanticError(msg, loc); });
193+
}
194+
180195
static ASR::asr_t* eval_list_insert(ASR::expr_t *s, Allocator &al, const Location &loc,
181196
Vec<ASR::expr_t*> &args, diag::Diagnostics &diag) {
182197
if (args.size() != 2) {

0 commit comments

Comments
 (0)