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;
symbol_table_store: Word;
temporary_variable_counter: Word;
pseudo_counter: Word;
(**
* 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)
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);
var
start: Word;
@@ -1858,20 +1879,18 @@ var
begin
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);
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);
(* Add offset to the string block pointer. *)
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, 2, 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, operand_type^, operand_value^, operand_length^);
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)
end;
@@ -2047,6 +2066,9 @@ var
is_address: Word;
first_instruction: Word;
instruction: Word;
base_type: Word;
base_value: Word;
base_length: Word;
begin
instruction := nil;
if parser_node^.kind = ElnaTreeKind.unary_expression then
@@ -2056,39 +2078,37 @@ begin
operator := 0;
operand := parser_node
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 is_address then
instruction := elna_tac_instruction_create(ElnaTacOperator.copy);
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$unary", 6);
elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^)
elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, base_type, base_value, base_length)
else
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, 2, operand_type^, operand_value^, operand_length^)
elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, base_type, base_value, base_length)
end
elsif operator = '-' then
instruction := elna_tac_instruction_create(ElnaTacOperator.negate);
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$unary", 6);
elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^)
elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, base_type, base_value, base_length)
elsif operator = '~' then
instruction := elna_tac_instruction_create(ElnaTacOperator.complement);
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$unary", 6);
elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^)
elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, base_type, base_value, base_length)
elsif is_address then
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, 2, ElnaTacKind.pseudo, "$unary", 6)
elna_tac_instruction_set_operand(instruction, 1, base_type, base_value, base_length);
elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^)
else
instruction := elna_tac_instruction_create(ElnaTacOperator.copy);
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$unary", 6);
elna_tac_instruction_set_operand(instruction, 2, operand_type^, operand_value^, operand_length^)
elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, base_type, base_value, base_length)
end;
operand_type^ := ElnaTacKind.pseudo;
operand_value^ := "$unary";
operand_length^ := 6;
return elna_instruction_list_concatenate(first_instruction, instruction)
end;
@@ -2168,13 +2188,13 @@ var
lhs_type: Word;
lhs_value: Word;
lhs_length: Word;
rhs_type: Word;
rhs_value: Word;
rhs_length: Word;
begin
if parser_node^.kind <> ElnaTreeKind.binary_expression then
first_instruction := elna_tac_unary_expression(parser_node, symbol_table, operand_type, operand_value, operand_length)
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);
(* 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, 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
else
elna_instruction_list_concatenate(first_instruction, instruction)
end;
current_instruction := instruction;
lhs_type := 0;
lhs_value := 0;
lhs_length := 0;
instruction := elna_tac_unary_expression(parser_node^.rhs, symbol_table, @lhs_type, @lhs_value, @lhs_length);
instruction := elna_tac_unary_expression(parser_node^.rhs, symbol_table, @rhs_type, @rhs_value, @rhs_length);
current_instruction := elna_instruction_list_concatenate(current_instruction, instruction);
if parser_node^.operator = ElnaLexerKind.plus then
@@ -2224,13 +2245,11 @@ begin
elsif parser_node^.operator = ElnaLexerKind.not_equal then
instruction := elna_tac_instruction_create(ElnaTacOperator.not_equal)
end;
elna_tac_instruction_set_operand(instruction, 1, ElnaTacKind.pseudo, "$binary", 7);
elna_tac_instruction_set_operand(instruction, 2, ElnaTacKind.pseudo, "$lhs", 4);
elna_tac_instruction_set_operand(instruction, 3, lhs_type, lhs_value, lhs_length);
elna_tac_generate_pseudo(operand_type, operand_value, operand_length);
operand_type^ := ElnaTacKind.pseudo;
operand_value^ := "$binary";
operand_length^ := 7;
elna_tac_instruction_set_operand(instruction, 1, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(instruction, 2, lhs_type, lhs_value, lhs_length);
elna_tac_instruction_set_operand(instruction, 3, rhs_type, rhs_value, rhs_length);
elna_instruction_list_concatenate(current_instruction, instruction)
end;
@@ -2299,30 +2318,22 @@ var
arguments_operand: ^ElnaTacOperand;
call_instruction: Word;
argument_entry: ^ElnaTreeExpressionList;
name_buffer: Word;
argument_count: Word;
begin
parsed_expression := parsed_call^.callee;
first_instruction := nil;
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);
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, 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;
.elna_tac_call_loop;
if argument_entry <> nil then
argument_type := 0;
argument_value := 0;
argument_length := 0;
instruction := elna_tac_binary_expression(argument_entry^.expression, symbol_table,
@argument_type, @argument_value, @argument_length);
if first_instruction = nil then
@@ -2333,27 +2344,12 @@ begin
if instruction <> nil then
current_instruction := instruction
end;
(* Save the argument on the stack. *)
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, 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^.kind := argument_type;
arguments_operand^.value := argument_value;
arguments_operand^.length := argument_length;
arguments_operand := arguments_operand + #size(ElnaTacOperand);
argument_entry := argument_entry^.next;
argument_count := argument_count + 1;
goto elna_tac_call_loop
end;
if first_instruction = nil then
@@ -2573,11 +2569,14 @@ var
current_field: ^ElnaTypeField;
field_offset: Word;
is_address: Word;
base_type: Word;
base_value: Word;
base_length: Word;
begin
designator_base := field_access_expression^.aggregate;
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;
current_field := aggregate_type^.members;
@@ -2592,14 +2591,12 @@ begin
field_offset := field_offset + field_type^.size;
goto elna_tac_field_access_expression_field
end;
last_instruction := elna_tac_instruction_create(ElnaTacOperator.add);
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^);
elna_tac_generate_pseudo(operand_type, operand_value, operand_length);
operand_type^ := ElnaTacKind.pseudo;
operand_value^ := "$unary";
operand_length^ := 6;
last_instruction := elna_tac_instruction_create(ElnaTacOperator.add);
elna_tac_instruction_set_operand(last_instruction, 1, operand_type^, operand_value^, operand_length^);
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)
end;
@@ -2611,9 +2608,9 @@ var
offset_instruction: Word;
add_instruction: Word;
is_address: Word;
offset_type: Word;
offset_value: Word;
offset_length: Word;
inter_type: Word;
inter_value: Word;
inter_length: Word;
aggregate_type: ^ElnaTypeArray;
designator_base: ^ElnaTreeExpression;
element_type: ^ElnaType;
@@ -2622,27 +2619,28 @@ begin
aggregate_type := designator_base^.type_decoration;
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);
elna_tac_instruction_set_operand(add_instruction, 1, ElnaTacKind.pseudo, "$lhs", 4);
elna_tac_instruction_set_operand(add_instruction, 2, 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, inter_type, inter_value, inter_length);
elna_tac_instruction_set_operand(add_instruction, 3, ElnaTacKind.immediate, 1, 0);
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, 2, 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, operand_type^, operand_value^, operand_length^);
elna_tac_instruction_set_operand(offset_instruction, 3, ElnaTacKind.immediate, element_type^.size, 0);
elna_instruction_list_concatenate(add_instruction, offset_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);
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, 3, ElnaTacKind.pseudo, "$lhs", 4);
elna_tac_instruction_set_operand(add_instruction, 2, inter_type, inter_value, inter_length);
elna_tac_instruction_set_operand(add_instruction, 3, operand_type^, operand_value^, operand_length^);
elna_instruction_list_concatenate(offset_instruction, array_instructions);