diff --git a/integration_tests/CMakeLists.txt b/integration_tests/CMakeLists.txt index 4caf155f5c..726c555dbd 100644 --- a/integration_tests/CMakeLists.txt +++ b/integration_tests/CMakeLists.txt @@ -328,6 +328,7 @@ RUN(NAME structs_11 LABELS cpython llvm c) RUN(NAME structs_12 LABELS cpython llvm c) RUN(NAME structs_13 LABELS llvm c EXTRAFILES structs_13b.c) +RUN(NAME structs_14 LABELS cpython llvm c) RUN(NAME structs_15 LABELS cpython llvm c) RUN(NAME sizeof_01 LABELS llvm c EXTRAFILES sizeof_01b.c) diff --git a/integration_tests/structs_14.py b/integration_tests/structs_14.py new file mode 100644 index 0000000000..6a47ffd249 --- /dev/null +++ b/integration_tests/structs_14.py @@ -0,0 +1,32 @@ +from ltypes import i8, dataclass, i32, ccallable +from numpy import empty, int8 +from copy import deepcopy + +@dataclass +class buffer_struct: + buffer: i8[32] + +@ccallable +@dataclass +class buffer_struct_clink: + buffer: i8[32] + +def f(): + i: i32 + buffer_var: i8[32] = empty(32, dtype=int8) + buffer_: buffer_struct = buffer_struct(deepcopy(buffer_var)) + buffer_clink_: buffer_struct_clink = buffer_struct_clink(deepcopy(buffer_var)) + print(buffer_.buffer[15]) + print(buffer_clink_.buffer[15]) + + for i in range(32): + buffer_.buffer[i] = i8(i + 1) + buffer_clink_.buffer[i] = i8(i + 2) + + for i in range(32): + print(i, buffer_.buffer[i], buffer_clink_.buffer[i]) + assert buffer_.buffer[i] == i8(i + 1) + assert buffer_clink_.buffer[i] == i8(i + 2) + assert buffer_clink_.buffer[i] - buffer_.buffer[i] == i8(1) + +f() diff --git a/src/libasr/asr_utils.h b/src/libasr/asr_utils.h index 45b00fac7e..aefb3a9a21 100644 --- a/src/libasr/asr_utils.h +++ b/src/libasr/asr_utils.h @@ -111,6 +111,23 @@ static inline ASR::ttype_t* symbol_type(const ASR::symbol_t *f) return nullptr; } +static inline ASR::abiType symbol_abi(const ASR::symbol_t *f) +{ + switch( f->type ) { + case ASR::symbolType::Variable: { + return ASR::down_cast(f)->m_abi; + } + case ASR::symbolType::EnumType: { + return ASR::down_cast(f)->m_abi; + } + default: { + throw LCompilersException("Cannot return ABI of, " + + std::to_string(f->type) + " symbol."); + } + } + return ASR::abiType::Source; +} + static inline ASR::ttype_t* get_contained_type(ASR::ttype_t* asr_type) { switch( asr_type->type ) { case ASR::ttypeType::List: { @@ -138,6 +155,20 @@ static inline ASR::ttype_t* get_contained_type(ASR::ttype_t* asr_type) { } } +static inline ASR::abiType expr_abi(ASR::expr_t* e) { + switch( e->type ) { + case ASR::exprType::Var: { + return ASRUtils::symbol_abi(ASR::down_cast(e)->m_v); + } + case ASR::exprType::StructInstanceMember: { + return ASRUtils::symbol_abi(ASR::down_cast(e)->m_m); + } + default: + throw LCompilersException("Cannot extract the ABI of " + + std::to_string(e->type) + " expression."); + } +} + static inline std::string type_to_str(const ASR::ttype_t *t) { switch (t->type) { @@ -1369,6 +1400,19 @@ inline int extract_dimensions_from_ttype(ASR::ttype_t *x, return n_dims; } +static inline bool is_fixed_size_array(ASR::dimension_t* m_dims, size_t n_dims) { + if( n_dims == 0 ) { + return false; + } + for( size_t i = 0; i < n_dims; i++ ) { + int64_t dim_size = -1; + if( !ASRUtils::extract_value(ASRUtils::expr_value(m_dims[i].m_length), dim_size) ) { + return false; + } + } + return true; +} + inline int extract_n_dims_from_ttype(ASR::ttype_t *x) { ASR::dimension_t* m_dims_temp = nullptr; return extract_dimensions_from_ttype(x, m_dims_temp); diff --git a/src/libasr/codegen/asr_to_c.cpp b/src/libasr/codegen/asr_to_c.cpp index c2df72e352..b27b5b2bd7 100644 --- a/src/libasr/codegen/asr_to_c.cpp +++ b/src/libasr/codegen/asr_to_c.cpp @@ -147,7 +147,13 @@ class ASRToCVisitor : public BaseCCPPVisitor std::string mem_var_name = current_scope->get_unique_name(itr.first + std::to_string(counter)); counter += 1; sub += indent + convert_variable_decl(*mem_var, true, true, true, true, mem_var_name) + ";\n"; - sub += indent + name + "->" + itr.first + " = " + mem_var_name + ";\n"; + if( mem_var->m_abi == ASR::abiType::BindC && + ASR::is_a(*mem_var->m_type) && + ASRUtils::extract_kind_from_ttype_t(mem_var->m_type) == 1 ) { + sub += indent + "strcpy(" + name + "->" + itr.first + ", " + mem_var_name + ");\n"; + } else { + sub += indent + name + "->" + itr.first + " = " + mem_var_name + ";\n"; + } } else if( ASR::is_a(*mem_type) ) { ASR::Struct_t* struct_t = ASR::down_cast(mem_type); ASR::StructType_t* struct_type_t = ASR::down_cast( @@ -238,16 +244,26 @@ class ASRToCVisitor : public BaseCCPPVisitor if( is_array ) { bool is_fixed_size = true; dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size, true); - std::string encoded_type_name = "i" + std::to_string(t->m_kind * 8); - bool is_struct_type_member = ASR::is_a( - *ASR::down_cast(v.m_parent_symtab->asr_owner)); - generate_array_decl(sub, std::string(v.m_name), type_name, dims, - encoded_type_name, t->m_dims, t->n_dims, - use_ref, dummy, - (v.m_intent != ASRUtils::intent_in && - v.m_intent != ASRUtils::intent_inout && - v.m_intent != ASRUtils::intent_out && - !is_struct_type_member) || force_declare, is_fixed_size); + if( t->m_kind == 1 && v.m_abi == ASR::abiType::BindC && is_fixed_size ) { + if( !force_declare ) { + force_declare_name = std::string(v.m_name); + } + sub = "char " + force_declare_name + dims; + } else { + std::string encoded_type_name = "i" + std::to_string(t->m_kind * 8); + bool is_struct_type_member = ASR::is_a( + *ASR::down_cast(v.m_parent_symtab->asr_owner)); + if( !force_declare ) { + force_declare_name = std::string(v.m_name); + } + generate_array_decl(sub, force_declare_name, type_name, dims, + encoded_type_name, t->m_dims, t->n_dims, + use_ref, dummy, + (v.m_intent != ASRUtils::intent_in && + v.m_intent != ASRUtils::intent_inout && + v.m_intent != ASRUtils::intent_out && + !is_struct_type_member) || force_declare, is_fixed_size); + } } else { bool is_fixed_size = true; dims = convert_dims_c(t->n_dims, t->m_dims, v_m_type, is_fixed_size); @@ -1024,9 +1040,18 @@ R"( this->visit_expr(*x.m_v); std::string array = src; std::string out = array; + ASR::ttype_t* x_mv_type = ASRUtils::expr_type(x.m_v); ASR::dimension_t* m_dims; - ASRUtils::extract_dimensions_from_ttype(ASRUtils::expr_type(x.m_v), m_dims); - out += "->data["; + int n_dims = ASRUtils::extract_dimensions_from_ttype(x_mv_type, m_dims); + bool is_i8_array = (ASR::is_a(*x_mv_type) && + ASRUtils::extract_kind_from_ttype_t(x_mv_type) == 1 && + ASRUtils::is_fixed_size_array(m_dims, n_dims) && + ASRUtils::expr_abi(x.m_v) == ASR::abiType::BindC); + if( is_i8_array ) { + out += "["; + } else { + out += "->data["; + } std::string index = ""; for (size_t i=0; idims[" - + std::to_string(i) + "].lower_bound)"; - for( size_t j = i + 1; j < x.n_args; j++ ) { - std::string length = array + "->dims[" + std::to_string(j) + "].length"; - current_index += " * " + length; + if( is_i8_array ) { + current_index += src; + for( size_t j = i + 1; j < x.n_args; j++ ) { + int64_t dim_size; + ASRUtils::extract_value(m_dims[j].m_length, dim_size); + std::string length = std::to_string(dim_size); + current_index += " * " + length; + } + index += current_index; + } else { + current_index += "(" + src + " - " + array + "->dims[" + + std::to_string(i) + "].lower_bound)"; + for( size_t j = i + 1; j < x.n_args; j++ ) { + std::string length = array + "->dims[" + std::to_string(j) + "].length"; + current_index += " * " + length; + } + index += current_index; } - index += current_index; if (i < x.n_args - 1) { index += " + "; } diff --git a/src/libasr/codegen/asr_to_c_cpp.h b/src/libasr/codegen/asr_to_c_cpp.h index ddfcabfc09..ac2c1e48b0 100644 --- a/src/libasr/codegen/asr_to_c_cpp.h +++ b/src/libasr/codegen/asr_to_c_cpp.h @@ -719,7 +719,41 @@ R"(#include alloc = indent + target + " = " + "(char *) malloc((strlen(" + value + ") + 1 ) * sizeof(char));\n"; } - src += alloc + indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; + if( ASRUtils::is_array(m_target_type) && ASRUtils::is_array(m_value_type) ) { + bool is_target_i8_array = (ASR::is_a(*m_target_type) && + ASRUtils::extract_kind_from_ttype_t(m_target_type) == 1 && + ASRUtils::expr_abi(x.m_target) == ASR::abiType::BindC); + bool is_value_i8_array = (ASR::is_a(*m_value_type) && + ASRUtils::extract_kind_from_ttype_t(m_value_type) == 1 && + ASRUtils::expr_abi(x.m_value) == ASR::abiType::BindC); + bool is_target_fixed_size = false, is_value_fixed_size = false; + if( is_target_i8_array ) { + ASR::Integer_t* target_integer_t = ASR::down_cast(m_target_type); + if( ASRUtils::is_fixed_size_array(target_integer_t->m_dims, target_integer_t->n_dims) ) { + is_target_fixed_size = true; + } + } + if( is_value_i8_array ) { + ASR::Integer_t* value_integer_t = ASR::down_cast(m_value_type); + if( ASRUtils::is_fixed_size_array(value_integer_t->m_dims, value_integer_t->n_dims) ) { + is_value_fixed_size = true; + } + } + if( (is_target_i8_array && is_target_fixed_size) || + (is_value_i8_array && is_value_fixed_size) ) { + if( !(is_target_i8_array && is_target_fixed_size) ) { + target = "(char*) " + target + "->data"; + } + if( !(is_value_i8_array && is_value_fixed_size) ) { + value = "(char*) " + value + "->data"; + } + src += indent + "strcpy(" + target + ", " + value + ");\n"; + } else { + src += alloc + indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; + } + } else { + src += alloc + indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; + } } else { src += indent + c_ds_api->get_deepcopy(m_target_type, value, target) + "\n"; } @@ -879,7 +913,7 @@ R"(#include step = "1"; } self().visit_expr(*x.m_a); - + ASR::ttype_t* t_ttype = ASRUtils::expr_type(x.m_a); ASR::List_t* t = ASR::down_cast(t_ttype); std::string list_var = std::move(src); diff --git a/src/libasr/codegen/asr_to_llvm.cpp b/src/libasr/codegen/asr_to_llvm.cpp index 6e619b52e1..c6aa23515c 100644 --- a/src/libasr/codegen/asr_to_llvm.cpp +++ b/src/libasr/codegen/asr_to_llvm.cpp @@ -522,7 +522,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } void fill_array_details(llvm::Value* arr, llvm::Type* llvm_data_type, - ASR::dimension_t* m_dims, int n_dims) { + ASR::dimension_t* m_dims, int n_dims, bool is_data_only=false) { std::vector> llvm_dims; for( int r = 0; r < n_dims; r++ ) { ASR::dimension_t m_dim = m_dims[r]; @@ -532,7 +532,19 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Value* end = tmp; llvm_dims.push_back(std::make_pair(start, end)); } - arr_descr->fill_array_details(arr, llvm_data_type, n_dims, llvm_dims); + if( is_data_only ) { + // llvm::Value* llvm_size = builder->CreateAlloca(llvm::Type::getInt32Ty(context), nullptr); + llvm::Value* const_1 = llvm::ConstantInt::get(context, llvm::APInt(32, 1)); + llvm::Value* prod = const_1; + for( int r = 0; r < n_dims; r++ ) { + llvm::Value* dim_size = llvm_dims[r].second; + prod = builder->CreateMul(prod, dim_size); + } + llvm::Value* arr_first = builder->CreateAlloca(llvm_data_type, prod); + builder->CreateStore(arr_first, arr); + } else { + arr_descr->fill_array_details(arr, llvm_data_type, n_dims, llvm_dims); + } } /* @@ -720,8 +732,8 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor } const std::map& scope = der_type->m_symtab->get_scope(); for( auto itr = scope.begin(); itr != scope.end(); itr++ ) { - ASR::Variable_t* member = (ASR::Variable_t*)(&(itr->second->base)); - llvm::Type* llvm_mem_type = get_type_from_ttype_t_util(member->m_type); + ASR::Variable_t* member = ASR::down_cast(itr->second); + llvm::Type* llvm_mem_type = get_type_from_ttype_t_util(member->m_type, member->m_abi); member_types.push_back(llvm_mem_type); name2memidx[der_type_name][std::string(member->m_name)] = member_idx; member_idx++; @@ -1682,6 +1694,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor this->visit_expr_wrapper(x.m_value, true); return; } + ASR::ttype_t* x_mv_type = ASRUtils::expr_type(x.m_v); bool is_argument = false; llvm::Value* array = nullptr; if( ASR::is_a(*x.m_v) ) { @@ -1702,16 +1715,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor int64_t ptr_loads_copy = ptr_loads; ptr_loads = 0; this->visit_expr(*x.m_v); - if( ASR::is_a(*ASRUtils::expr_type(x.m_v)) ) { - ASR::Struct_t* der_type = ASR::down_cast(ASRUtils::expr_type(x.m_v)); + if( ASR::is_a(*x_mv_type) ) { + ASR::Struct_t* der_type = ASR::down_cast(x_mv_type); der_type_name = ASRUtils::symbol_name(ASRUtils::symbol_get_past_external(der_type->m_derived_type)); } ptr_loads = ptr_loads_copy; array = tmp; } ASR::dimension_t* m_dims; - int n_dims = ASRUtils::extract_dimensions_from_ttype( - ASRUtils::expr_type(x.m_v), m_dims); + int n_dims = ASRUtils::extract_dimensions_from_ttype(x_mv_type, m_dims); if (ASR::is_a(*x.m_type) && n_dims == 0) { // String indexing: if (x.n_args != 1) { @@ -1747,10 +1759,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ptr_loads = ptr_loads_copy; indices.push_back(tmp); } - if (ASRUtils::expr_type(x.m_v)->type == ASR::ttypeType::Pointer) { + int a_kind = ASRUtils::extract_kind_from_ttype_t(x_mv_type); + bool is_i8_array = (ASR::is_a(*x_mv_type) && a_kind == 1 && + ASRUtils::expr_abi(x.m_v) == ASR::abiType::BindC); + if (ASR::is_a(*x_mv_type) || + (is_i8_array && ASR::is_a(*x.m_v))) { array = CreateLoad(array); } bool is_data_only = is_argument && !ASRUtils::is_dimension_empty(m_dims, n_dims); + is_data_only = is_data_only || is_i8_array; Vec llvm_diminfo; llvm_diminfo.reserve(al, 2 * x.n_args + 1); if( is_data_only ) { @@ -1763,8 +1780,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm_diminfo.push_back(al, dim_size); } } - LFORTRAN_ASSERT(ASRUtils::extract_n_dims_from_ttype( - ASRUtils::expr_type(x.m_v)) > 0); + LFORTRAN_ASSERT(ASRUtils::extract_n_dims_from_ttype(x_mv_type) > 0); tmp = arr_descr->get_single_element(array, indices, x.n_args, is_data_only, llvm_diminfo.p); } @@ -2357,7 +2373,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ASR::storage_typeType m_storage, bool& is_array_type, bool& is_malloc_array_type, bool& is_list, ASR::dimension_t*& m_dims, - int& n_dims, int& a_kind) { + int& n_dims, int& a_kind, ASR::abiType m_abi=ASR::abiType::Source) { llvm::Type* llvm_type = nullptr; switch (asr_type->type) { case (ASR::ttypeType::Integer) : { @@ -2366,13 +2382,17 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor n_dims = v_type->n_dims; a_kind = v_type->m_kind; if( n_dims > 0 ) { - is_array_type = true; - llvm::Type* el_type = get_el_type(asr_type); - if( m_storage == ASR::storage_typeType::Allocatable ) { - is_malloc_array_type = true; - llvm_type = arr_descr->get_malloc_array_type(asr_type, el_type); + if( a_kind == 1 && m_abi == ASR::abiType::BindC ) { + llvm_type = llvm::Type::getInt8PtrTy(context); } else { - llvm_type = arr_descr->get_array_type(asr_type, el_type); + is_array_type = true; + llvm::Type* el_type = get_el_type(asr_type); + if( m_storage == ASR::storage_typeType::Allocatable ) { + is_malloc_array_type = true; + llvm_type = arr_descr->get_malloc_array_type(asr_type, el_type); + } else { + llvm_type = arr_descr->get_array_type(asr_type, el_type); + } } } else { llvm_type = getIntType(a_kind); @@ -2495,7 +2515,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ASR::ttype_t *t2 = ASR::down_cast(asr_type)->m_type; llvm_type = get_type_from_ttype_t(t2, m_storage, is_array_type, is_malloc_array_type, is_list, m_dims, - n_dims, a_kind); + n_dims, a_kind, m_abi); llvm_type = llvm_type->getPointerTo(); break; } @@ -2505,7 +2525,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor llvm::Type* el_llvm_type = get_type_from_ttype_t(asr_list->m_type, m_storage, is_array_type, is_malloc_array_type, is_list, m_dims, n_dims, - a_kind); + a_kind, m_abi); std::string el_type_code = ASRUtils::get_type_code(asr_list->m_type); int32_t type_size = -1; if( LLVM::is_llvm_struct(asr_list->m_type) || @@ -2537,7 +2557,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor ASR::storage_typeType local_m_storage = ASR::storage_typeType::Default; llvm_el_types.push_back(get_type_from_ttype_t(asr_tuple->m_type[i], local_m_storage, is_local_array_type, is_local_malloc_array_type, - is_local_list, local_m_dims, local_n_dims, local_a_kind)); + is_local_list, local_m_dims, local_n_dims, local_a_kind, m_abi)); } llvm_type = tuple_api->get_tuple_type(type_code, llvm_el_types); break; @@ -2553,7 +2573,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor case (ASR::ttypeType::Const) : { llvm_type = get_type_from_ttype_t(ASRUtils::get_contained_type(asr_type), m_storage, is_array_type, is_malloc_array_type, is_list, - m_dims, n_dims, a_kind); + m_dims, n_dims, a_kind, m_abi); break; } default : @@ -2563,7 +2583,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor return llvm_type; } - inline llvm::Type* get_type_from_ttype_t_util(ASR::ttype_t* asr_type) { + inline llvm::Type* get_type_from_ttype_t_util(ASR::ttype_t* asr_type, ASR::abiType asr_abi=ASR::abiType::Source) { ASR::storage_typeType m_storage_local = ASR::storage_typeType::Default; bool is_array_type_local, is_malloc_array_type_local; bool is_list_local; @@ -2571,15 +2591,15 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor int n_dims_local, a_kind_local; return get_type_from_ttype_t(asr_type, m_storage_local, is_array_type_local, is_malloc_array_type_local, is_list_local, - m_dims_local, n_dims_local, a_kind_local); + m_dims_local, n_dims_local, a_kind_local, asr_abi); } void fill_array_details_(llvm::Value* ptr, ASR::dimension_t* m_dims, size_t n_dims, bool is_malloc_array_type, bool is_array_type, - bool is_list, ASR::ttype_t* m_type) { + bool is_list, ASR::ttype_t* m_type, bool is_data_only=false) { if( is_malloc_array_type && m_type->type != ASR::ttypeType::Pointer && - !is_list ) { + !is_list && !is_data_only ) { arr_descr->fill_dimension_descriptor(ptr, n_dims); } if( is_array_type && !is_malloc_array_type && @@ -2587,11 +2607,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor !is_list ) { ASR::ttype_t* asr_data_type = ASRUtils::duplicate_type_without_dims(al, m_type, m_type->base.loc); llvm::Type* llvm_data_type = get_type_from_ttype_t_util(asr_data_type); - fill_array_details(ptr, llvm_data_type, m_dims, n_dims); + fill_array_details(ptr, llvm_data_type, m_dims, n_dims, is_data_only); } if( is_array_type && is_malloc_array_type && m_type->type != ASR::ttypeType::Pointer && - !is_list ) { + !is_list && !is_data_only ) { // Set allocatable arrays as unallocated arr_descr->set_is_allocated_flag(ptr, 0); } @@ -2615,7 +2635,11 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor // Assume that struct member array is not allocatable ASR::dimension_t* m_dims = nullptr; size_t n_dims = ASRUtils::extract_dimensions_from_ttype(symbol_type, m_dims); - fill_array_details_(ptr_member, m_dims, n_dims, false, true, false, symbol_type); + int a_kind = ASRUtils::extract_kind_from_ttype_t(symbol_type); + bool is_data_only = (ASRUtils::symbol_abi(item.second) == ASR::abiType::BindC && + a_kind == 1 && ASR::is_a(*symbol_type) && + ASRUtils::is_fixed_size_array(m_dims, n_dims)); + fill_array_details_(ptr_member, m_dims, n_dims, false, true, false, symbol_type, is_data_only); } else if( ASR::is_a(*symbol_type) ) { allocate_array_members_of_struct(ptr_member, symbol_type); } @@ -2985,7 +3009,7 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor is_array_type, is_malloc_array_type, is_list, m_dims, n_dims, - a_kind); + a_kind, m_abi); int32_t type_size = -1; if( LLVM::is_llvm_struct(asr_list->m_type) || ASR::is_a(*asr_list->m_type) || @@ -4012,8 +4036,67 @@ class ASRToLLVMVisitor : public ASR::BaseVisitor if( ASRUtils::is_array(target_type) && ASRUtils::is_array(value_type) && ASRUtils::check_equal_type(target_type, value_type) ) { - arr_descr->copy_array(value, target, module.get(), - target_type, false, false); + int target_kind = ASRUtils::extract_kind_from_ttype_t(target_type); + int value_kind = ASRUtils::extract_kind_from_ttype_t(value_type); + bool data_only_copy = false; + bool is_target_i8_array = (ASR::is_a(*target_type) && target_kind == 1 && + ASRUtils::expr_abi(x.m_target) == ASR::abiType::BindC); + bool is_value_i8_array = (ASR::is_a(*value_type) && value_kind == 1 && + ASRUtils::expr_abi(x.m_value) == ASR::abiType::BindC); + if( is_target_i8_array || is_value_i8_array ) { + llvm::Value *target_data = nullptr, *value_data = nullptr, *llvm_size = nullptr; + if( is_target_i8_array ) { + target_data = target; + ASR::dimension_t* target_dims = nullptr; + int target_ndims = ASRUtils::extract_dimensions_from_ttype(target_type, target_dims); + size_t target_size = 1; + data_only_copy = true; + for( int i = 0; i < target_ndims; i++ ) { + int dim_length = -1; + if( !ASRUtils::extract_value(ASRUtils::expr_value(target_dims[i].m_length), dim_length) ) { + data_only_copy = false; + break; + } + target_size *= dim_length; + } + if( data_only_copy ) { + llvm_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), + llvm::APInt(32, target_size)); + data_only_copy = false; + } + } else { + target_data = LLVM::CreateLoad(*builder, arr_descr->get_pointer_to_data(target)); + } + if( is_value_i8_array ) { + value_data = value; + ASR::dimension_t* value_dims = nullptr; + int value_ndims = ASRUtils::extract_dimensions_from_ttype(value_type, value_dims); + size_t value_size = 1; + data_only_copy = true; + for( int i = 0; i < value_ndims; i++ ) { + int dim_length = -1; + if( !ASRUtils::extract_value(ASRUtils::expr_value(value_dims[i].m_length), dim_length) ) { + data_only_copy = false; + break; + } + value_size *= dim_length; + } + if( data_only_copy ) { + llvm_size = llvm::ConstantInt::get(llvm::Type::getInt32Ty(context), + llvm::APInt(32, value_size)); + data_only_copy = false; + } + } else { + value_data = LLVM::CreateLoad(*builder, arr_descr->get_pointer_to_data(value)); + } + if( llvm_size ) { + arr_descr->copy_array_data_only(value_data, target_data, module.get(), + target_type, llvm_size); + } + } else { + arr_descr->copy_array(value, target, module.get(), + target_type, false, false); + } } else { builder->CreateStore(value, target); } diff --git a/src/libasr/codegen/llvm_array_utils.cpp b/src/libasr/codegen/llvm_array_utils.cpp index 0f200c3d6f..57a6edb5f1 100644 --- a/src/libasr/codegen/llvm_array_utils.cpp +++ b/src/libasr/codegen/llvm_array_utils.cpp @@ -648,6 +648,16 @@ namespace LFortran { builder->CreateStore(n_dims, this->get_rank(dest, true)); } + void SimpleCMODescriptor::copy_array_data_only(llvm::Value* src, llvm::Value* dest, + llvm::Module* module, ASR::ttype_t* asr_data_type, llvm::Value* num_elements) { + llvm::Type* llvm_data_type = tkr2array[ASRUtils::get_type_code(asr_data_type, false, false)].second; + llvm::DataLayout data_layout(module); + uint64_t size = data_layout.getTypeAllocSize(llvm_data_type); + llvm::Value* llvm_size = llvm::ConstantInt::get(context, llvm::APInt(32, size)); + num_elements = builder->CreateMul(num_elements, llvm_size); + builder->CreateMemCpy(src, llvm::MaybeAlign(), dest, llvm::MaybeAlign(), num_elements); + } + } // LLVMArrUtils } // LFortran diff --git a/src/libasr/codegen/llvm_array_utils.h b/src/libasr/codegen/llvm_array_utils.h index 30d75ba8c4..5998ffd907 100644 --- a/src/libasr/codegen/llvm_array_utils.h +++ b/src/libasr/codegen/llvm_array_utils.h @@ -262,6 +262,11 @@ namespace LFortran { llvm::Module* module, ASR::ttype_t* asr_data_type, bool create_dim_des_array, bool reserve_memory) = 0; + virtual + void copy_array_data_only(llvm::Value* src, llvm::Value* dest, + llvm::Module* module, ASR::ttype_t* asr_data_type, + llvm::Value* num_elements) = 0; + virtual llvm::Value* get_array_size(llvm::Value* array, llvm::Value* dim, int output_kind, int dim_kind=4) = 0; @@ -396,6 +401,11 @@ namespace LFortran { llvm::Module* module, ASR::ttype_t* asr_data_type, bool create_dim_des_array, bool reserve_memory); + virtual + void copy_array_data_only(llvm::Value* src, llvm::Value* dest, + llvm::Module* module, ASR::ttype_t* asr_data_type, + llvm::Value* num_elements); + virtual llvm::Value* get_array_size(llvm::Value* array, llvm::Value* dim, int output_kind, int dim_kind=4); diff --git a/src/lpython/semantics/python_ast_to_asr.cpp b/src/lpython/semantics/python_ast_to_asr.cpp index 2e2e1b36b2..5bdceb1b42 100644 --- a/src/lpython/semantics/python_ast_to_asr.cpp +++ b/src/lpython/semantics/python_ast_to_asr.cpp @@ -303,14 +303,16 @@ ASR::Module_t* load_module(Allocator &al, SymbolTable *symtab, const Location &loc, diag::Diagnostics &diagnostics, LocationManager &lm, bool intrinsic, std::vector &rl_path, - bool <ypes, bool& enum_py, + bool <ypes, bool& enum_py, bool& copy, const std::function err, bool allow_implicit_casting) { + ltypes = false; + enum_py = false; + copy = false; if( module_name == "copy" ) { + copy = true; return nullptr; } - ltypes = false; - enum_py = false; LFORTRAN_ASSERT(symtab); if (symtab->get_scope().find(module_name) != symtab->get_scope().end()) { ASR::symbol_t *m = symtab->get_symbol(module_name); @@ -577,10 +579,10 @@ class CommonVisitor : public AST::BaseVisitor { SymbolTable *tu_symtab = ASRUtils::get_tu_symtab(current_scope); std::string rl_path = get_runtime_library_dir(); std::vector paths = {rl_path, parent_dir}; - bool ltypes, enum_py; + bool ltypes, enum_py, copy; ASR::Module_t *m = load_module(al, tu_symtab, module_name, loc, diag, lm, true, paths, - ltypes, enum_py, + ltypes, enum_py, copy, [&](const std::string &msg, const Location &loc) { throw SemanticError(msg, loc); }, allow_implicit_casting); LFORTRAN_ASSERT(!ltypes && !enum_py) @@ -2069,6 +2071,22 @@ class CommonVisitor : public AST::BaseVisitor { } } + bool is_bindc_class(AST::expr_t** decorators, size_t n) { + for( size_t i = 0; i < n; i++ ) { + AST::expr_t* decorator = decorators[0]; + if( !AST::is_a(*decorator) ) { + return false; + } + + AST::Name_t* dec_name = AST::down_cast(decorator); + if (std::string(dec_name->m_id) == "ccallable" || + std::string(dec_name->m_id) == "ccall") { + return true; + } + } + return false; + } + bool is_dataclass(AST::expr_t** decorators, size_t n, ASR::expr_t*& aligned_expr, bool& is_packed) { if( n == 1 ) { @@ -2087,10 +2105,12 @@ class CommonVisitor : public AST::BaseVisitor { AST::Name_t* dc2_name = AST::down_cast(decorators[1]); std::string dc1_str = dc1_name->m_id; std::string dc2_str = dc2_name->m_id; - is_packed = true; + if( dc2_str == "packed" || dc1_str == "packed" ) { + is_packed = true; + } aligned_expr = nullptr; - return ((dc1_str == "dataclass" && dc2_str == "packed") || - (dc1_str == "packed" && dc2_str == "dataclass")); + return ((dc1_str == "dataclass" && (dc2_str == "packed" || dc2_str == "ccallable")) || + ((dc1_str == "packed" || dc1_str == "ccallable") && dc2_str == "dataclass")); } int32_t dc_idx = -1, pck_idx = -1; @@ -2496,12 +2516,16 @@ class CommonVisitor : public AST::BaseVisitor { member_names.reserve(al, x.n_body); Vec struct_dependencies; struct_dependencies.reserve(al, 1); - visit_ClassMembers(x, member_names, struct_dependencies); + ASR::abiType class_abi = ASR::abiType::Source; + if( is_bindc_class(x.m_decorator_list, x.n_decorator_list) ) { + class_abi = ASR::abiType::BindC; + } + visit_ClassMembers(x, member_names, struct_dependencies, false, class_abi); ASR::symbol_t* class_type = ASR::down_cast(ASR::make_StructType_t(al, x.base.base.loc, current_scope, x.m_name, struct_dependencies.p, struct_dependencies.size(), member_names.p, member_names.size(), - ASR::abiType::Source, ASR::accessType::Public, + class_abi, ASR::accessType::Public, is_packed, algined_expr, nullptr)); current_scope = parent_scope; @@ -3557,13 +3581,13 @@ class SymbolTableVisitor : public CommonVisitor { if (!main_module) { st = st->parent; } - bool ltypes, enum_py; + bool ltypes, enum_py, copy; set_module_symbol(msym, paths); t = (ASR::symbol_t*)(load_module(al, st, - msym, x.base.base.loc, diag, lm, false, paths, ltypes, enum_py, + msym, x.base.base.loc, diag, lm, false, paths, ltypes, enum_py, copy, [&](const std::string &msg, const Location &loc) { throw SemanticError(msg, loc); }, allow_implicit_casting)); - if (ltypes || enum_py) { + if (ltypes || enum_py || copy) { // TODO: For now we skip ltypes import completely. Later on we should note what symbols // got imported from it, and give an error message if an annotation is used without // importing it. @@ -3615,13 +3639,13 @@ class SymbolTableVisitor : public CommonVisitor { st = st->parent; } for (auto &mod_sym : mods) { - bool ltypes, enum_py; + bool ltypes, enum_py, copy; set_module_symbol(mod_sym, paths); t = (ASR::symbol_t*)(load_module(al, st, - mod_sym, x.base.base.loc, diag, lm, false, paths, ltypes, enum_py, + mod_sym, x.base.base.loc, diag, lm, false, paths, ltypes, enum_py, copy, [&](const std::string &msg, const Location &loc) { throw SemanticError(msg, loc); }, allow_implicit_casting)); - if (ltypes || enum_py) { + if (ltypes || enum_py || copy) { // TODO: For now we skip ltypes import completely. Later on we should note what symbols // got imported from it, and give an error message if an annotation is used without // importing it. diff --git a/src/lpython/semantics/python_comptime_eval.h b/src/lpython/semantics/python_comptime_eval.h index bf219adf4f..ed40dd8a6b 100644 --- a/src/lpython/semantics/python_comptime_eval.h +++ b/src/lpython/semantics/python_comptime_eval.h @@ -24,7 +24,8 @@ struct ProceduresDatabase { to_be_ignored = {{"numpy", {"empty", "int64", "int32", "float32", "float64", "reshape", "array", "int16", - "complex64", "complex128"}}, + "complex64", "complex128", + "int8"}}, {"enum", {"Enum"}} }; }