~ubuntu-branches/ubuntu/vivid/qemu/vivid

« back to all changes in this revision

Viewing changes to debian/patches/ubuntu/arm64/0112-target-arm-A64-Add-SIMD-ld-st-multiple.patch

  • Committer: Package Import Robot
  • Author(s): dann frazier
  • Date: 2014-02-11 15:41:53 UTC
  • Revision ID: package-import@ubuntu.com-20140211154153-2d001tf0ium08u81
Tags: 1.7.0+dfsg-3ubuntu2
* Backport changes to enable qemu-user-static support for aarch64
* debian/control: add ppc64el to Architectures
* debian/rules: only install qemu-system-aarch64 on arm64.
  Fixes a FTBFS  when built twice in a row on non-arm64 due to a stale
  debian/qemu-system-aarch64 directory

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
From 82fcc7f26f3ab8391c120ad9437a85b8fb919d2d Mon Sep 17 00:00:00 2001
 
2
From: =?UTF-8?q?Alex=20Benn=C3=A9e?= <alex.bennee@linaro.org>
 
3
Date: Fri, 31 Jan 2014 14:47:30 +0000
 
4
Subject: [PATCH 112/158] target-arm: A64: Add SIMD ld/st multiple
 
5
MIME-Version: 1.0
 
6
Content-Type: text/plain; charset=UTF-8
 
7
Content-Transfer-Encoding: 8bit
 
8
 
 
9
This adds support support for the SIMD load/store
 
10
multiple category of instructions.
 
11
 
 
12
This also brings in a couple of helper functions for manipulating
 
13
sections of the SIMD registers:
 
14
 
 
15
  * do_vec_get - fetch value from a slice of a vector register
 
16
  * do_vec_set - set a slice of a vector register
 
17
 
 
18
which use vec_reg_offset for consistent processing of offsets in an
 
19
endian aware manner. There are also additional helpers:
 
20
 
 
21
  * do_vec_ld - load value into SIMD
 
22
  * do_vec_st - store value from SIMD
 
23
 
 
24
which load or store a slice of a vector register to memory.
 
25
These don't zero extend like the fp variants.
 
26
 
 
27
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
 
28
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
 
29
Reviewed-by: Richard Henderson <rth@twiddle.net>
 
30
---
 
31
 target-arm/translate-a64.c | 250 ++++++++++++++++++++++++++++++++++++++++++++-
 
32
 1 file changed, 248 insertions(+), 2 deletions(-)
 
33
 
 
34
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
 
35
index cf80c46..e4fdf00 100644
 
36
--- a/target-arm/translate-a64.c
 
37
+++ b/target-arm/translate-a64.c
 
38
@@ -308,6 +308,28 @@ static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
 
39
     return v;
 
40
 }
 
41
 
 
42
+/* Return the offset into CPUARMState of an element of specified
 
43
+ * size, 'element' places in from the least significant end of
 
44
+ * the FP/vector register Qn.
 
45
+ */
 
46
+static inline int vec_reg_offset(int regno, int element, TCGMemOp size)
 
47
+{
 
48
+    int offs = offsetof(CPUARMState, vfp.regs[regno * 2]);
 
49
+#ifdef HOST_WORDS_BIGENDIAN
 
50
+    /* This is complicated slightly because vfp.regs[2n] is
 
51
+     * still the low half and  vfp.regs[2n+1] the high half
 
52
+     * of the 128 bit vector, even on big endian systems.
 
53
+     * Calculate the offset assuming a fully bigendian 128 bits,
 
54
+     * then XOR to account for the order of the two 64 bit halves.
 
55
+     */
 
56
+    offs += (16 - ((element + 1) * (1 << size)));
 
57
+    offs ^= 8;
 
58
+#else
 
59
+    offs += element * (1 << size);
 
60
+#endif
 
61
+    return offs;
 
62
+}
 
63
+
 
64
 /* Return the offset into CPUARMState of a slice (from
 
65
  * the least significant end) of FP register Qn (ie
 
66
  * Dn, Sn, Hn or Bn).
 
67
@@ -661,6 +683,108 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
 
68
 }
 
69
 
 
70
 /*
 
71
+ * Vector load/store helpers.
 
72
+ *
 
73
+ * The principal difference between this and a FP load is that we don't
 
74
+ * zero extend as we are filling a partial chunk of the vector register.
 
75
+ * These functions don't support 128 bit loads/stores, which would be
 
76
+ * normal load/store operations.
 
77
+ */
 
78
+
 
79
+/* Get value of an element within a vector register */
 
80
+static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
 
81
+                             int element, TCGMemOp memop)
 
82
+{
 
83
+    int vect_off = vec_reg_offset(srcidx, element, memop & MO_SIZE);
 
84
+    switch (memop) {
 
85
+    case MO_8:
 
86
+        tcg_gen_ld8u_i64(tcg_dest, cpu_env, vect_off);
 
87
+        break;
 
88
+    case MO_16:
 
89
+        tcg_gen_ld16u_i64(tcg_dest, cpu_env, vect_off);
 
90
+        break;
 
91
+    case MO_32:
 
92
+        tcg_gen_ld32u_i64(tcg_dest, cpu_env, vect_off);
 
93
+        break;
 
94
+    case MO_8|MO_SIGN:
 
95
+        tcg_gen_ld8s_i64(tcg_dest, cpu_env, vect_off);
 
96
+        break;
 
97
+    case MO_16|MO_SIGN:
 
98
+        tcg_gen_ld16s_i64(tcg_dest, cpu_env, vect_off);
 
99
+        break;
 
100
+    case MO_32|MO_SIGN:
 
101
+        tcg_gen_ld32s_i64(tcg_dest, cpu_env, vect_off);
 
102
+        break;
 
103
+    case MO_64:
 
104
+    case MO_64|MO_SIGN:
 
105
+        tcg_gen_ld_i64(tcg_dest, cpu_env, vect_off);
 
106
+        break;
 
107
+    default:
 
108
+        g_assert_not_reached();
 
109
+    }
 
110
+}
 
111
+
 
112
+/* Set value of an element within a vector register */
 
113
+static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
 
114
+                              int element, TCGMemOp memop)
 
115
+{
 
116
+    int vect_off = vec_reg_offset(destidx, element, memop & MO_SIZE);
 
117
+    switch (memop) {
 
118
+    case MO_8:
 
119
+        tcg_gen_st8_i64(tcg_src, cpu_env, vect_off);
 
120
+        break;
 
121
+    case MO_16:
 
122
+        tcg_gen_st16_i64(tcg_src, cpu_env, vect_off);
 
123
+        break;
 
124
+    case MO_32:
 
125
+        tcg_gen_st32_i64(tcg_src, cpu_env, vect_off);
 
126
+        break;
 
127
+    case MO_64:
 
128
+        tcg_gen_st_i64(tcg_src, cpu_env, vect_off);
 
129
+        break;
 
130
+    default:
 
131
+        g_assert_not_reached();
 
132
+    }
 
133
+}
 
134
+
 
135
+/* Clear the high 64 bits of a 128 bit vector (in general non-quad
 
136
+ * vector ops all need to do this).
 
137
+ */
 
138
+static void clear_vec_high(DisasContext *s, int rd)
 
139
+{
 
140
+    TCGv_i64 tcg_zero = tcg_const_i64(0);
 
141
+
 
142
+    write_vec_element(s, tcg_zero, rd, 1, MO_64);
 
143
+    tcg_temp_free_i64(tcg_zero);
 
144
+}
 
145
+
 
146
+/* Store from vector register to memory */
 
147
+static void do_vec_st(DisasContext *s, int srcidx, int element,
 
148
+                      TCGv_i64 tcg_addr, int size)
 
149
+{
 
150
+    TCGMemOp memop = MO_TE + size;
 
151
+    TCGv_i64 tcg_tmp = tcg_temp_new_i64();
 
152
+
 
153
+    read_vec_element(s, tcg_tmp, srcidx, element, size);
 
154
+    tcg_gen_qemu_st_i64(tcg_tmp, tcg_addr, get_mem_index(s), memop);
 
155
+
 
156
+    tcg_temp_free_i64(tcg_tmp);
 
157
+}
 
158
+
 
159
+/* Load from memory to vector register */
 
160
+static void do_vec_ld(DisasContext *s, int destidx, int element,
 
161
+                      TCGv_i64 tcg_addr, int size)
 
162
+{
 
163
+    TCGMemOp memop = MO_TE + size;
 
164
+    TCGv_i64 tcg_tmp = tcg_temp_new_i64();
 
165
+
 
166
+    tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr, get_mem_index(s), memop);
 
167
+    write_vec_element(s, tcg_tmp, destidx, element, size);
 
168
+
 
169
+    tcg_temp_free_i64(tcg_tmp);
 
170
+}
 
171
+
 
172
+/*
 
173
  * This utility function is for doing register extension with an
 
174
  * optional shift. You will likely want to pass a temporary for the
 
175
  * destination register. See DecodeRegExtend() in the ARM ARM.
 
176
@@ -1835,10 +1959,132 @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
 
177
     }
 
178
 }
 
179
 
 
180
-/* AdvSIMD load/store multiple structures */
 
181
+/* C3.3.1 AdvSIMD load/store multiple structures
 
182
+ *
 
183
+ *  31  30  29           23 22  21         16 15    12 11  10 9    5 4    0
 
184
+ * +---+---+---------------+---+-------------+--------+------+------+------+
 
185
+ * | 0 | Q | 0 0 1 1 0 0 0 | L | 0 0 0 0 0 0 | opcode | size |  Rn  |  Rt  |
 
186
+ * +---+---+---------------+---+-------------+--------+------+------+------+
 
187
+ *
 
188
+ * C3.3.2 AdvSIMD load/store multiple structures (post-indexed)
 
189
+ *
 
190
+ *  31  30  29           23 22  21  20     16 15    12 11  10 9    5 4    0
 
191
+ * +---+---+---------------+---+---+---------+--------+------+------+------+
 
192
+ * | 0 | Q | 0 0 1 1 0 0 1 | L | 0 |   Rm    | opcode | size |  Rn  |  Rt  |
 
193
+ * +---+---+---------------+---+---+---------+--------+------+------+------+
 
194
+ *
 
195
+ * Rt: first (or only) SIMD&FP register to be transferred
 
196
+ * Rn: base address or SP
 
197
+ * Rm (post-index only): post-index register (when !31) or size dependent #imm
 
198
+ */
 
199
 static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
 
200
 {
 
201
-    unsupported_encoding(s, insn);
 
202
+    int rt = extract32(insn, 0, 5);
 
203
+    int rn = extract32(insn, 5, 5);
 
204
+    int size = extract32(insn, 10, 2);
 
205
+    int opcode = extract32(insn, 12, 4);
 
206
+    bool is_store = !extract32(insn, 22, 1);
 
207
+    bool is_postidx = extract32(insn, 23, 1);
 
208
+    bool is_q = extract32(insn, 30, 1);
 
209
+    TCGv_i64 tcg_addr, tcg_rn;
 
210
+
 
211
+    int ebytes = 1 << size;
 
212
+    int elements = (is_q ? 128 : 64) / (8 << size);
 
213
+    int rpt;    /* num iterations */
 
214
+    int selem;  /* structure elements */
 
215
+    int r;
 
216
+
 
217
+    if (extract32(insn, 31, 1) || extract32(insn, 21, 1)) {
 
218
+        unallocated_encoding(s);
 
219
+        return;
 
220
+    }
 
221
+
 
222
+    /* From the shared decode logic */
 
223
+    switch (opcode) {
 
224
+    case 0x0:
 
225
+        rpt = 1;
 
226
+        selem = 4;
 
227
+        break;
 
228
+    case 0x2:
 
229
+        rpt = 4;
 
230
+        selem = 1;
 
231
+        break;
 
232
+    case 0x4:
 
233
+        rpt = 1;
 
234
+        selem = 3;
 
235
+        break;
 
236
+    case 0x6:
 
237
+        rpt = 3;
 
238
+        selem = 1;
 
239
+        break;
 
240
+    case 0x7:
 
241
+        rpt = 1;
 
242
+        selem = 1;
 
243
+        break;
 
244
+    case 0x8:
 
245
+        rpt = 1;
 
246
+        selem = 2;
 
247
+        break;
 
248
+    case 0xa:
 
249
+        rpt = 2;
 
250
+        selem = 1;
 
251
+        break;
 
252
+    default:
 
253
+        unallocated_encoding(s);
 
254
+        return;
 
255
+    }
 
256
+
 
257
+    if (size == 3 && !is_q && selem != 1) {
 
258
+        /* reserved */
 
259
+        unallocated_encoding(s);
 
260
+        return;
 
261
+    }
 
262
+
 
263
+    if (rn == 31) {
 
264
+        gen_check_sp_alignment(s);
 
265
+    }
 
266
+
 
267
+    tcg_rn = cpu_reg_sp(s, rn);
 
268
+    tcg_addr = tcg_temp_new_i64();
 
269
+    tcg_gen_mov_i64(tcg_addr, tcg_rn);
 
270
+
 
271
+    for (r = 0; r < rpt; r++) {
 
272
+        int e;
 
273
+        for (e = 0; e < elements; e++) {
 
274
+            int tt = (rt + r) % 32;
 
275
+            int xs;
 
276
+            for (xs = 0; xs < selem; xs++) {
 
277
+                if (is_store) {
 
278
+                    do_vec_st(s, tt, e, tcg_addr, size);
 
279
+                } else {
 
280
+                    do_vec_ld(s, tt, e, tcg_addr, size);
 
281
+
 
282
+                    /* For non-quad operations, setting a slice of the low
 
283
+                     * 64 bits of the register clears the high 64 bits (in
 
284
+                     * the ARM ARM pseudocode this is implicit in the fact
 
285
+                     * that 'rval' is a 64 bit wide variable). We optimize
 
286
+                     * by noticing that we only need to do this the first
 
287
+                     * time we touch a register.
 
288
+                     */
 
289
+                    if (!is_q && e == 0 && (r == 0 || xs == selem - 1)) {
 
290
+                        clear_vec_high(s, tt);
 
291
+                    }
 
292
+                }
 
293
+                tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes);
 
294
+                tt = (tt + 1) % 32;
 
295
+            }
 
296
+        }
 
297
+    }
 
298
+
 
299
+    if (is_postidx) {
 
300
+        int rm = extract32(insn, 16, 5);
 
301
+        if (rm == 31) {
 
302
+            tcg_gen_mov_i64(tcg_rn, tcg_addr);
 
303
+        } else {
 
304
+            tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
 
305
+        }
 
306
+    }
 
307
+    tcg_temp_free_i64(tcg_addr);
 
308
 }
 
309
 
 
310
 /* AdvSIMD load/store single structure */
 
311
-- 
 
312
1.9.rc1
 
313