]>
Commit | Line | Data |
---|---|---|
c63539ff ML |
1 | .. |
2 | Copyright 1988-2022 Free Software Foundation, Inc. | |
3 | This is part of the GCC manual. | |
4 | For copying conditions, see the copyright.rst file. | |
5 | ||
6 | .. index:: iterators in .md files | |
7 | ||
8 | .. _iterators: | |
9 | ||
10 | Iterators | |
11 | ********* | |
12 | ||
13 | Ports often need to define similar patterns for more than one machine | |
14 | mode or for more than one rtx code. GCC provides some simple iterator | |
15 | facilities to make this process easier. | |
16 | ||
17 | .. toctree:: | |
18 | :maxdepth: 2 | |
19 | ||
20 | ||
21 | .. index:: mode iterators in .md files | |
22 | ||
23 | .. _mode-iterators: | |
24 | ||
25 | Mode Iterators | |
26 | ^^^^^^^^^^^^^^ | |
27 | ||
28 | Ports often need to define similar patterns for two or more different modes. | |
29 | For example: | |
30 | ||
31 | * If a processor has hardware support for both single and double | |
32 | floating-point arithmetic, the ``SFmode`` patterns tend to be | |
33 | very similar to the ``DFmode`` ones. | |
34 | ||
35 | * If a port uses ``SImode`` pointers in one configuration and | |
36 | ``DImode`` pointers in another, it will usually have very similar | |
37 | ``SImode`` and ``DImode`` patterns for manipulating pointers. | |
38 | ||
39 | Mode iterators allow several patterns to be instantiated from one | |
40 | :samp:`.md` file template. They can be used with any type of | |
41 | rtx-based construct, such as a ``define_insn``, | |
42 | ``define_split``, or ``define_peephole2``. | |
43 | ||
44 | .. toctree:: | |
45 | :maxdepth: 2 | |
46 | ||
47 | ||
48 | .. index:: define_mode_iterator | |
49 | ||
50 | .. _defining-mode-iterators: | |
51 | ||
52 | Defining Mode Iterators | |
53 | ~~~~~~~~~~~~~~~~~~~~~~~ | |
54 | ||
55 | The syntax for defining a mode iterator is: | |
56 | ||
57 | .. code-block:: | |
58 | ||
59 | (define_mode_iterator name [(mode1 "cond1") ... (moden "condn")]) | |
60 | ||
61 | This allows subsequent :samp:`.md` file constructs to use the mode suffix | |
62 | ``:name``. Every construct that does so will be expanded | |
63 | :samp:`{n}` times, once with every use of ``:name`` replaced by | |
64 | ``:mode1``, once with every use replaced by ``:mode2``, | |
65 | and so on. In the expansion for a particular :samp:`{modei}`, every | |
66 | C condition will also require that :samp:`{condi}` be true. | |
67 | ||
68 | For example: | |
69 | ||
70 | .. code-block:: | |
71 | ||
72 | (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")]) | |
73 | ||
74 | defines a new mode suffix ``:P``. Every construct that uses | |
75 | ``:P`` will be expanded twice, once with every ``:P`` replaced | |
76 | by ``:SI`` and once with every ``:P`` replaced by ``:DI``. | |
77 | The ``:SI`` version will only apply if ``Pmode == SImode`` and | |
78 | the ``:DI`` version will only apply if ``Pmode == DImode``. | |
79 | ||
80 | As with other :samp:`.md` conditions, an empty string is treated | |
81 | as 'always true'. ``(mode "")`` can also be abbreviated | |
82 | to ``mode``. For example: | |
83 | ||
84 | .. code-block:: | |
85 | ||
86 | (define_mode_iterator GPR [SI (DI "TARGET_64BIT")]) | |
87 | ||
88 | means that the ``:DI`` expansion only applies if ``TARGET_64BIT`` | |
89 | but that the ``:SI`` expansion has no such constraint. | |
90 | ||
91 | Iterators are applied in the order they are defined. This can be | |
92 | significant if two iterators are used in a construct that requires | |
93 | substitutions. See :ref:`substitutions`. | |
94 | ||
95 | .. index:: define_mode_attr | |
96 | ||
97 | .. _substitutions: | |
98 | ||
99 | Substitution in Mode Iterators | |
100 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | |
101 | ||
102 | If an :samp:`.md` file construct uses mode iterators, each version of the | |
103 | construct will often need slightly different strings or modes. For | |
104 | example: | |
105 | ||
106 | * When a ``define_expand`` defines several ``addm3`` patterns | |
107 | (see :ref:`standard-names`), each expander will need to use the | |
108 | appropriate mode name for :samp:`{m}`. | |
109 | ||
110 | * When a ``define_insn`` defines several instruction patterns, | |
111 | each instruction will often use a different assembler mnemonic. | |
112 | ||
113 | * When a ``define_insn`` requires operands with different modes, | |
114 | using an iterator for one of the operand modes usually requires a specific | |
115 | mode for the other operand(s). | |
116 | ||
117 | GCC supports such variations through a system of 'mode attributes'. | |
118 | There are two standard attributes: ``mode``, which is the name of | |
119 | the mode in lower case, and ``MODE``, which is the same thing in | |
120 | upper case. You can define other attributes using: | |
121 | ||
122 | .. code-block:: | |
123 | ||
124 | (define_mode_attr name [(mode1 "value1") ... (moden "valuen")]) | |
125 | ||
126 | where :samp:`{name}` is the name of the attribute and :samp:`{valuei}` | |
127 | is the value associated with :samp:`{modei}`. | |
128 | ||
129 | When GCC replaces some :samp:`{:iterator}` with :samp:`{:mode}`, it will scan | |
130 | each string and mode in the pattern for sequences of the form | |
131 | ``<iterator:attr>``, where :samp:`{attr}` is the name of a | |
132 | mode attribute. If the attribute is defined for :samp:`{mode}`, the whole | |
133 | ``<...>`` sequence will be replaced by the appropriate attribute | |
134 | value. | |
135 | ||
136 | For example, suppose an :samp:`.md` file has: | |
137 | ||
138 | .. code-block:: | |
139 | ||
140 | (define_mode_iterator P [(SI "Pmode == SImode") (DI "Pmode == DImode")]) | |
141 | (define_mode_attr load [(SI "lw") (DI "ld")]) | |
142 | ||
143 | If one of the patterns that uses ``:P`` contains the string | |
144 | ``"<P:load>\t%0,%1"``, the ``SI`` version of that pattern | |
145 | will use ``"lw\t%0,%1"`` and the ``DI`` version will use | |
146 | ``"ld\t%0,%1"``. | |
147 | ||
148 | Here is an example of using an attribute for a mode: | |
149 | ||
150 | .. code-block:: | |
151 | ||
152 | (define_mode_iterator LONG [SI DI]) | |
153 | (define_mode_attr SHORT [(SI "HI") (DI "SI")]) | |
154 | (define_insn ... | |
155 | (sign_extend:LONG (match_operand:<LONG:SHORT> ...)) ...) | |
156 | ||
157 | The ``iterator:`` prefix may be omitted, in which case the | |
158 | substitution will be attempted for every iterator expansion. | |
159 | ||
160 | .. _examples: | |
161 | ||
162 | Mode Iterator Examples | |
163 | ~~~~~~~~~~~~~~~~~~~~~~ | |
164 | ||
165 | Here is an example from the MIPS port. It defines the following | |
166 | modes and attributes (among others): | |
167 | ||
168 | .. code-block:: | |
169 | ||
170 | (define_mode_iterator GPR [SI (DI "TARGET_64BIT")]) | |
171 | (define_mode_attr d [(SI "") (DI "d")]) | |
172 | ||
173 | and uses the following template to define both ``subsi3`` | |
174 | and ``subdi3`` : | |
175 | ||
176 | .. code-block:: | |
177 | ||
178 | (define_insn "sub<mode>3" | |
179 | [(set (match_operand:GPR 0 "register_operand" "=d") | |
180 | (minus:GPR (match_operand:GPR 1 "register_operand" "d") | |
181 | (match_operand:GPR 2 "register_operand" "d")))] | |
182 | "" | |
183 | "<d>subu\t%0,%1,%2" | |
184 | [(set_attr "type" "arith") | |
185 | (set_attr "mode" "<MODE>")]) | |
186 | ||
187 | This is exactly equivalent to: | |
188 | ||
189 | .. code-block:: | |
190 | ||
191 | (define_insn "subsi3" | |
192 | [(set (match_operand:SI 0 "register_operand" "=d") | |
193 | (minus:SI (match_operand:SI 1 "register_operand" "d") | |
194 | (match_operand:SI 2 "register_operand" "d")))] | |
195 | "" | |
196 | "subu\t%0,%1,%2" | |
197 | [(set_attr "type" "arith") | |
198 | (set_attr "mode" "SI")]) | |
199 | ||
200 | (define_insn "subdi3" | |
201 | [(set (match_operand:DI 0 "register_operand" "=d") | |
202 | (minus:DI (match_operand:DI 1 "register_operand" "d") | |
203 | (match_operand:DI 2 "register_operand" "d")))] | |
204 | "TARGET_64BIT" | |
205 | "dsubu\t%0,%1,%2" | |
206 | [(set_attr "type" "arith") | |
207 | (set_attr "mode" "DI")]) | |
208 | ||
209 | .. index:: code iterators in .md files, define_code_iterator, define_code_attr | |
210 | ||
211 | .. _code-iterators: | |
212 | ||
213 | Code Iterators | |
214 | ^^^^^^^^^^^^^^ | |
215 | ||
216 | Code iterators operate in a similar way to mode iterators. See :ref:`mode-iterators`. | |
217 | ||
218 | The construct: | |
219 | ||
220 | .. code-block:: | |
221 | ||
222 | (define_code_iterator name [(code1 "cond1") ... (coden "condn")]) | |
223 | ||
224 | defines a pseudo rtx code :samp:`{name}` that can be instantiated as | |
225 | :samp:`{codei}` if condition :samp:`{condi}` is true. Each :samp:`{codei}` | |
226 | must have the same rtx format. See :ref:`rtl-classes`. | |
227 | ||
228 | As with mode iterators, each pattern that uses :samp:`{name}` will be | |
229 | expanded :samp:`{n}` times, once with all uses of :samp:`{name}` replaced by | |
230 | :samp:`{code1}`, once with all uses replaced by :samp:`{code2}`, and so on. | |
231 | See :ref:`defining-mode-iterators`. | |
232 | ||
233 | It is possible to define attributes for codes as well as for modes. | |
234 | There are two standard code attributes: ``code``, the name of the | |
235 | code in lower case, and ``CODE``, the name of the code in upper case. | |
236 | Other attributes are defined using: | |
237 | ||
238 | .. code-block:: | |
239 | ||
240 | (define_code_attr name [(code1 "value1") ... (coden "valuen")]) | |
241 | ||
242 | Instruction patterns can use code attributes as rtx codes, which can be | |
243 | useful if two sets of codes act in tandem. For example, the following | |
244 | ``define_insn`` defines two patterns, one calculating a signed absolute | |
245 | difference and another calculating an unsigned absolute difference: | |
246 | ||
247 | .. code-block:: | |
248 | ||
249 | (define_code_iterator any_max [smax umax]) | |
250 | (define_code_attr paired_min [(smax "smin") (umax "umin")]) | |
251 | (define_insn ... | |
252 | [(set (match_operand:SI 0 ...) | |
253 | (minus:SI (any_max:SI (match_operand:SI 1 ...) | |
254 | (match_operand:SI 2 ...)) | |
255 | (<paired_min>:SI (match_dup 1) (match_dup 2))))] | |
256 | ...) | |
257 | ||
258 | The signed version of the instruction uses ``smax`` and ``smin`` | |
259 | while the unsigned version uses ``umax`` and ``umin``. There | |
260 | are no versions that pair ``smax`` with ``umin`` or ``umax`` | |
261 | with ``smin``. | |
262 | ||
263 | Here's an example of code iterators in action, taken from the MIPS port: | |
264 | ||
265 | .. code-block:: | |
266 | ||
267 | (define_code_iterator any_cond [unordered ordered unlt unge uneq ltgt unle ungt | |
268 | eq ne gt ge lt le gtu geu ltu leu]) | |
269 | ||
270 | (define_expand "b<code>" | |
271 | [(set (pc) | |
272 | (if_then_else (any_cond:CC (cc0) | |
273 | (const_int 0)) | |
274 | (label_ref (match_operand 0 "")) | |
275 | (pc)))] | |
276 | "" | |
277 | { | |
278 | gen_conditional_branch (operands, <CODE>); | |
279 | DONE; | |
280 | }) | |
281 | ||
282 | This is equivalent to: | |
283 | ||
284 | .. code-block:: | |
285 | ||
286 | (define_expand "bunordered" | |
287 | [(set (pc) | |
288 | (if_then_else (unordered:CC (cc0) | |
289 | (const_int 0)) | |
290 | (label_ref (match_operand 0 "")) | |
291 | (pc)))] | |
292 | "" | |
293 | { | |
294 | gen_conditional_branch (operands, UNORDERED); | |
295 | DONE; | |
296 | }) | |
297 | ||
298 | (define_expand "bordered" | |
299 | [(set (pc) | |
300 | (if_then_else (ordered:CC (cc0) | |
301 | (const_int 0)) | |
302 | (label_ref (match_operand 0 "")) | |
303 | (pc)))] | |
304 | "" | |
305 | { | |
306 | gen_conditional_branch (operands, ORDERED); | |
307 | DONE; | |
308 | }) | |
309 | ||
310 | ... | |
311 | ||
312 | .. index:: int iterators in .md files, define_int_iterator, define_int_attr | |
313 | ||
314 | .. _int-iterators: | |
315 | ||
316 | Int Iterators | |
317 | ^^^^^^^^^^^^^ | |
318 | ||
319 | Int iterators operate in a similar way to code iterators. See :ref:`code-iterators`. | |
320 | ||
321 | The construct: | |
322 | ||
323 | .. code-block:: | |
324 | ||
325 | (define_int_iterator name [(int1 "cond1") ... (intn "condn")]) | |
326 | ||
327 | defines a pseudo integer constant :samp:`{name}` that can be instantiated as | |
328 | :samp:`{inti}` if condition :samp:`{condi}` is true. Each :samp:`{int}` must have the | |
329 | same rtx format. See :ref:`rtl-classes`. Int iterators can appear in only | |
330 | those rtx fields that have 'i', 'n', 'w', or 'p' as the specifier. This | |
331 | means that each :samp:`{int}` has to be a constant defined using define_constant | |
332 | or define_c_enum. | |
333 | ||
334 | As with mode and code iterators, each pattern that uses :samp:`{name}` will be | |
335 | expanded :samp:`{n}` times, once with all uses of :samp:`{name}` replaced by | |
336 | :samp:`{int1}`, once with all uses replaced by :samp:`{int2}`, and so on. | |
337 | See :ref:`defining-mode-iterators`. | |
338 | ||
339 | It is possible to define attributes for ints as well as for codes and modes. | |
340 | Attributes are defined using: | |
341 | ||
342 | .. code-block:: | |
343 | ||
344 | (define_int_attr name [(int1 "value1") ... (intn "valuen")]) | |
345 | ||
346 | Here's an example of int iterators in action, taken from the ARM port: | |
347 | ||
348 | .. code-block:: | |
349 | ||
350 | (define_int_iterator QABSNEG [UNSPEC_VQABS UNSPEC_VQNEG]) | |
351 | ||
352 | (define_int_attr absneg [(UNSPEC_VQABS "abs") (UNSPEC_VQNEG "neg")]) | |
353 | ||
354 | (define_insn "neon_vq<absneg><mode>" | |
355 | [(set (match_operand:VDQIW 0 "s_register_operand" "=w") | |
356 | (unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w") | |
357 | (match_operand:SI 2 "immediate_operand" "i")] | |
358 | QABSNEG))] | |
359 | "TARGET_NEON" | |
360 | "vq<absneg>.<V_s_elem>\t%<V_reg>0, %<V_reg>1" | |
361 | [(set_attr "type" "neon_vqneg_vqabs")] | |
362 | ) | |
363 | ||
364 | This is equivalent to: | |
365 | ||
366 | .. code-block:: | |
367 | ||
368 | (define_insn "neon_vqabs<mode>" | |
369 | [(set (match_operand:VDQIW 0 "s_register_operand" "=w") | |
370 | (unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w") | |
371 | (match_operand:SI 2 "immediate_operand" "i")] | |
372 | UNSPEC_VQABS))] | |
373 | "TARGET_NEON" | |
374 | "vqabs.<V_s_elem>\t%<V_reg>0, %<V_reg>1" | |
375 | [(set_attr "type" "neon_vqneg_vqabs")] | |
376 | ) | |
377 | ||
378 | (define_insn "neon_vqneg<mode>" | |
379 | [(set (match_operand:VDQIW 0 "s_register_operand" "=w") | |
380 | (unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w") | |
381 | (match_operand:SI 2 "immediate_operand" "i")] | |
382 | UNSPEC_VQNEG))] | |
383 | "TARGET_NEON" | |
384 | "vqneg.<V_s_elem>\t%<V_reg>0, %<V_reg>1" | |
385 | [(set_attr "type" "neon_vqneg_vqabs")] | |
386 | ) | |
387 | ||
388 | .. index:: subst iterators in .md files, define_subst, define_subst_attr | |
389 | ||
390 | .. _subst-iterators: | |
391 | ||
392 | Subst Iterators | |
393 | ^^^^^^^^^^^^^^^ | |
394 | ||
395 | Subst iterators are special type of iterators with the following | |
396 | restrictions: they could not be declared explicitly, they always have | |
397 | only two values, and they do not have explicit dedicated name. | |
398 | Subst-iterators are triggered only when corresponding subst-attribute is | |
399 | used in RTL-pattern. | |
400 | ||
401 | Subst iterators transform templates in the following way: the templates | |
402 | are duplicated, the subst-attributes in these templates are replaced | |
403 | with the corresponding values, and a new attribute is implicitly added | |
404 | to the given ``define_insn`` / ``define_expand``. The name of the | |
405 | added attribute matches the name of ``define_subst``. Such | |
406 | attributes are declared implicitly, and it is not allowed to have a | |
407 | ``define_attr`` named as a ``define_subst``. | |
408 | ||
409 | Each subst iterator is linked to a ``define_subst``. It is declared | |
410 | implicitly by the first appearance of the corresponding | |
411 | ``define_subst_attr``, and it is not allowed to define it explicitly. | |
412 | ||
413 | Declarations of subst-attributes have the following syntax: | |
414 | ||
415 | .. index:: define_subst_attr | |
416 | ||
417 | .. code-block:: | |
418 | ||
419 | (define_subst_attr "name" | |
420 | "subst-name" | |
421 | "no-subst-value" | |
422 | "subst-applied-value") | |
423 | ||
424 | :samp:`{name}` is a string with which the given subst-attribute could be | |
425 | referred to. | |
426 | ||
427 | :samp:`{subst-name}` shows which ``define_subst`` should be applied to an | |
428 | RTL-template if the given subst-attribute is present in the | |
429 | RTL-template. | |
430 | ||
431 | :samp:`{no-subst-value}` is a value with which subst-attribute would be | |
432 | replaced in the first copy of the original RTL-template. | |
433 | ||
434 | :samp:`{subst-applied-value}` is a value with which subst-attribute would be | |
435 | replaced in the second copy of the original RTL-template. | |
436 | ||
437 | .. index:: @ in instruction pattern names | |
438 | ||
439 | .. _parameterized-names: | |
440 | ||
441 | Parameterized Names | |
442 | ^^^^^^^^^^^^^^^^^^^ | |
443 | ||
444 | Ports sometimes need to apply iterators using C++ code, in order to | |
445 | get the code or RTL pattern for a specific instruction. For example, | |
446 | suppose we have the :samp:`neon_vq<absneg><mode>` pattern given above: | |
447 | ||
448 | .. code-block:: | |
449 | ||
450 | (define_int_iterator QABSNEG [UNSPEC_VQABS UNSPEC_VQNEG]) | |
451 | ||
452 | (define_int_attr absneg [(UNSPEC_VQABS "abs") (UNSPEC_VQNEG "neg")]) | |
453 | ||
454 | (define_insn "neon_vq<absneg><mode>" | |
455 | [(set (match_operand:VDQIW 0 "s_register_operand" "=w") | |
456 | (unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w") | |
457 | (match_operand:SI 2 "immediate_operand" "i")] | |
458 | QABSNEG))] | |
459 | ... | |
460 | ) | |
461 | ||
462 | A port might need to generate this pattern for a variable | |
463 | :samp:`QABSNEG` value and a variable :samp:`VDQIW` mode. There are two | |
464 | ways of doing this. The first is to build the rtx for the pattern | |
465 | directly from C++ code; this is a valid technique and avoids any risk | |
466 | of combinatorial explosion. The second is to prefix the instruction | |
467 | name with the special character :samp:`@`, which tells GCC to generate | |
468 | the four additional functions below. In each case, :samp:`{name}` is the | |
469 | name of the instruction without the leading :samp:`@` character, | |
470 | without the :samp:`<...>` placeholders, and with any underscore | |
471 | before a :samp:`<...>` placeholder removed if keeping it would | |
472 | lead to a double or trailing underscore. | |
473 | ||
474 | :samp:`insn_code maybe_code_for_{name} ({i1}, {i2}, ...)` | |
475 | See whether replacing the first :samp:`<...>` placeholder with | |
476 | iterator value :samp:`{i1}`, the second with iterator value :samp:`{i2}`, and | |
477 | so on, gives a valid instruction. Return its code if so, otherwise | |
478 | return ``CODE_FOR_nothing``. | |
479 | ||
480 | :samp:`insn_code code_for_{name} ({i1}, {i2}, ...)` | |
481 | Same, but abort the compiler if the requested instruction does not exist. | |
482 | ||
483 | :samp:`rtx maybe_gen_{name} ({i1}, {i2}, ..., {op0}, {op1}, ...)` | |
484 | Check for a valid instruction in the same way as | |
485 | ``maybe_code_for_name``. If the instruction exists, | |
486 | generate an instance of it using the operand values given by :samp:`{op0}`, | |
487 | :samp:`{op1}`, and so on, otherwise return null. | |
488 | ||
489 | :samp:`rtx gen_{name} ({i1}, {i2}, ..., {op0}, {op1}, ...)` | |
490 | Same, but abort the compiler if the requested instruction does not exist, | |
491 | or if the instruction generator invoked the ``FAIL`` macro. | |
492 | ||
493 | For example, changing the pattern above to: | |
494 | ||
495 | .. code-block:: | |
496 | ||
497 | (define_insn "@neon_vq<absneg><mode>" | |
498 | [(set (match_operand:VDQIW 0 "s_register_operand" "=w") | |
499 | (unspec:VDQIW [(match_operand:VDQIW 1 "s_register_operand" "w") | |
500 | (match_operand:SI 2 "immediate_operand" "i")] | |
501 | QABSNEG))] | |
502 | ... | |
503 | ) | |
504 | ||
505 | would define the same patterns as before, but in addition would generate | |
506 | the four functions below: | |
507 | ||
508 | .. code-block:: c++ | |
509 | ||
510 | insn_code maybe_code_for_neon_vq (int, machine_mode); | |
511 | insn_code code_for_neon_vq (int, machine_mode); | |
512 | rtx maybe_gen_neon_vq (int, machine_mode, rtx, rtx, rtx); | |
513 | rtx gen_neon_vq (int, machine_mode, rtx, rtx, rtx); | |
514 | ||
515 | Calling :samp:`code_for_neon_vq (UNSPEC_VQABS, V8QImode)` | |
516 | would then give ``CODE_FOR_neon_vqabsv8qi``. | |
517 | ||
518 | It is possible to have multiple :samp:`@` patterns with the same | |
519 | name and same types of iterator. For example: | |
520 | ||
521 | .. code-block:: | |
522 | ||
523 | (define_insn "@some_arithmetic_op<mode>" | |
524 | [(set (match_operand:INTEGER_MODES 0 "register_operand") ...)] | |
525 | ... | |
526 | ) | |
527 | ||
528 | (define_insn "@some_arithmetic_op<mode>" | |
529 | [(set (match_operand:FLOAT_MODES 0 "register_operand") ...)] | |
530 | ... | |
531 | ) | |
532 | ||
533 | would produce a single set of functions that handles both | |
534 | ``INTEGER_MODES`` and ``FLOAT_MODES``. | |
535 | ||
536 | It is also possible for these :samp:`@` patterns to have different | |
537 | numbers of operands from each other. For example, patterns with | |
538 | a binary rtl code might take three operands (one output and two inputs) | |
539 | while patterns with a ternary rtl code might take four operands (one | |
540 | output and three inputs). This combination would produce separate | |
541 | :samp:`maybe_gen_{name}` and :samp:`gen_{name}` functions for | |
542 | each operand count, but it would still produce a single | |
3ed1b4ce | 543 | :samp:`maybe_code_for_{name}` and a single :samp:`code_for_{name}`. |