Here are some things which I found important but unclear on my
first couple of readings of the
Gcc Internals Manual:
The Standard Pattern Names For Generation list is the key to understanding Gcc's use of the machine description. This is the core machine-independent vocabulary which gcc uses to describe all code. The machine description is ultimately all about translating this vocabulary into the actual assembly code vocabulary of your machine.
The fundamental backend basic block intermediate representation with which your machine description interacts is a doubly linked list of insns, each containing one of the trees specified by your .md-file rmachine description rules.
Gcc does not tile these trees as you might expect -- it does "full-tree matching". Each rule pattern must match the entire tree for the insn in question.
Initial generation of this insn-list representation is done by the expand pass, but .md-file rules may be called earlier, for example the ivopts pass calls them to obtain instruction costs.
When the insn-list representation is modified by optimization passes, the new nodes are created by re-invoking your machine-description rules. This is critically important because it gives your machine description a chance to respond appropriately to changes in constant values, say, by selecting different insns.
The Gcc Internals Manual left me with the impression that define_expand is mainly about producing a sequence of insns. In practice, it is typically used to choose between alternate insn representations for the standard op in question, often synthesizing them entirely in the "preparation" C code and using DONE to have the template ignored.