Generate pseudo variables where possible

This commit is contained in:
2026-01-25 21:22:46 +01:00
parent f0f0f431ba
commit 01e55f30f6

View File

@@ -563,6 +563,7 @@ var
label_counter: Word; label_counter: Word;
symbol_table_store: Word; symbol_table_store: Word;
temporary_variable_counter: Word; temporary_variable_counter: Word;
pseudo_counter: Word;
(** (**
* Calculates and returns the string token length between quotes, including the * Calculates and returns the string token length between quotes, including the
@@ -694,6 +695,26 @@ proc _is_alnum(character: Word);
return _is_alpha(character) or isdigit(character) return _is_alpha(character) or isdigit(character)
end; end;
proc elna_tac_generate_pseudo(operand_type: Word, operand_value: Word, operand_length: Word);
var
buffer: Word;
begin
(* TODO: 100 pseudo registers should be enough to save temporary state,
but this should not be the final solution. *)
if pseudo_counter > 100 then
pseudo_counter := 1
else
pseudo_counter := pseudo_counter + 1
end;
buffer := malloc(6);
sprintf(buffer, "$%i\0", pseudo_counter);
operand_type^ := ElnaTacKind.pseudo;
operand_value^ := buffer;
operand_length^ := strlen(buffer);
end;
proc elna_instruction_list_concatenate(this: ^ElnaInstructionList, value: Word); proc elna_instruction_list_concatenate(this: ^ElnaInstructionList, value: Word);
var var
start: Word; start: Word;
@@ -1858,20 +1879,18 @@ var
begin begin
offset := _add_string(string_literal_node^.value); offset := _add_string(string_literal_node^.value);
elna_tac_generate_pseudo(operand_type, operand_value, operand_length);
first_instruction := elna_tac_instruction_create(ElnaTacOperator.get_address); first_instruction := elna_tac_instruction_create(ElnaTacOperator.get_address);
elna_tac_instruction_set_operand(first_instruction, 1, ElnaTacKind.pseudo, "$unary", 6); elna_tac_instruction_set_operand(first_instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(first_instruction, 2, ElnaTacKind.symbol, "strings", 7); elna_tac_instruction_set_operand(first_instruction, 2, ElnaTacKind.symbol, "strings", 7);
(* Add offset to the string block pointer. *) (* Add offset to the string block pointer. *)
next_instruction := elna_tac_instruction_create(ElnaTacOperator.add); next_instruction := elna_tac_instruction_create(ElnaTacOperator.add);
elna_tac_instruction_set_operand(next_instruction, 1, ElnaTacKind.pseudo, "$unary", 6); elna_tac_instruction_set_operand(next_instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(next_instruction, 2, ElnaTacKind.pseudo, "$unary", 6); elna_tac_instruction_set_operand(next_instruction, 2, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(next_instruction, 3, ElnaTacKind.immediate, offset, 0); elna_tac_instruction_set_operand(next_instruction, 3, ElnaTacKind.immediate, offset, 0);
operand_type^ := ElnaTacKind.pseudo;
operand_value^ := "$unary";
operand_length^ := 6;
return elna_instruction_list_concatenate(first_instruction, next_instruction) return elna_instruction_list_concatenate(first_instruction, next_instruction)
end; end;
@@ -2047,6 +2066,9 @@ var
is_address: Word; is_address: Word;
first_instruction: Word; first_instruction: Word;
instruction: Word; instruction: Word;
base_type: Word;
base_value: Word;
base_length: Word;
begin begin
instruction := nil; instruction := nil;
if parser_node^.kind = ElnaTreeKind.unary_expression then if parser_node^.kind = ElnaTreeKind.unary_expression then
@@ -2056,39 +2078,37 @@ begin
operator := 0; operator := 0;
operand := parser_node operand := parser_node
end; end;
first_instruction := elna_tac_designator(operand, symbol_table, @is_address, operand_type, operand_value, operand_length); first_instruction := elna_tac_designator(operand, symbol_table, @is_address, @base_type, @base_value, @base_length);
elna_tac_generate_pseudo(operand_type, operand_value, operand_length);
if operator = '@' then if operator = '@' then
if is_address then if is_address then
instruction := elna_tac_instruction_create(ElnaTacOperator.copy); instruction := elna_tac_instruction_create(ElnaTacOperator.copy);
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$unary", 6); elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^) elna_tac_instruction_set_operand(instruction, 2, base_type, base_value, base_length)
else else
instruction := elna_tac_instruction_create(ElnaTacOperator.get_address); instruction := elna_tac_instruction_create(ElnaTacOperator.get_address);
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$unary", 6); elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^) elna_tac_instruction_set_operand(instruction, 2, base_type, base_value, base_length)
end end
elsif operator = '-' then elsif operator = '-' then
instruction := elna_tac_instruction_create(ElnaTacOperator.negate); instruction := elna_tac_instruction_create(ElnaTacOperator.negate);
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$unary", 6); elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^) elna_tac_instruction_set_operand(instruction, 2, base_type, base_value, base_length)
elsif operator = '~' then elsif operator = '~' then
instruction := elna_tac_instruction_create(ElnaTacOperator.complement); instruction := elna_tac_instruction_create(ElnaTacOperator.complement);
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$unary", 6); elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^) elna_tac_instruction_set_operand(instruction, 2, base_type, base_value, base_length)
elsif is_address then elsif is_address then
instruction := elna_tac_instruction_create(ElnaTacOperator.load); instruction := elna_tac_instruction_create(ElnaTacOperator.load);
elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^); elna_tac_instruction_set_operand(instruction, 1, base_type, base_value, base_length);
elna_tac_instruction_set_operand(instruction, 2, ElnaTacKind.pseudo, "$unary", 6) elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^)
else else
instruction := elna_tac_instruction_create(ElnaTacOperator.copy); instruction := elna_tac_instruction_create(ElnaTacOperator.copy);
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$unary", 6); elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^) elna_tac_instruction_set_operand(instruction, 2, base_type, base_value, base_length)
end; end;
operand_type^ := ElnaTacKind.pseudo;
operand_value^ := "$unary";
operand_length^ := 6;
return elna_instruction_list_concatenate(first_instruction, instruction) return elna_instruction_list_concatenate(first_instruction, instruction)
end; end;
@@ -2168,13 +2188,13 @@ var
lhs_type: Word; lhs_type: Word;
lhs_value: Word; lhs_value: Word;
lhs_length: Word; lhs_length: Word;
rhs_type: Word;
rhs_value: Word;
rhs_length: Word;
begin begin
if parser_node^.kind <> ElnaTreeKind.binary_expression then if parser_node^.kind <> ElnaTreeKind.binary_expression then
first_instruction := elna_tac_unary_expression(parser_node, symbol_table, operand_type, operand_value, operand_length) first_instruction := elna_tac_unary_expression(parser_node, symbol_table, operand_type, operand_value, operand_length)
else else
lhs_type := 0;
lhs_value := 0;
lhs_length := 0;
first_instruction := elna_tac_unary_expression(parser_node^.lhs, symbol_table, @lhs_type, @lhs_value, @lhs_length); first_instruction := elna_tac_unary_expression(parser_node^.lhs, symbol_table, @lhs_type, @lhs_value, @lhs_length);
(* Save the value of the left expression on the stack. *) (* Save the value of the left expression on the stack. *)
@@ -2182,17 +2202,18 @@ begin
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$lhs", 4); elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$lhs", 4);
elna_tac_instruction_set_operand(instruction, 2, lhs_type, lhs_value, lhs_length); elna_tac_instruction_set_operand(instruction, 2, lhs_type, lhs_value, lhs_length);
if first_instruction = 0 then lhs_type := ElnaTacKind.pseudo;
lhs_value := "$lhs";
lhs_length := 4;
if first_instruction = nil then
first_instruction := instruction first_instruction := instruction
else else
elna_instruction_list_concatenate(first_instruction, instruction) elna_instruction_list_concatenate(first_instruction, instruction)
end; end;
current_instruction := instruction; current_instruction := instruction;
lhs_type := 0; instruction := elna_tac_unary_expression(parser_node^.rhs, symbol_table, @rhs_type, @rhs_value, @rhs_length);
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); current_instruction := elna_instruction_list_concatenate(current_instruction, instruction);
if parser_node^.operator = ElnaLexerKind.plus then if parser_node^.operator = ElnaLexerKind.plus then
@@ -2224,13 +2245,11 @@ begin
elsif parser_node^.operator = ElnaLexerKind.not_equal then elsif parser_node^.operator = ElnaLexerKind.not_equal then
instruction := elna_tac_instruction_create(ElnaTacOperator.not_equal) instruction := elna_tac_instruction_create(ElnaTacOperator.not_equal)
end; end;
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$binary", 7); elna_tac_generate_pseudo(operand_type, operand_value, operand_length);
elna_tac_instruction_set_operand(instruction, 2, ElnaTacKind.pseudo, "$lhs", 4);
elna_tac_instruction_set_operand(instruction, 3, lhs_type, lhs_value, lhs_length);
operand_type^ := ElnaTacKind.pseudo; elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
operand_value^ := "$binary"; elna_tac_instruction_set_operand(instruction, 2, lhs_type, lhs_value, lhs_length);
operand_length^ := 7; elna_tac_instruction_set_operand(instruction, 3, rhs_type, rhs_value, rhs_length);
elna_instruction_list_concatenate(current_instruction, instruction) elna_instruction_list_concatenate(current_instruction, instruction)
end; end;
@@ -2299,30 +2318,22 @@ var
arguments_operand: ^ElnaTacOperand; arguments_operand: ^ElnaTacOperand;
call_instruction: Word; call_instruction: Word;
argument_entry: ^ElnaTreeExpressionList; argument_entry: ^ElnaTreeExpressionList;
name_buffer: Word;
argument_count: Word;
begin begin
parsed_expression := parsed_call^.callee; parsed_expression := parsed_call^.callee;
first_instruction := nil; first_instruction := nil;
arguments_operand := malloc(parsed_call^.count * #size(ElnaTacOperand)); arguments_operand := malloc(parsed_call^.count * #size(ElnaTacOperand));
elna_tac_generate_pseudo(operand_type, operand_value, operand_length);
call_instruction := elna_tac_instruction_create(ElnaTacOperator.proc_call); call_instruction := elna_tac_instruction_create(ElnaTacOperator.proc_call);
elna_tac_instruction_set_operand(call_instruction, 1, ElnaTacKind.symbol, parsed_expression^.name, parsed_expression^.length); elna_tac_instruction_set_operand(call_instruction, 1, ElnaTacKind.symbol, parsed_expression^.name, parsed_expression^.length);
elna_tac_instruction_set_operand(call_instruction, 2, ElnaTacKind.list, arguments_operand, parsed_call^.count); elna_tac_instruction_set_operand(call_instruction, 2, ElnaTacKind.list, arguments_operand, parsed_call^.count);
elna_tac_instruction_set_operand(call_instruction, 3, ElnaTacKind.pseudo, "$unary", 6); elna_tac_instruction_set_operand(call_instruction, 3, operand_type^, operand_value^, operand_length^);
operand_type^ := ElnaTacKind.pseudo;
operand_value^ := "$unary";
operand_length^ := 6;
argument_count := 0;
argument_entry := parsed_call^.arguments; argument_entry := parsed_call^.arguments;
.elna_tac_call_loop; .elna_tac_call_loop;
if argument_entry <> nil then if argument_entry <> nil then
argument_type := 0;
argument_value := 0;
argument_length := 0;
instruction := elna_tac_binary_expression(argument_entry^.expression, symbol_table, instruction := elna_tac_binary_expression(argument_entry^.expression, symbol_table,
@argument_type, @argument_value, @argument_length); @argument_type, @argument_value, @argument_length);
if first_instruction = nil then if first_instruction = nil then
@@ -2333,27 +2344,12 @@ begin
if instruction <> nil then if instruction <> nil then
current_instruction := instruction current_instruction := instruction
end; end;
arguments_operand^.kind := argument_type;
(* Save the argument on the stack. *) arguments_operand^.value := argument_value;
name_buffer := malloc(4); arguments_operand^.length := argument_length;
sprintf(name_buffer, "$ar%i\0", argument_count);
instruction := elna_tac_instruction_create(ElnaTacOperator.copy);
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, name_buffer, 4);
elna_tac_instruction_set_operand(instruction, 2, argument_type, argument_value, argument_length);
if first_instruction = 0 then
first_instruction := instruction
else
elna_instruction_list_concatenate(current_instruction, instruction)
end;
current_instruction := instruction;
arguments_operand^.kind := ElnaTacKind.pseudo;
arguments_operand^.value := name_buffer;
arguments_operand^.length := 4;
arguments_operand := arguments_operand + #size(ElnaTacOperand); arguments_operand := arguments_operand + #size(ElnaTacOperand);
argument_entry := argument_entry^.next; argument_entry := argument_entry^.next;
argument_count := argument_count + 1;
goto elna_tac_call_loop goto elna_tac_call_loop
end; end;
if first_instruction = nil then if first_instruction = nil then
@@ -2573,11 +2569,14 @@ var
current_field: ^ElnaTypeField; current_field: ^ElnaTypeField;
field_offset: Word; field_offset: Word;
is_address: Word; is_address: Word;
base_type: Word;
base_value: Word;
base_length: Word;
begin begin
designator_base := field_access_expression^.aggregate; designator_base := field_access_expression^.aggregate;
aggregate_type := designator_base^.type_decoration; aggregate_type := designator_base^.type_decoration;
first_instruction := elna_tac_designator(designator_base, symbol_table, @is_address, operand_type, operand_value, operand_length); first_instruction := elna_tac_designator(designator_base, symbol_table, @is_address, @base_type, @base_value, @base_length);
field_count := aggregate_type^.length; field_count := aggregate_type^.length;
current_field := aggregate_type^.members; current_field := aggregate_type^.members;
@@ -2592,14 +2591,12 @@ begin
field_offset := field_offset + field_type^.size; field_offset := field_offset + field_type^.size;
goto elna_tac_field_access_expression_field goto elna_tac_field_access_expression_field
end; end;
last_instruction := elna_tac_instruction_create(ElnaTacOperator.add); elna_tac_generate_pseudo(operand_type, operand_value, operand_length);
elna_tac_instruction_set_operand(last_instruction, 1, ElnaTacKind.pseudo, "$unary", 6);
elna_tac_instruction_set_operand(last_instruction, 2, ElnaTacKind.immediate, field_offset, 0);
elna_tac_instruction_set_operand(last_instruction, 3, operand_type^, operand_value^, operand_length^);
operand_type^ := ElnaTacKind.pseudo; last_instruction := elna_tac_instruction_create(ElnaTacOperator.add);
operand_value^ := "$unary"; elna_tac_instruction_set_operand(last_instruction, 1, operand_type^, operand_value^, operand_length^);
operand_length^ := 6; elna_tac_instruction_set_operand(last_instruction, 2, ElnaTacKind.immediate, field_offset, 0);
elna_tac_instruction_set_operand(last_instruction, 3, base_type, base_value, base_length);
return elna_instruction_list_concatenate(first_instruction, last_instruction) return elna_instruction_list_concatenate(first_instruction, last_instruction)
end; end;
@@ -2611,9 +2608,9 @@ var
offset_instruction: Word; offset_instruction: Word;
add_instruction: Word; add_instruction: Word;
is_address: Word; is_address: Word;
offset_type: Word; inter_type: Word;
offset_value: Word; inter_value: Word;
offset_length: Word; inter_length: Word;
aggregate_type: ^ElnaTypeArray; aggregate_type: ^ElnaTypeArray;
designator_base: ^ElnaTreeExpression; designator_base: ^ElnaTreeExpression;
element_type: ^ElnaType; element_type: ^ElnaType;
@@ -2622,27 +2619,28 @@ begin
aggregate_type := designator_base^.type_decoration; aggregate_type := designator_base^.type_decoration;
element_type := aggregate_type^.base; element_type := aggregate_type^.base;
index_instructions := elna_tac_binary_expression(array_access_expression^.index, symbol_table, operand_type, operand_value, operand_length); index_instructions := elna_tac_binary_expression(array_access_expression^.index, symbol_table, @inter_type, @inter_value, @inter_length);
elna_tac_generate_pseudo(operand_type, operand_value, operand_length);
add_instruction := elna_tac_instruction_create(ElnaTacOperator.subtract); add_instruction := elna_tac_instruction_create(ElnaTacOperator.subtract);
elna_tac_instruction_set_operand(add_instruction, 1, ElnaTacKind.pseudo, "$lhs", 4); elna_tac_instruction_set_operand(add_instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(add_instruction, 2, operand_type^, operand_value^, operand_length^); elna_tac_instruction_set_operand(add_instruction, 2, inter_type, inter_value, inter_length);
elna_tac_instruction_set_operand(add_instruction, 3, ElnaTacKind.immediate, 1, 0); elna_tac_instruction_set_operand(add_instruction, 3, ElnaTacKind.immediate, 1, 0);
offset_instruction := elna_tac_instruction_create(ElnaTacOperator.multiply); offset_instruction := elna_tac_instruction_create(ElnaTacOperator.multiply);
elna_tac_instruction_set_operand(offset_instruction, 1, ElnaTacKind.pseudo, "$lhs", 4); elna_tac_instruction_set_operand(offset_instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(offset_instruction, 2, ElnaTacKind.pseudo, "$lhs", 4); elna_tac_instruction_set_operand(offset_instruction, 2, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(offset_instruction, 3, ElnaTacKind.immediate, element_type^.size, 0); elna_tac_instruction_set_operand(offset_instruction, 3, ElnaTacKind.immediate, element_type^.size, 0);
elna_instruction_list_concatenate(add_instruction, offset_instruction); elna_instruction_list_concatenate(add_instruction, offset_instruction);
index_instructions := elna_instruction_list_concatenate(index_instructions, add_instruction); index_instructions := elna_instruction_list_concatenate(index_instructions, add_instruction);
array_instructions := elna_tac_designator(array_access_expression^.array, symbol_table, @is_address, operand_type, operand_value, operand_length); array_instructions := elna_tac_designator(array_access_expression^.array, symbol_table, @is_address, @inter_type, @inter_value, @inter_length);
add_instruction := elna_tac_instruction_create(ElnaTacOperator.add); add_instruction := elna_tac_instruction_create(ElnaTacOperator.add);
elna_tac_instruction_set_operand(add_instruction, 1, operand_type^, operand_value^, operand_length^); elna_tac_instruction_set_operand(add_instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(add_instruction, 2, operand_type^, operand_value^, operand_length^); elna_tac_instruction_set_operand(add_instruction, 2, inter_type, inter_value, inter_length);
elna_tac_instruction_set_operand(add_instruction, 3, ElnaTacKind.pseudo, "$lhs", 4); elna_tac_instruction_set_operand(add_instruction, 3, operand_type^, operand_value^, operand_length^);
elna_instruction_list_concatenate(offset_instruction, array_instructions); elna_instruction_list_concatenate(offset_instruction, array_instructions);