fix exponential behavior of defwidthle()

This commit is contained in:
Quentin Carbonneaux 2026-05-05 15:22:12 +02:00
parent de6fdc1b8c
commit e01207f772
3 changed files with 55 additions and 29 deletions

6
all.h
View File

@ -240,11 +240,11 @@ struct Ins {
struct Phi { struct Phi {
Ref to; Ref to;
short cls;
int visit;
uint narg;
Ref *arg; Ref *arg;
Blk **blk; Blk **blk;
uint narg;
short cls;
uint visit:1;
Phi *link; Phi *link;
}; };

59
copy.c
View File

@ -41,6 +41,20 @@ bitwidth(uint64_t v)
return n+v; return n+v;
} }
static int
visit(Fn *fn, Ref r, int w, int f(Fn *, Ref, int))
{
Blk *b;
Phi *p;
int ret;
ret = f(fn, r, w);
for (b=fn->start; b; b=b->link)
for (p=b->phi; p; p=p->link)
p->visit = 0;
return ret;
}
static int static int
uwl(Fn *fn, Ref r, int w) uwl(Fn *fn, Ref r, int w)
{ {
@ -107,15 +121,7 @@ uwl(Fn *fn, Ref r, int w)
static int static int
usewidthle(Fn *fn, Ref r, int w) usewidthle(Fn *fn, Ref r, int w)
{ {
Blk *b; return visit(fn, r, w, uwl);
Phi *p;
int ret;
ret = uwl(fn, r, w);
for (b=fn->start; b; b=b->link)
for (p=b->phi; p; p=p->link)
p->visit = 0;
return ret;
} }
static int static int
@ -124,9 +130,8 @@ min(int v1, int v2)
return v1 < v2 ? v1 : v2; return v1 < v2 ? v1 : v2;
} }
/* is the ref narrower than w bits */
static int static int
defwidthle(Fn *fn, Ref r, int w) dwl(Fn *fn, Ref r, int w)
{ {
Ext e; Ext e;
Tmp *t; Tmp *t;
@ -139,6 +144,8 @@ defwidthle(Fn *fn, Ref r, int w)
if (isconbits(fn, r, &v) if (isconbits(fn, r, &v)
&& bitwidth(v) <= w) && bitwidth(v) <= w)
return 1; return 1;
if (w <= 0)
return 0;
if (rtype(r) != RTmp) if (rtype(r) != RTmp)
return 0; return 0;
t = &fn->tmp[r.val]; t = &fn->tmp[r.val];
@ -151,21 +158,18 @@ defwidthle(Fn *fn, Ref r, int w)
if (req(p->to, r)) if (req(p->to, r))
break; break;
assert(p); assert(p);
if (p->visit) if (p->visit && p->visit <= w)
return 1; return 1;
p->visit = 1; p->visit = w;
for (n=0; n<p->narg; n++) for (n=0; n<p->narg; n++)
if (!defwidthle(fn, p->arg[n], w)) { if (!dwl(fn, p->arg[n], w))
p->visit = 0;
return 0; return 0;
}
p->visit = 0;
return 1; return 1;
} }
i = t->def; i = t->def;
if (i->op == Ocopy) if (i->op == Ocopy)
return defwidthle(fn, i->arg[0], w); return dwl(fn, i->arg[0], w);
if (i->op == Oshr || i->op == Osar) { if (i->op == Oshr || i->op == Osar) {
if (isconbits(fn, i->arg[1], &v)) if (isconbits(fn, i->arg[1], &v))
if (0 < v && v <= 32) { if (0 < v && v <= 32) {
@ -178,19 +182,19 @@ defwidthle(Fn *fn, Ref r, int w)
w = min(32, w+v); w = min(32, w+v);
} }
} }
return defwidthle(fn, i->arg[0], w); return dwl(fn, i->arg[0], w);
} }
if (iscmp(i->op, &x, &x)) if (iscmp(i->op, &x, &x))
return w >= 1; return w >= 1;
if (i->op == Oand) { if (i->op == Oand) {
if (defwidthle(fn, i->arg[0], w) if (dwl(fn, i->arg[0], w)
|| defwidthle(fn, i->arg[1], w)) || dwl(fn, i->arg[1], w))
return 1; return 1;
return 0; return 0;
} }
if (i->op == Oor || i->op == Oxor) { if (i->op == Oor || i->op == Oxor) {
if (defwidthle(fn, i->arg[0], w) if (dwl(fn, i->arg[0], w)
&& defwidthle(fn, i->arg[1], w)) && dwl(fn, i->arg[1], w))
return 1; return 1;
return 0; return 0;
} }
@ -198,12 +202,19 @@ defwidthle(Fn *fn, Ref r, int w)
if (e.zext && e.usew <= w) if (e.zext && e.usew <= w)
return 1; return 1;
w = min(w, e.nopw); w = min(w, e.nopw);
return defwidthle(fn, i->arg[0], w); return dwl(fn, i->arg[0], w);
} }
return 0; return 0;
} }
/* is the ref narrower than w bits */
static int
defwidthle(Fn *fn, Ref r, int w)
{
return visit(fn, r, w, dwl);
}
static int static int
isw1(Fn *fn, Ref r) isw1(Fn *fn, Ref r)
{ {

View File

@ -8,8 +8,23 @@ export function w $f() {
ret %c ret %c
} }
export function w $g(w %arg) {
@start
%a0 =w extuh %arg # 1
%a1 =w or 65536, %a0 # 65537
@loop
%a2 =w phi @loop %a2, @start %a1 # 65537
jnz %arg, @end, @loop
@end
%a3 =w shr %a2, 1 # 32768
%a4 =w or %a2, 1 # 65537
%a5 =w or %a3, %a4 # 98305
%ret =w extuh %a5 # 32769
ret %ret
}
# >>> driver # >>> driver
# char a = -1; # char a = -1;
# extern int f(); # extern int f(), g(int);
# int main() { return !(f() == 1); } # int main() { return !(f() == 1 && g(1) == 32769); }
# <<< # <<<