On 8/25/2026 5:29 AM, Paolo Bonzini wrote:
The REX2 prefix has two main complications: it does not apply
to vector registers, and it disables or mutates some opcodes
(thus needing separate decoding functions instead of decode_root
and decode_0F).  Otherwise, all it does is extend s->rex_r,
s->rex_w and s->rex_b to two bits.

Since REX2 provides the ability to access r16...r31, extend
cpu_regs[] to CPU_NB_EREGS elements.

The code looks like it matches the definition quite well to me:

  Reviewed-by: Chang S. Bae <[email protected]>

+/* MASK must have two bits set.  Bring the lowest just below the highest;
+ * for example if MASK == 0x11, bit 1 of value is moved to bit 3.  Clear
+ * every other bit in VALUE.
+ *
+ * Generally mask will be a constant, so that all of the first three
+ * lines disappear.  Likewise, if the bits in mask are already adjacent
+ * this becomes just "return value & mask".
+ */
+static inline uint8_t collapse_two_bits(uint8_t value, uint8_t mask)
+{
+    uint8_t high = mask & (mask - 1);
+    uint8_t low = mask & ~high;
+    uint8_t tweak = (high >> 1) - low;
+
+    value &= mask;
+    return (value + tweak) & (mask + tweak);
+}
This logic looks quite interesting. The following changes look pretty much usage sites -- for the possible combinations for the input. Then just quickly ran the calculation. The math seems to work as expected:

  value,  mask,   return

  0x0     0x11    0x0
  0x1     0x11    0x8
  0x10    0x11    0x10
  0x11    0x11    0x18

  0x0     0x22    0x0
  0x2     0x22    0x10
  0x20    0x22    0x20
  0x22    0x22    0x30

  0x0     0x44    0x0
  0x4     0x44    0x20
  0x40    0x44    0x40
  0x44    0x44    0x60

Alternatively, while with more lines,

enum rex {
        REX_B,
        REX_X,
        REX_R
};

static inline uint8_t get_reg_bits(uint8_t value, enum rex rex)
{
        bool bit4 = false, bit3 = false;
        uint8_t bits = 0;

        switch (rex) {
        case REX_B:
                bit4 = 0x10 & value;
                bit3 = 0x01 & value;
                break;
        case REX_X:
                bit4 = 0x20 & value;
                bit3 = 0x02 & value;
                break;
        case REX_R:
                bit4 = 0x40 & value;
                bit3 = 0x04 & value;
                break;
        default:
        }

        bits += bit4 ? 0x10 : 0;
        bits += bit3 ? 0x08 : 0;
        return bits;
}

...later
        s->rex_b = get_reg_bits(rex2, REX_B);
        s->rex_x = get_reg_bits(rex2, REX_X);
        s->rex_r = get_reg_bits(rex2, REX_R);

Reply via email to