Added assert to check inner/outer results match
[openpower-isa.git] / src / openpower / decoder / isa / test_caller_svp64_matrix.py
1 import operator
2 import unittest
3 from functools import reduce
4
5 from nmutil.formaltest import FHDLTestCase
6 from openpower.decoder.helpers import fp64toselectable
7 from openpower.decoder.isa.test_caller import run_tst
8 from openpower.decoder.selectable_int import SelectableInt
9 from openpower.simulator.program import Program
10 from openpower.insndb.asm import SVP64Asm
11
12 def setup_result_matrix(rows, cols):
13 result = []
14 for i in range(0, rows):
15 result.append([])
16 for k in range(0, cols):
17 result[-1].append(0)
18 return result
19
20 # Outer product - normal method learned at school
21 def matmult_outer(a,b):
22 # Result matrix has same number of rows as matrix a
23 # and same number of columns as matrix b
24 result = setup_result_matrix(len(a), len(b[0]))
25
26 for i in range(len(a)): # Number of rows in matrix a
27 for k in range(len(b[0])): # Number of columns in matrix b
28 # Number of columns in matrix a or rows in mat b
29 for j in range(0, len(a[0])):
30 result[i][k] += a[i][j] * b[j][k]
31
32 return result
33
34 # Inner product - slight re-arrangement to reduce stalling
35 # on cpu pipeline
36 def matmult_inner(a,b):
37 result = setup_result_matrix(len(a), len(b[0]))
38
39 for i in range(len(a)): # Number of rows in matrix a
40 # Number of columns in matrix a or rows in mat b
41 for j in range(0, len(a[0])):
42 for k in range(len(b[0])): # Number of columns in matrix b
43 result[i][k] += a[i][j] * b[j][k]
44
45 return result
46
47
48 class DecoderTestCase(FHDLTestCase):
49
50 def _check_regs(self, sim, expected):
51 for i in range(32):
52 self.assertEqual(sim.gpr(i), SelectableInt(expected[i], 64))
53
54 def test_sv_maddld_remap1(self):
55 """perform an integer matrix multiply using maddld
56 lst = ["svshape 2, 2, 3, 0, 0",
57 "svremap 31, 1, 2, 3, 0, 0, 0",
58 "sv.maddld *0, *8, *16, *0"
59 ]
60 REMAP maddld RT, RA, RB, RC
61 """
62 lst = SVP64Asm(["svshape 2, 2, 3, 0, 0",
63 "svremap 31, 1, 2, 3, 0, 0, 0",
64 "sv.maddld *0, *16, *32, *0"
65 ])
66 lst = list(lst)
67
68 gprs = [0] * 64
69 # 3x2 matrix
70 X1 = [[1, 2, 3],
71 [3, 4, 5],
72 ]
73 # 2x3 matrix
74 Y1 = [[6, 7],
75 [8, 9],
76 [10, 11],
77 ]
78
79 X = X1
80 Y = Y1
81
82
83 xf = reduce(operator.add, X)
84 yf = reduce(operator.add, Y)
85 expected = reduce(operator.add, matmult_outer(X, Y))
86 expected2 = reduce(operator.add, matmult_inner(X, Y))
87 # Check that outer/inner methods match
88 assert expected == expected2
89 print("flattened X,Y,expected (outer), expected (inner)")
90 print("\t", xf)
91 print("\t", yf)
92 print("\t", expected)
93 print("\t", expected2)
94
95 # and create a linear result2, same scheme
96 #result1 = [0] * (ydim1*xdim2)
97
98 res = []
99 # store GPR x-flattened and y-flattened in GPRs
100 for i, x in enumerate(xf):
101 gprs[i+16] = x # X matrix
102 for i, y in enumerate(yf):
103 gprs[i+32] = y # Y matrix
104
105 with Program(lst, bigendian=False) as program:
106 sim = self.run_tst_program(program, initial_regs=gprs)
107 print("spr svshape0", sim.spr['SVSHAPE0'])
108 print(" xdimsz", sim.spr['SVSHAPE0'].xdimsz)
109 print(" ydimsz", sim.spr['SVSHAPE0'].ydimsz)
110 print(" zdimsz", sim.spr['SVSHAPE0'].zdimsz)
111 print("spr svshape1", sim.spr['SVSHAPE1'])
112 print("spr svshape2", sim.spr['SVSHAPE2'])
113 print("spr svshape3", sim.spr['SVSHAPE3'])
114 results = []
115 total = len(X)*len(Y[0])
116 for i in range(total):
117 results.append(sim.gpr(i).asint())
118 for i in range(total):
119 print("maddld-matrix i", i, results[i])
120 # confirm that the results are as expected
121 self.assertEqual(results, expected)
122
123 def test_sv_remap1(self):
124 """>>> lst = ["svshape 2, 2, 3, 0, 0",
125 "svremap 31, 1, 2, 3, 0, 0, 0",
126 "sv.fmadds *0, *8, *16, *0"
127 ]
128 REMAP fmadds FRT, FRA, FRC, FRB
129 """
130 lst = SVP64Asm(["svshape 2, 2, 3, 0, 0",
131 "svremap 31, 1, 2, 3, 0, 0, 0",
132 "sv.fmadds *0, *16, *32, *0"
133 ])
134 lst = list(lst)
135
136 fprs = [0] * 64
137 # 3x2 matrix
138 X1 = [[1, 2, 3],
139 [3, 4, 5],
140 ]
141 # 2x3 matrix
142 Y1 = [[6, 7],
143 [8, 9],
144 [10, 11],
145 ]
146
147 X = X1
148 Y = Y1
149
150 xf = reduce(operator.add, X)
151 yf = reduce(operator.add, Y)
152 print("flattened X,Y")
153 print("\t", xf)
154 print("\t", yf)
155
156 # and create a linear result2, same scheme
157 #result1 = [0] * (ydim1*xdim2)
158
159 res = []
160 # store FPs
161 for i, x in enumerate(xf):
162 fprs[i+16] = fp64toselectable(float(x)) # X matrix
163 for i, y in enumerate(yf):
164 fprs[i+32] = fp64toselectable(float(y)) # Y matrix
165 continue
166 # t = DOUBLE2SINGLE(fp64toselectable(t)) # convert to Power single
167 # u = DOUBLE2SINGLE(fp64toselectable(u)) # from double
168 #res.append((t, u))
169 # print ("FFT", i, "in", a, b, "coeff", c, "mul",
170 # mul, "res", t, u)
171
172 with Program(lst, bigendian=False) as program:
173 sim = self.run_tst_program(program, initial_fprs=fprs)
174 print("spr svshape0", sim.spr['SVSHAPE0'])
175 print(" xdimsz", sim.spr['SVSHAPE0'].xdimsz)
176 print(" ydimsz", sim.spr['SVSHAPE0'].ydimsz)
177 print(" zdimsz", sim.spr['SVSHAPE0'].zdimsz)
178 print("spr svshape1", sim.spr['SVSHAPE1'])
179 print("spr svshape2", sim.spr['SVSHAPE2'])
180 print("spr svshape3", sim.spr['SVSHAPE3'])
181 for i in range(4):
182 print("ffmadds-matrix i", i, float(sim.fpr(i)))
183 # confirm that the results are as expected
184 # for i, (t, u) in enumerate(res):
185 # self.assertEqual(sim.fpr(i+2), t)
186 # self.assertEqual(sim.fpr(i+6), u)
187
188 def test_sv_remap2(self):
189 """>>> lst = ["svshape 5, 4, 3, 0, 0",
190 "svremap 31, 1, 2, 3, 0, 0, 0",
191 "sv.fmadds *0, *8, *16, *0"
192 ]
193 REMAP fmadds FRT, FRA, FRC, FRB
194 """
195 lst = SVP64Asm(["svshape 4, 3, 3, 0, 0",
196 "svremap 31, 1, 2, 3, 0, 0, 0",
197 "sv.fmadds *0, *16, *32, *0"
198 ])
199 lst = list(lst)
200
201 # 3x2 matrix
202 X1 = [[1, 2, 3],
203 [3, 4, 5],
204 ]
205 # 2x3 matrix
206 Y1 = [[6, 7],
207 [8, 9],
208 [10, 11],
209 ]
210
211 # test matrices 2
212 # 3x3 matrix
213 X2 = [[12, 7, 3],
214 [4, 5, 6],
215 [7, 8, 9],
216 ]
217 # 3x4 matrix
218 Y2 = [[5, 8, 1, 2],
219 [6, 7, 3, 0],
220 [4, 5, 9, 1]]
221
222 # test matrices 3
223 # 3x4 matrix
224 X3 = [[12, 7, 3],
225 [4, 5, 6],
226 [7, 8, 9],
227 [2, 0, 1]]
228 # 5x3 matrix
229 Y3 = [[5, 8, 1, 2, 3],
230 [6, 7, 3, 0, 9],
231 [4, 5, 9, 1, 2]]
232
233 X = X2
234 Y = Y2
235
236 # get the dimensions of the 2 matrices
237 xdim1 = len(X[0])
238 ydim1 = len(X)
239 xdim2 = len(Y[0])
240 ydim2 = len(Y)
241
242 print("xdim2 ydim1 ydim2", xdim2, ydim1, ydim2)
243
244 xf = reduce(operator.add, X)
245 yf = reduce(operator.add, Y)
246 print("flattened X,Y")
247 print("\t", xf)
248 print("\t", yf)
249
250 # and create a linear result2, same scheme
251 #result1 = [0] * (ydim1*xdim2)
252
253 res = []
254 # store FPs
255 fprs = [0] * 64
256 for i, x in enumerate(xf):
257 fprs[i+16] = fp64toselectable(float(x)) # X matrix
258 for i, y in enumerate(yf):
259 fprs[i+32] = fp64toselectable(float(y)) # Y matrix
260 continue
261 # t = DOUBLE2SINGLE(fp64toselectable(t)) # convert to Power single
262 # u = DOUBLE2SINGLE(fp64toselectable(u)) # from double
263 #res.append((t, u))
264 # print ("FFT", i, "in", a, b, "coeff", c, "mul",
265 # mul, "res", t, u)
266
267 with Program(lst, bigendian=False) as program:
268 sim = self.run_tst_program(program, initial_fprs=fprs)
269 print("spr svshape0", sim.spr['SVSHAPE0'])
270 print(" xdimsz", sim.spr['SVSHAPE0'].xdimsz)
271 print(" ydimsz", sim.spr['SVSHAPE0'].ydimsz)
272 print(" zdimsz", sim.spr['SVSHAPE0'].zdimsz)
273 print("spr svshape1", sim.spr['SVSHAPE1'])
274 print("spr svshape2", sim.spr['SVSHAPE2'])
275 print("spr svshape3", sim.spr['SVSHAPE3'])
276 for i in range(16):
277 print("i", i, float(sim.fpr(i)))
278 # confirm that the results are as expected
279 # for i, (t, u) in enumerate(res):
280 # self.assertEqual(sim.fpr(i+2), t)
281 # self.assertEqual(sim.fpr(i+6), u)
282
283 def test_sv_remap3_horizontal_or(self):
284 """>>> lst = ["svshape 3, 2, 1, 0, 0",
285 "svremap 31, 1, 3, 1, 1, 1, 0",
286 "sv.or *0, *0, *6"
287 ]
288 REMAP horizontal-or using "or RA,RS,RB"
289 same trick can be applied to do horizontal-add
290 or horizontal-multiply. just remember for multiply
291 to pre-load 1 (1.0) into the results first (or any other
292 scaling factor).
293
294 sv.or is horribly obscure because RA (the destination)
295 actually gets treated as RT by the REMAP subsystem.
296
297 The purpose here is to demonstrate a horizontal mapreduce
298 by using/abusing Matrix REMAP (ignoring the B-Matrix entirely)
299
300 if data is laid out in R G B R G B R G B format and
301 comprises tuples (R<<16 G<<8 B<<0) then a horizontal-or
302 may reduce down to (R<<16) | (G<<8> | (B<<0) on a per-row
303 basis.
304 """
305 # 3x4 matrix of data to be ORed together by row.
306 # Add any number of extra rows (up to 6) here (6 because sv.or *0,*0,*6)
307 X1 = [[0x1, 0x10, 0x100], # 0x111
308 [0x2, 0x40, 0x300], # 0x342
309 [0x9, 0x70, 0x800], # 0x879
310 [0x3, 0x71, 0x460], # overlaps (still ORed) - 0x473
311 ]
312
313 # get the dimensions of the array
314 xdim1 = len(X1[0])
315 ydim1 = len(X1)
316
317 lst = SVP64Asm(["svshape %d, %d, 1, 0, 0" % (xdim1, ydim1),
318 # also works:
319 # "svremap 31, 3, 0, 3, 1, 2, 0",
320 # "sv.ternlogi *12, *0, *6, 250" # 0b11111110
321 "svremap 31, 1, 3, 1, 1, 1, 0",
322 "sv.or *0, *0, *6"
323 ])
324 lst = list(lst)
325
326 print("xdim1, ydim1", xdim1, ydim1)
327
328 expected = [0] * ydim1
329 for i, row in enumerate(X1):
330 expected[i] = reduce(operator.or_, row)
331 print("\texpected ORed", hex(expected[i]))
332 xf = reduce(operator.add, X1)
333 print("flattened X")
334 print("\t", xf)
335
336 res = []
337 # store FPs
338 gprs = [0] * 64
339 for i, x in enumerate(xf):
340 gprs[i+6] = x
341
342 with Program(lst, bigendian=False) as program:
343 sim = self.run_tst_program(program, gprs)
344 print("spr svshape0", sim.spr['SVSHAPE0'])
345 print(" xdimsz", sim.spr['SVSHAPE0'].xdimsz)
346 print(" ydimsz", sim.spr['SVSHAPE0'].ydimsz)
347 print(" zdimsz", sim.spr['SVSHAPE0'].zdimsz)
348 print("spr svshape1", sim.spr['SVSHAPE1'])
349 print("spr svshape2", sim.spr['SVSHAPE2'])
350 print("spr svshape3", sim.spr['SVSHAPE3'])
351 for i in range(ydim1):
352 print("i", i, sim.gpr(0+i), hex(expected[i]))
353 for i in range(ydim1):
354 self.assertEqual(sim.gpr(0+i), SelectableInt(expected[i], 64))
355
356 def run_tst_program(self, prog, initial_regs=None,
357 svstate=None,
358 initial_mem=None,
359 initial_fprs=None):
360 if initial_regs is None:
361 initial_regs = [0] * 32
362 simulator = run_tst(prog, initial_regs, mem=initial_mem,
363 initial_fprs=initial_fprs,
364 svstate=svstate)
365
366 print("GPRs")
367 simulator.gpr.dump()
368 print("FPRs")
369 simulator.fpr.dump()
370
371 return simulator
372
373
374 if __name__ == "__main__":
375 unittest.main()