aboutsummaryrefslogtreecommitdiff
path: root/source/qbe.elna
diff options
context:
space:
mode:
authorEugen Wissner <belka@caraus.de>2026-10-04 00:51:52 +0200
committerEugen Wissner <belka@caraus.de>2026-10-04 00:51:52 +0200
commit8a6ed3a4ddf9c4e16bb4ddc3b8c5094bb937598b (patch)
tree18198be391a5fd4b10421c1850f1046b3c2e12c4 /source/qbe.elna
parente4ce7f658741a7428597da4872435a1b0bae944c (diff)
downloadelna-8a6ed3a4ddf9c4e16bb4ddc3b8c5094bb937598b.tar.gz
Update the old compiler with the new syntax
Diffstat (limited to 'source/qbe.elna')
-rw-r--r--source/qbe.elna635
1 files changed, 635 insertions, 0 deletions
diff --git a/source/qbe.elna b/source/qbe.elna
new file mode 100644
index 0000000..0a5a45b
--- /dev/null
+++ b/source/qbe.elna
@@ -0,0 +1,635 @@
+(* This Source Code Form is subject to the terms of the Mozilla Public License,
+ v. 2.0. If a copy of the MPL was not distributed with this file, You can
+ obtain one at https://mozilla.org/MPL/2.0/. *)
+module
+import common, cstdlib, cstdio, cstring, lexer, ast, symbol, tac
+
+var
+ qbe_unique_id: Word := 0u
+
+proc qbe_write_slice(file: ^FILE; text: []const Word8)
+begin
+ fwrite#[Word8](text.ptr, 1u, text.length, file)
+return
+
+proc qbe_write_str(file: ^FILE; str: ^const Word8)
+begin
+ fwrite#[Word8](str, 1u, strlen(str), file)
+return
+
+proc qbe_write_word(file: ^FILE; val: Word)
+var
+ buf: [32]Word8
+ len: Int
+begin
+ len := sprintf(@buf[1], "%u\0".ptr, val);
+ fwrite#[Word8](@buf[1], 1u, cast(len: Word), file)
+return
+
+proc is_global(globals: ^ElnaTacStaticVariable; name: []const Word8) -> Bool
+var
+ current: ^ElnaTacStaticVariable
+ found: Bool := false
+begin
+ current := globals;
+ while current <> nil & ~found do
+ if current^.name = name then
+ found := true
+ else
+ current := current^.next
+ end
+ end
+return found
+
+proc is_string_constant(strings: ^ElnaTacStringConstant; name: []const Word8) -> Bool
+var
+ current: ^ElnaTacStringConstant
+ found: Bool := false
+begin
+ current := strings;
+ while current <> nil & ~found do
+ if current^.name = name then
+ found := true
+ else
+ current := current^.next
+ end
+ end
+return found
+
+proc is_pointer_type(_type: ^ElnaType) -> Bool
+var
+ result: Bool := false
+begin
+ if _type <> nil then
+ if _type^.kind = ElnaTypeKind.pointer then
+ result := true
+ elsif _type = pointer_type then
+ result := true
+ end
+ end
+return result
+
+proc get_procedure_return_type(proc_name: []const Word8) -> ^ElnaType
+var
+ symbol_info: ^ElnaSymbolInfo
+ procedure_info: ^ElnaSymbolProcedureInfo
+ result: ^ElnaType := nil
+begin
+ symbol_info := elna_symbol_table_lookup(symbol_table_global, proc_name);
+ if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.procedure_info then
+ procedure_info := cast(symbol_info: ^ElnaSymbolProcedureInfo);
+ if procedure_info^.procedure_type <> nil then
+ result := procedure_info^.procedure_type^.return_type
+ end
+ end
+return result
+
+proc get_param_type(sym_table: ^ElnaSymbolTable; param_name: []const Word8) -> ^ElnaType
+var
+ symbol_info: ^ElnaSymbolInfo
+ temp_info: ^ElnaSymbolTemporaryInfo
+ result: ^ElnaType := nil
+begin
+ symbol_info := elna_symbol_table_lookup(sym_table, param_name);
+ if symbol_info <> nil & symbol_info^.kind = ElnaSymbolInfoKind.temporary_info then
+ temp_info := cast(symbol_info: ^ElnaSymbolTemporaryInfo);
+ result := temp_info^.variable_type
+ end
+return result
+
+proc is_pointer_operand(op: ^ElnaTacOperand; sym_table: ^ElnaSymbolTable;
+ globals: ^ElnaTacStaticVariable; strings: ^ElnaTacStringConstant) -> Bool
+var
+ var_type: ^ElnaType
+ result: Bool := false
+begin
+ if op^.kind = ElnaTacKind.variable then
+ if is_global(globals, op^.name) or is_string_constant(strings, op^.name) then
+ result := true
+ else
+ var_type := get_param_type(sym_table, op^.name);
+ if is_pointer_type(var_type) then
+ result := true
+ end
+ end
+ end
+return result
+
+proc qbe_emit_operand(file: ^FILE; op: ^ElnaTacOperand;
+ globals: ^ElnaTacStaticVariable; strings: ^ElnaTacStringConstant)
+begin
+ case op^.kind of
+ ElnaTacKind.constant:
+ qbe_write_word(file, op^.constant)
+ | ElnaTacKind.variable:
+ if is_global(globals, op^.name) or is_string_constant(strings, op^.name) then
+ qbe_write_str(file, "$\0".ptr)
+ else
+ qbe_write_str(file, "%\0".ptr)
+ end;
+ qbe_write_slice(file, op^.name)
+ | ElnaTacKind.label:
+ qbe_write_str(file, "@\0".ptr);
+ qbe_write_slice(file, op^.name)
+ else
+ end
+return
+
+proc var_needs_stack_alloc(instructions: ^ElnaList; sym_table: ^ElnaSymbolTable; name: []const Word8) -> Bool
+var
+ node: ^ElnaListNode
+ inst: ^ElnaTacInstruction
+ var_type: ^ElnaType
+ result: Bool := false
+begin
+ var_type := get_param_type(sym_table, name);
+ if var_type <> nil then
+ if var_type^.kind = ElnaTypeKind._record or var_type^.kind = ElnaTypeKind.array then
+ result := true
+ end
+ end;
+
+ node := instructions^.first;
+ while node <> nil & ~result do
+ inst := cast(node: ^ElnaTacInstruction);
+ if inst^.operator = ElnaTacOperator.get_address & inst^.operands[1].name = name then
+ result := true
+ elsif inst^.operator = ElnaTacOperator.copy_to_offset & inst^.operands[2].name = name then
+ result := true
+ elsif inst^.operator = ElnaTacOperator.copy_from_offset & inst^.operands[1].name = name then
+ result := true
+ end;
+ node := node^.next
+ end
+return result
+
+proc qbe_emit_procedure(file: ^FILE; proc_node: ^ElnaTacProcedure;
+ globals: ^ElnaTacStaticVariable; strings: ^ElnaTacStringConstant)
+var
+ node: ^ElnaListNode
+ inst: ^ElnaTacInstruction
+ ret_type: ^ElnaType
+ param_idx: Word := 0u
+ param_name: []const Word8
+ param_type: ^ElnaType
+ entry: ^ElnaSymbolEntry
+ temp_info: ^ElnaSymbolTemporaryInfo
+ sym_idx: Word := 0u
+ alloc_size: Word
+ last_operator: ElnaTacOperator := ElnaTacOperator.nop
+ tid: Word
+ arg_i: Word
+ arg_op: ^ElnaTacOperand
+ callee_ret: ^ElnaType
+ scaled: Word
+begin
+ qbe_write_str(file, "export function \0".ptr);
+ ret_type := get_procedure_return_type(proc_node^.name);
+
+ if proc_node^.name = "main" then
+ qbe_write_str(file, "w \0".ptr)
+ elsif ret_type <> nil then
+ if ret_type = bool_type then
+ qbe_write_str(file, "w \0".ptr)
+ else
+ qbe_write_str(file, "l \0".ptr)
+ end
+ end;
+
+ qbe_write_str(file, "$\0".ptr);
+ qbe_write_slice(file, proc_node^.name);
+ qbe_write_str(file, "(\0".ptr);
+
+ while param_idx < proc_node^.count do
+ param_name := (proc_node^.parameters + param_idx)^;
+ param_type := get_param_type(proc_node^.symbol_table, param_name);
+ if param_type = bool_type then
+ qbe_write_str(file, "w %\0".ptr)
+ else
+ qbe_write_str(file, "l %\0".ptr)
+ end;
+ qbe_write_slice(file, param_name);
+ if param_idx + 1u < proc_node^.count then
+ qbe_write_str(file, ", \0".ptr)
+ end;
+ param_idx := param_idx + 1u
+ end;
+
+ qbe_write_str(file, ") {\n@start\n\0".ptr);
+
+ (* Stack allocate variables needing memory address *)
+ if proc_node^.symbol_table <> nil then
+ while sym_idx < proc_node^.symbol_table^.count do
+ entry := proc_node^.symbol_table^.symbols + sym_idx;
+ if entry^.name.length > 0u & entry^.symbol_info <> nil then
+ if entry^.symbol_info^.kind = ElnaSymbolInfoKind.temporary_info then
+ temp_info := cast(entry^.symbol_info: ^ElnaSymbolTemporaryInfo);
+ if var_needs_stack_alloc(@proc_node^.body, proc_node^.symbol_table, entry^.name) then
+ alloc_size := 8u;
+ if temp_info^.variable_type <> nil & temp_info^.variable_type^.size > 8u then
+ alloc_size := (temp_info^.variable_type^.size + 7u) / 8u * 8u
+ end;
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, entry^.name);
+ qbe_write_str(file, " =l alloc8 \0".ptr);
+ qbe_write_word(file, alloc_size);
+ qbe_write_str(file, "\n\0".ptr)
+ end
+ end
+ end;
+ sym_idx := sym_idx + 1u
+ end
+ end;
+
+ (* Emit TAC instructions *)
+ node := proc_node^.body.first;
+ while node <> nil do
+ inst := cast(node: ^ElnaTacInstruction);
+ last_operator := inst^.operator;
+
+ case inst^.operator of
+ ElnaTacOperator.get_address:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[2].name);
+ qbe_write_str(file, " =l copy \0".ptr);
+ if is_global(globals, inst^.operands[1].name) or is_string_constant(strings, inst^.operands[1].name) then
+ qbe_write_str(file, "$\0".ptr)
+ else
+ qbe_write_str(file, "%\0".ptr)
+ end;
+ qbe_write_slice(file, inst^.operands[1].name);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.copy:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[2].name);
+ qbe_write_str(file, " =l copy \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.add:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =l add \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.subtract:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =l sub \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.multiply:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =l mul \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.divide:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =l div \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.remainder:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =l rem \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator._or:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =l or \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator._xor:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =l xor \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.and:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =l and \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.equal:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =w ceql \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.not_equal:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =w cnew \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.less_than:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =w csltl \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.greater_than:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =w csgtl \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.less_or_equal:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =w cslel \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.greater_or_equal:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =w csgel \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.negate:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[2].name);
+ qbe_write_str(file, " =l neg \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.complement:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[2].name);
+ qbe_write_str(file, " =l xor \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", -1\n\0".ptr)
+ | ElnaTacOperator.load:
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[2].name);
+ qbe_write_str(file, " =l loadl \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.store:
+ qbe_write_str(file, "\tstorel \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.copy_to_offset:
+ if inst^.operands[3].constant = 0u then
+ qbe_write_str(file, "\tstorel \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ else
+ qbe_unique_id := qbe_unique_id + 1u;
+ tid := qbe_unique_id;
+ qbe_write_str(file, "\t%qbe_off_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, " =l add \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_write_word(file, inst^.operands[3].constant);
+ qbe_write_str(file, "\n\tstorel \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", %qbe_off_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, "\n\0".ptr)
+ end
+ | ElnaTacOperator.copy_from_offset:
+ if inst^.operands[2].constant = 0u then
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =l loadl \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ else
+ qbe_unique_id := qbe_unique_id + 1u;
+ tid := qbe_unique_id;
+ qbe_write_str(file, "\t%qbe_off_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, " =l add \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_write_word(file, inst^.operands[2].constant);
+ qbe_write_str(file, "\n\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ qbe_write_str(file, " =l loadl %qbe_off_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, "\n\0".ptr)
+ end
+ | ElnaTacOperator.add_ptr:
+ qbe_unique_id := qbe_unique_id + 1u;
+ tid := qbe_unique_id;
+ if inst^.operands[2].kind = ElnaTacKind.constant then
+ if inst^.operands[3].constant = 1u then
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[4].name);
+ qbe_write_str(file, " =l add \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_write_word(file, inst^.operands[2].constant);
+ qbe_write_str(file, "\n\0".ptr)
+ else
+ scaled := inst^.operands[2].constant * inst^.operands[3].constant;
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[4].name);
+ qbe_write_str(file, " =l add \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_write_word(file, scaled);
+ qbe_write_str(file, "\n\0".ptr)
+ end
+ else
+ qbe_write_str(file, "\t%qbe_ext_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, " =l extuw \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[2], globals, strings);
+ qbe_write_str(file, "\n\0".ptr);
+
+ if inst^.operands[3].constant = 1u then
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[4].name);
+ qbe_write_str(file, " =l add \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", %qbe_ext_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, "\n\0".ptr)
+ else
+ qbe_write_str(file, "\t%qbe_s_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, " =l mul %qbe_ext_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, ", \0".ptr);
+ qbe_write_word(file, inst^.operands[3].constant);
+ qbe_write_str(file, "\n\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[4].name);
+ qbe_write_str(file, " =l add \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", %qbe_s_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, "\n\0".ptr)
+ end
+ end
+ | ElnaTacOperator.proc_call:
+ callee_ret := get_procedure_return_type(inst^.operands[1].name);
+ if inst^.operands[3].kind = ElnaTacKind.ignore then
+ qbe_write_str(file, "\tcall $\0".ptr)
+ else
+ qbe_write_str(file, "\t%\0".ptr);
+ qbe_write_slice(file, inst^.operands[3].name);
+ if callee_ret = bool_type then
+ qbe_write_str(file, " =w call $\0".ptr)
+ else
+ qbe_write_str(file, " =l call $\0".ptr)
+ end
+ end;
+ qbe_write_slice(file, inst^.operands[1].name);
+ qbe_write_str(file, "(\0".ptr);
+
+ arg_i := 0u;
+ while arg_i < inst^.operands[2].length do
+ arg_op := inst^.operands[2].list_operands + arg_i;
+ qbe_write_str(file, "l \0".ptr);
+ qbe_emit_operand(file, arg_op, globals, strings);
+ if arg_i + 1u < inst^.operands[2].length then
+ qbe_write_str(file, ", \0".ptr)
+ end;
+ arg_i := arg_i + 1u
+ end;
+ qbe_write_str(file, ")\n\0".ptr)
+ | ElnaTacOperator.jump:
+ qbe_write_str(file, "\tjmp @\0".ptr);
+ qbe_write_slice(file, inst^.operands[1].name);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.jump_if_zero:
+ qbe_unique_id := qbe_unique_id + 1u;
+ tid := qbe_unique_id;
+ qbe_write_str(file, "\tjnz \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", @qbe_ft_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, ", @\0".ptr);
+ qbe_write_slice(file, inst^.operands[2].name);
+ qbe_write_str(file, "\n@qbe_ft_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.jump_if_not_zero:
+ qbe_unique_id := qbe_unique_id + 1u;
+ tid := qbe_unique_id;
+ qbe_write_str(file, "\tjnz \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, ", @\0".ptr);
+ qbe_write_slice(file, inst^.operands[2].name);
+ qbe_write_str(file, ", @qbe_ft_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, "\n@qbe_ft_\0".ptr);
+ qbe_write_word(file, tid);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator.label:
+ qbe_write_str(file, "@\0".ptr);
+ qbe_write_slice(file, inst^.operands[1].name);
+ qbe_write_str(file, "\n\0".ptr)
+ | ElnaTacOperator._return:
+ if inst^.operands[1].kind = ElnaTacKind.ignore then
+ qbe_write_str(file, "\tret\n\0".ptr)
+ else
+ qbe_write_str(file, "\tret \0".ptr);
+ qbe_emit_operand(file, @inst^.operands[1], globals, strings);
+ qbe_write_str(file, "\n\0".ptr)
+ end
+ else
+ end;
+ node := node^.next
+ end;
+
+ (* Function terminator if not terminated *)
+ if last_operator <> ElnaTacOperator._return & last_operator <> ElnaTacOperator.jump then
+ if proc_node^.name = "main" then
+ qbe_write_str(file, "\tret 0\n\0".ptr)
+ elsif ret_type = nil then
+ qbe_write_str(file, "\tret\n\0".ptr)
+ else
+ qbe_write_str(file, "\tret 0\n\0".ptr)
+ end
+ end;
+
+ qbe_write_str(file, "}\n\n\0".ptr)
+return
+
+proc elna_qbe_emit*(instruction_module: ^ElnaInstructionModule; out_file: ^FILE)
+var
+ current_string: ^ElnaTacStringConstant
+ current_global: ^ElnaTacStaticVariable
+ current_proc: ^ElnaTacProcedure
+ i: Word
+ byte_val: Word
+begin
+ (* Emit strings *)
+ current_string := instruction_module^.strings;
+ while current_string <> nil do
+ qbe_write_str(out_file, "data $\0".ptr);
+ qbe_write_slice(out_file, current_string^.name);
+ qbe_write_str(out_file, " = { \0".ptr);
+
+ i := 0u;
+ while i < current_string^.value.length do
+ qbe_write_str(out_file, "b \0".ptr);
+ byte_val := cast((current_string^.value.ptr + i)^: Word);
+ qbe_write_word(out_file, byte_val);
+ qbe_write_str(out_file, ", \0".ptr);
+ i := i + 1u
+ end;
+ qbe_write_str(out_file, "b 0 }\n\0".ptr);
+
+ current_string := current_string^.next
+ end;
+
+ (* Emit global data *)
+ current_global := instruction_module^.data;
+ while current_global <> nil do
+ qbe_write_str(out_file, "export data $\0".ptr);
+ qbe_write_slice(out_file, current_global^.name);
+ qbe_write_str(out_file, " = { z \0".ptr);
+ qbe_write_word(out_file, current_global^.size);
+ qbe_write_str(out_file, " }\n\0".ptr);
+
+ current_global := current_global^.next
+ end;
+
+ (* Emit procedures *)
+ current_proc := instruction_module^.code;
+ while current_proc <> nil do
+ qbe_emit_procedure(out_file, current_proc, instruction_module^.data, instruction_module^.strings);
+ current_proc := current_proc^.next
+ end
+return
+
+end.