Here's what I do for my massively nested switch statements in my Intel x86-64 disassembler (which has five or six nested levels of switch statements)
1. Each nested switch goes in a separate function. A case statement in the first switch calls a function with another switch in it (if necessary - not all instructions nest all the way down).
2. The Intel instructions have this really tedious-to-enter prefix pattern for the SSE/AVX instructions:
The instruction's 66, F3, and F2 prefix(es) can be combined to change the instruction mnemonic entirely (in addition to the typical three opcode bytes).
Due to how the Intel manual's opcode map is laid out (the 66/F3/F2 prefixes are arranged in rows), in the 0F38xx and 0F3Axx switch tables, I do this (this is technically C# but the syntax is nearly identical):
Instead of switch once on the opcodeByte3 and then switch again on the SimdType, making one big 256-entry switch followed by 256x 4-entry switch functions (which would have no longer lined up nicely with the Intel manual), I rearrange the bits. I still switch twice, but the adjusted arrangement is more readable.
opcodeByte3 = reader.ReadByte();
// Encode the switch to make cases line up more exactly with the manual.
int row = opcodeByte3 & 0xF0;
switch (simdType)
{
case SimdType.None: break;
case SimdType.S_66: row += 1; break;
case SimdType.S_F3: row += 2; break;
case SimdType.S_F2: row += 3; break;
case SimdType.F266: row += 4; break;
}
// This switch ignores the low 3 bits in order to map directly to rows.
// Case statements are be the leftmost column of each page.
switch (row)
{
case 0x00: return FindOpcode0F38_Row0_None();
case 0x01: return FindOpcode0F38_Row0_66();
case 0x10: return FindOpcode0F38_Row1_None();
case 0x11: return FindOpcode0F38_Row1_66();
case 0x21: return FindOpcode0F38_Row2_66();
case 0x31: return FindOpcode0F38_Row3_66();
case 0x41: return FindOpcode0F38_Row4_66();
case 0x51: return FindOpcode0F38_Row5_66();
case 0x71: return FindOpcode0F38_Row7_66();
case 0x81: return FindOpcode0F38_Row8_66();
case 0x91: return FindOpcode0F38_Row9_66();
case 0xA1: return FindOpcode0F38_RowA_66();
case 0xB1: return FindOpcode0F38_RowB_66();
case 0xD1: return FindOpcode0F38_RowD_66();
case 0xF0: return FindOpcode0F38_RowF_None();
case 0xF1: return FindOpcode0F38_RowF_66();
case 0xF2: return FindOpcode0F38_RowF_F3();
case 0xF3: return FindOpcode0F38_RowF_F2();
case 0xF4: return FindOpcode0F38_RowF_66F2();
}
Each individual row function looks like this:
private bool FindOpcode0F38_Row0_None()
{
switch (opcodeByte3)
{
case 0x00: return Valid(Opcode.PSHUFB, Pq, Qq);
case 0x01: return Valid(Opcode.PHADDW, Pq, Qq);
case 0x02: return Valid(Opcode.PHADDD, Pq, Qq);
case 0x03: return Valid(Opcode.PHADDSW, Pq, Qq);
case 0x04: return Valid(Opcode.PMADDUBSW, Pq, Qq);
case 0x05: return Valid(Opcode.PHSUBW, Pq, Qq);
case 0x06: return Valid(Opcode.PHSUBD, Pq, Qq);
case 0x07: return Valid(Opcode.PHSUBSW, Pq, Qq);
case 0x08: return ValidSimd(Opcode.PSIGNB, Pq, Qq);
case 0x09: return ValidSimd(Opcode.PSIGNW, Pq, Qq);
case 0x0A: return ValidSimd(Opcode.PSIGND, Pq, Qq);
case 0x0B: return ValidSimd(Opcode.PMULHRSW, Pq, Qq);
}
return false;
}
private bool FindOpcode0F38_Row0_66()
{
switch (opcodeByte3)
{
case 0x00: return ValidSV13(Opcode.VPSHUFB, Vx, Hx, Wx);
case 0x01: return ValidSV13(Opcode.VPHADDW, Vx, Hx, Wx);
case 0x02: return ValidSV13(Opcode.VPHADDD, Vx, Hx, Wx);
case 0x03: return ValidSV13(Opcode.VPHADDSW, Vx, Hx, Wx);
case 0x04: return ValidSV13(Opcode.VPMADDUBSW, Vx, Hx, Wx);
case 0x05: return ValidSV13(Opcode.VPHSUBW, Vx, Hx, Wx);
case 0x06: return ValidSV13(Opcode.VPHSUBD, Vx, Hx, Wx);
case 0x07: return ValidSV13(Opcode.VPHSUBSW, Vx, Hx, Wx);
case 0x08: return ValidSV13(Opcode.VPSIGNB, Vx, Hx, Wx);
case 0x09: return ValidSV13(Opcode.VPSIGNW, Vx, Hx, Wx);
case 0x0A: return ValidSV13(Opcode.VPSIGND, Vx, Hx, Wx);
case 0x0B: return ValidSV13(Opcode.VPMULHRSW, Vx, Hx, Wx);
case 0x0C: return ValidVexOnly(Opcode.VPERMILPS, Vx, Hx, Wx);
case 0x0D: return ValidVexOnly(Opcode.VPERMILPD, Vx, Hx, Wx);
case 0x0E: return ValidVexOnly(Opcode.VTESTPS, Vx, Wx);
case 0x0F: return ValidVexOnly(Opcode.VTESTPD, Vx, Wx);
}
return false;
}