### 16.21 Constant Definitions

Using literal constants inside instruction patterns reduces legibility and can be a maintenance problem.

To overcome this problem, you may use the `define_constants` expression. It contains a vector of name-value pairs. From that point on, wherever any of the names appears in the MD file, it is as if the corresponding value had been written instead. You may use `define_constants` multiple times; each appearance adds more constants to the table. It is an error to redefine a constant with a different value.

To come back to the a29k load multiple example, instead of

         (define_insn ""
           [(match_parallel 0 "load_multiple_operation"
              [(set (match_operand:SI 1 "gpc_reg_operand" "=r")
                    (match_operand:SI 2 "memory_operand" "m"))
               (use (reg:SI 179))
               (clobber (reg:SI 179))])]
           ""
           "loadm 0,0,%1,%2")

You could write:

         (define_constants [
             (R_BP 177)
             (R_FC 178)
             (R_CR 179)
             (R_Q  180)
         ])

         (define_insn ""
           [(match_parallel 0 "load_multiple_operation"
              [(set (match_operand:SI 1 "gpc_reg_operand" "=r")
                    (match_operand:SI 2 "memory_operand" "m"))
               (use (reg:SI R_CR))
               (clobber (reg:SI R_CR))])]
           ""
           "loadm 0,0,%1,%2")

The constants that are defined with a define_constant are also output in the insn-codes.h header file as #defines.

You can also use the machine description file to define enumerations. Like the constants defined by `define_constant`, these enumerations are visible to both the machine description file and the main C code.

The syntax is as follows:

         (define_c_enum "name" [
           value0
           value1
           ...
           valuen
         ])

This definition causes the equivalent of the following C code to appear in `insn-constants.h`:

         enum name {
           value0 = 0,
           value1 = 1,
           ...
           valuen = n
         };
         #define NUM_cname_VALUES (n + 1)

where cname is the capitalized form of name. It also makes each valuei available in the machine description file, just as if it had been declared with:

         (define_constants [(valuei i)])

Each valuei is usually an upper-case identifier and usually begins with cname.

You can split the enumeration definition into as many statements as you like. The above example is directly equivalent to:

         (define_c_enum "name" [value0])
         (define_c_enum "name" [value1])
         ...
         (define_c_enum "name" [valuen])

Splitting the enumeration helps to improve the modularity of each individual `.md` file. For example, if a port defines its synchronization instructions in a separate `sync.md` file, it is convenient to define all synchronization-specific enumeration values in `sync.md` rather than in the main `.md` file.

Some enumeration names have special significance to GCC:

`unspecv`
  If an enumeration called `unspecv` is defined, GCC will use it when printing out `unspec_volatile` expressions. For example:

                (define_c_enum "unspecv" [
                  UNSPECV_BLOCKAGE
                ])

  causes GCC to print ‘`(unspec_volatile ... 0)`’ as:

                (unspec_volatile ... UNSPECV_BLOCKAGE)

`unspec`
  If an enumeration called `unspec` is defined, GCC will use it when printing out `unspec` expressions. GCC will also use it when printing out `unspec_volatile` expressions unless an `unspecv` enumeration is also defined. You can therefore decide whether to keep separate enumerations for volatile and non-volatile expressions or whether to use the same enumeration for both.

Another way of defining an enumeration is to use `define_enum`:

         (define_enum "name" [
           value0
           value1
           ...
           valuen
         ])

This directive implies:

         (define_c_enum "name" [
           cname_cvalue0
           cname_cvalue1
           ...
           cname_cvaluen
         ])

where cvaluei is the capitalized form of valuei. However, unlike `define_c_enum`, the enumerations defined by `define_enum` can be used in attribute specifications (see define_enum_attr).