Skip to content

Commit 8340b79

Browse files
authored
Merge pull request #1884 from czgdp1807/expr_16
Accept shape in ``c_p_pointer`` if target is an array
2 parents 11e2f0b + 19b22a0 commit 8340b79

24 files changed

+224
-82
lines changed

integration_tests/bindc_02.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
from lpython import c_p_pointer, CPtr, pointer, i16, Pointer, empty_c_void_p
2-
from numpy import empty, int16
2+
from numpy import empty, int16, array
33

44
queries: CPtr = empty_c_void_p()
5-
x: Pointer[i16[:]] = c_p_pointer(queries, i16[:])
5+
x: Pointer[i16[:]] = c_p_pointer(queries, i16[:], array([1]))
66
print(queries, x)
77

88
def f():
@@ -17,7 +17,7 @@ def f():
1717
assert yptr1[0] == i16(1)
1818
assert yptr1[1] == i16(2)
1919

20-
yptr1 = c_p_pointer(yq, i16[:])
20+
yptr1 = c_p_pointer(yq, i16[:], array([2]))
2121

2222
print(yq, yptr1)
2323

integration_tests/bindc_03.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Pointer, ccall, p_c_pointer, dataclass,
33
ccallable, empty_c_void_p, cptr_to_u64,
44
u64_to_cptr, u64)
5+
from numpy import array
56

67
@dataclass
78
class ArrayWrapped:
@@ -22,7 +23,7 @@ def get_array(size: i32) -> CPtr:
2223
def f(q_void: CPtr) -> None:
2324
i: i32
2425
el: i32
25-
q: Pointer[i32[:]] = c_p_pointer(q_void, i32[:])
26+
q: Pointer[i32[:]] = c_p_pointer(q_void, i32[:], array([10]))
2627
for i in range(10):
2728
q2: CPtr
2829
p_c_pointer(pointer(q[i]), q2)
@@ -35,7 +36,7 @@ def f(q_void: CPtr) -> None:
3536
def h(q_void: CPtr) -> None:
3637
i: i32
3738
el: i32
38-
q: Pointer[i32[:]] = c_p_pointer(q_void, i32[:])
39+
q: Pointer[i32[:]] = c_p_pointer(q_void, i32[:], array([10]))
3940
for i in range(10):
4041
# TODO: Use q[i] directly in the assert.
4142
el = q[i]

integration_tests/bindc_07.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from lpython import CPtr, i64, sizeof, i32, i16, i8, ccall, c_p_pointer, empty_c_void_p, Pointer, pointer
2-
from numpy import empty, int64
2+
from numpy import empty, int64, array
33

44
@ccall
55
def _lfortran_malloc(size: i32) -> CPtr:
@@ -13,12 +13,12 @@ def allocate_memory(size: i32) -> tuple[CPtr, CPtr, CPtr, CPtr]:
1313
return array1, array2, array3, array4
1414

1515
def sum_arrays(array1: CPtr, array2: CPtr, array3: CPtr, array4: CPtr, size: i32):
16-
iarray1: Pointer[i8[size]] = c_p_pointer(array1, i8[size])
17-
iarray2: Pointer[i16[size]] = c_p_pointer(array2, i16[size])
18-
iarray3: Pointer[i32[size]] = c_p_pointer(array3, i32[size])
19-
iarray4: Pointer[i64[size]] = c_p_pointer(array4, i64[size])
16+
iarray1: Pointer[i8[:]] = c_p_pointer(array1, i8[:], array([size]))
17+
iarray2: Pointer[i16[:]] = c_p_pointer(array2, i16[:], array([size]))
18+
iarray3: Pointer[i32[:]] = c_p_pointer(array3, i32[:], array([size]))
19+
iarray4: Pointer[i64[:]] = c_p_pointer(array4, i64[:], array([size]))
2020
sum_array_cptr: CPtr = _lfortran_malloc(size * i32(sizeof(i64)))
21-
sum_array: Pointer[i64[size]] = c_p_pointer(sum_array_cptr, i64[size])
21+
sum_array: Pointer[i64[:]] = c_p_pointer(sum_array_cptr, i64[:], array([size]))
2222
i: i32
2323

2424
for i in range(size):

integration_tests/bindc_08.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
# file: main.py
22
from lpython import CPtr, i32, dataclass, c_p_pointer, Pointer, empty_c_void_p, p_c_pointer
33

4-
from numpy import empty
4+
from numpy import empty, array
55

66
@dataclass
77
class Foo:
88
x: i32
99
y: i32
1010

1111
def init(foos_ptr: CPtr) -> None:
12-
foos: Pointer[Foo[1]] = c_p_pointer(foos_ptr, Foo[1])
12+
foos: Pointer[Foo[:]] = c_p_pointer(foos_ptr, Foo[:], array([1]))
1313
foos[0] = Foo(3, 2)
1414

1515
def main() -> None:

integration_tests/expr_16.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,20 @@
11
from lpython import f64, Pointer, c_p_pointer, ccall, i32, CPtr, sizeof
2+
from numpy import array
23

34
@ccall
45
def _lfortran_malloc(size: i32) -> CPtr:
56
pass
67

78
def foo(xs_ptr: CPtr, length: i32) -> None:
8-
xs: Pointer[f64[length]] = c_p_pointer(xs_ptr, f64[length])
9+
xs: Pointer[f64[:]] = c_p_pointer(xs_ptr, f64[:], array([length]))
910
xs[0] = 3.0
1011
xs[1] = 4.0
1112

1213
def main() -> None:
1314
length: i32 = 32
1415
xs_ptr: CPtr = _lfortran_malloc(length * i32(sizeof(f64)))
1516
foo(xs_ptr, length)
16-
t: Pointer[f64[:]] = c_p_pointer(xs_ptr, f64[:])
17+
t: Pointer[f64[:]] = c_p_pointer(xs_ptr, f64[:], array([32]))
1718
print(t[0], t[1])
1819
assert t[0] == 3.0
1920
assert t[1] == 4.0

integration_tests/structs_13.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from lpython import i32, i16, i64, CPtr, dataclass, ccall, Pointer, c_p_pointer, sizeof
2+
from numpy import array
23

34
@dataclass
45
class A:
@@ -23,7 +24,7 @@ def add_Aptr_members(Ax: i32, Ay: i16) -> i32:
2324
def test_A_member_passing():
2425
array_cptr: CPtr = cmalloc(sizeof(A) * i64(10))
2526
assert not bool(is_null(array_cptr)), "Failed to allocate array on memory"
26-
array_ptr: Pointer[A[:]] = c_p_pointer(array_cptr, A[:])
27+
array_ptr: Pointer[A[:]] = c_p_pointer(array_cptr, A[:], array([10]))
2728
i: i32; sum_A_members: i32
2829
for i in range(10):
2930
array_ptr[i] = A(i, i16(i + 1))

src/libasr/asr_verify.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1009,6 +1009,12 @@ class VerifyVisitor : public BaseWalkVisitor<VerifyVisitor>
10091009
symbol_owner);
10101010
}
10111011

1012+
void visit_ArrayConstant(const ArrayConstant_t& x) {
1013+
require(ASR::is_a<ASR::Array_t>(*x.m_type),
1014+
"Type of ArrayConstant must be an array");
1015+
BaseWalkVisitor<VerifyVisitor>::visit_ArrayConstant(x);
1016+
}
1017+
10121018
void visit_Array(const Array_t& x) {
10131019
visit_ttype(*x.m_type);
10141020
require(x.n_dims != 0, "Array type cannot have 0 dimensions.")
@@ -1021,6 +1027,14 @@ class VerifyVisitor : public BaseWalkVisitor<VerifyVisitor>
10211027
void visit_Pointer(const Pointer_t &x) {
10221028
require(!ASR::is_a<ASR::Allocatable_t>(*x.m_type),
10231029
"Pointer type conflicts with Allocatable type");
1030+
if( ASR::is_a<ASR::Array_t>(*x.m_type) ) {
1031+
ASR::Array_t* array_t = ASR::down_cast<ASR::Array_t>(x.m_type);
1032+
for (size_t i = 0; i < array_t->n_dims; i++) {
1033+
require(array_t->m_dims[i].m_start == nullptr &&
1034+
array_t->m_dims[i].m_length == nullptr,
1035+
"Array type in pointer must have deferred shape");
1036+
}
1037+
}
10241038
visit_ttype(*x.m_type);
10251039
}
10261040

src/lpython/semantics/python_ast_to_asr.cpp

Lines changed: 75 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2559,39 +2559,63 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {
25592559

25602560
#define fill_shape_and_lower_bound_for_CPtrToPointer() ASR::dimension_t* target_dims = nullptr; \
25612561
int target_n_dims = ASRUtils::extract_dimensions_from_ttype(target_type, target_dims); \
2562-
ASR::expr_t* target_shape = nullptr; \
25632562
ASR::expr_t* lower_bounds = nullptr; \
25642563
if( target_n_dims > 0 ) { \
2565-
Vec<ASR::expr_t*> sizes, lbs; \
2566-
sizes.reserve(al, target_n_dims); \
2564+
ASR::dimension_t* alloc_asr_type_dims = nullptr; \
2565+
int alloc_asr_type_n_dims = ASRUtils::extract_dimensions_from_ttype( \
2566+
asr_alloc_type, alloc_asr_type_dims); \
2567+
for( int i = 0; i < alloc_asr_type_n_dims; i++ ) { \
2568+
if( alloc_asr_type_dims[i].m_length != nullptr || \
2569+
alloc_asr_type_dims[i].m_start != nullptr ) { \
2570+
throw SemanticError("Target type specified in " \
2571+
"c_p_pointer must have deferred shape.", \
2572+
loc); \
2573+
} \
2574+
} \
2575+
if( target_shape == nullptr ) { \
2576+
throw SemanticError("shape argument not specified in c_f_pointer " \
2577+
"even though pptr is an array.", \
2578+
loc); \
2579+
} \
2580+
int shape_rank = ASRUtils::extract_n_dims_from_ttype( \
2581+
ASRUtils::expr_type(target_shape)); \
2582+
if( shape_rank != 1 ) { \
2583+
throw SemanticError("shape array passed to c_p_pointer " \
2584+
"must be of rank 1 but given rank is " + \
2585+
std::to_string(shape_rank), loc); \
2586+
} \
2587+
Vec<ASR::expr_t*> lbs; \
25672588
lbs.reserve(al, target_n_dims); \
2568-
bool success = true; \
25692589
for( int i = 0; i < target_n_dims; i++ ) { \
2570-
if( target_dims->m_length == nullptr ) { \
2571-
success = false; \
2572-
break; \
2573-
} \
2574-
sizes.push_back(al, target_dims->m_length); \
25752590
lbs.push_back(al, ASRUtils::EXPR(ASR::make_IntegerConstant_t( \
25762591
al, loc, 0, ASRUtils::TYPE( \
25772592
ASR::make_Integer_t(al, loc, 4))))); \
25782593
} \
2579-
if( success ) { \
2580-
target_shape = ASRUtils::EXPR(ASR::make_ArrayConstant_t(al, \
2581-
loc, sizes.p, sizes.size(), ASRUtils::expr_type(target_dims[0].m_length), \
2582-
ASR::arraystorageType::RowMajor)); \
2583-
lower_bounds = ASRUtils::EXPR(ASR::make_ArrayConstant_t(al, \
2584-
loc, lbs.p, lbs.size(), ASRUtils::expr_type(lbs[0]), \
2585-
ASR::arraystorageType::RowMajor)); \
2586-
} \
2594+
Vec<ASR::dimension_t> dims; \
2595+
dims.reserve(al, 1); \
2596+
ASR::dimension_t dim; \
2597+
dim.loc = loc; \
2598+
dim.m_length = nullptr; \
2599+
dim.m_start = nullptr; \
2600+
dims.push_back(al, dim); \
2601+
ASR::ttype_t* type = ASRUtils::make_Array_t_util(al, loc, \
2602+
ASRUtils::expr_type(lbs[0]), dims.p, dims.size()); \
2603+
lower_bounds = ASRUtils::EXPR(ASR::make_ArrayConstant_t(al, \
2604+
loc, lbs.p, lbs.size(), type, \
2605+
ASR::arraystorageType::RowMajor)); \
25872606
} \
25882607

25892608
ASR::asr_t* create_CPtrToPointerFromArgs(AST::expr_t* ast_cptr, AST::expr_t* ast_pptr,
2590-
AST::expr_t* ast_type_expr, const Location& loc) {
2609+
AST::expr_t* ast_type_expr, AST::expr_t* ast_target_shape, const Location& loc) {
25912610
this->visit_expr(*ast_cptr);
25922611
ASR::expr_t* cptr = ASRUtils::EXPR(tmp);
25932612
this->visit_expr(*ast_pptr);
25942613
ASR::expr_t* pptr = ASRUtils::EXPR(tmp);
2614+
ASR::expr_t* target_shape = nullptr;
2615+
if( ast_target_shape ) {
2616+
this->visit_expr(*ast_target_shape);
2617+
target_shape = ASRUtils::EXPR(tmp);
2618+
}
25952619
bool is_allocatable = false;
25962620
ASR::ttype_t* asr_alloc_type = ast_expr_to_asr_type(ast_type_expr->base.loc, *ast_type_expr, is_allocatable);
25972621
ASR::ttype_t* target_type = ASRUtils::type_get_past_pointer(ASRUtils::expr_type(pptr));
@@ -2693,8 +2717,13 @@ class CommonVisitor : public AST::BaseVisitor<Struct> {
26932717
AST::Call_t* c_p_pointer_call = AST::down_cast<AST::Call_t>(x.m_value);
26942718
AST::expr_t* cptr = c_p_pointer_call->m_args[0];
26952719
AST::expr_t* pptr = assign_ast_target;
2720+
AST::expr_t* pptr_shape = nullptr;
2721+
if( c_p_pointer_call->n_args == 3 &&
2722+
c_p_pointer_call->m_args[2] != nullptr ) {
2723+
pptr_shape = c_p_pointer_call->m_args[2];
2724+
}
26962725
tmp = create_CPtrToPointerFromArgs(cptr, pptr, c_p_pointer_call->m_args[1],
2697-
x.base.base.loc);
2726+
pptr_shape, x.base.base.loc);
26982727
// if( current_body ) {
26992728
// current_body->push_back(al, ASRUtils::STMT(tmp));
27002729
// }
@@ -4766,8 +4795,12 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
47664795
AST::Call_t* c_p_pointer_call = AST::down_cast<AST::Call_t>(x.m_value);
47674796
AST::expr_t* cptr = c_p_pointer_call->m_args[0];
47684797
AST::expr_t* pptr = x.m_targets[0];
4798+
AST::expr_t* target_shape = nullptr;
4799+
if( c_p_pointer_call->n_args == 3 ) {
4800+
target_shape = c_p_pointer_call->m_args[2];
4801+
}
47694802
tmp = create_CPtrToPointerFromArgs(cptr, pptr, c_p_pointer_call->m_args[1],
4770-
x.base.base.loc);
4803+
target_shape, x.base.base.loc);
47714804
is_c_p_pointer_call = is_c_p_pointer_call;
47724805
return ;
47734806
}
@@ -6328,16 +6361,23 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
63286361

63296362

63306363
ASR::asr_t* create_CPtrToPointer(const AST::Call_t& x) {
6331-
if( x.n_args != 2 ) {
6332-
throw SemanticError("c_p_pointer accepts two positional arguments, "
6333-
"first a variable of c_ptr type and second "
6334-
" the target type of the first variable.",
6364+
if( x.n_args != 2 && x.n_args != 3 ) {
6365+
throw SemanticError("c_p_pointer accepts maximum three positional arguments, "
6366+
"first a variable of c_ptr type, second "
6367+
"the target type of the first variable and "
6368+
"third optionally the shape of the target variable "
6369+
"if target variable is an array",
63356370
x.base.base.loc);
63366371
}
63376372
visit_expr(*x.m_args[0]);
63386373
ASR::expr_t* cptr = ASRUtils::EXPR(tmp);
63396374
visit_expr(*x.m_args[1]);
63406375
ASR::expr_t* pptr = ASRUtils::EXPR(tmp);
6376+
ASR::expr_t* target_shape = nullptr;
6377+
if( x.n_args == 3 ) {
6378+
visit_expr(*x.m_args[2]);
6379+
target_shape = ASRUtils::EXPR(tmp);
6380+
}
63416381
bool is_allocatable = false;
63426382
ASR::ttype_t* asr_alloc_type = ast_expr_to_asr_type(x.m_args[1]->base.loc, *x.m_args[1], is_allocatable);
63436383
ASR::ttype_t* target_type = ASRUtils::type_get_past_pointer(ASRUtils::expr_type(pptr));
@@ -7183,8 +7223,9 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
71837223
return;
71847224
} else if( call_name == "pointer" ) {
71857225
parse_args(x, args);
7186-
ASR::ttype_t *type = ASRUtils::TYPE(ASR::make_Pointer_t(al, x.base.base.loc,
7187-
ASRUtils::expr_type(args[0].m_value)));
7226+
ASR::ttype_t* type_ = ASRUtils::duplicate_type_with_empty_dims(
7227+
al, ASRUtils::expr_type(args[0].m_value));
7228+
ASR::ttype_t *type = ASRUtils::TYPE(ASR::make_Pointer_t(al, x.base.base.loc, type_));
71887229
tmp = ASR::make_GetPointer_t(al, x.base.base.loc, args[0].m_value, type, nullptr);
71897230
return ;
71907231
} else if( call_name == "array" ) {
@@ -7201,6 +7242,14 @@ class BodyVisitor : public CommonVisitor<BodyVisitor> {
72017242
ASR::ListConstant_t* list = ASR::down_cast<ASR::ListConstant_t>(arg);
72027243
ASR::expr_t **m_args = list->m_args;
72037244
size_t n_args = list->n_args;
7245+
Vec<ASR::dimension_t> dims;
7246+
dims.reserve(al, 1);
7247+
ASR::dimension_t dim;
7248+
dim.loc = x.base.base.loc;
7249+
dim.m_length = nullptr;
7250+
dim.m_start = nullptr;
7251+
dims.push_back(al, dim);
7252+
type = ASRUtils::make_Array_t_util(al, x.base.base.loc, type, dims.p, dims.size());
72047253
tmp = ASR::make_ArrayConstant_t(al, x.base.base.loc, m_args, n_args, type, ASR::arraystorageType::RowMajor);
72057254
} else {
72067255
throw SemanticError("array accepts only list for now, got " +

src/runtime/lpython/lpython.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -560,9 +560,13 @@ def __setattr__(self, name: str, value):
560560
value = value.value
561561
self.ctypes_ptr.contents.__setattr__(name, value)
562562

563-
def c_p_pointer(cptr, targettype):
563+
def c_p_pointer(cptr, targettype, targetshape=None):
564564
targettype_ptr = convert_type_to_ctype(targettype)
565565
if isinstance(targettype, Array):
566+
if targetshape is None:
567+
raise ValueError("target shape must be "
568+
"provided if target type is an array.")
569+
# TODO: Add support for multi-dimensional shape of target variable
566570
if py_is_dataclass(targettype._type):
567571
return ctypes.cast(cptr.value, ctypes.py_object).value
568572
newa = ctypes.cast(cptr, targettype_ptr)

tests/errors/bindc_03.py

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,10 @@
11

22
from lpython import c_p_pointer, CPtr, i32, Pointer, i16
3+
from numpy import array
34

45
def fill_A(k: i32, n: i32, b: CPtr) -> None:
5-
nk: i32 = n * k
6-
A: Pointer[i16[nk]] = c_p_pointer(b, i16[k * n])
6+
A: Pointer[i16[:]] = c_p_pointer(b, i16[n * k], array([k * n]))
77
i: i32; j: i32
88
for j in range(k):
99
for i in range(n):
1010
A[j*n+i] = i16((i+j))
11-
12-
def fill_B(k: i32, n: i32, b: CPtr) -> None:
13-
B: Pointer[i16[n * k]] = c_p_pointer(b, i16[k * n])
14-
i: i32; j: i32
15-
for j in range(k):
16-
for i in range(n):
17-
B[j*n+i] = i16((i+j))
18-
19-
def fill_C(k: i32, n: i32, b: CPtr) -> None:
20-
C: Pointer[i16[n]] = c_p_pointer(b, i16[n * k])
21-
i: i32; j: i32
22-
for j in range(k):
23-
for i in range(n):
24-
C[j*n+i] = i16((i+j))

0 commit comments

Comments
 (0)