From 8142680fb7d8e91061a8aa6bf25150c0a890d865 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Tue, 17 Feb 2026 19:14:49 +0100 Subject: [PATCH] Allow compound types on the stack --- boot/stage19/cl.elna | 251 +++++++++++++++++++++++++++---------------- 1 file changed, 161 insertions(+), 90 deletions(-) diff --git a/boot/stage19/cl.elna b/boot/stage19/cl.elna index 881bf88..2fd12a0 100644 --- a/boot/stage19/cl.elna +++ b/boot/stage19/cl.elna @@ -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);