diff options
| author | Eugen Wissner <belka@caraus.de> | 2026-10-04 00:51:52 +0200 |
|---|---|---|
| committer | Eugen Wissner <belka@caraus.de> | 2026-10-04 00:51:52 +0200 |
| commit | 8a6ed3a4ddf9c4e16bb4ddc3b8c5094bb937598b (patch) | |
| tree | 18198be391a5fd4b10421c1850f1046b3c2e12c4 /source/qbe.elna | |
| parent | e4ce7f658741a7428597da4872435a1b0bae944c (diff) | |
| download | elna-8a6ed3a4ddf9c4e16bb4ddc3b8c5094bb937598b.tar.gz | |
Update the old compiler with the new syntax
Diffstat (limited to 'source/qbe.elna')
| -rw-r--r-- | source/qbe.elna | 635 |
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. |
