Develop and Download Open Source Software

Browse Subversion Repository

Contents of /branches/mty-makai/synth.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 252 - (show annotations) (download) (as text)
Mon Dec 27 03:23:48 2010 UTC (13 years, 3 months ago) by notanpe
File MIME type: text/x-csrc
File size: 28991 byte(s)
本家 R245 をベースに全てやりなおし。
1 /***********************************************************************
2 *
3 * file: synth.c
4 *
5 * 木から命令列を生成する
6 *
7 * $Id$
8 *
9 */
10
11 #include <assert.h>
12 #include <limits.h>
13 #include <stdarg.h>
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <sys/types.h>
18
19 #include "config.h"
20 #include "crypt64.h"
21 #include "debug.h"
22 #include "desconst.h"
23 #include "simplify.h"
24 #include "synth.h"
25 #include "util.h"
26 #include "wdict.h"
27
28 /* 連モノ ad hoc */
29 #define SEQ 8
30
31 static int g_tn = HIT_BOOL + 1; /* hit[] インデクス */
32
33 /* キャラクタ毎LRインデクス */
34 static int n_lrq[11];
35 static struct ITREE **lrq[11];
36
37 /***************************************************************
38 *
39 * オペコードを展開
40 *
41 * r EAX, ECX, EDX, EBX
42 * SIB, EBP, ESI, EDI
43 *
44 */
45
46 /* ofs8(i) もしくは ofs32(i) を生成 */
47 static
48 void
49 disp_rm(FILE *sfp,
50 unsigned d,
51 unsigned i,
52 int32_t ofs)
53 {
54 assert(i != 4); /* SP ではなく SIB になる */
55 if (i != 5 && ofs == 0)
56 {
57 /* オフセット省略
58 00 ddd sss */
59 putc(0000
60 | ((d << 3) & 0070)
61 | (i & 0007),
62 sfp);
63 }
64 else if (-128 <= ofs && ofs <= 127)
65 {
66 /* short ofs
67 01 ddd sss [ofs.b] */
68 putc(0100
69 | ((d << 3) & 0070)
70 | (i & 0007),
71 sfp);
72 putc(ofs, sfp);
73 }
74 else
75 {
76 /* long ofs
77 10 ddd sss [ofs.l] */
78 putc(0200
79 | ((d << 3) & 0070)
80 | (i & 0007),
81 sfp);
82 fwrite(&ofs, sizeof(ofs), 1, sfp);
83 }
84 }
85
86 #define PTR_H 1 /* CX */
87 #define PTR_LR 5 /* BP */
88 #define PTR_RL 7 /* DI */
89 #define PTR_T 6 /* SI */
90
91 #define OFS_H(n) (sizeof(WS_T) * (n))
92 #define OFS_T(n) (sizeof(WS_T) * ((n) - 16))
93
94 #ifdef USE_64 /* ALU 64 */
95
96 /*
97 * 0x49 0xF7 11-010-ddd not
98 * 0x49 op 11-sss-ddd
99 *
100 * 0x4C op rm
101 * 0x4C 0x8B rm load
102 * 0x4C 0x89 rm store
103 *
104 */
105
106 #define OP_MOV 0x8B
107 #define OP_STOR 0x89
108 #define OP_AND 0x23
109 #define OP_OR 0x0B
110 #define OP_XOR 0x33
111
112 static
113 void
114 reg_op(FILE *sfp,
115 unsigned op,
116 unsigned d,
117 unsigned s)
118 {
119 putc(0x4D, sfp);
120 putc(op & 0xFD, sfp);
121 /* 11 sss ddd */
122 putc(0300
123 | ((s << 3) & 0070)
124 | (d & 0007),
125 sfp);
126 }
127
128 static
129 void
130 reg_not(FILE *sfp,
131 unsigned d)
132 {
133 putc(0x47, sfp);
134 putc(0xF7, sfp);
135 /* 11 010 ddd */
136 putc(0320
137 | (d & 0007),
138 sfp);
139 }
140
141 static
142 void
143 reg_mem(FILE *sfp,
144 unsigned op,
145 unsigned d,
146 unsigned i,
147 long ofs)
148 {
149 putc(0x4C, sfp);
150 putc(op, sfp);
151 disp_rm(sfp, d, i, ofs);
152 }
153
154 #else /* MMX or XMM */
155
156 #define OP_MOV 0x6F
157 #define OP_STOR 0x7F
158 #define OP_AND 0xDB
159 #define OP_ANDN 0xDF
160 #define OP_OR 0xEB
161 #define OP_XOR 0xEF
162
163 static
164 void
165 reg_op(FILE *sfp,
166 unsigned op,
167 unsigned d,
168 unsigned s)
169 {
170 #ifndef USE_MMX
171 putc(0x66, sfp);
172 #endif
173 putc(0x0F, sfp);
174 putc(op, sfp);
175 /* 11 ddd sss */
176 putc(0300
177 | ((d << 3) & 0070)
178 | (s & 0007),
179 sfp);
180 }
181
182 static
183 void
184 reg_mem(FILE *sfp,
185 unsigned op,
186 unsigned d,
187 unsigned i,
188 int ofs)
189 {
190 #ifndef USE_MMX
191 putc(0x66, sfp);
192 #endif
193 putc(0x0F, sfp);
194 putc(op, sfp);
195 disp_rm(sfp, d, i, ofs);
196 }
197
198 /* 残念だがメモリ上の定数と演算 */
199 static
200 void
201 reg_not(FILE *sfp,
202 unsigned d)
203 {
204 reg_mem(sfp,
205 OP_XOR,
206 d,
207 PTR_T,
208 OFS_T(T_INV));
209 }
210
211 #endif
212
213 static
214 void
215 reg_clr(FILE *sfp,
216 unsigned d)
217 {
218 reg_op(sfp, OP_XOR, d, d);
219 }
220
221 /***************************************************************
222 *
223 * ノード作成
224 *
225 */
226
227 #define ALLOC_LEAP 64 /* 2**n */
228
229 static
230 struct ITREE *
231 synth_mknod(enum NODE_ID id)
232 {
233 struct ITREE *node;
234
235 node = calloc(1, sizeof(struct ITREE));
236 assert(node != NULL);
237 node->opcode = id;
238 node->tn = -1;
239 node->n_alloc = sizeof(node->tops) / sizeof(*node->tops);
240 node->ops = node->tops;
241 return node;
242 }
243
244 struct ITREE *
245 synth_make_not(void)
246 {
247 return synth_mknod(NI_NOT);
248 }
249
250 struct ITREE *
251 synth_make_and(void)
252 {
253 return synth_mknod(NI_AND);
254 }
255
256 struct ITREE *
257 synth_make_or(void)
258 {
259 return synth_mknod(NI_OR);
260 }
261
262 struct ITREE *
263 synth_make_xor(void)
264 {
265 return synth_mknod(NI_XOR);
266 }
267
268 struct ITREE *
269 synth_add(struct ITREE *parent, ...)
270 {
271 struct ITREE *node;
272 va_list ap;
273 va_start(ap, parent);
274 while ((node = va_arg(ap, struct ITREE *)) != NULL)
275 {
276 /* alloc の拡張 */
277 if (parent->n_alloc == parent->n_ops)
278 {
279 assert(IS_POWER2(ALLOC_LEAP));
280 parent->n_alloc = (parent->n_alloc + ALLOC_LEAP) & -ALLOC_LEAP;
281 assert(parent->n_alloc > parent->n_ops);
282 if (parent->ops == parent->tops)
283 {
284 parent->ops = malloc(parent->n_alloc * sizeof(*parent->ops));
285 memcpy(parent->ops, parent->tops, sizeof(parent->tops));
286 }
287 else
288 parent->ops = realloc(parent->ops,
289 parent->n_alloc * sizeof(*parent->ops));
290 }
291 parent->ops[parent->n_ops++] = node;
292 node->ref++;
293 }
294 va_end(ap);
295 return parent;
296 }
297
298 /***************************************************************
299 *
300 * ノードを解放する
301 * コドモは解放しない
302 *
303 */
304
305 static
306 void
307 synth_free(struct ITREE *node)
308 {
309 #if DEBUG>=2
310 printf("free: node=%p opcode=%d ops=%d\n",
311 node,
312 node->opcode,
313 node->n_ops);
314 #endif
315
316 if (node->ops != NULL
317 && node->ops != node->tops)
318 free(node->ops);
319
320 /* 自分自身を削除 */
321 free(node);
322 }
323
324 /***************************************************************
325 *
326 * ノードを切り離す
327 * ref == 0 になったらメモリからも削除して削除数を返す
328 *
329 */
330
331 int
332 synth_unlink(struct ITREE *node)
333 {
334 int i;
335 int n = 0;
336
337 assert(node->ref > 0);
338 if (--node->ref > 0)
339 return 0;
340
341 assert(node->dict == NULL);
342
343 /* 枝を切り落とす */
344 for (i = 0; i < node->n_ops; i++)
345 n += synth_unlink(node->ops[i]);
346
347 /* LR の場合、リストから切り離す */
348 if (node->opcode == NI_LR)
349 {
350 for (i = 0; i < n_lrq[node->lrn]; i++)
351 if (lrq[node->lrn][i] == node)
352 {
353 memmove(&lrq[node->lrn][i],
354 &lrq[node->lrn][i + 1],
355 (--n_lrq[node->lrn] - i) * sizeof(*lrq[0][0]));
356 goto deleted;
357 }
358 assert(!"XXX orphan node");
359 deleted:
360 ;
361 }
362
363 /* 自分自身を削除 */
364 synth_free(node);
365
366 return n + 1;
367 }
368
369 /***************************************************************
370 *
371 * LRノードを登録
372 *
373 */
374
375 struct ITREE *
376 synth_make_lr(uint64_t bmp, int lrn)
377 {
378 struct ITREE *node;
379 int qa, qb;
380
381 assert(1 <= lrn && lrn <= 10);
382 assert(bmp != 0);
383
384 /* 末尾マスク */
385 if (lrn == 10)
386 {
387 bmp &= 0x1111111111111111ULL;
388
389 /* 後段の最適化のため
390 always t のノードは全ビット立てておく */
391 if (!(~bmp & 0x1111111111111111ULL))
392 bmp = 0xFFFFFFFFFFFFFFFFULL;
393 }
394
395 assert(bmp != 0);
396
397 /* キャッシュにすでに登録されていればそれを返す
398 この版ではメンドくさいのでバイナリサーチ(笑 */
399 for (qa = 0, qb = n_lrq[lrn];
400 qb > 0;
401 qb >>= 1)
402 {
403 int q = qa + (qb >> 1);
404 assert(lrq[lrn] != NULL);
405 assert(lrq[lrn][q] != NULL);
406 assert(lrq[lrn][q]->opcode == NI_LR);
407 if (bmp == lrq[lrn][q]->bmp)
408 return lrq[lrn][q];
409 else if (bmp > lrq[lrn][q]->bmp)
410 {
411 qa = q + 1;
412 qb--;
413 }
414 }
415
416 #if DEBUG>=1
417 if (n_lrq[lrn] == 0)
418 printf("%2d:%3d/%3d=---------------- %08X%08X\n",
419 lrn,
420 qa, n_lrq[lrn],
421 (unsigned)(bmp >> 32),
422 (unsigned)bmp);
423
424 if (qa < n_lrq[lrn])
425 printf("%2d:%3d/%3d=%08X%08X %08X%08X\n",
426 lrn,
427 qa, n_lrq[lrn],
428 (unsigned)(lrq[lrn][qa]->bmp >> 32),
429 (unsigned)(lrq[lrn][qa]->bmp),
430 (unsigned)(bmp >> 32),
431 (unsigned)bmp);
432 #endif
433
434 node = calloc(1, sizeof(struct ITREE));
435 assert(node != NULL);
436 node->opcode = NI_LR;
437 node->tn = -1;
438 node->lrn = lrn;
439 node->bmp = bmp;
440
441 /* キャッシュに挿入登録 */
442 if (lrq[lrn] == NULL)
443 {
444 assert(n_lrq[lrn] == 0);
445 lrq[lrn] = malloc(sizeof(*lrq[lrn]));
446 n_lrq[lrn]++;
447 assert(qa == 0);
448 }
449 else
450 {
451 int n = n_lrq[lrn];
452 lrq[lrn] = realloc(lrq[lrn], (n + 1) * sizeof(*lrq[lrn]));
453 memmove(&lrq[lrn][qa + 1], &lrq[lrn][qa], (n - qa) * sizeof(*lrq[lrn]));
454 n_lrq[lrn] = n + 1;
455 }
456 assert(lrq[lrn] != NULL);
457 assert(qa < n_lrq[lrn]);
458 lrq[lrn][qa] = node;
459
460 return node;
461 }
462
463 /***************************************************************
464 *
465 * 辞書に単語を突っ込む
466 *
467 */
468
469 struct ITREE *synth_make_dict(int pos,
470 struct DICT_CHAR const *word)
471 {
472 struct WDICT *pd;
473 struct ITREE *node = NULL;
474
475 /* 辞書に単語を登録
476 NULL が返ってきたときはすでにある辞書に登録 */
477 pd = wdict_add(g_tn, pos, word);
478
479 /* 空ノードをつくる */
480 if (pd != NULL)
481 {
482 node = synth_mknod(NI_AND);
483 assert(node != NULL);
484 node->dict = pd;
485 node->tn = g_tn++;
486 wdict_setnode(pd, node);
487 return node;
488 }
489 else
490 {
491 /* どこかに追加できた場合は、ナニも返さない(いいのか?) */
492 return NULL;
493 }
494 }
495
496 /***************************************************************
497 *
498 * 木をダンプ; for debug
499 *
500 */
501
502 static
503 void
504 synth_dump(int lv, struct ITREE const *node)
505 {
506 int i;
507 char const *t = &"\t\t\t\t\t\t\t\t\t\t"[10 - lv];
508 static char const node_name[][4] =
509 {
510 "LR", /* -256 */
511 "SEQ", /* XXX */
512 "NOT",
513 "AND",
514 "OR",
515 "XOR",
516 "NAN",
517 };
518
519 if (!node)
520 return;
521
522 if (NI_LR <= node->opcode && node->opcode < NI_MAX)
523 printf("%s%s[%s] (n=%d) ref=%d tn=%d %p\n%s{\n",
524 t,
525 (node->dict != NULL ? "[DIC]" : ""),
526 node_name[node->opcode - NI_LR],
527 node->n_ops, node->ref,
528 node->tn,
529 node,
530 t);
531 else
532 printf("%snode=%d (n=%d) ref=%d dict=%p %p\n%s{\n",
533 t,
534 node->opcode, node->n_ops, node->ref,
535 node->dict,
536 node,
537 t);
538
539 if (node->dict != NULL)
540 wdict_dump(lv, node->dict);
541
542 if (node->opcode == NI_LR)
543 {
544 int cn = popcnt64(node->bmp);
545 printf("%s\t%2d:",
546 t,
547 node->lrn);
548 if (cn > 14)
549 printf(F016LLX"\t(%2d)\n",
550 A016LLX(node->bmp),
551 cn);
552 else
553 {
554 putchar('[');
555 for (i = 0; i < 64; i++)
556 if (node->bmp & (1ULL << i))
557 putchar(C64[i]);
558 printf("]\t(%2d)\n", cn);
559 }
560 }
561 else for (i = 0; i < node->n_ops; i++)
562 {
563 printf("%s%d:\n", t, i);
564 synth_dump(lv + 1, node->ops[i]);
565 }
566 printf("%s}\n", t);
567 }
568
569 /***************************************************************
570 *
571 * 愚直なレジスタ割り当て
572 *
573 */
574
575 #define REG_RELOAD 0 /* 付け焼き刃の最適はむしろ有害 */
576 #define N_INFLIGHT 1 /* 同時演算を試みる個数 */
577
578 #if defined(USE_64_XMM)
579 #define NREGS 16
580 #else
581 #define NREGS 8
582 #endif
583
584 static struct ITREE *a_regs[NREGS];
585 static int g_reggen, a_reggen[NREGS];
586
587 static
588 int
589 synth_reg_find(struct ITREE *node)
590 {
591 int i;
592 assert(node != NULL);
593 assert(node->ref > 0);
594 for (i = 0; i < NREGS; i++)
595 if (a_regs[i]
596 && a_regs[i] == node)
597 {
598 a_reggen[i] = g_reggen++;
599 return i;
600 }
601 return -1;
602 }
603
604 /* あきレジスタを探す(きをつけろ) */
605 static
606 int
607 synth_reg_alloc_vacant(void)
608 {
609 int i;
610
611 for (i = 0; i < NREGS; i++)
612 if (a_regs[i] == NULL
613 || a_regs[i]->ref == 0)
614 return i;
615
616 return -1;
617 }
618
619 static
620 int
621 synth_reg_alloc(struct ITREE *node)
622 {
623 int i;
624 int g, r;
625
626 /* すでに割り当てられていればそれを返す */
627 i = synth_reg_find(node);
628 if (i >= 0)
629 return i;
630 /* アキレジスタを探す */
631 r = -1;
632 g = INT_MAX;
633 for (i = 0; i < NREGS; i++)
634 if (a_regs[i] != NULL
635 && a_regs[i]->ref > 0)
636 {
637 /* 占められている */
638 if (g > a_reggen[i]
639 && a_regs[i]->tn >= 0)
640 {
641 g = a_reggen[i];
642 r = i;
643 }
644 }
645 else
646 {
647 a_regs[i] = node;
648 a_reggen[i] = g_reggen++;
649 return i;
650 }
651
652 /* XXX どれかひとつを待避して、かわりにそこに割り当てるものは将来実装 */
653 assert(r >= 0);
654 assert(a_regs[r]->tn >= 0);
655 a_regs[r] = node;
656 a_reggen[r] = g_reggen++;
657 return r;
658 }
659
660 /***************************************************************
661 *
662 * 命令列を生成
663 *
664 */
665
666 struct LRX
667 {
668 struct ITREE *node;
669 int mtn;
670 int otn;
671 int src;
672 struct QMX *xp;
673 unsigned mtm;
674 };
675
676 #define MTM_NOT 0x100U
677
678 static
679 int
680 cmp_lrx(void const *pa, void const *pb)
681 {
682 struct LRX const *a = pa;
683 struct LRX const *b = pb;
684 int r;
685 assert(a->node != NULL);
686 assert(b->node != NULL);
687 if ((r = a->mtn - b->mtn)
688 || (r = a->mtm - b->mtm)
689 || (r = (int)popcnt64(a->node->bmp) - (int)popcnt64(b->node->bmp))
690 || (r = (int)(a->node->bmp >> 32) - (int)(b->node->bmp >> 32)))
691 return r;
692 return (int)a->node->bmp - (int)b->node->bmp;
693 }
694
695 #if SEQ
696 #define LRR(r,pos) (((r) + 6 * (pos)) & (NREGS - 1))
697 #else
698 #define LRR(r,pos) (r)
699 #endif
700
701 static int g_seqn = -1;
702
703 static
704 void
705 synth_load_lr(FILE *sfp, int pos, int i)
706 {
707 int o = tr_fp[6 * pos + (5 - i)];
708 if (o < 32)
709 reg_mem(sfp,
710 OP_MOV,
711 LRR(i, pos),
712 PTR_LR,
713 sizeof(WS_T) * (o - 16));
714 else if (o < 64)
715 reg_mem(sfp,
716 OP_MOV,
717 LRR(i, pos),
718 PTR_RL,
719 sizeof(WS_T) * (o - 32 - 16));
720 }
721
722 /* 連モノツリーを組み上げる */
723 static
724 struct ITREE *
725 synth_mkseq(void)
726 {
727 int i, j;
728 struct ITREE *t0;
729 struct ITREE *seqnode[9];
730
731 if (g_seqn < 0)
732 {
733 g_seqn = g_tn;
734 g_tn += 9;
735 }
736
737 for (i = 0; i < 9; i++)
738 {
739 seqnode[i] = synth_mknod(NI_SEQ);
740 seqnode[i]->tn = g_seqn + i;
741 }
742
743 t0 = synth_mknod(NI_NAND);
744 for (i = 0; i < 10 + 1 - SEQ; i++)
745 {
746 struct ITREE *t1 = synth_make_or();
747 for (j = 0; j < SEQ - 1; j++)
748 {
749 assert(i + j < 9);
750 synth_add(t1, seqnode[i + j], NULL);
751 }
752 synth_add(t0, t1, NULL);
753 }
754
755 return t0;
756 }
757
758 static
759 int
760 synth_assemble_lr(FILE *sfp, int pos, struct ITREE **nodea, int noden)
761 {
762 int i;
763 uint64_t m;
764 unsigned regs_loaded = 0;
765 int rd;
766 int recon;
767 struct LRX *lrx;
768 struct QMX (*qmx)[QMX_LEN + 1];
769 int nts_total = 0;
770 int nts_reduced = 0;
771 assert(noden <= 10000);
772 debug_eprintf(1, "ASSEMBLE! (noden=%d)\n", noden);
773 recon = 0;
774
775 /* XXX 気休め */
776 for (i = 0; i < NREGS; i++)
777 a_regs[i] = NULL;
778
779 #if SEQ > 0
780 if (pos >= 1) /* 11連対応ではない! */
781 {
782 /* 末尾処理 */
783 i = 0;
784 if (pos == 10)
785 {
786 reg_op(sfp, OP_OR, LRR(1, pos - 1), LRR(0, pos - 1));
787 i = 2;
788 }
789
790 /* adhoc な連モノ検出 */
791 for (/*nil*/; i < 6; i++)
792 {
793 synth_load_lr(sfp, pos, i);
794 regs_loaded |= (1 << i);
795 if (pos >= 2)
796 {
797 reg_op(sfp, OP_XOR, LRR(i, pos - 1), LRR(i, pos));
798 if (i > 0)
799 reg_op(sfp, OP_OR, LRR(i, pos - 1), LRR(i - 1, pos - 1));
800 }
801 }
802
803 /* 連モノ生成場所 */
804 if (pos >= 2)
805 {
806 assert(g_seqn >= 0);
807 reg_mem(sfp,
808 OP_STOR,
809 LRR(5, pos - 1),
810 PTR_H,
811 OFS_H(g_seqn + pos - 2));
812 }
813 }
814 #endif
815
816 if (noden == 0)
817 return 0;
818
819 assert(nodea != NULL);
820
821 m = (pos < 10
822 ? 0x0000000000000000ULL
823 : 0xEEEEEEEEEEEEEEEEULL);
824
825 /* ワークエリア */
826 lrx = calloc(noden, sizeof(*lrx));
827 assert(lrx != NULL);
828 qmx = calloc(noden, sizeof(*qmx));
829 assert(qmx != NULL);
830
831 for (i = 0; i < noden; i++)
832 {
833 int j, k;
834 unsigned opo, opa;
835 struct ITREE *node;
836 struct QMX *xp;
837 struct QMX const *px;
838
839 for (j = i; j < noden; j++)
840 {
841 /* 最初のループで通るはず */
842 if (lrx[j].node == NULL)
843 {
844 lrx[j].node = nodea[j];
845 lrx[j].xp = qmx[j];
846 lrx[j].mtn = simplify_qm(lrx[j].xp,
847 lrx[j].node->bmp,
848 m);
849 lrx[j].otn = lrx[j].mtn;
850 lrx[j].mtm = OP_MOV;
851 lrx[j].src = -256; /* 決してマッチしない */
852 }
853 if (recon && lrx[j].mtn == INT_MAX)
854 {
855 lrx[j].mtn = simplify_qm(lrx[j].xp,
856 lrx[j].node->bmp,
857 m);
858 lrx[j].otn = lrx[j].mtn;
859 assert(lrx[j].mtm == OP_MOV);
860 }
861
862 /* 被覆の被覆を求める */
863 for (k = 0; k < i; k++)
864 {
865 int ttn;
866 struct QMX txp[QMX_LEN + 1];
867
868 if (!recon && k < i - 2) /* 計算する必要ナシ */
869 continue;
870
871 if ((lrx[k].node->bmp & lrx[j].node->bmp) == lrx[k].node->bmp
872 && (ttn = simplify_qm(txp,
873 lrx[j].node->bmp,
874 m | lrx[k].node->bmp)) < INT_MAX)
875 {
876 /* OR */
877 if (k != i - 1) /* 直前のものでなければ1段コスト増 */
878 ttn++;
879 if (lrx[j].mtn > ttn)
880 {
881 lrx[j].mtn = ttn;
882 lrx[j].mtm = OP_OR;
883 lrx[j].src = k;
884 memcpy(lrx[j].xp, txp, sizeof(txp));
885 }
886 }
887
888 if ((lrx[k].node->bmp & lrx[j].node->bmp) == lrx[j].node->bmp
889 && (ttn = simplify_qm(txp,
890 lrx[j].node->bmp,
891 m | ~lrx[k].node->bmp)) < INT_MAX)
892 {
893 /* AND */
894 ttn++; /* ロードの分浪費 */
895 if (lrx[j].mtn > ttn)
896 {
897 lrx[j].mtn = ttn;
898 lrx[j].mtm = OP_AND;
899 lrx[j].src = k;
900 memcpy(lrx[j].xp, txp, sizeof(txp));
901 }
902 }
903
904 if ((~lrx[k].node->bmp & lrx[j].node->bmp) == ~lrx[k].node->bmp
905 && (ttn = simplify_qm(txp,
906 lrx[j].node->bmp,
907 m | ~lrx[k].node->bmp)) < INT_MAX)
908 {
909 /* NOT OR */
910 if (k != i - 1) /* 直前のものでなければ1段コスト増 */
911 ttn++;
912 ttn += 1; /* NOT */
913 if (lrx[j].mtn > ttn)
914 {
915 lrx[j].mtn = ttn;
916 lrx[j].mtm = OP_OR | MTM_NOT;
917 lrx[j].src = k;
918 memcpy(lrx[j].xp, txp, sizeof(txp));
919 }
920 }
921
922 if ((~lrx[k].node->bmp & lrx[j].node->bmp) == lrx[j].node->bmp
923 && (ttn = simplify_qm(txp,
924 lrx[j].node->bmp,
925 m | lrx[k].node->bmp)) < INT_MAX)
926 {
927 /* NOT AND (not ANDN) */
928 ttn += 3; /* LOAD, NOT, AND */
929 if (lrx[j].mtn > ttn)
930 {
931 lrx[j].mtn = ttn;
932 lrx[j].mtm = OP_AND | MTM_NOT;
933 lrx[j].src = k;
934 memcpy(lrx[j].xp, txp, sizeof(txp));
935 }
936 }
937 }
938 }
939
940 /* 項数順にソート
941 先頭に来たモノを選出することになる */
942 recon = 0;
943 qsort(&lrx[i], noden - i, sizeof(*lrx), cmp_lrx);
944
945 assert(lrx[i].mtn != INT_MAX);
946
947 #if DEBUG>=1
948 fprintf(stderr,
949 "%4d/%4d:n=%3d/%3d(mt=%c%02X:src=%4d) %08X%08X\n",
950 i, (noden - i),
951 lrx[i].mtn,
952 lrx[i].otn,
953 (lrx[i].mtm & MTM_NOT ? '!' : ' '),
954 lrx[i].mtm & 0xFF,
955 lrx[i].src,
956 (unsigned)(lrx[i].node->bmp >> 32),
957 (unsigned)lrx[i].node->bmp);
958 #endif
959 assert(lrx[i].mtn >= 0);
960
961 /* 統計 */
962 nts_total += lrx[i].mtn;
963 if (lrx[i].mtm && lrx[i].otn < INT_MAX)
964 nts_reduced += lrx[i].otn - lrx[i].mtn;
965
966 /* 命令列の生成 */
967 node = lrx[i].node;
968 xp = lrx[i].xp;
969
970 /* ワークエリア割り当て */
971 node->tn = g_tn++;
972
973 switch (lrx[i].mtm)
974 {
975 case OP_OR | MTM_NOT:
976 case OP_OR: rd = 6; opo = OP_OR; break;
977 default: rd = 7; opo = OP_MOV; break;
978 }
979
980 /* 既出の項を利用して演算するばあい */
981 if (opo != OP_MOV && lrx[i].src != i - 1)
982 reg_mem(sfp,
983 OP_MOV,
984 LRR(7, pos),
985 PTR_H,
986 OFS_H(lrx[lrx[i].src].node->tn));
987
988 if (lrx[i].mtm == (OP_OR | MTM_NOT))
989 reg_not(sfp, LRR(7, pos));
990
991 if (!(node->bmp & ~m)
992 || !~(node->bmp | m))
993 {
994 fprintf(stderr,
995 "やっちゃったー %08X%08X\n",
996 (unsigned)(node->bmp >> 32),
997 (unsigned)node->bmp);
998 assert(!!(node->bmp & ~m));
999 assert(!!~(node->bmp | m));
1000 }
1001
1002 /* 圧縮された式を展開 */
1003 for (px = xp; px->m; px++)
1004 {
1005 int j;
1006 unsigned mi, pi;
1007
1008 opa = OP_MOV;
1009
1010 /* 補項; !a!b..!f => !(a+b+...+f) */
1011 mi = px->m & ~px->n;
1012 for (j = 0; j < 6; j++)
1013 if (mi & (1 << j))
1014 {
1015 if (!(regs_loaded & (1 << j)))
1016 {
1017 synth_load_lr(sfp, pos, j);
1018 regs_loaded |= (1 << j);
1019 }
1020 reg_op(sfp, opa, LRR(rd, pos), LRR(j, pos));
1021 opa = OP_OR;
1022 }
1023
1024 #ifdef OP_ANDN
1025 if (opa == OP_OR)
1026 opa = OP_ANDN;
1027 #else
1028 if (opa == OP_OR)
1029 {
1030 reg_not(sfp, LRR(rd, pos));
1031 opa = OP_AND;
1032 }
1033 #endif
1034 /* 残りの積項 */
1035 pi = px->m & px->n;
1036 for (j = 0; j < 6; j++)
1037 if (pi & (1 << j))
1038 {
1039 if (!(regs_loaded & (1 << j)))
1040 {
1041 synth_load_lr(sfp, pos, j);
1042 regs_loaded |= (1 << j);
1043 }
1044 reg_op(sfp, opa, LRR(rd, pos), LRR(j, pos));
1045 opa = OP_AND;
1046 }
1047
1048 /* 補項だけだった場合の処理 */
1049 #ifdef OP_ANDN
1050 if (opa == OP_ANDN)
1051 reg_not(sfp, LRR(rd, pos));
1052 #endif
1053
1054 /* 和項に追加 */
1055 if (rd != 7)
1056 reg_op(sfp, opo, LRR(7, pos), LRR(rd, pos));
1057 rd = 6;
1058 opo = OP_OR;
1059 }
1060
1061 if (opo == OP_MOV)
1062 {
1063 /* 積和項が生成されなかった場合 */
1064 assert(lrx[i].mtm != OP_MOV);
1065 assert(lrx[i].mtm != OP_OR);
1066 assert(lrx[i].src >= 0);
1067 if (lrx[i].src != i - 1)
1068 reg_mem(sfp,
1069 OP_MOV,
1070 LRR(7, pos),
1071 PTR_H,
1072 OFS_H(lrx[lrx[i].src].node->tn));
1073 if (lrx[i].mtm & MTM_NOT)
1074 reg_not(sfp, LRR(7, pos));
1075 }
1076 else switch (lrx[i].mtm) /* 既出項との演算 */
1077 {
1078 case OP_AND | MTM_NOT:
1079 reg_mem(sfp,
1080 OP_MOV,
1081 LRR(6, pos),
1082 PTR_H,
1083 OFS_H(lrx[lrx[i].src].node->tn));
1084 reg_not(sfp, LRR(6, pos));
1085 reg_op(sfp, OP_AND, LRR(7, pos), LRR(6, pos));
1086 break;
1087 case OP_AND:
1088 reg_mem(sfp,
1089 lrx[i].mtm,
1090 LRR(7, pos),
1091 PTR_H,
1092 OFS_H(lrx[lrx[i].src].node->tn));
1093 break;
1094 }
1095
1096 /* 結果の格納 */
1097 reg_mem(sfp,
1098 OP_STOR,
1099 LRR(7, pos),
1100 PTR_H,
1101 OFS_H(node->tn));
1102
1103 a_regs[LRR(7, pos)] = node; /* XXX 気休め */
1104 }
1105 #if DEBUG>=1
1106 {
1107 static int tt, tn;
1108 tt += nts_total;
1109 tn += nts_reduced;
1110 fprintf(stderr,
1111 "term=%d (reduced %d) total:%d%%(%d reduced=%d)\n",
1112 nts_total, nts_reduced,
1113 100 * tt / (tt + tn),
1114 tt, tn);
1115 }
1116 #endif
1117
1118 free(lrx);
1119 free(qmx);
1120
1121 return 0;
1122 }
1123
1124 static
1125 int
1126 synth_assemble(FILE *sfp, struct ITREE *node)
1127 {
1128 int i;
1129 int m;
1130 int rd[N_INFLIGHT];
1131 unsigned op[N_INFLIGHT];
1132 unsigned opx;
1133 int f_dict = 0;
1134
1135 assert(node != NULL);
1136 assert(node->dict != NULL || node->tn < 0);
1137 assert(node->n_ops > 0);
1138 assert(node->ops != NULL);
1139
1140 switch (node->opcode)
1141 {
1142 default: assert(!"XXX not supported");
1143 case NI_AND: opx = OP_AND; break;
1144 case NI_OR: opx = OP_OR; break;
1145 case NI_XOR: opx = OP_XOR; break;
1146 case NI_NAND:opx = OP_AND; break;
1147 }
1148
1149 /* おまじない */
1150 node->ref++;
1151
1152 /* レジスタ割り当ての初期化 */
1153 for (m = 0; m < N_INFLIGHT; m++)
1154 {
1155 op[m] = OP_MOV;
1156 rd[m] = -1;
1157 }
1158
1159 /* 枝をかき集める */
1160 m = 0;
1161 for (i = 0; i < node->n_ops; i++)
1162 {
1163 struct ITREE *leaf = node->ops[i];
1164 int rs;
1165
1166 assert(leaf != NULL);
1167 assert(leaf->ref > 0);
1168
1169 /* 辞書群に突入する前に、結果を HIT_BOOL に書き留める
1170 このへんの処理はたいへんアドホック
1171 なので INFLIGHT = 1 でお願いね! */
1172 if (!f_dict
1173 && leaf->dict != NULL)
1174 {
1175 int td;
1176 if (i > 0
1177 && node->ops[i - 1]->dict == NULL)
1178 {
1179 assert(rd[m] >= 0);
1180 td = rd[m];
1181 }
1182 else
1183 {
1184 /* 要クリア */
1185 td = synth_reg_alloc_vacant();
1186 assert(td >= 0); /* ここで空いてないハズがないよな… */
1187 reg_clr(sfp, td);
1188 }
1189 reg_mem(sfp,
1190 OP_STOR,
1191 td,
1192 PTR_H,
1193 OFS_H(HIT_BOOL));
1194 f_dict = 1;
1195 }
1196
1197 /* 枝を生成
1198 DICT は先にワークを割り付けられている */
1199 if (leaf->dict != NULL)
1200 synth_assemble(sfp, leaf);
1201
1202 rs = (leaf->tn >= 0
1203 ? synth_reg_find(leaf)
1204 : synth_assemble(sfp, leaf));
1205
1206 if (op[m] == OP_MOV)
1207 {
1208 assert(rd[m] < 0);
1209 if (rs >= 0)
1210 {
1211 assert(a_regs[rs] != NULL);
1212 assert(a_regs[rs] == leaf);
1213 if (a_regs[rs]->ref > 1)
1214 {
1215 /* 他参照されているレジスタはコピー */
1216 rd[m] = synth_reg_alloc(node);
1217 assert(rd[m] >= 0);
1218 reg_op(sfp, OP_MOV, rd[m], rs);
1219 }
1220 else
1221 {
1222 /* 参照されなくなったので乗っ取る */
1223 rd[m] = rs;
1224 a_regs[rd[m]] = node;
1225 }
1226 }
1227 else
1228 {
1229 /* レジスタに割り当てられていない場合ロード */
1230 assert(leaf->tn >= 0);
1231 rs = synth_reg_alloc(leaf);
1232 reg_mem(sfp,
1233 op[m],
1234 rs,
1235 PTR_H,
1236 OFS_H(leaf->tn));
1237 #if REG_RELOAD
1238 if (leaf->ref > 1)
1239 {
1240 /* コピーとする */
1241 rd[m] = synth_reg_alloc(node);
1242 reg_op(sfp, OP_MOV, rd[m], rs);
1243 }
1244 else
1245 #endif
1246 {
1247 /* 乗っ取って構わない */
1248 a_regs[rd[m] = rs] = node;
1249 }
1250 }
1251
1252 /* 次からは MOV ではない */
1253 assert(rd[m] >= 0);
1254 op[m] = opx;
1255 }
1256 else
1257 {
1258 assert(rs >= 0 || leaf->tn >= 0);
1259
1260 /* あとのことを考えて?? いったんレジスタ割り当て */
1261 #if REG_RELOAD
1262 if (rs < 0 && leaf->ref > 1)
1263 {
1264 rs = synth_reg_alloc(leaf);
1265 reg_mem(sfp,
1266 op[m],
1267 rs,
1268 PTR_H,
1269 OFS_H(leaf->tn));
1270 }
1271 #endif
1272
1273 if (rs >= 0)
1274 reg_op(sfp, op[m], rd[m], rs);
1275 else
1276 reg_mem(sfp,
1277 op[m],
1278 rd[m],
1279 PTR_H,
1280 OFS_H(leaf->tn));
1281 }
1282
1283 /* 参照数を減らす */
1284 leaf->ref--;
1285
1286 /* 循環 */
1287 if (++m >= N_INFLIGHT)
1288 m = 0;
1289 }
1290
1291 /* 空だったらゼロにする */
1292 if (op[0] == OP_MOV)
1293 {
1294 rd[0] = synth_reg_alloc(node);
1295 reg_clr(sfp, rd[0]);
1296 }
1297 else
1298 for (i = 1; i < N_INFLIGHT; i++)
1299 {
1300 if (op[i] != OP_MOV)
1301 reg_op(sfp, op[i], rd[0], rd[i]);
1302 if (rd[i] >= 0)
1303 a_regs[rd[i]] = NULL;
1304 }
1305
1306 /* NAND 処理 */
1307 if (node->opcode == NI_NAND)
1308 reg_not(sfp, rd[0]);
1309
1310 /* 辞書は必ず結果を残す必要あり */
1311 if (node->dict != NULL)
1312 assert(node->tn >= 0);
1313
1314 /* AND 項の記録 */
1315 if (node->opcode == NI_OR
1316 && node->dict == NULL
1317 && !f_dict)
1318 reg_mem(sfp,
1319 OP_STOR,
1320 rd[0],
1321 PTR_H,
1322 OFS_H(HIT_BOOL));
1323
1324 /* ストア */
1325 if (node->tn >= 0)
1326 reg_mem(sfp,
1327 OP_STOR,
1328 rd[0],
1329 PTR_H,
1330 OFS_H(node->tn));
1331
1332 /* おまじないおわり */
1333 node->ref--;
1334
1335 return rd[0];
1336 }
1337
1338 /***************************************************************
1339 *
1340 * 木をプチ最適化してみるテスト
1341 * 最適化による効果を返す
1342 *
1343 */
1344
1345 static
1346 int
1347 cmp_node(void const *pa, void const *pb)
1348 {
1349 int r;
1350 struct ITREE *a = *(struct ITREE **)pa;
1351 struct ITREE *b = *(struct ITREE **)pb;
1352 if ((r = (!!a->dict) - (!!b->dict))
1353 || (r = a->tn - b->tn)
1354 || (r = b->opcode - a->opcode)
1355 || (r = (char const *)pa - (char const *)pb)) /* 順列を崩さないため */
1356 return r;
1357
1358 assert(!"XXX notreached");
1359 return 0;
1360 }
1361
1362 static
1363 int
1364 synth_optimize(struct ITREE *node)
1365 {
1366 int neff = 0;
1367 int i, j;
1368 int sort_needed = 0;
1369
1370 /* 先に枝を最適化しておく */
1371 for (i = 0; i < node->n_ops; i++)
1372 {
1373 struct ITREE *child = node->ops[i];
1374
1375 /* 先に、枝の最適化に挑戦 */
1376 neff += synth_optimize(child);
1377
1378 /* 意味のないノードを落とす */
1379 if (child->opcode == NI_LR
1380 && ((node->opcode == NI_AND && !~child->bmp)
1381 || (node->opcode == NI_OR && !child->bmp)))
1382 {
1383 debug_eprintf(1, "op=%d child="F016LLX" ~child="F016LLX" !~child=%d !!~child=%d\n",
1384 node->opcode,
1385 A016LLX(child->bmp),
1386 A016LLX(~child->bmp),
1387 !~child->bmp,
1388 !!~child->bmp);
1389
1390 neff += 1 + synth_unlink(child);
1391 memmove(&node->ops[i],
1392 &node->ops[i + 1],
1393 (--node->n_ops - i) * sizeof(*node->ops));
1394 i--; goto redo_i;
1395 }
1396
1397 /* 同じポインタは無条件に融合できる */
1398 for (j = 0; j < i; j++)
1399 if (node->ops[j] == child)
1400 {
1401 child->ref--;
1402 assert(child->ref >= 1);
1403 memmove(&node->ops[i],
1404 &node->ops[i + 1],
1405 (--node->n_ops - i) * sizeof(node->ops[i]));
1406 neff++;
1407 i--; goto redo_i;
1408 }
1409
1410 /* 同種の演算は融合可能 */
1411 if (child->opcode == node->opcode
1412 && child->tn < 0
1413 && child->ref == 1)
1414 {
1415 assert(child->dict == NULL);
1416 memmove(&node->ops[i],
1417 &node->ops[i + 1],
1418 (--node->n_ops - i) * sizeof(node->ops[i]));
1419 if (node->n_alloc < node->n_ops + child->n_ops)
1420 {
1421 node->n_alloc = 3 * (node->n_ops + child->n_ops) / 2;
1422 if (node->ops == node->tops)
1423 {
1424 node->ops = malloc(node->n_alloc * sizeof(node->ops[0]));
1425 memcpy(node->ops, node->tops, sizeof(node->tops));
1426 }
1427 else
1428 node->ops = realloc(node->ops,
1429 node->n_alloc * sizeof(node->ops[0]));
1430 }
1431 memcpy(&node->ops[node->n_ops],
1432 &child->ops[0],
1433 child->n_ops * sizeof(child->ops[0]));
1434 node->n_ops += child->n_ops;
1435 synth_free(child);
1436 neff++;
1437 i--; goto redo_i;
1438 }
1439
1440 /* 孫のみを指す子を落とす */
1441 if (child->n_ops == 1
1442 && !(child->opcode == NI_NAND
1443 || child->opcode == NI_XOR)
1444 && child->ref == 1)
1445 {
1446 assert(child->tn < 0);
1447 assert(child->dict == NULL);
1448 node->ops[i] = child->ops[0];
1449 child->n_ops--;
1450 neff += 1 + synth_unlink(child);
1451 i--; goto redo_i;
1452 }
1453
1454 if (i > 0
1455 && node->ops[i - 1]->dict != NULL
1456 && node->ops[i]->dict == NULL)
1457 sort_needed++;
1458
1459 redo_i:
1460 ;
1461 }
1462
1463 /* AND->DICT となるようにソートする */
1464 if (sort_needed)
1465 qsort(node->ops, node->n_ops, sizeof(*node->ops), cmp_node);
1466
1467 return neff;
1468 }
1469
1470 /***************************************************************
1471 *
1472 * 木から命令列を生成
1473 * 生成の結果必要なワークエリアサイズを返す
1474 *
1475 */
1476
1477 int
1478 synth_synthesize(FILE *sfp,
1479 struct ITREE *node)
1480 {
1481 int i;
1482 int r;
1483 off_t olr, ot;
1484
1485 /* 辞書を展開する */
1486 if (node)
1487 fprintf(stderr, "単語を展開中…\n");
1488 wdict_setup_lr();
1489
1490 if (node)
1491 {
1492 #if SEQ > 0
1493 fprintf(stderr, "純 %d 連を勝手に拾うモード!\n", SEQ);
1494 synth_add(node, synth_mkseq(), NULL);
1495 #endif
1496
1497 fprintf(stderr, "木をプチ最適化してみるテスト…\n");
1498 #if DEBUG>=2
1499 synth_dump(0, node);
1500 #endif
1501 r = synth_optimize(node);
1502 if (r > 0)
1503 fprintf(stderr, "ムダを %d 個やっつけました。\n", r);
1504 }
1505 else
1506 {
1507 fprintf(stderr,
1508 "* 検索を行わせるには target.txt が必要です。\n"
1509 " 勝手にベンチマークモード(%dビット級)に突入します。\n"
1510 " 純 %d 連だけを探します。\n",
1511 1 << N_STRIDE, SEQ);
1512 node = synth_mkseq();
1513 r = synth_optimize(node);
1514 }
1515
1516 #if DEBUG>=1
1517 synth_dump(0, node);
1518 #endif
1519
1520 /* LR 命令列を生成 */
1521 olr = ftell(sfp);
1522 if (node)
1523 {
1524 fprintf(stderr, "難しい処理に挑戦中…\n");
1525 for (i = 0; i < 11; i++)
1526 synth_assemble_lr(sfp, i, lrq[i], n_lrq[i]);
1527 }
1528 #if DEBUG>=1
1529 ot = ftell(sfp);
1530 olr = ot - olr;
1531 fprintf(stderr, "0x%08X(%d): LR size\n", (unsigned)olr, (unsigned)olr);
1532 #endif
1533
1534 /* 木をトラバースして残りの命令列を生成 */
1535 if (node)
1536 {
1537 fprintf(stderr, "組み立て中…\n");
1538 r = synth_assemble(sfp, node);
1539 }
1540
1541 /* 最終結果の格納 */
1542 reg_mem(sfp,
1543 OP_STOR,
1544 r,
1545 PTR_H,
1546 OFS_H(HIT_ANY));
1547
1548 #if DEBUG>=1
1549 ot = ftell(sfp) - ot;
1550 fprintf(stderr,
1551 "0x%08X(%d): TR size\ng_tn=%d g_reggen=%d\n",
1552 (unsigned)ot, (unsigned)ot,
1553 g_tn, g_reggen);
1554 #endif
1555
1556 return g_tn;
1557 }
1558
1559 /*
1560 * Local Variables:
1561 * tab-width: 4
1562 * End:
1563 *
1564 * EOF */

Properties

Name Value
svn:eol-style native
svn:keywords Author Date Id Rev URL

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26