aboutsummaryrefslogtreecommitdiff
path: root/src/ir/irgen_util.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/ir/irgen_util.cc')
-rw-r--r--src/ir/irgen_util.cc244
1 files changed, 244 insertions, 0 deletions
diff --git a/src/ir/irgen_util.cc b/src/ir/irgen_util.cc
new file mode 100644
index 0000000..e7e89f5
--- /dev/null
+++ b/src/ir/irgen_util.cc
@@ -0,0 +1,244 @@
+/* Source code for RCC-Legacy.
+ Copyright (C) 2026 Richard Qin
+
+This file is part of RCC.
+
+RCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+RCC 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 General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with RCC; see the file LICENSE. If not see
+<http://www.gnu.org/licenses/>. */
+/// @file irgen_util.cc
+/// @brief Constant evaluation, array init flattening, array address computation
+
+#include "rcc/irgen.h"
+
+#include <cstddef>
+
+namespace rcc {
+
+// Compile-time constant evaluation
+
+int32_t IRGen::eval_const_int(ASTNode* node) {
+ switch (node->kind) {
+ case NodeKind::IntLiteral:
+ return static_cast<IntLiteralNode*>(node)->value;
+ case NodeKind::FloatLiteral:
+ return static_cast<int32_t>(static_cast<FloatLiteralNode*>(node)->value);
+ case NodeKind::LVal: {
+ auto* lv = static_cast<LValNode*>(node);
+ Symbol* sym = sym_.lookup(lv->name);
+ if (sym && sym->is_const && !sym->is_array) {
+ if (auto* iv = std::get_if<int32_t>(&sym->const_val))
+ return *iv;
+ if (auto* fv = std::get_if<float>(&sym->const_val))
+ return static_cast<int32_t>(*fv);
+ }
+ return 0;
+ }
+ case NodeKind::UnaryExpr: {
+ auto* u = static_cast<UnaryExprNode*>(node);
+ int32_t v = eval_const_int(u->operand.get());
+ if (u->op == UnaryOp::Neg)
+ return -v;
+ if (u->op == UnaryOp::Not)
+ return !v;
+ return v;
+ }
+ case NodeKind::BinaryExpr: {
+ auto* b = static_cast<BinaryExprNode*>(node);
+ int32_t l = eval_const_int(b->lhs.get());
+ int32_t r = eval_const_int(b->rhs.get());
+ switch (b->op) {
+ case BinOp::Add:
+ return l + r;
+ case BinOp::Sub:
+ return l - r;
+ case BinOp::Mul:
+ return l * r;
+ case BinOp::Div:
+ return r ? l / r : 0;
+ case BinOp::Mod:
+ return r ? l % r : 0;
+ case BinOp::Lt:
+ return l < r;
+ case BinOp::Gt:
+ return l > r;
+ case BinOp::Le:
+ return l <= r;
+ case BinOp::Ge:
+ return l >= r;
+ case BinOp::Eq:
+ return l == r;
+ case BinOp::Ne:
+ return l != r;
+ case BinOp::And:
+ return l && r;
+ case BinOp::Or:
+ return l || r;
+ }
+ return 0;
+ }
+ default:
+ return 0;
+ }
+}
+
+float IRGen::eval_const_float(ASTNode* node) {
+ switch (node->kind) {
+ case NodeKind::FloatLiteral:
+ return static_cast<FloatLiteralNode*>(node)->value;
+ case NodeKind::IntLiteral:
+ return static_cast<float>(static_cast<IntLiteralNode*>(node)->value);
+ case NodeKind::LVal: {
+ auto* lv = static_cast<LValNode*>(node);
+ Symbol* sym = sym_.lookup(lv->name);
+ if (sym && sym->is_const && !sym->is_array) {
+ if (auto* fv = std::get_if<float>(&sym->const_val))
+ return *fv;
+ if (auto* iv = std::get_if<int32_t>(&sym->const_val))
+ return static_cast<float>(*iv);
+ }
+ return 0.0f;
+ }
+ case NodeKind::UnaryExpr: {
+ auto* u = static_cast<UnaryExprNode*>(node);
+ float v = eval_const_float(u->operand.get());
+ if (u->op == UnaryOp::Neg)
+ return -v;
+ return v;
+ }
+ case NodeKind::BinaryExpr: {
+ auto* b = static_cast<BinaryExprNode*>(node);
+ float l = eval_const_float(b->lhs.get());
+ float r = eval_const_float(b->rhs.get());
+ switch (b->op) {
+ case BinOp::Add:
+ return l + r;
+ case BinOp::Sub:
+ return l - r;
+ case BinOp::Mul:
+ return l * r;
+ case BinOp::Div:
+ return r != 0.0f ? l / r : 0.0f;
+ default:
+ return 0.0f;
+ }
+ }
+ default:
+ return 0.0f;
+ }
+}
+
+// Array initialization flattening
+
+void IRGen::flatten_init(const std::vector<int>& dims, ASTNode* init, std::vector<ASTNode*>& out) {
+ if (!init)
+ return;
+
+ if (init->kind != NodeKind::InitList) {
+ out.push_back(init);
+ return;
+ }
+
+ auto* list = static_cast<InitListNode*>(init);
+ if (dims.empty())
+ return;
+
+ int sub_size = 1;
+ for (size_t i = 1; i < dims.size(); i++)
+ sub_size *= dims[i];
+
+ int total = dims[0] * sub_size;
+ int pos = 0;
+
+ for (auto& item : list->items) {
+ if (pos >= total)
+ break;
+
+ if (item->kind == NodeKind::InitList) {
+ if (dims.size() > 1) {
+ std::vector<int> sub_dims(dims.begin() + 1, dims.end());
+ int before = static_cast<int>(out.size());
+ flatten_init(sub_dims, item.get(), out);
+ int filled = static_cast<int>(out.size()) - before;
+ while (filled < sub_size) {
+ out.push_back(nullptr);
+ filled++;
+ }
+ pos += sub_size;
+ } else {
+ auto* inner = static_cast<InitListNode*>(item.get());
+ for (auto& elem : inner->items) {
+ if (pos < total) {
+ out.push_back(elem.get());
+ pos++;
+ }
+ }
+ }
+ } else {
+ out.push_back(item.get());
+ pos++;
+ }
+ }
+
+ while (pos < total) {
+ out.push_back(nullptr);
+ pos++;
+ }
+}
+
+// Array address calculation
+
+Ref IRGen::compute_array_addr(LValNode* node) {
+ Symbol* sym = sym_.lookup(node->name);
+ Ref base = get_var_addr_ref(sym);
+
+ if (sym->is_param && sym->is_array)
+ base = read_variable(sym->uid, cur_blk_, Kl);
+
+ const auto& dims = sym->dims;
+ size_t ndims = dims.size();
+
+ Ref offset = Ref::none();
+ bool offset_valid = false;
+
+ for (size_t i = 0; i < node->indices.size(); i++) {
+ Ref idx = visit_expr(node->indices[i].get());
+
+ int stride = 1;
+ size_t dim_idx = sym->is_param ? i : (i + 1);
+ for (size_t j = dim_idx; j < ndims; j++)
+ stride *= dims[j];
+
+ // Extend index to 'l' type for pointer arithmetic
+ int idx_cls = Kw;
+ if (rtype(idx) == RTmp && idx.val >= Tmp0)
+ idx_cls = cur_fn_->tmp[idx.val].cls;
+ if (idx_cls == Kw)
+ idx = emit_ins(Oextsw, Kl, idx, Ref::none());
+
+ Ref byte_off = emit_ins(Omul, Kl, idx, make_int_ref(stride * 4));
+
+ if (offset_valid) {
+ offset = emit_ins(Oadd, Kl, offset, byte_off);
+ } else {
+ offset = byte_off;
+ offset_valid = true;
+ }
+ }
+
+ if (offset_valid)
+ return emit_ins(Oadd, Kl, base, offset);
+ return base;
+}
+
+} // namespace rcc