Yes, I'm serious. I think the overlap is an aesthetic problem rather than a practical one, given that:

* The profile used by "Big SoCs" already explicitly depends on F + D + C, implying ZcdZcf, so the newer Zce won't be implemented.

* The compressed float load/store opcodes repurposed for Zce are often unimplemented on embedded processors.

* The ELF file has an attribute section telling you the exact ISA string. If you're debugging an embedded system you probably depend on the ELF file anyway for DWARF info as you likely don't have frame pointers.

If you disagree then that's ok, I'm happy to be disagreed with, but please explain.

In x86 land, there are, as a practical matter, four ISAs: real/v8086 mode, 16-bit protected mode, 32-bit protected mode, and 64-bit “long” mode. Machine code targeting one of these will be executed correctly by the CPU as long as the CPU is in the right mode. (Really it’s messier — there are the CS.D, CS.L, and SS.B bits plus the control bits for v8086, protected and long mode, but this barely matters.)

Sure, this is messy. But, critically, on x86, these are all modes, and any CPU that supports them makes them detectable and supports them in the same way. If you run long mode code outside long mode, some opcodes will be interpreted as the wrong instruction. But you will not find multiple different CPUs that decode valid instructions differently. If I run your weird old x86 code, either it will run correctly or it will fault.

Oh, and all these modes are older than RISC-V. To the extent that there are lessons to be learned, RISC-V should have learned them.

The fact that you can apparently find two RISC-V CPUs that decode some ordinary user mode instructions based on published standards as entirely different operations is bizarre, to say the least. The fact that the relevant CPU features can’t even be enumerated in user mode just makes it worse.

(There are edge cases in x86. Some invalid opcodes have different lengths on different vendors’ CPUs. This is not a problem in practice because, one way or another, they fault. There was also a little glitch in the 64-bit design where some really really old x87 FPU code that uses exceptions cannot be corrected handled by a kernel on a modern CPU.)

> But you will not find multiple different CPUs that decode valid instructions differently. If I run your weird old x86 code, either it will run correctly or it will fault.

Oh, that's not completely true. Intel 64 and AMD64 are not identical and they certainly have encodings that behave differently. As an example: f3 41 90 is pause on Intel, but xchg r8d, eax on AMD (granted, this is not a canonical instruction encoding). 66 e9 xx xx yy yy is a unconditional jump to a 32-bit relative offset on Intel, but on AMD, the offset is 16-bit only (yy yy are the start of the next instruction). x86-64 is typically used to refer to the very large common subset, but this doesn't mean the implementations behave identically.

There are also some weird corner cases where CPUs aren't 100% backwards compatible, just backwards compatible enough for the software that matters.

For those less familiar with x86, the example instruction encodings that are interpreted differently on Intel and AMD are not base encodings, but instruction encodings modified with prefixes.

The x86 ISA includes a great number of bytes that are used as instruction prefixes, many of which are obsolete. The problem is that the effect of prefixes upon instructions has never been completely defined in any Intel or AMD documentation. The prefix effects have been documented for some instructions, but they were left unspecified for most other instructions.

This has lead to divergent implementations in the unspecified cases. Well-behaved compilers should not generate such undocumented combinations of instruction prefixes with base encodings.

> The problem is that the effect of prefixes upon instructions has never been completely defined in any Intel or AMD documentation.

In case of the jump example, the effects are documented by Intel and AMD and they still differ. Point of the GP was that all CPUs don't decode valid instructions differently, which is not fully accurate as shown by the examples; and some of these differences are also explicitly documented.

It's also not accurate that most prefixes are obsolete when most see regular use today (66 size override for 16-bit operations, f2/f3 for string operations, 66/f2/f3 mandatory prefix for many (e.g. SSE) instructions, 64/65 fs/gs override for thread-local storage access and per-thread kernel storage, f0 lock for atomic operations, 3e (again) for branch-taken hint, 4x REX prefix for r8-r15 and 64-bit operand size; one can argue that the 67 address-size override is useless, and only the 26, 2e, and 36 are ignored; I don't count VEX/EVEX/REX2 as prefixes but more as opcode escapes).

Fair point.

66 E9 is not a practical compatibility problem, though: it’s not a useful encoding of a useful instruction on any CPU :)

> The fact that the relevant CPU features can’t even be enumerated in user mode just makes it worse.

User-mode feature detection is usually used to select paths for acceleration instructions, like SIMD or crypto. The overlapping RISC-V instructions don't fit in that category: they're compressed versions of basic functions, mostly used in epilogs/prologs, which would be unconditionally compiled in.

There are no overlapping encodings in the 32-bit encoding space and I'm really hoping it stays that way.

> To the extent that there are lessons to be learned, RISC-V should have learned them.

Yeah, I think I agree with this. Also I wish I had been there when Andrew Waterman was writing his master's thesis so I could ask him not to include Whetstone in his size benchmarks, so that we might have left that encoding space free and avoided this conversation :-)

At least with user-mode feature detection there could be an assertion that the correct feature set is present.

There is a lot to unpack, hence my reaction. Instead of a straight compressed instruction format supported (or not supported) everywhere, we get an alphabet soup of options. C -> "ZcfZcdZca" just by itself is insanity. But the actual technical change is a problem too. Now I can't make vendor-independent RISC-V code, since apparently they all support different compressed instruction sets.

I represented my company as a founding member of the RISC-V foundation. I now shake my head at what it has become and hope I never have to write code for a RISC-V system again. Every time I check in it seems like some new insanity has manifest itself.

> C -> "ZcfZcdZca" just by itself is insanity

Separating the float load/stores from the rest of the compressed ISA is insanity? Why?

> Now I can't make vendor-independent RISC-V code

I think this is what RVA23 is for. Any system running shrinkwrapped binaries is going to have vanilla RVC.

I agree there is some insane stuff going on in RISC-V. Like when the double-trap spec was in public review I popped my head in to say "hi, this seems to break all existing code that uses nested interrupts because the condition is overly broad" and the spec maintainer said words to the effect of "yes, it's supposed to do that."

This is not that weird, though? Float load/store should never really have been included in the C extension, but we can't revise the C extension. So, define an extension for "C: the good parts", aka Zca, and separate extensions for float load/store (two of them because F and D are separate). Ideally we wouldn't have made the mistake in the first place, but what would have been a better way to redact it?