1
1
#include < libasr/assert.h>
2
2
#include < libasr/codegen/llvm_utils.h>
3
+ #include < libasr/asr_utils.h>
3
4
4
5
namespace LFortran {
5
6
@@ -179,6 +180,59 @@ namespace LFortran {
179
180
return builder->CreateCall (fn, args);
180
181
}
181
182
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
+
182
236
LLVMList::LLVMList (llvm::LLVMContext& context_,
183
237
LLVMUtils* llvm_utils_,
184
238
llvm::IRBuilder<>* builder_):
@@ -233,9 +287,9 @@ namespace LFortran {
233
287
}
234
288
235
289
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 ) {
238
291
LFORTRAN_ASSERT (src->getType () == dest->getType ());
292
+ std::string src_type_code = ASRUtils::get_type_code (list_type->m_type );
239
293
llvm::Value* src_end_point = LLVM::CreateLoad (*builder, get_pointer_to_current_end_point (src));
240
294
llvm::Value* src_capacity = LLVM::CreateLoad (*builder, get_pointer_to_current_capacity (src));
241
295
llvm::Value* dest_end_point_ptr = get_pointer_to_current_end_point (dest);
@@ -250,15 +304,73 @@ namespace LFortran {
250
304
arg_size);
251
305
llvm::Type* el_type = std::get<2 >(typecode2listtype[src_type_code]);
252
306
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 );
256
367
}
257
368
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) {
259
371
llvm::Value* list_data = LLVM::CreateLoad (*builder, get_pointer_to_list_data (list));
260
372
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);
262
374
}
263
375
264
376
llvm::Value* LLVMList::read_item (llvm::Value* list, llvm::Value* pos, bool get_pointer) {
@@ -311,21 +423,22 @@ namespace LFortran {
311
423
}
312
424
313
425
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 ) {
316
427
llvm::Value* current_end_point = LLVM::CreateLoad (*builder, get_pointer_to_current_end_point (list));
317
428
llvm::Value* current_capacity = LLVM::CreateLoad (*builder, get_pointer_to_current_capacity (list));
429
+ std::string type_code = ASRUtils::get_type_code (asr_type);
318
430
int type_size = std::get<1 >(typecode2listtype[type_code]);
319
431
llvm::Type* el_type = std::get<2 >(typecode2listtype[type_code]);
320
432
resize_if_needed (list, current_end_point, current_capacity,
321
433
type_size, el_type, module );
322
- write_item (list, current_end_point, item);
434
+ write_item (list, current_end_point, item, asr_type, module );
323
435
shift_end_point_by_one (list);
324
436
}
325
437
326
438
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);
329
442
llvm::Value* current_end_point = LLVM::CreateLoad (*builder,
330
443
get_pointer_to_current_end_point (list));
331
444
llvm::Value* current_capacity = LLVM::CreateLoad (*builder,
@@ -380,7 +493,7 @@ namespace LFortran {
380
493
LLVM::CreateLoad (*builder, pos_ptr),
381
494
llvm::ConstantInt::get (context, llvm::APInt (32 , 1 )));
382
495
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));
384
497
LLVM::CreateStore (*builder, tmp, tmp_ptr);
385
498
386
499
tmp = builder->CreateAdd (
@@ -393,12 +506,12 @@ namespace LFortran {
393
506
// end
394
507
llvm_utils->start_new_block (loopend);
395
508
396
- write_item (list, pos, item);
509
+ write_item (list, pos, item, asr_type, module );
397
510
shift_end_point_by_one (list);
398
511
}
399
512
400
513
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 ) {
402
515
llvm::Type* pos_type = llvm::Type::getInt32Ty (context);
403
516
llvm::Value* current_end_point = LLVM::CreateLoad (*builder,
404
517
get_pointer_to_current_end_point (list));
@@ -425,15 +538,13 @@ namespace LFortran {
425
538
// head
426
539
llvm_utils->start_new_block (loophead);
427
540
{
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
+ );
437
548
llvm::Value *cond = builder->CreateAnd (is_item_not_equal,
438
549
builder->CreateICmpSGT (current_end_point,
439
550
LLVM::CreateLoad (*builder, i)));
@@ -484,7 +595,7 @@ namespace LFortran {
484
595
}
485
596
486
597
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 ) {
488
599
llvm::Type* pos_type = llvm::Type::getInt32Ty (context);
489
600
llvm::Value* current_end_point = LLVM::CreateLoad (*builder,
490
601
get_pointer_to_current_end_point (list));
@@ -536,6 +647,13 @@ namespace LFortran {
536
647
builder->CreateStore (end_point, end_point_ptr);
537
648
}
538
649
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
+
539
657
540
658
LLVMTuple::LLVMTuple (llvm::LLVMContext& context_,
541
659
LLVMUtils* llvm_utils_,
@@ -577,14 +695,31 @@ namespace LFortran {
577
695
}
578
696
579
697
void LLVMTuple::tuple_deepcopy (llvm::Value* src, llvm::Value* dest,
580
- std::string& type_code ) {
698
+ ASR::Tuple_t* tuple_type, llvm::Module& module ) {
581
699
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]) );
585
703
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);
587
721
}
722
+ return is_equal;
588
723
}
589
724
590
725
} // namespace LFortran
0 commit comments