From 43ab423d96bc6786f30bb82888d18a908af07db7 Mon Sep 17 00:00:00 2001 From: Will Schmidt Date: Tue, 25 Sep 2018 18:34:06 +0000 Subject: [PATCH] altivec-6.C: Updated vec_splat() calls. [testsuite] 2018-09-25 Will Schmidt * g++.dg/ext/altivec-6.C: Updated vec_splat() calls. * gcc.target/powerpc/fold-vec-splat-char.c: Remove invalid vec_splat calls from recently added tests. Update instruction counts. * gcc.target/powerpc/fold-vec-splat-floatdouble.c: Same. * gcc.target/powerpc/fold-vec-splat-int.c: Same. * gcc.target/powerpc/fold-vec-splat-longlong.c: Same. * gcc.target/powerpc/fold-vec-splat-pixel.c: Same. * gcc.target/powerpc/fold-vec-splat-short.c: Same. From-SVN: r264582 --- gcc/testsuite/ChangeLog | 11 +++++ gcc/testsuite/g++.dg/ext/altivec-6.C | 8 ++-- .../gcc.target/powerpc/fold-vec-splat-char.c | 21 ++------- .../powerpc/fold-vec-splat-floatdouble.c | 45 +++++++------------ .../gcc.target/powerpc/fold-vec-splat-int.c | 25 +---------- .../powerpc/fold-vec-splat-longlong.c | 37 +++------------ .../gcc.target/powerpc/fold-vec-splat-pixel.c | 12 +---- .../gcc.target/powerpc/fold-vec-splat-short.c | 22 +-------- 8 files changed, 46 insertions(+), 135 deletions(-) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 90f54494ae9..da2d96c4a30 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,14 @@ +2018-09-25 Will Schmidt + + * g++.dg/ext/altivec-6.C: Updated vec_splat() calls. + * gcc.target/powerpc/fold-vec-splat-char.c: Remove invalid + vec_splat calls from recently added tests. Update instruction counts. + * gcc.target/powerpc/fold-vec-splat-floatdouble.c: Same. + * gcc.target/powerpc/fold-vec-splat-int.c: Same. + * gcc.target/powerpc/fold-vec-splat-longlong.c: Same. + * gcc.target/powerpc/fold-vec-splat-pixel.c: Same. + * gcc.target/powerpc/fold-vec-splat-short.c: Same. + 2018-09-25 Marek Polacek PR c++/87425 diff --git a/gcc/testsuite/g++.dg/ext/altivec-6.C b/gcc/testsuite/g++.dg/ext/altivec-6.C index 63ae0b0b91b..4c863ef0e76 100644 --- a/gcc/testsuite/g++.dg/ext/altivec-6.C +++ b/gcc/testsuite/g++.dg/ext/altivec-6.C @@ -22,7 +22,9 @@ void foo(void) { vp = vec_sld(vp, vp, 5); vbc = vec_splat(vbc, 7); - vbs = vec_splat(vbs, 12); - vp = vec_splat(vp, 17); - vbi = vec_splat(vbi, 31); + /* The second argument to vec_splat needs to be less than the number of + elements in the referenced vector. */ + vbs = vec_splat(vbs, 4); + vp = vec_splat(vp, 1); + vbi = vec_splat(vbi, 15); } diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-char.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-char.c index d50d073979f..fbe347c67e6 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-char.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-char.c @@ -12,27 +12,18 @@ vector bool char testb_1 (vector bool char x) { return vec_splat (x, 0b00001); vector bool char testb_2 (vector bool char x) { return vec_splat (x, 0b00010); } vector bool char testb_4 (vector bool char x) { return vec_splat (x, 0b00100); } vector bool char testb_8 (vector bool char x) { return vec_splat (x, 0b01000); } -vector bool char testb_10 (vector bool char x) { return vec_splat (x, 0b10000); } -vector bool char testb_1e (vector bool char x) { return vec_splat (x, 0b11110); } -vector bool char testb_1f (vector bool char x) { return vec_splat (x, 0b11111); } vector signed char tests_0 (vector signed char x) { return vec_splat (x, 0b00000); } vector signed char tests_1 (vector signed char x) { return vec_splat (x, 0b00001); } vector signed char tests_2 (vector signed char x) { return vec_splat (x, 0b00010); } vector signed char tests_4 (vector signed char x) { return vec_splat (x, 0b00100); } vector signed char tests_8 (vector signed char x) { return vec_splat (x, 0b01000); } -vector signed char tests_10 (vector signed char x) { return vec_splat (x, 0b10000); } -vector signed char tests_1e (vector signed char x) { return vec_splat (x, 0b11110); } -vector signed char tests_1f (vector signed char x) { return vec_splat (x, 0b11111); } vector unsigned char testu_0 (vector unsigned char x) { return vec_splat (x, 0b00000); } vector unsigned char testu_1 (vector unsigned char x) { return vec_splat (x, 0b00001); } vector unsigned char testu_2 (vector unsigned char x) { return vec_splat (x, 0b00010); } vector unsigned char testu_4 (vector unsigned char x) { return vec_splat (x, 0b00100); } vector unsigned char testu_8 (vector unsigned char x) { return vec_splat (x, 0b01000); } -vector unsigned char testu_10 (vector unsigned char x) { return vec_splat (x, 0b10000); } -vector unsigned char testu_1e (vector unsigned char x) { return vec_splat (x, 0b11110); } -vector unsigned char testu_1f (vector unsigned char x) { return vec_splat (x, 0b11111); } /* Similar tests as above, but the source vector is a known constant. */ const vector bool char by = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p'}; @@ -43,13 +34,7 @@ vector bool char test_bc (vector bool char x) { return vec_splat (by, 0b00010); vector signed char test_sc (vector signed char x) { return vec_splat (sy, 0b00011); } vector unsigned char test_uc (vector unsigned char x) { return vec_splat (uy, 0b00110); } -/* Similar tests as above, mask is greater than number of elements in the - source vector. */ -vector bool char test_obc (vector bool char x) { return vec_splat (by, 0b10010); } -vector signed char test_osc (vector signed char x) { return vec_splat (sy, 0b10011); } -vector unsigned char test_ouc (vector unsigned char x) { return vec_splat (uy, 0b10110); } - // vec_splat() using variable vectors should generate the vspltb instruction. -/* { dg-final { scan-assembler-times "vspltb" 24 } } */ -// vec_splat() using a constant vector should generate a load. -/* { dg-final { scan-assembler-times {\mlvx\M|\mlxvw4x\M} 6 } } */ +/* { dg-final { scan-assembler-times "vspltb" 15 } } */ +// vec_splat() using a constant vector will generate a load or a splat immediate byte. +/* { dg-final { scan-assembler-times {\mlvx\M|\mlxvw4x\M|\mxxspltib\M} 3 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-floatdouble.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-floatdouble.c index fd74002bb1f..ab396967c3d 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-floatdouble.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-floatdouble.c @@ -7,40 +7,25 @@ #include +/* Floats. */ vector float testf_00 (vector float x) { return vec_splat (x, 0b00000); } vector float testf_01 (vector float x) { return vec_splat (x, 0b00001); } vector float testf_02 (vector float x) { return vec_splat (x, 0b00010); } -vector float testf_04 (vector float x) { return vec_splat (x, 0b00100); } -vector float testf_08 (vector float x) { return vec_splat (x, 0b01000); } -vector float testf_0f (vector float x) { return vec_splat (x, 0b01111); } -vector float testf_10 (vector float x) { return vec_splat (x, 0b10000); } -vector float testf_1e (vector float x) { return vec_splat (x, 0b11110); } -vector float testf_1f (vector float x) { return vec_splat (x, 0b11111); } +vector float test_fc () +{ const vector float y = { 7.1, 8.2, 9.3, 10.4}; return vec_splat (y, 0b00010); } +/* Doubles. */ vector double testd_00 (vector double x) { return vec_splat (x, 0b00000); } vector double testd_01 (vector double x) { return vec_splat (x, 0b00001); } -vector double testd_02 (vector double x) { return vec_splat (x, 0b00010); } -vector double testd_04 (vector double x) { return vec_splat (x, 0b00100); } -vector double testd_08 (vector double x) { return vec_splat (x, 0b01000); } -vector double testd_0f (vector double x) { return vec_splat (x, 0b01111); } -vector double testd_10 (vector double x) { return vec_splat (x, 0b10000); } -vector double testd_1e (vector double x) { return vec_splat (x, 0b11110); } -vector double testd_1f (vector double x) { return vec_splat (x, 0b11111); } - -/* Similar tests as above, but the source vector is a known constant. */ -vector float test_fc () { const vector float y = { 7.1, 8.2, 9.3, 10.4}; return vec_splat (y, 0b00010); } -vector double test_dc () { const vector double y = { 3.0, 5.0 }; return vec_splat (y, 0b00010); } - -/* Similar tests as above, mask is greater than number of elements in the - source vector. */ -vector float test_ofc () { const vector float y = { 7.1, 8.2, 9.3, 10.4}; return vec_splat (y, 0b10010); } -vector double test_odc () { const vector double y = { 3.0, 5.0 }; return vec_splat (y, 0b10010); } - -/* lvx or lxvd2x for loading of the constants. */ -/* vspltw or xxspltw for non-constants with the float type. */ -/* xxpermdi for non-constants with the double type. */ - -/* { dg-final { scan-assembler-times {\mlvx\M|\mlxvd2x\M} 4 } } */ -/* { dg-final { scan-assembler-times "vspltw|xxspltw" 9 } } */ -/* { dg-final { scan-assembler-times "xxpermdi" 9 } } */ +vector double test_dc () +{ const vector double y = { 3.0, 5.0 }; return vec_splat (y, 0b00010); } + +/* If the source vector is a known constant, we will generate a load. */ +/* { dg-final { scan-assembler-times {\mlvx\M|\mlxvd2x\M|\mlxv\M} 2 } } */ + +/* For float types, we generate a splat. */ +/* { dg-final { scan-assembler-times "vspltw|xxspltw" 3 } } */ + +/* For double types, we will generate xxpermdi instructions. */ +/* { dg-final { scan-assembler-times "xxpermdi" 3 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-int.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-int.c index 7697853f75a..5df96d11acb 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-int.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-int.c @@ -10,41 +10,20 @@ vector bool int testb_0 (vector bool int x) { return vec_splat (x, 0b00000); } vector bool int testb_1 (vector bool int x) { return vec_splat (x, 0b00001); } vector bool int testb_2 (vector bool int x) { return vec_splat (x, 0b00010); } -vector bool int testb_4 (vector bool int x) { return vec_splat (x, 0b00100); } -vector bool int testb_8 (vector bool int x) { return vec_splat (x, 0b01000); } -vector bool int testb_10 (vector bool int x) { return vec_splat (x, 0b10000); } -vector bool int testb_1e (vector bool int x) { return vec_splat (x, 0b11110); } -vector bool int testb_1f (vector bool int x) { return vec_splat (x, 0b11111); } vector signed int tests_0 (vector signed int x) { return vec_splat (x, 0b00000); } vector signed int tests_1 (vector signed int x) { return vec_splat (x, 0b00001); } vector signed int tests_2 (vector signed int x) { return vec_splat (x, 0b00010); } -vector signed int tests_4 (vector signed int x) { return vec_splat (x, 0b00100); } -vector signed int tests_8 (vector signed int x) { return vec_splat (x, 0b01000); } -vector signed int tests_10 (vector signed int x) { return vec_splat (x, 0b10000); } -vector signed int tests_1e (vector signed int x) { return vec_splat (x, 0b11110); } -vector signed int tests_1f (vector signed int x) { return vec_splat (x, 0b11111); } vector unsigned int testu_0 (vector unsigned int x) { return vec_splat (x, 0b00000); } vector unsigned int testu_1 (vector unsigned int x) { return vec_splat (x, 0b00001); } vector unsigned int testu_2 (vector unsigned int x) { return vec_splat (x, 0b00010); } -vector unsigned int testu_4 (vector unsigned int x) { return vec_splat (x, 0b00100); } -vector unsigned int testu_8 (vector unsigned int x) { return vec_splat (x, 0b01000); } -vector unsigned int testu_10 (vector unsigned int x) { return vec_splat (x, 0b10000); } -vector unsigned int testu_1e (vector unsigned int x) { return vec_splat (x, 0b11110); } -vector unsigned int testu_1f (vector unsigned int x) { return vec_splat (x, 0b11111); } /* Similar test as above, but the source vector is a known constant. */ vector bool int test_bic () { const vector bool int y = { 1,2,3,4}; return vec_splat (y, 0b00010); } vector signed int test_sic () { const vector signed int y = { 1,2,3,4}; return vec_splat (y, 0b00010); } vector unsigned int test_uic () { const vector unsigned int y = { 1,2,3,4}; return vec_splat (y, 0b00010); } -/* Similar tests as above, mask is greater than number of elements in the - source vector. */ -vector bool int test_obic () { const vector bool int y = { 1,2,3,4}; return vec_splat (y, 0b10010); } -vector signed int test_osic () { const vector signed int y = { 1,2,3,4}; return vec_splat (y, 0b10010); } -vector unsigned int test_ouic () { const vector unsigned int y = { 1,2,3,4}; return vec_splat (y, 0b10010); } - -/* { dg-final { scan-assembler-times "vspltisw" 6 } } */ -/* { dg-final { scan-assembler-times "vspltw|xxspltw" 24 } } */ +/* { dg-final { scan-assembler-times "vspltisw" 3 } } */ +/* { dg-final { scan-assembler-times "vspltw|xxspltw" 9 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-longlong.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-longlong.c index 0720e20a116..4fa06c85ecc 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-longlong.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-longlong.c @@ -10,51 +10,26 @@ vector bool long long testb_00 (vector bool long long x) { return vec_splat (x, 0b00000); } vector bool long long testb_01 (vector bool long long x) { return vec_splat (x, 0b00001); } vector bool long long testb_02 (vector bool long long x) { return vec_splat (x, 0b00010); } -vector bool long long testb_04 (vector bool long long x) { return vec_splat (x, 0b00100); } -vector bool long long testb_08 (vector bool long long x) { return vec_splat (x, 0b01000); } -vector bool long long testb_10 (vector bool long long x) { return vec_splat (x, 0b10000); } -vector bool long long testb_1e (vector bool long long x) { return vec_splat (x, 0b11110); } -vector bool long long testb_1f (vector bool long long x) { return vec_splat (x, 0b11111); } vector signed long long tests_00 (vector signed long long x) { return vec_splat (x, 0b00000); } vector signed long long tests_01 (vector signed long long x) { return vec_splat (x, 0b00001); } vector signed long long tests_02 (vector signed long long x) { return vec_splat (x, 0b00010); } -vector signed long long tests_04 (vector signed long long x) { return vec_splat (x, 0b00100); } -vector signed long long tests_08 (vector signed long long x) { return vec_splat (x, 0b01000); } -vector signed long long tests_10 (vector signed long long x) { return vec_splat (x, 0b10000); } -vector signed long long tests_1e (vector signed long long x) { return vec_splat (x, 0b11110); } -vector signed long long tests_1f (vector signed long long x) { return vec_splat (x, 0b11111); } vector unsigned long long testu_00 (vector unsigned long long x) { return vec_splat (x, 0b00000); } vector unsigned long long testu_01 (vector unsigned long long x) { return vec_splat (x, 0b00001); } vector unsigned long long testu_02 (vector unsigned long long x) { return vec_splat (x, 0b00010); } -vector unsigned long long testu_04 (vector unsigned long long x) { return vec_splat (x, 0b00100); } -vector unsigned long long testu_08 (vector unsigned long long x) { return vec_splat (x, 0b01000); } -vector unsigned long long testu_10 (vector unsigned long long x) { return vec_splat (x, 0b10000); } -vector unsigned long long testu_1e (vector unsigned long long x) { return vec_splat (x, 0b11110); } -vector unsigned long long testu_1f (vector unsigned long long x) { return vec_splat (x, 0b11111); } /* Similar test as above, but the source vector is a known constant. */ vector bool long long test_bll () { const vector bool long long y = {12, 23}; return vec_splat (y, 0b00010); } vector signed long long test_sll () { const vector signed long long y = {34, 45}; return vec_splat (y, 0b00010); } vector unsigned long long test_ull () { const vector unsigned long long y = {56, 67}; return vec_splat (y, 0b00010); } -/* Similar tests as above, mask is greater than number of elements in the - source vector. */ -vector bool long long test_obll () { const vector bool long long y = {12, 23}; return vec_splat (y, 0b10010); } -vector signed long long test_osll () { const vector signed long long y = {34, 45}; return vec_splat (y, 0b10010); } -vector unsigned long long test_oull () { const vector unsigned long long y = {56, 67}; return vec_splat (y, 0b10010); } - -/* lvx for the initialization with known constants. */ -/* { dg-final { scan-assembler-times {\mlvx\M|\mlxvd2x\M} 6 } } */ +/* Assorted load instructions for the initialization with known constants. */ +/* { dg-final { scan-assembler-times {\mlvx\M|\mlxvd2x\M|\mlxv\M} 3 } } */ /* xxpermdi for vec_splat of long long vectors. - At the time of this writing, the number of xxpermdi instructions - generated could be 24 or 26 or 27, ultimately depending on the - platform and whether or not folding is enabled. - Roughly: - 24 occurrences on older targets (power5) regardless of folding state. - 26 occurrences with gimple folding enabled (through power9). - 27 occurrences with gimple folding disabled (through power9). - So, ensure we have at least one hit. */ + At the time of this writing, the number of xxpermdi instructions + generated will vary depending on the target processor (p5/p6/p7/p8/...) + and whether or not folding is enabled. + So, ensure we have at least one hit. */ /* { dg-final { scan-assembler "xxpermdi" } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-pixel.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-pixel.c index 7170588f568..bb9b516fa5c 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-pixel.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-pixel.c @@ -11,17 +11,9 @@ vector pixel test1_00 (vector pixel x) { return vec_splat (x, 0b00000); } vector pixel test1_01 (vector pixel x) { return vec_splat (x, 0b00001); } vector pixel test1_02 (vector pixel x) { return vec_splat (x, 0b00010); } vector pixel test1_04 (vector pixel x) { return vec_splat (x, 0b00100); } -vector pixel test1_08 (vector pixel x) { return vec_splat (x, 0b01000); } -vector pixel test1_10 (vector pixel x) { return vec_splat (x, 0b10000); } -vector pixel test1_1e (vector pixel x) { return vec_splat (x, 0b11110); } -vector pixel test1_1f (vector pixel x) { return vec_splat (x, 0b11111); } /* Similar test as above, but the source vector is a known constant. */ vector pixel test_p () { const vector pixel y = { 1,2,3,4}; return vec_splat (y, 0b00010); } -/* Similar tests as above, mask is greater than number of elements in the - source vector. */ -vector pixel test_op () { const vector pixel y = { 1,2,3,4}; return vec_splat (y, 0b10010); } - -/* { dg-final { scan-assembler-times "vspltish" 2 } } */ -/* { dg-final { scan-assembler-times "vsplth" 8 } } */ +/* { dg-final { scan-assembler-times "vspltish" 1 } } */ +/* { dg-final { scan-assembler-times "vsplth" 4 } } */ diff --git a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-short.c b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-short.c index 96c553f124f..92bdfa4525f 100644 --- a/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-short.c +++ b/gcc/testsuite/gcc.target/powerpc/fold-vec-splat-short.c @@ -11,39 +11,21 @@ vector bool short testb_00 (vector bool short x) { return vec_splat (x, 0b00000) vector bool short testb_01 (vector bool short x) { return vec_splat (x, 0b00001); } vector bool short testb_02 (vector bool short x) { return vec_splat (x, 0b00010); } vector bool short testb_04 (vector bool short x) { return vec_splat (x, 0b00100); } -vector bool short testb_08 (vector bool short x) { return vec_splat (x, 0b01000); } -vector bool short testb_10 (vector bool short x) { return vec_splat (x, 0b10000); } -vector bool short testb_1e (vector bool short x) { return vec_splat (x, 0b11110); } -vector bool short testb_1f (vector bool short x) { return vec_splat (x, 0b11111); } vector signed short tests_00 (vector signed short x) { return vec_splat (x, 0b00000); } vector signed short tests_01 (vector signed short x) { return vec_splat (x, 0b00001); } vector signed short tests_02 (vector signed short x) { return vec_splat (x, 0b00010); } vector signed short tests_04 (vector signed short x) { return vec_splat (x, 0b00100); } -vector signed short tests_08 (vector signed short x) { return vec_splat (x, 0b01000); } -vector signed short tests_10 (vector signed short x) { return vec_splat (x, 0b10000); } -vector signed short tests_1e (vector signed short x) { return vec_splat (x, 0b11110); } -vector signed short tests_1f (vector signed short x) { return vec_splat (x, 0b11111); } vector unsigned short testu_00 (vector unsigned short x) { return vec_splat (x, 0b00000); } vector unsigned short testu_01 (vector unsigned short x) { return vec_splat (x, 0b00001); } vector unsigned short testu_02 (vector unsigned short x) { return vec_splat (x, 0b00010); } vector unsigned short testu_04 (vector unsigned short x) { return vec_splat (x, 0b00100); } -vector unsigned short testu_08 (vector unsigned short x) { return vec_splat (x, 0b01000); } -vector unsigned short testu_10 (vector unsigned short x) { return vec_splat (x, 0b10000); } -vector unsigned short testu_1e (vector unsigned short x) { return vec_splat (x, 0b11110); } -vector unsigned short testu_1f (vector unsigned short x) { return vec_splat (x, 0b11111); } /* Similar test as above, but the source vector is a known constant. */ vector bool short test_bs () { const vector bool short y = {1, 2, 3, 4, 5, 6, 7, 8}; return vec_splat (y, 0b00010); } vector signed short test_ss () { const vector signed short y = {1, 2, 3, 4, 5, 6, 7, 8}; return vec_splat (y, 0b00010); } vector unsigned short test_us () { const vector unsigned short y = {1, 2, 3, 4, 5, 6, 7, 8}; return vec_splat (y, 0b00010); } -/* Similar tests as above, mask is greater than number of elements in the - source vector. */ -vector bool short test_obs () { const vector bool short y = {1, 2, 3, 4, 5, 6, 7, 8}; return vec_splat (y, 0b10010); } -vector signed short test_oss () { const vector signed short y = {1, 2, 3, 4, 5, 6, 7, 8}; return vec_splat (y, 0b10010); } -vector unsigned short test_ous () { const vector unsigned short y = {1, 2, 3, 4, 5, 6, 7, 8}; return vec_splat (y, 0b10010); } - -/* { dg-final { scan-assembler-times "vspltish" 6 } } */ -/* { dg-final { scan-assembler-times "vsplth" 24 } } */ +/* { dg-final { scan-assembler-times "vspltish" 3 } } */ +/* { dg-final { scan-assembler-times "vsplth" 12 } } */ -- 2.30.2