Skip to content

Commit 67868c4

Browse files
committed
Implemented code generation for the following,
1. Equality check of two values 2. Deepcopy support for any two llvm values
1 parent 1610c7e commit 67868c4

File tree

1 file changed

+165
-30
lines changed

1 file changed

+165
-30
lines changed

src/libasr/codegen/llvm_utils.cpp

Lines changed: 165 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <libasr/assert.h>
22
#include <libasr/codegen/llvm_utils.h>
3+
#include <libasr/asr_utils.h>
34

45
namespace LFortran {
56

@@ -179,6 +180,59 @@ namespace LFortran {
179180
return builder->CreateCall(fn, args);
180181
}
181182

183+
llvm::Value* LLVMUtils::is_equal_by_value(llvm::Value* left, llvm::Value* right,
184+
llvm::Module& module, ASR::ttype_t* asr_type) {
185+
switch( asr_type->type ) {
186+
case ASR::ttypeType::Integer: {
187+
return builder->CreateICmpEQ(left, right);
188+
};
189+
case ASR::ttypeType::Real: {
190+
return builder->CreateFCmpOEQ(left, right);
191+
}
192+
case ASR::ttypeType::Character: {
193+
return lfortran_str_cmp(left, right, "_lpython_str_compare_eq",
194+
module);
195+
}
196+
case ASR::ttypeType::Tuple: {
197+
ASR::Tuple_t* tuple_type = ASR::down_cast<ASR::Tuple_t>(asr_type);
198+
return tuple_api->check_tuple_equality(left, right, tuple_type, context,
199+
builder, module);
200+
}
201+
default: {
202+
throw LCompilersException("LLVMUtils::is_equal_by_value isn't implemented for " +
203+
ASRUtils::type_to_str_python(asr_type));
204+
}
205+
}
206+
}
207+
208+
void LLVMUtils::deepcopy(llvm::Value* src, llvm::Value* dest,
209+
ASR::ttype_t* asr_type, llvm::Module& module) {
210+
switch( asr_type->type ) {
211+
case ASR::ttypeType::Integer:
212+
case ASR::ttypeType::Real:
213+
case ASR::ttypeType::Character:
214+
case ASR::ttypeType::Logical:
215+
case ASR::ttypeType::Complex: {
216+
LLVM::CreateStore(*builder, src, dest);
217+
break ;
218+
};
219+
case ASR::ttypeType::Tuple: {
220+
ASR::Tuple_t* tuple_type = ASR::down_cast<ASR::Tuple_t>(asr_type);
221+
tuple_api->tuple_deepcopy(src, dest, tuple_type, module);
222+
break ;
223+
}
224+
case ASR::ttypeType::List: {
225+
ASR::List_t* list_type = ASR::down_cast<ASR::List_t>(asr_type);
226+
list_api->list_deepcopy(src, dest, list_type, module);
227+
break ;
228+
}
229+
default: {
230+
throw LCompilersException("LLVMUtils::deepcopy isn't implemented for " +
231+
ASRUtils::type_to_str_python(asr_type));
232+
}
233+
}
234+
}
235+
182236
LLVMList::LLVMList(llvm::LLVMContext& context_,
183237
LLVMUtils* llvm_utils_,
184238
llvm::IRBuilder<>* builder_):
@@ -233,9 +287,9 @@ namespace LFortran {
233287
}
234288

235289
void LLVMList::list_deepcopy(llvm::Value* src, llvm::Value* dest,
236-
std::string& src_type_code,
237-
llvm::Module& module) {
290+
ASR::List_t* list_type, llvm::Module& module) {
238291
LFORTRAN_ASSERT(src->getType() == dest->getType());
292+
std::string src_type_code = ASRUtils::get_type_code(list_type->m_type);
239293
llvm::Value* src_end_point = LLVM::CreateLoad(*builder, get_pointer_to_current_end_point(src));
240294
llvm::Value* src_capacity = LLVM::CreateLoad(*builder, get_pointer_to_current_capacity(src));
241295
llvm::Value* dest_end_point_ptr = get_pointer_to_current_end_point(dest);
@@ -250,15 +304,73 @@ namespace LFortran {
250304
arg_size);
251305
llvm::Type* el_type = std::get<2>(typecode2listtype[src_type_code]);
252306
copy_data = builder->CreateBitCast(copy_data, el_type->getPointerTo());
253-
builder->CreateMemCpy(copy_data, llvm::MaybeAlign(), src_data,
254-
llvm::MaybeAlign(), arg_size);
255-
builder->CreateStore(copy_data, get_pointer_to_list_data(dest));
307+
308+
// We consider the case when the element type of a list is defined by a struct
309+
// which may also contain non-trivial structs (such as in case of list[list[f64]],
310+
// list[tuple[f64]]). We need to make sure that all the data inside those structs
311+
// is deepcopied and not just the address of the first element of those structs.
312+
// Hence we dive deeper into the lowest level of nested types and deepcopy everything
313+
// properly. If we don't consider this case then the data only from first level of nested types
314+
// will be deep copied and rest will be shallow copied. The importance of this case
315+
// can be figured out by goind through, integration_tests/test_list_06.py and
316+
// integration_tests/test_list_07.py.
317+
if( LLVM::is_llvm_struct(list_type->m_type) ) {
318+
builder->CreateStore(copy_data, get_pointer_to_list_data(dest));
319+
llvm::AllocaInst *pos_ptr = builder->CreateAlloca(llvm::Type::getInt32Ty(context),
320+
nullptr);
321+
LLVM::CreateStore(*builder, llvm::ConstantInt::get(llvm::Type::getInt32Ty(context),
322+
llvm::APInt(32, 0)), pos_ptr);
323+
324+
llvm::BasicBlock *loophead = llvm::BasicBlock::Create(context, "loop.head");
325+
llvm::BasicBlock *loopbody = llvm::BasicBlock::Create(context, "loop.body");
326+
llvm::BasicBlock *loopend = llvm::BasicBlock::Create(context, "loop.end");
327+
328+
// head
329+
llvm_utils->start_new_block(loophead);
330+
{
331+
llvm::Value *cond = builder->CreateICmpSGT(
332+
src_end_point,
333+
LLVM::CreateLoad(*builder, pos_ptr));
334+
builder->CreateCondBr(cond, loopbody, loopend);
335+
}
336+
337+
// body
338+
llvm_utils->start_new_block(loopbody);
339+
{
340+
llvm::Value* pos = LLVM::CreateLoad(*builder, pos_ptr);
341+
llvm::Value* srci = read_item(src, pos, true);
342+
llvm::Value* desti = read_item(dest, pos, true);
343+
llvm_utils->deepcopy(srci, desti, list_type->m_type, module);
344+
llvm::Value* tmp = builder->CreateAdd(
345+
pos,
346+
llvm::ConstantInt::get(context, llvm::APInt(32, 1)));
347+
LLVM::CreateStore(*builder, tmp, pos_ptr);
348+
}
349+
350+
builder->CreateBr(loophead);
351+
352+
// end
353+
llvm_utils->start_new_block(loopend);
354+
} else {
355+
builder->CreateMemCpy(copy_data, llvm::MaybeAlign(), src_data,
356+
llvm::MaybeAlign(), arg_size);
357+
builder->CreateStore(copy_data, get_pointer_to_list_data(dest));
358+
}
359+
}
360+
361+
void LLVMList::write_item(llvm::Value* list, llvm::Value* pos,
362+
llvm::Value* item, ASR::ttype_t* asr_type,
363+
llvm::Module& module) {
364+
llvm::Value* list_data = LLVM::CreateLoad(*builder, get_pointer_to_list_data(list));
365+
llvm::Value* element_ptr = llvm_utils->create_ptr_gep(list_data, pos);
366+
llvm_utils->deepcopy(item, element_ptr, asr_type, module);
256367
}
257368

258-
void LLVMList::write_item(llvm::Value* list, llvm::Value* pos, llvm::Value* item) {
369+
void LLVMList::write_item(llvm::Value* list, llvm::Value* pos,
370+
llvm::Value* item) {
259371
llvm::Value* list_data = LLVM::CreateLoad(*builder, get_pointer_to_list_data(list));
260372
llvm::Value* element_ptr = llvm_utils->create_ptr_gep(list_data, pos);
261-
builder->CreateStore(item, element_ptr);
373+
LLVM::CreateStore(*builder, item, element_ptr);
262374
}
263375

264376
llvm::Value* LLVMList::read_item(llvm::Value* list, llvm::Value* pos, bool get_pointer) {
@@ -311,21 +423,22 @@ namespace LFortran {
311423
}
312424

313425
void LLVMList::append(llvm::Value* list, llvm::Value* item,
314-
llvm::Module& module,
315-
std::string& type_code) {
426+
ASR::ttype_t* asr_type, llvm::Module& module) {
316427
llvm::Value* current_end_point = LLVM::CreateLoad(*builder, get_pointer_to_current_end_point(list));
317428
llvm::Value* current_capacity = LLVM::CreateLoad(*builder, get_pointer_to_current_capacity(list));
429+
std::string type_code = ASRUtils::get_type_code(asr_type);
318430
int type_size = std::get<1>(typecode2listtype[type_code]);
319431
llvm::Type* el_type = std::get<2>(typecode2listtype[type_code]);
320432
resize_if_needed(list, current_end_point, current_capacity,
321433
type_size, el_type, module);
322-
write_item(list, current_end_point, item);
434+
write_item(list, current_end_point, item, asr_type, module);
323435
shift_end_point_by_one(list);
324436
}
325437

326438
void LLVMList::insert_item(llvm::Value* list, llvm::Value* pos,
327-
llvm::Value* item, llvm::Module& module,
328-
std::string& type_code) {
439+
llvm::Value* item, ASR::ttype_t* asr_type,
440+
llvm::Module& module) {
441+
std::string type_code = ASRUtils::get_type_code(asr_type);
329442
llvm::Value* current_end_point = LLVM::CreateLoad(*builder,
330443
get_pointer_to_current_end_point(list));
331444
llvm::Value* current_capacity = LLVM::CreateLoad(*builder,
@@ -380,7 +493,7 @@ namespace LFortran {
380493
LLVM::CreateLoad(*builder, pos_ptr),
381494
llvm::ConstantInt::get(context, llvm::APInt(32, 1)));
382495
tmp = read_item(list, next_index, false);
383-
write_item(list, next_index, LLVM::CreateLoad(*builder, tmp_ptr));
496+
write_item(list, next_index, LLVM::CreateLoad(*builder, tmp_ptr));
384497
LLVM::CreateStore(*builder, tmp, tmp_ptr);
385498

386499
tmp = builder->CreateAdd(
@@ -393,12 +506,12 @@ namespace LFortran {
393506
// end
394507
llvm_utils->start_new_block(loopend);
395508

396-
write_item(list, pos, item);
509+
write_item(list, pos, item, asr_type, module);
397510
shift_end_point_by_one(list);
398511
}
399512

400513
llvm::Value* LLVMList::find_item_position(llvm::Value* list,
401-
llvm::Value* item, ASR::ttypeType item_type, llvm::Module& module) {
514+
llvm::Value* item, ASR::ttype_t* item_type, llvm::Module& module) {
402515
llvm::Type* pos_type = llvm::Type::getInt32Ty(context);
403516
llvm::Value* current_end_point = LLVM::CreateLoad(*builder,
404517
get_pointer_to_current_end_point(list));
@@ -425,15 +538,13 @@ namespace LFortran {
425538
// head
426539
llvm_utils->start_new_block(loophead);
427540
{
428-
llvm::Value* is_item_not_equal = nullptr;
429-
llvm::Value* left_arg = read_item(list, LLVM::CreateLoad(*builder, i), false);
430-
if( item_type == ASR::ttypeType::Character ) {
431-
is_item_not_equal = llvm_utils->lfortran_str_cmp(left_arg, item,
432-
"_lpython_str_compare_noteq",
433-
module);
434-
} else {
435-
is_item_not_equal = builder->CreateICmpNE(left_arg, item);
436-
}
541+
llvm::Value* left_arg = read_item(list, LLVM::CreateLoad(*builder, i),
542+
LLVM::is_llvm_struct(item_type));
543+
llvm::Value* is_item_not_equal = builder->CreateNot(
544+
llvm_utils->is_equal_by_value(
545+
left_arg, item,
546+
module, item_type)
547+
);
437548
llvm::Value *cond = builder->CreateAnd(is_item_not_equal,
438549
builder->CreateICmpSGT(current_end_point,
439550
LLVM::CreateLoad(*builder, i)));
@@ -484,7 +595,7 @@ namespace LFortran {
484595
}
485596

486597
void LLVMList::remove(llvm::Value* list, llvm::Value* item,
487-
ASR::ttypeType item_type, llvm::Module& module) {
598+
ASR::ttype_t* item_type, llvm::Module& module) {
488599
llvm::Type* pos_type = llvm::Type::getInt32Ty(context);
489600
llvm::Value* current_end_point = LLVM::CreateLoad(*builder,
490601
get_pointer_to_current_end_point(list));
@@ -536,6 +647,13 @@ namespace LFortran {
536647
builder->CreateStore(end_point, end_point_ptr);
537648
}
538649

650+
void LLVMList::list_clear(llvm::Value* list) {
651+
llvm::Value* end_point_ptr = get_pointer_to_current_end_point(list);
652+
llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context),
653+
llvm::APInt(32, 0));
654+
LLVM::CreateStore(*builder, zero, end_point_ptr);
655+
}
656+
539657

540658
LLVMTuple::LLVMTuple(llvm::LLVMContext& context_,
541659
LLVMUtils* llvm_utils_,
@@ -577,14 +695,31 @@ namespace LFortran {
577695
}
578696

579697
void LLVMTuple::tuple_deepcopy(llvm::Value* src, llvm::Value* dest,
580-
std::string& type_code) {
698+
ASR::Tuple_t* tuple_type, llvm::Module& module) {
581699
LFORTRAN_ASSERT(src->getType() == dest->getType());
582-
size_t n_elements = typecode2tupletype[type_code].second;
583-
for( size_t i = 0; i < n_elements; i++ ) {
584-
llvm::Value* src_item = read_item(src, i, false);
700+
for( size_t i = 0; i < tuple_type->n_type; i++ ) {
701+
llvm::Value* src_item = read_item(src, i, LLVM::is_llvm_struct(
702+
tuple_type->m_type[i]));
585703
llvm::Value* dest_item_ptr = read_item(dest, i, true);
586-
builder->CreateStore(src_item, dest_item_ptr);
704+
llvm_utils->deepcopy(src_item, dest_item_ptr,
705+
tuple_type->m_type[i], module);
706+
}
707+
}
708+
709+
llvm::Value* LLVMTuple::check_tuple_equality(llvm::Value* t1, llvm::Value* t2,
710+
ASR::Tuple_t* tuple_type,
711+
llvm::LLVMContext& context,
712+
llvm::IRBuilder<>* builder,
713+
llvm::Module& module) {
714+
llvm::Value* is_equal = llvm::ConstantInt::get(context, llvm::APInt(1, 1));
715+
for( size_t i = 0; i < tuple_type->n_type; i++ ) {
716+
llvm::Value* t1i = llvm_utils->tuple_api->read_item(t1, i);
717+
llvm::Value* t2i = llvm_utils->tuple_api->read_item(t2, i);
718+
llvm::Value* is_t1_eq_t2 = llvm_utils->is_equal_by_value(t1i, t2i, module,
719+
tuple_type->m_type[i]);
720+
is_equal = builder->CreateAnd(is_equal, is_t1_eq_t2);
587721
}
722+
return is_equal;
588723
}
589724

590725
} // namespace LFortran

0 commit comments

Comments
 (0)