Skip to content

Commit cf22bce

Browse files
authored
Merge pull request #79315 from meg-gupta/typevaluecse
Add CSE support for type_value instruction and add a few bounds check tests for InlineArray
2 parents 9595425 + 797dd8f commit cf22bce

File tree

4 files changed

+329
-1
lines changed

4 files changed

+329
-1
lines changed

lib/SIL/IR/SILInstruction.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,9 @@ namespace {
897897
return X->getElementType() == RHS->getElementType();
898898
}
899899

900+
bool visitTypeValueInst(const TypeValueInst *RHS) {
901+
return true;
902+
}
900903
private:
901904
const SILInstruction *LHS;
902905
};

lib/SILOptimizer/Transforms/CSE.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,13 @@ class HashVisitor : public SILInstructionVisitor<HashVisitor, llvm::hash_code> {
518518
llvm::hash_combine_range(Operands.begin(), Operands.end()),
519519
X->getElementType());
520520
}
521+
522+
hash_code visitTypeValueInst(TypeValueInst *X) {
523+
OperandValueArrayRef Operands(X->getAllOperands());
524+
return llvm::hash_combine(
525+
X->getKind(), X->getType(),
526+
llvm::hash_combine_range(Operands.begin(), Operands.end()));
527+
}
521528
};
522529
} // end anonymous namespace
523530

@@ -1231,6 +1238,7 @@ bool CSE::canHandle(SILInstruction *Inst) {
12311238
case SILInstructionKind::ScalarPackIndexInst:
12321239
case SILInstructionKind::DynamicPackIndexInst:
12331240
case SILInstructionKind::TuplePackElementAddrInst:
1241+
case SILInstructionKind::TypeValueInst:
12341242
// Intentionally we don't handle (prev_)dynamic_function_ref.
12351243
// They change at runtime.
12361244
#define LOADABLE_REF_STORAGE(Name, ...) \

test/SILOptimizer/cse_ossa.sil

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -update-borrowed-from -cse | %FileCheck %s
1+
// RUN: %target-sil-opt -sil-print-types -enable-sil-verify-all %s -update-borrowed-from -cse -enable-experimental-feature ValueGenerics | %FileCheck %s
2+
3+
// REQUIRES: swift_feature_ValueGenerics
4+
25
sil_stage canonical
36

47
import Builtin
@@ -1328,3 +1331,25 @@ exit(%proj : @guaranteed $C, %borrow : @guaranteed $S, %owned_s_2 : @owned $S):
13281331
return %copy : $C
13291332
}
13301333

1334+
// CHECK-LABEL: sil [ossa] @type_value_test : {{.*}} {
1335+
// CHECK: type_value
1336+
// CHECK-NOT: type_value
1337+
// CHECK-LABEL: } // end sil function 'type_value_test'
1338+
sil [ossa] @type_value_test : $@convention(thin) <let N : Int> (@in_guaranteed InlineArray<N, Int>, Int) -> () {
1339+
bb0(%0 : $*InlineArray<N, Int>, %1 : $Int):
1340+
%2 = integer_literal $Builtin.Int64, 0
1341+
%3 = type_value $Int for N
1342+
%4 = struct_extract %1, #Int._value
1343+
%5 = struct_extract %3, #Int._value
1344+
%6 = builtin "cmp_slt_Int64"(%4, %2) : $Builtin.Int1
1345+
cond_fail %6, "Index out of bounds"
1346+
%8 = integer_literal $Builtin.Int64, 0
1347+
%9 = type_value $Int for N
1348+
%10 = struct_extract %1, #Int._value
1349+
%11 = struct_extract %9, #Int._value
1350+
%12 = builtin "cmp_slt_Int64"(%10, %8) : $Builtin.Int1
1351+
cond_fail %12, "Index out of bounds"
1352+
%14 = tuple ()
1353+
return %14
1354+
}
1355+
Lines changed: 292 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,292 @@
1+
// RUN: %target-swift-frontend %s -emit-sil -O \
2+
// RUN: -disable-availability-checking \
3+
// RUN: -enable-experimental-feature ValueGenerics | %FileCheck %s --check-prefix=CHECK-SIL
4+
5+
// RUN: %target-swift-frontend %s -emit-ir -O \
6+
// RUN: -disable-availability-checking \
7+
// RUN: -enable-experimental-feature ValueGenerics | %FileCheck %s --check-prefix=CHECK-IR
8+
9+
// REQUIRES: swift_in_compiler
10+
// REQUIRES: swift_feature_ValueGenerics
11+
// REQUIRES: swift_stdlib_no_asserts, optimized_stdlib
12+
13+
// Bounds check should be eliminated
14+
// SIL removes lower bounds check from the loop
15+
// LLVM removes the upper bounds check from the loop and then vectorizes
16+
// A lower bounds check is left behind in the entry block
17+
18+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A29_sum_iterate_to_count_wo_trapySis11InlineArrayVyxSiGSiRVzlF :
19+
// CHECK-SIL: bb3
20+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
21+
// CHECK-SIL: cond_br
22+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A29_sum_iterate_to_count_wo_trapySis11InlineArrayVyxSiGSiRVzlF'
23+
24+
// CHECK-IR: define {{.*}} @"$s30inlinearray_bounds_check_tests0A29_sum_iterate_to_count_wo_trapySis11InlineArrayVyxSiGSiRVzlF"
25+
// CHECK-IR: @llvm.vector.reduce.add
26+
public func inlinearray_sum_iterate_to_count_wo_trap<let N: Int>(_ v: InlineArray<N, Int>) -> Int {
27+
var sum = 0
28+
for i in 0..<v.count {
29+
sum &+= v[i]
30+
}
31+
return sum
32+
}
33+
34+
// Bounds check should be eliminated
35+
// SIL removes lower bounds check from the loop
36+
// LLVM removes the upper bounds check from the loop
37+
// A lower bounds check is left behind in the entry block
38+
39+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A31_sum_iterate_to_count_with_trapySis11InlineArrayVyxSiGSiRVzlF :
40+
// CHECK-SIL: bb3
41+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
42+
// CHECK-SIL: cond_br
43+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A31_sum_iterate_to_count_with_trapySis11InlineArrayVyxSiGSiRVzlF'
44+
45+
public func inlinearray_sum_iterate_to_count_with_trap<let N: Int>(_ v: InlineArray<N, Int>) -> Int {
46+
var sum = 0
47+
for i in 0..<v.count {
48+
sum += v[i]
49+
}
50+
return sum
51+
}
52+
53+
// Bounds check should be hoisted
54+
// SIL removes lower bounds check from the loop
55+
// LLVM removes the upper bounds check from the loop and then vectorizes
56+
// A lower bounds check is left behind in the entry block
57+
58+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A31_sum_iterate_to_unknown_wo_trapySis11InlineArrayVyxSiG_SitSiRVzlF :
59+
// CHECK-SIL: bb3
60+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
61+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
62+
// CHECK-SIL: cond_br
63+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A31_sum_iterate_to_unknown_wo_trapySis11InlineArrayVyxSiG_SitSiRVzlF'
64+
65+
// CHECK-IR: define {{.*}} @"$s30inlinearray_bounds_check_tests0A31_sum_iterate_to_unknown_wo_trapySis11InlineArrayVyxSiG_SitSiRVzlF"
66+
// CHECK-IR: @llvm.vector.reduce.add
67+
public func inlinearray_sum_iterate_to_unknown_wo_trap<let N: Int>(_ v: InlineArray<N, Int>, _ n: Int) -> Int {
68+
var sum = 0
69+
for i in 0...n {
70+
sum &+= v[i]
71+
}
72+
return sum
73+
}
74+
75+
// Bounds check should be hoisted
76+
// SIL removes lower bounds check from the loop
77+
// LLVM removes the upper bounds check from the loop
78+
// A lower bounds check is left behind in the entry block
79+
80+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A33_sum_iterate_to_unknown_with_trapySis11InlineArrayVyxSiG_SitSiRVzlF :
81+
// CHECK-SIL: bb3
82+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
83+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
84+
// CHECK-SIL: cond_br
85+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A33_sum_iterate_to_unknown_with_trapySis11InlineArrayVyxSiG_SitSiRVzlF'
86+
public func inlinearray_sum_iterate_to_unknown_with_trap<let N: Int>(_ v: InlineArray<N, Int>, _ n: Int) -> Int {
87+
var sum = 0
88+
for i in 0...n {
89+
sum += v[i]
90+
}
91+
return sum
92+
}
93+
94+
// Bounds check should be eliminated
95+
// SIL removes lower bounds check from the loop
96+
// LLVM removes the upper bounds check from the loop and then vectorizes
97+
98+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A40_sum_iterate_to_deducible_count1_wo_trapySis11InlineArrayVyxSiG_SitSiRVzlF :
99+
// CHECK-SIL: bb3
100+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
101+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
102+
// CHECK-SIL: cond_br
103+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A40_sum_iterate_to_deducible_count1_wo_trapySis11InlineArrayVyxSiG_SitSiRVzlF'
104+
105+
// CHECK-IR: define {{.*}} @"$s30inlinearray_bounds_check_tests0A40_sum_iterate_to_deducible_count1_wo_trapySis11InlineArrayVyxSiG_SitSiRVzlF"
106+
// CHECK-IR: @llvm.vector.reduce.add
107+
public func inlinearray_sum_iterate_to_deducible_count1_wo_trap<let N: Int>(_ v: InlineArray<N, Int>, _ n: Int) -> Int {
108+
var sum = 0
109+
precondition(n <= v.count)
110+
for i in 0..<n {
111+
sum &+= v[i]
112+
}
113+
return sum
114+
}
115+
116+
// Bounds check should be eliminated
117+
// SIL removes lower bounds check from the loop
118+
// LLVM does not eliminate redundant bounds check
119+
120+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A42_sum_iterate_to_deducible_count1_with_trapySis11InlineArrayVyxSiG_SitSiRVzlF :
121+
// CHECK-SIL: bb3
122+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
123+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
124+
// CHECK-SIL: cond_br
125+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A42_sum_iterate_to_deducible_count1_with_trapySis11InlineArrayVyxSiG_SitSiRVzlF'
126+
public func inlinearray_sum_iterate_to_deducible_count1_with_trap<let N: Int>(_ v: InlineArray<N, Int>, _ n: Int) -> Int {
127+
var sum = 0
128+
precondition(n <= v.count)
129+
for i in 0..<n {
130+
sum += v[i]
131+
}
132+
return sum
133+
}
134+
135+
// Bounds check should be eliminated
136+
// SIL removes lower bounds check from the loop
137+
// LLVM removes upper bounds check and vectorizes the loop
138+
139+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A40_sum_iterate_to_deducible_count2_wo_trapySis11InlineArrayVyxSiG_SitSiRVzlF :
140+
// CHECK-SIL: bb3
141+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
142+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
143+
// CHECK-SIL: cond_br
144+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A40_sum_iterate_to_deducible_count2_wo_trapySis11InlineArrayVyxSiG_SitSiRVzlF'
145+
146+
// CHECK-IR: define {{.*}} @"$s30inlinearray_bounds_check_tests0A40_sum_iterate_to_deducible_count2_wo_trapySis11InlineArrayVyxSiG_SitSiRVzlF"
147+
// CHECK-IR: @llvm.vector.reduce.add
148+
public func inlinearray_sum_iterate_to_deducible_count2_wo_trap<let N: Int>(_ v: InlineArray<N, Int>, _ n: Int) -> Int {
149+
var sum = 0
150+
precondition(n <= v.count)
151+
for i in 0...n {
152+
sum &+= v[i]
153+
}
154+
return sum
155+
}
156+
157+
// Bounds check should be eliminated
158+
// SIL removes lower bounds check from the loop
159+
// LLVM does not eliminate redundant bounds check
160+
161+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A42_sum_iterate_to_deducible_count2_with_trapySis11InlineArrayVyxSiG_SitSiRVzlF :
162+
// CHECK-SIL: bb3
163+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
164+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
165+
// CHECK-SIL: cond_br
166+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A42_sum_iterate_to_deducible_count2_with_trapySis11InlineArrayVyxSiG_SitSiRVzlF'
167+
public func inlinearray_sum_iterate_to_deducible_count2_with_trap<let N: Int>(_ v: InlineArray<N, Int>, _ n: Int) -> Int {
168+
var sum = 0
169+
precondition(n <= v.count)
170+
for i in 0...n {
171+
sum += v[i]
172+
}
173+
return sum
174+
}
175+
176+
// Bounds check should be eliminated
177+
// SIL removes lower bounds check from the loop
178+
// LLVM removes upper bounds check and vectorizes the loop
179+
180+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A29_iterate_over_indices_wo_trapySis11InlineArrayVyxSiGSiRVzlF :
181+
// CHECK-SIL: bb3
182+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
183+
// CHECK-SIL: cond_br
184+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A29_iterate_over_indices_wo_trapySis11InlineArrayVyxSiGSiRVzlF'
185+
186+
// CHECK-IR: define {{.*}} @"$s30inlinearray_bounds_check_tests0A29_iterate_over_indices_wo_trapySis11InlineArrayVyxSiGSiRVzlF"
187+
// CHECK-IR: @llvm.vector.reduce.add
188+
public func inlinearray_iterate_over_indices_wo_trap<let N: Int>(_ v: InlineArray<N, Int>) -> Int {
189+
var sum = 0
190+
for i in v.indices {
191+
sum &+= v[i]
192+
}
193+
return sum
194+
}
195+
196+
// Bounds check should be eliminated
197+
// SIL removes lower bounds check from the loop
198+
// LLVM does not eliminate redundant bounds check
199+
200+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A31_iterate_over_indices_with_trapySis11InlineArrayVyxSiGSiRVzlF :
201+
// CHECK-SIL: bb3
202+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
203+
// CHECK-SIL: cond_br
204+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A31_iterate_over_indices_with_trapySis11InlineArrayVyxSiGSiRVzlF'
205+
public func inlinearray_iterate_over_indices_with_trap<let N: Int>(_ v: InlineArray<N, Int>) -> Int {
206+
var sum = 0
207+
for i in v.indices {
208+
sum += v[i]
209+
}
210+
return sum
211+
}
212+
213+
// Eliminate duplicate bounds check
214+
215+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A17_element_equalityySbs11InlineArrayVyxSiG_SitSiRVzlF :
216+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
217+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
218+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A17_element_equalityySbs11InlineArrayVyxSiG_SitSiRVzlF'
219+
220+
public func inlinearray_element_equality<let N: Int>(_ v: InlineArray<N, Int>, _ i: Int) -> Bool {
221+
return v[i] == v[i]
222+
}
223+
224+
// Eliminate duplicate bounds check
225+
226+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A12_element_sumySis11InlineArrayVyxSiG_SitSiRVzlF :
227+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
228+
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
229+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A12_element_sumySis11InlineArrayVyxSiG_SitSiRVzlF'
230+
public func inlinearray_element_sum<let N: Int>(_ v: InlineArray<N, Int>, _ i: Int) -> Int {
231+
return v[i] &+ v[i]
232+
}
233+
234+
// Bounds check should be eliminated
235+
236+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A7_searchySiSgs11InlineArrayVyq_xG_xtSiRV_SQRzr0_lF :
237+
// CHECK-SIL: bb3:
238+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
239+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
240+
// CHECK-SIL: cond_br
241+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A7_searchySiSgs11InlineArrayVyq_xG_xtSiRV_SQRzr0_lF'
242+
public func inlinearray_search<T : Equatable, let N: Int>(_ v: InlineArray<N, T>, _ elem: T) -> Int? {
243+
for i in v.indices {
244+
if v[i] == elem {
245+
return i
246+
}
247+
}
248+
return nil
249+
}
250+
251+
// Bounds check should be eliminated
252+
253+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A11_search_splySiSgs11InlineArrayVyxSiG_SitSiRVzlF :
254+
// CHECK-SIL: bb3:
255+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
256+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
257+
// CHECK-SIL: cond_br
258+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A11_search_splySiSgs11InlineArrayVyxSiG_SitSiRVzlF'
259+
public func inlinearray_search_spl<let N: Int>(_ v: InlineArray<N, Int>, _ elem: Int) -> Int? {
260+
for i in v.indices {
261+
if v[i] == elem {
262+
return i
263+
}
264+
}
265+
return nil
266+
}
267+
268+
// Bounds check should be eliminated
269+
270+
// CHECK-SIL-LABEL: sil @$s30inlinearray_bounds_check_tests0A18_binary_search_splySiSgs11InlineArrayVyxSiG_SitSiRVzlF :
271+
// CHECK-SIL: bb2
272+
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
273+
// CHECK-SIL: cond_br
274+
// CHECK-SIL-LABEL: } // end sil function '$s30inlinearray_bounds_check_tests0A18_binary_search_splySiSgs11InlineArrayVyxSiG_SitSiRVzlF'
275+
public func inlinearray_binary_search_spl<let N: Int>(_ v: InlineArray<N, Int>, _ elem: Int) -> Int? {
276+
var low = 0, high = v.count - 1
277+
while low <= high {
278+
let mid = low + (high - low) / 2
279+
280+
if v[mid] == elem {
281+
return mid
282+
}
283+
else if v[mid] < elem {
284+
low = mid + 1
285+
} else {
286+
high = mid - 1
287+
}
288+
}
289+
290+
return nil;
291+
}
292+

0 commit comments

Comments
 (0)