aboutsummaryrefslogtreecommitdiff
path: root/tools/pmov.c
diff options
context:
space:
mode:
authorQuentin Carbonneaux <[email protected]>2016-03-27 18:17:08 -0400
committerQuentin Carbonneaux <[email protected]>2016-03-27 18:17:08 -0400
commitda640c5a467bfdf7b3bbced52fc13a28fd8b37bd (patch)
treecf5a4af994ac8b8f7357bbf3414c4179f94321ad /tools/pmov.c
parente38c61d95fccd208e13dd14a31a567c3d431677a (diff)
move tools to the root
Diffstat (limited to 'tools/pmov.c')
-rw-r--r--tools/pmov.c252
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];