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 {
Ref to;
short cls;
int visit;
uint narg;
Ref *arg;
Blk **blk;
uint narg;
short cls;
uint visit:1;
Phi *link;
};

59
copy.c
View File

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

View File

@ -8,8 +8,23 @@ export function w $f() {
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
# char a = -1;
# extern int f();
# int main() { return !(f() == 1); }
# extern int f(), g(int);
# int main() { return !(f() == 1 && g(1) == 32769); }
# <<<