fold scaled offsets in addresses

This commit is contained in:
Quentin Carbonneaux 2024-04-11 10:28:41 +02:00
parent 8e8f706436
commit 4a809d69b5
5 changed files with 79 additions and 11 deletions

2
all.h
View file

@ -484,7 +484,7 @@ void chuse(Ref, int, Fn *);
int symeq(Sym, Sym); int symeq(Sym, Sym);
Ref newcon(Con *, Fn *); Ref newcon(Con *, Fn *);
Ref getcon(int64_t, Fn *); Ref getcon(int64_t, Fn *);
int addcon(Con *, Con *); int addcon(Con *, Con *, int);
void salloc(Ref, Ref, Fn *); void salloc(Ref, Ref, Fn *);
void dumpts(BSet *, Tmp *, FILE *); void dumpts(BSet *, Tmp *, FILE *);
void runmatch(uchar *, Num *, Ref, Ref *); void runmatch(uchar *, Num *, Ref, Ref *);

View file

@ -293,7 +293,7 @@ Next:
if (rtype(m->base) == RSlot) { if (rtype(m->base) == RSlot) {
off.type = CBits; off.type = CBits;
off.bits.i = slot(m->base, fn); off.bits.i = slot(m->base, fn);
addcon(&m->offset, &off); addcon(&m->offset, &off, 1);
m->base = TMP(RBP); m->base = TMP(RBP);
} }
if (m->offset.type != CUndef) if (m->offset.type != CUndef)

View file

@ -692,7 +692,7 @@ anumber(Num *tn, Blk *b, Con *con)
} }
static Ref static Ref
adisp(Con *c, Num *tn, Ref r, Fn *fn) adisp(Con *c, Num *tn, Ref r, Fn *fn, int s)
{ {
Ref v[2]; Ref v[2];
int n; int n;
@ -704,7 +704,7 @@ adisp(Con *c, Num *tn, Ref r, Fn *fn)
break; break;
runmatch(matcher[Pob], tn, r, v); runmatch(matcher[Pob], tn, r, v);
assert(rtype(v[0]) == RCon); assert(rtype(v[0]) == RCon);
addcon(c, &fn->con[v[0].val]); addcon(c, &fn->con[v[0].val], s);
r = v[1]; r = v[1];
} }
return r; return r;
@ -733,18 +733,18 @@ amatch(Addr *a, Num *tn, Ref r, Fn *fn)
memset(&co, 0, sizeof co); memset(&co, 0, sizeof co);
ro = v[0]; ro = v[0];
rb = adisp(&co, tn, v[1], fn); rb = adisp(&co, tn, v[1], fn, 1);
ri = v[2]; ri = v[2];
rs = v[3]; rs = v[3];
s = 1; s = 1;
if (*p < 0 && co.type != CUndef) if (*p < 0 && co.type != CUndef)
if (amatch(a, tn, rb, fn)) if (amatch(a, tn, rb, fn))
return addcon(&a->offset, &co); return addcon(&a->offset, &co, 1);
if (!req(ro, R)) { if (!req(ro, R)) {
assert(rtype(ro) == RCon); assert(rtype(ro) == RCon);
c = &fn->con[ro.val]; c = &fn->con[ro.val];
if (!addcon(&co, c)) if (!addcon(&co, c, 1))
return 0; return 0;
} }
if (!req(rs, R)) { if (!req(rs, R)) {
@ -753,6 +753,7 @@ amatch(Addr *a, Num *tn, Ref r, Fn *fn)
assert(c->type = CBits); assert(c->type = CBits);
s = c->bits.i; s = c->bits.i;
} }
ri = adisp(&co, tn, ri, fn, s);
*a = (Addr){co, rb, ri, s}; *a = (Addr){co, rb, ri, s};
if (rtype(ri) == RTmp) if (rtype(ri) == RTmp)

64
test/isel4.ssa Normal file
View file

@ -0,0 +1,64 @@
# amd64 address-folding stress
export function w $f0(l %a, l %b) {
@start
%c =l add %b, 2
%d =l mul %c, 4
%e =l add %a, %d
%q =l loadw %e
ret %q
}
export function w $f1(l %a, l %b) {
@start
%c =l add 1, %b
%f =l add %c, 1
%d =l mul %f, 4
%e =l add %d, %a
%q =l loadw %e
ret %q
}
export function w $f2(l %a, l %b) {
@start
%l =l mul %b, 4
%d =l add 8, %l
%e =l add %a, %d
%q =l loadw %e
ret %q
}
# fixme: folding is not good here
export function w $f3(l %a, l %b) {
@start
%l =l mul %b, 4
%d =l add 4, %l
%f =l add 4, %d
%e =l add %a, %f
%q =l loadw %e
ret %q
}
export function w $f4(l %a, l %b) {
@start
%c =l add 1, %b
%d =l mul %c, 4
%e =l add 4, %d
%f =l add %e, %a
%q =l loadw %f
ret %q
}
# >>> driver
# int a[] = {1, 2, 3, 4};
# typedef int loadf(int *, long long);
# extern loadf f0, f1, f2, f3, f4;
# loadf *fns[] = {&f0, &f1, &f2, &f3, &f4, 0};
# int main() {
# loadf **f;
# int n;
# for (n=1,f=fns; *f; f++,n++)
# if ((*f)(a, 1) != 4) return n;
# return 0;
# }
# <<<

11
util.c
View file

@ -398,18 +398,21 @@ getcon(int64_t val, Fn *fn)
} }
int int
addcon(Con *c0, Con *c1) addcon(Con *c0, Con *c1, int m)
{ {
if (c0->type == CUndef) if (m != 1 && c1->type == CAddr)
return 0;
if (c0->type == CUndef) {
*c0 = *c1; *c0 = *c1;
else { c0->bits.i *= m;
} else {
if (c1->type == CAddr) { if (c1->type == CAddr) {
if (c0->type == CAddr) if (c0->type == CAddr)
return 0; return 0;
c0->type = CAddr; c0->type = CAddr;
c0->sym = c1->sym; c0->sym = c1->sym;
} }
c0->bits.i += c1->bits.i; c0->bits.i += c1->bits.i * m;
} }
return 1; return 1;
} }