diff --git a/risu_reginfo_aarch64.h b/risu_reginfo_aarch64.h
index efbca56..536c12b 100644
--- a/risu_reginfo_aarch64.h
+++ b/risu_reginfo_aarch64.h
@@ -13,27 +13,17 @@
 #ifndef RISU_REGINFO_AARCH64_H
 #define RISU_REGINFO_AARCH64_H
 
-#include <signal.h> /* for SVE_MAGIC */
-
-struct simd_reginfo {
-    __uint128_t vregs[32];
-    char end[0];
-};
-
-struct sve_reginfo {
-    /* SVE */
-    uint16_t    vl; /* current VL */
-    __uint128_t zregs[SVE_NUM_ZREGS][SVE_VQ_MAX];
-    uint16_t    pregs[SVE_NUM_PREGS][SVE_VQ_MAX];
-    uint16_t    ffr[SVE_VQ_MAX];
-    char end[0];
-};
+#include <signal.h>
 
 /* The kernel headers set this based on future arch extensions.
    The current arch maximum is 16.  Save space below.  */
 #undef SVE_VQ_MAX
 #define SVE_VQ_MAX 16
 
+#define ROUND_UP(SIZE, POW2)    (((SIZE) + (POW2) - 1) & -(POW2))
+#define RISU_SVE_REGS_SIZE(VQ)  ROUND_UP(SVE_SIG_REGS_SIZE(VQ), 16)
+#define RISU_SIMD_REGS_SIZE     (32 * 16)
+
 struct reginfo {
     uint64_t fault_address;
     uint64_t regs[31];
@@ -45,11 +35,28 @@ struct reginfo {
     /* FP/SIMD */
     uint32_t fpsr;
     uint32_t fpcr;
+    uint16_t sve_vl;
+    uint16_t reserved;
 
-    union {
-        struct simd_reginfo simd;
-        struct sve_reginfo sve;
-    };
+    char extra[RISU_SVE_REGS_SIZE(SVE_VQ_MAX)]
+        __attribute__((aligned(16)));
 };
 
+static inline uint64_t *reginfo_vreg(struct reginfo *ri, int i)
+{
+    return (uint64_t *)&ri->extra[i * 16];
+}
+
+static inline uint64_t *reginfo_zreg(struct reginfo *ri, int vq, int i)
+{
+    return (uint64_t *)&ri->extra[SVE_SIG_ZREG_OFFSET(vq, i) -
+                                  SVE_SIG_REGS_OFFSET];
+}
+
+static inline uint16_t *reginfo_preg(struct reginfo *ri, int vq, int i)
+{
+    return (uint16_t *)&ri->extra[SVE_SIG_PREG_OFFSET(vq, i) -
+                                  SVE_SIG_REGS_OFFSET];
+}
+
 #endif /* RISU_REGINFO_AARCH64_H */
diff --git a/risu_reginfo_aarch64.c b/risu_reginfo_aarch64.c
index 16a57ba..81a77ba 100644
--- a/risu_reginfo_aarch64.c
+++ b/risu_reginfo_aarch64.c
@@ -61,9 +61,13 @@ void process_arch_opt(int opt, const char *arg)
 
 int reginfo_size(struct reginfo *ri)
 {
-    int size = offsetof(struct reginfo, simd.end);
-    if (test_sve) {
-        size = offsetof(struct reginfo, sve.end);
+    int size = offsetof(struct reginfo, extra);
+
+    if (ri->sve_vl) {
+        int vq = sve_vq_from_vl(ri->sve_vl);
+        size += RISU_SVE_REGS_SIZE(vq);
+    } else {
+        size += RISU_SIMD_REGS_SIZE;
     }
     return size;
 }
@@ -128,6 +132,7 @@ void reginfo_init(struct reginfo *ri, ucontext_t *uc)
             fprintf(stderr, "risu_reginfo_aarch64: failed to get SVE state\n");
             return;
         }
+
         if (sve->vl != sve_vl_from_vq(vq)) {
             fprintf(stderr, "risu_reginfo_aarch64: "
                     "unexpected SVE state: %d != %d\n",
@@ -135,42 +140,22 @@ void reginfo_init(struct reginfo *ri, ucontext_t *uc)
             return;
         }
 
-        ri->sve.vl = sve->vl;
-
-        if (sve->head.size < SVE_SIG_CONTEXT_SIZE(vq)) {
-            if (sve->head.size == sizeof(*sve)) {
-                /* SVE state is empty -- not an error.  */
-            } else {
-                fprintf(stderr, "risu_reginfo_aarch64: "
-                        "failed to get complete SVE state\n");
-            }
+        if (sve->head.size <= SVE_SIG_CONTEXT_SIZE(0)) {
+            /* Only AdvSIMD state is present. */
+        } else if (sve->head.size < SVE_SIG_CONTEXT_SIZE(vq)) {
+            fprintf(stderr, "risu_reginfo_aarch64: "
+                    "failed to get complete SVE state\n");
+            return;
+        } else {
+            ri->sve_vl = sve->vl;
+            memcpy(reginfo_zreg(ri, vq, 0),
+                   (char *)sve + SVE_SIG_REGS_OFFSET,
+                   SVE_SIG_REGS_SIZE(vq));
             return;
         }
-
-        /* Copy ZREG's one at a time */
-        for (i = 0; i < SVE_NUM_ZREGS; i++) {
-            memcpy(&ri->sve.zregs[i],
-                   (void *)sve + SVE_SIG_ZREG_OFFSET(vq, i),
-                   SVE_SIG_ZREG_SIZE(vq));
-        }
-
-        /* Copy PREG's one at a time */
-        for (i = 0; i < SVE_NUM_PREGS; i++) {
-            memcpy(&ri->sve.pregs[i],
-                   (void *)sve + SVE_SIG_PREG_OFFSET(vq, i),
-                   SVE_SIG_PREG_SIZE(vq));
-        }
-
-        /* Finally the FFR */
-        memcpy(&ri->sve.ffr, (void *)sve + SVE_SIG_FFR_OFFSET(vq),
-               SVE_SIG_FFR_SIZE(vq));
-
-        return;
     }
 
-    for (i = 0; i < 32; i++) {
-        ri->simd.vregs[i] = fp->vregs[i];
-    }
+    memcpy(reginfo_vreg(ri, 0), fp->vregs, RISU_SIMD_REGS_SIZE);
 }
 
 /* reginfo_is_eq: compare the reginfo structs, returns nonzero if equal */
@@ -206,18 +191,20 @@ static void sve_dump_preg_diff(FILE *f, int vq, const uint16_t *p1,
     fprintf(f, "\n");
 }
 
-static void sve_dump_zreg_diff(FILE *f, int vq, const __uint128_t *z1,
-                               const __uint128_t *z2)
+static void sve_dump_zreg_diff(FILE *f, int vq, const uint64_t *za,
+                               const uint64_t *zb)
 {
     const char *pad = "";
     int q;
 
     for (q = 0; q < vq; ++q) {
-        if (z1[q] != z2[q]) {
+        uint64_t za0 = za[2 * q], za1 = za[2 * q + 1];
+        uint64_t zb0 = zb[2 * q], zb1 = zb[2 * q + 1];
+
+        if (za0 != zb0 || za1 != zb1) {
             fprintf(f, "%sq%-2d: %016" PRIx64 "%016" PRIx64
-                    " vs %016" PRIx64 "%016" PRIx64"\n", pad, q,
-                    (uint64_t)(z1[q] >> 64), (uint64_t)z1[q],
-                    (uint64_t)(z2[q] >> 64), (uint64_t)z2[q]);
+                    " vs %016" PRIx64 "%016" PRIx64"\n",
+                    pad, q, za1, za0, zb1, zb0);
             pad = "      ";
         }
     }
@@ -239,38 +226,41 @@ int reginfo_dump(struct reginfo *ri, FILE * f)
     fprintf(f, "  fpsr   : %08x\n", ri->fpsr);
     fprintf(f, "  fpcr   : %08x\n", ri->fpcr);
 
-    if (test_sve) {
-        int q, vq = test_sve;
+    if (ri->sve_vl) {
+        int vq = sve_vq_from_vl(ri->sve_vl);
+        int q;
 
-        fprintf(f, "  vl     : %d\n", ri->sve.vl);
+        fprintf(f, "  vl     : %d\n", ri->sve_vl);
 
-        for (i = 0; i < 32; i++) {
-            fprintf(f, "  Z%-2d q%-2d: %016" PRIx64 "%016" PRIx64 "\n", i, 0,
-                    (uint64_t)(ri->sve.zregs[i][0] >> 64),
-                    (uint64_t)ri->sve.zregs[i][0]);
+        for (i = 0; i < SVE_NUM_ZREGS; i++) {
+            uint64_t *z = reginfo_zreg(ri, vq, i);
+
+            fprintf(f, "  Z%-2d q%-2d: %016" PRIx64 "%016" PRIx64 "\n",
+                    i, 0, z[1], z[0]);
             for (q = 1; q < vq; ++q) {
-                fprintf(f, "      q%-2d: %016" PRIx64 "%016" PRIx64 "\n", q,
-                        (uint64_t)(ri->sve.zregs[i][q] >> 64),
-                        (uint64_t)ri->sve.zregs[i][q]);
+                fprintf(f, "      q%-2d: %016" PRIx64 "%016" PRIx64 "\n",
+                        q, z[q * 2 + 1], z[q * 2]);
             }
         }
 
-        for (i = 0; i < 16; i++) {
-            fprintf(f, "  P%-2d    : ", i);
-            sve_dump_preg(f, vq, &ri->sve.pregs[i][0]);
+        for (i = 0; i < SVE_NUM_PREGS + 1; i++) {
+            uint16_t *p = reginfo_preg(ri, vq, i);
+
+            if (i == SVE_NUM_PREGS) {
+                fprintf(f, "  FFR    : ");
+            } else {
+                fprintf(f, "  P%-2d    : ", i);
+            }
+            sve_dump_preg(f, vq, p);
             fprintf(f, "\n");
         }
-        fprintf(f, "  FFR    : ");
-        sve_dump_preg(f, vq, &ri->sve.ffr[0]);
-        fprintf(f, "\n");
-
         return !ferror(f);
     }
 
     for (i = 0; i < 32; i++) {
-        fprintf(f, "  V%-2d    : %016" PRIx64 "%016" PRIx64 "\n", i,
-                (uint64_t) (ri->simd.vregs[i] >> 64),
-                (uint64_t) (ri->simd.vregs[i]));
+        uint64_t *v = reginfo_vreg(ri, i);
+        fprintf(f, "  V%-2d    : %016" PRIx64 "%016" PRIx64 "\n",
+                i, v[1], v[0]);
     }
 
     return !ferror(f);
@@ -314,44 +304,47 @@ int reginfo_dump_mismatch(struct reginfo *m, struct reginfo *a, FILE * f)
         fprintf(f, "  fpcr   : %08x vs %08x\n", m->fpcr, a->fpcr);
     }
 
-    if (test_sve) {
-        int vq = sve_vq_from_vl(m->sve.vl);
+    if (m->sve_vl != a->sve_vl) {
+        fprintf(f, "  vl    : %d vs %d\n", m->sve_vl, a->sve_vl);
+    }
 
-        if (m->sve.vl != a->sve.vl) {
-            fprintf(f, "  vl    : %d vs %d\n", m->sve.vl, a->sve.vl);
-        }
+    if (m->sve_vl) {
+        int vq = sve_vq_from_vl(m->sve_vl);
 
         for (i = 0; i < SVE_NUM_ZREGS; i++) {
-            if (!sve_zreg_is_eq(vq, &m->sve.zregs[i], &a->sve.zregs[i])) {
-                fprintf(f, "  Z%-2d ", i);
-                sve_dump_zreg_diff(f, vq, &m->sve.zregs[i][0],
-                                   &a->sve.zregs[i][0]);
-            }
-        }
-        for (i = 0; i < SVE_NUM_PREGS; i++) {
-            if (!sve_preg_is_eq(vq, &m->sve.pregs[i], &a->sve.pregs[i])) {
-                fprintf(f, "  P%-2d    : ", i);
-                sve_dump_preg_diff(f, vq, &m->sve.pregs[i][0],
-                                   &a->sve.pregs[i][0]);
-            }
-        }
-        if (!sve_preg_is_eq(vq, &m->sve.ffr, &a->sve.ffr)) {
-            fprintf(f, "  FFR   : ");
-            sve_dump_preg_diff(f, vq, &m->sve.pregs[i][0], &a->sve.pregs[i][0]);
-        }
+            uint64_t *zm = reginfo_zreg(m, vq, i);
+            uint64_t *za = reginfo_zreg(a, vq, i);
 
+            if (!sve_zreg_is_eq(vq, zm, za)) {
+                fprintf(f, "  Z%-2d ", i);
+                sve_dump_zreg_diff(f, vq, zm, za);
+            }
+        }
+        for (i = 0; i < SVE_NUM_PREGS + 1; i++) {
+            uint16_t *pm = reginfo_preg(m, vq, i);
+            uint16_t *pa = reginfo_preg(a, vq, i);
+
+            if (!sve_preg_is_eq(vq, pm, pa)) {
+                if (i == SVE_NUM_PREGS) {
+                    fprintf(f, "  FFR   : ");
+                } else {
+                    fprintf(f, "  P%-2d    : ", i);
+                }
+                sve_dump_preg_diff(f, vq, pm, pa);
+            }
+        }
         return !ferror(f);
     }
 
     for (i = 0; i < 32; i++) {
-        if (m->simd.vregs[i] != a->simd.vregs[i]) {
+        uint64_t *mv = reginfo_vreg(m, i);
+        uint64_t *av = reginfo_vreg(a, i);
+
+        if (mv[0] != av[0] || mv[1] != av[1]) {
             fprintf(f, "  V%-2d    : "
                     "%016" PRIx64 "%016" PRIx64 " vs "
-                    "%016" PRIx64 "%016" PRIx64 "\n", i,
-                    (uint64_t) (m->simd.vregs[i] >> 64),
-                    (uint64_t) m->simd.vregs[i],
-                    (uint64_t) (a->simd.vregs[i] >> 64),
-                    (uint64_t) a->simd.vregs[i]);
+                    "%016" PRIx64 "%016" PRIx64 "\n",
+                    i, mv[1], mv[0], av[1], av[0]);
         }
     }
 
