I am programming a virtual machine and I've made a union of restricted pointers to iterate the script's instruction stream:
union Pointer {
uint8_t *restrict UInt8Ptr;
uint16_t *restrict UInt16Ptr;
uint32_t *restrict UInt32Ptr;
uint64_t *restrict UInt64Ptr;
int8_t *restrict Int8Ptr;
int16_t *restrict Int16Ptr;
int32_t *restrict Int32Ptr;
int64_t *restrict Int64Ptr;
float *restrict FloatPtr;
double *restrict DoublePtr;
const char *restrict CStrPtr;
void *restrict Ptr;
};
For the CALL opcode, I have the instruction pointer's value saved (indirectly) which, if I understand the usage of the "restrict" keyword, would cause undefined behavior.
(--regs[regStk].SelfPtr)->Ptr = ip.Ptr; /* push rip */
*--regs[regStk].SelfPtr = regs[regBase]; /* push rbp */
regs[regBase] = regs[regStk]; /* mov rbp, rsp */
I should also say that in the RET opcode, the instruction pointer's value is restored.
regs[regStk] = regs[regBase]; /* mov rsp, rbp */
regs[regBase] = *regs[regStk].SelfPtr++; /* pop rbp */
ip.Ptr = (*regs[regStk].SelfPtr++).Ptr; /* pop rip */
I've done many many tests and even used different compilers (GCC and clang v3.5 and clang v6.0) and this didn't seem to produce undefined behavior, why is that?
EDIT UPDATE:
The variables are both declared one a local block scope:
int32_t VM_Exec(struct VM *const restrict vm)
{
if( !vm or !vm->CurrScript.Ptr ) {
return ErrInstrBounds;
}
union Value *const restrict regs = vm->Regs; // <--
union Pointer pc = (union Pointer){.UInt8Ptr = regs[regInstr].UCharPtr}; // <--