aboutsummaryrefslogtreecommitdiff
path: root/src/backend/peephole.cc
diff options
context:
space:
mode:
authorRichard Qin <richard.qin.001@gmail.com>2026-09-15 08:16:43 +0800
committerRichard Qin <richard.qin.001@gmail.com>2026-09-15 08:16:43 +0800
commit4022e5c95210631e4aceb08eaf9d9071aa5aefc4 (patch)
treea5922559836e45fb3459a3d070367912e1035b1a /src/backend/peephole.cc
downloadrcc-master.tar.gz
rcc-master.tar.xz
Set up a git repoHEADmaster
Diffstat (limited to 'src/backend/peephole.cc')
-rw-r--r--src/backend/peephole.cc146
1 files changed, 146 insertions, 0 deletions
diff --git a/src/backend/peephole.cc b/src/backend/peephole.cc
new file mode 100644
index 0000000..0c5e95f
--- /dev/null
+++ b/src/backend/peephole.cc
@@ -0,0 +1,146 @@
+/* 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 peephole.cc
+/// @brief Backend sliding-window peephole pass.
+
+#include "rcc/all.h"
+
+namespace rcc {
+
+namespace {
+
+// Store op to byte width.
+int store_size(int op) {
+ switch (op) {
+ case Ostoreb:
+ return 1;
+ case Ostoreh:
+ return 2;
+ case Ostorew:
+ case Ostores:
+ return 4;
+ case Ostorel:
+ case Ostored:
+ return 8;
+ default:
+ return 0;
+ }
+}
+
+// Check if store and load are compatible for forwarding.
+bool store_load_compatible(int sop, int lcls) {
+ switch (sop) {
+ case Ostorew:
+ return lcls == Kw;
+ case Ostorel:
+ return lcls == Kl;
+ case Ostores:
+ return lcls == Ks;
+ case Ostored:
+ return lcls == Kd;
+ default:
+ return false;
+ }
+}
+
+void peep_blk(Blk* b) {
+ uint n = b->nins;
+ if (n == 0)
+ return;
+
+ // Self Ocopy elimination.
+ for (uint k = 0; k < n; k++) {
+ Ins* i = &b->ins[k];
+ if (i->op == Ocopy && req(i->to, i->arg[0]) && rtype(i->to) != -1)
+ i->op = Onop;
+ }
+
+ // Window 2 mode.
+ auto next_live = [&](uint from) -> int {
+ for (uint k = from; k < n; k++)
+ if (b->ins[k].op != Onop)
+ return static_cast<int>(k);
+ return -1;
+ };
+
+ int p = next_live(0);
+ while (p >= 0) {
+ int q = next_live(static_cast<uint>(p) + 1);
+ if (q < 0)
+ break;
+ Ins* pi = &b->ins[p];
+ Ins* qi = &b->ins[q];
+
+ // Store + Load to same slot: keep store, change load to copy.
+ if (isstore(pi->op) && qi->op == Oload && rtype(pi->arg[1]) == RSlot &&
+ rtype(qi->arg[0]) == RSlot && req(pi->arg[1], qi->arg[0]) &&
+ store_load_compatible(pi->op, qi->cls) && rtype(pi->arg[0]) != RCon) {
+ // Skip forwarding if value is a constant.
+ qi->op = Ocopy;
+ qi->arg[0] = pi->arg[0];
+ qi->arg[1] = Ref::none();
+ // Keep cls and to.
+ p = q;
+ continue;
+ }
+
+ // Consecutive stores to same slot: drop first.
+ if (isstore(pi->op) && pi->op == qi->op && rtype(pi->arg[1]) == RSlot &&
+ rtype(qi->arg[1]) == RSlot && req(pi->arg[1], qi->arg[1]) && store_size(pi->op) > 0) {
+ pi->op = Onop;
+ p = q;
+ continue;
+ }
+
+ p = q;
+ }
+
+ // Redundant Oextsw elimination.
+ for (uint pidx = 0; pidx < n; pidx++) {
+ Ins* pi = &b->ins[pidx];
+ if (pi->op != Oextsw)
+ continue;
+ if (!isreg(pi->to) || !isreg(pi->arg[0]))
+ continue;
+ for (uint qidx = pidx + 1; qidx < n; qidx++) {
+ Ins* qi = &b->ins[qidx];
+ if (qi->op == Onop)
+ continue;
+ // Identical Oextsw.
+ if (qi->op == pi->op && req(qi->to, pi->to) && req(qi->arg[0], pi->arg[0]) &&
+ req(qi->arg[1], pi->arg[1])) {
+ qi->op = Onop;
+ continue;
+ }
+ // Anchor invalidated.
+ if (isreg(qi->to) && (req(qi->to, pi->to) || req(qi->to, pi->arg[0])))
+ break;
+ }
+ }
+}
+
+} // namespace
+
+void peephole(Ctx* /*ctx*/, Fn* fn) {
+ for (Blk* b = fn->start; b; b = b->link)
+ peep_blk(b);
+}
+
+} // namespace rcc