2.1.2. Overview of DEFINE_INSN pattern
[ A define_insn as an RTL expression containing four or five operands:
1. An optional name. The presence of a name indicates that this instruction pattern can perform a certain standard job for the RTL-generation pass of the compiler. This pass knows certain names and will use the instruction patterns with those names, if the names are defined in the machine description.
The absence of a name is indicated by writing an empty string where the name should go. Nameless instruction patterns are never used for generating RTL code, but they may permit several simpler insns to be combined later on.
Names that are not thus known and used in RTL-generation have no effect; they are equivalent to no name at all.
A name beginning with the ‘*’ character is used only for identifying the instruction in RTL dump; it’s entirely equivalent to having a nameless pattern for all other purposes.
2. The RTL template is a vector of imcomplete RTL expressions which show what the instruction should look like. It is incomplete because it may contain match_operand, match_operator, and match_dup expressions that stand for operands of the instruction.
3. A condition – a string which contains a C expression that is the final test to decide whether an insn body matches this pattern.
4. The output template: a string that says how to output matching insn as assembler code. ‘%’ in this string specifies where to substitute the value of an operand. When simple substitution isn’t general enough, a piece of C code to compute the output.
5. Optionally, a vector containing the values of attributes for insns matching this pattern. ]
Now define_insn is recognized, and infile currently stays at the first character of string “cmpdi_ccno_1_rex64”. Following read_rtx handles the content according to the format “sEsTV” which corresponding to the five parts of define_insn.
read_rtx (continued)
578 /* If what follows is `: mode ', read it and
579 store the mode in the rtx. */
580
581 i = read_skip_spaces (infile);
582 if (i == ':')
583 {
584 read_name (tmp_char, infile);
585 for (j = 0; j < NUM_MACHINE_MODES; j++)
586 if (! strcmp (GET_MODE_NAME (j), tmp_char))
587 break ;
588
589 if (j == MAX_MACHINE_MODE)
590 fatal_with_file_and_line (infile, "unknown mode `%s'", tmp_char);
591
592 PUT_MODE (return_rtx, (enum machine_mode) j);
593 }
594 else
595 ungetc (i, infile);
596
597 for (i = 0; i < GET_RTX_LENGTH (GET_CODE (return_rtx)); i++)
598 switch (*format_ptr++)
599 {
600 /* 0 means a field for internal use only.
601 Don't expect it to be present in the input. */
602 case '0':
603 break ;
604
605 case 'e':
606 case 'u':
607 XEXP (return_rtx, i) = read_rtx (infile);
608 break ;
609
610 case 'V':
611 /* 'V' is an optional vector: if a closeparen follows,
612 just store NULL for this element. */
613 c = read_skip_spaces (infile);
614 ungetc (c, infile);
615 if (c == ')')
616 {
617 XVEC (return_rtx, i) = 0;
618 break ;
619 }
620 /* Now process the vector. */
621
622 case 'E':
623 {
624 /* Obstack to store scratch vector in. */
625 struct obstack vector_stack;
626 int list_counter = 0;
627 rtvec return_vec = NULL_RTVEC;
628
629 c = read_skip_spaces (infile);
630 if (c != '[')
631 fatal_expected_char (infile, '[', c);
632
633 /* add expressions to a list, while keeping a count */
634 obstack_init (&vector_stack);
635 while ((c = read_skip_spaces (infile)) && c != ']')
636 {
637 ungetc (c, infile);
638 list_counter++;
639 obstack_ptr_grow (&vector_stack, read_rtx (infile));
640 }
641 if (list_counter > 0)
642 {
643 return_vec = rtvec_alloc (list_counter);
644 memcpy (&return_vec->elem[0], obstack_finish (&vector_stack),
645 list_counter * sizeof (rtx));
646 }
647 XVEC (return_rtx, i) = return_vec;
648 obstack_free (&vector_stack, NULL);
649 /* close bracket gotten */
650 }
651 break ;
652
653 case 'S':
654 /* 'S' is an optional string: if a closeparen follows,
655 just store NULL for this element. */
656 c = read_skip_spaces (infile);
657 ungetc (c, infile);
658 if (c == ')')
659 {
660 XSTR (return_rtx, i) = 0;
661 break ;
662 }
663
664 case 'T':
665 case 's':
666 {
667 char *stringbuf;
668
669 /* The output template slot of a DEFINE_INSN,
670 DEFINE_INSN_AND_SPLIT, or DEFINE_PEEPHOLE automatically
671 gets a star inserted as its first character, if it is
672 written with a brace block instead of a string constant. */
673 int star_if_braced = (format_ptr[-1] == 'T');
674
675 stringbuf = read_string (&rtl_obstack, infile, star_if_braced);
676
677 /* For insn patterns, we want to provide a default name
678 based on the file and line, like "*foo.md:12", if the
679 given name is blank. These are only for define_insn and
680 define_insn_and_split, to aid debugging. */
681 if (*stringbuf == '/0'
682 && i == 0
683 && (GET_CODE (return_rtx) == DEFINE_INSN
684 || GET_CODE (return_rtx) == DEFINE_INSN_AND_SPLIT))
685 {
686 char line_name[20];
687 const char *fn = (read_rtx_filename ? read_rtx_filename : "rtx");
688 const char *slash;
689 for (slash = fn; *slash; slash ++)
690 if (*slash == '/' || *slash == '//' || *slash == ':')
691 fn = slash + 1;
692 obstack_1grow (&rtl_obstack, '*');
693 obstack_grow (&rtl_obstack, fn, strlen (fn));
694 sprintf (line_name, ":%d", read_rtx_lineno );
695 obstack_grow (&rtl_obstack, line_name, strlen (line_name)+1);
696 stringbuf = (char *) obstack_finish (&rtl_obstack);
697 }
698
699 if (star_if_braced)
700 XTMPL (return_rtx, i) = stringbuf;
701 else
702 XSTR (return_rtx, i) = stringbuf;
703 }
704 break ;
705
706 case 'w':
707 read_name (tmp_char, infile);
708 validate_const_int (infile, tmp_char);
709 #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_INT
710 tmp_wide = atoi (tmp_char);
711 #else
712 #if HOST_BITS_PER_WIDE_INT == HOST_BITS_PER_LONG
713 tmp_wide = atol (tmp_char);
714 #else
715 /* Prefer atoll over atoq, since the former is in the ISO C99 standard.
716 But prefer not to use our hand-rolled function above either. */
717 #if defined (HAVE_ATOLL) || !defined (HAVE_ATOQ)
718 tmp_wide = atoll (tmp_char);
719 #else
720 tmp_wide = atoq (tmp_char);
721 #endif
722 #endif
723 #endif
724 XWINT (return_rtx, i) = tmp_wide;
725 break ;
726
727 case 'i':
728 case 'n':
729 read_name (tmp_char, infile);
730 validate_const_int (infile, tmp_char);
731 tmp_int = atoi (tmp_char);
732 XINT (return_rtx, i) = tmp_int;
733 break ;
734
735 default :
736 fprintf (stderr ,
737 "switch format wrong in rtl.read_rtx(). format was: %c./n",
738 format_ptr[-1]);
739 fprintf (stderr , "/tfile position: %ld/n", ftell (infile));
740 abort ();
741 }
742
743 c = read_skip_spaces (infile);
744 if (c != ')')
745 fatal_expected_char (infile, ')', c);
746
747 return return_rtx;
748 }
‘S’, ‘T’, ‘s’ are almost same, except that ‘S’ is optonal, and ‘T’ is dependent on RTL reader. And more concretely, if string begins with ‘*’ or ‘@’, ‘T’ requires different explaination. Function read_string retrieves the content.
325 static char *
326 read_string (struct obstack *ob, FILE *infile, int star_if_braced) in read-rtl.c
327 {
328 char *stringbuf;
329 int saw_paren = 0;
330 int c;
331
332 c = read_skip_spaces (infile);
333 if (c == '(')
334 {
335 saw_paren = 1;
336 c = read_skip_spaces (infile);
337 }
338
339 if (c == '"')
340 stringbuf = read_quoted_string (ob, infile);
341 else if (c == '{')
342 {
343 if (star_if_braced)
344 obstack_1grow (ob, '*');
345 stringbuf = read_braced_string (ob, infile);
346 }
347 else
348 fatal_with_file_and_line (infile, "expected `/"' or `{', found `%c'", c);
349
350 if (saw_paren)
351 {
352 c = read_skip_spaces (infile);
353 if (c != ')')
354 fatal_expected_char (infile, ')', c);
355 }
356
357 return stringbuf;
358 }
In md file, the output template in define_insn patterns may be a string enclosed in ‘”’, which commonly tells how to output matching insn as assembler code. But if it begins with ‘*’, following string is assumed be a piece of C program. Other exception includes ‘@’, which indicates a series of templates, each on a separate line. And if the output template is written as a brace block, it is assumed to be C code. However, when creating RTL object, only one style stays – the string form. Above, from line 341 to 345, brace block is replaced by string with star head. Line 681 to 696 create the internal name in case the pattern name begins with ‘*’. At line 700 and 702 in read_rtx , XTMPL and XSTR both access the string in the rtstr field of rtunion but with different validating condition.
Then comes the ‘E’ which corresponds to
[(set (reg 17)
(compare (match_operand:DI 0 "nonimmediate_operand" "r,?mr")
(match_operand:DI 1 "const0_operand" "n,n")))]
This part must be enclosed with “[]”. Above at line 630 in read_rtx does the test, and as the content itself is an expression, so read_rtx is recursed at line 639 to handle the expression further. Here it is the set expression, and we can find following defintion in rtl.def.
746 DEF_RTL_EXPR(SET, "set", "ee", 'x')
The expression has two children. So at line 605, read_rtx is recursed again, once for reg expression, and once for compare expression. No doubtly, compare expression in rtl.def also has two children of expression (‘e’), which are both match_operand expression.
129 DEF_RTL_EXPR(MATCH_OPERAND, "match_operand", "iss", 'm')
130 DEF_RTL_EXPR(REG, "reg", "i00", 'o')
Guided by format string, it is easy to travel round by read_rtx , and in the end we can get an rtx object of above pattern as following:
http://hi.csdn.net/attachment/201104/16/4457637_130291210053ob.jpg
figure 1 : genconditions - example of define_insn pattern
In the same way, all patterns except define_constants in the machine description file are treated and allocated with an rtx object like that above. Next this rtx object needs to be recorded by some way.
264 static void
265 process_rtx (rtx desc, int lineno) in gensupport.c
266 {
267 switch (GET_CODE (desc))
268 {
269 case DEFINE_INSN:
270 queue_pattern (desc, &define_insn_tail , read_rtx_filename , lineno);
271 break ;
272
273 case DEFINE_COND_EXEC:
274 queue_pattern (desc, &define_cond_exec_tail , read_rtx_filename , lineno);
275 break ;
276
277 case DEFINE_ATTR:
278 queue_pattern (desc, &define_attr_tail , read_rtx_filename , lineno);
279 break ;
280
281 case INCLUDE:
282 process_include (desc, lineno);
283 break ;
284
285 case DEFINE_INSN_AND_SPLIT:
286 {
287 const char *split_cond;
288 rtx split;
289 rtvec attr;
290 int i;
291
292 /* Create a split with values from the insn_and_split. */
293 split = rtx_alloc (DEFINE_SPLIT);
294
295 i = XVECLEN (desc, 1);
296 XVEC (split, 0) = rtvec_alloc (i);
297 while (--i >= 0)
298 {
299 XVECEXP (split, 0, i) = copy_rtx (XVECEXP (desc, 1, i));
300 remove_constraints (XVECEXP (split, 0, i));
301 }
302
303 /* If the split condition starts with "&&", append it to the
304 insn condition to create the new split condition. */
305 split_cond = XSTR (desc, 4);
306 if (split_cond[0] == '&' && split_cond[1] == '&')
307 split_cond = concat (XSTR (desc, 2), split_cond, NULL);
308 XSTR (split, 1) = split_cond;
309 XVEC (split, 2) = XVEC (desc, 5);
310 XSTR (split, 3) = XSTR (desc, 6);
311
312 /* Fix up the DEFINE_INSN. */
313 attr = XVEC (desc, 7);
314 PUT_CODE (desc, DEFINE_INSN);
315 XVEC (desc, 4) = attr;
316
317 /* Queue them. */
318 queue_pattern (desc, &define_insn_tail , read_rtx_filename , lineno);
319 queue_pattern (split, &other_tail , read_rtx_filename , lineno);
320 break ;
321 }
322
323 default :
324 queue_pattern (desc, &other_tail , read_rtx_filename , lineno);
325 break ;
326 }
327 }
Instructions and attributes are close related, but till now we still need to save them separatly, function queue_pattern just puts the specified rtx object into the corresponding list.
139 static void
140 queue_pattern (rtx pattern, struct queue_elem ***list_tail, in gensupport.c
141 const char *filename, int lineno)
142 {
143 struct queue_elem *e = xmalloc (sizeof (*e));
144 e->data = pattern;
145 e->filename = filename;
146 e->lineno = lineno;
147 e->next = NULL;
148 **list_tail = e;
149 *list_tail = &e->next;
150 }
Above, at line 281 in process_rtx , in machine description file, we can include other machine description files by using include statement. Here in process_include , these included machine description files will be read in and treated in the same way. Other special pattern is define_insn_and_split. It is combined pattern; here it is separated into define_insn and define_split. We see the treatment by an exmaple in following:
4225 (define_insn_and_split "*fix_truncsi_1" in i386.md
4226 [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r")
4227 (fix:SI (match_operand 1 "register_operand" "f,f")))]
4228 "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))
4229 && !reload_completed && !reload_in_progress
4230 && !SSE_FLOAT_MODE_P (GET_MODE (operands[1]))"
4231 "#"
4232 "&& 1"
4233 [(const_int 0)]
4234 {
4235 ix86_optimize_mode_switching = 1;
4236 operands[2] = assign_386_stack_local (HImode, 1);
4237 operands[3] = assign_386_stack_local (HImode, 2);
4238 if (memory_operand (operands[0], VOIDmode))
4239 emit_insn (gen_fix_truncsi_memory (operands[0], operands[1],
4240 operands[2], operands[3]));
4241 else
4242 {
4243 operands[4] = assign_386_stack_local (SImode, 0);
4244 emit_insn (gen_fix_truncsi_nomemory (operands[0], operands[1],
4245 operands[2], operands[3],
4246 operands[4]));
4247 }
4248 DONE;
4249 }
4250 [(set_attr "type" "fistp")
4251 (set_attr "mode" "SI")])
This pattern after treated in read_rtx , we can get following rtx object.
figure 2 : genconditions - example of define_insn_and_split pattern, figure 1
After processed by case block at line 285, we can get two rtx objects as following:
figure 3 : genconditons - example of define_insn_and_split pattern, figure 2
figure 4 : gencodntion - example of define_insn_and_split pattern, figure 3