fix sub-word returns on arm64_apple
[qbe.git] / tools / pmov.c
blobffc38eaf042dc3824949d0f03a8b0734a6d89611
1 /*% rm -f rega.o main.o && cc -g -std=c99 -Wall -DTEST_PMOV -o pmov % *.o
3 * This is a test framwork for the dopm() function
4 * in rega.c, use it when you want to modify it or
5 * all the parallel move functions.
7 * You might need to decrease NIReg to see it
8 * terminate, I used NIReg == 7 at most.
9 */
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
14 static void assert_test(char *, int), fail(void), iexec(int *);
16 #include "../../rega.c"
18 static void bsinit_(BSet *, uint);
20 static RMap mbeg;
21 static Ins ins[NIReg], *ip;
22 static Blk dummyb = { .ins = ins };
24 int
25 main()
27 Ins *i1;
28 unsigned long long tm, rm, cnt;
29 RMap mend;
30 int reg[NIReg], val[NIReg+1];
31 int t, i, r, nr;
33 tmp = (Tmp[Tmp0+NIReg]){{{0}}};
34 for (t=0; t<Tmp0+NIReg; t++)
35 if (t >= Tmp0) {
36 tmp[t].cls = Kw;
37 tmp[t].hint.r = -1;
38 tmp[t].hint.m = 0;
39 tmp[t].slot = -1;
40 sprintf(tmp[t].name, "tmp%d", t-Tmp0+1);
43 bsinit_(mbeg.b, Tmp0+NIReg);
44 bsinit_(mend.b, Tmp0+NIReg);
45 cnt = 0;
46 for (tm = 0; tm < 1ull << (2*NIReg); tm++) {
47 mbeg.n = 0;
48 bszero(mbeg.b);
49 ip = ins;
51 /* find what temporaries are in copy and
52 * wether or not they are in register
54 for (t=0; t<NIReg; t++)
55 switch ((tm >> (2*t)) & 3) {
56 case 0:
57 /* not in copy, not in reg */
58 break;
59 case 1:
60 /* not in copy, in reg */
61 radd(&mbeg, Tmp0+t, t+1);
62 break;
63 case 2:
64 /* in copy, not in reg */
65 *ip++ = (Ins){OCopy, Kw, TMP(Tmp0+t), {R, R}};
66 break;
67 case 3:
68 /* in copy, in reg */
69 *ip++ = (Ins){OCopy, Kw, TMP(Tmp0+t), {R, R}};
70 radd(&mbeg, Tmp0+t, t+1);
71 break;
74 if (ip == ins)
75 /* cancel if the parallel move
76 * is empty
78 goto Nxt;
80 /* find registers for temporaries
81 * in mbeg
83 nr = ip - ins;
84 rm = (1ull << (nr+1)) - 1;
85 for (i=0; i<nr; i++)
86 reg[i] = i+1;
88 for (;;) {
89 /* set registers on copies
91 for (i=0, i1=ins; i1<ip; i1++, i++)
92 i1->arg[0] = TMP(reg[i]);
94 /* compile the parallel move
96 rcopy(&mend, &mbeg);
97 dopm(&dummyb, ip-1, &mend);
98 cnt++;
100 /* check that mend contain mappings for
101 * source registers and does not map any
102 * assigned temporary, then check that
103 * all temporaries in mend are mapped in
104 * mbeg and not used in the copy
106 for (i1=ins; i1<ip; i1++) {
107 r = i1->arg[0].val;
108 assert(rfree(&mend, r) == r);
109 t = i1->to.val;
110 assert(!bshas(mend.b, t));
112 for (i=0; i<mend.n; i++) {
113 t = mend.t[i];
114 assert(bshas(mbeg.b, t));
115 t -= Tmp0;
116 assert(((tm >> (2*t)) & 3) == 1);
119 /* execute the code generated and check
120 * that all assigned temporaries got their
121 * value, and that all live variables's
122 * content got preserved
124 for (i=1; i<=NIReg; i++)
125 val[i] = i;
126 iexec(val);
127 for (i1=ins; i1<ip; i1++) {
128 t = i1->to.val;
129 r = rfind(&mbeg, t);
130 if (r != -1)
131 assert(val[r] == i1->arg[0].val);
133 for (i=0; i<mend.n; i++) {
134 t = mend.t[i];
135 r = mend.r[i];
136 assert(val[t-Tmp0+1] == r);
139 /* find the next register assignment */
140 i = nr - 1;
141 for (;;) {
142 r = reg[i];
143 rm &= ~(1ull<<r);
145 r++;
146 while (r <= NIReg && (rm & (1ull<<r)));
147 if (r == NIReg+1) {
148 if (i == 0)
149 goto Nxt;
150 i--;
151 } else {
152 rm |= (1ull<<r);
153 reg[i++] = r;
154 break;
157 for (; i<nr; i++)
158 for (r=1; r<=NIReg; r++)
159 if (!(rm & (1ull<<r))) {
160 rm |= (1ull<<r);
161 reg[i] = r;
162 break;
165 Nxt: freeall();
167 printf("%llu tests successful!\n", cnt);
168 exit(0);
172 /* execute what pmgen() wrote (swap, copy) */
174 #define validr(r) \
175 rtype(r) == RTmp && \
176 r.val > 0 && \
177 r.val <= NIReg
179 static void
180 iexec(int val[])
182 Ins *i;
183 int t;
185 for (i=insb; i<curi; i++)
186 switch (i->op) {
187 default:
188 assert(!"iexec: missing case\n");
189 exit(1);
190 case OSwap:
191 assert(validr(i->arg[0]));
192 assert(validr(i->arg[1]));
193 t = val[i->arg[0].val];
194 val[i->arg[0].val] = val[i->arg[1].val];
195 val[i->arg[1].val] = t;
196 break;
197 case OCopy:
198 assert(validr(i->to));
199 assert(validr(i->arg[0]));
200 val[i->to.val] = val[i->arg[0].val];
201 break;
206 /* failure diagnostics */
208 static int re;
210 static void
211 replay()
213 RMap mend;
215 re = 1;
216 bsinit_(mend.b, Tmp0+NIReg);
217 rcopy(&mend, &mbeg);
218 dopm(&dummyb, ip-1, &mend);
221 static void
222 fail()
224 Ins *i1;
225 int i;
227 printf("\nIn registers: ");
228 for (i=0; i<mbeg.n; i++)
229 printf("%s(r%d) ",
230 tmp[mbeg.t[i]].name,
231 mbeg.r[i]);
232 printf("\n");
233 printf("Parallel move:\n");
234 for (i1=ins; i1<ip; i1++)
235 printf("\t %s <- r%d\n",
236 tmp[i1->to.val].name,
237 i1->arg[0].val);
238 replay();
239 abort();
242 static void
243 assert_test(char *s, int x)
245 if (x)
246 return;
247 if (re)
248 abort();
249 printf("!assertion failure: %s\n", s);
250 fail();
253 static void
254 bsinit_(BSet *bs, uint n)
256 n = (n + NBit-1) / NBit;
257 bs->nt = n;
258 bs->t = emalloc(n * sizeof bs->t[0]);
261 /* symbols required by the linker */
262 char debug['Z'+1];