Skip to content

Commit 0f3ede9

Browse files
authored
[X86] Allow AVX512 512-bit variants of AVX2 per-element i32 shift intrinsics to be used in constexpr (llvm#156480)
Followup to llvm#154780
1 parent e915d9a commit 0f3ede9

File tree

5 files changed

+40
-30
lines changed

5 files changed

+40
-30
lines changed

clang/include/clang/Basic/BuiltinsX86.td

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1993,6 +1993,10 @@ let Features = "avx512dq,evex512", Attributes = [NoThrow, Const, RequiredVectorW
19931993
}
19941994

19951995
let Features = "avx512f,evex512", Attributes = [NoThrow, Const, Constexpr, RequiredVectorWidth<512>] in {
1996+
def psllv16si : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>)">;
1997+
def psrav16si : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>)">;
1998+
def psrlv16si : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>)">;
1999+
19962000
def prold512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Constant int)">;
19972001
def prord512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Constant int)">;
19982002
def prolq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Constant int)">;
@@ -2422,15 +2426,12 @@ let Features = "avx512vl",
24222426
let Features = "avx512f,evex512", Attributes = [NoThrow, Const, RequiredVectorWidth<512>] in {
24232427
def pslld512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<4, int>)">;
24242428
def psllq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<2, long long int>)">;
2425-
def psllv16si : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>)">;
24262429
def psllv8di : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>)">;
24272430
def psrad512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<4, int>)">;
24282431
def psraq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<2, long long int>)">;
2429-
def psrav16si : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>)">;
24302432
def psrav8di : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>)">;
24312433
def psrld512 : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<4, int>)">;
24322434
def psrlq512 : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<2, long long int>)">;
2433-
def psrlv16si : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>)">;
24342435
def psrlv8di : X86Builtin<"_Vector<8, long long int>(_Vector<8, long long int>, _Vector<8, long long int>)">;
24352436
def pternlogd512_mask : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>, _Vector<16, int>, _Constant int, unsigned short)">;
24362437
def pternlogd512_maskz : X86Builtin<"_Vector<16, int>(_Vector<16, int>, _Vector<16, int>, _Vector<16, int>, _Constant int, unsigned short)">;

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3268,6 +3268,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
32683268
case clang::X86::BI__builtin_ia32_psllv4di:
32693269
case clang::X86::BI__builtin_ia32_psllv4si:
32703270
case clang::X86::BI__builtin_ia32_psllv8si:
3271+
case clang::X86::BI__builtin_ia32_psllv16si:
32713272
case clang::X86::BI__builtin_ia32_psllwi128:
32723273
case clang::X86::BI__builtin_ia32_psllwi256:
32733274
case clang::X86::BI__builtin_ia32_psllwi512:
@@ -3287,6 +3288,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
32873288

32883289
case clang::X86::BI__builtin_ia32_psrav4si:
32893290
case clang::X86::BI__builtin_ia32_psrav8si:
3291+
case clang::X86::BI__builtin_ia32_psrav16si:
32903292
case clang::X86::BI__builtin_ia32_psrawi128:
32913293
case clang::X86::BI__builtin_ia32_psrawi256:
32923294
case clang::X86::BI__builtin_ia32_psrawi512:
@@ -3308,6 +3310,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const CallExpr *Call,
33083310
case clang::X86::BI__builtin_ia32_psrlv4di:
33093311
case clang::X86::BI__builtin_ia32_psrlv4si:
33103312
case clang::X86::BI__builtin_ia32_psrlv8si:
3313+
case clang::X86::BI__builtin_ia32_psrlv16si:
33113314
case clang::X86::BI__builtin_ia32_psrlwi128:
33123315
case clang::X86::BI__builtin_ia32_psrlwi256:
33133316
case clang::X86::BI__builtin_ia32_psrlwi512:

clang/lib/AST/ExprConstant.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11687,12 +11687,15 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
1168711687
case clang::X86::BI__builtin_ia32_psllv4di:
1168811688
case clang::X86::BI__builtin_ia32_psllv4si:
1168911689
case clang::X86::BI__builtin_ia32_psllv8si:
11690+
case clang::X86::BI__builtin_ia32_psllv16si:
1169011691
case clang::X86::BI__builtin_ia32_psrav4si:
1169111692
case clang::X86::BI__builtin_ia32_psrav8si:
11693+
case clang::X86::BI__builtin_ia32_psrav16si:
1169211694
case clang::X86::BI__builtin_ia32_psrlv2di:
1169311695
case clang::X86::BI__builtin_ia32_psrlv4di:
1169411696
case clang::X86::BI__builtin_ia32_psrlv4si:
1169511697
case clang::X86::BI__builtin_ia32_psrlv8si:
11698+
case clang::X86::BI__builtin_ia32_psrlv16si:
1169611699

1169711700
case clang::X86::BI__builtin_ia32_psllwi128:
1169811701
case clang::X86::BI__builtin_ia32_pslldi128:
@@ -11823,6 +11826,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
1182311826
case clang::X86::BI__builtin_ia32_psllv4di:
1182411827
case clang::X86::BI__builtin_ia32_psllv4si:
1182511828
case clang::X86::BI__builtin_ia32_psllv8si:
11829+
case clang::X86::BI__builtin_ia32_psllv16si:
1182611830
if (RHS.uge(RHS.getBitWidth())) {
1182711831
ResultElements.push_back(
1182811832
APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned)));
@@ -11833,6 +11837,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
1183311837
break;
1183411838
case clang::X86::BI__builtin_ia32_psrav4si:
1183511839
case clang::X86::BI__builtin_ia32_psrav8si:
11840+
case clang::X86::BI__builtin_ia32_psrav16si:
1183611841
if (RHS.uge(RHS.getBitWidth())) {
1183711842
ResultElements.push_back(
1183811843
APValue(APSInt(LHS.ashr(RHS.getBitWidth() - 1), DestUnsigned)));
@@ -11845,6 +11850,7 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
1184511850
case clang::X86::BI__builtin_ia32_psrlv4di:
1184611851
case clang::X86::BI__builtin_ia32_psrlv4si:
1184711852
case clang::X86::BI__builtin_ia32_psrlv8si:
11853+
case clang::X86::BI__builtin_ia32_psrlv16si:
1184811854
if (RHS.uge(RHS.getBitWidth())) {
1184911855
ResultElements.push_back(
1185011856
APValue(APSInt(APInt::getZero(RHS.getBitWidth()), DestUnsigned)));

clang/lib/Headers/avx512fintrin.h

Lines changed: 18 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5644,23 +5644,20 @@ _mm512_maskz_sll_epi64(__mmask8 __U, __m512i __A, __m128i __B)
56445644
(__v8di)_mm512_setzero_si512());
56455645
}
56465646

5647-
static __inline__ __m512i __DEFAULT_FN_ATTRS512
5648-
_mm512_sllv_epi32(__m512i __X, __m512i __Y)
5649-
{
5647+
static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR
5648+
_mm512_sllv_epi32(__m512i __X, __m512i __Y) {
56505649
return (__m512i)__builtin_ia32_psllv16si((__v16si)__X, (__v16si)__Y);
56515650
}
56525651

5653-
static __inline__ __m512i __DEFAULT_FN_ATTRS512
5654-
_mm512_mask_sllv_epi32(__m512i __W, __mmask16 __U, __m512i __X, __m512i __Y)
5655-
{
5652+
static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR
5653+
_mm512_mask_sllv_epi32(__m512i __W, __mmask16 __U, __m512i __X, __m512i __Y) {
56565654
return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U,
56575655
(__v16si)_mm512_sllv_epi32(__X, __Y),
56585656
(__v16si)__W);
56595657
}
56605658

5661-
static __inline__ __m512i __DEFAULT_FN_ATTRS512
5662-
_mm512_maskz_sllv_epi32(__mmask16 __U, __m512i __X, __m512i __Y)
5663-
{
5659+
static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR
5660+
_mm512_maskz_sllv_epi32(__mmask16 __U, __m512i __X, __m512i __Y) {
56645661
return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U,
56655662
(__v16si)_mm512_sllv_epi32(__X, __Y),
56665663
(__v16si)_mm512_setzero_si512());
@@ -5732,23 +5729,20 @@ _mm512_maskz_sra_epi64(__mmask8 __U, __m512i __A, __m128i __B)
57325729
(__v8di)_mm512_setzero_si512());
57335730
}
57345731

5735-
static __inline__ __m512i __DEFAULT_FN_ATTRS512
5736-
_mm512_srav_epi32(__m512i __X, __m512i __Y)
5737-
{
5732+
static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR
5733+
_mm512_srav_epi32(__m512i __X, __m512i __Y) {
57385734
return (__m512i)__builtin_ia32_psrav16si((__v16si)__X, (__v16si)__Y);
57395735
}
57405736

5741-
static __inline__ __m512i __DEFAULT_FN_ATTRS512
5742-
_mm512_mask_srav_epi32(__m512i __W, __mmask16 __U, __m512i __X, __m512i __Y)
5743-
{
5737+
static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR
5738+
_mm512_mask_srav_epi32(__m512i __W, __mmask16 __U, __m512i __X, __m512i __Y) {
57445739
return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U,
57455740
(__v16si)_mm512_srav_epi32(__X, __Y),
57465741
(__v16si)__W);
57475742
}
57485743

5749-
static __inline__ __m512i __DEFAULT_FN_ATTRS512
5750-
_mm512_maskz_srav_epi32(__mmask16 __U, __m512i __X, __m512i __Y)
5751-
{
5744+
static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR
5745+
_mm512_maskz_srav_epi32(__mmask16 __U, __m512i __X, __m512i __Y) {
57525746
return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U,
57535747
(__v16si)_mm512_srav_epi32(__X, __Y),
57545748
(__v16si)_mm512_setzero_si512());
@@ -5820,23 +5814,20 @@ _mm512_maskz_srl_epi64(__mmask8 __U, __m512i __A, __m128i __B)
58205814
(__v8di)_mm512_setzero_si512());
58215815
}
58225816

5823-
static __inline__ __m512i __DEFAULT_FN_ATTRS512
5824-
_mm512_srlv_epi32(__m512i __X, __m512i __Y)
5825-
{
5817+
static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR
5818+
_mm512_srlv_epi32(__m512i __X, __m512i __Y) {
58265819
return (__m512i)__builtin_ia32_psrlv16si((__v16si)__X, (__v16si)__Y);
58275820
}
58285821

5829-
static __inline__ __m512i __DEFAULT_FN_ATTRS512
5830-
_mm512_mask_srlv_epi32(__m512i __W, __mmask16 __U, __m512i __X, __m512i __Y)
5831-
{
5822+
static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR
5823+
_mm512_mask_srlv_epi32(__m512i __W, __mmask16 __U, __m512i __X, __m512i __Y) {
58325824
return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U,
58335825
(__v16si)_mm512_srlv_epi32(__X, __Y),
58345826
(__v16si)__W);
58355827
}
58365828

5837-
static __inline__ __m512i __DEFAULT_FN_ATTRS512
5838-
_mm512_maskz_srlv_epi32(__mmask16 __U, __m512i __X, __m512i __Y)
5839-
{
5829+
static __inline__ __m512i __DEFAULT_FN_ATTRS512_CONSTEXPR
5830+
_mm512_maskz_srlv_epi32(__mmask16 __U, __m512i __X, __m512i __Y) {
58405831
return (__m512i)__builtin_ia32_selectd_512((__mmask16)__U,
58415832
(__v16si)_mm512_srlv_epi32(__X, __Y),
58425833
(__v16si)_mm512_setzero_si512());

clang/test/CodeGen/X86/avx512f-builtins.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5918,20 +5918,23 @@ __m512i test_mm512_sllv_epi32(__m512i __X, __m512i __Y) {
59185918
// CHECK: @llvm.x86.avx512.psllv.d.512
59195919
return _mm512_sllv_epi32(__X, __Y);
59205920
}
5921+
TEST_CONSTEXPR(match_v16si(_mm512_sllv_epi32((__m512i)(__v16si){1, -2, 3, -4, 5, -6, 7, -8, 1, -2, 3, -4, 5, -6, 7, -8}, (__m512i)(__v16si){1, 2, 3, 4, -17, 31, 33, 29, 29, 33, 31, -17, 4, 3, 2, 1}), 2, -8, 24, -64, 0, 0, 0, 0, 536870912, 0, -2147483648, 0, 80, -48, 28, -16));
59215922

59225923
__m512i test_mm512_mask_sllv_epi32(__m512i __W, __mmask16 __U, __m512i __X, __m512i __Y) {
59235924
// CHECK-LABEL: test_mm512_mask_sllv_epi32
59245925
// CHECK: @llvm.x86.avx512.psllv.d.512
59255926
// CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
59265927
return _mm512_mask_sllv_epi32(__W, __U, __X, __Y);
59275928
}
5929+
TEST_CONSTEXPR(match_v16si(_mm512_mask_sllv_epi32((__m512i)(__v16si){99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}, 0x912A, (__m512i)(__v16si){1, -2, 3, -4, 5, -6, 7, -8, 1, -2, 3, -4, 5, -6, 7, -8}, (__m512i)(__v16si){1, 2, 3, 4, -17, 31, 33, 29, 29, 33, 31, -17, 4, 3, 2, 1}), 99, -8, 99, -64, 99, 0, 99, 99, 536870912, 99, 99, 99, 80, 99, 99, -16));
59285930

59295931
__m512i test_mm512_maskz_sllv_epi32(__mmask16 __U, __m512i __X, __m512i __Y) {
59305932
// CHECK-LABEL: test_mm512_maskz_sllv_epi32
59315933
// CHECK: @llvm.x86.avx512.psllv.d.512
59325934
// CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
59335935
return _mm512_maskz_sllv_epi32(__U, __X, __Y);
59345936
}
5937+
TEST_CONSTEXPR(match_v16si(_mm512_maskz_sllv_epi32(0x3C8F, (__m512i)(__v16si){1, -2, 3, -4, 5, -6, 7, -8, 1, -2, 3, -4, 5, -6, 7, -8}, (__m512i)(__v16si){1, 2, 3, 4, -17, 31, 33, 29, 29, 33, 31, -17, 4, 3, 2, 1}), 2, -8, 24, -64, 0, 0, 0, 0, 0, 0, -2147483648, 0, 80, -48, 0, 0));
59355938

59365939
__m512i test_mm512_sllv_epi64(__m512i __X, __m512i __Y) {
59375940
// CHECK-LABEL: test_mm512_sllv_epi64
@@ -5998,20 +6001,23 @@ __m512i test_mm512_srav_epi32(__m512i __X, __m512i __Y) {
59986001
// CHECK: @llvm.x86.avx512.psrav.d.512
59996002
return _mm512_srav_epi32(__X, __Y);
60006003
}
6004+
TEST_CONSTEXPR(match_v16si(_mm512_srav_epi32((__m512i)(__v16si){1, -2, 3, -4, 5, -6, 7, -8, 1, -2, 3, -4, 5, -6, 7, -8}, (__m512i)(__v16si){1, 2, 3, 4, -17, 31, 33, 29, 29, 33, 31, -17, 4, 3, 2, 1}), 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 0, -1, 1, -4));
60016005

60026006
__m512i test_mm512_mask_srav_epi32(__m512i __W, __mmask16 __U, __m512i __X, __m512i __Y) {
60036007
// CHECK-LABEL: test_mm512_mask_srav_epi32
60046008
// CHECK: @llvm.x86.avx512.psrav.d.512
60056009
// CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
60066010
return _mm512_mask_srav_epi32(__W, __U, __X, __Y);
60076011
}
6012+
TEST_CONSTEXPR(match_v16si(_mm512_mask_srav_epi32((__m512i)(__v16si){99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}, 0x912A, (__m512i)(__v16si){1, -2, 3, -4, 5, -6, 7, -8, 1, -2, 3, -4, 5, -6, 7, -8}, (__m512i)(__v16si){1, 2, 3, 4, -17, 31, 33, 29, 29, 33, 31, -17, 4, 3, 2, 1}), 99, -1, 99, -1, 99, -1, 99, 99, 0, 99, 99, 99, 0, 99, 99, -4));
60086013

60096014
__m512i test_mm512_maskz_srav_epi32(__mmask16 __U, __m512i __X, __m512i __Y) {
60106015
// CHECK-LABEL: test_mm512_maskz_srav_epi32
60116016
// CHECK: @llvm.x86.avx512.psrav.d.512
60126017
// CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
60136018
return _mm512_maskz_srav_epi32(__U, __X, __Y);
60146019
}
6020+
TEST_CONSTEXPR(match_v16si(_mm512_maskz_srav_epi32(0x3C8F, (__m512i)(__v16si){1, -2, 3, -4, 5, -6, 7, -8, 1, -2, 3, -4, 5, -6, 7, -8}, (__m512i)(__v16si){1, 2, 3, 4, -17, 31, 33, 29, 29, 33, 31, -17, 4, 3, 2, 1}), 0, -1, 0, -1, 0, 0, 0, -1, 0, 0, 0, -1, 0, -1, 0, 0));
60156021

60166022
__m512i test_mm512_srav_epi64(__m512i __X, __m512i __Y) {
60176023
// CHECK-LABEL: test_mm512_srav_epi64
@@ -6078,20 +6084,23 @@ __m512i test_mm512_srlv_epi32(__m512i __X, __m512i __Y) {
60786084
// CHECK: @llvm.x86.avx512.psrlv.d.512
60796085
return _mm512_srlv_epi32(__X, __Y);
60806086
}
6087+
TEST_CONSTEXPR(match_v16si(_mm512_srlv_epi32((__m512i)(__v16si){1, -2, 3, -4, 5, -6, 7, -8, 1, -2, 3, -4, 5, -6, 7, -8}, (__m512i)(__v16si){1, 2, 3, 4, -17, 31, 33, 29, 29, 33, 31, -17, 4, 3, 2, 1}), 0, 1073741823, 0, 268435455, 0, 1, 0, 7, 0, 0, 0, 0, 0, 536870911, 1, 2147483644));
60816088

60826089
__m512i test_mm512_mask_srlv_epi32(__m512i __W, __mmask16 __U, __m512i __X, __m512i __Y) {
60836090
// CHECK-LABEL: test_mm512_mask_srlv_epi32
60846091
// CHECK: @llvm.x86.avx512.psrlv.d.512
60856092
// CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
60866093
return _mm512_mask_srlv_epi32(__W, __U, __X, __Y);
60876094
}
6095+
TEST_CONSTEXPR(match_v16si(_mm512_mask_srlv_epi32((__m512i)(__v16si){99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99, 99}, 0x912A, (__m512i)(__v16si){1, -2, 3, -4, 5, -6, 7, -8, 1, -2, 3, -4, 5, -6, 7, -8}, (__m512i)(__v16si){1, 2, 3, 4, -17, 31, 33, 29, 29, 33, 31, -17, 4, 3, 2, 1}), 99, 1073741823, 99, 268435455, 99, 1, 99, 99, 0, 99, 99, 99, 0, 99, 99, 2147483644));
60886096

60896097
__m512i test_mm512_maskz_srlv_epi32(__mmask16 __U, __m512i __X, __m512i __Y) {
60906098
// CHECK-LABEL: test_mm512_maskz_srlv_epi32
60916099
// CHECK: @llvm.x86.avx512.psrlv.d.512
60926100
// CHECK: select <16 x i1> %{{.*}}, <16 x i32> %{{.*}}, <16 x i32> %{{.*}}
60936101
return _mm512_maskz_srlv_epi32(__U, __X, __Y);
60946102
}
6103+
TEST_CONSTEXPR(match_v16si(_mm512_maskz_srlv_epi32(0x3C8F, (__m512i)(__v16si){1, -2, 3, -4, 5, -6, 7, -8, 1, -2, 3, -4, 5, -6, 7, -8}, (__m512i)(__v16si){1, 2, 3, 4, -17, 31, 33, 29, 29, 33, 31, -17, 4, 3, 2, 1}), 0, 1073741823, 0, 268435455, 0, 0, 0, 7, 0, 0, 0, 0, 0, 536870911, 0, 0));
60956104

60966105
__m512i test_mm512_srlv_epi64(__m512i __X, __m512i __Y) {
60976106
// CHECK-LABEL: test_mm512_srlv_epi64

0 commit comments

Comments
 (0)