I have a couple questions about the AArch64 encoding.Some instructions are defined to be UNDEFINED if fields are set in a certain way (where UNDEFINED means that the instruction generates an Undefined Instruction exception). For example, EOR contains the following decode pseudocode:```if sf == '0' && N != '0' then UNDEFINED;```I just want to confirm that this means that an EOR instruction encoded with `sf == '0'` and `N != '0'` is guaranteed to generate an Undefined Instruction exception. Therefore this encoding will never be reused in the future for a different operation, since it must generate an exception.Also, the AArch64 manual states this at the end of Section C1.1 "About the A64 instruction set":> All encodings that are not fully defined are described as unallocated. An attempt to execute an unallocated instruction is UNDEFINED, unless the behavior is otherwise defined in this Manual.It seems like unallocated instructions should actually be defined as UNPREDICTABLE, since they may be allocated in a future version of AArch64 in which case they can no longer be relied upon to generate an undefined exception. For example, if unallocated instructions were defined in Armv8.0 as UNDEFINED, then if Armv8.1 allocated new instructions it would be incompatible with Armv8.0 (i.e., an Armv8.1 processor would not be Armv8.0 compliant and therefore could not run Armv8.0 binaries). Is this statement in the manual a mistake, or am I misunderstanding the guarantees that are being provided?
Zachary Y said:It seems like unallocated instructions should actually be defined as UNPREDICTABLE
... but they are not "UNPREDICTABLE" (i.e. unpredictable behaviour is not specified as predictably generating an undefined instruction exception).
Zachary Y said:For example, if unallocated instructions were defined in Armv8.0 as UNDEFINED, then if Armv8.1 allocated new instructions it would be incompatible with Armv8.0
Specifications are versioned and applied as written to the current version of the architecture. If you want to write software that is compatible with e.g. 8.1 then you have to confirm to the 8.1 architecture specification, at which point the instructions in question will be allocated and will not be UNDEFINED.
TLDR: Software written for 8.0 should not be relying on specific unallocated instructions generating an undefined exception if it wants to be forward-compatible.
I'm saying the unallocated instructions should be defined as UNPREDICTABLE, so that they cannot be relied upon as predictably generating an undefined instruction exception. Currently they appear to be defined as UNDEFINED by the manual, which seems incorrect because it is not forward-compatible (my understanding is that this would define them all to predictably generate an exception, which seems in conflict with forward-compatibility).
Your TLDR makes perfect sense, but I think it implies that the manual should say unallocated instructions are UNPREDICTABLE, not UNDEFINED (since UNDEFINED assigns them a particular behavior).
But they *do* have a specific behaviour on hardware that matches the version of the architecture specification.
If you read the spec for a specific version, it applies to hardware that implements that specific version. On that version it MUST generate an undef exception. It is entirely defined and predictable behaviour.
I don't understand where the ambiguity is. It's a hardware specification, and you need to read the version of the spec that matches the version implemented by the hardware.
Maybe I'm just really picking nits here, but if unallocated instructions are defined for Armv8.0 to do one predictable thing, and then do something different on Armv8.1, then Armv8.1 is not compatible with 8.0.
For example, I am using an Armv8.0 device, so I read the spec for Armv8.0 and it says unallocated instructions are UNDEFINED. Now I start relying on this behavior (for the sake of argument) in my program -- it is supposedly entirely defined and predictable for Armv8.0 so my program should have perfectly predictable behavior on any device that supports Armv8.0. Now someone (Arm) comes out with an Armv8.1 device, and claims that it is compatible with all Armv8.0 programs (I believe Arm does make this claim). If I was relying on an exception from an unallocated instruction that has now become allocated in 8.1, then my program will no longer do the same thing as it did on a purely Armv8.0 device. Thus it seems that if it is correct for Armv8.0 to define all unallocated instructions as UNDEFINED, then the claim of backwards compatibility is wrong.
While I get your argument, I have to agree with Peter. UNDEFINED and UNPREDICTABLE (or CONSTRAINED UNPREDICTABLE) are different things, and they're intended to tell programmer's different things.
UNDEFINED = This opcode/operation/encoding is not yet allocated, but might be allocated in the future.UNPRED = Don't this, the architecture does not guarantee the behaviour AND given hardware might not give consistent behaviour.The second part of the UNPRED definition is important. If something is UNPRED a given processor is allowed to do different things each time it hits the operation.
So I was nit picking, I'd phrase it as:It is IMPLEMENTATION DEFINED whether <feature> is implemented. If <feature> is not implemented, <X> is UNDEFINED.
Forgot to add... In A64 there is an opcode reserved to always UNDEF
Arm A-profile A64 Instruction Set Architecture
Although I suggest that if you want to raise an exception in a controlled manner, UNDEF might not be the best choice.
> UNDEFINED = This opcode/operation/encoding is not yet allocated, but might be allocated in the future.
But UNDEFINED is not defined in this manner in the Arm manual glossary. Instead it says "UNDEFINED - Indicates cases where an attempt to execute a particular encoding bit pattern generates an exception, that is taken to the current Exception level, or to the default Exception level for taking exceptions if the UNDEFINED encoding was executed at EL0." I cannot find any reference that UNDEFINED indicates that the operation might become allocated in the future (change behavior).
I think your phrasing using IMPLEMENTATION DEFINED is reasonable. I can see how using UNPREDICTABLE might go further than desired. If the manual were updated to use your phrasing for unallocated instructions I would be satisfied with that. I think there needs to be some difference between UNDEFINED (permanent definition of behavior) and unallocated.
Ultimately, I am looking for a formal assurance from the spec that things like UDF, or EOR with a certain bit pattern are guaranteed to generate an Undefined exception for all versions of the architecture. However, these instructions appear to be defined in exactly the same way as unallocated instructions -- the manual simply says that both unallocated and UDF are "UNDEFINED" but apparently one appears to have some permanence guarantee (UDF) while the other does not (unallocated). While the manual's text for UDF does say "Permanently undefined" the pseudocode just says "UNDEFINED." The text for EOR says nothing about its UNDEFINED encoding, so in that case I only have the pseudocode to rely on, which gets back to part 1 of my original question about whether the EOR UNDEFINED encoding is guaranteed to generate an exception permanently.
Thanks for reading all this and helping out, I think I have mostly gotten to the bottom of this.
Zachary Y said:While the manual's text for UDF does say "Permanently undefined" the pseudocode just says "UNDEFINED." The text for EOR says nothing about its UNDEFINED encoding, so in that case I only have the pseudocode to rely on, which gets back to part 1 of my original question about whether the EOR UNDEFINED encoding is guaranteed to generate an exception permanently.
The UDF instruction encoding being "permanently undefined" gives you the future-proof guarantee you require. The pseudocode defines the function of the hardware, so has no temporal aspect.
You have no such guarantees for the EOR encoding.