Files
swift-mirror/test/SILOptimizer/span_bounds_check_tests.swift
Erik Eckstein 27dc031d1e IRGen: better code generation for the _assumeNonNegative intrinsic
So far we only supported this for `load` and `call` arguments. Now we use `llvm.assume` for other kind of argument values.
This helps optimizing bounds checking for `Span`.
2025-07-22 12:42:54 +02:00

345 lines
12 KiB
Swift

// RUN: %target-swift-frontend %s -emit-sil -O \
// RUN: -disable-availability-checking \
// RUN: -enable-experimental-feature Lifetimes \
// RUN: | %FileCheck %s --check-prefix=CHECK-SIL
// RUN: %target-swift-frontend %s -emit-ir -O \
// RUN: -disable-availability-checking \
// RUN: -enable-experimental-feature Lifetimes \
// RUN: | %FileCheck %s --check-prefix=CHECK-IR
// REQUIRES: swift_in_compiler
// REQUIRES: swift_feature_Lifetimes
// REQUIRES: swift_stdlib_no_asserts, optimized_stdlib
// Bounds check should be eliminated
// SIL optimizer eliminates bounds checks from the loop
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A29_sum_iterate_to_count_wo_trapySis4SpanVySiGF :
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: bb3
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A29_sum_iterate_to_count_wo_trapySis4SpanVySiGF'
// CHECK-IR: define {{.*}} @"$s23span_bounds_check_tests0A29_sum_iterate_to_count_wo_trapySis4SpanVySiGF"
// CHECK-IR: @llvm.vector.reduce.add
public func span_sum_iterate_to_count_wo_trap(_ v: Span<Int>) -> Int {
var sum = 0
for i in 0..<v.count {
sum &+= v[i]
}
return sum &+ 1 // adding 1 to avoid LLVM function merging
}
// Bounds check should be eliminated
// SIL optimizer eliminates bounds checks from the loop
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A31_sum_iterate_to_count_with_trapySis4SpanVySiGF :
// CHECK-SIL: bb1
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: bb3
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A31_sum_iterate_to_count_with_trapySis4SpanVySiGF'
public func span_sum_iterate_to_count_with_trap(_ v: Span<Int>) -> Int {
var sum = 0
for i in 0..<v.count {
sum += v[i]
}
return sum
}
// Bounds check should be hoisted
// SIL optimizer hoists bounds checks from the loop
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A31_sum_iterate_to_unknown_wo_trapySis4SpanVySiG_SitF :
// CHECK-SIL: bb1
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: bb3
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A31_sum_iterate_to_unknown_wo_trapySis4SpanVySiG_SitF'
// CHECK-IR: define {{.*}} @"$s23span_bounds_check_tests0A31_sum_iterate_to_unknown_wo_trapySis4SpanVySiG_SitF"
// CHECK-IR: @llvm.vector.reduce.add
public func span_sum_iterate_to_unknown_wo_trap(_ v: Span<Int>, _ n: Int) -> Int {
var sum = 0
for i in 0...n {
sum &+= v[i]
}
return sum
}
// Bounds check should be hoisted
// SIL optimizer hoists bounds checks from the loop
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A33_sum_iterate_to_unknown_with_trapySis4SpanVySiG_SitF :
// CHECK-SIL: bb1
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: bb3
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A33_sum_iterate_to_unknown_with_trapySis4SpanVySiG_SitF'
public func span_sum_iterate_to_unknown_with_trap(_ v: Span<Int>, _ n: Int) -> Int {
var sum = 0
for i in 0...n {
sum += v[i]
}
return sum
}
// Bounds check should be eliminated
// SIL optimizer hoists bounds checks from the loop
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A40_sum_iterate_to_deducible_count1_wo_trapySis4SpanVySiG_SitF :
// CHECK-SIL: bb3
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A40_sum_iterate_to_deducible_count1_wo_trapySis4SpanVySiG_SitF'
// CHECK-IR: define {{.*}} @"$s23span_bounds_check_tests0A40_sum_iterate_to_deducible_count1_wo_trapySis4SpanVySiG_SitF"
// CHECK-IR: @llvm.vector.reduce.add
public func span_sum_iterate_to_deducible_count1_wo_trap(_ v: Span<Int>, _ n: Int) -> Int {
var sum = 0
precondition(n <= v.count)
for i in 0..<n {
sum &+= v[i]
}
return sum
}
// Bounds check should be eliminated
// SIL optimizer hoists bounds checks from the loop
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A42_sum_iterate_to_deducible_count1_with_trapySis4SpanVySiG_SitF :
// CHECK-SIL: bb1
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: bb3
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A42_sum_iterate_to_deducible_count1_with_trapySis4SpanVySiG_SitF'
public func span_sum_iterate_to_deducible_count1_with_trap(_ v: Span<Int>, _ n: Int) -> Int {
var sum = 0
precondition(n <= v.count)
for i in 0..<n {
sum += v[i]
}
return sum
}
// Bounds check should be eliminated
// SIL optimizer hoists bounds checks from the loop
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A40_sum_iterate_to_deducible_count2_wo_trapySis4SpanVySiG_SitF :
// CHECK-SIL: bb1
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: bb3
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A40_sum_iterate_to_deducible_count2_wo_trapySis4SpanVySiG_SitF'
// CHECK-IR: define {{.*}} @"$s23span_bounds_check_tests0A40_sum_iterate_to_deducible_count2_wo_trapySis4SpanVySiG_SitF"
// CHECK-IR: @llvm.vector.reduce.add
public func span_sum_iterate_to_deducible_count2_wo_trap(_ v: Span<Int>, _ n: Int) -> Int {
var sum = 0
precondition(n <= v.count)
for i in 0...n {
sum &+= v[i]
}
return sum
}
// Bounds check should be eliminated
// SIL optimizer hoists bounds checks from the loop
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A42_sum_iterate_to_deducible_count2_with_trapySis4SpanVySiG_SitF :
// CHECK-SIL: bb1
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: bb3
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A42_sum_iterate_to_deducible_count2_with_trapySis4SpanVySiG_SitF'
public func span_sum_iterate_to_deducible_count2_with_trap(_ v: Span<Int>, _ n: Int) -> Int {
var sum = 0
precondition(n <= v.count)
for i in 0...n {
sum += v[i]
}
return sum
}
// Bounds check should be eliminated
// TODO: there should not be any cond_fail in this function
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A29_iterate_over_indices_wo_trapySis4SpanVySiGF :
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A29_iterate_over_indices_wo_trapySis4SpanVySiGF'
// CHECK-IR: define {{.*}} @"$s23span_bounds_check_tests0A29_iterate_over_indices_wo_trapySis4SpanVySiGF"
// CHECK-IR: @llvm.vector.reduce.add
public func span_iterate_over_indices_wo_trap(_ v: Span<Int>) -> Int {
var sum = 0
for i in v.indices {
sum &+= v[i]
}
return sum
}
// Bounds check should be eliminated
// SIL optimizer hoists bounds checks from the loop
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A31_iterate_over_indices_with_trapySis4SpanVySiGF :
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A31_iterate_over_indices_with_trapySis4SpanVySiGF'
public func span_iterate_over_indices_with_trap(_ v: Span<Int>) -> Int {
var sum = 0
for i in v.indices {
sum += v[i]
}
return sum
}
// Eliminate duplicate bounds check
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A17_element_equalityySbs4SpanVySiG_SitF :
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A17_element_equalityySbs4SpanVySiG_SitF'
public func span_element_equality(_ v: Span<Int>, _ i: Int) -> Bool {
return v[i] == v[i]
}
// Eliminate duplicate bounds check
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A12_element_sumySis4SpanVySiG_SitF :
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A12_element_sumySis4SpanVySiG_SitF'
public func span_element_sum(_ v: Span<Int>, _ i: Int) -> Int {
return v[i] &+ v[i]
}
// Bounds check should be eliminated
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A7_searchySiSgs4SpanVyxG_xtSQRzlF :
// CHECK-SIL: bb3:
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A7_searchySiSgs4SpanVyxG_xtSQRzlF'
public func span_search<T : Equatable>(_ v: Span<T>, _ elem: T) -> Int? {
for i in v.indices {
if v[i] == elem {
return i
}
}
return nil
}
// TODO: Bounds check should be eliminated
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A11_search_splySiSgs4SpanVySiG_SitF :
// CHECK-SIL: bb3:
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A11_search_splySiSgs4SpanVySiG_SitF'
public func span_search_spl(_ v: Span<Int>, _ elem: Int) -> Int? {
for i in v.indices {
if v[i] == elem {
return i
}
}
return nil
}
// Bounds check should be eliminated
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A18_binary_search_splySiSgs4SpanVySiG_SitF :
// CHECK-SIL: bb2
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A18_binary_search_splySiSgs4SpanVySiG_SitF'
public func span_binary_search_spl(_ v: Span<Int>, _ elem: Int) -> Int? {
var low = 0, high = v.count - 1
while low <= high {
let mid = low + (high - low) / 2
if v[mid] == elem {
return mid
}
else if v[mid] < elem {
low = mid + 1
} else {
high = mid - 1
}
}
return nil;
}
public struct Wrapper<Int> : ~Escapable {
let s: Span<Int>
}
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests0A41_wrapper_sum_iterate_to_unknown_with_trapySiAA7WrapperVySiG_SitF :
// CHECK-SIL: bb1
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: bb3
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests0A41_wrapper_sum_iterate_to_unknown_with_trapySiAA7WrapperVySiG_SitF'
public func span_wrapper_sum_iterate_to_unknown_with_trap(_ w: Wrapper<Int>, _ n: Int) -> Int {
let v = w.s
var sum = 0
for i in 0...n {
sum += v[i]
}
return sum
}
@inline(never)
@_optimize(none)
public func mutate_span(_ v: inout Span<Int>) { }
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests06inout_A33_sum_iterate_to_unknown_with_trapySis4SpanVySiGz_SitF :
// CHECK-SIL: bb1
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: bb3
// CHECK-SIL-NOT: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests06inout_A33_sum_iterate_to_unknown_with_trapySis4SpanVySiGz_SitF'
@_lifetime(v: copy v)
public func inout_span_sum_iterate_to_unknown_with_trap(_ v: inout Span<Int>, _ n: Int) -> Int {
var sum = 0
for i in 0...n {
sum += v[i]
}
mutate_span(&v)
return sum
}
// CHECK-SIL-LABEL: sil @$s23span_bounds_check_tests06inout_A41_sum_iterate_to_unknown_with_trap_dontoptySis4SpanVySiGz_SitF :
// CHECK-SIL: bb3
// CHECK-SIL: cond_fail {{.*}}, "Index out of bounds"
// CHECK-SIL: cond_br
// CHECK-SIL-LABEL: } // end sil function '$s23span_bounds_check_tests06inout_A41_sum_iterate_to_unknown_with_trap_dontoptySis4SpanVySiGz_SitF'
@_lifetime(v: copy v)
public func inout_span_sum_iterate_to_unknown_with_trap_dontopt(_ v: inout Span<Int>, _ n: Int) -> Int {
var sum = 0
for i in 0...n {
sum += v[i]
mutate_span(&v)
}
return sum
}