/* * Copyright (C) 2025 Johnny Richard * * SPDX-License-Identifier: LGPL-3.0-or-later * * This file is part of obe. * * obe is free software: you can redistribute it and/or modify it under the * terms of the GNU Lesser General Public License as published by the Free * Software Foundation, either version 3 of the License, or (at your option) * any later version. * * obe is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public License * along with obe. If not, see . */ #include #include #include #include #include #include static void obe_x86_64_codegen_emit_function(obe_ir_function_t *fn, FILE *out) { fprintf(out, PRIs ":\n", PRIsARG(fn->name)); fprintf(out, "\tpush %%rbp\n"); fprintf(out, "\tmov %%rsp, %%rbp\n"); size_t insts_length = obe_array_length(fn->instrs); for (size_t i = 0; i < insts_length; ++i) { obe_ir_inst_t inst = fn->instrs[i]; switch (inst.kind) { case OBE_IR_INST_RETURN: { if (inst.operand1.kind == OBE_IR_OPERAND_LITERAL) { fprintf(out, "\tmov $%s, %%rax\n", inst.operand1.value); } else { fprintf(stderr, "Operation kind not supported\n"); exit(EXIT_FAILURE); } } break; default: { fprintf(stderr, "Instruction not supported\n"); exit(EXIT_FAILURE); } } } fprintf(out, "\tleave\n"); fprintf(out, "\tret\n"); } void _obe_x86_64_codegen_emit(obe_ir_translation_unit_t* tu, FILE *out) { // FIXME: Add syntax to configure globl fprintf(out, ".globl main\n"); fprintf(out, ".text\n"); size_t funcs_length = obe_array_length(tu->funcs); for (size_t i = 0; i < funcs_length; ++i) { obe_ir_function_t fn = tu->funcs[i]; obe_x86_64_codegen_emit_function(&fn, out); } } typedef struct obe_basic_block obe_basic_block_t; typedef struct obe_cfg obe_cfg_t; typedef struct obe_int_graph obe_int_graph_t; struct obe_basic_block { obe_string_t id; obe_ir_inst_t *instrs; struct obe_basic_block *pred; struct obe_basic_block *succ; }; struct obe_cfg { obe_basic_block_t *init_block; obe_basic_block_t *curr_block; }; typedef struct obe_int_edge { size_t v1; size_t v2; } obe_int_edge_t; struct obe_int_graph { obe_int_edge_t *edges; }; obe_int_graph_t create_interference_graph(obe_cfg_t *cfg, obe_arena_t *arena) { obe_int_graph_t graph = {0}; graph.edges = obe_array(arena, obe_int_edge_t); return graph; } void obe_x86_64_codegen_emit(obe_ir_translation_unit_t* tu, FILE *out) { // FIXME: Create a valid CFG obe_arena_t arena = {0}; obe_cfg_t cfg = {0}; if (cfg.init_block == NULL) { cfg.init_block = obe_arena_alloc(&arena, sizeof(obe_basic_block_t)); cfg.curr_block = cfg.init_block; cfg.curr_block->instrs = obe_array(&arena, obe_ir_inst_t); } size_t funcs_length = obe_array_length(tu->funcs); for (size_t i = 0; i < funcs_length; ++i) { obe_ir_function_t fn = tu->funcs[i]; size_t instrs_length = obe_array_length(fn.instrs); for (size_t j = 0; j < instrs_length; ++j) { obe_ir_inst_t inst = fn.instrs[j]; switch (inst.kind) { default: { obe_array_append(cfg.curr_block->instrs, inst); } } } } // TODO: Register Allocation // liveness analysis (create interference graph) size_t instrs_length = obe_array_length(cfg.init_block->instrs); for (size_t i = 0; i < instrs_length; ++i) { obe_ir_inst_t inst = cfg.init_block->instrs[i]; // asm("int3"); printf("inst = %d\n", inst.kind); } // TODO: create_interference_graph(&cfg, &arena); // TODO: Emit assembly code obe_arena_free(&arena); }