On Sat, Jan 18, 2025 at 09:36:14AM -0700, Jeff Law wrote: [...] > > > Do we detect conflicts between a hard register constraint and another > > > constraint which requires a singleton class? That's going to be an error > > > I > > > suspect, but curious if it's handled. > > > > That is a good point. Currently I suspect no. I will have a look. > Thanks. It's not the most important thing on our plate, but given the way > x86 is structured we probably need to do something sensible here. > > I also worry a bit about non-singleton classes that the target may have > added to CLASS_LIKELY_SPILLED_P, though unlike the singleton case, there's > at least a chance these will work, albeit potentially generating poor code > when an object needs spilling. I also don't think it's terribly common to > add non-singleton classes to that set.
I was first worried that the single register class construct is somewhat special. To me, it turns out that they behave very similar to my current draft. Basically during LRA in process_alt_operands() I'm installing case '{': { int regno = decode_hard_reg_constraint (p); gcc_assert (regno >= 0); cl = REGNO_REG_CLASS (regno); CLEAR_HARD_REG_SET (hard_reg_constraint); SET_HARD_REG_BIT (hard_reg_constraint, regno); cl_filter = &hard_reg_constraint; goto reg; } a singleton set via cl_filter for a pseudo which corresponds to a hard register constraint. Thus, ultimately this means that if this set intersects with another single register class for a different pseudo, we bail out. I came up with a couple of tests like: int x, y; __asm__ __volatile__ ("" : "=a" (x), "={rbx}" (y)); __asm__ __volatile__ ("" : "=a" (x), "={rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */ __asm__ __volatile__ ("" : "=a" (x) : "{rax}" (y)); __asm__ __volatile__ ("" : "=&a" (x) : "{rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */ __asm__ __volatile__ ("" :: "a" (x), "{rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */ or for register class A containing two registers: int x, y; __int128 z; __asm__ __volatile__ ("" : "=A" (z), "={rbx}" (y)); __asm__ __volatile__ ("" : "=A" (z), "={rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */ __asm__ __volatile__ ("" : "=A" (z), "={rdx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */ __asm__ __volatile__ ("" : "=A" (z) : "{rax}" (y)); __asm__ __volatile__ ("" : "=A" (z) : "{rdx}" (y)); __asm__ __volatile__ ("" : "=&A" (z) : "{rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */ __asm__ __volatile__ ("" : "=&A" (z) : "{rdx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */ __asm__ __volatile__ ("" :: "A" (z), "{rax}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */ __asm__ __volatile__ ("" :: "A" (z), "{rdx}" (y)); /* { dg-error "'asm' operand has impossible constraints or there are not enough registers" } */ (I have tested those only on x86_64 so far but I expect them to work on 32-bit, too, module int128) I will include those, and of course, similar ones for constraints b,c,d,S,D in a future patch revision. If there is any other target with non-ordinary register classes/constraints/whatnot just let me know and I will have a look. > I'm sure someone will try to implement ABI semantics for asms with calls at > some point on top of this infrastructure. It seems to be a persistent thing > developers want to do with asms. It always ends in a bit of fireworks > either running out of registers in the asm itself or generating crappy code > because of all the hard register usages. Not something you need to fix, > more a rant about what's likely to happen in the future ;-) Heh, yes maybe ... I hope not ;-) Ultimately I hope to get rid of those hard to find bugs which are introduced by implicit function calls by demoting register asm into hard register constraints. Cheers, Stefan