From d5bb407cc4d159bdcebc7975ec74d7fbfbaa1571 Mon Sep 17 00:00:00 2001
From: Michael Matz <matz@suse.de>
Date: Tue, 13 Aug 2019 03:21:58 +0200
Subject: [PATCH] riscv: Add special cases for const operands

RISC-V supports small immediates for some operations, let's
use them.
---
 riscv64-gen.c | 67 ++++++++++++++++++++++++++++++++++++++++++++++++---
 tccgen.c      |  2 +-
 2 files changed, 65 insertions(+), 4 deletions(-)

diff --git a/riscv64-gen.c b/riscv64-gen.c
index 488ab25e..5b771b91 100644
--- a/riscv64-gen.c
+++ b/riscv64-gen.c
@@ -794,8 +794,70 @@ static void gen_opil(int op, int ll)
 {
     int a, b, d;
     int inv = 0;
-    int func3 = 0, func7 = 0;
-    /* XXX We could special-case some constant args.  */
+    int func3 = 0;
+    ll = ll ? 0 : 8;
+    if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_SYM)) == VT_CONST) {
+        int fc = vtop->c.i;
+        if (fc == vtop->c.i && !(((unsigned)fc + (1 << 11)) >> 12)) {
+            int cll = 0;
+            vswap();
+            gv(RC_INT);
+            a = ireg(vtop[0].r);
+            --vtop;
+            d = get_reg(RC_INT);
+            ++vtop;
+            vswap();
+            switch (op) {
+                case '-':
+                    if (fc <= -(1 << 11))
+                      break;
+                    fc = -fc;
+                case '+':
+                    func3 = 0; // addi d, a, fc
+                do_cop:
+                    EI(0x13 | cll, func3, ireg(d), a, fc);
+                    --vtop;
+                    vtop[0].r = d;
+                    return;
+                case TOK_LE:
+                    if (fc >= (1 << 11) - 1)
+                      break;
+                    ++fc;
+                case TOK_LT:  func3 = 2; goto do_cop; // slti d, a, fc
+                case TOK_ULE:
+                    if (fc >= (1 << 11) - 1)
+                      break;
+                    ++fc;
+                case TOK_ULT: func3 = 3; goto do_cop; // sltiu d, a, fc
+                case '^':     func3 = 4; goto do_cop; // xori d, a, fc
+                case '|':     func3 = 6; goto do_cop; // ori  d, a, fc
+                case '&':     func3 = 7; goto do_cop; // andi d, a, fc
+                case TOK_SHL: func3 = 1; fc &= 63; goto do_cop; // slli d, a, fc
+                case TOK_SHR: func3 = 5; cll = ll; fc &= 63; goto do_cop; // srli d, a, fc
+                case TOK_SAR: func3 = 5; cll = ll; fc = 1024 | (fc & 63); goto do_cop;
+
+                case TOK_UGE:
+                case TOK_UGT:
+                case TOK_GE:
+                case TOK_GT:
+                    gen_opil(op - 1, ll);
+                    EI(0x13, 4, ireg(vtop->r), ireg(vtop->r), 1);// xori d, d, 1
+                    return;
+
+                case TOK_NE:
+                case TOK_EQ:
+                    if (fc)
+                      gen_opil('-', ll), a = ireg(vtop++->r);
+                    if (op == TOK_NE)
+                      o(0x33 | (3 << 12) | (ireg(d) << 7) | (0 << 15) | (a << 20)); // sltu d, x0, a == snez d,a
+                    else
+                      EI(0x13, 3, ireg(d), a, 1); // sltiu d, a, 1 == seqz d,a
+                    --vtop;
+                    vtop[0].r = d;
+                    return;
+            }
+        }
+    }
     gv2(RC_INT, RC_INT);
     a = ireg(vtop[-1].r);
     b = ireg(vtop[0].r);
@@ -804,7 +866,6 @@ static void gen_opil(int op, int ll)
     vtop++;
     vtop[0].r = d;
     d = ireg(d);
-    ll = ll ? 0 : 8;
     switch (op) {
     default:
         tcc_error("implement me: %s(%s)", __FUNCTION__, get_tok_str(op, NULL));
diff --git a/tccgen.c b/tccgen.c
index 14c7b014..262f42d6 100644
--- a/tccgen.c
+++ b/tccgen.c
@@ -2151,7 +2151,7 @@ static void gen_opic(int op)
     } else {
         /* if commutative ops, put c2 as constant */
         if (c1 && (op == '+' || op == '&' || op == '^' || 
-                   op == '|' || op == '*')) {
+                   op == '|' || op == '*' || op == TOK_EQ || op == TOK_NE)) {
             vswap();
             c2 = c1; //c = c1, c1 = c2, c2 = c;
             l2 = l1; //l = l1, l1 = l2, l2 = l;