diff options
Diffstat (limited to 'tools/pmov.c')
-rw-r--r-- | tools/pmov.c | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/tools/pmov.c b/tools/pmov.c new file mode 100644 index 0000000..efbecd7 --- /dev/null +++ b/tools/pmov.c @@ -0,0 +1,252 @@ +/*% rm -f rega.o main.o && cc -g -std=c99 -Wall -DTEST_PMOV -o # % *.o + * + * This is a test framwork for the dopm() function + * in rega.c, use it when you want to modify it or + * all the parallel move functions. + * + * You might need to decrease NIReg to see it + * terminate, I used NIReg == 7 at most. + */ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void assert_test(char *, int), fail(void), iexec(int *); + +#include "../rega.c" + +static RMap mbeg; +static Ins ins[NIReg], *ip; +static Blk dummyb = { .ins = ins }; + +int +main() +{ + Ins *i1; + unsigned long long tm, rm, cnt; + RMap mend; + int reg[NIReg], val[NIReg+1]; + int t, i, r, nr; + + tmp = (Tmp[Tmp0+NIReg]){{{0}}}; + for (t=0; t<Tmp0+NIReg; t++) + if (t >= Tmp0) { + tmp[t].cls = Kw; + tmp[t].hint.r = -1; + tmp[t].hint.m = 0; + tmp[t].slot = -1; + sprintf(tmp[t].name, "tmp%d", t-Tmp0+1); + } + + bsinit(mbeg.b, Tmp0+NIReg); + bsinit(mend.b, Tmp0+NIReg); + cnt = 0; + for (tm = 0; tm < 1ull << (2*NIReg); tm++) { + mbeg.n = 0; + bszero(mbeg.b); + ip = ins; + + /* find what temporaries are in copy and + * wether or not they are in register + */ + for (t=0; t<NIReg; t++) + switch ((tm >> (2*t)) & 3) { + case 0: + /* not in copy, not in reg */ + break; + case 1: + /* not in copy, in reg */ + radd(&mbeg, Tmp0+t, t+1); + break; + case 2: + /* in copy, not in reg */ + *ip++ = (Ins){OCopy, TMP(Tmp0+t), {R, R}, Kw}; + break; + case 3: + /* in copy, in reg */ + *ip++ = (Ins){OCopy, TMP(Tmp0+t), {R, R}, Kw}; + radd(&mbeg, Tmp0+t, t+1); + break; + } + + if (ip == ins) + /* cancel if the parallel move + * is empty + */ + goto Nxt; + + /* find registers for temporaries + * in mbeg + */ + nr = ip - ins; + rm = (1ull << (nr+1)) - 1; + for (i=0; i<nr; i++) + reg[i] = i+1; + + for (;;) { + /* set registers on copies + */ + for (i=0, i1=ins; i1<ip; i1++, i++) + i1->arg[0] = TMP(reg[i]); + + /* compile the parallel move + */ + rcopy(&mend, &mbeg); + dopm(&dummyb, ip-1, &mend); + cnt++; + + /* check that mend contain mappings for + * source registers and does not map any + * assigned temporary, then check that + * all temporaries in mend are mapped in + * mbeg and not used in the copy + */ + for (i1=ins; i1<ip; i1++) { + r = i1->arg[0].val; + assert(rfree(&mend, r) == r); + t = i1->to.val; + assert(!bshas(mend.b, t)); + } + for (i=0; i<mend.n; i++) { + t = mend.t[i]; + assert(bshas(mbeg.b, t)); + t -= Tmp0; + assert(((tm >> (2*t)) & 3) == 1); + } + + /* execute the code generated and check + * that all assigned temporaries got their + * value, and that all live variables's + * content got preserved + */ + for (i=1; i<=NIReg; i++) + val[i] = i; + iexec(val); + for (i1=ins; i1<ip; i1++) { + t = i1->to.val; + r = rfind(&mbeg, t); + if (r != -1) + assert(val[r] == i1->arg[0].val); + } + for (i=0; i<mend.n; i++) { + t = mend.t[i]; + r = mend.r[i]; + assert(val[t-Tmp0+1] == r); + } + + /* find the next register assignment */ + i = nr - 1; + for (;;) { + r = reg[i]; + rm &= ~(1ull<<r); + do + r++; + while (r <= NIReg && (rm & (1ull<<r))); + if (r == NIReg+1) { + if (i == 0) + goto Nxt; + i--; + } else { + rm |= (1ull<<r); + reg[i++] = r; + break; + } + } + for (; i<nr; i++) + for (r=1; r<=NIReg; r++) + if (!(rm & (1ull<<r))) { + rm |= (1ull<<r); + reg[i] = r; + break; + } + } + Nxt: ; + } + printf("%llu tests successful!\n", cnt); + exit(0); +} + + +/* execute what pmgen() wrote (swap, copy) */ + +#define validr(r) \ + rtype(r) == RTmp && \ + r.val > 0 && \ + r.val <= NIReg + +static void +iexec(int val[]) +{ + Ins *i; + int t; + + for (i=insb; i<curi; i++) + switch (i->op) { + default: + assert(!"iexec: missing case\n"); + exit(1); + case OSwap: + assert(validr(i->arg[0])); + assert(validr(i->arg[1])); + t = val[i->arg[0].val]; + val[i->arg[0].val] = val[i->arg[1].val]; + val[i->arg[1].val] = t; + break; + case OCopy: + assert(validr(i->to)); + assert(validr(i->arg[0])); + val[i->to.val] = val[i->arg[0].val]; + break; + } +} + + +/* failure diagnostics */ + +static int re; + +static void +replay() +{ + RMap mend; + + re = 1; + bsinit(mend.b, Tmp0+NIReg); + rcopy(&mend, &mbeg); + dopm(&dummyb, ip-1, &mend); +} + +static void +fail() +{ + Ins *i1; + int i; + + printf("\nIn registers: "); + for (i=0; i<mbeg.n; i++) + printf("%s(r%d) ", + tmp[mbeg.t[i]].name, + mbeg.r[i]); + printf("\n"); + printf("Parallel move:\n"); + for (i1=ins; i1<ip; i1++) + printf("\t %s <- r%d\n", + tmp[i1->to.val].name, + i1->arg[0].val); + replay(); + abort(); +} + +static void +assert_test(char *s, int x) +{ + if (x) + return; + if (re) + abort(); + printf("!assertion failure: %s\n", s); + fail(); +} + +/* symbols required by the linker */ +char debug['Z'+1]; |