aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2023-06-12 19:16:39 +0200
committerlemon <lsof@mailbox.org>2023-06-12 19:16:39 +0200
commit106fe60243bd61d017d28795f6eba68fecc981b4 (patch)
tree7fbb5c1a84346af8243630cb6c0057ab9b475978
parent6df4f80c99609162ad3e46bfdce46d0c10696a45 (diff)
dec,inc,sub
-rw-r--r--amd64/emit.c22
-rw-r--r--amd64/isel.c18
-rw-r--r--op.def3
-rw-r--r--regalloc.c1
-rw-r--r--test/test3.c16
5 files changed, 57 insertions, 3 deletions
diff --git a/amd64/emit.c b/amd64/emit.c
index a89b021..e1d9463 100644
--- a/amd64/emit.c
+++ b/amd64/emit.c
@@ -280,11 +280,24 @@ DEFINSTR2(Xadd,
{4, PFPR, PMEM, "\xF3\x0F\x58", EN_RM}, /* ADDSS xmm, m32 */
{8, PFPR, PMEM, "\xF2\x0F\x58", EN_RM}, /* ADDSD xmm, m64 */
)
+DEFINSTR2(Xsub,
+ {4|8, PGPR, PGPR, "\x2B", EN_RR}, /* SUB r32/64, r32/64 */
+ {4|8, PGPR, PI8, "\x83", EN_RI8, .ext=5}, /* SUB r32/64, imm8 */
+ {4|8, PRAX, PI32, "\x2D", EN_I32}, /* SUB eax/rax, imm */
+ {4|8, PGPR, PI32, "\x81", EN_RI32, .ext=5}, /* SUB r32/64, imm */
+ { 8, PGPR, PMEM, "\x2B", EN_RM}, /* SUB r64, m64 */
+ {4, PFPR, PFPR, "\xF3\x0F\x5C", EN_RR}, /* SUBSS xmm, xmm */
+ {8, PFPR, PFPR, "\xF2\x0F\x5C", EN_RR}, /* SUBSD xmm, xmm */
+ {4, PFPR, PMEM, "\xF3\x0F\x5C", EN_RM}, /* SUBSS xmm, m32 */
+ {8, PFPR, PMEM, "\xF2\x0F\x5C", EN_RM}, /* SUBSD xmm, m64 */
+)
DEFINSTR2(Xshl,
{4|8, PGPR, P1, "\xD1", EN_R, .ext=4}, /* SHL r32/64, 1 */
{4|8, PGPR, PI32, "\xC1", EN_RI8, .ext=4}, /* SHL r32/64, imm */
{4|8, PGPR, PRCX, "\xD3", EN_R, .ext=4}, /* SHL r32/64, CL */
)
+DEFINSTR1(Xinc, {4|8, PGPR, 0, "\xFF", EN_R, .ext=0} /* INC r32/64 */)
+DEFINSTR1(Xdec, {4|8, PGPR, 0, "\xFF", EN_R, .ext=1} /* DEC r32/64 */)
DEFINSTR1(Xidiv,
{4|8, PGPR, 0, "\xF7", EN_R, .ext=7}, /* IDIV r32/64 */
{4|8, PMEM, 0, "\xF7", EN_M, .ext=7}, /* IDIV m32/64 */
@@ -433,6 +446,7 @@ emitinstr(uchar **pcode, uint *stktop, struct function *fn, struct block *blk, i
struct oper dst, src;
uchar ksiz = cls2siz[ins->cls];
void (*X)(uchar **, uint, struct oper, struct oper) = NULL;
+ void (*X1)(uchar **, uint, struct oper) = NULL;
if (oisalloca(ins->op)) {
uint alignlog2 = ins->op - Oalloca1;
@@ -473,12 +487,20 @@ emitinstr(uchar **pcode, uint *stktop, struct function *fn, struct block *blk, i
Xlea(pcode, ksiz, dst, mem);
}
break;
+ case Osub: X = Xsub; goto ALU2;
case Oshl: X = Xshl; goto ALU2;
ALU2:
dst = mkregoper(ins->l);
assert(ins->reg-1 == dst.reg);
X(pcode, ksiz, dst, mkimmdatregoper(ins->r));
break;
+ case Oxinc: X1 = Xinc; goto ALU1;
+ case Oxdec: X1 = Xdec; goto ALU1;
+ ALU1:
+ dst = mkregoper(ins->l);
+ assert(ins->reg-1 == dst.reg);
+ X1(pcode, ksiz, dst);
+ break;
case Odiv: case Orem:
switch (ins->cls) {
case KI8: B(0x48); /* REX.W */
diff --git a/amd64/isel.c b/amd64/isel.c
index 8ab11a7..30ad222 100644
--- a/amd64/isel.c
+++ b/amd64/isel.c
@@ -171,7 +171,11 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
insertinstr(blk, ++(*curi), temp);
break;
case Osub:
- if (iscon(ins->l)) {
+ if (ins->r.bits == mkref(RICON, 1).bits) {
+ /* sub x,1 -> dec x */
+ ins->op = Oxdec;
+ ins->r = NOREF;
+ } else if (iscon(ins->l)) {
/* sub imm, x -> sub x, imm; neg x */
struct instr sub = *ins;
rswap(sub.l, sub.r);
@@ -181,6 +185,18 @@ sel(struct function *fn, struct instr *ins, struct block *blk, int *curi)
}
goto ALU;
case Oadd:
+ if (ins->l.bits == mkref(RICON, 1).bits) {
+ /* add 1,x -> inc x */
+ ins->op = Oxinc;
+ ins->l = ins->r;
+ ins->r = NOREF;
+ goto ALU;
+ } else if (ins->r.bits == mkref(RICON, 1).bits) {
+ /* add x,1 -> inc x */
+ ins->op = Oxinc;
+ ins->r = NOREF;
+ goto ALU;
+ }
if (kisint(ins->cls) && (addarg4addrp(ins->l) || addarg4addrp(ins->r))) {
temp.op = Ocopy;
temp.cls = ins->cls;
diff --git a/op.def b/op.def
index 8bdfbbc..42b7c3c 100644
--- a/op.def
+++ b/op.def
@@ -67,3 +67,6 @@ _(arg, 2)
_(call, 2)
_(intrin, 2)
_(phi, 1)
+/* machine-specific instructions */
+_(xinc, 1)
+_(xdec, 1)
diff --git a/regalloc.c b/regalloc.c
index f03c33c..f001fee 100644
--- a/regalloc.c
+++ b/regalloc.c
@@ -219,6 +219,7 @@ regalloc(struct function *fn)
/* an in-place operation where the destination does not
* match the first operand, so we need to add a move */
insertinstr(blk, i, mkmove(ins->cls, ins->reg-1, ins->l.i));
+ ins->l.i = ins->reg-1;
}
}
}
diff --git a/test/test3.c b/test/test3.c
index c39d15b..8bd9020 100644
--- a/test/test3.c
+++ b/test/test3.c
@@ -12,10 +12,22 @@ int shcl(int a, int b) {
return a << (b+1);
}
-int div(int a,int b) {
- return a < 0 ? a / b : b / a;
+struct p { long x,y; };
+struct p divsh(int a) {
+ struct p p;
+ p.x = a << (a / 5);
+ p.y = a;
+ return p;
}
+struct bitset { unsigned long long u; };
+static inline void
+bscopy(struct bitset dst[/*siz*/], const struct bitset src[/*siz*/], unsigned siz)
+{
+ while (siz--) dst++->u = src++->u;
+}
+
+
#if 0
long test(long x) {
return x + (long)"abc";