Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix vm array assignment #398

Open
wants to merge 23 commits into
base: feature
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
228 changes: 226 additions & 2 deletions libs/compiler/codegen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1142,6 +1142,95 @@ static void emit_ternary_expression(encoder *const enc, const node *const nd)
mem_set(enc, addr, (item_t)mem_size(enc));
}

/**
* Loads copy of array initializer on top of the stack
*
* @param enc Encoder
* @param nd Node in AST
*/
static void array_load_initializer(encoder *const enc, const node *const array)
{
assert((expression_get_class(array) == EXPR_IDENTIFIER || expression_get_class(array) == EXPR_MEMBER
|| expression_get_class(array) == EXPR_SUBSCRIPT) && type_is_array(enc->sx, expression_get_type(array)));
emit_expression(enc, array);
item_t current_type = expression_get_type(array);

int dimensions = 0;
while (type_is_array(enc->sx, current_type))
{
current_type = type_array_get_element_type(enc->sx, current_type);
++dimensions;
}

const size_t element_size = type_size(enc->sx, current_type);

if (dimensions == 1)
{
// Начало инициализатора
mem_add(enc, IC_LI);
mem_add(enc, -1);
mem_add(enc, IC_ADD);

// Его размер
mem_add(enc, IC_COPY_FROM_END);
mem_add(enc, 0);
mem_add(enc, IC_LAT);
mem_add(enc, IC_LI);
mem_add(enc, element_size);
mem_add(enc, IC_MUL);
mem_add(enc, IC_LI);
mem_add(enc, 1);
mem_add(enc, IC_ADD);

// Копирование его в конец стека
mem_add(enc, IC_COPY2ST);
return;
}

// Вычисление смещения старта инициализатора
for (int i = 0; i < dimensions - 1; i++)
{
mem_add(enc, IC_LAT);
}

mem_add(enc, IC_LI);
mem_add(enc, -dimensions);
mem_add(enc, IC_ADD);

// Вычисление смещения конца инициализатора (предыдущий индекс относительно найденного)
emit_expression(enc, array);
for (int i = 0; i < dimensions - 1; i++)
{
mem_add(enc, IC_LI);
mem_add(enc, -1);
mem_add(enc, IC_ADD);
mem_add(enc, IC_COPY_FROM_END);
mem_add(enc, 0);
mem_add(enc, IC_LAT);
mem_add(enc, IC_ADD);
mem_add(enc, IC_LAT);
}

mem_add(enc, IC_COPY_FROM_END);
mem_add(enc, 0);
mem_add(enc, IC_LI);
mem_add(enc, -1);
mem_add(enc, IC_ADD);
mem_add(enc, IC_LAT);
mem_add(enc, IC_LI);
mem_add(enc, element_size);
mem_add(enc, IC_MUL);
mem_add(enc, IC_ADD);

// Вычисление длины инициализатора (конец - начало)
mem_add(enc, IC_COPY_FROM_END);
mem_add(enc, 1);
mem_add(enc, IC_SUB);

// Копирование его в конец стека
mem_add(enc, IC_COPY2ST);
}

/**
* Emit assignment expression
*
Expand All @@ -1154,9 +1243,12 @@ static void emit_assignment_expression(encoder *const enc, const node *const nd)
const lvalue value = emit_lvalue(enc, &LHS);

const node RHS = expression_assignment_get_RHS(nd);
emit_expression(enc, &RHS);

const item_t type = expression_get_type(nd);
if (!type_is_array(enc->sx, type)) {
emit_expression(enc, &RHS);
}

if (type_is_structure(enc->sx, type))
{
if (value.kind == VARIABLE)
Expand All @@ -1171,6 +1263,129 @@ static void emit_assignment_expression(encoder *const enc, const node *const nd)

mem_add(enc, (item_t)type_size(enc->sx, type));
}
else if (type_is_array(enc->sx, type))
{
item_t current_type = type;
item_t dimensions = 0;
while (type_is_array(enc->sx, current_type))
{
current_type = type_array_get_element_type(enc->sx, current_type);
dimensions++;
}

mem_add(enc, IC_SET_ARR_INIT_START);
if (expression_get_class(&RHS) == EXPR_IDENTIFIER || expression_get_class(&RHS) == EXPR_MEMBER
|| expression_get_class(&RHS) == EXPR_SUBSCRIPT)
{
array_load_initializer(enc, &RHS);
}
else
{
emit_expression(enc, &RHS);
}


if (expression_get_class(&LHS) == EXPR_IDENTIFIER)
{
size_t usual = 1;
if (type_is_string(enc->sx, current_type))
{
usual += 2;
}
const item_t length = (item_t)type_size(enc->sx, current_type);
mem_add(enc, IC_ARR_INIT);
mem_add(enc, dimensions);
mem_add(enc, length);
mem_add(enc, displacements_get(enc, expression_identifier_get_id(&LHS)));
mem_add(enc, usual);
}
else if (expression_get_class(&LHS) == EXPR_SUBSCRIPT)
{
// Address loading
const node base = expression_subscript_get_base(&LHS);
emit_expression(enc, &base);

const node index = expression_subscript_get_index(&LHS);
emit_expression(enc, &index);

mem_add(enc, IC_SLICE);

mem_add(enc, (item_t)type_size(enc->sx, type));


size_t usual = 1;
if (type_is_string(enc->sx, current_type))
{
usual += 2;
}

const item_t length = (item_t)type_size(enc->sx, current_type);
mem_add(enc, IC_ARR_INIT_STACK_ADDR);
mem_add(enc, dimensions);
mem_add(enc, length);
mem_add(enc, usual);
}
else if (expression_get_class(&LHS) == EXPR_MEMBER)
{
size_t usual = 1;
if (type_is_string(enc->sx, current_type))
{
usual += 2;
}

// Address loading
const node base = expression_member_get_base(&LHS);
const item_t base_type = expression_get_type(&base);
const bool is_arrow = expression_member_is_arrow(&LHS);
const size_t member_index = expression_member_get_member_index(&LHS);

item_t member_displ = 0;
for (size_t i = 0; i < member_index; i++)
{
const item_t member_type = type_structure_get_member_type(enc->sx, base_type, i);
member_displ += (item_t)type_size(enc->sx, member_type);
}

if (is_arrow)
{
emit_expression(enc, &base);
mem_add(enc, IC_SELECT);
mem_add(enc, member_displ);

const item_t length = (item_t)type_size(enc->sx, current_type);
mem_add(enc, IC_ARR_INIT_STACK_ADDR);
mem_add(enc, dimensions);
mem_add(enc, length);
mem_add(enc, usual);
}
else
{
const lvalue base_value = emit_lvalue(enc, &base);
if (base_value.kind == VARIABLE)
{
const item_t displ = base_value.displ > 0 ? base_value.displ + member_displ : base_value.displ - member_displ;

const item_t length = (item_t)type_size(enc->sx, current_type);
mem_add(enc, IC_ARR_INIT);
mem_add(enc, dimensions);
mem_add(enc, length);
mem_add(enc, displ);
mem_add(enc, usual);
}
else
{
mem_add(enc, IC_SELECT);
mem_add(enc, member_displ);

const item_t length = (item_t)type_size(enc->sx, current_type);
mem_add(enc, IC_ARR_INIT_STACK_ADDR);
mem_add(enc, dimensions);
mem_add(enc, length);
mem_add(enc, usual);
}
}
}
}
else // Скалярное присваивание
{
const binary_t op = expression_assignment_get_operator(nd);
Expand Down Expand Up @@ -1214,7 +1429,16 @@ static void emit_initializer(encoder *const enc, const node *const nd)
for (size_t i = 0; i < size; i++)
{
const node subexpr = expression_initializer_get_subexpr(nd, i);
emit_expression(enc, &subexpr);
if (type_is_array(enc->sx, expression_get_type(&subexpr)) &&
(expression_get_class(&subexpr) == EXPR_IDENTIFIER || expression_get_class(&subexpr) == EXPR_MEMBER
|| expression_get_class(&subexpr) == EXPR_SUBSCRIPT))
{
array_load_initializer(enc, &subexpr);
}
else
{
emit_expression(enc, &subexpr);
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions libs/compiler/instructions.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,8 @@ typedef enum INSTURCTION
IC_STRING_INIT, /**< 'STRINGINIT' instruction code */
IC_ARR_INIT, /**< 'ARRINIT' instruction code */
IC_STRUCT_WITH_ARR, /**< 'STRUCTWITHARR' instruction code */
IC_ARR_INIT_STACK_ADDR, /**< 'ARRINITSTACKADDR' instruction code */
IC_SET_ARR_INIT_START, /**< 'SETARRINITSTART' instruction code */

IC_BEG_INIT = 9481, /**< 'BEGINIT' instruction code */
IC_ROWING, /**< 'ROWING' instruction code */
Expand All @@ -208,6 +210,8 @@ typedef enum INSTURCTION
IC_COPY0ST_ASSIGN, /**< 'COPY0STASS' instruction code */
IC_COPY1ST_ASSIGN, /**< 'COPY1STASS' instruction code */
IC_COPYST, /**< 'COPYST' instruction code */
IC_COPY2ST, /**< 'COPY2ST' instruction code */
IC_COPY_FROM_END, /**< 'COPYLAST' instruction code */

IC_ABS = 9534, /**< 'ABS' instruction code */
IC_SQRT, /**< 'SQRT' instruction code */
Expand Down
99 changes: 99 additions & 0 deletions tests/codegen/executable/arrays/assignment/arrays-assignment.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
void main()
{
int a[3] = {1, 2, 3};
int d[3] = {1, 2, 3};
int b[2][3] = {{1, 2, 3}, {4, 5, 6}};
int c[2][2][3] = {{{7, 8, 9}, {10, 11, 12}}, {{1, 2, 3}, {4, 5, 6}}};

a = {2 ,3, 4};
b = {a, {1, 2, 3}};
d = a;
c[1] = b;
c[1][1] = a;

assert(a[0] == 2, "a[0] must be 2");
assert(a[1] == 3, "a[1] must be 3");
assert(a[2] == 4, "a[2] must be 4");

assert(d[0] == 2, "d[0] must be 2");
assert(d[1] == 3, "d[1] must be 3");
assert(d[2] == 4, "d[2] must be 4");

assert(b[0][0] == 2, "b[0][0] must be 2");
assert(b[0][1] == 3, "b[0][1] must be 3");
assert(b[0][2] == 4, "b[0][2] must be 4");
assert(b[1][0] == 1, "b[1][0] must be 1");
assert(b[1][1] == 2, "b[1][1] must be 2");
assert(b[1][2] == 3, "b[1][2] must be 3");

assert(c[0][0][0] == 7, "c[0][0][0] must be 7");
assert(c[0][0][1] == 8, "c[0][0][1] must be 8");
assert(c[0][0][2] == 9, "c[0][0][2] must be 9");
assert(c[0][1][0] == 10, "c[0][1][0] must be 10");
assert(c[0][1][1] == 11, "c[0][1][1] must be 11");
assert(c[0][1][2] == 12, "c[0][1][2] must be 12");
assert(c[1][0][0] == 2, "c[1][0][0] must be 2");
assert(c[1][0][1] == 3, "c[1][0][1] must be 3");
assert(c[1][0][2] == 4, "c[1][0][2] must be 4");
assert(c[1][1][0] == 2, "c[1][1][0] must be 2");
assert(c[1][1][1] == 3, "c[1][1][1] must be 3");
assert(c[1][1][2] == 4, "c[1][1][2] must be 4");

a = b[1];

assert(a[0] == 1, "a[0] must be 1");
assert(a[1] == 2, "a[1] must be 2");
assert(a[2] == 3, "a[2] must be 3");

a = c[0][0];

assert(a[0] == 7, "a[0] must be 7");
assert(a[1] == 8, "a[1] must be 8");
assert(a[2] == 9, "a[2] must be 9");

b[0] = c[0][0];

assert(b[0][0] == 7, "b[0][0] must be 7");
assert(b[0][1] == 8, "b[0][1] must be 8");
assert(b[0][2] == 9, "b[0][2] must be 9");
assert(b[1][0] == 1, "b[1][0] must be 1");
assert(b[1][1] == 2, "b[1][1] must be 2");
assert(b[1][2] == 3, "b[1][2] must be 3");

c[0] = {b[1], a};

assert(c[0][0][0] == 1, "c[0][0][0] must be 1");
assert(c[0][0][1] == 2, "c[0][0][1] must be 2");
assert(c[0][0][2] == 3, "c[0][0][2] must be 3");
assert(c[0][1][0] == 7, "c[0][1][0] must be 7");
assert(c[0][1][1] == 8, "c[0][1][1] must be 8");
assert(c[0][1][2] == 9, "c[0][1][2] must be 9");
assert(c[1][0][0] == 2, "c[1][0][0] must be 2");
assert(c[1][0][1] == 3, "c[1][0][1] must be 3");
assert(c[1][0][2] == 4, "c[1][0][2] must be 4");
assert(c[1][1][0] == 2, "c[1][1][0] must be 2");
assert(c[1][1][1] == 3, "c[1][1][1] must be 3");
assert(c[1][1][2] == 4, "c[1][1][2] must be 4");

/*

c = {c[0], c[1]};


assert(c[0][0][0] == 1, "c[0][0][0] must be 1");
assert(c[0][0][1] == 2, "c[0][0][1] must be 2");
assert(c[0][0][2] == 3, "c[0][0][2] must be 3");
assert(c[0][1][0] == 7, "c[0][1][0] must be 7");
assert(c[0][1][1] == 8, "c[0][1][1] must be 8");
assert(c[0][1][2] == 9, "c[0][1][2] must be 9");
assert(c[1][0][0] == 2, "c[1][0][0] must be 2");
assert(c[1][0][1] == 3, "c[1][0][1] must be 3");
assert(c[1][0][2] == 4, "c[1][0][2] must be 4");
assert(c[1][1][0] == 2, "c[1][1][0] must be 2");
assert(c[1][1][1] == 3, "c[1][1][1] must be 3");
assert(c[1][1][2] == 4, "c[1][1][2] must be 4");

*/

}

Loading