Skip to content

Commit a52dcfc

Browse files
committed
Added opt. Updated tests.
1 parent b784fa9 commit a52dcfc

30 files changed

+280
-207
lines changed

clang/test/CodeGen/AArch64/ls64-inline-asm.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@ void store(const struct foo *input, void *addr)
6969
// CHECK-NEXT: [[S_SROA_6_0_INSERT_INSERT:%.*]] = or disjoint i512 [[S_SROA_7_0_INSERT_INSERT]], [[S_SROA_6_0_INSERT_SHIFT]]
7070
// CHECK-NEXT: [[S_SROA_5_0_INSERT_EXT:%.*]] = zext i64 [[CONV5]] to i512
7171
// CHECK-NEXT: [[S_SROA_5_0_INSERT_SHIFT:%.*]] = shl nuw nsw i512 [[S_SROA_5_0_INSERT_EXT]], 128
72+
// CHECK-NEXT: [[S_SROA_5_0_INSERT_INSERT:%.*]] = or disjoint i512 [[S_SROA_6_0_INSERT_INSERT]], [[S_SROA_5_0_INSERT_SHIFT]]
7273
// CHECK-NEXT: [[S_SROA_4_0_INSERT_EXT:%.*]] = zext i64 [[CONV2]] to i512
7374
// CHECK-NEXT: [[S_SROA_4_0_INSERT_SHIFT:%.*]] = shl nuw nsw i512 [[S_SROA_4_0_INSERT_EXT]], 64
74-
// CHECK-NEXT: [[S_SROA_4_0_INSERT_MASK:%.*]] = or disjoint i512 [[S_SROA_6_0_INSERT_INSERT]], [[S_SROA_5_0_INSERT_SHIFT]]
75+
// CHECK-NEXT: [[S_SROA_4_0_INSERT_INSERT:%.*]] = or disjoint i512 [[S_SROA_5_0_INSERT_INSERT]], [[S_SROA_4_0_INSERT_SHIFT]]
7576
// CHECK-NEXT: [[S_SROA_0_0_INSERT_EXT:%.*]] = zext i64 [[CONV]] to i512
76-
// CHECK-NEXT: [[S_SROA_0_0_INSERT_MASK:%.*]] = or disjoint i512 [[S_SROA_4_0_INSERT_MASK]], [[S_SROA_4_0_INSERT_SHIFT]]
77-
// CHECK-NEXT: [[S_SROA_0_0_INSERT_INSERT:%.*]] = or i512 [[S_SROA_0_0_INSERT_MASK]], [[S_SROA_0_0_INSERT_EXT]]
77+
// CHECK-NEXT: [[S_SROA_0_0_INSERT_INSERT:%.*]] = or disjoint i512 [[S_SROA_4_0_INSERT_INSERT]], [[S_SROA_0_0_INSERT_EXT]]
7878
// CHECK-NEXT: tail call void asm sideeffect "st64b $0,[$1]", "r,r,~{memory}"(i512 [[S_SROA_0_0_INSERT_INSERT]], ptr [[ADDR]]) #[[ATTR1]], !srcloc [[META8:![0-9]+]]
7979
// CHECK-NEXT: ret void
8080
//
@@ -90,5 +90,5 @@ void store2(int *in, void *addr)
9090
// CHECK: [[META5]] = !{!"Simple C/C++ TBAA"}
9191
// CHECK: [[META6]] = !{i64 789}
9292
// CHECK: [[META7]] = !{i64 1368}
93-
// CHECK: [[META8]] = !{i64 5992}
93+
// CHECK: [[META8]] = !{i64 6009}
9494
//.

llvm/include/llvm/Analysis/ValueTracking.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class TargetLibraryInfo;
4444
class IntrinsicInst;
4545
template <typename T> class ArrayRef;
4646

47-
constexpr unsigned MaxAnalysisRecursionDepth = 6;
47+
constexpr unsigned MaxAnalysisRecursionDepth = 20;
4848

4949
/// The max limit of the search depth in DecomposeGEPExpression() and
5050
/// getUnderlyingObject().

llvm/lib/Analysis/ValueTracking.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
#include "llvm/Support/Casting.h"
7272
#include "llvm/Support/CommandLine.h"
7373
#include "llvm/Support/Compiler.h"
74+
#include "llvm/Support/Debug.h"
7475
#include "llvm/Support/ErrorHandling.h"
7576
#include "llvm/Support/KnownBits.h"
7677
#include "llvm/Support/KnownFPClass.h"
@@ -2367,9 +2368,29 @@ void computeKnownBits(const Value *V, const APInt &DemandedElts,
23672368
}
23682369

23692370
// Aligned pointers have trailing zeros - refine Known.Zero set
2371+
auto SameFunction = [](auto A, auto B) {
2372+
return A->getParent()->getParent() == B->getParent()->getParent();
2373+
};
23702374
if (isa<PointerType>(V->getType())) {
23712375
Align Alignment = V->getPointerAlignment(Q.DL);
23722376
Known.Zero.setLowBits(Log2(Alignment));
2377+
for (auto *User : V->users()) {
2378+
if (auto *Load = dyn_cast<LoadInst>(User)) {
2379+
if (!Q.CxtI || !SameFunction(Load, Q.CxtI) ||
2380+
!isValidAssumeForContext(Load, Q.CxtI, Q.DT)) {
2381+
continue;
2382+
}
2383+
Known.Zero.setLowBits(Log2(Load->getAlign()));
2384+
}
2385+
if (auto *Store = dyn_cast<StoreInst>(User)) {
2386+
if (Store->getPointerOperand() != V ||
2387+
(!Q.CxtI || !SameFunction(Store, Q.CxtI) ||
2388+
!isValidAssumeForContext(Store, Q.CxtI, Q.DT))) {
2389+
continue;
2390+
}
2391+
Known.Zero.setLowBits(Log2(Store->getAlign()));
2392+
}
2393+
}
23732394
}
23742395

23752396
// computeKnownBitsFromContext strictly refines Known.

llvm/test/Analysis/ScalarEvolution/shift-recurrences.ll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -558,11 +558,11 @@ define void @test_ashr_tc_either(i1 %a) {
558558
; CHECK-NEXT: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ]
559559
; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%loop> U: [0,61) S: [0,61) Exits: 60 LoopDispositions: { %loop: Computable }
560560
; CHECK-NEXT: %iv.ashr = phi i8 [ %start, %entry ], [ %iv.ashr.next, %loop ]
561-
; CHECK-NEXT: --> %iv.ashr U: [-16,16) S: [-16,16) Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
561+
; CHECK-NEXT: --> %iv.ashr U: [-1,1) S: [-1,1) Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
562562
; CHECK-NEXT: %iv.next = add i64 %iv, 1
563563
; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%loop> U: [1,62) S: [1,62) Exits: 61 LoopDispositions: { %loop: Computable }
564564
; CHECK-NEXT: %iv.ashr.next = ashr i8 %iv.ashr, 1
565-
; CHECK-NEXT: --> %iv.ashr.next U: [-16,16) S: [-16,16) Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
565+
; CHECK-NEXT: --> %iv.ashr.next U: [-1,1) S: [-1,1) Exits: <<Unknown>> LoopDispositions: { %loop: Variant }
566566
; CHECK-NEXT: Determining loop execution counts for: @test_ashr_tc_either
567567
; CHECK-NEXT: Loop %loop: backedge-taken count is i64 60
568568
; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 60

llvm/test/Analysis/ValueTracking/monotonic-phi.ll

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -628,13 +628,10 @@ define i1 @test_ashr_zero_start(i8 %n) {
628628
; CHECK-NEXT: entry:
629629
; CHECK-NEXT: br label [[LOOP:%.*]]
630630
; CHECK: loop:
631-
; CHECK-NEXT: [[A:%.*]] = phi i8 [ 0, [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ]
632-
; CHECK-NEXT: [[NEXT]] = ashr exact i8 [[A]], 1
633-
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 [[A]], [[N:%.*]]
631+
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i8 0, [[N:%.*]]
634632
; CHECK-NEXT: br i1 [[CMP1]], label [[EXIT:%.*]], label [[LOOP]]
635633
; CHECK: exit:
636-
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i8 [[A]], 0
637-
; CHECK-NEXT: ret i1 [[CMP]]
634+
; CHECK-NEXT: ret i1 true
638635
;
639636
entry:
640637
br label %loop

llvm/test/CodeGen/BPF/cc_args.ll

Lines changed: 76 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,45 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
12
; RUN: llc < %s -mtriple=bpfel -mcpu=v1 -show-mc-encoding | FileCheck %s
23

34
define void @test() #0 {
5+
; CHECK-LABEL: test:
6+
; CHECK: # %bb.0: # %entry
7+
; CHECK-NEXT: r1 = 123 # encoding: [0xb7,0x01,0x00,0x00,0x7b,0x00,0x00,0x00]
8+
; CHECK-NEXT: call f_i16 # encoding: [0x85'A',A,A,A,0x00,0x00,0x00,0x00]
9+
; CHECK-NEXT: # fixup A - offset: 0, value: f_i16, kind: FK_PCRel_4
10+
; CHECK-NEXT: r1 = 12345678 # encoding: [0xb7,0x01,0x00,0x00,0x4e,0x61,0xbc,0x00]
11+
; CHECK-NEXT: call f_i32 # encoding: [0x85'A',A,A,A,0x00,0x00,0x00,0x00]
12+
; CHECK-NEXT: # fixup A - offset: 0, value: f_i32, kind: FK_PCRel_4
13+
; CHECK-NEXT: r1 = 72623859790382856 ll # encoding: [0x18,0x01,0x00,0x00,0x08,0x07,0x06,0x05,0x00,0x00,0x00,0x00,0x04,0x03,0x02,0x01]
14+
; CHECK-NEXT: call f_i64 # encoding: [0x85'A',A,A,A,0x00,0x00,0x00,0x00]
15+
; CHECK-NEXT: # fixup A - offset: 0, value: f_i64, kind: FK_PCRel_4
16+
; CHECK-NEXT: r1 = 1234 # encoding: [0xb7,0x01,0x00,0x00,0xd2,0x04,0x00,0x00]
17+
; CHECK-NEXT: r2 = 5678 # encoding: [0xb7,0x02,0x00,0x00,0x2e,0x16,0x00,0x00]
18+
; CHECK-NEXT: call f_i32_i32 # encoding: [0x85'A',A,A,A,0x00,0x00,0x00,0x00]
19+
; CHECK-NEXT: # fixup A - offset: 0, value: f_i32_i32, kind: FK_PCRel_4
20+
; CHECK-NEXT: r1 = 2 # encoding: [0xb7,0x01,0x00,0x00,0x02,0x00,0x00,0x00]
21+
; CHECK-NEXT: r2 = 3 # encoding: [0xb7,0x02,0x00,0x00,0x03,0x00,0x00,0x00]
22+
; CHECK-NEXT: r3 = 4 # encoding: [0xb7,0x03,0x00,0x00,0x04,0x00,0x00,0x00]
23+
; CHECK-NEXT: call f_i16_i32_i16 # encoding: [0x85'A',A,A,A,0x00,0x00,0x00,0x00]
24+
; CHECK-NEXT: # fixup A - offset: 0, value: f_i16_i32_i16, kind: FK_PCRel_4
25+
; CHECK-NEXT: r1 = 5 # encoding: [0xb7,0x01,0x00,0x00,0x05,0x00,0x00,0x00]
26+
; CHECK-NEXT: r2 = 7262385979038285 ll # encoding: [0x18,0x02,0x00,0x00,0x4d,0x9a,0x80,0x00,0x00,0x00,0x00,0x00,0x1a,0xcd,0x19,0x00]
27+
; CHECK-NEXT: r3 = 6 # encoding: [0xb7,0x03,0x00,0x00,0x06,0x00,0x00,0x00]
28+
; CHECK-NEXT: call f_i16_i64_i16 # encoding: [0x85'A',A,A,A,0x00,0x00,0x00,0x00]
29+
; CHECK-NEXT: # fixup A - offset: 0, value: f_i16_i64_i16, kind: FK_PCRel_4
30+
; CHECK-NEXT: exit # encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
431
entry:
5-
; CHECK: test:
632

7-
; CHECK: r1 = 123 # encoding: [0xb7,0x01,0x00,0x00,0x7b,0x00,0x00,0x00]
8-
; CHECK: call f_i16
933
call void @f_i16(i16 123)
1034

11-
; CHECK: r1 = 12345678 # encoding: [0xb7,0x01,0x00,0x00,0x4e,0x61,0xbc,0x00]
12-
; CHECK: call f_i32
1335
call void @f_i32(i32 12345678)
1436

15-
; CHECK: r1 = 72623859790382856 ll # encoding: [0x18,0x01,0x00,0x00,0x08,0x07,0x06,0x05,0x00,0x00,0x00,0x00,0x04,0x03,0x02,0x01]
16-
; CHECK: call f_i64
1737
call void @f_i64(i64 72623859790382856)
1838

19-
; CHECK: r1 = 1234
20-
; CHECK: r2 = 5678
21-
; CHECK: call f_i32_i32
2239
call void @f_i32_i32(i32 1234, i32 5678)
2340

24-
; CHECK: r1 = 2
25-
; CHECK: r2 = 3
26-
; CHECK: r3 = 4
27-
; CHECK: call f_i16_i32_i16
2841
call void @f_i16_i32_i16(i16 2, i32 3, i16 4)
2942

30-
; CHECK: r1 = 5
31-
; CHECK: r2 = 7262385979038285 ll
32-
; CHECK: r3 = 6
33-
; CHECK: call f_i16_i64_i16
3443
call void @f_i16_i64_i16(i16 5, i64 7262385979038285, i16 6)
3544

3645
ret void
@@ -41,55 +50,85 @@ entry:
4150
@g_i64 = common global i64 0, align 4
4251

4352
define void @f_i16(i16 %a) #0 {
44-
; CHECK: f_i16:
45-
; CHECK: *(u16 *)(r2 + 0) = r1 # encoding: [0x6b,0x12,0x00,0x00,0x00,0x00,0x00,0x00]
53+
; CHECK-LABEL: f_i16:
54+
; CHECK: # %bb.0:
55+
; CHECK-NEXT: r2 = g_i16 ll # encoding: [0x18'A',0x02'A',A,A,A,A,A,A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
56+
; CHECK-NEXT: # fixup A - offset: 0, value: g_i16, kind: FK_SecRel_8
57+
; CHECK-NEXT: *(u16 *)(r2 + 0) = r1 # encoding: [0x6b,0x12,0x00,0x00,0x00,0x00,0x00,0x00]
58+
; CHECK-NEXT: exit # encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
4659
store volatile i16 %a, ptr @g_i16, align 2
4760
ret void
4861
}
4962

5063
define void @f_i32(i32 %a) #0 {
51-
; CHECK: f_i32:
52-
; CHECK: *(u16 *)(r2 + 0) = r1 # encoding: [0x6b,0x12,0x00,0x00,0x00,0x00,0x00,0x00]
53-
; CHECK: *(u16 *)(r2 + 2) = r1 # encoding: [0x6b,0x12,0x02,0x00,0x00,0x00,0x00,0x00]
64+
; CHECK-LABEL: f_i32:
65+
; CHECK: # %bb.0:
66+
; CHECK-NEXT: r2 = g_i32 ll # encoding: [0x18'A',0x02'A',A,A,A,A,A,A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
67+
; CHECK-NEXT: # fixup A - offset: 0, value: g_i32, kind: FK_SecRel_8
68+
; CHECK-NEXT: *(u16 *)(r2 + 0) = r1 # encoding: [0x6b,0x12,0x00,0x00,0x00,0x00,0x00,0x00]
69+
; CHECK-NEXT: r1 >>= 16 # encoding: [0x77,0x01,0x00,0x00,0x10,0x00,0x00,0x00]
70+
; CHECK-NEXT: *(u16 *)(r2 + 2) = r1 # encoding: [0x6b,0x12,0x02,0x00,0x00,0x00,0x00,0x00]
71+
; CHECK-NEXT: exit # encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
5472
store volatile i32 %a, ptr @g_i32, align 2
5573
ret void
5674
}
5775

5876
define void @f_i64(i64 %a) #0 {
59-
; CHECK: f_i64:
60-
; CHECK: *(u32 *)(r2 + 0) = r1
61-
; CHECK: *(u32 *)(r2 + 4) = r1 # encoding: [0x63,0x12,0x04,0x00,0x00,0x00,0x00,0x00]
77+
; CHECK-LABEL: f_i64:
78+
; CHECK: # %bb.0:
79+
; CHECK-NEXT: r2 = g_i64 ll # encoding: [0x18'A',0x02'A',A,A,A,A,A,A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
80+
; CHECK-NEXT: # fixup A - offset: 0, value: g_i64, kind: FK_SecRel_8
81+
; CHECK-NEXT: *(u32 *)(r2 + 0) = r1 # encoding: [0x63,0x12,0x00,0x00,0x00,0x00,0x00,0x00]
82+
; CHECK-NEXT: r1 >>= 32 # encoding: [0x77,0x01,0x00,0x00,0x20,0x00,0x00,0x00]
83+
; CHECK-NEXT: *(u32 *)(r2 + 4) = r1 # encoding: [0x63,0x12,0x04,0x00,0x00,0x00,0x00,0x00]
84+
; CHECK-NEXT: exit # encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
6285
store volatile i64 %a, ptr @g_i64, align 2
6386
ret void
6487
}
6588

6689
define void @f_i32_i32(i32 %a, i32 %b) #0 {
67-
; CHECK: f_i32_i32:
68-
; CHECK: *(u32 *)(r3 + 0) = r1
90+
; CHECK-LABEL: f_i32_i32:
91+
; CHECK: # %bb.0:
92+
; CHECK-NEXT: r3 = g_i32 ll # encoding: [0x18'A',0x03'A',A,A,A,A,A,A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
93+
; CHECK-NEXT: # fixup A - offset: 0, value: g_i32, kind: FK_SecRel_8
94+
; CHECK-NEXT: *(u32 *)(r3 + 0) = r1 # encoding: [0x63,0x13,0x00,0x00,0x00,0x00,0x00,0x00]
95+
; CHECK-NEXT: *(u32 *)(r3 + 0) = r2 # encoding: [0x63,0x23,0x00,0x00,0x00,0x00,0x00,0x00]
96+
; CHECK-NEXT: exit # encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
6997
store volatile i32 %a, ptr @g_i32, align 4
70-
; CHECK: *(u32 *)(r3 + 0) = r2
7198
store volatile i32 %b, ptr @g_i32, align 4
7299
ret void
73100
}
74101

75102
define void @f_i16_i32_i16(i16 %a, i32 %b, i16 %c) #0 {
76-
; CHECK: f_i16_i32_i16:
77-
; CHECK: *(u16 *)(r4 + 0) = r1
103+
; CHECK-LABEL: f_i16_i32_i16:
104+
; CHECK: # %bb.0:
105+
; CHECK-NEXT: r4 = g_i16 ll # encoding: [0x18'A',0x04'A',A,A,A,A,A,A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
106+
; CHECK-NEXT: # fixup A - offset: 0, value: g_i16, kind: FK_SecRel_8
107+
; CHECK-NEXT: *(u16 *)(r4 + 0) = r1 # encoding: [0x6b,0x14,0x00,0x00,0x00,0x00,0x00,0x00]
108+
; CHECK-NEXT: r1 = g_i32 ll # encoding: [0x18'A',0x01'A',A,A,A,A,A,A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
109+
; CHECK-NEXT: # fixup A - offset: 0, value: g_i32, kind: FK_SecRel_8
110+
; CHECK-NEXT: *(u32 *)(r1 + 0) = r2 # encoding: [0x63,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
111+
; CHECK-NEXT: *(u16 *)(r4 + 0) = r3 # encoding: [0x6b,0x34,0x00,0x00,0x00,0x00,0x00,0x00]
112+
; CHECK-NEXT: exit # encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
78113
store volatile i16 %a, ptr @g_i16, align 2
79-
; CHECK: *(u32 *)(r1 + 0) = r2
80114
store volatile i32 %b, ptr @g_i32, align 4
81-
; CHECK: *(u16 *)(r4 + 0) = r3
82115
store volatile i16 %c, ptr @g_i16, align 2
83116
ret void
84117
}
85118

86119
define void @f_i16_i64_i16(i16 %a, i64 %b, i16 %c) #0 {
87-
; CHECK: f_i16_i64_i16:
88-
; CHECK: *(u16 *)(r4 + 0) = r1
120+
; CHECK-LABEL: f_i16_i64_i16:
121+
; CHECK: # %bb.0:
122+
; CHECK-NEXT: r4 = g_i16 ll # encoding: [0x18'A',0x04'A',A,A,A,A,A,A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
123+
; CHECK-NEXT: # fixup A - offset: 0, value: g_i16, kind: FK_SecRel_8
124+
; CHECK-NEXT: *(u16 *)(r4 + 0) = r1 # encoding: [0x6b,0x14,0x00,0x00,0x00,0x00,0x00,0x00]
125+
; CHECK-NEXT: r1 = g_i64 ll # encoding: [0x18'A',0x01'A',A,A,A,A,A,A,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
126+
; CHECK-NEXT: # fixup A - offset: 0, value: g_i64, kind: FK_SecRel_8
127+
; CHECK-NEXT: *(u64 *)(r1 + 0) = r2 # encoding: [0x7b,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
128+
; CHECK-NEXT: *(u16 *)(r4 + 0) = r3 # encoding: [0x6b,0x34,0x00,0x00,0x00,0x00,0x00,0x00]
129+
; CHECK-NEXT: exit # encoding: [0x95,0x00,0x00,0x00,0x00,0x00,0x00,0x00]
89130
store volatile i16 %a, ptr @g_i16, align 2
90-
; CHECK: *(u64 *)(r1 + 0) = r2 # encoding: [0x7b,0x21,0x00,0x00,0x00,0x00,0x00,0x00]
91131
store volatile i64 %b, ptr @g_i64, align 8
92-
; CHECK: *(u16 *)(r4 + 0) = r3
93132
store volatile i16 %c, ptr @g_i16, align 2
94133
ret void
95134
}

0 commit comments

Comments
 (0)