https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114741
--- Comment #4 from Andrew Pinski <pinskia at gcc dot gnu.org> --- (In reply to Wilco from comment #2) > It looks like the underlying bug is '^' being incorrectly treated like '?' > in record_reg_classes (which is never used during reload). Fixing that > results in the expected code being generated in all cases. It looks this > issue was introduced in the original commit > d1457701461d5a49ca6b5d8a6d1c83a37a6dc771 static const struct cpu_regmove_cost generic_armv9_a_regmove_cost = { 1, /* GP2GP */ /* Spilling to int<->fp instead of memory is recommended so set realistic costs compared to memmov_cost. */ 3, /* GP2FP */ 2, /* FP2GP */ 2 /* FP2FP */ }; Note these costs are broken. TARGET_REGISTER_MOVE_COST has this to say about the special value 2: ``` If reload sees an insn consisting of a single set between two hard registers, and if TARGET_REGISTER_MOVE_COST applied to their classes returns a value of 2, reload does not check to ensure that the constraints of the insn are met. Setting a cost of other than 2 will allow reload to verify that the constraints are met. You should do this if the ‘movm’ pattern’s constraints do not allow such copying. ``` The way I implemented this for thunderx was have GP2GP being cost of 2 and then be relative from there. That gave better code generation in general and even less spilling. I know I wrote about this before too.