I'm about to post a series of patches that reworks the handling of standard constraints. As part of that I needed to make single_reg_class handle "extra" constraints in a similar way to the standard ones. It's not a particularly worthwhile change in itself -- not enough to justify this long essay -- but I split it out because it's the only part of the series that changes codegen.
The function looks like this: case 'i': if (CONSTANT_P (op) || (equiv_const != NULL_RTX && CONSTANT_P (equiv_const))) return NO_REGS; break; case 'n': if (CONST_SCALAR_INT_P (op) || (equiv_const != NULL_RTX && CONST_SCALAR_INT_P (equiv_const))) return NO_REGS; break; case 's': if ((CONSTANT_P (op) && !CONST_SCALAR_INT_P (op)) || (equiv_const != NULL_RTX && CONSTANT_P (equiv_const) && !CONST_SCALAR_INT_P (equiv_const))) return NO_REGS; break; case 'I': case 'J': case 'K': case 'L': case 'M': case 'N': case 'O': case 'P': if ((CONST_INT_P (op) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (op), c, constraints)) || (equiv_const != NULL_RTX && CONST_INT_P (equiv_const) && CONST_OK_FOR_CONSTRAINT_P (INTVAL (equiv_const), c, constraints))) return NO_REGS; break; case 'E': case 'F': if (CONST_DOUBLE_AS_FLOAT_P (op) || (GET_CODE (op) == CONST_VECTOR && GET_MODE_CLASS (GET_MODE (op)) == MODE_VECTOR_FLOAT) || (equiv_const != NULL_RTX && (CONST_DOUBLE_AS_FLOAT_P (equiv_const) || (GET_CODE (equiv_const) == CONST_VECTOR && (GET_MODE_CLASS (GET_MODE (equiv_const)) == MODE_VECTOR_FLOAT))))) return NO_REGS; break; case 'G': case 'H': if ((CONST_DOUBLE_AS_FLOAT_P (op) && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (op, c, constraints)) || (equiv_const != NULL_RTX && CONST_DOUBLE_AS_FLOAT_P (equiv_const) && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (equiv_const, c, constraints))) return NO_REGS; /* ??? what about memory */ case 'r': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h': case 'j': case 'k': case 'l': case 'q': case 't': case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': case 'A': case 'B': case 'C': case 'D': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'W': case 'Y': case 'Z': next_cl = (c == 'r' ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, constraints)); if (cl == NO_REGS ? ira_class_singleton[next_cl][GET_MODE (op)] < 0 : (ira_class_singleton[cl][GET_MODE (op)] != ira_class_singleton[next_cl][GET_MODE (op)])) return NO_REGS; cl = next_cl; break; [...] default: return NO_REGS; So for known constant contraints we check whether OP or its equivalent constant satisfies the constraint and return NO_REGS if so. I'd like to extend this behaviour to the extra constraints, since some targets match constants (often symbolic or unspec-based constants) there too. The code that checks next_cl effectively assumes that the constraint is always a register constraint. If it's something else, next_cl will be NO_REGS, which isn't a singleton class, so we'll return NO_REGS regardless of what type of constraint we're matching or what OP is. (In principle this includes register constraints that are disabled on the current subtarget, since they'll have a next_cl of NO_REGS too.) In order to handle extra constant constraints as described above, we'd need to ignore cases where next_cl itself is NO_REGS. This brings me on to memory and address constraints... The comment says: /* ??? what about memory */ At the moment we return NO_REGS for target-independent memory constraints like "m", "o" and "g", because of the default case. The handling of next_cl means that we effectively do the same for extra memory constraints, since next_cl is always NO_REGS for them. That seems reasonable to me and I'm not trying to change it here. The patch just makes the current choice explicit by checking for extra memory constraints. Likewise we return NO_REGS for 'p' and (indirectly) for extra address constraints. This too makes sense, since I don't think we support a singleton BASE_REG_CLASS. Again the patch makes that explicit. So all in all, the patch only really affects two cases: extra constant constraints and the (probably rare) situation that there is a singleton register constraint alongside disabled/NO_REGS register constraints. The former does occur on Alpha and MIPS. E.g.: (define_insn "*call_osf_1" [(call (mem:DI (match_operand:DI 0 "call_operand" "c,R,s")) (match_operand 1)) (use (reg:DI 29)) (clobber (reg:DI 26))] "! TARGET_EXPLICIT_RELOCS && TARGET_ABI_OSF" "@ jsr $26,($27),0\;ldgp $29,0($26) bsr $26,$%0..ng jsr $26,%0\;ldgp $29,0($26)" [(set_attr "type" "jsr") (set_attr "length" "12,*,16")]) Here "c" is a singleton register class (the ABI-defined indirect call register). "s" is the standard constraint for symbolic addresses and "R" is an extra constant constraint. If the call address is a register, single_reg_class currently returns NO_REGS because of the way that "R" is handled via next_cl==NO_REGS. After the patch it returns the singleton register class for "c" instead. I think this is the right behaviour, since indirect calls really do require a single register; the other constraints are for direct calls instead. It looks like there's a missing break after the 'G' and 'H' handling. Tested on x86_64-linux-gnu. I also did an assembly comparison for a range of targets and Alpha and MIPS seemed to be the only ones affected. OK to install? Sorry for the long write-up... Thanks, Richard gcc/ * ira-lives.c (single_reg_class): Add missing break. Return NO_REGS for extra address and memory constraints, not just 'p' and TARGET_MEM_CONSTRAINT. Likewise if the operand is a constant or equivalent to a constant and if it matches an extra constraint. Ignore other non-register operands. Index: gcc/ira-lives.c =================================================================== --- gcc/ira-lives.c 2014-06-04 22:15:23.527995920 +0100 +++ gcc/ira-lives.c 2014-06-04 22:15:50.765243138 +0100 @@ -839,7 +839,8 @@ single_reg_class (const char *constraint && CONST_DOUBLE_OK_FOR_CONSTRAINT_P (equiv_const, c, constraints))) return NO_REGS; - /* ??? what about memory */ + break; + case 'r': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h': case 'j': case 'k': case 'l': @@ -848,9 +849,22 @@ single_reg_class (const char *constraint case 'A': case 'B': case 'C': case 'D': case 'Q': case 'R': case 'S': case 'T': case 'U': case 'W': case 'Y': case 'Z': +#ifdef EXTRA_CONSTRAINT_STR + /* ??? Is rejecting memory the best thing to do? */ + if (EXTRA_MEMORY_CONSTRAINT (c, constraints) + || EXTRA_ADDRESS_CONSTRAINT (c, constraints)) + return NO_REGS; + if (EXTRA_CONSTRAINT_STR (op, c, constraints) + || (equiv_const != NULL_RTX + && CONSTANT_P (equiv_const) + && EXTRA_CONSTRAINT_STR (equiv_const, c, constraints))) + return NO_REGS; +#endif next_cl = (c == 'r' ? GENERAL_REGS : REG_CLASS_FROM_CONSTRAINT (c, constraints)); + if (next_cl == NO_REGS) + break; if (cl == NO_REGS ? ira_class_singleton[next_cl][GET_MODE (op)] < 0 : (ira_class_singleton[cl][GET_MODE (op)]