This tool outputs insn-emit.c file from machine description file. Insn-emit.c defines function sto generate a body for patterns, given operands as arguments.
775 int
776 main (int argc, char **argv) in genemit.c
777 {
778 rtx desc;
779
780 progname = "genemit";
781
782 if (argc <= 1)
783 fatal ("no input file name");
784
785 if (init_md_reader_args (argc, argv) != SUCCESS_EXIT_CODE)
786 return (FATAL_EXIT_CODE);
787
788 /* Assign sequential codes to all entries in the machine description
789 i n parallel with the tables in insn-output.c. */
790
791 insn_code_number = 0;
792 insn_index_number = 0;
793
794 printf ("/* Generated automatically by the program `genemit'/n/
795 from the machine description file `md'. *//n/n");
796
797 printf ("#include /"config.h/"/n");
798 printf ("#include /"system.h/"/n");
799 printf ("#include /"coretypes.h/"/n");
800 printf ("#include /"tm.h/"/n");
801 printf ("#include /"rtl.h/"/n");
802 printf ("#include /"tm_p.h/"/n");
803 printf ("#include /"function.h/"/n");
804 printf ("#include /"expr.h/"/n");
805 printf ("#include /"optabs.h/"/n");
806 printf ("#include /"real.h/"/n");
807 printf ("#include /"flags.h/"/n");
808 printf ("#include /"output.h/"/n");
809 printf ("#include /"insn-config.h/"/n");
810 printf ("#include /"hard-reg-set.h/"/n");
811 printf ("#include /"recog.h/"/n");
812 printf ("#include /"resource.h/"/n");
813 printf ("#include /"reload.h/"/n");
814 printf ("#include /"toplev.h/"/n");
815 printf ("#include /"ggc.h/"/n/n");
816 printf ("#define FAIL return (end_sequence (), _val)/n");
817 printf ("#define DONE return (_val = get_insns (), end_sequence (), _val)/n/n");
The beginning all looks alike. At line 785, init_md_reader_args reads in the machine description file and creates corresponding rtx objects. We just takes the define_insn_and_split example in Tool of genconditions , which will be splited into two rtx objects.
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")])
Then in following, in main we will handle the rtx object instead.
main (continued)
819 /* Read the machine description. */
820
821 while (1)
822 {
823 int line_no;
824
825 desc = read_md_rtx (&line_no, &insn_code_number);
826 if (desc == NULL)
827 break ;
828
829 switch (GET_CODE (desc))
830 {
831 case DEFINE_INSN:
832 gen_insn (desc, line_no);
833 break ;
834
835 case DEFINE_EXPAND:
836 printf ("/* %s:%d *//n", read_rtx_filename, line_no);
837 gen_expand (desc);
838 break ;
839
840 case DEFINE_SPLIT:
841 printf ("/* %s:%d *//n", read_rtx_filename, line_no);
842 gen_split (desc);
843 break ;
844
845 case DEFINE_PEEPHOLE2:
846 printf ("/* %s:%d *//n", read_rtx_filename, line_no);
847 gen_split (desc);
848 break ;
849
850 default :
851 break ;
852 }
853 ++insn_index_number;
854 }
855
856 /* Write out the routines to add CLOBBERs to a pattern and say whether they
857 clobber a hard reg. */
858 output_add_clobbers ();
859 output_added_clobbers_hard_reg_p ();
860
861 fflush (stdout);
862 return (ferror (stdout) != 0 ? FATAL_EXIT_CODE : SUCCESS_EXIT_CODE);
863 }
For our example define_insn_and_split pattern, after read in, the define_insn part is as following.
figure 29 : genemit - example of define_insn_and_split pattern – insn part
It is a define_insn rtx object, so gen_insn will be invoked.
287 static void
288 gen_ins n (rtx insn, int lineno) in genemit.c
289 {
290 int operands;
291 int i;
292
293 /* See if the pattern for this insn ends with a group of CLOBBERs of (hard)
294 registers or MATCH_SCRATCHes. If so, store away the information for
295 later. */
296
297 if (XVEC (insn, 1))
298 {
299 int has_hard_reg = 0;
300
301 for (i = XVECLEN (insn, 1) - 1; i > 0; i--)
302 {
303 if (GET_CODE (XVECEXP (insn, 1, i)) != CLOBBER)
304 break ;
305
306 if (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) == REG)
307 has_hard_reg = 1;
308 else if (GET_CODE (XEXP (XVECEXP (insn, 1, i), 0)) != MATCH_SCRATCH)
309 break ;
310 }
For our example above, it breaks out the loop at line 304, as the pattern doesn’t clobber any register.
gen_insn (continued)
312 if (i != XVECLEN (insn, 1) - 1)
313 {
314 struct clobber_pat *p;
315 struct clobber_ent *link = xmalloc (sizeof (struct clobber_ent));
316 int j;
317
318 link->code_number = insn_code_number ;
319
320 /* See if any previous CLOBBER_LIST entry is the same as this
321 one. */
322
323 for (p = clobber_list ; p; p = p->next)
324 {
325 if (p->first_clobber != i + 1
326 || XVECLEN (p->pattern, 1) != XVECLEN (insn, 1))
327 continue ;
328
329 for (j = i + 1; j < XVECLEN (insn, 1); j++)
330 {
331 rtx old = XEXP (XVECEXP (p->pattern, 1, j), 0);
332 rtx new = XEXP (XVECEXP (insn, 1, j), 0);
333
334 /* OLD and NEW are the same if both are to be a SCRATCH
335 of the same mode,
336 or if both are registers of the same mode and number. */
337 if (! (GET_MODE (old) == GET_MODE (new)
338 && ((GET_CODE (old) == MATCH_SCRATCH
339 && GET_CODE (new) == MATCH_SCRATCH)
340 || (GET_CODE (old) == REG && GET_CODE (new) == REG
341 && REGNO (old) == REGNO (new)))))
342 break ;
343 }
344
345 if (j == XVECLEN (insn, 1))
346 break ;
347 }
348
349 if (p == 0)
350 {
351 p = xmalloc (sizeof (struct clobber_pat));
352
353 p->insns = 0;
354 p->pattern = insn;
355 p->first_clobber = i + 1;
356 p->next = clobber_list ;
357 p->has_hard_reg = has_hard_reg;
358 clobber_list = p;
359 }
360
361 link->next = p->insns;
362 p->insns = link;
363 }
364 }
Above, for pattern will clobber register, the relative information must be saved in clobber_list. It has following definition:
42 struct clobber_pat in genemit.c
43 {
44 struct clobber_ent *insns;
45 rtx pattern;
46 int first_clobber;
47 struct clobber_pat *next;
48 int has_hard_reg;
49 } *clobber_list;
50
51 /* Records one insn that uses the clobber list. */
52
53 struct clobber_ent
54 {
55 int code_number; /* Counts only insns. */
56 struct clobber_ent *next;
57 };
clobber_pat keeps the record of clobber information for the patterns having the same form, in other words, for two patterns have different form, they will belong to different clobber_pat instances. So has_hard_reg , first_clobber are meaningful for all members in clobber_ent , in which first_clobber means at which step the specified register will be clobbered and has_hard_reg indicates if real register is involved.
code_number in clobber_ent distincts the patterns, as it comes from insn_code_number , which is unique and invariable for specified pattern. Obviously, clobber_ent is per pattern. And for our example, no clobber information is collected.
gen_insn (continued)
366 /* Don't mention instructions whose names are the null string
367 or begin with '*'. They are in the machine description just
368 to be recognized. */
369 if (XSTR (insn, 0)[0] == 0 || XSTR (insn, 0)[0] == '*')
370 return ;
371
372 printf ("/* %s:%d *//n", read_rtx_filename , lineno);
373
374 /* Find out how many operands this function has. */
375 operands = max_operand_vec (insn, 1);
376 if (max_dup_opno >= operands)
377 fatal ("match_dup operand number has no match_operand");
378 /* Output the function name and argument declarations. */
379 printf ("rtx/ngen_%s (", XSTR (insn, 0));
380 if (operands)
381 for (i = 0; i < operands; i++)
382 if (i)
383 printf (",/n/trtx operand%d ATTRIBUTE_UNUSED", i);
384 else
385 printf ("rtx operand%d ATTRIBUTE_UNUSED", i);
386 else
387 printf ("void");
388 printf (")/n");
389 printf ("{/n");
Unfortunatly, our example has ‘*’ at the beginning of its name, which means the instruction pattern is never used for generating RTL code and such a name is used only for identifying the instruction in RTL dumps. So in real world, it will return at line 370 without doing something meaningful.
Now, we assuem that the ‘*’ is not appeared all long. At line 372, it gives information where we are from. At line 375, max_operand_vec finds out the number of operands in the pattern. This function is quite simple. For our example, max_opno will be 2.
108 static int
109 max_operand_vec (rtx insn, int arg) in genemit.c
110 {
111 int len = XVECLEN (insn, arg);
112 int i;
113
114 max_opno = -1;
115 max_dup_opno = -1;
116 max_scratch_opno = -1;
117
118 for (i = 0; i < len; i++)
119 max_operand_1 (XVECEXP (insn, arg, i));
120
121 return max_opno + 1;
122 }
72 static void
73 max_operand_1 (rtx x) in genemit.c
74 {
75 RTX_CODE code;
76 int i;
77 int len;
78 const char *fmt;
79
80 if (x == 0)
81 return ;
82
83 code = GET_CODE (x);
84
85 if (code == MATCH_OPERAND || code == MATCH_OPERATOR
86 || code == MATCH_PARALLEL)
87 max_opno = MAX (max_opno , XINT (x, 0));
88 if (code == MATCH_DUP || code == MATCH_OP_DUP || code == MATCH_PAR_DUP)
89 max_dup_opno = MAX (max_dup_opno , XINT (x, 0));
90 if (code == MATCH_SCRATCH)
91 max_scratch_opno = MAX (max_scratch_opno , XINT (x, 0));
92
93 fmt = GET_RTX_FORMAT (code);
94 len = GET_RTX_LENGTH (code);
95 for (i = 0; i < len; i++)
96 {
97 if (fmt[i] == 'e' || fmt[i] == 'u')
98 max_operand_1 (XEXP (x, i));
99 else if (fmt[i] == 'E')
100 {
101 int j;
102 for (j = 0; j < XVECLEN (x, i); j++)
103 max_operand_1 (XVECEXP (x, i, j));
104 }
105 }
106 }
Then we will get the function definition as below (assume the pattern name is fix_truncsi_1 instead of *fix_truncsi_1) from above code fragment.
rtx
gen_fix_truncsi_1(rtx operand0 ATTRIBUTE_UNUSED,
rtx operand1 ATTRIBUTE_UNUSED,
rtx operand2 ATTRIBUTE_UNUSED)
{
gen_insn (continued)
392 /* Output code to construct and return the rtl for the instruction body. */
393
394 if (XVECLEN (insn, 1) == 1)
395 {
396 printf (" return ");
397 gen_exp (XVECEXP (insn, 1, 0), DEFINE_INSN, NULL);
398 printf (";/n}/n/n");
399 }
400 else
401 {
402 printf (" return gen_rtx_PARALLEL (VOIDmode, gen_rtvec (%d",
403 XVECLEN (insn, 1));
404
405 for (i = 0; i < XVECLEN (insn, 1); i++)
406 {
407 printf (",/n/t/t");
408 gen_exp (XVECEXP (insn, 1, i), DEFINE_INSN, NULL);
409 }
410 printf ("));/n}/n/n");
411 }
412 }
In rtx format of define_pattern, RTL template has format ‘E’ – vector of rtx objects. Above, at line 394 XVECLEN gets the size of the vector, and at line 408 XVECEXP gets the element in the vector. For parameter x of gen_exp , it points to RTL template as following.
4225 [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r")
4226 (fix:SI (match_operand 1 "register_operand" "f,f")))]
148 static void
149 gen_exp (rtx x, enum rtx_code subroutine_type, char *used) in genemit.c
150 {
151 RTX_CODE code;
152 int i;
153 int len;
154 const char *fmt;
155
156 if (x == 0)
157 {
158 printf ("NULL_RTX");
159 return ;
160 }
161
162 code = GET_CODE (x);
163
164 switch (code)
165 {
166 case MATCH_OPERAND:
167 case MATCH_DUP:
168 if (used)
169 {
170 if (used[XINT (x, 0)])
171 {
172 printf ("copy_rtx (operand%d)", XINT (x, 0));
173 return ;
174 }
175 used[XINT (x, 0)] = 1;
176 }
177 printf ("operand%d", XINT (x, 0));
178 return ;
179
180 case MATCH_OP_DUP:
181 printf ("gen_rtx (GET_CODE (operand%d), ", XINT (x, 0));
182 if (GET_MODE (x) == VOIDmode)
183 printf ("GET_MODE (operand%d)", XINT (x, 0));
184 else
185 printf ("%smode", GET_MODE_NAME (GET_MODE (x)));
186 for (i = 0; i < XVECLEN (x, 1); i++)
187 {
188 printf (",/n/t/t");
189 gen_exp (XVECEXP (x, 1, i), subroutine_type, used);
190 }
191 printf (")");
192 return ;
193
194 case MATCH_OPERATOR:
195 printf ("gen_rtx (GET_CODE (operand%d)", XINT (x, 0));
196 printf (", %smode", GET_MODE_NAME (GET_MODE (x)));
197 for (i = 0; i < XVECLEN (x, 2); i++)
198 {
199 printf (",/n/t/t");
200 gen_exp (XVECEXP (x, 2, i), subroutine_type, used);
201 }
202 printf (")");
203 return ;
204
205 case MATCH_PARALLEL:
206 case MATCH_PAR_DUP:
207 printf ("operand%d", XINT (x, 0));
208 return ;
209
210 case MATCH_SCRATCH:
211 gen_rtx_scratch (x, subroutine_type);
212 return ;
213
214 case ADDRESS:
215 fatal ("ADDRESS expression code used in named instruction pattern");
216
217 case PC:
218 printf ("pc_rtx");
219 return ;
220
221 case CC0:
222 printf ("cc0_rtx");
223 return ;
224
225 case CONST_INT:
226 if (INTVAL (x) == 0)
227 printf ("const0_rtx");
228 else if (INTVAL (x) == 1)
229 printf ("const1_rtx");
230 else if (INTVAL (x) == -1)
231 printf ("constm1_rtx");
232 else if (INTVAL (x) == STORE_FLAG_VALUE)
233 printf ("const_true_rtx");
234 else
235 {
236 printf ("GEN_INT (");
237 printf (HOST_WIDE_INT_PRINT_DEC_C, INTVAL (x));
238 printf (")");
239 }
240 return ;
241
242 case CONST_DOUBLE:
243 /* These shouldn't be written in MD files. Instead, the appropriate
244 routines in varasm.c should be called. */
245 abort ();
246
247 default :
248 break ;
249 }
250
251 printf ("gen_rtx_");
252 print_code (code);
253 printf (" (%smode", GET_MODE_NAME (GET_MODE (x)));
For our example here, the code is SET, so we drop to line 251 directly. As the set pattern hasn’t mode information with it, the mode is VIODmode in default. Now we get:
rtx
gen_fix_truncsi_1(rtx operand0 ATTRIBUTE_UNUSED,
rtx operand1 ATTRIBUTE_UNUSED,
rtx operand2 ATTRIBUTE_UNUSED)
{
return gen_rtx_set (VOIDmode,
For set pattern, its rtl format is “ee”, so recursing gen_exp with its children at line 263.
gen_exp (continued)
255 fmt = GET_RTX_FORMAT (code);
256 len = GET_RTX_LENGTH (code);
257 for (i = 0; i < len; i++)
258 {
259 if (fmt[i] == '0')
260 break ;
261 printf (",/n/t");
262 if (fmt[i] == 'e' || fmt[i] == 'u')
263 gen_exp (XEXP (x, i), subroutine_type, used);
264 else if (fmt[i] == 'i')
265 printf ("%u", XINT (x, i));
266 else if (fmt[i] == 's')
267 printf ("/"%s/"", XSTR (x, i));
268 else if (fmt[i] == 'E')
269 {
270 int j;
271 printf ("gen_rtvec (%d", XVECLEN (x, i));
272 for (j = 0; j < XVECLEN (x, i); j++)
273 {
274 printf (",/n/t/t");
275 gen_exp (XVECEXP (x, i, j), subroutine_type, used);
276 }
277 printf (")");
278 }
279 else
280 abort ();
281 }
282 printf (")");
283 }
The first child of set pattern is match_operand , and we will enter at line 166. Note that the used parameter of the gen_exp is null, so we get:
rtx
gen_fix_truncsi_1(rtx operand0 ATTRIBUTE_UNUSED,
rtx operand1 ATTRIBUTE_UNUSED,
rtx operand2 ATTRIBUTE_UNUSED)
{
return gen_rtx_set (VOIDmode,
operand0
The second child of set pattern is fix , its rtl format is ‘e’. Again, we just drop to line 251 as set pattern. And it will recurse gen_exp with its first child match_operand too. So we get following code for this set pattern.
rtx
gen_fix_truncsi_1(rtx operand0 ATTRIBUTE_UNUSED,
rtx operand1 ATTRIBUTE_UNUSED,
rtx operand2 ATTRIBUTE_UNUSED)
{
return gen_rtx_SET (VOIDmode,
operand0,
gen_rtx_FIX (SImode,
operand1));
}