Changing Multiple RTL SSA Instructions (GNU Compiler Collection (GCC) Internals)

#### 15.21.8.2 Changing Multiple RTL SSA Instructions ¶

The process for changing multiple instructions is similar to the process for changing single instructions (see Changing One RTL SSA Instruction). The pass should again start the change attempt with:

    auto attempt = crtl->ssa->new_change_attempt ();

and keep `attempt` in scope for the duration of the change attempt. It should then construct an `rtl_ssa::insn_change` for each change that it wants to make.

After this, it should combine the changes into a sequence of `rtl_ssa::insn_change` pointers. This sequence must be in reverse postorder; the instructions will remain strictly in the order that the sequence specifies.

For example, if a pass is changing exactly two instructions, it might do:

    rtl_ssa::insn_change *changes[] = { &change1, &change2 };

where `change1`’s instruction must come before `change2`’s. Alternatively, if the pass is changing a variable number of instructions, it might build up the sequence in a `vec<rtl_ssa::insn_change *>`.

By default, `rtl_ssa::restrict_movement` assumes that all instructions other than the one passed to it will remain in their current positions and will retain their current uses and definitions. When changing multiple instructions, it is usually more effective to ignore the other instructions that are changing. The sequencing described above ensures that the changing instructions remain in the correct order with respect to each other. The way to do this is:

    if (!rtl_ssa::restrict_movement (change, ignore_changing_insns (changes)))
      return false;

Similarly, when `rtl_ssa::restrict_movement` is detecting whether a register can be clobbered, it by default assumes that all other instructions will remain in their current positions and retain their current form. It is again more effective to ignore changing instructions (which might, for example, no longer need to clobber the flags register). The way to do this is:

    if (!rtl_ssa::recog (attempt, change, ignore_changing_insns (changes)))
      return false;

When changing multiple instructions, the important question is usually not whether each individual change is worthwhile, but whether the changes as a whole are worthwhile. The way to test this is:

    if (!rtl_ssa::changes_are_worthwhile (changes))
      return false;

The process for changing single instructions makes sure that one `rtl_ssa::insn_change` in isolation is valid. But when changing multiple instructions, it is also necessary to test whether the sequence as a whole is valid. For example, it might be impossible to satisfy all of the `move_range`s at once.

Therefore, once the pass has a sequence of changes that are individually correct, it should use:

    if (!crtl->ssa->verify_insn_changes (changes))
      return false;

to check whether the sequence as a whole is valid. If all checks pass, the final step is:

    confirm_change_group ();
    crtl->ssa->change_insns (changes);

Putting all this together, the process for a two-instruction change is:

    auto attempt = crtl->ssa->new_change_attempt ();

    rtl_ssa::insn_change change1 (insn1);
    change1.new_defs = ...;
    change1.new_uses = ...;
    change1.move_range = ...;

    rtl_ssa::insn_change change2 (insn2);
    change2.new_defs = ...;
    change2.new_uses = ...;
    change2.move_range = ...;

    rtl_ssa::insn_change *changes[] = { &change1, &change2 };

    auto ignore = ignore_changing_insns (changes);
    if (!rtl_ssa::restrict_movement (change1, ignore)
        || !rtl_ssa::restrict_movement (change2, ignore))
      return false;

    insn_change_watermark watermark;
    // Use validate_change etc. to change INSN1's and INSN2's patterns.
    ...
    if (!rtl_ssa::recog (attempt, change1, ignore)
        || !rtl_ssa::recog (attempt, change2, ignore)
        || !rtl_ssa::changes_are_worthwhile (changes)
        || !crtl->ssa->verify_insn_changes (changes))
      return false;

    confirm_change_group ();
    crtl->ssa->change_insns (changes);