aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorlemon <lsof@mailbox.org>2026-03-22 19:25:46 +0100
committerlemon <lsof@mailbox.org>2026-03-22 19:25:46 +0100
commitcbca5355c0c0b1910735b1430e2552855a2aa5c7 (patch)
tree7a0e0452f8dba566a5c7c0ed20dc4a60084bbea8
parent2d0b096a8c2f45370ef2535e1c500a008b949611 (diff)
aarch64: rem/urem, bswap*, arg bugfix
-rw-r--r--src/ir_op.def3
-rw-r--r--src/ir_regalloc.c12
-rw-r--r--src/t_aarch64_emit.c22
-rw-r--r--src/t_aarch64_isel.c40
-rwxr-xr-xtest/run.sh2
5 files changed, 67 insertions, 12 deletions
diff --git a/src/ir_op.def b/src/ir_op.def
index 4e775a1..dde4e10 100644
--- a/src/ir_op.def
+++ b/src/ir_op.def
@@ -75,5 +75,6 @@ _(phi, 1)
_(swap, 2)
_(vastart, 1)
_(vaarg, 2)
-/* machine-specific instructions */
+/* machine-specific/internal instructions */
_(xvaprologue, 1)
+_(msub, 3)
diff --git a/src/ir_regalloc.c b/src/ir_regalloc.c
index 41a4026..3b204c6 100644
--- a/src/ir_regalloc.c
+++ b/src/ir_regalloc.c
@@ -725,9 +725,9 @@ buildintervals(RegAlloc *ra)
queue[0] = ins->r;
} else {
switch ((nqueue = opnarg[ins->op])) {
- case 2: queue[2] = ins->oper[2];
- case 1: queue[1] = ins->oper[1];
- case 0: queue[0] = ins->oper[0];
+ case 3: queue[2] = ins->oper[2];
+ case 2: queue[1] = ins->oper[1];
+ case 1: queue[0] = ins->oper[0];
}
}
if (0) {
@@ -1148,15 +1148,15 @@ devirt(RegAlloc *ra, Block *blk)
Interval *it;
Alloc *alloc;
IRAddr newaddr;
- Ref *argref[4];
+ Ref *argref[6];
int curi0;
int naddr = 0;
int nargref = 0;
int nspill = 0;
/** devirtualize operands **/
- for (int i = 0; i < 2; ++i) {
- Ref *r = &i[&ins->l];
+ for (int i = 0; i < 3; ++i) {
+ Ref *r = &ins->oper[i];
if (r->t == RADDR) {
IRAddr *a = &addrtab.p[r->i];
++naddr;
diff --git a/src/t_aarch64_emit.c b/src/t_aarch64_emit.c
index 4679569..abf1f3e 100644
--- a/src/t_aarch64_emit.c
+++ b/src/t_aarch64_emit.c
@@ -227,6 +227,9 @@ encode(uchar **pcode, const EncDesc *tab, int ntab, enum irclass k, Oper o[3])
case EN_ADDSUBSHFT3R: case EN_LOGSHFT3R:
ins |= sf<<31 | o[2].shft<<22 | o[2].reg<<16 | o[2].shamt<<10 | o[1].reg<<5 | o[0].reg;
break;
+ case EN_ARITH2R:
+ ins |= sf<<31 | o[1].reg<<5 | o[0].reg;
+ break;
case EN_ARITH3R:
ins |= sf<<31 | o[2].reg<<16 | o[1].reg<<5 | o[0].reg;
break;
@@ -352,6 +355,15 @@ Xmadd(uchar **pcode, enum irclass k, Oper d, Oper n, Oper m, Oper a)
W32(0x1B000000 | sf<<31 | m.reg<<16 | a.reg<<10 | n.reg<<5 | d.reg);
}
+static void
+Xmsub(uchar **pcode, enum irclass k, Oper d, Oper n, Oper m, Oper a)
+{
+ assert(opermatch(PGPRZ, k, d) && opermatch(PGPRZ, k, n)
+ && opermatch(PGPRZ, k, a) && opermatch(PGPRZ, k, m));
+ uint sf = k > KI32;
+ W32(0x1B008000 | sf<<31 | m.reg<<16 | a.reg<<10 | n.reg<<5 | d.reg);
+}
+
DEFINSTR3(Xsdiv, {4|8, {PGPRZ, PGPRZ, PGPRZ}, 0x1AC00C00, EN_ARITH3R})
DEFINSTR3(Xudiv, {4|8, {PGPRZ, PGPRZ, PGPRZ}, 0x1AC00800, EN_ARITH3R})
@@ -515,6 +527,10 @@ DEFINSTR2(Xfcmp,
{4|8, {PFPR, PZERO}, 0x1E602008, EN_FPCMPZ},
{4|8, {PFPR, PFPR}, 0x1E602000, EN_FPCMP},
)
+DEFINSTR2(Xrev,
+ {4 , {PGPRZ, PGPRZ}, 0x5AC00800, EN_ARITH2R},
+ { 8, {PGPRZ, PGPRZ}, 0xDAC00C00, EN_ARITH2R},
+)
static void
gencopy(uchar **pcode, enum irclass cls, Block *blk, int curi, Oper dst, Ref val)
@@ -744,12 +760,18 @@ emitinstr(uchar **pcode, Function *fn, Block *blk, int curi, Instr *ins)
Cvt:
X2(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l));
break;
+ case Obswap32: case Obswap64:
+ Xrev(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l));
+ break;
case Oadd: X3 = kisint(cls) ? Xadd : Xfadd; goto ALU3;
case Osub: X3 = kisint(cls) ? Xsub : Xfsub; goto ALU3;
case Omul: if (kisflt(cls)) { X3 = Xfmul; goto ALU3; }
/* MUL Rd,Rn,Rm ==> MADD Rd,Rn,Rm,zr */
Xmadd(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), ref2oper(ins->r), REGZR);
break;
+ case Omsub:
+ Xmsub(pcode, cls, reg2oper(ins->reg-1), ref2oper(ins->l), ref2oper(ins->r), ref2oper(ins->oper[2]));
+ break;
case Odiv: X3 = kisint(cls) ? Xsdiv : Xfdiv; goto ALU3;
case Oudiv: X3 = Xudiv; goto ALU3;
case Oand: X3 = Xand; goto ALU3;
diff --git a/src/t_aarch64_isel.c b/src/t_aarch64_isel.c
index 381a57d..29056bc 100644
--- a/src/t_aarch64_isel.c
+++ b/src/t_aarch64_isel.c
@@ -137,7 +137,15 @@ fixarg(Ref *r, Instr *ins, Block *blk, int *curi)
else
*r = insertinstr(blk, (*curi)++, adr);
} else if (r->t != RTMP) Reg: {
- regarg(r, r->t == RTMP ? instrtab[r->i].cls : ins->cls ? ins->cls : KI32, blk, curi);
+ enum irclass k;
+ if (r->t == RTMP) k = insrescls(instrtab[r->i]);
+ else if (ins->op == Oarg) {
+ IRType ty = ref2type(ins->l);
+ k = ty.isagg ? KPTR : ty.cls;
+ } else {
+ k = ins->cls;
+ }
+ regarg(r, k, blk, curi);
}
}
@@ -351,8 +359,9 @@ loadstoreaddr(Block *blk, Ref *r, int *curi, enum op op)
static void
sel(Function *fn, Instr *ins, Block *blk, int *curi)
{
- enum op op = ins->op;
+ Ref tmp;
enum irclass cls;
+ enum op op = ins->op;
if (oisarith(ins->op) && arithfold(ins)) {
fixarg(&ins->l, ins, blk, curi);
@@ -390,6 +399,18 @@ sel(Function *fn, Instr *ins, Block *blk, int *curi)
regarg(&ins->l, ins->cls, blk, curi);
ins->op = Ocopy;
break;
+ case Obswap32: case Obswap64:
+ regarg(&ins->l, ins->cls, blk, curi);
+ break;
+ case Obswap16:
+ /* %tmp = rev %x
+ * %res = lsr %tmp, 16 */
+ regarg(&ins->l, ins->cls, blk, curi);
+ tmp = insertinstr(blk, (*curi)++, mkinstr1(Obswap32, KI32, ins->l));
+ ins->op = Oslr;
+ ins->l = tmp;
+ ins->r = mkref(RICON, 16);
+ break;
case Oadd:
if (isnumcon(ins->l)) {
/* swap to have const in rhs */
@@ -409,7 +430,7 @@ sel(Function *fn, Instr *ins, Block *blk, int *curi)
case Oand: case Oior: case Oxor:
if (isnumcon(ins->l)) {
/* swap to have const in rhs */
- Ref tmp = ins->l;
+ tmp = ins->l;
ins->l = ins->r;
ins->r = tmp;
}
@@ -421,9 +442,20 @@ sel(Function *fn, Instr *ins, Block *blk, int *curi)
regarg(&ins->l, ins->cls, blk, curi);
fixarg(&ins->r, ins, blk, curi);
break;
- case Omul: case Odiv: case Oudiv: case Ourem:
+ case Omul: case Odiv: case Oudiv:
+ regarg(&ins->l, ins->cls, blk, curi);
+ regarg(&ins->r, ins->cls, blk, curi);
+ break;
+ case Orem: case Ourem:
regarg(&ins->l, ins->cls, blk, curi);
regarg(&ins->r, ins->cls, blk, curi);
+ /* %tmp = div %l, %r
+ * %res = msub %tmp, %r, %l */
+ tmp = insertinstr(blk, (*curi)++,
+ mkinstr2(op == Orem ? Odiv : Oudiv, ins->cls, ins->l, ins->r));
+ ins->op = Omsub;
+ ins->oper[2] = ins->l;
+ ins->oper[0] = tmp;
break;
case Oarg:
fixarg(&ins->r, ins, blk, curi);
diff --git a/test/run.sh b/test/run.sh
index ec40161..07f967e 100755
--- a/test/run.sh
+++ b/test/run.sh
@@ -26,7 +26,7 @@ run() {
echo '-------'
else
actual=build/"$(echo "$f" | sed 's/\.c$/.actual/')"
- x "$exe" $args > "$actual"
+ x $QEMU "$exe" $args > "$actual"
if ! cmp "$actual" "$expected" > /dev/null; then
echo --- !TEST ERROR "$f"
diff --unified=0 "$expected" "$actual"