1 /*
  2  * Copyright (c) 2022, 2023, Arm Limited. All rights reserved.
  3  * Copyright (c) 2024, 2026, Oracle and/or its affiliates. All rights reserved.
  4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  5  *
  6  * This code is free software; you can redistribute it and/or modify it
  7  * under the terms of the GNU General Public License version 2 only, as
  8  * published by the Free Software Foundation.
  9  *
 10  * This code is distributed in the hope that it will be useful, but WITHOUT
 11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 13  * version 2 for more details (a copy is included in the LICENSE file that
 14  * accompanied this code).
 15  *
 16  * You should have received a copy of the GNU General Public License version
 17  * 2 along with this work; if not, write to the Free Software Foundation,
 18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 19  *
 20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 21  * or visit www.oracle.com if you need additional information or have any
 22  * questions.
 23  */
 24 
 25 /*
 26  * @test
 27  * @bug 8183390 8340010 8342095
 28  * @summary Vectorization test on array type conversions
 29  * @library /test/lib /
 30  *
 31  * @build jdk.test.whitebox.WhiteBox
 32  *        compiler.vectorization.runner.VectorizationTestRunner
 33  *
 34  * @requires vm.compiler2.enabled
 35  *
 36  * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
 37  *
 38  * @run main/othervm -Xbootclasspath/a:.
 39  *                   -XX:+UnlockDiagnosticVMOptions
 40  *                   -XX:+WhiteBoxAPI
 41  *                   compiler.vectorization.runner.ArrayTypeConvertTest nCOH_nAV
 42  *
 43  * @run main/othervm -Xbootclasspath/a:.
 44  *                   -XX:+UnlockDiagnosticVMOptions
 45  *                   -XX:+WhiteBoxAPI
 46  *                   compiler.vectorization.runner.ArrayTypeConvertTest nCOH_yAV
 47  *
 48  * @run main/othervm -Xbootclasspath/a:.
 49  *                   -XX:+UnlockDiagnosticVMOptions
 50  *                   -XX:+WhiteBoxAPI
 51  *                   compiler.vectorization.runner.ArrayTypeConvertTest yCOH_nAV
 52  *
 53  * @run main/othervm -Xbootclasspath/a:.
 54  *                   -XX:+UnlockDiagnosticVMOptions
 55  *                   -XX:+WhiteBoxAPI
 56  *                   compiler.vectorization.runner.ArrayTypeConvertTest yCOH_yAV
 57  */
 58 
 59 package compiler.vectorization.runner;
 60 
 61 import compiler.lib.ir_framework.*;
 62 
 63 // Explanation about AlignVector: we require 8-byte alignment of all addresses.
 64 // But the array base offset changes with UseCompactObjectHeaders.
 65 // This means it affects the alignment constraints.
 66 
 67 public class ArrayTypeConvertTest extends VectorizationTestRunner {
 68 
 69     // We must pass the flags directly to the test-VM, and not the driver vm in the @run above.
 70     @Override
 71     protected String[] testVMFlags(String[] args) {
 72         return switch (args[0]) {
 73             case "nCOH_nAV" -> new String[]{"-XX:-UseCompactObjectHeaders", "-XX:-AlignVector"};
 74             case "nCOH_yAV" -> new String[]{"-XX:-UseCompactObjectHeaders", "-XX:+AlignVector"};
 75             case "yCOH_nAV" -> new String[]{"-XX:+UseCompactObjectHeaders", "-XX:-AlignVector"};
 76             case "yCOH_yAV" -> new String[]{"-XX:+UseCompactObjectHeaders", "-XX:+AlignVector"};
 77             default -> { throw new RuntimeException("Test argument not recognized: " + args[0]); }
 78         };
 79     }
 80 
 81     private static final int SIZE = 543;
 82 
 83     private   byte[] bytes;
 84     private  short[] shorts;
 85     private   char[] chars;
 86     private    int[] ints;
 87     private   long[] longs;
 88     private  float[] floats;
 89     private double[] doubles;
 90 
 91     public ArrayTypeConvertTest() {
 92         bytes   = new   byte[SIZE];
 93         shorts  = new  short[SIZE];
 94         chars   = new   char[SIZE];
 95         ints    = new    int[SIZE];
 96         longs   = new   long[SIZE];
 97         floats  = new  float[SIZE];
 98         doubles = new double[SIZE];
 99         for (int i = 0; i < SIZE; i++) {
100             bytes[i]   = (byte)  (-i / 128);
101             shorts[i]  = (short) (i / 3 - 12345);
102             chars[i]   = (char)  (i * 2);
103             ints[i]    = -22 * i;
104             longs[i]   = -258L * i + 99L;
105             floats[i]  = (float) (i * 2.498f);
106             doubles[i] = -3 * i;
107         }
108     }
109 
110     // ---------------- Integer Extension ----------------
111     @Test
112     @IR(applyIfCPUFeature = { "avx", "true" },
113         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
114         counts = { IRNode.VECTOR_CAST_S2I, IRNode.VECTOR_SIZE + "min(max_int, max_short)", ">0" })
115     public int[] signExtension() {
116         int[] res = new int[SIZE];
117         for (int i = 0; i < SIZE; i++) {
118             res[i] = shorts[i];
119         }
120         return res;
121     }
122 
123     @Test
124     @IR(failOn = {IRNode.STORE_VECTOR})
125     // Subword vector casts with char do not work currently, see JDK-8349562.
126     // Assert the vectorization failure so that we are reminded to update
127     // the test when this limitation is addressed in the future.
128     public int[] zeroExtension() {
129         int[] res = new int[SIZE];
130         for (int i = 0; i < SIZE; i++) {
131             res[i] = chars[i];
132         }
133         return res;
134     }
135 
136     @Test
137     @IR(applyIfCPUFeature = { "avx", "true" },
138         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
139         counts = { IRNode.VECTOR_CAST_B2I, IRNode.VECTOR_SIZE + "min(max_int, max_byte)", ">0" })
140     public int[] signExtensionFromByte() {
141         int[] res = new int[SIZE];
142         for (int i = 0; i < SIZE; i++) {
143             res[i] = bytes[i];
144         }
145         return res;
146     }
147 
148     @Test
149     @IR(applyIfCPUFeature = { "avx", "true" },
150         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
151         counts = { IRNode.VECTOR_CAST_B2S, IRNode.VECTOR_SIZE + "min(max_short, max_byte)", ">0" })
152     public short[] signExtensionFromByteToShort() {
153         short[] res = new short[SIZE];
154         for (int i = 0; i < SIZE; i++) {
155             res[i] = bytes[i];
156         }
157         return res;
158     }
159 
160     // ---------------- Integer Narrow ----------------
161     @Test
162     @IR(applyIfCPUFeature = { "avx", "true" },
163         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
164         counts = { IRNode.VECTOR_CAST_I2S, IRNode.VECTOR_SIZE + "min(max_int, max_short)", ">0" })
165     public short[] narrowToSigned() {
166         short[] res = new short[SIZE];
167         for (int i = 0; i < SIZE; i++) {
168             res[i] = (short) ints[i];
169         }
170         return res;
171     }
172 
173     @Test
174     @IR(applyIfCPUFeature = { "avx", "true" },
175         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
176         counts = { IRNode.VECTOR_CAST_I2S, IRNode.VECTOR_SIZE + "min(max_int, max_char)", ">0" })
177     public char[] narrowToUnsigned() {
178         char[] res = new char[SIZE];
179         for (int i = 0; i < SIZE; i++) {
180             res[i] = (char) ints[i];
181         }
182         return res;
183     }
184 
185     @Test
186     @IR(applyIfCPUFeature = { "avx", "true" },
187         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
188         counts = { IRNode.VECTOR_CAST_I2B, IRNode.VECTOR_SIZE + "min(max_int, max_byte)", ">0" })
189     public byte[] narrowToByte() {
190         byte[] res = new byte[SIZE];
191         for (int i = 0; i < SIZE; i++) {
192             res[i] = (byte) ints[i];
193         }
194         return res;
195     }
196 
197     @Test
198     @IR(applyIfCPUFeature = { "avx", "true" },
199         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
200         counts = { IRNode.VECTOR_CAST_S2B, IRNode.VECTOR_SIZE + "min(max_short, max_byte)", ">0" })
201     public byte[] narrowShortToByte() {
202         byte[] res = new byte[SIZE];
203         for (int i = 0; i < SIZE; i++) {
204             res[i] = (byte) shorts[i];
205         }
206         return res;
207     }
208 
209     // ---------------- Convert I/L to F/D ----------------
210     @Test
211     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
212         counts = {IRNode.VECTOR_CAST_I2F, IRNode.VECTOR_SIZE + "min(max_int, max_float)", ">0"})
213     public float[] convertIntToFloat() {
214         float[] res = new float[SIZE];
215         for (int i = 0; i < SIZE; i++) {
216             res[i] = (float) ints[i];
217         }
218         return res;
219     }
220 
221     @Test
222     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
223         counts = {IRNode.VECTOR_CAST_I2D, IRNode.VECTOR_SIZE + "min(max_int, max_double)", ">0"})
224     public double[] convertIntToDouble() {
225         double[] res = new double[SIZE];
226         for (int i = 0; i < SIZE; i++) {
227             res[i] = (double) ints[i];
228         }
229         return res;
230     }
231 
232     @Test
233     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx512dq", "true", "rvv", "true"},
234         counts = {IRNode.VECTOR_CAST_L2F, IRNode.VECTOR_SIZE + "min(max_long, max_float)", ">0"})
235     public float[] convertLongToFloat() {
236         float[] res = new float[SIZE];
237         for (int i = 0; i < SIZE; i++) {
238             res[i] = (float) longs[i];
239         }
240         return res;
241     }
242 
243     @Test
244     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "rvv", "true"},
245         counts = {IRNode.VECTOR_CAST_L2D, IRNode.VECTOR_SIZE + "min(max_long, max_double)", ">0"})
246     public double[] convertLongToDouble() {
247         double[] res = new double[SIZE];
248         for (int i = 0; i < SIZE; i++) {
249             res[i] = (double) longs[i];
250         }
251         return res;
252     }
253 
254     // ---------------- Convert Subword-I to F/D ----------------
255     @Test
256     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "rvv", "true"},
257         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
258         counts = {IRNode.VECTOR_CAST_S2F, IRNode.VECTOR_SIZE + "min(max_short, max_float)", ">0"})
259     public float[] convertShortToFloat() {
260         float[] res = new float[SIZE];
261         for (int i = 0; i < SIZE; i++) {
262             res[i] = (float) shorts[i];
263             // AlignVector=true requires that all vector load/store are 8-byte aligned.
264             // F_adr = base + UNSAFE.ARRAY_FLOAT_BASE_OFFSET + 4*i
265             //                = 16 (UseCompactObjectHeaders=false)    -> i % 2 = 0
266             //                = 12 (UseCompactObjectHeaders=true )    -> i % 2 = 1
267             // S_adr = base + UNSAFE.ARRAY_SHORT_BASE_OFFSET + 2*i
268             //                = 16 (UseCompactObjectHeaders=false)    -> i % 4 = 0  -> can align both
269             //                = 12 (UseCompactObjectHeaders=true )    -> i % 4 = 2  -> cannot align both
270         }
271         return res;
272     }
273 
274     @Test
275     @IR(applyIfCPUFeature = {"rvv", "true"},
276         applyIf = {"MaxVectorSize", ">=32"},
277         counts = {IRNode.VECTOR_CAST_S2D, IRNode.VECTOR_SIZE + "min(max_short, max_double)", ">0"})
278     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true"},
279         applyIf = {"MaxVectorSize", ">=16"},
280         counts = {IRNode.VECTOR_CAST_S2D, IRNode.VECTOR_SIZE + "min(max_short, max_double)", ">0"})
281     public double[] convertShortToDouble() {
282         double[] res = new double[SIZE];
283         for (int i = 0; i < SIZE; i++) {
284             res[i] = (double) shorts[i];
285         }
286         return res;
287     }
288 
289     @Test
290     @IR(failOn = {IRNode.STORE_VECTOR})
291     // Subword vector casts with char do not work currently, see JDK-8349562.
292     // Assert the vectorization failure so that we are reminded to update
293     // the test when this limitation is addressed in the future.
294     public float[] convertCharToFloat() {
295         float[] res = new float[SIZE];
296         for (int i = 0; i < SIZE; i++) {
297             res[i] = (float) chars[i];
298         }
299         return res;
300     }
301 
302     @Test
303     @IR(failOn = {IRNode.STORE_VECTOR})
304     // Subword vector casts with char do not work currently, see JDK-8349562.
305     // Assert the vectorization failure so that we are reminded to update
306     // the test when this limitation is addressed in the future.
307     public double[] convertCharToDouble() {
308         double[] res = new double[SIZE];
309         for (int i = 0; i < SIZE; i++) {
310             res[i] = (double) chars[i];
311         }
312         return res;
313     }
314 
315     // ---------------- Convert F/D to I/L ----------------
316     @Test
317     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "avx10_2", "true", "rvv", "true"},
318         counts = {IRNode.VECTOR_CAST_F2I, IRNode.VECTOR_SIZE + "min(max_float, max_int)", "> 0"})
319     @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
320         applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
321     @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"},
322         applyIfCPUFeature = {"avx10_2", "true"})
323     public int[] convertFloatToInt() {
324         int[] res = new int[SIZE];
325         for (int i = 0; i < SIZE; i++) {
326             res[i] = (int) floats[i];
327         }
328         return res;
329     }
330 
331     @Test
332     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"},
333         counts = {IRNode.VECTOR_CAST_F2L, IRNode.VECTOR_SIZE + "min(max_float, max_long)", "> 0"})
334     @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
335         applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"})
336     @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"},
337         applyIfCPUFeature = {"avx10_2", "true"})
338     public long[] convertFloatToLong() {
339         long[] res = new long[SIZE];
340         for (int i = 0; i < SIZE; i++) {
341             res[i] = (long) floats[i];
342         }
343         return res;
344     }
345 
346     @Test
347     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true", "rvv", "true"},
348         counts = {IRNode.VECTOR_CAST_D2I, IRNode.VECTOR_SIZE + "min(max_double, max_int)", "> 0"})
349     @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
350         applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
351     @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"},
352         applyIfCPUFeature = {"avx10_2", "true"})
353     public int[] convertDoubleToInt() {
354         int[] res = new int[SIZE];
355         for (int i = 0; i < SIZE; i++) {
356             res[i] = (int) doubles[i];
357         }
358         return res;
359     }
360 
361     @Test
362     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx512dq", "true", "avx10_2", "true", "rvv", "true"},
363         counts = {IRNode.VECTOR_CAST_D2L, IRNode.VECTOR_SIZE + "min(max_double, max_long)", "> 0"})
364     @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
365         applyIfCPUFeatureAnd = {"avx512dq", "true", "avx10_2", "false"})
366     @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"},
367         applyIfCPUFeature = {"avx10_2", "true"})
368     public long[] convertDoubleToLong() {
369         long[] res = new long[SIZE];
370         for (int i = 0; i < SIZE; i++) {
371             res[i] = (long) doubles[i];
372         }
373         return res;
374     }
375 
376     // ---------------- Convert F/D to Subword-I ----------------
377     @Test
378     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"},
379         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
380         counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_short)", "> 0"})
381     @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
382         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
383         applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"})
384     @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"},
385         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
386         applyIfCPUFeature = {"avx10_2", "true"})
387     public short[] convertFloatToShort() {
388         short[] res = new short[SIZE];
389         for (int i = 0; i < SIZE; i++) {
390             res[i] = (short) floats[i];
391             // AlignVector=true requires that all vector load/store are 8-byte aligned.
392             // F_adr = base + UNSAFE.ARRAY_FLOAT_BASE_OFFSET + 4*i
393             //                = 16 (UseCompactObjectHeaders=false)    -> i % 2 = 0
394             //                = 12 (UseCompactObjectHeaders=true )    -> i % 2 = 1
395             // S_adr = base + UNSAFE.ARRAY_SHORT_BASE_OFFSET + 2*i
396             //                = 16 (UseCompactObjectHeaders=false)    -> i % 4 = 0  -> can align both
397             //                = 12 (UseCompactObjectHeaders=true )    -> i % 4 = 2  -> cannot align both
398         }
399         return res;
400     }
401 
402     @Test
403     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx2", "true", "avx10_2", "true", "rvv", "true"},
404         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
405         counts = {IRNode.VECTOR_CAST_F2S, IRNode.VECTOR_SIZE + "min(max_float, max_char)", "> 0"})
406     @IR(counts = {IRNode.X86_VCAST_F2X, "> 0"},
407         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
408         applyIfCPUFeatureAnd = {"avx2", "true", "avx10_2", "false"})
409     @IR(counts = {IRNode.X86_VCAST_F2X_AVX10_2, "> 0"},
410         applyIfOr = {"AlignVector", "false", "UseCompactObjectHeaders", "false"},
411         applyIfCPUFeature = {"avx10_2", "true"})
412     public char[] convertFloatToChar() {
413         char[] res = new char[SIZE];
414         for (int i = 0; i < SIZE; i++) {
415             res[i] = (char) floats[i];
416             // AlignVector=true requires that all vector load/store are 8-byte aligned.
417             // F_adr = base + UNSAFE.ARRAY_FLOAT_BASE_OFFSET + 4*i
418             //                = 16 (UseCompactObjectHeaders=false)    -> i % 2 = 0
419             //                = 12 (UseCompactObjectHeaders=true )    -> i % 2 = 1
420             // S_adr = base + UNSAFE.ARRAY_SHORT_BASE_OFFSET + 2*i
421             //                = 16 (UseCompactObjectHeaders=false)    -> i % 4 = 0  -> can align both
422             //                = 12 (UseCompactObjectHeaders=true )    -> i % 4 = 2  -> cannot align both
423         }
424         return res;
425     }
426 
427     @Test
428     @IR(applyIfCPUFeature = {"rvv", "true"},
429         applyIf = {"MaxVectorSize", ">=32"},
430         counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"})
431     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"},
432         applyIf = {"MaxVectorSize", ">=16"},
433         counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_short)", "> 0"})
434     @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
435         applyIf = {"MaxVectorSize", ">=16"},
436         applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
437     @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"},
438         applyIf = {"MaxVectorSize", ">=16"},
439         applyIfCPUFeature = {"avx10_2", "true"})
440     public short[] convertDoubleToShort() {
441         short[] res = new short[SIZE];
442         for (int i = 0; i < SIZE; i++) {
443             res[i] = (short) doubles[i];
444         }
445         return res;
446     }
447 
448     @Test
449     @IR(applyIfCPUFeature = {"rvv", "true"},
450         applyIf = {"MaxVectorSize", ">= 32"},
451         counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"})
452     @IR(applyIfCPUFeatureOr = {"sve", "true", "avx", "true", "avx10_2", "true"},
453         applyIf = {"MaxVectorSize", ">= 16"},
454         counts = {IRNode.VECTOR_CAST_D2S, IRNode.VECTOR_SIZE + "min(max_double, max_char)", "> 0"})
455     @IR(counts = {IRNode.X86_VCAST_D2X, "> 0"},
456         applyIf = {"MaxVectorSize", ">=16"},
457         applyIfCPUFeatureAnd = {"avx", "true", "avx10_2", "false"})
458     @IR(counts = {IRNode.X86_VCAST_D2X_AVX10_2, "> 0"},
459         applyIf = {"MaxVectorSize", ">=16"},
460         applyIfCPUFeature = {"avx10_2", "true"})
461     public char[] convertDoubleToChar() {
462         char[] res = new char[SIZE];
463         for (int i = 0; i < SIZE; i++) {
464             res[i] = (char) doubles[i];
465         }
466         return res;
467     }
468 
469     // ---------------- Convert Between F & D ----------------
470     @Test
471     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
472         counts = {IRNode.VECTOR_CAST_F2D, IRNode.VECTOR_SIZE + "min(max_float, max_double)", ">0"})
473     public double[] convertFloatToDouble() {
474         double[] res = new double[SIZE];
475         for (int i = 0; i < SIZE; i++) {
476             res[i] = (double) floats[i];
477         }
478         return res;
479     }
480 
481     @Test
482     @IR(applyIfCPUFeatureOr = {"asimd", "true", "avx", "true", "rvv", "true"},
483         counts = {IRNode.VECTOR_CAST_D2F, IRNode.VECTOR_SIZE + "min(max_double, max_float)", ">0"})
484     public float[] convertDoubleToFloat() {
485         float[] res = new float[SIZE];
486         for (int i = 0; i < SIZE; i++) {
487             res[i] = (float) doubles[i];
488         }
489         return res;
490     }
491 }