4.3. 为 define_split 产生代码
现在回到 main ,在 840 行,这个 define_insn_and_split 的 split 部分 将被通过 gen_split 写出。我们的例子显示如下:
图 30 : genemit - define_insn_and_split 模式的例子 – split 部分
550 static void
551 g en_split (rtx split) in genemit.c
552 {
553 int i;
554 int operands;
555 const char *const name =
556 ((GET_CODE (split) == DEFINE_PEEPHOLE2) ? "peephole2" : "split");
557 const char *unused;
558 char *used;
559
560 if (XVEC (split, 0) == 0)
561 fatal ("define_%s (definition %d) lacks a pattern", name,
562 insn_index_number );
563 else if (XVEC (split, 2) == 0)
564 fatal ("define_%s (definition %d) lacks a replacement pattern", name,
565 insn_index_number );
566
567 /* Find out how many operands this function has. */
568
569 max_operand_vec (split, 2);
570 operands = MAX (max_opno , MAX (max_dup_opno , max_scratch_opno )) + 1;
571 unused = (operands == 0 ? " ATTRIBUTE_UNUSED" : "");
572 used = xcalloc (1, operands);
573
574 /* Output the prototype, function name and argument declarations. */
575 if (GET_CODE (split) == DEFINE_PEEPHOLE2)
576 {
577 printf ("extern rtx gen_%s_%d (rtx, rtx *);/n",
578 name, insn_code_number );
579 printf ("rtx/ngen_%s_%d (rtx curr_insn ATTRIBUTE_UNUSED, rtx *operands%s)/n",
580 name, insn_code_number , unused);
581 }
582 else
583 {
584 printf ("extern rtx gen_split_%d (rtx *);/n", insn_code_number );
585 printf ("rtx/ngen_%s_%d (rtx *operands%s)/n", name, insn_code_number , unused);
586 }
587 printf ("{/n");
在 569 行,因为其第二个参数为 2 , max_operand_vec 检查 define_split 模式的第三个孩子的操作数的个数。显然,在 570 行, operands 是 2 。这里我们假定对于我们的例子 insn_code_number 是 0 ,因此由上面的代码我们得到如下判断。
extern rtx gen_split_0 (rtx *);
rtx
gen_split_0 (rtx *operands)
{
gen_split (continued)
589 /* Declare all local variables. */
590 for (i = 0; i < operands; i++)
591 printf (" rtx operand%d;/n", i);
592 printf (" rtx _val = 0;/n");
593
594 if (GET_CODE (split) == DEFINE_PEEPHOLE2)
595 output_peephole2_scratches (split);
596
597 printf (" start_sequence ();/n");
598
599 /* The fourth operand of DEFINE_SPLIT is some code to be executed
600 before the actual construction. */
601
602 if (XSTR (split, 3))
603 printf ("%s/n", XSTR (split, 3));
604
605 /* Output code to copy the arguments back out of `operands' */
606 for (i = 0; i < operands; i++)
607 printf (" operand%d = operands[%d];/n", i, i);
在执行上面的代码之后,我们将得到如下片段。在 602 行,这个 split 模式的第四个孩子得到处理。
extern rtx gen_split_0 (rtx *);
rtx
gen_split_0 (rtx *operands)
{
rtx operand0;
rtx operand1;
rtx_val = 0;
start_sequence ();
ix86_optimize_mode_switching = 1;
operands[2] = assign_386_stack_local (HImode, 1);
operands[3] = assign_386_stack_local (HImode, 2);
if (memory_operand (operands[0], VOIDmode))
emit_insn (gen_fix_truncdi_memory (operands[0], operands[1],
operands[2], operands[3]));
else
{
operands[4] = assign_386_stack_local (DImode, 0);
emit_insn (gen_fix_truncdi_nomemory (operands[0], operands[1],
operands[2], operands[3],
operands[4]));
}
DONE;
operand0 = operands[0];
operand1 = operands[1];
在上面的代码中, DONE 定义在 main 的 817 行:“ #define DONE return (_val = get_insns (), end_sequence (), _val)/n/n ”。因此在 DONE 下面的代码将得不到执行。
gen_split (continued)
609 /* Output code to construct the rtl for the instruction bodies.
610 Use emit_insn to add them to the sequence being accumulated.
611 But don't do this if the user's code has set `no_more' nonzero. */
612
613 for (i = 0; i < XVECLEN (split, 2); i++)
614 {
615 rtx next = XVECEXP (split, 2, i);
616 if ((GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC)
617 || (GET_CODE (next) == PARALLEL
618 && GET_CODE (XVECEXP (next, 0, 0)) == SET
619 && GET_CODE (SET_DEST (XVECEXP (next, 0, 0))) == PC)
620 || GET_CODE (next) == RETURN)
621 printf (" emit_jump_insn (");
622 else if ((GET_CODE (next) == SET && GET_CODE (SET_SRC (next)) == CALL)
623 || GET_CODE (next) == CALL
624 || (GET_CODE (next) == PARALLEL
625 && GET_CODE (XVECEXP (next, 0, 0)) == SET
626 && GET_CODE (SET_SRC (XVECEXP (next, 0, 0))) == CALL)
627 || (GET_CODE (next) == PARALLEL
628 && GET_CODE (XVECEXP (next, 0, 0)) == CALL))
629 printf (" emit_call_insn (");
630 else if (GET_CODE (next) == CODE_LABEL)
631 printf (" emit_label (");
632 else if (GET_CODE (next) == MATCH_OPERAND
633 || GET_CODE (next) == MATCH_OPERATOR
634 || GET_CODE (next) == MATCH_PARALLEL
635 || GET_CODE (next) == MATCH_OP_DUP
636 || GET_CODE (next) == MATCH_DUP
637 || GET_CODE (next) == PARALLEL)
638 printf (" emit (");
639 else
640 printf (" emit_insn (");
641 gen_exp (next, GET_CODE (split), used);
642 printf (");/n");
643 if (GET_CODE (next) == SET && GET_CODE (SET_DEST (next)) == PC
644 && GET_CODE (SET_SRC (next)) == LABEL_REF)
645 printf (" emit_barrier ();");
646 }
647
648 /* Call `get_insns' to make a list of all the
649 insns emitted within this gen_... function. */
650
651 printf (" _val = get_insns ();/n");
652 printf (" end_sequence ();/n");
653 printf (" return _val;/n}/n/n");
654
655 free (used);
656 }
这个 split 模式的第三个孩子是 const_int ,而 gen_exp 在 641 行被调用来处理它。因此我们最后得到如下的代码。
1 extern rtx gen_split_0 (rtx *);
2 rtx
3 gen_split_0 (rtx *operands)
4 {
5 rtx operand0;
6 rtx operand1;
7 rtx_val = 0;
8 start_sequence ();
9 ix86_optimize_mode_switching = 1;
10 operands[2] = assign_386_stack_local (HImode, 1);
11 operands[3] = assign_386_stack_local (HImode, 2);
12 if (memory_operand (operands[0], VOIDmode))
13 emit_insn (gen_fix_truncdi_memory (operands[0], operands[1],
14 operands[2], operands[3]));
15 else
16 {
17 operands[4] = assign_386_stack_local (DImode, 0);
18 emit_insn (gen_fix_truncdi_nomemory (operands[0], operands[1],
19 operands[2], operands[3],
20 operands[4]));
21 }
22 DONE;
23 operand0 = operands[0];
24 operand1 = operands[1];
25 emit insn (const0_rtx);
26 _val = get_insn ();
27 end_sequence ();
28 return _val;
29 }
好了,现在我们做完了,不过记得这个模式在其名字的开头有‘ * ’,因此事实上它不会被 genemit 生成进入 insn-emit.c 。
4.3. 为 define_peephole2 产生代码
至于 define_peephole 的正式解释,参考 概览 – 关于 define_peephole ,而 define_peephole2 的描述则参考 define_peephole2的概览 。工具 genemit 将为 define_peephole2 模式产生转移( transformation )函数,它将为 recog 相关函数所使用(关于 recog 的细节,参考 genrecog工具 )。
gen_split 也被用于处理 define_peephole2 ,它在 595 行调用。
736 static void
737 output_peephole2_scratches (rtx split) in genemit.c
738 {
739 int i;
740 int insn_nr = 0;
741
742 printf (" HARD_REG_SET _regs_allocated;/n");
743 printf (" CLEAR_HARD_REG_SET (_regs_allocated);/n");
744
745 for (i = 0; i < XVECLEN (split, 0); i++)
746 {
747 rtx elt = XVECEXP (split, 0, i);
748 if (GET_CODE (elt) == MATCH_SCRATCH)
749 {
750 int last_insn_nr = insn_nr;
751 int cur_insn_nr = insn_nr;
752 int j;
753 for (j = i + 1; j < XVECLEN (split, 0); j++)
754 if (GET_CODE (XVECEXP (split, 0, j)) == MATCH_DUP)
755 {
756 if (XINT (XVECEXP (split, 0, j), 0) == XINT (elt, 0))
757 last_insn_nr = cur_insn_nr;
758 }
759 else if (GET_CODE (XVECEXP (split, 0, j)) != MATCH_SCRATCH)
760 cur_insn_nr++;
761
762 printf (" if ((operands[%d] = peep2_find_free_register (%d, %d, /"%s/", %smode, &_regs_allocated)) == NULL_RTX)/n/
763 return NULL;/n",
764 XINT (elt, 0),
765 insn_nr, last_insn_nr,
766 XSTR (elt, 1),
767 GET_MODE_NAME (GET_MODE (elt)));
768
769 }
770 else if (GET_CODE (elt) != MATCH_DUP)
771 insn_nr++;
772 }
773 }
这个函数,为模式中的 match_scratch 操作符,产生选择空闲寄存器的代码。输出的一个例子如下。
if ((operands[2] = peep2_find_free_register (1, 1, "r", SImode, &_regs_allocated)) == NULL_RTX)
return NULL;