1 /*
  2  * Copyright (c) 2025-2026, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package hat.test;
 26 
 27 import hat.Accelerator;
 28 import hat.ComputeContext;
 29 import hat.NDRange;
 30 import hat.backend.Backend;
 31 import hat.buffer.BF16Array;
 32 import hat.device.DeviceSchema;
 33 import hat.device.NonMappableIface;
 34 import hat.test.annotation.HatTest;
 35 import hat.test.exceptions.HATAssertionError;
 36 import hat.test.exceptions.HATAsserts;
 37 import hat.test.exceptions.HATExpectedPrecisionError;
 38 import hat.types.BF16;
 39 import jdk.incubator.code.Reflect;
 40 
 41 import java.lang.invoke.MethodHandles;
 42 import java.util.Random;
 43 
 44 import static hat.KernelContext.GIX;
 45 import static hat.KernelContext.GSX;
 46 import static hat.KernelContext.LIX;
 47 import static hat.KernelContext.barrier;
 48 
 49 public class TestBFloat16Type {
 50 
 51     @Reflect
 52     public static void kernelCopy(BF16Array a, BF16Array b) {
 53         if (GIX() < GSX()) {
 54             BF16 ha = a.array(GIX());
 55             b.array(GIX()).value(ha.value());
 56         }
 57     }
 58 
 59     @Reflect
 60     public static void bf16_02(BF16Array a, BF16Array b, BF16Array c) {
 61         if (GIX() < GSX()) {
 62             BF16 ha = a.array(GIX());
 63             BF16 hb = b.array(GIX());
 64             BF16 result = BF16.add(ha, hb);
 65             BF16 hc = c.array(GIX());
 66             hc.value(result.value());
 67         }
 68     }
 69 
 70     @Reflect
 71     public static void bf16_03(BF16Array a, BF16Array b, BF16Array c) {
 72         if (GIX() < GSX()) {
 73             BF16 ha = a.array(GIX());
 74             BF16 hb = b.array(GIX());
 75 
 76             BF16 result = BF16.add(ha, BF16.add(hb, hb));
 77             BF16 hC = c.array(GIX());
 78             hC.value(result.value());
 79         }
 80     }
 81 
 82     @Reflect
 83     public static void bf16_04(BF16Array a, BF16Array b, BF16Array c) {
 84         if (GIX() < GSX()) {
 85             BF16 ha = a.array(GIX());
 86             BF16 hb = b.array(GIX());
 87 
 88             BF16 r1 = BF16.mul(ha, hb);
 89             BF16 r2 = BF16.div(ha, hb);
 90             BF16 r3 = BF16.sub(ha, hb);
 91             BF16 r4 = BF16.add(r1, r2);
 92             BF16 r5 = BF16.add(r4, r3);
 93             BF16 hC = c.array(GIX());
 94             hC.value(r5.value());
 95         }
 96     }
 97 
 98     @Reflect
 99     public static void bf16_05(BF16Array a) {
100         if (GIX() < GSX()) {
101             BF16 ha = a.array(GIX());
102             BF16 initVal = BF16.of(2.1f);
103             ha.value(initVal.value());
104         }
105     }
106 
107     @Reflect
108     public static void bf16_06(BF16Array a) {
109         if (GIX() < GSX()) {
110             BF16 initVal = BF16.of(GIX());
111             BF16 ha = a.array(GIX());
112             ha.value(initVal.value());
113         }
114     }
115 
116     @Reflect
117     public static void bf16_08(BF16Array a) {
118         if (GIX() < GSX()) {
119             BF16 initVal = BF16.float2bfloat16(GIX());
120             BF16 ha = a.array(GIX());
121             ha.value(initVal.value());
122         }
123     }
124 
125     @Reflect
126     public static void bf16_09(BF16Array a, BF16Array b) {
127         if (GIX() < GSX()) {
128             BF16 ha = a.array(GIX());
129             float f = BF16.bfloat162float(ha);
130             BF16 result = BF16.float2bfloat16(f);
131             BF16 hb = b.array(GIX());
132             hb.value(result.value());
133         }
134     }
135 
136     @Reflect
137     public static void bf16_10(BF16Array a) {
138         if (GIX() < GSX()) {
139             BF16 ha = a.array(GIX());
140             BF16 f16 = BF16.of(1.1f);
141             float f = BF16.bfloat162float(f16);
142             BF16 result = BF16.float2bfloat16(f);
143             ha.value(result.value());
144         }
145     }
146 
147     public interface LocalArray extends NonMappableIface {
148         BF16 array(int index);
149 
150         DeviceSchema<LocalArray> deviceSchema = DeviceSchema.of(LocalArray.class,
151                 builder -> builder.array("array", 1024,
152                         bfloat16 -> bfloat16.field("value")));
153 
154         static LocalArray createLocal() {
155             return null;
156         }
157     }
158 
159     @Reflect
160     public static void bf16_11(BF16Array a, BF16Array b) {
161         LocalArray sm = LocalArray.createLocal();
162         if (GIX() < GSX()) {
163             int lix = LIX();
164             BF16 ha = a.array(GIX());
165 
166             sm.array(lix).value(ha.value());
167             barrier();
168 
169             BF16 hb = sm.array(lix);
170             b.array(GIX()).value(hb.value());
171         }
172     }
173 
174     @Reflect
175     public static void bf16_12(BF16Array a, BF16Array b, BF16Array c) {
176         // Test the fluent API style
177         if (GIX() < GSX()) {
178             BF16 ha = a.array(GIX());
179             BF16 hb = b.array(GIX());
180             BF16 result = BF16.add(ha, hb);
181             c.array(GIX()).value(result.value());
182         }
183     }
184 
185     @Reflect
186     public static void bf16_13(BF16Array a, BF16Array b, BF16Array c) {
187         // Test the fluent API style
188         if (GIX() < GSX()) {
189             BF16 ha = a.array(GIX());
190             BF16 hb = b.array(GIX());
191             BF16 result = BF16.div(BF16.mul(BF16.sub(BF16.add(ha, hb), hb), ha), ha);
192             c.array(GIX()).value(result.value());
193         }
194     }
195 
196     @Reflect
197     public static void bf16_14(BF16Array a, BF16Array b) {
198         // Testing mixed float types
199         if (GIX() < GSX()) {
200             BF16 ha = a.array(GIX());
201             float myFloat = 32.1f;
202             BF16 result = BF16.add(myFloat, ha);
203             b.array(GIX()).value(result.value());
204         }
205     }
206 
207     public interface PrivateArray extends NonMappableIface {
208         BF16 array(int index);
209 
210         DeviceSchema<PrivateArray> deviceSchema = DeviceSchema.of(PrivateArray.class,
211                 builder -> builder.array("array", 256, bfloat16 -> bfloat16.field("value")));
212         static PrivateArray createPrivate() {
213             return null;
214         }
215     }
216 
217     @Reflect
218     public static void bf16_15(BF16Array a, BF16Array b) {
219         PrivateArray privateArray = PrivateArray.createPrivate();
220         if (GIX() < GSX()) {
221             int lix = LIX();
222             BF16 ha = a.array(GIX());
223             privateArray.array(lix).value(ha.value());
224             BF16 hb = privateArray.array(lix);
225             b.array(GIX()).value(hb.value());
226         }
227     }
228 
229     @Reflect
230     public static void bf16_16(BF16Array a) {
231         BF16 ha = a.array(0);
232         BF16 hre = BF16.add(ha, ha);
233         hre = BF16.add(hre, hre);
234         a.array(0).value(hre.value());
235     }
236 
237     @Reflect
238     public static void bf16_17(BF16Array a) {
239 
240         BF16 ha = a.array(0);
241         PrivateArray privateArray = PrivateArray.createPrivate();
242         privateArray.array(0).value(ha.value());
243 
244         // Obtain the value from private memory
245         BF16 acc = privateArray.array(0);
246 
247         // compute
248         acc = BF16.add(acc, acc);
249 
250         // store the result
251         a.array(0).value(acc.value());
252     }
253 
254     @Reflect
255     public static void compute01(ComputeContext computeContext, BF16Array a, BF16Array b) {
256         computeContext.dispatchKernel(NDRange.of1D(a.length()), () -> TestBFloat16Type.kernelCopy(a, b));
257     }
258 
259     @Reflect
260     public static void compute02(ComputeContext computeContext, BF16Array a, BF16Array b, BF16Array c) {
261         computeContext.dispatchKernel(NDRange.of1D(a.length()),
262                 () -> TestBFloat16Type.bf16_02(a, b, c));
263     }
264 
265     @Reflect
266     public static void compute03(ComputeContext computeContext, BF16Array a, BF16Array b, BF16Array c) {
267         computeContext.dispatchKernel(NDRange.of1D(a.length()),
268                 () -> TestBFloat16Type.bf16_03(a, b, c));
269     }
270 
271     @Reflect
272     public static void compute04(ComputeContext computeContext, BF16Array a, BF16Array b, BF16Array c) {
273         computeContext.dispatchKernel(NDRange.of1D(a.length()),
274                 () -> TestBFloat16Type.bf16_04(a, b, c));
275     }
276 
277     @Reflect
278     public static void compute05(ComputeContext computeContext, BF16Array a) {
279         computeContext.dispatchKernel(NDRange.of1D(a.length()), () -> TestBFloat16Type.bf16_05(a));
280     }
281 
282     @Reflect
283     public static void compute06(ComputeContext computeContext, BF16Array a) {
284         computeContext.dispatchKernel(NDRange.of1D(a.length()), () -> TestBFloat16Type.bf16_06(a));
285     }
286 
287     @Reflect
288     public static void compute08(ComputeContext computeContext, BF16Array a) {
289         computeContext.dispatchKernel(NDRange.of1D(a.length()), () -> TestBFloat16Type.bf16_08(a));
290     }
291 
292     @Reflect
293     public static void compute09(ComputeContext computeContext, BF16Array a, BF16Array b) {
294         computeContext.dispatchKernel(NDRange.of1D(a.length()), () -> TestBFloat16Type.bf16_09(a, b));
295     }
296 
297     @Reflect
298     public static void compute10(ComputeContext computeContext, BF16Array a) {
299         computeContext.dispatchKernel(NDRange.of1D(a.length()), () -> TestBFloat16Type.bf16_10(a));
300     }
301 
302     @Reflect
303     public static void compute11(ComputeContext computeContext, BF16Array a, BF16Array b) {
304         computeContext.dispatchKernel(NDRange.of1D(a.length(), 16), () -> TestBFloat16Type.bf16_11(a, b));
305     }
306 
307     @Reflect
308     public static void compute12(ComputeContext computeContext, BF16Array a, BF16Array b, BF16Array c) {
309         computeContext.dispatchKernel(NDRange.of1D(a.length()), () -> TestBFloat16Type.bf16_12(a, b, c));
310     }
311 
312     @Reflect
313     public static void compute13(ComputeContext computeContext, BF16Array a, BF16Array b, BF16Array c) {
314         computeContext.dispatchKernel(NDRange.of1D(a.length()), () -> TestBFloat16Type.bf16_13(a, b, c));
315     }
316 
317     @Reflect
318     public static void compute14(ComputeContext computeContext, BF16Array a, BF16Array b) {
319         computeContext.dispatchKernel(NDRange.of1D(a.length()), () -> TestBFloat16Type.bf16_14(a, b));
320     }
321 
322     @Reflect
323     public static void compute15(ComputeContext computeContext, BF16Array a, BF16Array b) {
324         computeContext.dispatchKernel(NDRange.of1D(a.length()), () -> TestBFloat16Type.bf16_15(a, b));
325     }
326 
327     @Reflect
328     public static void compute16(ComputeContext computeContext, BF16Array a) {
329         computeContext.dispatchKernel(NDRange.of1D(1), () -> TestBFloat16Type.bf16_16(a));
330     }
331 
332     @Reflect
333     public static void compute17(ComputeContext computeContext, BF16Array a) {
334         computeContext.dispatchKernel(NDRange.of1D(1), () -> TestBFloat16Type.bf16_17(a));
335     }
336 
337     @HatTest
338     @Reflect
339     public void test_bfloat16_01() {
340         final int size = 256;
341         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
342 
343         BF16Array arrayA = BF16Array.create(accelerator, size);
344         BF16Array arrayB = BF16Array.create(accelerator, size);
345         for (int i = 0; i < size; i++) {
346             arrayA.array(i).value(BF16.float2bfloat16(i).value());
347         }
348 
349         accelerator.compute(computeContext -> TestBFloat16Type.compute01(computeContext, arrayA, arrayB));
350 
351         for (int i = 0; i < size; i++) {
352             BF16 result = arrayB.array(i);
353             HATAsserts.assertEquals((float) i, BF16.bfloat162float(result), 0.001f);
354         }
355     }
356 
357     @HatTest
358     @Reflect
359     public void test_bfloat16_02() {
360         final int size = 256;
361         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
362 
363         BF16Array arrayA = BF16Array.create(accelerator, size);
364         BF16Array arrayB = BF16Array.create(accelerator, size);
365         BF16Array arrayC = BF16Array.create(accelerator, size);
366 
367         Random r = new Random(19);
368         for (int i = 0; i < size; i++) {
369             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
370             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
371         }
372 
373         accelerator.compute(computeContext -> TestBFloat16Type.compute02(computeContext, arrayA, arrayB, arrayC));
374 
375         for (int i = 0; i < size; i++) {
376             BF16 result = arrayC.array(i);
377             BF16 a = arrayA.array(i);
378             BF16 b = arrayB.array(i);
379             float res = BF16.bfloat162float(a) + BF16.bfloat162float(b);
380             HATAsserts.assertEquals(res, BF16.bfloat162float(result), 0.001f);
381         }
382     }
383 
384     @HatTest
385     @Reflect
386     public void test_bfloat16_03() {
387         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
388 
389         final int size = 256;
390         BF16Array arrayA = BF16Array.create(accelerator, size);
391         BF16Array arrayB = BF16Array.create(accelerator, size);
392         BF16Array arrayC = BF16Array.create(accelerator, size);
393 
394         Random random = new Random();
395         for (int i = 0; i < arrayA.length(); i++) {
396             arrayA.array(i).value(BF16.float2bfloat16(random.nextFloat()).value());
397             arrayB.array(i).value(BF16.float2bfloat16(random.nextFloat()).value());
398         }
399 
400         accelerator.compute(computeContext -> TestBFloat16Type.compute03(computeContext, arrayA, arrayB, arrayC));
401 
402         for (int i = 0; i < arrayC.length(); i++) {
403             BF16 val = arrayC.array(i);
404             float fa = BF16.bfloat162float(arrayA.array(i));
405             float fb = BF16.bfloat162float(arrayB.array(i));
406             HATAsserts.assertEquals((fa + fb + fb), BF16.bfloat162float(val), 0.01f);
407         }
408     }
409 
410     @HatTest
411     @Reflect
412     public void test_bfloat16_04() {
413         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
414 
415         final int size = 256;
416         BF16Array arrayA = BF16Array.create(accelerator, size);
417         BF16Array arrayB = BF16Array.create(accelerator, size);
418         BF16Array arrayC = BF16Array.create(accelerator, size);
419 
420         Random random = new Random();
421         for (int i = 0; i < arrayA.length(); i++) {
422             arrayA.array(i).value(BF16.float2bfloat16(random.nextFloat()).value());
423             arrayB.array(i).value(BF16.float2bfloat16(random.nextFloat()).value());
424         }
425 
426         accelerator.compute(computeContext -> {
427             TestBFloat16Type.compute04(computeContext, arrayA, arrayB, arrayC);
428         });
429 
430         for (int i = 0; i < arrayC.length(); i++) {
431             BF16 gotResult = arrayC.array(i);
432 
433             // CPU Computation
434             BF16 ha = arrayA.array(i);
435             BF16 hb = arrayB.array(i);
436             BF16 r1 = BF16.mul(ha, hb);
437             BF16 r2 = BF16.div(ha, hb);
438             BF16 r3 = BF16.sub(ha, hb);
439             BF16 r4 = BF16.add(r1, r2);
440             BF16 r5 = BF16.add(r4, r3);
441 
442             HATAsserts.assertEquals(BF16.bfloat162float(r5), BF16.bfloat162float(gotResult), 0.01f);
443         }
444     }
445 
446     @HatTest
447     @Reflect
448     public void test_bfloat16_05() {
449         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
450 
451         final int size = 16;
452         BF16Array arrayA = BF16Array.create(accelerator, size);
453         for (int i = 0; i < arrayA.length(); i++) {
454             arrayA.array(i).value(BF16.float2bfloat16(0.0f).value());
455         }
456 
457         accelerator.compute(computeContext -> {
458             TestBFloat16Type.compute05(computeContext, arrayA);
459         });
460 
461         for (int i = 0; i < arrayA.length(); i++) {
462             BF16 val = arrayA.array(i);
463             HATAsserts.assertEquals(2.1f, BF16.bfloat162float(val), 0.01f);
464         }
465     }
466 
467     @HatTest
468     @Reflect
469     public void test_bfloat16_06() {
470         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
471 
472         final int size = 512;
473         BF16Array arrayA = BF16Array.create(accelerator, size);
474         for (int i = 0; i < arrayA.length(); i++) {
475             arrayA.array(i).value(BF16.float2bfloat16(0.0f).value());
476         }
477 
478         accelerator.compute(computeContext -> TestBFloat16Type.compute06(computeContext, arrayA));
479 
480         for (int i = 0; i < arrayA.length(); i++) {
481             BF16 val = arrayA.array(i);
482             try {
483                 HATAsserts.assertEquals(BF16.bfloat162float(BF16.float2bfloat16(i)), BF16.bfloat162float(val), 0.01f);
484             } catch (HATAssertionError hatAssertionError) {
485                 throw new HATExpectedPrecisionError(hatAssertionError.getMessage());
486             }
487 
488         }
489     }
490 
491     @HatTest
492     @Reflect
493     public void test_bfloat16_07() {
494         // Test CPU Implementation of BF16
495         BF16 a = BF16.of(2.5f);
496         BF16 b = BF16.of(3.5f);
497         BF16 c = BF16.add(a, b);
498         HATAsserts.assertEquals((2.5f + 3.5f), BF16.bfloat162float(c), 0.01f);
499 
500         BF16 d = BF16.sub(a, b);
501         HATAsserts.assertEquals((2.5f - 3.5f), BF16.bfloat162float(d), 0.01f);
502 
503         BF16 e = BF16.mul(a, b);
504         HATAsserts.assertEquals((2.5f * 3.5f), BF16.bfloat162float(e), 0.01f);
505 
506         BF16 f = BF16.div(a, b);
507         HATAsserts.assertEquals((2.5f / 3.5f), BF16.bfloat162float(f), 0.01f);
508     }
509 
510     @HatTest
511     @Reflect
512     public void test_bfloat16_08() {
513         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
514 
515         final int size = 256;
516         BF16Array arrayA = BF16Array.create(accelerator, size);
517         for (int i = 0; i < arrayA.length(); i++) {
518             arrayA.array(i).value(BF16.float2bfloat16(0.0f).value());
519         }
520 
521         accelerator.compute(computeContext -> {
522             TestBFloat16Type.compute08(computeContext, arrayA);
523         });
524 
525         for (int i = 0; i < arrayA.length(); i++) {
526             BF16 val = arrayA.array(i);
527             HATAsserts.assertEquals(i, BF16.bfloat162float(val), 0.01f);
528         }
529     }
530 
531     @HatTest
532     @Reflect
533     public void test_bfloat16_09() {
534         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
535 
536         final int size = 16;
537         BF16Array arrayA = BF16Array.create(accelerator, size);
538         BF16Array arrayB = BF16Array.create(accelerator, size);
539 
540         Random r = new Random(73);
541         for (int i = 0; i < arrayA.length(); i++) {
542             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
543         }
544 
545         accelerator.compute(computeContext -> TestBFloat16Type.compute09(computeContext, arrayA, arrayB));
546 
547         for (int i = 0; i < arrayB.length(); i++) {
548             BF16 val = arrayB.array(i);
549             HATAsserts.assertEquals(BF16.bfloat162float(arrayA.array(i)), BF16.bfloat162float(val), 0.01f);
550         }
551     }
552 
553     @HatTest
554     @Reflect
555     public void test_bfloat16_10() {
556         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
557         final int size = 256;
558         BF16Array arrayA = BF16Array.create(accelerator, size);
559 
560         accelerator.compute(computeContext -> TestBFloat16Type.compute10(computeContext, arrayA));
561 
562         for (int i = 0; i < arrayA.length(); i++) {
563             BF16 val = arrayA.array(i);
564             HATAsserts.assertEquals(1.1f, BF16.bfloat162float(val), 0.01f);
565         }
566     }
567 
568     @HatTest
569     @Reflect
570     public void test_bfloat16_11() {
571         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
572         final int size = 256;
573         BF16Array arrayA = BF16Array.create(accelerator, size);
574         BF16Array arrayB = BF16Array.create(accelerator, size);
575 
576         Random r = new Random(73);
577         for (int i = 0; i < arrayA.length(); i++) {
578             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
579         }
580 
581         accelerator.compute(computeContext -> TestBFloat16Type.compute11(computeContext, arrayA, arrayB));
582 
583         for (int i = 0; i < arrayB.length(); i++) {
584             BF16 val = arrayB.array(i);
585             HATAsserts.assertEquals(arrayA.array(i).value(), val.value());
586         }
587     }
588 
589     @HatTest
590     @Reflect
591     public void test_bfloat16_12() {
592         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
593         final int size = 1024;
594         BF16Array arrayA = BF16Array.create(accelerator, size);
595         BF16Array arrayB = BF16Array.create(accelerator, size);
596         BF16Array arrayC = BF16Array.create(accelerator, size);
597 
598         Random r = new Random(73);
599         for (int i = 0; i < arrayA.length(); i++) {
600             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
601             arrayB.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
602         }
603 
604         accelerator.compute(computeContext -> TestBFloat16Type.compute12(computeContext, arrayA, arrayB, arrayC));
605 
606         for (int i = 0; i < arrayB.length(); i++) {
607             BF16 result = arrayC.array(i);
608             HATAsserts.assertEquals(BF16.bfloat162float(BF16.add(arrayA.array(i), arrayB.array(i))), BF16.bfloat162float(result), 0.01f);
609         }
610     }
611 
612     @HatTest
613     @Reflect
614     public void test_bfloat16_13() {
615         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
616         final int size = 1024;
617         BF16Array arrayA = BF16Array.create(accelerator, size);
618         BF16Array arrayB = BF16Array.create(accelerator, size);
619         BF16Array arrayC = BF16Array.create(accelerator, size);
620 
621         Random r = new Random(73);
622         for (int i = 0; i < arrayA.length(); i++) {
623             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
624             arrayB.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
625         }
626 
627         accelerator.compute(computeContext -> TestBFloat16Type.compute13(computeContext, arrayA, arrayB, arrayC));
628 
629         for (int i = 0; i < arrayB.length(); i++) {
630             BF16 result = arrayC.array(i);
631             HATAsserts.assertEquals(BF16.bfloat162float(arrayA.array(i)), BF16.bfloat162float(result), 0.01f);
632         }
633     }
634 
635     @HatTest
636     @Reflect
637     public void test_bfloat16_14() {
638         // Testing mixed types
639         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
640         final int size = 1024;
641         BF16Array arrayA = BF16Array.create(accelerator, size);
642         BF16Array arrayB = BF16Array.create(accelerator, size);
643 
644         Random r = new Random(73);
645         for (int i = 0; i < arrayA.length(); i++) {
646             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
647         }
648 
649         accelerator.compute(computeContext -> TestBFloat16Type.compute14(computeContext, arrayA, arrayB));
650 
651         for (int i = 0; i < arrayB.length(); i++) {
652             BF16 result = arrayB.array(i);
653             BF16 sum = BF16.add(arrayA.array(i), BF16.float2bfloat16(32.1f));
654             try {
655                 HATAsserts.assertEquals(BF16.bfloat162float(sum), BF16.bfloat162float(result), 0.1f);
656             } catch (HATAssertionError hatAssertionError) {
657                 throw new HATExpectedPrecisionError(hatAssertionError.getMessage());
658             }
659         }
660     }
661 
662     @HatTest
663     @Reflect
664     public void test_bfloat16_15() {
665         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
666         final int size = 256;
667         BF16Array arrayA = BF16Array.create(accelerator, size);
668         BF16Array arrayB = BF16Array.create(accelerator, size);
669 
670         Random r = new Random(73);
671         for (int i = 0; i < arrayA.length(); i++) {
672             arrayA.array(i).value(BF16.float2bfloat16(r.nextFloat()).value());
673         }
674 
675         accelerator.compute(computeContext -> TestBFloat16Type.compute15(computeContext, arrayA, arrayB));
676 
677         for (int i = 0; i < arrayB.length(); i++) {
678             BF16 val = arrayB.array(i);
679             HATAsserts.assertEquals(arrayA.array(i).value(), val.value());
680         }
681     }
682 
683     // Check accumulators
684     @HatTest
685     @Reflect
686     public void test_bfloat16_16() {
687         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
688         final int size = 1;
689         BF16Array arrayA = BF16Array.create(accelerator, size);
690 
691         arrayA.array(0).value(BF16.float2bfloat16(10).value());
692 
693         accelerator.compute(computeContext -> TestBFloat16Type.compute16(computeContext, arrayA));
694 
695         BF16 val = arrayA.array(0);
696         HATAsserts.assertEquals(40.0f, BF16.bfloat162float(val), 0.01f);
697     }
698 
699     // Check accumulators in private memory
700     @HatTest
701     @Reflect
702     public void test_bfloat16_17() {
703         var accelerator = new Accelerator(MethodHandles.lookup(), Backend.FIRST);
704         final int size = 1;
705         BF16Array arrayA = BF16Array.create(accelerator, size);
706 
707         Random r = new Random(73);
708         arrayA.array(0).value(BF16.float2bfloat16(10).value());
709 
710         accelerator.compute(computeContext -> TestBFloat16Type.compute17(computeContext, arrayA));
711 
712         BF16 val = arrayA.array(0);
713         HATAsserts.assertEquals(20.0f, BF16.bfloat162float(val), 0.01f);
714     }
715 
716 }