Allow compound types on the stack

This commit is contained in:
2026-02-17 19:14:49 +01:00
parent 512a57ccca
commit 8142680fb7

View File

@@ -7,6 +7,8 @@ program;
(* Stage 19 compiler. *)
(* - Aggregates can be allocated on the stack. *)
type
(**
* List of intermediate representation items.
@@ -18,14 +20,6 @@ type
data: Word;
code: Word
end;
ElnaInstructionDeclaration = record
next: Word;
name: Word;
length: Word;
body: Word;
parameters: Word;
count: Word
end;
(* Type representation. *)
ElnaTypeKind = (primitive, enumeration, _record, pointer, array);
@@ -540,6 +534,19 @@ type
value: Word;
length: Word
end;
ElnaRtlStaticVariable = record
next: Word;
name: Word;
length: Word;
body: Word
end;
ElnaRtlProcedure = record
next: Word;
name: Word;
length: Word;
body: Word;
variable_map: ^ElnaSymbolTable
end;
ElnaRtlInstruction = record
next: Word;
operator: ElnaRtlOperator;
@@ -579,13 +586,27 @@ type
t5,
t6
);
ElnaRtlTypeKind = (long_word, byte_array);
ElnaRtlType = record
kind: ElnaRtlTypeKind;
size: Word
end;
ElnaRtlTypeWord = record
kind: ElnaRtlTypeKind;
size: Word
end;
ElnaRtlTypeByteArray = record
kind: ElnaRtlTypeKind;
size: Word
end;
ElnaRtlInfo = record
counter: Word
counter: Word;
rtl_type: ^ElnaRtlType;
allocated: Word
end;
var
symbol_table_global: [1024]Word;
variable_map: [1024]Word;
compiler_strings: [1024]Word;
classification: [256]Word;
@@ -1232,18 +1253,6 @@ begin
return result
end;
proc elna_instruction_module_create(data: Word, code: Word);
var
result: ^ElnaInstructionModule;
begin
result := malloc(#size(ElnaInstructionModule));
result^.data := data;
result^.code := code;
return result
end;
proc elna_tac_label(counter: Word, length: Word);
var
result: Word;
@@ -1368,17 +1377,16 @@ begin
end
end;
proc elna_alloc_variable(operand_value: Word, operand_length: Word);
proc elna_alloc_variable(operand_value: Word, operand_length: Word, variable_map: ^ElnaSymbolTable);
var
pseudo_symbol: ^ElnaRtlInfo;
begin
pseudo_symbol := elna_symbol_table_lookup(@variable_map, operand_value, operand_length);
if pseudo_symbol = nil then
pseudo_symbol := malloc(#size(ElnaRtlInfo));
pseudo_symbol := elna_symbol_table_lookup(variable_map, operand_value, operand_length);
if pseudo_symbol^.allocated = false then
pseudo_symbol^.allocated := true;
pseudo_symbol^.counter := temporary_variable_counter;
elna_symbol_table_enter(@variable_map, operand_value, operand_length, pseudo_symbol);
temporary_variable_counter := temporary_variable_counter + 4
temporary_variable_counter := temporary_variable_counter + pseudo_symbol^.rtl_type^.size
end;
return pseudo_symbol
end;
@@ -1388,7 +1396,7 @@ end;
* to be a register, but is not a register, then this procedure rewrites it
* to a temporary register and preserves its value in the following instruction.
*)
proc elna_alloc_operation_target(instruction: ^ElnaRtlInstruction);
proc elna_alloc_operation_target(instruction: ^ElnaRtlInstruction, variable_map: ^ElnaSymbolTable);
var
pseudo_symbol: ^ElnaRtlInfo;
store_instruction: ^ElnaRtlInstruction;
@@ -1397,7 +1405,8 @@ begin
store_instruction := elna_rtl_instruction_create(ElnaRtlOperator.sw);
store_instruction^.next := instruction^.next;
pseudo_symbol := elna_alloc_variable(instruction^.operands[1].value, instruction^.operands[1].length);
pseudo_symbol := elna_alloc_variable(instruction^.operands[1].value, instruction^.operands[1].length,
variable_map);
elna_rtl_instruction_set_operand(store_instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.t0, 0);
elna_rtl_instruction_set_operand(store_instruction, 2, ElnaRtlKind.offset, ElnaRtlRegister.sp, pseudo_symbol^.counter);
@@ -1406,23 +1415,24 @@ begin
end
end;
proc elna_alloc_load_address(instruction: ^ElnaRtlInstruction);
proc elna_alloc_load_address(instruction: ^ElnaRtlInstruction, variable_map: ^ElnaSymbolTable);
var
pseudo_symbol: ^ElnaRtlInfo;
begin
if instruction^.operands[2].kind = ElnaRtlKind.pseudo then
pseudo_symbol := elna_alloc_variable(instruction^.operands[2].value, instruction^.operands[2].length);
pseudo_symbol := elna_alloc_variable(instruction^.operands[2].value, instruction^.operands[2].length,
variable_map);
instruction^.operator := ElnaRtlOperator.addi;
elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.register, ElnaRtlRegister.sp, 0);
elna_rtl_instruction_set_operand(instruction, 3, ElnaRtlKind.immediate, pseudo_symbol^.counter, 0)
end;
if instruction^.operands[1].kind = ElnaRtlKind.pseudo then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
end
end;
proc elna_alloc_store(instruction: ^ElnaRtlInstruction);
proc elna_alloc_store(instruction: ^ElnaRtlInstruction, variable_map: ^ElnaSymbolTable);
var
old_instruction: ^ElnaRtlInstruction;
pseudo_symbol: ^ElnaRtlInfo;
@@ -1431,7 +1441,8 @@ begin
old_instruction := malloc(#size(ElnaRtlInstruction));
memcpy(old_instruction, instruction, #size(ElnaRtlInstruction));
pseudo_symbol := elna_alloc_variable(instruction^.operands[2].value, instruction^.operands[2].length);
pseudo_symbol := elna_alloc_variable(instruction^.operands[2].value, instruction^.operands[2].length,
variable_map);
instruction^.operator := ElnaRtlOperator.lw;
elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.t1, 0);
@@ -1442,7 +1453,7 @@ begin
end
end;
proc elna_alloc_load(instruction: ^ElnaRtlInstruction);
proc elna_alloc_load(instruction: ^ElnaRtlInstruction, variable_map: ^ElnaSymbolTable);
var
old_instruction: ^ElnaRtlInstruction;
pseudo_symbol: ^ElnaRtlInfo;
@@ -1451,7 +1462,8 @@ begin
old_instruction := malloc(#size(ElnaRtlInstruction));
memcpy(old_instruction, instruction, #size(ElnaRtlInstruction));
pseudo_symbol := elna_alloc_variable(instruction^.operands[1].value, instruction^.operands[1].length);
pseudo_symbol := elna_alloc_variable(instruction^.operands[1].value, instruction^.operands[1].length,
variable_map);
old_instruction^.operator := ElnaRtlOperator.sw;
elna_rtl_instruction_set_operand(old_instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.t1, 0);
@@ -1462,14 +1474,15 @@ begin
end
end;
proc elna_alloc_instruction(instruction: ^ElnaRtlInstruction);
proc elna_alloc_instruction(instruction: ^ElnaRtlInstruction, variable_map: ^ElnaSymbolTable);
var
pseudo_symbol: ^ElnaRtlInfo;
old_instruction: ^ElnaRtlInstruction;
begin
if instruction^.operator = ElnaRtlOperator.move then
if instruction^.operands[1].kind = ElnaRtlKind.pseudo then
pseudo_symbol := elna_alloc_variable(instruction^.operands[1].value, instruction^.operands[1].length);
pseudo_symbol := elna_alloc_variable(instruction^.operands[1].value, instruction^.operands[1].length,
variable_map);
instruction^.operator = ElnaRtlOperator.sw;
instruction^.operands[1].kind := instruction^.operands[2].kind;
@@ -1480,40 +1493,42 @@ begin
goto elna_alloc_instruction_end
end;
if instruction^.operands[2].kind = ElnaRtlKind.pseudo then
pseudo_symbol := elna_alloc_variable(instruction^.operands[2].value, instruction^.operands[2].length);
pseudo_symbol := elna_alloc_variable(instruction^.operands[2].value, instruction^.operands[2].length,
variable_map);
instruction^.operator = ElnaRtlOperator.lw;
elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlKind.offset, ElnaRtlRegister.sp, pseudo_symbol^.counter);
goto elna_alloc_instruction_end
end
elsif instruction^.operator = ElnaRtlOperator.la then
elna_alloc_load_address(instruction)
elna_alloc_load_address(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.lw then
elna_alloc_load(instruction)
elna_alloc_load(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.sw then
elna_alloc_store(instruction)
elna_alloc_store(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator._or then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.and then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.mul then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.sub then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.add then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator._xor then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.rem then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.slt then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.beqz then
if instruction^.operands[1].kind = ElnaRtlKind.pseudo then
old_instruction := malloc(#size(ElnaRtlInstruction));
memcpy(old_instruction, instruction, #size(ElnaRtlInstruction));
pseudo_symbol := elna_alloc_variable(instruction^.operands[1].value, instruction^.operands[1].length);
pseudo_symbol := elna_alloc_variable(instruction^.operands[1].value, instruction^.operands[1].length,
variable_map);
instruction^.operator := ElnaRtlOperator.lw;
elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlKind.register, ElnaRtlRegister.t0, 0);
@@ -1525,11 +1540,11 @@ begin
goto elna_alloc_instruction_end
end
elsif instruction^.operator = ElnaRtlOperator.seqz then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.snez then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
elsif instruction^.operator = ElnaRtlOperator.xori then
elna_alloc_operation_target(instruction)
elna_alloc_operation_target(instruction, variable_map)
end;
.elna_alloc_instruction_end;
end;
@@ -1604,12 +1619,12 @@ begin
return first_copy
end;
proc elna_alloc_instructions(instruction: ^ElnaRtlInstruction);
proc elna_alloc_instructions(instruction: ^ElnaRtlInstruction, variable_map: ^ElnaSymbolTable);
begin
.elna_alloc_instructions_start;
if instruction <> nil then
elna_alloc_instruction(instruction);
elna_alloc_instruction(instruction, variable_map);
instruction := instruction^.next;
goto elna_alloc_instructions_start
end
@@ -1625,15 +1640,14 @@ begin
end
end;
proc elna_alloc_procedure(rtl_declaration: ^ElnaInstructionDeclaration);
proc elna_alloc_procedure(rtl_declaration: ^ElnaRtlProcedure);
var
stack_instruction: ^ElnaRtlInstruction;
begin
.elna_alloc_procedure_loop;
temporary_variable_counter := 0;
variable_map := 0;
elna_alloc_instructions(rtl_declaration^.body);
elna_alloc_instructions(rtl_declaration^.body, rtl_declaration^.variable_map);
stack_instruction := elna_rtl_instruction_create(ElnaRtlOperator.allocate_stack);
stack_instruction^.next := rtl_declaration^.body;
@@ -1651,7 +1665,7 @@ begin
end
end;
proc elna_riscv_procedure(procedure: ^ElnaInstructionDeclaration);
proc elna_riscv_procedure(procedure: ^ElnaRtlProcedure);
begin
.elna_riscv_procedure_loop;
@@ -1670,7 +1684,7 @@ begin
end
end;
proc elna_riscv_variable(variable: ^ElnaInstructionDeclaration);
proc elna_riscv_variable(variable: ^ElnaRtlStaticVariable);
begin
.elna_riscv_variable_loop;
if variable <> 0 then
@@ -1685,13 +1699,13 @@ end;
proc elna_rtl_module_declaration(tac_module: ^ElnaInstructionModule);
var
code_part: ^ElnaInstructionDeclaration;
data_part: ^ElnaInstructionDeclaration;
result: ^ElnaInstructionModule;
begin
data_part := elna_rtl_globals(tac_module^.data);
code_part := elna_rtl_procedures(tac_module^.code);
result := malloc(#size(ElnaInstructionModule));
result^.data := elna_rtl_globals(tac_module^.data);
result^.code := elna_rtl_procedures(tac_module^.code);
return elna_instruction_module_create(data_part, code_part)
return result
end;
proc elna_alloc_module(pair: ^ElnaInstructionModule);
@@ -3614,9 +3628,9 @@ end;
proc elna_rtl_global_declaration(tac_declaration: ^ElnaTacStaticVariable);
var
result: ^ElnaInstructionDeclaration;
result: ^ElnaRtlStaticVariable;
begin
result := malloc(#size(ElnaInstructionDeclaration));
result := malloc(#size(ElnaRtlStaticVariable));
result^.next := nil;
result^.name := tac_declaration^.name;
@@ -3663,13 +3677,72 @@ begin
return result
end;
proc elna_rtl_procedure_declaration(tac_declaration: ^ElnaInstructionDeclaration);
(* Returns whether the provided type is array or record. *)
proc elna_type_is_aggregate(_type: ^ElnaType);
var
result: ^ElnaInstructionDeclaration;
lhs: Word;
rhs: Word;
begin
lhs := _type^.kind = ElnaTypeKind._record;
rhs := _type^.kind = ElnaTypeKind.array;
return lhs or rhs
end;
proc elna_rtl_symbol_table(symbol_table: ^ElnaSymbolTable);
var
variable_map: ^ElnaSymbolTable;
count: Word;
current_entry: ^ElnaSymbolEntry;
pseudo_symbol: ^ElnaRtlInfo;
variable_info: ^ElnaSymbolTemporaryInfo;
byte_array: ^ElnaRtlTypeByteArray;
long_word: ^ElnaRtlTypeWord;
begin
variable_map := malloc(16384);
variable_map^.count := 0;
count := symbol_table^.count;
current_entry := symbol_table + 4;
.elna_rtl_symbol_table_loop;
if count > 0 then
variable_info := current_entry^.symbol_info;
pseudo_symbol := malloc(#size(ElnaRtlInfo));
pseudo_symbol^.allocated := false;
if elna_type_is_aggregate(variable_info^.variable_type) then
long_word := malloc(#size(ElnaRtlTypeWord));
long_word^.kind := ElnaRtlTypeKind.long_word;
long_word^.size := variable_info^.variable_type^.size;
pseudo_symbol^.rtl_type = long_word
else
byte_array := malloc(#size(ElnaRtlTypeByteArray));
byte_array^.kind := ElnaRtlTypeKind.byte_array;
byte_array^.size := variable_info^.variable_type^.size;
pseudo_symbol^.rtl_type = byte_array
end;
elna_symbol_table_enter(variable_map, current_entry^.name, current_entry^.length, pseudo_symbol);
count := count - 1;
current_entry := current_entry + #size(ElnaSymbolEntry);
goto elna_rtl_symbol_table_loop
end;
return variable_map;
end;
proc elna_rtl_procedure_declaration(tac_declaration: ^ElnaTacProcedure);
var
result: ^ElnaRtlProcedure;
body: ^ElnaRtlInstruction;
parameters: ^ElnaRtlInstruction;
begin
result := malloc(#size(ElnaInstructionDeclaration));
result := malloc(#size(ElnaRtlProcedure));
result^.next := nil;
result^.name := tac_declaration^.name;
@@ -3678,6 +3751,7 @@ begin
parameters = elna_rtl_parameters(tac_declaration^.parameters, tac_declaration^.count);
body := elna_rtl_instructions(tac_declaration^.body);
result^.body := elna_instruction_list_concatenate(parameters, body);
result^.variable_map := elna_rtl_symbol_table(tac_declaration^.symbol_table);
return result
end;
@@ -3738,9 +3812,9 @@ end;
proc elna_rtl_globals(tac_procedure: ^ElnaTacStaticVariable);
var
current_copy: ^ElnaInstructionDeclaration;
next_copy: ^ElnaInstructionDeclaration;
first_copy: ^ElnaInstructionDeclaration;
current_copy: ^ElnaRtlStaticVariable;
next_copy: ^ElnaRtlStaticVariable;
first_copy: ^ElnaRtlStaticVariable;
begin
if tac_procedure <> nil then
first_copy := elna_rtl_global_declaration(tac_procedure);
@@ -3764,11 +3838,11 @@ begin
return first_copy
end;
proc elna_rtl_procedures(tac_procedure: ^ElnaInstructionDeclaration);
proc elna_rtl_procedures(tac_procedure: ^ElnaTacProcedure);
var
current_copy: ^ElnaInstructionDeclaration;
next_copy: ^ElnaInstructionDeclaration;
first_copy: ^ElnaInstructionDeclaration;
current_copy: ^ElnaRtlProcedure;
next_copy: ^ElnaRtlProcedure;
first_copy: ^ElnaRtlProcedure;
begin
if tac_procedure <> nil then
first_copy := elna_rtl_procedure_declaration(tac_procedure);
@@ -3794,9 +3868,9 @@ end;
proc elna_tac_procedures(parser_node: ^ElnaTreeDeclaration);
var
result: ^ElnaInstructionDeclaration;
current_procedure: ^ElnaInstructionDeclaration;
first_procedure: ^ElnaInstructionDeclaration;
result: ^ElnaTacProcedure;
current_procedure: ^ElnaTacProcedure;
first_procedure: ^ElnaTacProcedure;
begin
first_procedure := nil;
@@ -4068,18 +4142,15 @@ begin
return result
end;
(**
* Process the source code and print the generated code.
*)
proc elna_tac_module_declaration(parser_node: ^ElnaTreeModuleDeclaration);
var
data_part: ^ElnaTacStaticVariable;
code_part: Word;
result: ^ElnaInstructionModule;
begin
data_part := elna_tac_var_part(parser_node^.globals);
code_part := elna_tac_procedures(parser_node^.procedures);
result := malloc(#size(ElnaInstructionModule));
result^.data := elna_tac_var_part(parser_node^.globals);
result^.code := elna_tac_procedures(parser_node^.procedures);
return elna_instruction_module_create(data_part, code_part)
return result
end;
proc elna_name_procedure_declaration(parser_node: ^ElnaTreeProcedureDeclaration);