parseref() has code to reuse address constants, but this is not done in other passes such as fold or isel. Introduce a new function newcon() which takes a Con and returns a Ref for that constant, and use this whenever creating address constants. This is necessary to fix folding of address constants when one operand is already folded. For example, in %a =l add $x, 1 %b =l add %a, 2 %c =w loadw %b %a and %b were folded to $x+1 and $x+3 respectively, but then the second add is visited again since it uses %a. This gets folded to $x+3 as well, but as a new distinct constant. This results in %b getting labeled as bottom instead of either constant, disabling the replacement of %b by a constant in subsequent instructions (such as the loadw).
Unified · Split
| @@ -431,6 +431,7 @@ int clsmerge(short *, short); · 430 unmodified lines | |||
| 431 | int phicls(int, Tmp *); | 431 | int phicls(int, Tmp *); |
| 432 | Ref newtmp(char *, int, Fn *); | 432 | Ref newtmp(char *, int, Fn *); |
| 433 | void chuse(Ref, int, Fn *); | 433 | void chuse(Ref, int, Fn *); |
| 434 | Ref newcon(Con *, Fn *); | ||
| 434 | Ref getcon(int64_t, Fn *); | 435 | Ref getcon(int64_t, Fn *); |
| 435 | int addcon(Con *, Con *); | 436 | int addcon(Con *, Con *); |
| 436 | void blit(Ref, uint, Ref, uint, Fn *); | 437 | void blit(Ref, uint, Ref, uint, Fn *); |
| @@ -117,12 +117,9 @@ fixarg(Ref *r, int k, Ins *i, Fn *fn) · 116 unmodified lines | |||
| 117 | m = &fn->mem[r0.val]; | 117 | m = &fn->mem[r0.val]; |
| 118 | if (req(m->base, R)) | 118 | if (req(m->base, R)) |
| 119 | if (m->offset.type == CAddr) { | 119 | if (m->offset.type == CAddr) { |
| 120 | n = fn->ncon; | ||
| 121 | vgrow(&fn->con, ++fn->ncon); | ||
| 122 | fn->con[n] = m->offset; | ||
| 123 | m->offset.type = CUndef; | ||
| 124 | r0 = newtmp("isel", Kl, fn); | 120 | r0 = newtmp("isel", Kl, fn); |
| 125 | emit(Oaddr, Kl, r0, CON(n), R); | 121 | emit(Oaddr, Kl, r0, newcon(&m->offset, fn), R); |
| 122 | m->offset.type = CUndef; | ||
| 126 | m->base = r0; | 123 | m->base = r0; |
| 127 | } | 124 | } |
| 128 | } | 125 | } |
| @@ -496,7 +496,7 @@ foldflt(Con *res, int op, int w, Con *cl, Con *cr) · 495 unmodified lines | |||
| 496 | static int | 496 | static int |
| 497 | opfold(int op, int cls, Con *cl, Con *cr, Fn *fn) | 497 | opfold(int op, int cls, Con *cl, Con *cr, Fn *fn) |
| 498 | { | 498 | { |
| 499 | int nc; | 499 | Ref r; |
| 500 | Con c; | 500 | Con c; |
| 501 | 501 | ||
| 502 | if ((op == Odiv || op == Oudiv | 502 | if ((op == Odiv || op == Oudiv |
| @@ -507,13 +507,7 @@ opfold(int op, int cls, Con *cl, Con *cr, Fn *fn) · 4 unmodified lines | |||
| 507 | return Bot; | 507 | return Bot; |
| 508 | } else | 508 | } else |
| 509 | foldflt(&c, op, cls == Kd, cl, cr); | 509 | foldflt(&c, op, cls == Kd, cl, cr); |
| 510 | if (c.type == CBits) | 510 | r = newcon(&c, fn); |
| 511 | nc = getcon(c.bits.i, fn).val; | ||
| 512 | else { | ||
| 513 | nc = fn->ncon; | ||
| 514 | vgrow(&fn->con, ++fn->ncon); | ||
| 515 | } | ||
| 516 | assert(!(cls == Ks || cls == Kd) || c.flt); | 511 | assert(!(cls == Ks || cls == Kd) || c.flt); |
| 517 | fn->con[nc] = c; | 512 | return r.val; |
| 518 | return nc; | ||
| 519 | } | 513 | } |
| @@ -118,7 +118,8 @@ load(Slice sl, bits msk, Loc *l) · 117 unmodified lines | |||
| 118 | { | 118 | { |
| 119 | Alias *a; | 119 | Alias *a; |
| 120 | Ref r, r1; | 120 | Ref r, r1; |
| 121 | int ld, cls, all, c; | 121 | int ld, cls, all; |
| 122 | Con c; | ||
| 122 | 123 | ||
| 123 | ld = (int[]){ | 124 | ld = (int[]){ |
| 124 | [1] = Oloadub, | 125 | [1] = Oloadub, |
| @@ -151,13 +152,11 @@ load(Slice sl, bits msk, Loc *l) · 26 unmodified lines | |||
| 151 | break; | 152 | break; |
| 152 | case ACon: | 153 | case ACon: |
| 153 | case ASym: | 154 | case ASym: |
| 154 | c = curf->ncon++; | 155 | c.type = CAddr; |
| 155 | vgrow(&curf->con, curf->ncon); | 156 | c.label = a->label; |
| 156 | curf->con[c].type = CAddr; | 157 | c.bits.i = a->offset; |
| 157 | curf->con[c].label = a->label; | 158 | c.local = 0; |
| 158 | curf->con[c].bits.i = a->offset; | 159 | r = newcon(&c, curf); |
| 159 | curf->con[c].local = 0; | ||
| 160 | r = CON(c); | ||
| 161 | break; | 160 | break; |
| 162 | } | 161 | } |
| 163 | } | 162 | } |
| @@ -381,7 +381,6 @@ static Ref · 380 unmodified lines | |||
| 381 | parseref() | 381 | parseref() |
| 382 | { | 382 | { |
| 383 | Con c; | 383 | Con c; |
| 384 | int i; | ||
| 385 | 384 | ||
| 386 | memset(&c, 0, sizeof c); | 385 | memset(&c, 0, sizeof c); |
| 387 | switch (next()) { | 386 | switch (next()) { |
| @@ -405,14 +404,7 @@ parseref() · 17 unmodified lines | |||
| 405 | c.type = CAddr; | 404 | c.type = CAddr; |
| 406 | c.label = intern(tokval.str); | 405 | c.label = intern(tokval.str); |
| 407 | Look: | 406 | Look: |
| 408 | for (i=0; i<curf->ncon; i++) | 407 | return newcon(&c, curf); |
| 409 | if (curf->con[i].type == c.type | ||
| 410 | && curf->con[i].bits.i == c.bits.i | ||
| 411 | && curf->con[i].label == c.label) | ||
| 412 | return CON(i); | ||
| 413 | vgrow(&curf->con, ++curf->ncon); | ||
| 414 | curf->con[i] = c; | ||
| 415 | return CON(i); | ||
| 416 | default: | 408 | default: |
| 417 | return R; | 409 | return R; |
| 418 | } | 410 | } |
| @@ -349,6 +349,25 @@ chuse(Ref r, int du, Fn *fn) · 348 unmodified lines | |||
| 349 | fn->tmp[r.val].nuse += du; | 349 | fn->tmp[r.val].nuse += du; |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | Ref | ||
| 353 | newcon(Con *c0, Fn *fn) | ||
| 354 | { | ||
| 355 | Con *c1; | ||
| 356 | int i; | ||
| 357 | |||
| 358 | for (i=0; i<fn->ncon; i++) { | ||
| 359 | c1 = &fn->con[i]; | ||
| 360 | if (c0->type == c1->type | ||
| 361 | && c0->bits.i == c1->bits.i | ||
| 362 | && c0->label == c1->label | ||
| 363 | && c0->local == c1->local) | ||
| 364 | return CON(i); | ||
| 365 | } | ||
| 366 | vgrow(&fn->con, ++fn->ncon); | ||
| 367 | fn->con[i] = *c0; | ||
| 368 | return CON(i); | ||
| 369 | } | ||
| 370 | |||
| 352 | Ref | 371 | Ref |
| 353 | getcon(int64_t val, Fn *fn) | 372 | getcon(int64_t val, Fn *fn) |
| 354 | { | 373 | { |