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

Added emition of the functions returning structure #366

Open
wants to merge 23 commits into
base: feature
Choose a base branch
from
Open
Changes from 6 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
cbbd9b3
Added a function which handles calls for the function returning a str…
DrRobik Feb 13, 2023
c93b456
Fixed emit_load_lvalue for structures
DrRobik Feb 15, 2023
9f3d3df
Changed emit_struct_return_call_expression(now it gets target, not ta…
DrRobik Feb 15, 2023
eecdbfa
Fixed func_definition
DrRobik Feb 15, 2023
b9dbd6c
Fixed codestyle
DrRobik Feb 17, 2023
67374dd
Fixed discrepancy with calling convention
DrRobik Feb 18, 2023
590be3b
Edited code and made separate function for loading function arguments
DrRobik Feb 27, 2023
a400fd3
Added call member emission (void, assign, member cases)
IgnatSergeev Mar 6, 2023
09dcd0b
Improved code style of emit_member_expression
IgnatSergeev Mar 13, 2023
4e11c70
Fixed lack of register freeing
IgnatSergeev Mar 13, 2023
139fdb7
Revert "Fixed emit_load_lvalue for structures"
IgnatSergeev Mar 26, 2023
380a402
Revert "Fixed lack of register freeing"
IgnatSergeev Mar 26, 2023
d196f7e
Revert "Improved code style of emit_member_expression"
IgnatSergeev Mar 26, 2023
3350b06
Revert "Added call member emission (void, assign, member cases)"
IgnatSergeev Mar 26, 2023
9551664
Reverted changes in function-declaration for merging
IgnatSergeev Mar 26, 2023
1426108
Merge branch 'feature' into fix-functions-returning-structure
IgnatSergeev Mar 26, 2023
8983bfd
Fixed merging
IgnatSergeev Mar 26, 2023
f2110d8
Added emit_function_argument for making all future changes easier
IgnatSergeev Mar 26, 2023
aef4167
Added ability for switch condition statement to be function returning…
IgnatSergeev Mar 26, 2023
9cf5902
Added displacement for return address
IgnatSergeev Mar 26, 2023
26ab6ac
Made separate function for emit_call_expression
IgnatSergeev Mar 27, 2023
4b5ce5b
Fixed register freeing
IgnatSergeev Mar 27, 2023
1840e2f
Merge branch 'feature' into fix-functions-returning-structure
IgnatSergeev Mar 28, 2023
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
254 changes: 243 additions & 11 deletions libs/compiler/mipsgen.c
Original file line number Diff line number Diff line change
Expand Up @@ -1344,8 +1344,13 @@ static rvalue emit_load_of_lvalue(encoder *const enc, const lvalue *const lval)
if (type_is_structure(enc->sx, lval->type))
{
// Грузим адрес первого элемента на регистр
const rvalue addr_rvalue = { .kind = RVALUE_KIND_CONST, .val.int_val = lval->loc.displ, .type = TYPE_INTEGER };
return emit_load_of_immediate(enc, &addr_rvalue);
const rvalue tmp = { .kind = RVALUE_KIND_CONST, .val.int_val = lval->loc.displ, .type = TYPE_INTEGER };
const rvalue displ_rvalue = emit_load_of_immediate(enc, &tmp);

const rvalue base_reg_rvalue = { .kind = RVALUE_KIND_REGISTER, .val.reg_num = lval->base_reg, .type = TYPE_INTEGER };

emit_binary_operation(enc, &displ_rvalue, &displ_rvalue, &base_reg_rvalue, BIN_ADD);
return displ_rvalue;
}

const bool is_floating = type_is_floating(lval->type);
Expand Down Expand Up @@ -2092,6 +2097,180 @@ static rvalue emit_builtin_call(encoder *const enc, const node *const nd)
}
}

/**
* Emit call expression of a function returning a structure
*
* @param enc Encoder
* @param nd Node in AST
* @param return_value_addr Rvalue storing the address of the place to store the return value
*
* @return Rvalue of the result of call expression
*/
static void emit_struct_return_call_expression(encoder *const enc, const node *const nd, const lvalue *const target)
{
const node callee = expression_call_get_callee(nd);
// Конвертируем в указатель на функцию
// FIXME: хотим рассмотреть любой callee как указатель
// на данный момент это не поддержано в билдере, когда будет сделано -- добавить в emit_expression()
// и применяем функцию emit_identifier_expression (т.к. его категория в билдере будет проставлена как rvalue)
const size_t func_ref = expression_identifier_get_id(&callee);
const size_t params_amount = expression_call_get_arguments_amount(nd);

const item_t return_type = type_function_get_return_type(enc->sx, expression_get_type(&callee));
assert(type_is_structure(enc->sx, return_type));

uni_printf(enc->sx->io, "\t# \"%s\" function call:\n", ident_get_spelling(enc->sx, func_ref));

assert(func_ref >= BEGIN_USER_FUNC);
bugdea1er marked this conversation as resolved.
Show resolved Hide resolved

size_t f_arg_count = 0;
size_t arg_count = 0;
size_t displ_for_parameters = (params_amount - 1) * WORD_LENGTH;
size_t displ_for_return_value_addr = WORD_LENGTH;
lvalue prev_arg_displ[4 /* за $a0-$a3 */
+ 4 / 2 /* за $fa0, $fa2 (т.к. single precision)*/];

uni_printf(enc->sx->io, "\t# setting up $sp:\n");
if (displ_for_parameters + displ_for_return_value_addr)
{
to_code_2R_I(enc->sx->io, IC_MIPS_ADDI, R_SP, R_SP, -(item_t)(displ_for_parameters + displ_for_return_value_addr));
}

uni_printf(enc->sx->io, "\n\t# parameters passing:\n");

uni_printf(enc->sx->io, "\t# saving ");
mips_register_to_io(enc->sx->io, R_A0);
uni_printf(enc->sx->io, " value on stack:\n");

const lvalue tmp_r_a0_lvalue = {
.base_reg = R_SP,
.loc.displ = 0,
.kind = LVALUE_KIND_STACK,
.type = TYPE_INTEGER
};

const rvalue r_a0_saved_rvalue = {
.kind = RVALUE_KIND_REGISTER,
.val.reg_num = R_A0,
.type = TYPE_INTEGER,
.from_lvalue = !FROM_LVALUE
};

emit_store_of_rvalue(
enc, &tmp_r_a0_lvalue,
&r_a0_saved_rvalue
);

const rvalue target_addr = emit_load_of_lvalue(enc, target);
emit_move_rvalue_to_register(
enc,
R_A0,
&target_addr
);

size_t arg_reg_count = 0;
++arg_count;
prev_arg_displ[arg_reg_count++] = tmp_r_a0_lvalue;
// TODO: структуры / массивы в параметры
for (size_t i = 0; i < params_amount; i++)
{
const node arg = expression_call_get_argument(nd, i);
const rvalue tmp = emit_expression(enc, &arg);
const rvalue arg_rvalue = (tmp.kind == RVALUE_KIND_CONST) ? emit_load_of_immediate(enc, &tmp) : tmp;

if ((type_is_floating(arg_rvalue.type) ? f_arg_count : arg_count) < ARG_REG_AMOUNT)
{
uni_printf(enc->sx->io, "\t# saving ");
mips_register_to_io(enc->sx->io, (type_is_floating(arg_rvalue.type) ? R_FA0 + f_arg_count
: R_A0 + arg_count));
uni_printf(enc->sx->io, " value on stack:\n");
}
else
{
uni_printf(enc->sx->io, "\t# parameter on stack:\n");
}

const lvalue tmp_arg_lvalue = {
.base_reg = R_SP,
// по call convention: первый на WORD_LENGTH выше предыдущего положения $fp,
// второй на 2*WORD_LENGTH и т.д.
.loc.displ = i * WORD_LENGTH + WORD_LENGTH,
.kind = LVALUE_KIND_STACK,
.type = arg_rvalue.type
};

const rvalue arg_saved_rvalue = {
.kind = RVALUE_KIND_REGISTER,
.val.reg_num =
(type_is_floating(arg_rvalue.type) ? R_FA0 + f_arg_count
: R_A0 + arg_count),
.type = arg_rvalue.type,
.from_lvalue = !FROM_LVALUE
};
// Сохранение текущего регистра-аргумента на стек либо передача аргументов на стек
emit_store_of_rvalue(
enc, &tmp_arg_lvalue,
(type_is_floating(arg_rvalue.type) ? f_arg_count : arg_count) < ARG_REG_AMOUNT
? &arg_saved_rvalue // Сохранение значения в регистре-аргументе
: &arg_rvalue // Передача аргумента
);

// Если это передача параметров в регистры-аргументы
if ((type_is_floating(arg_rvalue.type) ? f_arg_count : arg_count) < ARG_REG_AMOUNT)
{
// Аргументы рассматриваются в данном случае как регистровые переменные
emit_move_rvalue_to_register(
enc,
type_is_floating(arg_rvalue.type) ? (R_FA0 + f_arg_count)
: (R_A0 + arg_count),
&arg_rvalue
);

// Запоминаем, куда положили текущее значение, лежавшее в регистре-аргументе
prev_arg_displ[arg_reg_count++] = tmp_arg_lvalue;
}

if (type_is_floating(arg_rvalue.type))
{
f_arg_count += 2;
}
else
{
arg_count += 1;
}

free_rvalue(enc, &arg_rvalue);
}

const label label_func = { .kind = L_FUNC, .num = func_ref };
emit_unconditional_branch(enc, IC_MIPS_JAL, &label_func);

// Восстановление регистров-аргументов -- они могут понадобится в дальнейшем
uni_printf(enc->sx->io, "\n\t# data restoring:\n");

size_t i = 0, j = 0; // Счётчик обычных и floating point регистров-аргументов соответственно
while (i + j < arg_reg_count)
{
uni_printf(enc->sx->io, "\n");

const rvalue tmp_rval = emit_load_of_lvalue(enc, &prev_arg_displ[i + j]);
emit_move_rvalue_to_register(
enc,
type_is_floating(prev_arg_displ[i + j].type) ? (R_FA0 + 2 * j++) : (R_A0 + i++),
&tmp_rval
);

free_rvalue(enc, &tmp_rval);
}

if (displ_for_parameters + displ_for_return_value_addr)
{
to_code_2R_I(enc->sx->io, IC_MIPS_ADDI, R_SP, R_SP, (item_t)(displ_for_parameters + displ_for_return_value_addr));
}

uni_printf(enc->sx->io, "\n");
}

/**
* Emit call expression
*
Expand Down Expand Up @@ -2129,7 +2308,7 @@ static rvalue emit_call_expression(encoder *const enc, const node *const nd)
}

uni_printf(enc->sx->io, "\n\t# parameters passing:\n");

// TODO: вынести загрузку аргументов в отдельную функцию
// TODO: структуры / массивы в параметры
size_t arg_reg_count = 0;
for (size_t i = 0; i < params_amount; i++)
Expand Down Expand Up @@ -2554,7 +2733,11 @@ static rvalue emit_struct_assignment(encoder *const enc, const lvalue *const tar
{
emit_structure_init(enc, target, value);
}
else // Присваивание другой структуры
else if (expression_get_class(value) == EXPR_CALL)
{
emit_struct_return_call_expression(enc, value, target);
}
else// Присваивание другой структуры
{
// FIXME: возврат структуры из функции
// FIXME: массив структур
Expand Down Expand Up @@ -2719,7 +2902,34 @@ static rvalue emit_expression(encoder *const enc, const node *const nd)
return emit_literal_expression(enc, nd);

case EXPR_CALL:
return emit_call_expression(enc, nd);
if (type_is_structure(enc->sx, expression_get_type(nd)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

В отдельную функцию emit_call_expression

{
const item_t type = expression_get_type(nd);
const size_t old_displ = enc->scope_displ;
const lvalue target = {
.kind = LVALUE_KIND_STACK,
.type = type,
.base_reg = R_FP,
.loc.displ = old_displ
};

enc->scope_displ += mips_type_size(enc->sx, type);
enc->max_displ = max(enc->scope_displ, enc->max_displ);

emit_struct_return_call_expression(enc, nd, &target);
enc->scope_displ = old_displ;

return (rvalue) {
.kind = RVALUE_KIND_REGISTER,
.type = TYPE_INTEGER,
.val.reg_num = R_A0,
.from_lvalue = !FROM_LVALUE
};
}
else
{
return emit_call_expression(enc, nd);
}

case EXPR_MEMBER:
return emit_member_expression(enc, nd);
Expand Down Expand Up @@ -3087,6 +3297,7 @@ static void emit_function_definition(encoder *const enc, const node *const nd)
emit_label_declaration(enc, &func_label);

const item_t func_type = ident_get_type(enc->sx, ref_ident);
const item_t return_type = type_function_get_return_type(enc->sx, func_type);
const size_t parameters = type_function_get_parameter_amount(enc->sx, func_type);

if (ref_ident == enc->sx->ref_main)
Expand Down Expand Up @@ -3145,14 +3356,19 @@ static void emit_function_definition(encoder *const enc, const node *const nd)
size_t gpr_count = 0;
size_t fp_count = 0;

if (type_is_structure(enc->sx, return_type))
{
++gpr_count;
}

for (size_t i = 0; i < parameters; i++)
{
const size_t id = declaration_function_get_parameter(nd, i);
uni_printf(enc->sx->io, "\t# parameter \"%s\" ", ident_get_spelling(enc->sx, id));

if (!type_is_floating(ident_get_type(enc->sx, id)))
{
if (i < ARG_REG_AMOUNT)
if (gpr_count < ARG_REG_AMOUNT)
{
// Рассматриваем их как регистровые переменные
const mips_register_t curr_reg = R_A0 + gpr_count++;
Expand All @@ -3171,7 +3387,7 @@ static void emit_function_definition(encoder *const enc, const node *const nd)
}
else
{
if (i < ARG_REG_AMOUNT / 2)
if (fp_count < ARG_REG_AMOUNT / 2)
{
// Рассматриваем их как регистровые переменные
const mips_register_t curr_reg = R_FA0 + 2 * fp_count++;
Expand Down Expand Up @@ -3634,12 +3850,28 @@ static void emit_return_statement(encoder *const enc, const node *const nd)
if (statement_return_has_expression(nd))
{
const node expression = statement_return_get_expression(nd);
const rvalue value = emit_expression(enc, &expression);

const lvalue return_lval = { .kind = LVALUE_KIND_REGISTER, .loc.reg_num = R_V0, .type = value.type };
if (type_is_structure(enc->sx, expression_get_type(&expression)))
{
const lvalue target = {
.kind = LVALUE_KIND_STACK,
.type = expression_get_type(&expression),
.base_reg = R_A0,
.loc.displ = 0
};

emit_struct_assignment(enc, &target, &expression);
}
else
{
const rvalue value = emit_expression(enc, &expression);

const lvalue return_lval = { .kind = LVALUE_KIND_REGISTER, .loc.reg_num = R_V0, .type = value.type };

emit_store_of_rvalue(enc, &return_lval, &value);
free_rvalue(enc, &value);
}

emit_store_of_rvalue(enc, &return_lval, &value);
free_rvalue(enc, &value);
}

const label label_end = { .kind = L_FUNCEND, .num = enc->curr_function_ident };
Expand Down