From 1cf71f1a5f5208db3d88c25c45b531096db12496 Mon Sep 17 00:00:00 2001 From: Eugen Wissner Date: Fri, 12 Dec 2025 18:32:01 +0100 Subject: [PATCH] Move procedure call register allocation to RTL --- boot/stage17/cl.elna | 303 ++++++++++++++++++++++++------------------- 1 file changed, 167 insertions(+), 136 deletions(-) diff --git a/boot/stage17/cl.elna b/boot/stage17/cl.elna index 6483c85..b40e2e0 100644 --- a/boot/stage17/cl.elna +++ b/boot/stage17/cl.elna @@ -467,7 +467,7 @@ type allocate_stack, ret ); - ElnaTacOperand = (temporary, immediate, symbol, stack, pseudo); + ElnaTacOperand = (temporary, immediate, symbol, stack, pseudo, list); ElnaRtlOperand = (register, immediate, symbol, offset, pseudo); ElnaRtlRegister = ( zero, @@ -819,45 +819,45 @@ end; proc elna_rtl_load_operand_value(tac_instruction: Word, operand_number: Word, into: Word); var - result1: ^ElnaInstructionList; - operand_value1: Word; - operand_length1: Word; - operand_type1: Word; + result: ^ElnaInstructionList; + operand_value: Word; + operand_length: Word; + operand_type: Word; next_instruction: Word; begin - operand_value1 := _elna_tac_instruction_get_operand_value(tac_instruction, operand_number); - operand_length1 := _elna_tac_instruction_get_operand_length(tac_instruction, operand_number); - operand_type1 := _elna_tac_instruction_get_operand_type(tac_instruction, operand_number); + operand_value := _elna_tac_instruction_get_operand_value(tac_instruction, operand_number); + operand_length := _elna_tac_instruction_get_operand_length(tac_instruction, operand_number); + operand_type := _elna_tac_instruction_get_operand_type(tac_instruction, operand_number); - if operand_type1 = ElnaTacOperand.immediate then - result1 := elna_rtl_instruction_create(ElnaRtlOperator.li); - elna_rtl_instruction_set_operand(result1, 1, ElnaRtlOperand.register, into, 0); - elna_rtl_instruction_set_operand(result1, 2, ElnaRtlOperand.immediate, operand_value1, operand_length1) - elsif operand_type1 = ElnaTacOperand.stack then - result1 := elna_rtl_instruction_create(ElnaRtlOperator.lw); - elna_rtl_instruction_set_operand(result1, 1, ElnaRtlOperand.register, into, 0); - elna_rtl_instruction_set_operand(result1, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, operand_value1) - elsif operand_type1 = ElnaTacOperand.symbol then - result1 := elna_rtl_instruction_create(ElnaRtlOperator.la); - elna_rtl_instruction_set_operand(result1, 1, ElnaRtlOperand.register, into, 0); - elna_rtl_instruction_set_operand(result1, 2, ElnaRtlOperand.symbol, operand_value1, operand_length1); + if operand_type = ElnaTacOperand.immediate then + result := elna_rtl_instruction_create(ElnaRtlOperator.li); + elna_rtl_instruction_set_operand(result, 1, ElnaRtlOperand.register, into, 0); + elna_rtl_instruction_set_operand(result, 2, ElnaRtlOperand.immediate, operand_value, operand_length) + elsif operand_type = ElnaTacOperand.stack then + result := elna_rtl_instruction_create(ElnaRtlOperator.lw); + elna_rtl_instruction_set_operand(result, 1, ElnaRtlOperand.register, into, 0); + elna_rtl_instruction_set_operand(result, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, operand_value) + elsif operand_type = ElnaTacOperand.symbol then + result := elna_rtl_instruction_create(ElnaRtlOperator.la); + elna_rtl_instruction_set_operand(result, 1, ElnaRtlOperand.register, into, 0); + elna_rtl_instruction_set_operand(result, 2, ElnaRtlOperand.symbol, operand_value, operand_length); next_instruction := elna_rtl_instruction_create(ElnaRtlOperator.lw); elna_rtl_instruction_set_operand(next_instruction, 1, ElnaRtlOperand.register, into, 0); elna_rtl_instruction_set_operand(next_instruction, 2, ElnaRtlOperand.offset, into, 0); - result1^.next := next_instruction - elsif operand_type1 = ElnaTacOperand.temporary then - result1 := elna_rtl_instruction_create(ElnaRtlOperator.move); - elna_rtl_instruction_set_operand(result1, 1, ElnaRtlOperand.register, into, 0); - elna_rtl_instruction_set_operand(result1, 2, ElnaRtlOperand.register, operand_value1, 0) - elsif operand_type1 = ElnaTacOperand.pseudo then - result1 := elna_rtl_instruction_create(ElnaRtlOperator.move); - elna_rtl_instruction_set_operand(result1, 1, ElnaRtlOperand.register, into, 0); - elna_rtl_instruction_set_operand(result1, 2, ElnaRtlOperand.pseudo, operand_value1, operand_length1) + result^.next := next_instruction + elsif operand_type = ElnaTacOperand.temporary then + result := elna_rtl_instruction_create(ElnaRtlOperator.move); + elna_rtl_instruction_set_operand(result, 1, ElnaRtlOperand.register, into, 0); + elna_rtl_instruction_set_operand(result, 2, ElnaRtlOperand.register, operand_value, 0) + elsif operand_type = ElnaTacOperand.pseudo then + result := elna_rtl_instruction_create(ElnaRtlOperator.move); + elna_rtl_instruction_set_operand(result, 1, ElnaRtlOperand.register, into, 0); + elna_rtl_instruction_set_operand(result, 2, ElnaRtlOperand.pseudo, operand_value, operand_length) end; - return result1 + return result end; proc elna_rtl_load_operand_address(tac_instruction: Word, operand_number: Word, into: Word); @@ -871,11 +871,7 @@ begin operand_length := _elna_tac_instruction_get_operand_length(tac_instruction, operand_number); operand_type := _elna_tac_instruction_get_operand_type(tac_instruction, operand_number); - if operand_type = ElnaTacOperand.stack then - result := elna_rtl_instruction_create(ElnaRtlOperator.addi); - elna_rtl_instruction_set_operand(result, 1, ElnaRtlOperand.register, into, 0); - elna_rtl_instruction_set_operand(result, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, operand_value) - elsif operand_type = ElnaTacOperand.symbol then + if operand_type = ElnaTacOperand.symbol then result := elna_rtl_instruction_create(ElnaRtlOperator.la); elna_rtl_instruction_set_operand(result, 1, ElnaRtlOperand.register, into, 0); elna_rtl_instruction_set_operand(result, 2, ElnaRtlOperand.symbol, operand_value, operand_length) @@ -996,6 +992,69 @@ begin return result end; +proc elna_rtl_call(tac_instruction: Word, next_instruction: ^^ElnaInstructionList); +var + argument_count: Word; + current_argument: Word; + argument_type: Word; + argument_value: Word; + argument_length: Word; + argument_move: Word; + current_register: Word; + first_instruction: Word; + current_instruction: Word; + name: Word; + name_length: Word; +begin + current_register := 0; + first_instruction := nil; + + current_argument := _elna_tac_instruction_get_operand_value(tac_instruction, 2); + argument_count := _elna_tac_instruction_get_operand_length(tac_instruction, 2); + + name := _elna_tac_instruction_get_operand_value(tac_instruction, 1); + name_length := _elna_tac_instruction_get_operand_length(tac_instruction, 1); + + .elna_rtl_call_loop; + + if argument_count > 0 then + argument_count := argument_count - 1; + + argument_type := current_argument^; + current_argument := current_argument + 4; + argument_value := current_argument^; + current_argument := current_argument + 4; + argument_length := current_argument^; + current_argument := current_argument + 4; + + argument_move := elna_rtl_instruction_create(ElnaRtlOperator.move); + elna_rtl_instruction_set_operand(argument_move, 1, ElnaRtlOperand.register, ElnaRtlRegister.a0 + current_register, 0); + elna_rtl_instruction_set_operand(argument_move, 2, argument_type, argument_value, argument_length); + + if first_instruction = nil then + first_instruction := argument_move + else + elna_instruction_list_concatenate(current_instruction, argument_move) + end; + current_instruction := argument_move; + + current_register := current_register + 1; + + goto elna_rtl_call_loop + end; + argument_move := elna_rtl_instruction_create(ElnaRtlOperator.jal); + elna_rtl_copy_operand(tac_instruction, 1, argument_move); + + if first_instruction = nil then + first_instruction := argument_move + else + elna_instruction_list_concatenate(current_instruction, argument_move) + end; + next_instruction^ := argument_move; + + return first_instruction +end; + proc elna_rtl_instruction(tac_instruction: Word, next_instruction: ^^ElnaInstructionList); var result: ^ElnaInstructionList; @@ -1042,18 +1101,7 @@ begin elsif instruction_kind = ElnaTacOperator.load then operand_type := _elna_tac_instruction_get_operand_type(tac_instruction, 2); - if operand_type = ElnaTacOperand.stack then - result := elna_rtl_instruction_create(ElnaRtlOperator.lw); - - operand_value := _elna_tac_instruction_get_operand_value(tac_instruction, 1); - next_instruction^ := elna_rtl_instruction_create(ElnaRtlOperator.lw); - elna_rtl_instruction_set_operand(next_instruction^, 1, ElnaRtlOperand.register, operand_value, 0); - elna_rtl_instruction_set_operand(next_instruction^, 2, ElnaRtlOperand.offset, operand_value, 0); - - operand_value := _elna_tac_instruction_get_operand_value(tac_instruction, 2); - elna_rtl_instruction_set_operand(result, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, operand_value); - result^.next := next_instruction^ - elsif operand_type = ElnaTacOperand.temporary then + if operand_type = ElnaTacOperand.temporary then result := elna_rtl_instruction_create(ElnaRtlOperator.lw); elna_rtl_copy_operand(tac_instruction, 1, result); @@ -1080,8 +1128,6 @@ begin operand_length := _elna_tac_instruction_get_operand_length(tac_instruction, 2); if operand_type = ElnaTacOperand.stack then elna_rtl_instruction_set_operand(next_instruction^, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, operand_value) - elsif operand_type = ElnaTacOperand.temporary then - elna_rtl_instruction_set_operand(next_instruction^, 2, ElnaRtlOperand.offset, operand_value, 0) elsif operand_type = ElnaTacOperand.pseudo then elna_rtl_instruction_set_operand(next_instruction^, 2, ElnaRtlOperand.pseudo, operand_value, operand_length) end; @@ -1091,8 +1137,7 @@ begin operands^.next := next_instruction^ end elsif instruction_kind = ElnaTacOperator.proc_call then - result := elna_rtl_instruction_create(ElnaRtlOperator.jal); - elna_rtl_copy_operand(tac_instruction, 1, result) + result := elna_rtl_call(tac_instruction, next_instruction) elsif instruction_kind = ElnaTacOperator.subtract then result := elna_rtl_binary_arithmetic(tac_instruction, next_instruction, ElnaRtlOperator.sub) elsif instruction_kind = ElnaTacOperator.multiply then @@ -1189,20 +1234,6 @@ begin if operand_type = ElnaTacOperand.temporary then result := elna_rtl_load_operand_value(tac_instruction, 2, operand_value); next_instruction^ := result^.next - elsif operand_type = ElnaTacOperand.stack then - operands := elna_rtl_load_operand_value(tac_instruction, 2, ElnaRtlRegister.t4); - result := operands; - operands := result^.next; - - next_instruction^ := elna_rtl_instruction_create(ElnaRtlOperator.sw); - _elna_tac_instruction_set_operand(next_instruction^, 1, ElnaRtlOperand.register, ElnaRtlRegister.t4, 0); - _elna_tac_instruction_set_operand(next_instruction^, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, operand_value); - - if operands = nil then - result^.next := next_instruction^ - else - operands^.next := next_instruction^ - end elsif operand_type = ElnaTacOperand.pseudo then operands := elna_rtl_load_operand_value(tac_instruction, 2, ElnaRtlRegister.t4); result := operands; @@ -1378,13 +1409,14 @@ begin return pseudo_symbol1 end; -proc elna_alloc_instruction(instruction: Word); +proc elna_alloc_instruction(instruction: ^ElnaInstructionList); var instruction_kind: Word; operand_type: Word; operand_value: Word; operand_length: Word; - pseudo_symbol1: Word; + pseudo_symbol: Word; + old_instruction: ^ElnaInstructionList; begin instruction_kind := elna_rtl_instruction_get_kind(instruction); @@ -1394,7 +1426,7 @@ begin operand_length := elna_rtl_instruction_get_operand_length(instruction, 1); if operand_type = ElnaRtlOperand.pseudo then - pseudo_symbol1 := elna_alloc_variable(operand_value, operand_length); + pseudo_symbol := elna_alloc_variable(operand_value, operand_length); elna_rtl_instruction_set_kind(instruction, ElnaRtlOperator.sw); operand_type := elna_rtl_instruction_get_operand_type(instruction, 2); @@ -1402,7 +1434,7 @@ begin operand_length := elna_rtl_instruction_get_operand_length(instruction, 2); elna_rtl_instruction_set_operand(instruction, 1, operand_type, operand_value, operand_length); - elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, pseudo_symbol1); + elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, pseudo_symbol); goto elna_alloc_instruction_end end; @@ -1412,9 +1444,9 @@ begin operand_length := elna_rtl_instruction_get_operand_length(instruction, 2); if operand_type = ElnaRtlOperand.pseudo then - pseudo_symbol1 := elna_alloc_variable(operand_value, operand_length); + pseudo_symbol := elna_alloc_variable(operand_value, operand_length); elna_rtl_instruction_set_kind(instruction, ElnaRtlOperator.lw); - elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, pseudo_symbol1); + elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, pseudo_symbol); goto elna_alloc_instruction_end end @@ -1424,15 +1456,31 @@ begin operand_length := elna_rtl_instruction_get_operand_length(instruction, 2); if operand_type = ElnaRtlOperand.pseudo then - (* Debug. Error stream output. - printf("# %i %.*s\n\0", operand_length, operand_length, operand_value); - fflush(nil); *) - - pseudo_symbol1 := elna_alloc_variable(operand_value, operand_length); + pseudo_symbol := elna_alloc_variable(operand_value, operand_length); elna_rtl_instruction_set_kind(instruction, ElnaRtlOperator.addi); elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlOperand.register, ElnaRtlRegister.sp, 0); - elna_rtl_instruction_set_operand(instruction, 3, ElnaRtlOperand.immediate, pseudo_symbol1, 0); + elna_rtl_instruction_set_operand(instruction, 3, ElnaRtlOperand.immediate, pseudo_symbol, 0); + + goto elna_alloc_instruction_end + end + elsif instruction_kind = ElnaRtlOperator.sw then + operand_type := elna_rtl_instruction_get_operand_type(instruction, 2); + operand_value := elna_rtl_instruction_get_operand_value(instruction, 2); + operand_length := elna_rtl_instruction_get_operand_length(instruction, 2); + + if operand_type = ElnaRtlOperand.pseudo then + old_instruction := malloc(elna_rtl_instruction_size()); + memcpy(old_instruction, instruction, elna_rtl_instruction_size()); + + pseudo_symbol := elna_alloc_variable(operand_value, operand_length); + elna_rtl_instruction_set_kind(instruction, ElnaRtlOperator.lw); + + elna_rtl_instruction_set_operand(instruction, 1, ElnaRtlOperand.register, ElnaRtlRegister.t2, 0); + elna_rtl_instruction_set_operand(instruction, 2, ElnaRtlOperand.offset, ElnaRtlRegister.sp, pseudo_symbol); + + instruction^.next := old_instruction; + elna_rtl_instruction_set_operand(old_instruction, 2, ElnaRtlOperand.offset, ElnaRtlRegister.t2, 0); goto elna_alloc_instruction_end end @@ -1541,7 +1589,7 @@ var stack_instruction: ^ElnaInstructionList; begin .elna_alloc_procedure_loop; - temporary_variable_counter := 60; + temporary_variable_counter := 32; variable_map := 0; elna_alloc_instructions(rtl_declaration^.body); @@ -2148,17 +2196,8 @@ begin lhs_value := 0; lhs_length := 0; instruction := _elna_tac_unary_expression(parser_node^.rhs, symbol_table, @lhs_type, @lhs_value, @lhs_length); - current_instruction := elna_instruction_list_concatenate(current_instruction, instruction); - (* Load the left expression from the stack; *) - instruction := _elna_tac_instruction_create(ElnaTacOperator.copy); - _elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.temporary, 7, 0); - _elna_tac_instruction_set_operand(instruction, 2, ElnaTacOperand.pseudo, "$lhs", 4); - - elna_instruction_list_concatenate(current_instruction, instruction); - current_instruction := instruction; - if parser_node^.operator = ElnaLexerKind.plus then instruction := _elna_tac_instruction_create(ElnaTacOperator.add) elsif parser_node^.operator = ElnaLexerKind.minus then @@ -2277,10 +2316,9 @@ end; proc _elna_tac_call(parsed_call: Word, symbol_table: Word); var - argument_count1: Word; + argument_count: Word; name_length: Word; name: Word; - stack_offset: Word; parsed_expression: ^ElnaTreeVariableExpression; instruction: Word; first_instruction: Word; @@ -2288,16 +2326,33 @@ var operand_type: Word; operand_value: Word; operand_length: Word; + arguments_operand: Word; + call_instruction: Word; + name_buffer: Word; begin parsed_expression := _call_get_name(parsed_call); name := parsed_expression^.name; name_length := parsed_expression^.length; - argument_count1 := 0; + argument_count := 0; first_instruction := 0; + .elna_tac_call_count; + parsed_expression := _call_get_argument(parsed_call, argument_count + 1); + + if parsed_expression <> nil ten + argument_count := argument_count + 1; + goto elna_tac_call_count + end; + arguments_operand := malloc(argument_count * 12); + + call_instruction := _elna_tac_instruction_create(ElnaTacOperator.proc_call); + _elna_tac_instruction_set_operand(call_instruction, 1, ElnaTacOperand.symbol, name, name_length); + _elna_tac_instruction_set_operand(call_instruction, 2, ElnaTacOperand.list, arguments_operand, argument_count); + + argument_count := 0; .elna_tac_call_loop; - parsed_expression := _call_get_argument(parsed_call, argument_count1 + 1); + parsed_expression := _call_get_argument(parsed_call, argument_count + 1); if parsed_expression = 0 then goto elna_tac_call_finalize else @@ -2315,11 +2370,11 @@ begin end; (* Save the argument on the stack. *) - stack_offset := argument_count1 * 4; - - instruction := _elna_tac_instruction_create(ElnaTacOperator.store); - _elna_tac_instruction_set_operand(instruction, 1, operand_type, operand_value, operand_length); - _elna_tac_instruction_set_operand(instruction, 2, ElnaTacOperand.stack, 56 - stack_offset, 0); + name_buffer := malloc(4); + sprintf(name_buffer, "$ar%i\0", argument_count); + instruction := _elna_tac_instruction_create(ElnaTacOperator.copy); + _elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.pseudo, name_buffer, 4); + _elna_tac_instruction_set_operand(instruction, 2, operand_type, operand_value, operand_length); if first_instruction = 0 then first_instruction := instruction else @@ -2327,32 +2382,22 @@ begin end; current_instruction := instruction; - argument_count1 := argument_count1 + 1; + arguments_operand^ := ElnaTacOperand.pseudo; + arguments_operand := arguments_operand + 4; + arguments_operand^ := name_buffer; + arguments_operand := arguments_operand + 4; + arguments_operand^ := 4; + arguments_operand := arguments_operand + 4; + + argument_count := argument_count + 1; goto elna_tac_call_loop end; .elna_tac_call_finalize; - (* Load the argument from the stack. *) - if argument_count1 <> 0 then - (* Decrement the argument counter. *) - argument_count1 := argument_count1 - 1; - stack_offset := argument_count1 * 4; - - (* Calculate the stack offset: 56 - (4 * argument_counter) *) - instruction := _elna_tac_instruction_create(ElnaTacOperator.copy); - _elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.temporary, 11 + argument_count1, 0); - _elna_tac_instruction_set_operand(instruction, 2, ElnaTacOperand.stack, 56 - stack_offset, 0); - elna_instruction_list_concatenate(current_instruction, instruction); - current_instruction := instruction; - - goto elna_tac_call_finalize - end; - instruction := _elna_tac_instruction_create(ElnaTacOperator.proc_call); - _elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.symbol, name, name_length); - if first_instruction = 0 then - first_instruction := instruction + if first_instruction = nil then + first_instruction := call_instruction else - elna_instruction_list_concatenate(current_instruction, instruction) + elna_instruction_list_concatenate(current_instruction, call_instruction) end; return first_instruction end; @@ -2551,15 +2596,9 @@ begin elsif parser_node^.kind = ElnaTreeKind.call then first_instruction := _elna_tac_call(parser_node, symbol_table); - last_instruction := _elna_tac_instruction_create(ElnaTacOperator.copy); - _elna_tac_instruction_set_operand(last_instruction, 1, ElnaTacOperand.temporary, 6, 0); - _elna_tac_instruction_set_operand(last_instruction, 2, ElnaTacOperand.temporary, 11, 0); - operand_type^ := ElnaTacOperand.temporary; - operand_value^ := 6; + operand_value^ := 11; operand_length^ := 0; - - elna_instruction_list_concatenate(first_instruction, last_instruction); is_address^ := 0 else first_instruction := _elna_tac_simple_expression(parser_node, symbol_table, operand_type, operand_value, operand_length); @@ -2621,11 +2660,10 @@ begin first_instruction := elna_instruction_list_concatenate(first_instruction, current_instruction); (* Save the assignee address on the stack. *) - current_instruction := _elna_tac_instruction_create(ElnaTacOperator.store); - _elna_tac_instruction_set_operand(current_instruction, 1, ElnaTacOperand.temporary, 6, 0); - _elna_tac_instruction_set_operand(current_instruction, 2, ElnaTacOperand.stack, 0, 0); + current_instruction := _elna_tac_instruction_create(ElnaTacOperator.copy); + _elna_tac_instruction_set_operand(current_instruction, 1, ElnaTacOperand.pseudo, "$assign", 7); + _elna_tac_instruction_set_operand(current_instruction, 2, ElnaTacOperand.temporary, 6, 0); elna_instruction_list_concatenate(first_instruction, current_instruction); - (* Compile the assignment. *) operand_type := 0; operand_value := 0; @@ -2637,16 +2675,9 @@ begin current_instruction := instruction end; - instruction := _elna_tac_instruction_create(ElnaTacOperator.copy); - _elna_tac_instruction_set_operand(instruction, 1, ElnaTacOperand.temporary, 7, 0); - _elna_tac_instruction_set_operand(instruction, 2, ElnaTacOperand.stack, 0, 0); - - elna_instruction_list_concatenate(current_instruction, instruction); - current_instruction := instruction; - instruction := _elna_tac_instruction_create(ElnaTacOperator.store); _elna_tac_instruction_set_operand(instruction, 1, operand_type, operand_value, operand_length); - _elna_tac_instruction_set_operand(instruction, 2, ElnaTacOperand.temporary, 7, 0); + _elna_tac_instruction_set_operand(instruction, 2, ElnaTacOperand.pseudo, "$assign", 7); elna_instruction_list_concatenate(current_instruction, instruction); end;