aarch32 avoid the VPUSH/VPOP of unused registers
PiperOrigin-RevId: 417544383
diff --git a/src/qs8-gemm/4x8-aarch32-neon-mlal-lane-ld64.S.in b/src/qs8-gemm/4x8-aarch32-neon-mlal-lane-ld64.S.in
index b99825b..c3c5be6 100644
--- a/src/qs8-gemm/4x8-aarch32-neon-mlal-lane-ld64.S.in
+++ b/src/qs8-gemm/4x8-aarch32-neon-mlal-lane-ld64.S.in
@@ -12,12 +12,12 @@
// size_t nc, r1
// size_t kc, r2 -> r5
// const uint8_t*restrict a, r3
-// size_t a_stride, sp + 96 -> (r7)
-// const void*restrict w, sp + 100 -> r9
-// uint8_t*restrict c, sp + 104 -> r11
-// size_t cm_stride, sp + 108 -> (r6)
-// size_t cn_stride, sp + 112 -> r7
-// const union xnn_qs8_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 116 -> (r5)
+// size_t a_stride, sp + 64 -> (r7)
+// const void*restrict w, sp + 68 -> r9
+// uint8_t*restrict c, sp + 72 -> r11
+// size_t cm_stride, sp + 76 -> (r6)
+// size_t cn_stride, sp + 80 -> r7
+// const union xnn_qs8_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 84 -> (r5)
// inner loop registers
@@ -34,16 +34,16 @@
// C2 r8 d24-d25 q12 d26-d27 q13
// C3 r6 d28-d29 q14 d30-d31 q15
-// Unused q5 q6
+// unused q6 q7
// params structure is 16 bytes
// struct {
-// int32_t right_pre_shift; d14[0]
-// int32_t multiplier; d14[1]
-// int32_t right_post_shift; d15[0]
-// int16_t output_zero_point; d15[2]
-// int8_t output_min; d15[6]
-// int8_t output_max; d15[7]
+// int32_t right_pre_shift; d10[0]
+// int32_t multiplier; d10[1]
+// int32_t right_post_shift; d11[0]
+// int16_t output_zero_point; d11[2]
+// int8_t output_min; d11[6]
+// int8_t output_max; d11[7]
// } rndnu_neon;
BEGIN_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_${"prfm_" if PREFETCH else ""}ld64
@@ -52,15 +52,15 @@
.arch armv7-a
.fpu neon
#endif
- # Push 96 bytes
+ # Push 64 bytes
PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32
- VPUSH {d8-d15} // +64 = 96
+ VPUSH {d8-d11} // +32 = 64
- LDR r7, [sp, 96] // a_stride
- LDR r11, [sp, 104] // c
- LDR r6, [sp, 108] // cm_stride
- LDR r9, [sp, 100] // w
- LDR r5, [sp, 116] // params
+ LDR r7, [sp, 64] // a_stride
+ LDR r11, [sp, 72] // c
+ LDR r6, [sp, 76] // cm_stride
+ LDR r9, [sp, 68] // w
+ LDR r5, [sp, 84] // params
# Clamp A and C pointers
CMP r0, 2 // if mr >= 2
@@ -81,8 +81,8 @@
MOVLO r6, r8 // c3
# Load params values
- VLDM r5!, {d14-d15} // RNDNU params
- LDR r7, [sp, 112] // cn_stride
+ VLDM r5!, {d10-d11} // RNDNU params
+ LDR r7, [sp, 80] // cn_stride
$if PREFETCH:
PLD [r9, 64] // Prefetch B
@@ -236,7 +236,7 @@
2:
# RNDNU quantization
- VDUP.32 q0, d14[0] // right_pre_shift
+ VDUP.32 q0, d10[0] // right_pre_shift
VQSHL.S32 q8, q8, q0
VQSHL.S32 q9, q9, q0
@@ -247,16 +247,16 @@
VQSHL.S32 q14, q14, q0
VQSHL.S32 q15, q15, q0
- VDUP.32 q2, d15[0] // right_post_shift
+ VDUP.32 q2, d11[0] // right_post_shift
- VQDMULH.S32 q8, q8, d14[1] // multiplier
- VQDMULH.S32 q9, q9, d14[1]
- VQDMULH.S32 q10, q10, d14[1]
- VQDMULH.S32 q12, q12, d14[1]
- VQDMULH.S32 q11, q11, d14[1]
- VQDMULH.S32 q13, q13, d14[1]
- VQDMULH.S32 q14, q14, d14[1]
- VQDMULH.S32 q15, q15, d14[1]
+ VQDMULH.S32 q8, q8, d10[1] // multiplier
+ VQDMULH.S32 q9, q9, d10[1]
+ VQDMULH.S32 q10, q10, d10[1]
+ VQDMULH.S32 q12, q12, d10[1]
+ VQDMULH.S32 q11, q11, d10[1]
+ VQDMULH.S32 q13, q13, d10[1]
+ VQDMULH.S32 q14, q14, d10[1]
+ VQDMULH.S32 q15, q15, d10[1]
VRSHL.S32 q8, q8, q2
VRSHL.S32 q9, q9, q2
@@ -267,7 +267,7 @@
VRSHL.S32 q14, q14, q2
VRSHL.S32 q15, q15, q2
- VDUP.16 q0, d15[2] // output_zero_point
+ VDUP.16 q0, d11[2] // output_zero_point
VQMOVN.S32 d16, q8
VQMOVN.S32 d17, q9
@@ -283,14 +283,14 @@
VQADD.S16 q10, q10, q0
VQADD.S16 q11, q11, q0
- VDUP.8 q12, d15[6] // output_min
+ VDUP.8 q12, d11[6] // output_min
VQMOVN.S16 d0, q8
VQMOVN.S16 d1, q9
VQMOVN.S16 d2, q10
VQMOVN.S16 d3, q11
- VDUP.8 q13, d15[7] // output_min
+ VDUP.8 q13, d11[7] // output_min
VMAX.S8 q0, q0, q12
VMAX.S8 q1, q1, q12
@@ -312,14 +312,14 @@
SUB r0, r0, r2
BHI 0b
- VPOP {d8-d15}
+ VPOP {d8-d11}
POP {r4, r5, r6, r7, r8, r9, r10, r11}
BX lr
# Remainder- 1 to 7 bytes of A
.p2align 3
3:
- AND r5, r2, 7 // kc remainder 1 to 7
+ AND r5, r5, 7 // kc remainder 1 to 7
VLD1.8 {d0}, [r3], r5
VLD1.8 {d8}, [r9]!
@@ -447,7 +447,7 @@
VST1.8 {d3[0]}, [r6]
7:
- VPOP {d8-d15}
+ VPOP {d8-d11}
POP {r4, r5, r6, r7, r8, r9, r10, r11}
BX lr
diff --git a/src/qs8-gemm/4x8c4-aarch32-neondot-ld64.S.in b/src/qs8-gemm/4x8c4-aarch32-neondot-ld64.S.in
index c85f7b4..bfcc79f 100644
--- a/src/qs8-gemm/4x8c4-aarch32-neondot-ld64.S.in
+++ b/src/qs8-gemm/4x8c4-aarch32-neondot-ld64.S.in
@@ -12,12 +12,12 @@
// size_t nc, r1
// size_t kc, r2 -> r5
// const uint8_t*restrict a, r3
-// size_t a_stride, sp + 96 -> (r7)
-// const void*restrict w, sp + 100 -> r9
-// uint8_t*restrict c, sp + 104 -> r11
-// size_t cm_stride, sp + 108 -> (r6)
-// size_t cn_stride, sp + 112 -> r7
-// const union xnn_qs8_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 116 -> (r5)
+// size_t a_stride, sp + 80 -> (r7)
+// const void*restrict w, sp + 84 -> r9
+// uint8_t*restrict c, sp + 88 -> r11
+// size_t cm_stride, sp + 92 -> (r6)
+// size_t cn_stride, sp + 96 -> r7
+// const union xnn_qs8_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 100 -> (r5)
// inner loop registers
@@ -34,30 +34,30 @@
// C2 r8 d24-d25 q12 d26-d27 q13
// C3 r6 d28-d29 q14 d30-d31 q15
-// Unused q6
+// unused q7
// params structure is 16 bytes
// struct {
-// int32_t right_pre_shift; d14[0]
-// int32_t multiplier; d14[1]
-// int32_t right_post_shift; d15[0]
-// int16_t output_zero_point; d15[2]
-// int8_t output_min; d15[6]
-// int8_t output_max; d15[7]
+// int32_t right_pre_shift; d12[0]
+// int32_t multiplier; d12[1]
+// int32_t right_post_shift; d13[0]
+// int16_t output_zero_point; d13[2]
+// int8_t output_min; d13[6]
+// int8_t output_max; d13[7]
// } rndnu_neon;
BEGIN_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_ld64
- # Push 96 bytes
+ # Push 80 bytes
PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32
- VPUSH {d8-d15} // +64 = 96
+ VPUSH {d8-d13} // +48 = 80
- LDR r7, [sp, 96] // a_stride
+ LDR r7, [sp, 80] // a_stride
ADD r2, r2, 3 // kc = (kc + 3) & ~3
- LDR r11, [sp, 104] // c
- LDR r6, [sp, 108] // cm_stride
- LDR r9, [sp, 100] // w
+ LDR r11, [sp, 88] // c
+ LDR r6, [sp, 92] // cm_stride
+ LDR r9, [sp, 84] // w
BIC r2, r2, 3
- LDR r5, [sp, 116] // params
+ LDR r5, [sp, 100] // params
# Clamp A and C pointers
CMP r0, 2 // if mr >= 2
@@ -78,8 +78,8 @@
MOVLO r6, r8 // c3
# Load params values
- VLDM r5!, {d14-d15} // RNDNU params
- LDR r7, [sp, 112] // cn_stride
+ VLDM r5!, {d12-d13} // RNDNU params
+ LDR r7, [sp, 96] // cn_stride
.p2align 3
0:
@@ -133,7 +133,7 @@
2:
# RNDNU quantization
- VDUP.32 q0, d14[0] // right_pre_shift
+ VDUP.32 q0, d12[0] // right_pre_shift
VQSHL.S32 q8, q8, q0
VQSHL.S32 q9, q9, q0
@@ -144,16 +144,16 @@
VQSHL.S32 q14, q14, q0
VQSHL.S32 q15, q15, q0
- VDUP.32 q2, d15[0] // right_post_shift
+ VDUP.32 q2, d13[0] // right_post_shift
- VQDMULH.S32 q8, q8, d14[1] // multiplier
- VQDMULH.S32 q9, q9, d14[1]
- VQDMULH.S32 q10, q10, d14[1]
- VQDMULH.S32 q12, q12, d14[1]
- VQDMULH.S32 q11, q11, d14[1]
- VQDMULH.S32 q13, q13, d14[1]
- VQDMULH.S32 q14, q14, d14[1]
- VQDMULH.S32 q15, q15, d14[1]
+ VQDMULH.S32 q8, q8, d12[1] // multiplier
+ VQDMULH.S32 q9, q9, d12[1]
+ VQDMULH.S32 q10, q10, d12[1]
+ VQDMULH.S32 q12, q12, d12[1]
+ VQDMULH.S32 q11, q11, d12[1]
+ VQDMULH.S32 q13, q13, d12[1]
+ VQDMULH.S32 q14, q14, d12[1]
+ VQDMULH.S32 q15, q15, d12[1]
VRSHL.S32 q8, q8, q2
VRSHL.S32 q9, q9, q2
@@ -164,7 +164,7 @@
VRSHL.S32 q14, q14, q2
VRSHL.S32 q15, q15, q2
- VDUP.16 q0, d15[2] // output_zero_point
+ VDUP.16 q0, d13[2] // output_zero_point
VQMOVN.S32 d16, q8
VQMOVN.S32 d17, q9
@@ -180,14 +180,14 @@
VQADD.S16 q10, q10, q0
VQADD.S16 q11, q11, q0
- VDUP.8 q12, d15[6] // output_min
+ VDUP.8 q12, d13[6] // output_min
VQMOVN.S16 d0, q8
VQMOVN.S16 d1, q9
VQMOVN.S16 d2, q10
VQMOVN.S16 d3, q11
- VDUP.8 q13, d15[7] // output_min
+ VDUP.8 q13, d13[7] // output_min
VMAX.S8 q0, q0, q12
VMAX.S8 q1, q1, q12
@@ -209,7 +209,7 @@
SUB r0, r0, r2
BHI 0b
- VPOP {d8-d15}
+ VPOP {d8-d13}
POP {r4, r5, r6, r7, r8, r9, r10, r11}
BX lr
@@ -263,7 +263,7 @@
VST1.8 {d3[0]}, [r6]
7:
- VPOP {d8-d15}
+ VPOP {d8-d13}
POP {r4, r5, r6, r7, r8, r9, r10, r11}
BX lr
diff --git a/src/qs8-gemm/gen/4x8-minmax-rndnu-aarch32-neon-mlal-lane-ld64.S b/src/qs8-gemm/gen/4x8-minmax-rndnu-aarch32-neon-mlal-lane-ld64.S
index 0420778..03cb1ee 100644
--- a/src/qs8-gemm/gen/4x8-minmax-rndnu-aarch32-neon-mlal-lane-ld64.S
+++ b/src/qs8-gemm/gen/4x8-minmax-rndnu-aarch32-neon-mlal-lane-ld64.S
@@ -16,12 +16,12 @@
// size_t nc, r1
// size_t kc, r2 -> r5
// const uint8_t*restrict a, r3
-// size_t a_stride, sp + 96 -> (r7)
-// const void*restrict w, sp + 100 -> r9
-// uint8_t*restrict c, sp + 104 -> r11
-// size_t cm_stride, sp + 108 -> (r6)
-// size_t cn_stride, sp + 112 -> r7
-// const union xnn_qs8_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 116 -> (r5)
+// size_t a_stride, sp + 64 -> (r7)
+// const void*restrict w, sp + 68 -> r9
+// uint8_t*restrict c, sp + 72 -> r11
+// size_t cm_stride, sp + 76 -> (r6)
+// size_t cn_stride, sp + 80 -> r7
+// const union xnn_qs8_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 84 -> (r5)
// inner loop registers
@@ -38,16 +38,16 @@
// C2 r8 d24-d25 q12 d26-d27 q13
// C3 r6 d28-d29 q14 d30-d31 q15
-// Unused q5 q6
+// unused q6 q7
// params structure is 16 bytes
// struct {
-// int32_t right_pre_shift; d14[0]
-// int32_t multiplier; d14[1]
-// int32_t right_post_shift; d15[0]
-// int16_t output_zero_point; d15[2]
-// int8_t output_min; d15[6]
-// int8_t output_max; d15[7]
+// int32_t right_pre_shift; d10[0]
+// int32_t multiplier; d10[1]
+// int32_t right_post_shift; d11[0]
+// int16_t output_zero_point; d11[2]
+// int8_t output_min; d11[6]
+// int8_t output_max; d11[7]
// } rndnu_neon;
BEGIN_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_ld64
@@ -56,15 +56,15 @@
.arch armv7-a
.fpu neon
#endif
- # Push 96 bytes
+ # Push 64 bytes
PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32
- VPUSH {d8-d15} // +64 = 96
+ VPUSH {d8-d11} // +32 = 64
- LDR r7, [sp, 96] // a_stride
- LDR r11, [sp, 104] // c
- LDR r6, [sp, 108] // cm_stride
- LDR r9, [sp, 100] // w
- LDR r5, [sp, 116] // params
+ LDR r7, [sp, 64] // a_stride
+ LDR r11, [sp, 72] // c
+ LDR r6, [sp, 76] // cm_stride
+ LDR r9, [sp, 68] // w
+ LDR r5, [sp, 84] // params
# Clamp A and C pointers
CMP r0, 2 // if mr >= 2
@@ -85,8 +85,8 @@
MOVLO r6, r8 // c3
# Load params values
- VLDM r5!, {d14-d15} // RNDNU params
- LDR r7, [sp, 112] // cn_stride
+ VLDM r5!, {d10-d11} // RNDNU params
+ LDR r7, [sp, 80] // cn_stride
.p2align 3
@@ -211,7 +211,7 @@
2:
# RNDNU quantization
- VDUP.32 q0, d14[0] // right_pre_shift
+ VDUP.32 q0, d10[0] // right_pre_shift
VQSHL.S32 q8, q8, q0
VQSHL.S32 q9, q9, q0
@@ -222,16 +222,16 @@
VQSHL.S32 q14, q14, q0
VQSHL.S32 q15, q15, q0
- VDUP.32 q2, d15[0] // right_post_shift
+ VDUP.32 q2, d11[0] // right_post_shift
- VQDMULH.S32 q8, q8, d14[1] // multiplier
- VQDMULH.S32 q9, q9, d14[1]
- VQDMULH.S32 q10, q10, d14[1]
- VQDMULH.S32 q12, q12, d14[1]
- VQDMULH.S32 q11, q11, d14[1]
- VQDMULH.S32 q13, q13, d14[1]
- VQDMULH.S32 q14, q14, d14[1]
- VQDMULH.S32 q15, q15, d14[1]
+ VQDMULH.S32 q8, q8, d10[1] // multiplier
+ VQDMULH.S32 q9, q9, d10[1]
+ VQDMULH.S32 q10, q10, d10[1]
+ VQDMULH.S32 q12, q12, d10[1]
+ VQDMULH.S32 q11, q11, d10[1]
+ VQDMULH.S32 q13, q13, d10[1]
+ VQDMULH.S32 q14, q14, d10[1]
+ VQDMULH.S32 q15, q15, d10[1]
VRSHL.S32 q8, q8, q2
VRSHL.S32 q9, q9, q2
@@ -242,7 +242,7 @@
VRSHL.S32 q14, q14, q2
VRSHL.S32 q15, q15, q2
- VDUP.16 q0, d15[2] // output_zero_point
+ VDUP.16 q0, d11[2] // output_zero_point
VQMOVN.S32 d16, q8
VQMOVN.S32 d17, q9
@@ -258,14 +258,14 @@
VQADD.S16 q10, q10, q0
VQADD.S16 q11, q11, q0
- VDUP.8 q12, d15[6] // output_min
+ VDUP.8 q12, d11[6] // output_min
VQMOVN.S16 d0, q8
VQMOVN.S16 d1, q9
VQMOVN.S16 d2, q10
VQMOVN.S16 d3, q11
- VDUP.8 q13, d15[7] // output_min
+ VDUP.8 q13, d11[7] // output_min
VMAX.S8 q0, q0, q12
VMAX.S8 q1, q1, q12
@@ -287,14 +287,14 @@
SUB r0, r0, r2
BHI 0b
- VPOP {d8-d15}
+ VPOP {d8-d11}
POP {r4, r5, r6, r7, r8, r9, r10, r11}
BX lr
# Remainder- 1 to 7 bytes of A
.p2align 3
3:
- AND r5, r2, 7 // kc remainder 1 to 7
+ AND r5, r5, 7 // kc remainder 1 to 7
VLD1.8 {d0}, [r3], r5
VLD1.8 {d8}, [r9]!
@@ -422,7 +422,7 @@
VST1.8 {d3[0]}, [r6]
7:
- VPOP {d8-d15}
+ VPOP {d8-d11}
POP {r4, r5, r6, r7, r8, r9, r10, r11}
BX lr
diff --git a/src/qs8-gemm/gen/4x8-minmax-rndnu-aarch32-neon-mlal-lane-prfm-ld64.S b/src/qs8-gemm/gen/4x8-minmax-rndnu-aarch32-neon-mlal-lane-prfm-ld64.S
index a46a374..28c4843 100644
--- a/src/qs8-gemm/gen/4x8-minmax-rndnu-aarch32-neon-mlal-lane-prfm-ld64.S
+++ b/src/qs8-gemm/gen/4x8-minmax-rndnu-aarch32-neon-mlal-lane-prfm-ld64.S
@@ -16,12 +16,12 @@
// size_t nc, r1
// size_t kc, r2 -> r5
// const uint8_t*restrict a, r3
-// size_t a_stride, sp + 96 -> (r7)
-// const void*restrict w, sp + 100 -> r9
-// uint8_t*restrict c, sp + 104 -> r11
-// size_t cm_stride, sp + 108 -> (r6)
-// size_t cn_stride, sp + 112 -> r7
-// const union xnn_qs8_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 116 -> (r5)
+// size_t a_stride, sp + 64 -> (r7)
+// const void*restrict w, sp + 68 -> r9
+// uint8_t*restrict c, sp + 72 -> r11
+// size_t cm_stride, sp + 76 -> (r6)
+// size_t cn_stride, sp + 80 -> r7
+// const union xnn_qs8_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 84 -> (r5)
// inner loop registers
@@ -38,16 +38,16 @@
// C2 r8 d24-d25 q12 d26-d27 q13
// C3 r6 d28-d29 q14 d30-d31 q15
-// Unused q5 q6
+// unused q6 q7
// params structure is 16 bytes
// struct {
-// int32_t right_pre_shift; d14[0]
-// int32_t multiplier; d14[1]
-// int32_t right_post_shift; d15[0]
-// int16_t output_zero_point; d15[2]
-// int8_t output_min; d15[6]
-// int8_t output_max; d15[7]
+// int32_t right_pre_shift; d10[0]
+// int32_t multiplier; d10[1]
+// int32_t right_post_shift; d11[0]
+// int16_t output_zero_point; d11[2]
+// int8_t output_min; d11[6]
+// int8_t output_max; d11[7]
// } rndnu_neon;
BEGIN_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8__aarch32_neon_mlal_lane_prfm_ld64
@@ -56,15 +56,15 @@
.arch armv7-a
.fpu neon
#endif
- # Push 96 bytes
+ # Push 64 bytes
PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32
- VPUSH {d8-d15} // +64 = 96
+ VPUSH {d8-d11} // +32 = 64
- LDR r7, [sp, 96] // a_stride
- LDR r11, [sp, 104] // c
- LDR r6, [sp, 108] // cm_stride
- LDR r9, [sp, 100] // w
- LDR r5, [sp, 116] // params
+ LDR r7, [sp, 64] // a_stride
+ LDR r11, [sp, 72] // c
+ LDR r6, [sp, 76] // cm_stride
+ LDR r9, [sp, 68] // w
+ LDR r5, [sp, 84] // params
# Clamp A and C pointers
CMP r0, 2 // if mr >= 2
@@ -85,8 +85,8 @@
MOVLO r6, r8 // c3
# Load params values
- VLDM r5!, {d14-d15} // RNDNU params
- LDR r7, [sp, 112] // cn_stride
+ VLDM r5!, {d10-d11} // RNDNU params
+ LDR r7, [sp, 80] // cn_stride
PLD [r9, 64] // Prefetch B
PLD [r9, 128]
@@ -226,7 +226,7 @@
2:
# RNDNU quantization
- VDUP.32 q0, d14[0] // right_pre_shift
+ VDUP.32 q0, d10[0] // right_pre_shift
VQSHL.S32 q8, q8, q0
VQSHL.S32 q9, q9, q0
@@ -237,16 +237,16 @@
VQSHL.S32 q14, q14, q0
VQSHL.S32 q15, q15, q0
- VDUP.32 q2, d15[0] // right_post_shift
+ VDUP.32 q2, d11[0] // right_post_shift
- VQDMULH.S32 q8, q8, d14[1] // multiplier
- VQDMULH.S32 q9, q9, d14[1]
- VQDMULH.S32 q10, q10, d14[1]
- VQDMULH.S32 q12, q12, d14[1]
- VQDMULH.S32 q11, q11, d14[1]
- VQDMULH.S32 q13, q13, d14[1]
- VQDMULH.S32 q14, q14, d14[1]
- VQDMULH.S32 q15, q15, d14[1]
+ VQDMULH.S32 q8, q8, d10[1] // multiplier
+ VQDMULH.S32 q9, q9, d10[1]
+ VQDMULH.S32 q10, q10, d10[1]
+ VQDMULH.S32 q12, q12, d10[1]
+ VQDMULH.S32 q11, q11, d10[1]
+ VQDMULH.S32 q13, q13, d10[1]
+ VQDMULH.S32 q14, q14, d10[1]
+ VQDMULH.S32 q15, q15, d10[1]
VRSHL.S32 q8, q8, q2
VRSHL.S32 q9, q9, q2
@@ -257,7 +257,7 @@
VRSHL.S32 q14, q14, q2
VRSHL.S32 q15, q15, q2
- VDUP.16 q0, d15[2] // output_zero_point
+ VDUP.16 q0, d11[2] // output_zero_point
VQMOVN.S32 d16, q8
VQMOVN.S32 d17, q9
@@ -273,14 +273,14 @@
VQADD.S16 q10, q10, q0
VQADD.S16 q11, q11, q0
- VDUP.8 q12, d15[6] // output_min
+ VDUP.8 q12, d11[6] // output_min
VQMOVN.S16 d0, q8
VQMOVN.S16 d1, q9
VQMOVN.S16 d2, q10
VQMOVN.S16 d3, q11
- VDUP.8 q13, d15[7] // output_min
+ VDUP.8 q13, d11[7] // output_min
VMAX.S8 q0, q0, q12
VMAX.S8 q1, q1, q12
@@ -302,14 +302,14 @@
SUB r0, r0, r2
BHI 0b
- VPOP {d8-d15}
+ VPOP {d8-d11}
POP {r4, r5, r6, r7, r8, r9, r10, r11}
BX lr
# Remainder- 1 to 7 bytes of A
.p2align 3
3:
- AND r5, r2, 7 // kc remainder 1 to 7
+ AND r5, r5, 7 // kc remainder 1 to 7
VLD1.8 {d0}, [r3], r5
VLD1.8 {d8}, [r9]!
@@ -437,7 +437,7 @@
VST1.8 {d3[0]}, [r6]
7:
- VPOP {d8-d15}
+ VPOP {d8-d11}
POP {r4, r5, r6, r7, r8, r9, r10, r11}
BX lr
diff --git a/src/qs8-gemm/gen/4x8c4-minmax-rndnu-aarch32-neondot-ld64.S b/src/qs8-gemm/gen/4x8c4-minmax-rndnu-aarch32-neondot-ld64.S
index 2cdf905..acad1f7 100644
--- a/src/qs8-gemm/gen/4x8c4-minmax-rndnu-aarch32-neondot-ld64.S
+++ b/src/qs8-gemm/gen/4x8c4-minmax-rndnu-aarch32-neondot-ld64.S
@@ -16,12 +16,12 @@
// size_t nc, r1
// size_t kc, r2 -> r5
// const uint8_t*restrict a, r3
-// size_t a_stride, sp + 96 -> (r7)
-// const void*restrict w, sp + 100 -> r9
-// uint8_t*restrict c, sp + 104 -> r11
-// size_t cm_stride, sp + 108 -> (r6)
-// size_t cn_stride, sp + 112 -> r7
-// const union xnn_qs8_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 116 -> (r5)
+// size_t a_stride, sp + 80 -> (r7)
+// const void*restrict w, sp + 84 -> r9
+// uint8_t*restrict c, sp + 88 -> r11
+// size_t cm_stride, sp + 92 -> (r6)
+// size_t cn_stride, sp + 96 -> r7
+// const union xnn_qs8_minmax_params params[restrict XNN_MIN_ELEMENTS(1)]) sp + 100 -> (r5)
// inner loop registers
@@ -38,30 +38,30 @@
// C2 r8 d24-d25 q12 d26-d27 q13
// C3 r6 d28-d29 q14 d30-d31 q15
-// Unused q6
+// unused q7
// params structure is 16 bytes
// struct {
-// int32_t right_pre_shift; d14[0]
-// int32_t multiplier; d14[1]
-// int32_t right_post_shift; d15[0]
-// int16_t output_zero_point; d15[2]
-// int8_t output_min; d15[6]
-// int8_t output_max; d15[7]
+// int32_t right_pre_shift; d12[0]
+// int32_t multiplier; d12[1]
+// int32_t right_post_shift; d13[0]
+// int16_t output_zero_point; d13[2]
+// int8_t output_min; d13[6]
+// int8_t output_max; d13[7]
// } rndnu_neon;
BEGIN_FUNCTION xnn_qs8_gemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_ld64
- # Push 96 bytes
+ # Push 80 bytes
PUSH {r4, r5, r6, r7, r8, r9, r10, r11} // 32
- VPUSH {d8-d15} // +64 = 96
+ VPUSH {d8-d13} // +48 = 80
- LDR r7, [sp, 96] // a_stride
+ LDR r7, [sp, 80] // a_stride
ADD r2, r2, 3 // kc = (kc + 3) & ~3
- LDR r11, [sp, 104] // c
- LDR r6, [sp, 108] // cm_stride
- LDR r9, [sp, 100] // w
+ LDR r11, [sp, 88] // c
+ LDR r6, [sp, 92] // cm_stride
+ LDR r9, [sp, 84] // w
BIC r2, r2, 3
- LDR r5, [sp, 116] // params
+ LDR r5, [sp, 100] // params
# Clamp A and C pointers
CMP r0, 2 // if mr >= 2
@@ -82,8 +82,8 @@
MOVLO r6, r8 // c3
# Load params values
- VLDM r5!, {d14-d15} // RNDNU params
- LDR r7, [sp, 112] // cn_stride
+ VLDM r5!, {d12-d13} // RNDNU params
+ LDR r7, [sp, 96] // cn_stride
.p2align 3
0:
@@ -137,7 +137,7 @@
2:
# RNDNU quantization
- VDUP.32 q0, d14[0] // right_pre_shift
+ VDUP.32 q0, d12[0] // right_pre_shift
VQSHL.S32 q8, q8, q0
VQSHL.S32 q9, q9, q0
@@ -148,16 +148,16 @@
VQSHL.S32 q14, q14, q0
VQSHL.S32 q15, q15, q0
- VDUP.32 q2, d15[0] // right_post_shift
+ VDUP.32 q2, d13[0] // right_post_shift
- VQDMULH.S32 q8, q8, d14[1] // multiplier
- VQDMULH.S32 q9, q9, d14[1]
- VQDMULH.S32 q10, q10, d14[1]
- VQDMULH.S32 q12, q12, d14[1]
- VQDMULH.S32 q11, q11, d14[1]
- VQDMULH.S32 q13, q13, d14[1]
- VQDMULH.S32 q14, q14, d14[1]
- VQDMULH.S32 q15, q15, d14[1]
+ VQDMULH.S32 q8, q8, d12[1] // multiplier
+ VQDMULH.S32 q9, q9, d12[1]
+ VQDMULH.S32 q10, q10, d12[1]
+ VQDMULH.S32 q12, q12, d12[1]
+ VQDMULH.S32 q11, q11, d12[1]
+ VQDMULH.S32 q13, q13, d12[1]
+ VQDMULH.S32 q14, q14, d12[1]
+ VQDMULH.S32 q15, q15, d12[1]
VRSHL.S32 q8, q8, q2
VRSHL.S32 q9, q9, q2
@@ -168,7 +168,7 @@
VRSHL.S32 q14, q14, q2
VRSHL.S32 q15, q15, q2
- VDUP.16 q0, d15[2] // output_zero_point
+ VDUP.16 q0, d13[2] // output_zero_point
VQMOVN.S32 d16, q8
VQMOVN.S32 d17, q9
@@ -184,14 +184,14 @@
VQADD.S16 q10, q10, q0
VQADD.S16 q11, q11, q0
- VDUP.8 q12, d15[6] // output_min
+ VDUP.8 q12, d13[6] // output_min
VQMOVN.S16 d0, q8
VQMOVN.S16 d1, q9
VQMOVN.S16 d2, q10
VQMOVN.S16 d3, q11
- VDUP.8 q13, d15[7] // output_min
+ VDUP.8 q13, d13[7] // output_min
VMAX.S8 q0, q0, q12
VMAX.S8 q1, q1, q12
@@ -213,7 +213,7 @@
SUB r0, r0, r2
BHI 0b
- VPOP {d8-d15}
+ VPOP {d8-d13}
POP {r4, r5, r6, r7, r8, r9, r10, r11}
BX lr
@@ -267,7 +267,7 @@
VST1.8 {d3[0]}, [r6]
7:
- VPOP {d8-d15}
+ VPOP {d8-d13}
POP {r4, r5, r6, r7, r8, r9, r10, r11}
BX lr
diff --git a/src/qs8-igemm/4x8c4-aarch32-neondot-ld64.S.in b/src/qs8-igemm/4x8c4-aarch32-neondot-ld64.S.in
index 32d07cf..546220f 100644
--- a/src/qs8-igemm/4x8c4-aarch32-neondot-ld64.S.in
+++ b/src/qs8-igemm/4x8c4-aarch32-neondot-ld64.S.in
@@ -10,16 +10,16 @@
// void xnn_qs8_igemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_ld64(
// size_t mr, r0
// size_t nc, r1
-// size_t kc, r2 -> r5 -> sp + 68
-// size_t ks, r3 -> sp + 72 -> r14
-// const float**restrict a, sp + 112 -> r2
-// const void*restrict w, sp + 116 -> r9
-// uint8_t*restrict c, sp + 120 -> r11
-// size_t cm_stride, sp + 124 -> (r6)
-// size_t cn_stride, sp + 128 -> (r7)
-// size_t a_offset, sp + 132 -> (r5)
-// const float* zero, sp + 136 -> (r7)
-// minmax_params*params, sp + 140 -> (r5)
+// size_t kc, r2 -> r5 -> sp + 52
+// size_t ks, r3 -> sp + 56 -> r14
+// const float**restrict a, sp + 96 -> r2
+// const void*restrict w, sp + 100 -> r9
+// uint8_t*restrict c, sp + 104 -> r11
+// size_t cm_stride, sp + 108 -> (r6)
+// size_t cn_stride, sp + 112 -> (r7)
+// size_t a_offset, sp + 116 -> (r5)
+// const float* zero, sp + 120 -> (r7)
+// minmax_params*params, sp + 124 -> (r5)
// inner loop registers
@@ -35,33 +35,33 @@
// C2 r8 d24-d25 q12 d26-d27 q13
// C3 r6 d28-d29 q14 d30-d31 q15
-// Unused q6
+// unused q7
// params structure is 16 bytes
// struct {
-// int32_t right_pre_shift; d14[0]
-// int32_t multiplier; d14[1]
-// int32_t right_post_shift; d15[0]
-// int16_t output_zero_point; d15[2]
-// int8_t output_min; d15[6]
-// int8_t output_max; d15[7]
+// int32_t right_pre_shift; d12[0]
+// int32_t multiplier; d12[1]
+// int32_t right_post_shift; d13[0]
+// int16_t output_zero_point; d13[2]
+// int8_t output_min; d13[6]
+// int8_t output_max; d13[7]
// } rndnu_neon;
BEGIN_FUNCTION xnn_qs8_igemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_ld64
ADD r2, r2, 3 // kc = (kc + 3) & ~3
BIC r2, r2, 3
- # Push 112 bytes
+ # Push 96 bytes
# r2 will be reloaded in outer loop. r3 is ks
PUSH {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r14} // +44
SUB sp, sp, 4 // 4
- VPUSH {d8-d15} // +64 = 112
+ VPUSH {d8-d13} // +48 = 96
- LDR r11, [sp, 120] // c
- LDR r6, [sp, 124] // cm_stride
- LDR r2, [sp, 112] // a
- LDR r9, [sp, 116] // w
- LDR r5, [sp, 140] // params
+ LDR r11, [sp, 104] // c
+ LDR r6, [sp, 108] // cm_stride
+ LDR r2, [sp, 96] // a
+ LDR r9, [sp, 100] // w
+ LDR r5, [sp, 124] // params
MOV r14, r3 // p = ks
# Clamp C pointers
@@ -76,7 +76,7 @@
MOVLO r6, r8 // c3
# Load params values
- VLDM r5!, {d14-d15} // RNDNU params
+ VLDM r5!, {d12-d13} // RNDNU params
0:
# Load initial bias from w into accumulators
@@ -97,8 +97,8 @@
ADD r2, r2, 16
# Add a_offset
- LDR r5, [sp, 132] // a_offset
- LDR r7, [sp, 136] // zero
+ LDR r5, [sp, 116] // a_offset
+ LDR r7, [sp, 120] // zero
CMP r3, r7 // if a0 == zero
ADD r3, r3, r5 // a0 += a_offset
MOVEQ r3, r7 // a0 = zero, else += a0 + a_offset
@@ -110,7 +110,7 @@
MOVEQ r10, r7 // a2 = zero, else += a2 + a_offset
CMP r0, r7 // if a3 == zero
ADD r0, r0, r5 // a3 += a_offset
- LDR r5, [sp, 68] // kc
+ LDR r5, [sp, 52] // kc
MOVEQ r0, r7 // a3 = zero, else += a3 + a_offset
SUBS r5, r5, 8 // kc - 8
@@ -158,11 +158,11 @@
SUBS r14, r14, 16 // ks -= MR * sizeof(void*)
BHI 1b
- LDR r7, [sp, 128] // cn_stride
- LDR r14, [sp, 72] // p = ks
+ LDR r7, [sp, 112] // cn_stride
+ LDR r14, [sp, 56] // p = ks
# RNDNU quantization
- VDUP.32 q0, d14[0] // right_pre_shift
+ VDUP.32 q0, d12[0] // right_pre_shift
VQSHL.S32 q8, q8, q0
VQSHL.S32 q9, q9, q0
@@ -173,16 +173,16 @@
VQSHL.S32 q14, q14, q0
VQSHL.S32 q15, q15, q0
- VDUP.32 q2, d15[0] // right_post_shift
+ VDUP.32 q2, d13[0] // right_post_shift
- VQDMULH.S32 q8, q8, d14[1] // multiplier
- VQDMULH.S32 q9, q9, d14[1]
- VQDMULH.S32 q10, q10, d14[1]
- VQDMULH.S32 q12, q12, d14[1]
- VQDMULH.S32 q11, q11, d14[1]
- VQDMULH.S32 q13, q13, d14[1]
- VQDMULH.S32 q14, q14, d14[1]
- VQDMULH.S32 q15, q15, d14[1]
+ VQDMULH.S32 q8, q8, d12[1] // multiplier
+ VQDMULH.S32 q9, q9, d12[1]
+ VQDMULH.S32 q10, q10, d12[1]
+ VQDMULH.S32 q12, q12, d12[1]
+ VQDMULH.S32 q11, q11, d12[1]
+ VQDMULH.S32 q13, q13, d12[1]
+ VQDMULH.S32 q14, q14, d12[1]
+ VQDMULH.S32 q15, q15, d12[1]
VRSHL.S32 q8, q8, q2
VRSHL.S32 q9, q9, q2
@@ -193,7 +193,7 @@
VRSHL.S32 q14, q14, q2
VRSHL.S32 q15, q15, q2
- VDUP.16 q0, d15[2] // output_zero_point
+ VDUP.16 q0, d13[2] // output_zero_point
VQMOVN.S32 d16, q8
VQMOVN.S32 d17, q9
@@ -209,14 +209,14 @@
VQADD.S16 q10, q10, q0
VQADD.S16 q11, q11, q0
- VDUP.8 q12, d15[6] // output_min
+ VDUP.8 q12, d13[6] // output_min
VQMOVN.S16 d0, q8
VQMOVN.S16 d1, q9
VQMOVN.S16 d2, q10
VQMOVN.S16 d3, q11
- VDUP.8 q13, d15[7] // output_min
+ VDUP.8 q13, d13[7] // output_min
VMAX.S8 q0, q0, q12
VMAX.S8 q1, q1, q12
@@ -235,7 +235,7 @@
SUB r2, r2, r14 // a -= ks
BHI 0b
- VPOP {d8-d15}
+ VPOP {d8-d13}
ADD sp, sp, 12 // skip pad, r2, r3
POP {r4, r5, r6, r7, r8, r9, r10, r11, pc}
@@ -288,7 +288,7 @@
VST1.8 {d0[0]}, [r11]
8:
- VPOP {d8-d15}
+ VPOP {d8-d13}
ADD sp, sp, 12 // skip pad, r2, r3
POP {r4, r5, r6, r7, r8, r9, r10, r11, pc}
diff --git a/src/qs8-igemm/gen/4x8c4-minmax-rndnu-aarch32-neondot-ld64.S b/src/qs8-igemm/gen/4x8c4-minmax-rndnu-aarch32-neondot-ld64.S
index 5ac0966..a96f6bf 100644
--- a/src/qs8-igemm/gen/4x8c4-minmax-rndnu-aarch32-neondot-ld64.S
+++ b/src/qs8-igemm/gen/4x8c4-minmax-rndnu-aarch32-neondot-ld64.S
@@ -14,16 +14,16 @@
// void xnn_qs8_igemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_ld64(
// size_t mr, r0
// size_t nc, r1
-// size_t kc, r2 -> r5 -> sp + 68
-// size_t ks, r3 -> sp + 72 -> r14
-// const float**restrict a, sp + 112 -> r2
-// const void*restrict w, sp + 116 -> r9
-// uint8_t*restrict c, sp + 120 -> r11
-// size_t cm_stride, sp + 124 -> (r6)
-// size_t cn_stride, sp + 128 -> (r7)
-// size_t a_offset, sp + 132 -> (r5)
-// const float* zero, sp + 136 -> (r7)
-// minmax_params*params, sp + 140 -> (r5)
+// size_t kc, r2 -> r5 -> sp + 52
+// size_t ks, r3 -> sp + 56 -> r14
+// const float**restrict a, sp + 96 -> r2
+// const void*restrict w, sp + 100 -> r9
+// uint8_t*restrict c, sp + 104 -> r11
+// size_t cm_stride, sp + 108 -> (r6)
+// size_t cn_stride, sp + 112 -> (r7)
+// size_t a_offset, sp + 116 -> (r5)
+// const float* zero, sp + 120 -> (r7)
+// minmax_params*params, sp + 124 -> (r5)
// inner loop registers
@@ -39,33 +39,33 @@
// C2 r8 d24-d25 q12 d26-d27 q13
// C3 r6 d28-d29 q14 d30-d31 q15
-// Unused q6
+// unused q7
// params structure is 16 bytes
// struct {
-// int32_t right_pre_shift; d14[0]
-// int32_t multiplier; d14[1]
-// int32_t right_post_shift; d15[0]
-// int16_t output_zero_point; d15[2]
-// int8_t output_min; d15[6]
-// int8_t output_max; d15[7]
+// int32_t right_pre_shift; d12[0]
+// int32_t multiplier; d12[1]
+// int32_t right_post_shift; d13[0]
+// int16_t output_zero_point; d13[2]
+// int8_t output_min; d13[6]
+// int8_t output_max; d13[7]
// } rndnu_neon;
BEGIN_FUNCTION xnn_qs8_igemm_minmax_rndnu_ukernel_4x8c4__aarch32_neondot_ld64
ADD r2, r2, 3 // kc = (kc + 3) & ~3
BIC r2, r2, 3
- # Push 112 bytes
+ # Push 96 bytes
# r2 will be reloaded in outer loop. r3 is ks
PUSH {r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r14} // +44
SUB sp, sp, 4 // 4
- VPUSH {d8-d15} // +64 = 112
+ VPUSH {d8-d13} // +48 = 96
- LDR r11, [sp, 120] // c
- LDR r6, [sp, 124] // cm_stride
- LDR r2, [sp, 112] // a
- LDR r9, [sp, 116] // w
- LDR r5, [sp, 140] // params
+ LDR r11, [sp, 104] // c
+ LDR r6, [sp, 108] // cm_stride
+ LDR r2, [sp, 96] // a
+ LDR r9, [sp, 100] // w
+ LDR r5, [sp, 124] // params
MOV r14, r3 // p = ks
# Clamp C pointers
@@ -80,7 +80,7 @@
MOVLO r6, r8 // c3
# Load params values
- VLDM r5!, {d14-d15} // RNDNU params
+ VLDM r5!, {d12-d13} // RNDNU params
0:
# Load initial bias from w into accumulators
@@ -101,8 +101,8 @@
ADD r2, r2, 16
# Add a_offset
- LDR r5, [sp, 132] // a_offset
- LDR r7, [sp, 136] // zero
+ LDR r5, [sp, 116] // a_offset
+ LDR r7, [sp, 120] // zero
CMP r3, r7 // if a0 == zero
ADD r3, r3, r5 // a0 += a_offset
MOVEQ r3, r7 // a0 = zero, else += a0 + a_offset
@@ -114,7 +114,7 @@
MOVEQ r10, r7 // a2 = zero, else += a2 + a_offset
CMP r0, r7 // if a3 == zero
ADD r0, r0, r5 // a3 += a_offset
- LDR r5, [sp, 68] // kc
+ LDR r5, [sp, 52] // kc
MOVEQ r0, r7 // a3 = zero, else += a3 + a_offset
SUBS r5, r5, 8 // kc - 8
@@ -162,11 +162,11 @@
SUBS r14, r14, 16 // ks -= MR * sizeof(void*)
BHI 1b
- LDR r7, [sp, 128] // cn_stride
- LDR r14, [sp, 72] // p = ks
+ LDR r7, [sp, 112] // cn_stride
+ LDR r14, [sp, 56] // p = ks
# RNDNU quantization
- VDUP.32 q0, d14[0] // right_pre_shift
+ VDUP.32 q0, d12[0] // right_pre_shift
VQSHL.S32 q8, q8, q0
VQSHL.S32 q9, q9, q0
@@ -177,16 +177,16 @@
VQSHL.S32 q14, q14, q0
VQSHL.S32 q15, q15, q0
- VDUP.32 q2, d15[0] // right_post_shift
+ VDUP.32 q2, d13[0] // right_post_shift
- VQDMULH.S32 q8, q8, d14[1] // multiplier
- VQDMULH.S32 q9, q9, d14[1]
- VQDMULH.S32 q10, q10, d14[1]
- VQDMULH.S32 q12, q12, d14[1]
- VQDMULH.S32 q11, q11, d14[1]
- VQDMULH.S32 q13, q13, d14[1]
- VQDMULH.S32 q14, q14, d14[1]
- VQDMULH.S32 q15, q15, d14[1]
+ VQDMULH.S32 q8, q8, d12[1] // multiplier
+ VQDMULH.S32 q9, q9, d12[1]
+ VQDMULH.S32 q10, q10, d12[1]
+ VQDMULH.S32 q12, q12, d12[1]
+ VQDMULH.S32 q11, q11, d12[1]
+ VQDMULH.S32 q13, q13, d12[1]
+ VQDMULH.S32 q14, q14, d12[1]
+ VQDMULH.S32 q15, q15, d12[1]
VRSHL.S32 q8, q8, q2
VRSHL.S32 q9, q9, q2
@@ -197,7 +197,7 @@
VRSHL.S32 q14, q14, q2
VRSHL.S32 q15, q15, q2
- VDUP.16 q0, d15[2] // output_zero_point
+ VDUP.16 q0, d13[2] // output_zero_point
VQMOVN.S32 d16, q8
VQMOVN.S32 d17, q9
@@ -213,14 +213,14 @@
VQADD.S16 q10, q10, q0
VQADD.S16 q11, q11, q0
- VDUP.8 q12, d15[6] // output_min
+ VDUP.8 q12, d13[6] // output_min
VQMOVN.S16 d0, q8
VQMOVN.S16 d1, q9
VQMOVN.S16 d2, q10
VQMOVN.S16 d3, q11
- VDUP.8 q13, d15[7] // output_min
+ VDUP.8 q13, d13[7] // output_min
VMAX.S8 q0, q0, q12
VMAX.S8 q1, q1, q12
@@ -239,7 +239,7 @@
SUB r2, r2, r14 // a -= ks
BHI 0b
- VPOP {d8-d15}
+ VPOP {d8-d13}
ADD sp, sp, 12 // skip pad, r2, r3
POP {r4, r5, r6, r7, r8, r9, r10, r11, pc}
@@ -292,7 +292,7 @@
VST1.8 {d0[0]}, [r11]
8:
- VPOP {d8-d15}
+ VPOP {d8-d13}
ADD sp, sp, 12 // skip pad, r2, r3
POP {r4, r5, r6, r7, r8, r9, r10, r11, pc}