Skip to content

Commit 8ad9e74

Browse files
authored
Merge pull request #621 from czgdp1807/structs_c
Enabling `C` backend for structs
2 parents 7f22dab + 1b0e974 commit 8ad9e74

File tree

7 files changed

+93
-9
lines changed

7 files changed

+93
-9
lines changed

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,3 +177,9 @@ integration_tests/bindc_01
177177
integration_tests/bindc_01.c
178178
integration_tests/bindc_02
179179
integration_tests/bindc_02.c
180+
integration_tests/structs_01
181+
integration_tests/structs_01.c
182+
integration_tests/structs_02
183+
integration_tests/structs_02.c
184+
integration_tests/structs_03
185+
integration_tests/structs_03.c

integration_tests/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,9 +169,9 @@ RUN(NAME test_unary_minus LABELS cpython llvm)
169169
RUN(NAME test_unary_plus LABELS cpython llvm)
170170
RUN(NAME test_bool_binop LABELS cpython llvm)
171171
RUN(NAME test_issue_518 LABELS cpython llvm)
172-
RUN(NAME structs_01 LABELS cpython llvm)
173-
RUN(NAME structs_02 LABELS llvm)
174-
RUN(NAME structs_03 LABELS llvm)
172+
RUN(NAME structs_01 LABELS cpython llvm c)
173+
RUN(NAME structs_02 LABELS llvm c)
174+
RUN(NAME structs_03 LABELS llvm c)
175175

176176
# Just CPython
177177
RUN(NAME test_builtin_bin LABELS cpython)

integration_tests/structs_01.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,10 @@ def f(a: A):
99
print(a.x)
1010
print(a.y)
1111

12+
def change_struct(a: A):
13+
a.x = a.x + 1
14+
a.y = a.y + 1
15+
1216
def g():
1317
x: A
1418
x = A(3.25, 3)
@@ -21,5 +25,8 @@ def g():
2125
f(x)
2226
assert x.x == 5
2327
assert x.y == 5.5
28+
change_struct(x)
29+
assert x.x == 6
30+
assert x.y == 6.5
2431

2532
g()

src/libasr/codegen/asr_to_c.cpp

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include <libasr/asr_utils.h>
1010
#include <libasr/string_utils.h>
1111
#include <libasr/pass/unused_functions.h>
12+
#include <libasr/pass/class_constructor.h>
1213

1314

1415
namespace LFortran {
@@ -76,6 +77,12 @@ class ASRToCVisitor : public BaseCCPPVisitor<ASRToCVisitor>
7677
type_name.append(" *");
7778
}
7879
sub = format_type_c(dims, type_name, v.m_name, use_ref, dummy);
80+
} else if(ASR::is_a<ASR::Derived_t>(*t2)) {
81+
ASR::Derived_t *t = ASR::down_cast<ASR::Derived_t>(t2);
82+
std::string der_type_name = ASRUtils::symbol_name(t->m_derived_type);
83+
std::string dims = convert_dims_c(t->n_dims, t->m_dims);
84+
sub = format_type_c(dims, "struct " + der_type_name + "*",
85+
v.m_name, use_ref, dummy);
7986
} else {
8087
diag.codegen_error_label("Type number '"
8188
+ std::to_string(v.m_type->type)
@@ -109,9 +116,27 @@ class ASRToCVisitor : public BaseCCPPVisitor<ASRToCVisitor>
109116
} else if (ASRUtils::is_character(*v.m_type)) {
110117
// TODO
111118
} else if (ASR::is_a<ASR::Derived_t>(*v.m_type)) {
119+
std::string indent(indentation_level*indentation_spaces, ' ');
112120
ASR::Derived_t *t = ASR::down_cast<ASR::Derived_t>(v.m_type);
121+
std::string der_type_name = ASRUtils::symbol_name(t->m_derived_type);
113122
std::string dims = convert_dims_c(t->n_dims, t->m_dims);
114-
sub = format_type_c(dims, "struct", v.m_name, use_ref, dummy);
123+
if( v.m_intent == ASRUtils::intent_local ) {
124+
std::string value_var_name = v.m_parent_symtab->get_unique_name(std::string(v.m_name) + "_value");
125+
sub = format_type_c(dims, "struct " + der_type_name,
126+
value_var_name, use_ref, dummy);
127+
if (v.m_symbolic_value) {
128+
this->visit_expr(*v.m_symbolic_value);
129+
std::string init = src;
130+
sub += "=" + init;
131+
}
132+
sub += ";\n";
133+
sub += indent + format_type_c("", "struct " + der_type_name + "*", v.m_name, use_ref, dummy);
134+
sub += "= &" + value_var_name;
135+
return sub;
136+
} else {
137+
sub = format_type_c(dims, "struct " + der_type_name + "*",
138+
v.m_name, use_ref, dummy);
139+
}
115140
} else if (ASR::is_a<ASR::CPtr_t>(*v.m_type)) {
116141
sub = format_type_c("", "void*", v.m_name, false, false);
117142
} else {
@@ -120,7 +145,7 @@ class ASRToCVisitor : public BaseCCPPVisitor<ASRToCVisitor>
120145
+ "' not supported", {v.base.base.loc}, "");
121146
throw Abort();
122147
}
123-
if (v.m_symbolic_value) {
148+
if (v.m_symbolic_value) {
124149
this->visit_expr(*v.m_symbolic_value);
125150
std::string init = src;
126151
sub += "=" + init;
@@ -172,6 +197,18 @@ R"(
172197
)";
173198
unit_src += head;
174199

200+
for (auto &item : x.m_global_scope->get_scope()) {
201+
if (ASR::is_a<ASR::DerivedType_t>(*item.second)) {
202+
unit_src += "struct " + item.first + ";\n\n";
203+
}
204+
}
205+
206+
for (auto &item : x.m_global_scope->get_scope()) {
207+
if (ASR::is_a<ASR::DerivedType_t>(*item.second)) {
208+
visit_symbol(*item.second);
209+
unit_src += src;
210+
}
211+
}
175212

176213
// Pre-declare all functions first, then generate code
177214
// Otherwise some function might not be found.
@@ -282,6 +319,22 @@ R"(
282319
indentation_level -= 2;
283320
}
284321

322+
void visit_DerivedType(const ASR::DerivedType_t& x) {
323+
std::string indent(indentation_level*indentation_spaces, ' ');
324+
indentation_level += 1;
325+
std::string open_struct = indent + "struct " + std::string(x.m_name) + " {\n";
326+
std::string body = "";
327+
indent.push_back(' ');
328+
for( size_t i = 0; i < x.n_members; i++ ) {
329+
ASR::symbol_t* member = x.m_symtab->get_symbol(x.m_members[i]);
330+
LFORTRAN_ASSERT(ASR::is_a<ASR::Variable_t>(*member));
331+
body += indent + convert_variable_decl(*ASR::down_cast<ASR::Variable_t>(member)) + ";\n";
332+
}
333+
indentation_level -= 1;
334+
std::string end_struct = "};\n\n";
335+
src = open_struct + body + end_struct;
336+
}
337+
285338
void visit_LogicalConstant(const ASR::LogicalConstant_t &x) {
286339
if (x.m_value == true) {
287340
src = "true";
@@ -378,6 +431,7 @@ Result<std::string> asr_to_c(Allocator &al, ASR::TranslationUnit_t &asr,
378431
diag::Diagnostics &diagnostics)
379432
{
380433
pass_unused_functions(al, asr);
434+
pass_replace_class_constructor(al, asr);
381435
ASRToCVisitor v(diagnostics);
382436
try {
383437
v.visit_asr((ASR::asr_t &)asr);

src/libasr/codegen/asr_to_c_cpp.h

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -533,6 +533,9 @@ R"(#include <stdio.h>
533533
} else if (ASR::is_a<ASR::ArrayRef_t>(*x.m_target)) {
534534
visit_ArrayRef(*ASR::down_cast<ASR::ArrayRef_t>(x.m_target));
535535
target = src;
536+
} else if (ASR::is_a<ASR::DerivedRef_t>(*x.m_target)) {
537+
visit_DerivedRef(*ASR::down_cast<ASR::DerivedRef_t>(x.m_target));
538+
target = src;
536539
} else {
537540
LFORTRAN_ASSERT(false)
538541
}
@@ -573,6 +576,14 @@ R"(#include <stdio.h>
573576
last_expr_precedence = 2;
574577
}
575578

579+
void visit_DerivedRef(const ASR::DerivedRef_t& x) {
580+
std::string der_expr, member;
581+
this->visit_expr(*x.m_v);
582+
der_expr = std::move(src);
583+
member = ASRUtils::symbol_name(x.m_m);
584+
src = der_expr + "->" + member;
585+
}
586+
576587
void visit_ArrayRef(const ASR::ArrayRef_t &x) {
577588
const ASR::symbol_t *s = ASRUtils::symbol_get_past_external(x.m_v);
578589
ASR::Variable_t* sv = ASR::down_cast<ASR::Variable_t>(s);
@@ -731,6 +742,11 @@ R"(#include <stdio.h>
731742
type_src = "void*";
732743
break;
733744
}
745+
case ASR::ttypeType::Derived: {
746+
ASR::Derived_t* der_type = ASR::down_cast<ASR::Derived_t>(t);
747+
type_src = std::string("struct ") + ASRUtils::symbol_name(der_type->m_derived_type);
748+
break;
749+
}
734750
default: {
735751
throw CodeGenError("Type " + ASRUtils::type_to_str_python(t) + " not supported yet.");
736752
}
@@ -742,7 +758,8 @@ R"(#include <stdio.h>
742758
self().visit_expr(*x.m_arg);
743759
std::string arg_src = std::move(src);
744760
std::string addr_prefix = "&";
745-
if( ASRUtils::is_array(ASRUtils::expr_type(x.m_arg)) ) {
761+
if( ASRUtils::is_array(ASRUtils::expr_type(x.m_arg)) ||
762+
ASR::is_a<ASR::Derived_t>(*ASRUtils::expr_type(x.m_arg)) ) {
746763
addr_prefix.clear();
747764
}
748765
src = addr_prefix + arg_src;

tests/reference/asr-structs_01-be14d49.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
"basename": "asr-structs_01-be14d49",
33
"cmd": "lpython --show-asr --no-color {infile} -o {outfile}",
44
"infile": "tests/../integration_tests/structs_01.py",
5-
"infile_hash": "b3fd3a07d6aab6b40e16f209a74c4d64448b8a0e509e539f96ebd167",
5+
"infile_hash": "6586261b9b6e998bad980042375ce6206037a9bb5e1efb586edf691c",
66
"outfile": null,
77
"outfile_hash": null,
88
"stdout": "asr-structs_01-be14d49.stdout",
9-
"stdout_hash": "13f16c8ce74e0249f7800d65538d55bbdb84d06ff6ee7a7887466ed3",
9+
"stdout_hash": "1be7dd10a2f5f2a23e9567c9da3e050c017ff61573bf72c6d34ce14e",
1010
"stderr": null,
1111
"stderr_hash": null,
1212
"returncode": 0
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
(TranslationUnit (SymbolTable 1 {A: (DerivedType (SymbolTable 2 {x: (Variable 2 x Local () () Default (Integer 4 []) Source Public Required .false.), y: (Variable 2 y Local () () Default (Real 4 []) Source Public Required .false.)}) A [y x] Source Public ()), _lpython_main_program: (Subroutine (SymbolTable 6 {}) _lpython_main_program [] [(SubroutineCall 1 g () [] ())] Source Public Implementation () .false. .false.), f: (Subroutine (SymbolTable 3 {a: (Variable 3 a In () () Default (Derived 1 A []) Source Public Required .false.)}) f [(Var 3 a)] [(Print () [(DerivedRef (Var 3 a) 2 x (Integer 4 []) ())]) (Print () [(DerivedRef (Var 3 a) 2 y (Real 4 []) ())])] Source Public Implementation () .false. .false.), g: (Subroutine (SymbolTable 4 {x: (Variable 4 x Local () () Default (Derived 1 A []) Source Public Required .false.)}) g [] [(= (Var 4 x) (DerivedTypeConstructor 1 A [(Cast (RealConstant 3.25000000000000000e+00 (Real 8 [])) RealToReal (Real 4 []) (RealConstant 3.25000000000000000e+00 (Real 4 []))) (IntegerConstant 3 (Integer 4 []))] (Derived 1 A []) ()) ()) (SubroutineCall 1 f () [((Var 4 x))] ()) (Assert (Compare (DerivedRef (Var 4 x) 2 x (Integer 4 []) ()) Eq (IntegerConstant 3 (Integer 4 [])) (Logical 4 []) () ()) ()) (Assert (Compare (Cast (DerivedRef (Var 4 x) 2 y (Real 4 []) ()) RealToReal (Real 8 []) ()) Eq (RealConstant 3.25000000000000000e+00 (Real 8 [])) (Logical 4 []) () ()) ()) (= (DerivedRef (Var 4 x) 2 x (Integer 4 []) ()) (IntegerConstant 5 (Integer 4 [])) ()) (= (DerivedRef (Var 4 x) 2 y (Real 4 []) ()) (Cast (RealConstant 5.50000000000000000e+00 (Real 8 [])) RealToReal (Real 4 []) (RealConstant 5.50000000000000000e+00 (Real 4 []))) ()) (SubroutineCall 1 f () [((Var 4 x))] ()) (Assert (Compare (DerivedRef (Var 4 x) 2 x (Integer 4 []) ()) Eq (IntegerConstant 5 (Integer 4 [])) (Logical 4 []) () ()) ()) (Assert (Compare (Cast (DerivedRef (Var 4 x) 2 y (Real 4 []) ()) RealToReal (Real 8 []) ()) Eq (RealConstant 5.50000000000000000e+00 (Real 8 [])) (Logical 4 []) () ()) ())] Source Public Implementation () .false. .false.), main_program: (Program (SymbolTable 5 {}) main_program [] [(SubroutineCall 1 _lpython_main_program () [] ())])}) [])
1+
(TranslationUnit (SymbolTable 1 {A: (DerivedType (SymbolTable 2 {x: (Variable 2 x Local () () Default (Integer 4 []) Source Public Required .false.), y: (Variable 2 y Local () () Default (Real 4 []) Source Public Required .false.)}) A [y x] Source Public ()), _lpython_main_program: (Subroutine (SymbolTable 7 {}) _lpython_main_program [] [(SubroutineCall 1 g () [] ())] Source Public Implementation () .false. .false.), change_struct: (Subroutine (SymbolTable 4 {a: (Variable 4 a In () () Default (Derived 1 A []) Source Public Required .false.)}) change_struct [(Var 4 a)] [(= (DerivedRef (Var 4 a) 2 x (Integer 4 []) ()) (IntegerBinOp (DerivedRef (Var 4 a) 2 x (Integer 4 []) ()) Add (IntegerConstant 1 (Integer 4 [])) (Integer 4 []) ()) ()) (= (DerivedRef (Var 4 a) 2 y (Real 4 []) ()) (RealBinOp (DerivedRef (Var 4 a) 2 y (Real 4 []) ()) Add (Cast (IntegerConstant 1 (Integer 4 [])) IntegerToReal (Real 4 []) ()) (Real 4 []) ()) ())] Source Public Implementation () .false. .false.), f: (Subroutine (SymbolTable 3 {a: (Variable 3 a In () () Default (Derived 1 A []) Source Public Required .false.)}) f [(Var 3 a)] [(Print () [(DerivedRef (Var 3 a) 2 x (Integer 4 []) ())]) (Print () [(DerivedRef (Var 3 a) 2 y (Real 4 []) ())])] Source Public Implementation () .false. .false.), g: (Subroutine (SymbolTable 5 {x: (Variable 5 x Local () () Default (Derived 1 A []) Source Public Required .false.)}) g [] [(= (Var 5 x) (DerivedTypeConstructor 1 A [(Cast (RealConstant 3.25000000000000000e+00 (Real 8 [])) RealToReal (Real 4 []) (RealConstant 3.25000000000000000e+00 (Real 4 []))) (IntegerConstant 3 (Integer 4 []))] (Derived 1 A []) ()) ()) (SubroutineCall 1 f () [((Var 5 x))] ()) (Assert (Compare (DerivedRef (Var 5 x) 2 x (Integer 4 []) ()) Eq (IntegerConstant 3 (Integer 4 [])) (Logical 4 []) () ()) ()) (Assert (Compare (Cast (DerivedRef (Var 5 x) 2 y (Real 4 []) ()) RealToReal (Real 8 []) ()) Eq (RealConstant 3.25000000000000000e+00 (Real 8 [])) (Logical 4 []) () ()) ()) (= (DerivedRef (Var 5 x) 2 x (Integer 4 []) ()) (IntegerConstant 5 (Integer 4 [])) ()) (= (DerivedRef (Var 5 x) 2 y (Real 4 []) ()) (Cast (RealConstant 5.50000000000000000e+00 (Real 8 [])) RealToReal (Real 4 []) (RealConstant 5.50000000000000000e+00 (Real 4 []))) ()) (SubroutineCall 1 f () [((Var 5 x))] ()) (Assert (Compare (DerivedRef (Var 5 x) 2 x (Integer 4 []) ()) Eq (IntegerConstant 5 (Integer 4 [])) (Logical 4 []) () ()) ()) (Assert (Compare (Cast (DerivedRef (Var 5 x) 2 y (Real 4 []) ()) RealToReal (Real 8 []) ()) Eq (RealConstant 5.50000000000000000e+00 (Real 8 [])) (Logical 4 []) () ()) ()) (SubroutineCall 1 change_struct () [((Var 5 x))] ()) (Assert (Compare (DerivedRef (Var 5 x) 2 x (Integer 4 []) ()) Eq (IntegerConstant 6 (Integer 4 [])) (Logical 4 []) () ()) ()) (Assert (Compare (Cast (DerivedRef (Var 5 x) 2 y (Real 4 []) ()) RealToReal (Real 8 []) ()) Eq (RealConstant 6.50000000000000000e+00 (Real 8 [])) (Logical 4 []) () ()) ())] Source Public Implementation () .false. .false.), main_program: (Program (SymbolTable 6 {}) main_program [] [(SubroutineCall 1 _lpython_main_program () [] ())])}) [])

0 commit comments

Comments
 (0)