Repository: lfortran/lfortran
Pull request #6618: Fix : Copy array descriptor info with `associate` expression
Author: login: assem2002
Created: 2025-03-14T09:08:01Z | Merged: 2025-03-15T14:04:25Z

Fixes #6611 
- Shallow copy data ptr
- Deep copy dimension descriptor + offset value

This change led to :
- Change on how we store `null()` in arrays (it used to set the whole descriptor to null and we fully depend on declared arrays to be ready for use)

Linked issue #6611: MRE for pot3d `--fast` compilation
```fortran
module xx
    type :: rp1d
        real, dimension(:), pointer :: f
    end type

    type :: sds
        integer, dimension(3) :: dims
        type(rp1d), dimension(3) :: scales
        real, dimension(:), pointer :: f
    end type
end module
subroutine sub()
    use xx
    real, dimension(:), pointer :: x
    call sub_to_allocate(x)
    print *, "x in sub = ", x
    deallocate(x)
    contains
    subroutine sub_to_allocate(x)
        use xx
        real, dimension(:), pointer :: x
        type(sds) :: s
        allocate(s%scales(1)%f(2))
        x => s%scales(1)%f
        x(1) = 2.0
        x(2) = 1.0
        print *, "x = ", x
    end subroutine
end subroutine
program derived_types_43
    implicit none
    call sub()
end program
```

```console
% lfortran a.f90           
x = 
2.00000000e+00
1.00000000e+00

x in sub = 

% lfortran a.f90 --fast
x = 
2.00000000e+00
1.00000000e+00

x in sub = 

a.out(11318,0x1ec134c00) malloc: *** error for object 0x10028bef7: pointer being freed was not allocated
a.out(11318,0x1ec134c00) malloc: *** set a breakpoint in malloc_error_break to debug
% gfortran a.f90 && ./a.out
 x =    2.00000000       1.00000000    
 x in sub =    2.00000000       1.00000000    
% gfortran a.f90 -o3 && ./a.out            
 x =    2.00000000       1.00000000    
 x in sub =    2.00000000       1.00000000    
```
Linked issue comments: user: login: gxyd
created_at: 2025-03-13T17:18:24Z
body: MRE pretty much extracted from POT3D without any assumptions:
```f90
module sds_def
      implicit none
      integer, parameter, private :: mxdim = 3
      type :: rp1d
        real, dimension(:), pointer :: f
      end type

      type :: sds
        integer :: ndim
        integer, dimension(mxdim) :: dims
        type(rp1d), dimension(mxdim) :: scales
        real, dimension(:,:,:), pointer :: f
      end type
end module

program POT3D
      use sds_def
      implicit none
      real, dimension(:,:), pointer :: bn
      real, dimension(:), pointer :: tn
      integer :: ntn,npn
      call rdhdf_2d (ntn,npn,bn,tn)
      deallocate (bn)
      deallocate (tn)

      contains

      subroutine rdhdf_2d (nx,ny,f,x)
           implicit none
           integer :: nx,ny,i
           real, dimension(:,:), pointer :: f
           real, dimension(:), pointer :: x
           intent(out) :: nx,ny
           type(sds) :: s
           s%dims(:) = 1
           s%ndim = 2
           s%dims(1) = 5
           s%dims(2) = 7
           allocate (s%f(5,7,1))
           allocate(s%scales(1)%f(5))
           allocate(s%scales(2)%f(7))
           allocate (s%scales(3)%f(1))
           nx=s%dims(1)
           ny=s%dims(2)
           x=>s%scales(1)%f
           allocate (f(nx,ny))
           f(:,:)=s%f(:,:,1)
           deallocate (s%f)
      end subroutine
end program pot3d


```

On it's execution with LFortran, I get the below output/error:
```console
> lfortran --version
LFortran version: 0.48.0-40-gbcc0dc28b-dirty
Platform: macOS ARM
LLVM: 11.1.0
Default target: arm64-apple-darwin23.6.0

> lfortran pot3d.F90 --fast
pot3d.out(36316,0x1feac4f40) malloc: *** error for object 0x104fa8080: pointer being freed was not allocated
pot3d.out(36316,0x1feac4f40) malloc: *** set a breakpoint in malloc_error_break to debug

> echo $?
6

> lfortran pot3d.F90
> echo $?
0
```
author_association: CONTRIBUTOR
user: login: Pranavchiku
created_at: 2025-03-13T17:20:05Z
body: Bingo!
author_association: MEMBER
user: login: Pranavchiku
created_at: 2025-03-13T17:23:30Z
body: The fix seems simple, we just do not free a variable if it is a function argument and pointer / allocatable.
author_association: MEMBER
user: login: Pranavchiku
created_at: 2025-03-13T18:16:31Z
body: ```fortran
program derived_types_43
    type :: sds
        real, dimension(:), pointer :: f
    end type
    real, dimension(:), pointer :: x
    call sub_to_allocate(x)
    if ( abs(x(1) - 1.0) > 1e-8 ) error stop
    print *, "x in sub = ", x
    deallocate(x)
contains
    subroutine sub_to_allocate(x)
        real, dimension(:), pointer, intent(inout) :: x
        type(sds) :: s
        allocate(s%f(2))
        x => s%f
        x(1)=1.0
        x(2)=2.0
        print *, "x = ", x
    end subroutine
end program

```

```console
% lfortran a.f90
x = 
1.00000000e+00
2.00000000e+00

x in sub = 
% echo $?
11
% gfortran a.f90 && ./a.out
 x =    1.00000000       2.00000000    
 x in sub =    1.00000000       2.00000000    
```
author_association: MEMBER
user: login: Pranavchiku
created_at: 2025-03-13T18:20:45Z
body: ```fortran
program derived_types_43
    type :: sds
        real, dimension(:), pointer :: f
    end type
    real, dimension(:), pointer :: x
    call sub_to_allocate(x)
    print *, "size(x): ", size(x)
    print *, "lbound(x): ", lbound(x)
    print *, "ubound(x): ", ubound(x)
    if ( abs(x(1) - 1.0) > 1e-8 ) error stop
    if ( abs(x(2) - 2.0) > 1e-8 ) error stop
    print *, "x in sub = ", x
    deallocate(x)
contains
    subroutine sub_to_allocate(x)
        real, dimension(:), pointer, intent(inout) :: x
        type(sds) :: s
        allocate(s%f(2))
        x => s%f
        x(1)=1.0

        print *, "x = ", x
    end subroutine
end program
```

```console
% lfortran a.f90           
x = 
1.00000000e+00
2.00000000e+00

size(x):     2
lbound(x):     620765245
ubound(x):     628311471
% echo $?
11
% gfortran a.f90 && ./a.out
 x =    1.00000000       2.00000000    
 size(x):            2
 lbound(x):            1
 ubound(x):            2
 x in sub =    1.00000000       2.00000000    
```
author_association: MEMBER
user: login: Pranavchiku
created_at: 2025-03-13T18:22:58Z
body: ```fortran
program derived_types_43
    type :: sds
        real, dimension(:), pointer :: f
    end type
    real, dimension(:), pointer :: x
    call sub_to_allocate(x)
    print *, "size(x): ", size(x)
    print *, "lbound(x): ", lbound(x)
    if (lbound(x,1) /= 1) error stop
    print *, "ubound(x): ", ubound(x)
    if ( abs(x(1) - 1.0) > 1e-8 ) error stop
    if ( abs(x(2) - 2.0) > 1e-8 ) error stop
    print *, "x in sub = ", x
    deallocate(x)
contains
    subroutine sub_to_allocate(x)
        real, dimension(:), pointer, intent(inout) :: x
        type(sds) :: s
        allocate(s%f(2))
        x => s%f
        x(1)=1.0
        x(2)=2.0
        print *, "x = ", x
    end subroutine
end program

```

```console
% lfortran a.f90
x = 
1.00000000e+00
2.00000000e+00

size(x):     2
lbound(x):     620765245
ERROR STOP
% gfortran a.f90 && ./a.out
 x =    1.00000000       2.00000000    
 size(x):            2
 lbound(x):            1
 ubound(x):            2
 x in sub =    1.00000000       2.00000000    
```
author_association: MEMBER
user: login: certik
created_at: 2025-03-13T18:29:51Z
body: Relevant issues:

* Previous PR: https://github.com/lfortran/lfortran/pull/6378, issue: https://github.com/lfortran/lfortran/issues/6377
* https://github.com/lfortran/lfortran/issues/6612
author_association: CONTRIBUTOR
user: login: assem2002
created_at: 2025-03-13T21:49:52Z
body: Some of the MRE outputs are OS dependent as we have undefined behavior here. But in general we get an error while printing after call to `sub_to_allocate`  
author_association: CONTRIBUTOR

Diff:
diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt
index 6c9a2cd93be..af1a717221f 100644
--- a/integration_tests/CMakeLists.txt
+++ b/integration_tests/CMakeLists.txt
@@ -1370,6 +1370,7 @@ RUN(NAME derived_types_40 LABELS gfortran llvm)
 RUN(NAME derived_types_41 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc)
 RUN(NAME derived_types_42 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc)
 RUN(NAME derived_types_43 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc)
+RUN(NAME derived_types_44 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc)
 
 RUN(NAME type_parameter_inquiry_01 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc)
 
diff --git a/integration_tests/derived_types_44.f90 b/integration_tests/derived_types_44.f90
new file mode 100644
index 00000000000..a0a35e2417b
--- /dev/null
+++ b/integration_tests/derived_types_44.f90
@@ -0,0 +1,32 @@
+! Test pointer association
+program derived_types_44
+    type :: sds
+        real, dimension(:), pointer :: f
+    end type
+    real, dimension(:), pointer :: x
+    call sub_to_allocate(x)
+    print *, "size(x): ", size(x)
+    print *, "lbound(x): ", lbound(x)
+    if (lbound(x,1) /= 1) error stop
+    print *, "ubound(x): ", ubound(x)
+    if ( abs(x(1) - 1.0) > 1e-8 ) error stop
+    if ( abs(x(2) - 2.0) > 1e-8 ) error stop
+    if ( abs(x(100000) - 88.0) > 1e-8 ) error stop
+    print *, "x(1) = ", x(1)
+    print *, "x(2) = ", x(2)
+    print *, "x(100000) = ", x(100000) ! Use big size to make sure about correct memory.
+    deallocate(x)
+contains
+    subroutine sub_to_allocate(x)
+        real, dimension(:), pointer, intent(inout) :: x
+        type(sds) :: s
+        allocate(s%f(100000))
+        x => s%f
+        x(1)=1.0
+        x(2)=2.0
+        x(100000)=88.0
+        print *, "x(1) = ", x(1)
+        print *, "x(2) = ", x(2)
+        print *, "x(100000) = ", x(100000)
+    end subroutine
+end program
diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp
index 405e50995c5..afdd2a94ade 100644
--- a/src/libasr/codegen/asr_to_llvm.cpp
+++ b/src/libasr/codegen/asr_to_llvm.cpp
@@ -1076,10 +1076,10 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
 #if LLVM_VERSION_MAJOR > 16
                             ptr_type[ptr_] = type;
 #endif
-                            arr_descr->fill_dimension_descriptor(ptr_, n_dims, module.get(), ASRUtils::expr_type(tmp_expr));
+                            arr_descr->fill_dimension_descriptor(ptr_, n_dims);
                         } else {
                             ptr_ = llvm_utils->CreateAlloca(*builder, type);
-                            arr_descr->fill_dimension_descriptor(ptr_, n_dims,nullptr,nullptr);
+                            arr_descr->fill_dimension_descriptor(ptr_, n_dims);
                         }
                         LLVM::CreateStore(*builder, ptr_, x_arr);
                     },
@@ -1162,9 +1162,20 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
                 // functions are pointers in LLVM, so we do not need to get the pointer to it
                 dest_type = tp;
             }
-            llvm::Value* np = builder->CreateIntToPtr(
-                llvm::ConstantInt::get(context, llvm::APInt(32, 0)), dest_type);
-            builder->CreateStore(np, target);
+
+
+            if(ASRUtils::is_array(ASRUtils::expr_type(x.m_vars[i]))){
+                llvm::Value* target_ = llvm_utils->CreateLoad2(ASRUtils::expr_type(x.m_vars[i]), target);
+                llvm::Value* data_ptr = arr_descr->get_pointer_to_data(ASRUtils::expr_type(x.m_vars[i]), target_ , module.get());
+                builder->CreateStore(
+                    llvm::ConstantPointerNull::get(llvm_utils->get_el_type(
+                        ASRUtils::extract_type(ASRUtils::expr_type(x.m_vars[i])), module.get())->getPointerTo())
+                    , data_ptr);
+            } else {
+                llvm::Value* np = builder->CreateIntToPtr(
+                    llvm::ConstantInt::get(context, llvm::APInt(32, 0)), dest_type);
+                builder->CreateStore(np, target);
+            }
         }
     }
 
@@ -3144,7 +3155,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
     }
 
     void visit_PointerNullConstant(const ASR::PointerNullConstant_t& x){
-        llvm::Type* value_type = llvm_utils->get_type_from_ttype_t_util(x.m_type, module.get());
+        llvm::Type* value_type;
+        value_type = ASRUtils::is_array(x.m_type)?
+            llvm_utils->get_type_from_ttype_t_util(
+                ASRUtils::extract_type(x.m_type), module.get())->getPointerTo():
+            llvm_utils->get_type_from_ttype_t_util(x.m_type, module.get());
         tmp = llvm::ConstantPointerNull::get(static_cast<llvm::PointerType*>(value_type));
     }
 
@@ -3497,7 +3512,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
         llvm::Value* ptr_ = nullptr;
         if( is_malloc_array_type && !is_list && !is_data_only ) {
             ptr_ = llvm_utils->CreateAlloca(*builder, type_, nullptr, "arr_desc");
-            arr_descr->fill_dimension_descriptor(ptr_, n_dims, nullptr, nullptr);
+            arr_descr->fill_dimension_descriptor(ptr_, n_dims);
         }
         if( is_array_type && !is_malloc_array_type &&
             !is_list ) {
@@ -3562,10 +3577,6 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor<ASRToLLVMVisitor>
                 set_pointer_variable_to_null(llvm::Constant::getNullValue(
                     llvm_utils->get_type_from_ttype_t_util(v->m_type, module.get())),
                     ptr_member);
-                if( v->m_symbolic_value ) {
-                    visit_expr(*v->m_symbolic_value);
-                    LLVM::CreateStore(*builder, tmp, ptr_member);
-                }
             }
             if( ASRUtils::is_array(symbol_type) && v) {
                 ASR::dimension_t* m_dims = nullptr;
@@ -3605,6 +3616,25 @@ ptr_type[ptr_member] = llvm_utils->get_type_from_ttype_t_util(
             } else if( ASR::is_a<ASR::StructType_t>(*symbol_type) ) {
                 allocate_array_members_of_struct(ptr_member, symbol_type);
             }
+            if( ASR::is_a<ASR::Variable_t>(*sym) ) {
+                v = ASR::down_cast<ASR::Variable_t>(sym);
+                if( v->m_symbolic_value ) {
+                    visit_expr(*v->m_symbolic_value);
+                    if( ASR::is_a<ASR::PointerNullConstant_t>(*v->m_symbolic_value) &&
+                        ASRUtils::is_array(v->m_type)){ // Store into array's data pointer.
+                        LCOMPILERS_ASSERT(ASR::is_a<ASR::Pointer_t>(*v->m_type));
+                        llvm::Value* pointer_array = builder->CreateLoad(
+                            llvm_utils->get_type_from_ttype_t_util(v->m_type, module.get()),
+                            ptr_member);
+                        llvm::Type* const array_desc_type = llvm_utils->arr_api->
+                            get_array_type(ASRUtils::type_get_past_allocatable_pointer(v->m_type), 
+                                llvm_utils->get_el_type(ASRUtils::extract_type(v->m_type), module.get()), false);
+                        builder->CreateStore(tmp, llvm_utils->create_gep2(array_desc_type, pointer_array, 0));
+                    } else {
+                        LLVM::CreateStore(*builder, tmp, ptr_member);
+                    }
+                }
+            }
         }
     }
 
@@ -3786,6 +3816,18 @@ ptr_type[ptr_member] = llvm_utils->get_type_from_ttype_t_util(
             if (v->m_intent == intent_local) {
                 strings_to_be_deallocated.push_back(al, llvm_utils->CreateLoad2(v->m_type, target_var));
             }
+        } else if(ASRUtils::is_array(v->m_type) &&
+                (ASR::is_a<ASR::PointerNullConstant_t>(*v->m_symbolic_value) || 
+                ASR::is_a<ASR::PointerNullConstant_t>(*v->m_value))){
+                LCOMPILERS_ASSERT(ASR::is_a<ASR::Pointer_t>(*v->m_type));
+                LCOMPILERS_ASSERT(ASRUtils::extract_physical_type(v->m_type) ==
+                                     ASR::array_physical_typeType::DescriptorArray);
+                llvm::Type* const array_desc_type = llvm_utils->arr_api->
+                    get_array_type(ASRUtils::type_get_past_allocatable_pointer(v->m_type), 
+                        llvm_utils->get_el_type(ASRUtils::extract_type(v->m_type), module.get()), false);
+                llvm::Value* data_ptr = llvm_utils->create_gep2(array_desc_type,
+                    llvm_utils->CreateLoad(target_var), 0);
+                builder->CreateStore(init_value, data_ptr);
         } else {
             if (v->m_storage == ASR::storage_typeType::Save
                 && v->m_value
@@ -4732,6 +4774,15 @@ ptr_type[ptr_member] = llvm_utils->get_type_from_ttype_t_util(
             ASRUtils::type_get_past_allocatable(
             ASRUtils::type_get_past_pointer(p_type)), module.get());
         ptr = llvm_utils->CreateLoad2(p_type, ptr);
+        if( ASRUtils::is_array(p_type) &&
+            ASRUtils::extract_physical_type(p_type) ==
+            ASR::array_physical_typeType::DescriptorArray) {
+            LCOMPILERS_ASSERT(ASR::is_a<ASR::Pointer_t>(*p_type));
+            ptr = arr_descr->get_pointer_to_data(ptr);
+            llvm::Type* array_inner_type = llvm_utils->get_type_from_ttype_t_util(
+                ASRUtils::extract_type(p_type), module.get());
+            ptr = llvm_utils->CreateLoad2(array_inner_type->getPointerTo(), ptr);
+        }
         ptr_type[ptr] = ptr_arr_type;
         ptr_loads = ptr_loads_copy;
         if( ASR::is_a<ASR::CPtr_t>(*ASRUtils::expr_type(x.m_ptr)) &&
@@ -4768,11 +4819,13 @@ ptr_type[ptr_member] = llvm_utils->get_type_from_ttype_t_util(
                         ASRUtils::expr_type(x.m_tgt));
                     if( tgt_ptype == ASR::array_physical_typeType::FixedSizeArray ) {
                         nptr = llvm_utils->create_gep(nptr, 0);
-                    }
-                    if( tgt_ptype != ASR::array_physical_typeType::DescriptorArray ) {
-                        llvm::Type *value_type = llvm_utils->get_type_from_ttype_t_util(
+                    } else if( tgt_ptype == ASR::array_physical_typeType::DescriptorArray ) {
+                        llvm::Type* array_type = llvm_utils->get_type_from_ttype_t_util(
+                            ASRUtils::expr_type(x.m_tgt), module.get());
+                        llvm::Type *array_inner_type = llvm_utils->get_type_from_ttype_t_util(
                             ASRUtils::extract_type(p_type), module.get());
-                        ptr = llvm_utils->CreateLoad2(value_type->getPointerTo(), arr_descr->get_pointer_to_data(ptr));
+                        nptr = builder->CreateLoad(array_type, nptr);
+                        nptr = llvm_utils->CreateLoad2(array_inner_type->getPointerTo(), arr_descr->get_pointer_to_data(nptr));
                     }
                 }
                 nptr = builder->CreatePtrToInt(nptr, llvm_utils->getIntType(8, false));
@@ -4911,6 +4964,12 @@ ptr_type[ptr_member] = llvm_utils->get_type_from_ttype_t_util(
                     ASRUtils::type_get_past_allocatable(value_type)));
             llvm::Type *i64 = llvm::Type::getInt64Ty(context);
             if (ASR::is_a<ASR::PointerNullConstant_t>(*x.m_value)) {
+                if(ASRUtils::is_array(target_type) ){ // Fetch data ptr
+                    LCOMPILERS_ASSERT(ASRUtils::extract_physical_type(target_type) == 
+                        ASR::array_physical_typeType::DescriptorArray);
+                    llvm_target = llvm_utils->CreateLoad(llvm_target);
+                    llvm_target = arr_descr->get_pointer_to_data(llvm_target);
+                }
                 builder->CreateStore(llvm_value, llvm_target);
             } else if (ASR::is_a<ASR::StructInstanceMember_t>(*x.m_value) &&
                         ASR::is_a<ASR::FunctionType_t>(*value_type)) {
@@ -4951,15 +5010,45 @@ ptr_type[ptr_member] = llvm_utils->get_type_from_ttype_t_util(
             } else {
                 bool is_value_data_only_array = (ASRUtils::is_array(value_type) && (
                       ASRUtils::extract_physical_type(value_type) == ASR::array_physical_typeType::PointerToDataArray ||
-                      ASRUtils::extract_physical_type(value_type) == ASR::array_physical_typeType::FixedSizeArray));
+                      ASRUtils::extract_physical_type(value_type) == ASR::array_physical_typeType::FixedSizeArray || 
+                      ASRUtils::extract_physical_type(value_type) == ASR::array_physical_typeType::DescriptorArray));
                 if( LLVM::is_llvm_pointer(*value_type) ) {
                     llvm_value = llvm_utils->CreateLoad(llvm_value);
                 }
-                if( is_value_data_only_array ) {
+                if( is_value_data_only_array ) { // This needs a refactor to handle 
                     ASR::ttype_t* target_type_ = ASRUtils::type_get_past_pointer(target_type);
                     switch( ASRUtils::extract_physical_type(target_type_) ) {
                         case ASR::array_physical_typeType::DescriptorArray: {
-                            if( ASRUtils::extract_physical_type(value_type) == ASR::array_physical_typeType::FixedSizeArray ) {
+                            if(ASRUtils::extract_physical_type(value_type) == ASR::array_physical_typeType::DescriptorArray){
+                                // Declare llvm type for (Array descriptor, Dimension Descriptor) 
+                                llvm::Type* const array_desc_type = llvm_utils->arr_api->
+                                    get_array_type(ASRUtils::type_get_past_allocatable_pointer(value_type), 
+                                        llvm_utils->get_el_type(ASRUtils::extract_type(value_type), module.get()), false);
+                                LCOMPILERS_ASSERT(array_desc_type->isStructTy());
+                                llvm::Type* const dim_desc_type = llvm_utils->arr_api->get_dimension_descriptor_type(false);
+                                llvm::Value* llvm_target_ = builder->CreateLoad(array_desc_type->getPointerTo(), llvm_target);
+                                // Store exact data pointer
+                                llvm::Value* value_data_ptr = llvm_utils->create_gep2(array_desc_type, llvm_value, 0); // Pointer to data of the RHS array.
+                                llvm::Value* target_data_ptr = llvm_utils->create_gep2(array_desc_type, llvm_target_, 0); // Pointer to data of the LHS array.
+                                builder->CreateStore(builder->CreateLoad(
+                                    llvm_utils->get_el_type(
+                                        ASRUtils::extract_type(value_type), module.get())->getPointerTo(), value_data_ptr),
+                                    target_data_ptr);
+                                // Deep Copy dimension descriptor
+                                llvm::Value* value_dim_ptr = builder->CreateLoad(dim_desc_type->getPointerTo(),
+                                                                 llvm_utils->create_gep2(array_desc_type, llvm_value, 2)); // Pointer to dimension descriptor of the RHS array.
+                                llvm::Value* target_dim_ptr = builder->CreateLoad(dim_desc_type->getPointerTo(),
+                                                            llvm_utils->create_gep2(array_desc_type, llvm_target_, 2)); // Pointer to dimension descriptor of the LHS array.
+                                llvm::DataLayout data_layout(module->getDataLayout());
+                                int dim_desc_size = (int)data_layout.getTypeAllocSize(dim_desc_type);
+                                builder->CreateMemCpy(target_dim_ptr, llvm::MaybeAlign(8), value_dim_ptr, llvm::MaybeAlign(8), dim_desc_size*n_dims);
+                                // Copy offset
+                                llvm::Value* value_offset = llvm_utils->create_gep2(array_desc_type, llvm_value, 1); // Pointer to offset of the RHS array.
+                                llvm::Value* target_offset = llvm_utils->create_gep2(array_desc_type, llvm_target_, 1); // Pointer to offset of the LHS array.
+                                builder->CreateStore(builder->CreateLoad(llvm::Type::getInt32Ty(context),value_offset), target_offset);
+                                // Other fields of the array descriptor should be already set.
+                                return;
+                            }else if( ASRUtils::extract_physical_type(value_type) == ASR::array_physical_typeType::FixedSizeArray ) {
                                 llvm_value = llvm_utils->create_gep(llvm_value, 0);
                             }
                             llvm::Type* llvm_target_type = llvm_utils->get_type_from_ttype_t_util(target_type_, module.get());
diff --git a/src/libasr/codegen/llvm_array_utils.cpp b/src/libasr/codegen/llvm_array_utils.cpp
index ee8a10e119e..9db23adc95f 100644
--- a/src/libasr/codegen/llvm_array_utils.cpp
+++ b/src/libasr/codegen/llvm_array_utils.cpp
@@ -390,26 +390,13 @@ namespace LCompilers {
             builder->CreateStore(first_ptr, ptr2firstptr);
         }
 
-        void SimpleCMODescriptor::fill_dimension_descriptor(
-            llvm::Value* arr, int n_dims,llvm::Module* module ,ASR::ttype_t* type ) {
+        void SimpleCMODescriptor::fill_dimension_descriptor(llvm::Value* arr, int n_dims) {
             llvm::Value* dim_des_val = llvm_utils->create_gep(arr, 2);
             llvm::Value* llvm_ndims = llvm_utils->CreateAlloca(*builder, llvm::Type::getInt32Ty(context));
             builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, n_dims)), llvm_ndims);
             llvm::Value* dim_des_first;
-            if(type && ASR::is_a<ASR::Pointer_t>(*type)){
-                std::vector<llvm::Value*> idx_vec = {
-                    llvm::ConstantInt::get(context, llvm::APInt(32, 1))};
-                    llvm::Value* null_dim_des_ptr = llvm::ConstantPointerNull::get(dim_des->getPointerTo());
-                    llvm::Value* size_of_dim_des_struct = llvm_utils->CreateGEP2(dim_des, null_dim_des_ptr, idx_vec);
-                    llvm::Value* size_of_dim_des_struct_casted = builder->CreatePtrToInt(size_of_dim_des_struct, llvm::Type::getInt32Ty(context)); //cast to int32
-                    llvm::Value* size_mul_ndim = builder->CreateMul(size_of_dim_des_struct_casted, llvm::ConstantInt::get(context, llvm::APInt(32, n_dims)));
-                    llvm::Value* struct_ptr = LLVMArrUtils::lfortran_malloc(
-                        context, *module, *builder, size_mul_ndim);
-                    dim_des_first = builder->CreateBitCast(struct_ptr, dim_des->getPointerTo());
-            } else {
-                dim_des_first = llvm_utils->CreateAlloca(*builder, dim_des,
-                                        llvm_utils->CreateLoad(llvm_ndims));
-            }
+            dim_des_first = llvm_utils->CreateAlloca(*builder, dim_des,
+                                    llvm_utils->CreateLoad(llvm_ndims));
             builder->CreateStore(dim_des_first, dim_des_val);
             builder->CreateStore(llvm::ConstantInt::get(context, llvm::APInt(32, n_dims)), get_rank(arr, true));
         }
@@ -568,6 +555,13 @@ namespace LCompilers {
             return llvm_utils->create_gep(arr, 0);
         }
 
+        llvm::Value* SimpleCMODescriptor::get_pointer_to_data(ASR::ttype_t* arr_type, llvm::Value* arr, llvm::Module* module) {
+            llvm::Type* const array_desc_type = llvm_utils->arr_api->
+                get_array_type(ASRUtils::type_get_past_allocatable_pointer(arr_type), 
+                    llvm_utils->get_el_type(ASRUtils::extract_type(arr_type), module), false);
+            return llvm_utils->create_gep2(array_desc_type, arr, 0);
+        }
+
         llvm::Value* SimpleCMODescriptor::get_offset(llvm::Value* arr, bool load) {
             llvm::Value* offset = llvm_utils->create_gep(arr, 1);
             if( !load ) {
diff --git a/src/libasr/codegen/llvm_array_utils.h b/src/libasr/codegen/llvm_array_utils.h
index 7b144f2427d..907410c0e09 100644
--- a/src/libasr/codegen/llvm_array_utils.h
+++ b/src/libasr/codegen/llvm_array_utils.h
@@ -154,8 +154,7 @@ namespace LCompilers {
                     llvm::Module* module, bool realloc=false) = 0;
 
                 virtual
-                void fill_dimension_descriptor(
-                    llvm::Value* arr, int n_dims, llvm::Module* module,ASR::ttype_t* type) = 0;
+                void fill_dimension_descriptor(llvm::Value* arr, int n_dims) = 0;
 
                 virtual
                 void reset_array_details(
@@ -189,6 +188,15 @@ namespace LCompilers {
                 */
                 virtual
                 llvm::Value* get_pointer_to_data(llvm::Value* arr) = 0;
+                
+                /*
+                * Returns pointer to data in the input
+                * array descriptor according to the rules
+                * implemented by current class.
+                * Uses ASR type to get the corresponding LLVM type 
+                */
+                virtual
+                llvm::Value* get_pointer_to_data(ASR::ttype_t* arr_type, llvm::Value* arr, llvm::Module* module) = 0;
 
                 /*
                 * Returns offset in the input
@@ -374,8 +382,7 @@ namespace LCompilers {
                     llvm::Module* module, bool realloc=false);
 
                 virtual
-                void fill_dimension_descriptor(
-                    llvm::Value* arr, int n_dims, llvm::Module* module, ASR::ttype_t* type);
+                void fill_dimension_descriptor(llvm::Value* arr, int n_dims);
 
                 virtual
                 void reset_array_details(
@@ -401,6 +408,13 @@ namespace LCompilers {
                 virtual
                 llvm::Value* get_pointer_to_data(llvm::Value* arr);
 
+                /* 
+                 * Return pointer to data in array descriptor,
+                 * Used arr_type to get the corresponding llvm::Type (LLVM 17+).
+                */
+                virtual
+                llvm::Value* get_pointer_to_data(ASR::ttype_t* arr_type, llvm::Value* arr, llvm::Module* module);
+
                 virtual
                 llvm::Value* get_rank(llvm::Value* arr, bool get_pointer=false);
 
diff --git a/tests/reference/llvm-arrays_13-8ff7d44.json b/tests/reference/llvm-arrays_13-8ff7d44.json
index 16ead514ac1..d8a408c0242 100644
--- a/tests/reference/llvm-arrays_13-8ff7d44.json
+++ b/tests/reference/llvm-arrays_13-8ff7d44.json
@@ -6,7 +6,7 @@
     "outfile": null,
     "outfile_hash": null,
     "stdout": "llvm-arrays_13-8ff7d44.stdout",
-    "stdout_hash": "5e2143b47d38bc01b8025e0719f444774990595cd7925c681e540584",
+    "stdout_hash": "634a966cd0987f48fe28df69a9c6c36f502e41f7701e3ee2ad2b456e",
     "stderr": null,
     "stderr_hash": null,
     "returncode": 0
diff --git a/tests/reference/llvm-arrays_13-8ff7d44.stdout b/tests/reference/llvm-arrays_13-8ff7d44.stdout
index dc04d9773ef..a56c7aafdb0 100644
--- a/tests/reference/llvm-arrays_13-8ff7d44.stdout
+++ b/tests/reference/llvm-arrays_13-8ff7d44.stdout
@@ -75,119 +75,149 @@ define i32 @main(i32 %0, i8** %1) {
   store i32 1, i32* %22, align 4
   store i32 1, i32* %23, align 4
   store i32 2, i32* %24, align 4
-  store %array.0* %array_descriptor, %array.0** %i, align 8
-  %25 = getelementptr [6 x float], [6 x float]* %rv, i32 0, i32 0
-  %26 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 0
-  store float* %25, float** %26, align 8
-  %27 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 1
-  store i32 0, i32* %27, align 4
-  %28 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 2
-  %29 = alloca %dimension_descriptor, i32 2, align 8
-  store %dimension_descriptor* %29, %dimension_descriptor** %28, align 8
-  %30 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 4
-  store i32 2, i32* %30, align 4
-  %31 = load %dimension_descriptor*, %dimension_descriptor** %28, align 8
-  %32 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %31, i32 0
-  %33 = getelementptr %dimension_descriptor, %dimension_descriptor* %32, i32 0, i32 0
-  %34 = getelementptr %dimension_descriptor, %dimension_descriptor* %32, i32 0, i32 1
-  %35 = getelementptr %dimension_descriptor, %dimension_descriptor* %32, i32 0, i32 2
-  store i32 1, i32* %33, align 4
-  store i32 1, i32* %34, align 4
-  store i32 2, i32* %35, align 4
-  %36 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %31, i32 1
-  %37 = getelementptr %dimension_descriptor, %dimension_descriptor* %36, i32 0, i32 0
-  %38 = getelementptr %dimension_descriptor, %dimension_descriptor* %36, i32 0, i32 1
-  %39 = getelementptr %dimension_descriptor, %dimension_descriptor* %36, i32 0, i32 2
-  store i32 2, i32* %37, align 4
-  store i32 1, i32* %38, align 4
-  store i32 3, i32* %39, align 4
-  store %array* %array_descriptor4, %array** %r, align 8
-  %40 = load %array.0*, %array.0** %i, align 8
-  %41 = getelementptr %array.0, %array.0* %40, i32 0, i32 2
-  %42 = load %dimension_descriptor*, %dimension_descriptor** %41, align 8
-  %43 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %42, i32 0
-  %44 = getelementptr %dimension_descriptor, %dimension_descriptor* %43, i32 0, i32 1
-  %45 = load i32, i32* %44, align 4
-  %46 = sub i32 1, %45
-  %47 = getelementptr %dimension_descriptor, %dimension_descriptor* %43, i32 0, i32 0
-  %48 = load i32, i32* %47, align 4
-  %49 = mul i32 %48, %46
-  %50 = add i32 0, %49
-  %51 = getelementptr %array.0, %array.0* %40, i32 0, i32 1
-  %52 = load i32, i32* %51, align 4
-  %53 = add i32 %50, %52
-  %54 = getelementptr %array.0, %array.0* %40, i32 0, i32 0
-  %55 = load i32*, i32** %54, align 8
-  %56 = getelementptr inbounds i32, i32* %55, i32 %53
-  store i32 1, i32* %56, align 4
-  %57 = load %array.0*, %array.0** %i, align 8
-  %58 = getelementptr %array.0, %array.0* %57, i32 0, i32 2
-  %59 = load %dimension_descriptor*, %dimension_descriptor** %58, align 8
-  %60 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %59, i32 0
-  %61 = getelementptr %dimension_descriptor, %dimension_descriptor* %60, i32 0, i32 1
-  %62 = load i32, i32* %61, align 4
-  %63 = sub i32 1, %62
-  %64 = getelementptr %dimension_descriptor, %dimension_descriptor* %60, i32 0, i32 0
-  %65 = load i32, i32* %64, align 4
-  %66 = mul i32 %65, %63
-  %67 = add i32 0, %66
-  %68 = getelementptr %array.0, %array.0* %57, i32 0, i32 1
-  %69 = load i32, i32* %68, align 4
-  %70 = add i32 %67, %69
-  %71 = getelementptr %array.0, %array.0* %57, i32 0, i32 0
-  %72 = load i32*, i32** %71, align 8
-  %73 = getelementptr inbounds i32, i32* %72, i32 %70
+  %25 = load %array.0*, %array.0** %i, align 8
+  %26 = getelementptr %array.0, %array.0* %array_descriptor, i32 0, i32 0
+  %27 = getelementptr %array.0, %array.0* %25, i32 0, i32 0
+  %28 = load i32*, i32** %26, align 8
+  store i32* %28, i32** %27, align 8
+  %29 = getelementptr %array.0, %array.0* %array_descriptor, i32 0, i32 2
+  %30 = load %dimension_descriptor*, %dimension_descriptor** %29, align 8
+  %31 = getelementptr %array.0, %array.0* %25, i32 0, i32 2
+  %32 = load %dimension_descriptor*, %dimension_descriptor** %31, align 8
+  %33 = bitcast %dimension_descriptor* %32 to i8*
+  %34 = bitcast %dimension_descriptor* %30 to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %33, i8* align 8 %34, i64 12, i1 false)
+  %35 = getelementptr %array.0, %array.0* %array_descriptor, i32 0, i32 1
+  %36 = getelementptr %array.0, %array.0* %25, i32 0, i32 1
+  %37 = load i32, i32* %35, align 4
+  store i32 %37, i32* %36, align 4
+  %38 = getelementptr [6 x float], [6 x float]* %rv, i32 0, i32 0
+  %39 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 0
+  store float* %38, float** %39, align 8
+  %40 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 1
+  store i32 0, i32* %40, align 4
+  %41 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 2
+  %42 = alloca %dimension_descriptor, i32 2, align 8
+  store %dimension_descriptor* %42, %dimension_descriptor** %41, align 8
+  %43 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 4
+  store i32 2, i32* %43, align 4
+  %44 = load %dimension_descriptor*, %dimension_descriptor** %41, align 8
+  %45 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %44, i32 0
+  %46 = getelementptr %dimension_descriptor, %dimension_descriptor* %45, i32 0, i32 0
+  %47 = getelementptr %dimension_descriptor, %dimension_descriptor* %45, i32 0, i32 1
+  %48 = getelementptr %dimension_descriptor, %dimension_descriptor* %45, i32 0, i32 2
+  store i32 1, i32* %46, align 4
+  store i32 1, i32* %47, align 4
+  store i32 2, i32* %48, align 4
+  %49 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %44, i32 1
+  %50 = getelementptr %dimension_descriptor, %dimension_descriptor* %49, i32 0, i32 0
+  %51 = getelementptr %dimension_descriptor, %dimension_descriptor* %49, i32 0, i32 1
+  %52 = getelementptr %dimension_descriptor, %dimension_descriptor* %49, i32 0, i32 2
+  store i32 2, i32* %50, align 4
+  store i32 1, i32* %51, align 4
+  store i32 3, i32* %52, align 4
+  %53 = load %array*, %array** %r, align 8
+  %54 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 0
+  %55 = getelementptr %array, %array* %53, i32 0, i32 0
+  %56 = load float*, float** %54, align 8
+  store float* %56, float** %55, align 8
+  %57 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 2
+  %58 = load %dimension_descriptor*, %dimension_descriptor** %57, align 8
+  %59 = getelementptr %array, %array* %53, i32 0, i32 2
+  %60 = load %dimension_descriptor*, %dimension_descriptor** %59, align 8
+  %61 = bitcast %dimension_descriptor* %60 to i8*
+  %62 = bitcast %dimension_descriptor* %58 to i8*
+  call void @llvm.memcpy.p0i8.p0i8.i64(i8* align 8 %61, i8* align 8 %62, i64 24, i1 false)
+  %63 = getelementptr %array, %array* %array_descriptor4, i32 0, i32 1
+  %64 = getelementptr %array, %array* %53, i32 0, i32 1
+  %65 = load i32, i32* %63, align 4
+  store i32 %65, i32* %64, align 4
+  %66 = load %array.0*, %array.0** %i, align 8
+  %67 = getelementptr %array.0, %array.0* %66, i32 0, i32 2
+  %68 = load %dimension_descriptor*, %dimension_descriptor** %67, align 8
+  %69 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %68, i32 0
+  %70 = getelementptr %dimension_descriptor, %dimension_descriptor* %69, i32 0, i32 1
+  %71 = load i32, i32* %70, align 4
+  %72 = sub i32 1, %71
+  %73 = getelementptr %dimension_descriptor, %dimension_descriptor* %69, i32 0, i32 0
   %74 = load i32, i32* %73, align 4
-  %75 = icmp ne i32 %74, 1
-  br i1 %75, label %then, label %else
+  %75 = mul i32 %74, %72
+  %76 = add i32 0, %75
+  %77 = getelementptr %array.0, %array.0* %66, i32 0, i32 1
+  %78 = load i32, i32* %77, align 4
+  %79 = add i32 %76, %78
+  %80 = getelementptr %array.0, %array.0* %66, i32 0, i32 0
+  %81 = load i32*, i32** %80, align 8
+  %82 = getelementptr inbounds i32, i32* %81, i32 %79
+  store i32 1, i32* %82, align 4
+  %83 = load %array.0*, %array.0** %i, align 8
+  %84 = getelementptr %array.0, %array.0* %83, i32 0, i32 2
+  %85 = load %dimension_descriptor*, %dimension_descriptor** %84, align 8
+  %86 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %85, i32 0
+  %87 = getelementptr %dimension_descriptor, %dimension_descriptor* %86, i32 0, i32 1
+  %88 = load i32, i32* %87, align 4
+  %89 = sub i32 1, %88
+  %90 = getelementptr %dimension_descriptor, %dimension_descriptor* %86, i32 0, i32 0
+  %91 = load i32, i32* %90, align 4
+  %92 = mul i32 %91, %89
+  %93 = add i32 0, %92
+  %94 = getelementptr %array.0, %array.0* %83, i32 0, i32 1
+  %95 = load i32, i32* %94, align 4
+  %96 = add i32 %93, %95
+  %97 = getelementptr %array.0, %array.0* %83, i32 0, i32 0
+  %98 = load i32*, i32** %97, align 8
+  %99 = getelementptr inbounds i32, i32* %98, i32 %96
+  %100 = load i32, i32* %99, align 4
+  %101 = icmp ne i32 %100, 1
+  br i1 %101, label %then, label %else
 
 then:                                             ; preds = %.entry
-  %76 = load %array.0*, %array.0** %i, align 8
-  %77 = getelementptr %array.0, %array.0* %76, i32 0, i32 2
-  %78 = load %dimension_descriptor*, %dimension_descriptor** %77, align 8
-  %79 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %78, i32 0
-  %80 = getelementptr %dimension_descriptor, %dimension_descriptor* %79, i32 0, i32 1
-  %81 = load i32, i32* %80, align 4
-  %82 = sub i32 2, %81
-  %83 = getelementptr %dimension_descriptor, %dimension_descriptor* %79, i32 0, i32 0
-  %84 = load i32, i32* %83, align 4
-  %85 = mul i32 %84, %82
-  %86 = add i32 0, %85
-  %87 = getelementptr %array.0, %array.0* %76, i32 0, i32 1
-  %88 = load i32, i32* %87, align 4
-  %89 = add i32 %86, %88
-  %90 = getelementptr %array.0, %array.0* %76, i32 0, i32 0
-  %91 = load i32*, i32** %90, align 8
-  %92 = getelementptr inbounds i32, i32* %91, i32 %89
-  store i32 3, i32* %92, align 4
+  %102 = load %array.0*, %array.0** %i, align 8
+  %103 = getelementptr %array.0, %array.0* %102, i32 0, i32 2
+  %104 = load %dimension_descriptor*, %dimension_descriptor** %103, align 8
+  %105 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %104, i32 0
+  %106 = getelementptr %dimension_descriptor, %dimension_descriptor* %105, i32 0, i32 1
+  %107 = load i32, i32* %106, align 4
+  %108 = sub i32 2, %107
+  %109 = getelementptr %dimension_descriptor, %dimension_descriptor* %105, i32 0, i32 0
+  %110 = load i32, i32* %109, align 4
+  %111 = mul i32 %110, %108
+  %112 = add i32 0, %111
+  %113 = getelementptr %array.0, %array.0* %102, i32 0, i32 1
+  %114 = load i32, i32* %113, align 4
+  %115 = add i32 %112, %114
+  %116 = getelementptr %array.0, %array.0* %102, i32 0, i32 0
+  %117 = load i32*, i32** %116, align 8
+  %118 = getelementptr inbounds i32, i32* %117, i32 %115
+  store i32 3, i32* %118, align 4
   br label %ifcont
 
 else:                                             ; preds = %.entry
-  %93 = load %array.0*, %array.0** %i, align 8
-  %94 = getelementptr %array.0, %array.0* %93, i32 0, i32 2
-  %95 = load %dimension_descriptor*, %dimension_descriptor** %94, align 8
-  %96 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %95, i32 0
-  %97 = getelementptr %dimension_descriptor, %dimension_descriptor* %96, i32 0, i32 1
-  %98 = load i32, i32* %97, align 4
-  %99 = sub i32 2, %98
-  %100 = getelementptr %dimension_descriptor, %dimension_descriptor* %96, i32 0, i32 0
-  %101 = load i32, i32* %100, align 4
-  %102 = mul i32 %101, %99
-  %103 = add i32 0, %102
-  %104 = getelementptr %array.0, %array.0* %93, i32 0, i32 1
-  %105 = load i32, i32* %104, align 4
-  %106 = add i32 %103, %105
-  %107 = getelementptr %array.0, %array.0* %93, i32 0, i32 0
-  %108 = load i32*, i32** %107, align 8
-  %109 = getelementptr inbounds i32, i32* %108, i32 %106
-  store i32 7, i32* %109, align 4
+  %119 = load %array.0*, %array.0** %i, align 8
+  %120 = getelementptr %array.0, %array.0* %119, i32 0, i32 2
+  %121 = load %dimension_descriptor*, %dimension_descriptor** %120, align 8
+  %122 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %121, i32 0
+  %123 = getelementptr %dimension_descriptor, %dimension_descriptor* %122, i32 0, i32 1
+  %124 = load i32, i32* %123, align 4
+  %125 = sub i32 2, %124
+  %126 = getelementptr %dimension_descriptor, %dimension_descriptor* %122, i32 0, i32 0
+  %127 = load i32, i32* %126, align 4
+  %128 = mul i32 %127, %125
+  %129 = add i32 0, %128
+  %130 = getelementptr %array.0, %array.0* %119, i32 0, i32 1
+  %131 = load i32, i32* %130, align 4
+  %132 = add i32 %129, %131
+  %133 = getelementptr %array.0, %array.0* %119, i32 0, i32 0
+  %134 = load i32*, i32** %133, align 8
+  %135 = getelementptr inbounds i32, i32* %134, i32 %132
+  store i32 7, i32* %135, align 4
   br label %ifcont
 
 ifcont:                                           ; preds = %else, %then
-  %110 = getelementptr [2 x i32], [2 x i32]* %iv, i32 0, i32 0
-  %111 = load i32, i32* %110, align 4
-  %112 = icmp ne i32 %111, 1
-  br i1 %112, label %then5, label %else6
+  %136 = getelementptr [2 x i32], [2 x i32]* %iv, i32 0, i32 0
+  %137 = load i32, i32* %136, align 4
+  %138 = icmp ne i32 %137, 1
+  br i1 %138, label %then5, label %else6
 
 then5:                                            ; preds = %ifcont
   call void (i8*, ...) @_lcompilers_print_error(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @8, i32 0, i32 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @6, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @7, i32 0, i32 0))
@@ -198,10 +228,10 @@ else6:                                            ; preds = %ifcont
   br label %ifcont7
 
 ifcont7:                                          ; preds = %else6, %then5
-  %113 = getelementptr [2 x i32], [2 x i32]* %iv, i32 0, i32 1
-  %114 = load i32, i32* %113, align 4
-  %115 = icmp ne i32 %114, 7
-  br i1 %115, label %then8, label %else9
+  %139 = getelementptr [2 x i32], [2 x i32]* %iv, i32 0, i32 1
+  %140 = load i32, i32* %139, align 4
+  %141 = icmp ne i32 %140, 7
+  br i1 %141, label %then8, label %else9
 
 then8:                                            ; preds = %ifcont7
   call void (i8*, ...) @_lcompilers_print_error(i8* getelementptr inbounds ([5 x i8], [5 x i8]* @11, i32 0, i32 0), i8* getelementptr inbounds ([11 x i8], [11 x i8]* @9, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @10, i32 0, i32 0))
@@ -212,80 +242,80 @@ else9:                                            ; preds = %ifcont7
   br label %ifcont10
 
 ifcont10:                                         ; preds = %else9, %then8
-  %116 = load %array*, %array** %r, align 8
-  %117 = getelementptr %array, %array* %116, i32 0, i32 2
-  %118 = load %dimension_descriptor*, %dimension_descriptor** %117, align 8
-  %119 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %118, i32 0
-  %120 = getelementptr %dimension_descriptor, %dimension_descriptor* %119, i32 0, i32 1
-  %121 = load i32, i32* %120, align 4
-  %122 = sub i32 %121, 1
-  store i32 %122, i32* %u2, align 4
+  %142 = load %array*, %array** %r, align 8
+  %143 = getelementptr %array, %array* %142, i32 0, i32 2
+  %144 = load %dimension_descriptor*, %dimension_descriptor** %143, align 8
+  %145 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %144, i32 0
+  %146 = getelementptr %dimension_descriptor, %dimension_descriptor* %145, i32 0, i32 1
+  %147 = load i32, i32* %146, align 4
+  %148 = sub i32 %147, 1
+  store i32 %148, i32* %u2, align 4
   br label %loop.head
 
 loop.head:                                        ; preds = %loop.end, %ifcont10
-  %123 = load i32, i32* %u2, align 4
-  %124 = add i32 %123, 1
-  %125 = load %array*, %array** %r, align 8
-  %126 = getelementptr %array, %array* %125, i32 0, i32 2
-  %127 = load %dimension_descriptor*, %dimension_descriptor** %126, align 8
-  %128 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %127, i32 0
-  %129 = getelementptr %dimension_descriptor, %dimension_descriptor* %128, i32 0, i32 1
-  %130 = load i32, i32* %129, align 4
-  %131 = getelementptr %dimension_descriptor, %dimension_descriptor* %128, i32 0, i32 2
-  %132 = load i32, i32* %131, align 4
-  %133 = add i32 %132, %130
-  %134 = sub i32 %133, 1
-  %135 = icmp sle i32 %124, %134
-  br i1 %135, label %loop.body, label %loop.end13
+  %149 = load i32, i32* %u2, align 4
+  %150 = add i32 %149, 1
+  %151 = load %array*, %array** %r, align 8
+  %152 = getelementptr %array, %array* %151, i32 0, i32 2
+  %153 = load %dimension_descriptor*, %dimension_descriptor** %152, align 8
+  %154 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %153, i32 0
+  %155 = getelementptr %dimension_descriptor, %dimension_descriptor* %154, i32 0, i32 1
+  %156 = load i32, i32* %155, align 4
+  %157 = getelementptr %dimension_descriptor, %dimension_descriptor* %154, i32 0, i32 2
+  %158 = load i32, i32* %157, align 4
+  %159 = add i32 %158, %156
+  %160 = sub i32 %159, 1
+  %161 = icmp sle i32 %150, %160
+  br i1 %161, label %loop.body, label %loop.end13
 
 loop.body:                                        ; preds = %loop.head
-  %136 = load i32, i32* %u2, align 4
-  %137 = add i32 %136, 1
-  store i32 %137, i32* %u2, align 4
-  %138 = load %array*, %array** %r, align 8
-  %139 = getelementptr %array, %array* %138, i32 0, i32 2
-  %140 = load %dimension_descriptor*, %dimension_descriptor** %139, align 8
-  %141 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %140, i32 1
-  %142 = getelementptr %dimension_descriptor, %dimension_descriptor* %141, i32 0, i32 1
-  %143 = load i32, i32* %142, align 4
-  %144 = sub i32 %143, 1
-  store i32 %144, i32* %v3, align 4
+  %162 = load i32, i32* %u2, align 4
+  %163 = add i32 %162, 1
+  store i32 %163, i32* %u2, align 4
+  %164 = load %array*, %array** %r, align 8
+  %165 = getelementptr %array, %array* %164, i32 0, i32 2
+  %166 = load %dimension_descriptor*, %dimension_descriptor** %165, align 8
+  %167 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %166, i32 1
+  %168 = getelementptr %dimension_descriptor, %dimension_descriptor* %167, i32 0, i32 1
+  %169 = load i32, i32* %168, align 4
+  %170 = sub i32 %169, 1
+  store i32 %170, i32* %v3, align 4
   br label %loop.head11
 
 loop.head11:                                      ; preds = %loop.body12, %loop.body
-  %145 = load i32, i32* %v3, align 4
-  %146 = add i32 %145, 1
-  %147 = load %array*, %array** %r, align 8
-  %148 = getelementptr %array, %array* %147, i32 0, i32 2
-  %149 = load %dimension_descriptor*, %dimension_descriptor** %148, align 8
-  %150 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %149, i32 1
-  %151 = getelementptr %dimension_descriptor, %dimension_descriptor* %150, i32 0, i32 1
-  %152 = load i32, i32* %151, align 4
-  %153 = getelementptr %dimension_descriptor, %dimension_descriptor* %150, i32 0, i32 2
-  %154 = load i32, i32* %153, align 4
-  %155 = add i32 %154, %152
-  %156 = sub i32 %155, 1
-  %157 = icmp sle i32 %146, %156
-  br i1 %157, label %loop.body12, label %loop.end
+  %171 = load i32, i32* %v3, align 4
+  %172 = add i32 %171, 1
+  %173 = load %array*, %array** %r, align 8
+  %174 = getelementptr %array, %array* %173, i32 0, i32 2
+  %175 = load %dimension_descriptor*, %dimension_descriptor** %174, align 8
+  %176 = getelementptr inbounds %dimension_descriptor, %dimension_descriptor* %175, i32 1
+  %177 = getelementptr %dimension_descriptor, %dimension_descriptor* %176, i32 0, i32 1
+  %178 = load i32, i32* %177, align 4
+  %179 = getelementptr %dimension_descriptor, %dimension_descriptor* %176, i32 0, i32 2
+  %180 = load i32, i32* %179, align 4
+  %181 = add i32 %180, %178
+  %182 = sub i32 %181, 1
+  %183 = icmp sle i32 %172, %182
+  br i1 %183, label %loop.body12, label %loop.end
 
 loop.body12:                                      ; preds = %loop.head11
-  %158 = load i32, i32* %v3, align 4
-  %159 = add i32 %158, 1
-  store i32 %159, i32* %v3, align 4
-  %160 = load i32, i32* %u2, align 4
-  %161 = load i32, i32* %v3, align 4
-  %162 = sub i32 %160, 1
-  %163 = mul i32 1, %162
-  %164 = add i32 0, %163
-  %165 = sub i32 %161, 1
-  %166 = mul i32 2, %165
-  %167 = add i32 %164, %166
-  %168 = getelementptr [6 x float], [6 x float]* %rv, i32 0, i32 %167
-  %169 = load i32, i32* %u2, align 4
-  %170 = load i32, i32* %v3, align 4
-  %171 = mul i32 %169, %170
-  %172 = sitofp i32 %171 to float
-  store float %172, float* %168, align 4
+  %184 = load i32, i32* %v3, align 4
+  %185 = add i32 %184, 1
+  store i32 %185, i32* %v3, align 4
+  %186 = load i32, i32* %u2, align 4
+  %187 = load i32, i32* %v3, align 4
+  %188 = sub i32 %186, 1
+  %189 = mul i32 1, %188
+  %190 = add i32 0, %189
+  %191 = sub i32 %187, 1
+  %192 = mul i32 2, %191
+  %193 = add i32 %190, %192
+  %194 = getelementptr [6 x float], [6 x float]* %rv, i32 0, i32 %193
+  %195 = load i32, i32* %u2, align 4
+  %196 = load i32, i32* %v3, align 4
+  %197 = mul i32 %195, %196
+  %198 = sitofp i32 %197 to float
+  store float %198, float* %194, align 4
   br label %loop.head11
 
 loop.end:                                         ; preds = %loop.head11
@@ -293,8 +323,8 @@ loop.end:                                         ; preds = %loop.head11
 
 loop.end13:                                       ; preds = %loop.head
   call void @check_real(%array** %r)
-  %173 = load %array*, %array** %r, align 8
-  call void @check_real_without_pointer(%array* %173)
+  %199 = load %array*, %array** %r, align 8
+  call void @check_real_without_pointer(%array* %199)
   call void @_lpython_free_argv()
   br label %return
 
@@ -543,4 +573,9 @@ declare void @exit(i32)
 
 declare void @_lpython_call_initial_functions(i32, i8**)
 
+; Function Attrs: argmemonly nounwind willreturn
+declare void @llvm.memcpy.p0i8.p0i8.i64(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i64, i1 immarg) #0
+
 declare void @_lpython_free_argv()
+
+attributes #0 = { argmemonly nounwind willreturn }


Reviews:
user: login: assem2002
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-15T10:01:21Z
user: login: assem2002
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-03-15T10:53:31Z
user: login: Pranavchiku
body: I had a quick review, this looks good to me! 
state: APPROVED
author_association: MEMBER
submitted_at: 2025-03-15T13:07:18Z
user: login: gxyd
body: Looks good to me.
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-03-15T14:04:17Z

Review comments:
diff_hunk: @@ -857,9 +857,9 @@ RUN(NAME intrinsics_162 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran) #
 RUN(NAME intrinsics_163 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran) # ishftc
 RUN(NAME intrinsics_164 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran) # iand
 RUN(NAME intrinsics_165 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc) # sum
-RUN(NAME intrinsics_166 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # ibset
-RUN(NAME intrinsics_167 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # btest
-RUN(NAME intrinsics_168 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # ibclr
+# RUN(NAME intrinsics_166 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # ibset
+# RUN(NAME intrinsics_167 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # btest
+# RUN(NAME intrinsics_168 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # ibclr
path: integration_tests/CMakeLists.txt
user: login: assem2002
body: I'm still handling those. But they all use similar function, it should be one shot. 
created_at: 2025-03-15T10:01:21Z
author_association: CONTRIBUTOR
diff_hunk: @@ -857,9 +857,9 @@ RUN(NAME intrinsics_162 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran) #
 RUN(NAME intrinsics_163 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran) # ishftc
 RUN(NAME intrinsics_164 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran) # iand
 RUN(NAME intrinsics_165 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc) # sum
-RUN(NAME intrinsics_166 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # ibset
-RUN(NAME intrinsics_167 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # btest
-RUN(NAME intrinsics_168 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # ibclr
+# RUN(NAME intrinsics_166 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # ibset
+# RUN(NAME intrinsics_167 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # btest
+# RUN(NAME intrinsics_168 LABELS gfortran llvm llvm_wasm llvm_wasm_emcc fortran NOFAST_TILL_LLVM16) # ibclr
path: integration_tests/CMakeLists.txt
user: login: assem2002
body: Oh I thought it failed. they run without problem.
created_at: 2025-03-15T10:53:31Z
author_association: CONTRIBUTOR

PR comments:
user: login: assem2002
created_at: 2025-03-14T09:14:02Z
body: The change should've been very small. but how we relied on `store` with `associate` made us fell free to use `null` however we wanted (associate `null` or `nullifying` both lead to removing the whole array descriptor- and we heavily rely on the fact that any declared variable should have its whole struct set and ready to go.) 
author_association: CONTRIBUTOR
user: login: assem2002
created_at: 2025-03-14T09:37:46Z
body: Mainly : testing CI
author_association: CONTRIBUTOR
user: login: certik
created_at: 2025-03-14T17:07:37Z
body: Thanks for fixing this. Yes, let's first figure out a solution that works, then we can clean it up. This is related to https://github.com/lfortran/lfortran/issues/6612 also.
author_association: CONTRIBUTOR
user: login: assem2002
created_at: 2025-03-15T10:49:59Z
body: Ready to review. maybe squash merge.
I tried to make the commits a bit descriptive.
author_association: CONTRIBUTOR
user: login: gxyd
created_at: 2025-03-15T11:38:39Z
body: > Fixes #6611

I checked locally on my machine, that this PR allows us to now run validation with POT3D with LFortran's `--fast` optimizations enabled successfully.

And fixes both the MRE's reported in the linked issue.
author_association: CONTRIBUTOR
user: login: Pranavchiku
created_at: 2025-03-15T13:06:29Z
body: Woahh! super news.
author_association: MEMBER
user: login: Pranavchiku
created_at: 2025-03-15T13:07:54Z
body: This is minor and can be done in subsequent PRs but let's add all the reported MREs at #6611 to integration tests.
author_association: MEMBER
user: login: certik
created_at: 2025-03-15T14:50:10Z
body: Great job @assem2002 !!!

The change is bigger and I didn't review every detail, and we can review the design at our next meeting, but I think it's likely the correct fix.
author_association: CONTRIBUTOR