Skip to content

Commit 5064297

Browse files
committed
InstructionSimplification: simplify negated integer comparsions
Replaces a builtin "xor", which negates its operand comparison ``` %3 = builtin "cmp_slt_Int64"(%1, %2) : $Builtin.Int1 %4 = integer_literal $Builtin.Int1, -1 %5 = builtin "xor_Int1"(%3, %4) : $Builtin.Int1 ``` with the negated comparison ``` %5 = builtin "cmp_ge_Int64"(%1, %2) : $Builtin.Int1 ``` This makes LLVM's IPSCCP happy. rdar://154950810
1 parent 12d9311 commit 5064297

File tree

7 files changed

+239
-12
lines changed

7 files changed

+239
-12
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBuiltin.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,8 @@ extension BuiltinInst : OnoneSimplifiable, SILCombineSimplifiable {
5353
constantFoldIntegerEquality(isEqual: true, context)
5454
case .ICMP_NE:
5555
constantFoldIntegerEquality(isEqual: false, context)
56+
case .Xor:
57+
simplifyNegation(context)
5658
default:
5759
if let literal = constantFold(context) {
5860
uses.replaceAll(with: literal, context)
@@ -255,6 +257,53 @@ private extension BuiltinInst {
255257
}
256258
return false
257259
}
260+
261+
/// Replaces a builtin "xor", which negates its operand comparison
262+
/// ```
263+
/// %3 = builtin "cmp_slt_Int64"(%1, %2) : $Builtin.Int1
264+
/// %4 = integer_literal $Builtin.Int1, -1
265+
/// %5 = builtin "xor_Int1"(%3, %4) : $Builtin.Int1
266+
/// ```
267+
/// with the negated comparison
268+
/// ```
269+
/// %5 = builtin "cmp_ge_Int64"(%1, %2) : $Builtin.Int1
270+
/// ```
271+
func simplifyNegation(_ context: SimplifyContext) {
272+
assert(id == .Xor)
273+
guard let one = arguments[1] as? IntegerLiteralInst,
274+
let oneValue = one.value,
275+
oneValue == -1,
276+
let lhsBuiltin = arguments[0] as? BuiltinInst,
277+
lhsBuiltin.type.isBuiltinInteger,
278+
let negatedBuiltinName = lhsBuiltin.negatedComparisonBuiltinName
279+
else {
280+
return
281+
}
282+
283+
let builder = Builder(before: lhsBuiltin, context)
284+
let negated = builder.createBuiltinBinaryFunction(name: negatedBuiltinName,
285+
operandType: lhsBuiltin.arguments[0].type,
286+
resultType: lhsBuiltin.type,
287+
arguments: Array(lhsBuiltin.arguments))
288+
self.replace(with: negated, context)
289+
}
290+
291+
private var negatedComparisonBuiltinName: String? {
292+
switch id {
293+
case .ICMP_EQ: return "cmp_ne"
294+
case .ICMP_NE: return "cmp_eq"
295+
case .ICMP_SLE: return "cmp_sgt"
296+
case .ICMP_SLT: return "cmp_sge"
297+
case .ICMP_SGE: return "cmp_slt"
298+
case .ICMP_SGT: return "cmp_sle"
299+
case .ICMP_ULE: return "cmp_ugt"
300+
case .ICMP_ULT: return "cmp_uge"
301+
case .ICMP_UGE: return "cmp_ult"
302+
case .ICMP_UGT: return "cmp_ule"
303+
default:
304+
return nil
305+
}
306+
}
258307
}
259308

260309
private extension Value {

test/Frontend/OptimizationOptions-with-stdlib-checks.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,8 +104,7 @@ func test_partial_safety_check(x: Int, y: Int) -> Int {
104104
// In release mode keep succinct library precondition checks (trap).
105105
// RELEASE-LABEL: sil hidden @$s19OptimizationOptions22testprecondition_check1x1yS2i_SitF : $@convention(thin) (Int, Int) -> Int {
106106
// RELEASE-NOT: "Fatal error"
107-
// RELEASE: %[[V2:.+]] = builtin "xor_Int1"(%{{.+}}, %{{.+}})
108-
// RELEASE: cond_fail %[[V2]]
107+
// RELEASE: cond_fail %{{[0-9]}}, "precondition failure"
109108
// RELEASE: return
110109

111110
// In unchecked mode remove library precondition checks.

test/Frontend/OptimizationOptions-without-stdlib-checks.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,7 @@ func test_partial_safety_check(x: Int, y: Int) -> Int {
101101
// In release mode keep succinct library precondition checks (trap).
102102
// RELEASE-LABEL: sil hidden @$s19OptimizationOptions22testprecondition_check1x1yS2i_SitF : $@convention(thin) (Int, Int) -> Int {
103103
// RELEASE-NOT: "Fatal error"
104-
// RELEASE: %[[V2:.+]] = builtin "xor_Int1"(%{{.+}}, %{{.+}})
105-
// RELEASE: cond_fail %[[V2]]
104+
// RELEASE: cond_fail %{{[0-9]}}, "precondition failure"
106105
// RELEASE: return
107106

108107
// In unchecked mode remove library precondition checks.

test/SILOptimizer/sil_combine.sil

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2870,11 +2870,9 @@ bb0(%0 : $Builtin.NativeObject):
28702870

28712871
// CHECK-LABEL: sil @test_cmp_xor_canonicalization
28722872
// CHECK:bb0([[ARG:%.*]] : $Builtin.Int1
2873-
// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
28742873
// CHECK: [[FALSE:%.*]] = integer_literal $Builtin.Int1, 0
2875-
// CHECK: [[EQ:%.*]] = builtin "cmp_eq_Int1"([[ARG]] : $Builtin.Int1, [[FALSE]]
2876-
// CHECK: [[NOT:%.*]] = builtin "xor_Int1"([[EQ]] : $Builtin.Int1, [[TRUE]] : $Builtin.Int1)
2877-
// CHECK: return [[NOT]]
2874+
// CHECK: [[NE:%.*]] = builtin "cmp_ne_Int1"([[ARG]] : $Builtin.Int1, [[FALSE]]
2875+
// CHECK: return [[NE]]
28782876

28792877
sil @test_cmp_xor_canonicalization : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 {
28802878
bb0(%0 : $Builtin.Int1):

test/SILOptimizer/sil_combine_ossa.sil

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3337,11 +3337,9 @@ bb0(%0 : @owned $Builtin.NativeObject):
33373337

33383338
// CHECK-LABEL: sil [ossa] @test_cmp_xor_canonicalization :
33393339
// CHECK:bb0([[ARG:%.*]] : $Builtin.Int1
3340-
// CHECK: [[TRUE:%.*]] = integer_literal $Builtin.Int1, -1
33413340
// CHECK: [[FALSE:%.*]] = integer_literal $Builtin.Int1, 0
3342-
// CHECK: [[EQ:%.*]] = builtin "cmp_eq_Int1"([[ARG]] : $Builtin.Int1, [[FALSE]]
3343-
// CHECK: [[NOT:%.*]] = builtin "xor_Int1"([[EQ]] : $Builtin.Int1, [[TRUE]] : $Builtin.Int1)
3344-
// CHECK: return [[NOT]]
3341+
// CHECK: [[NE:%.*]] = builtin "cmp_ne_Int1"([[ARG]] : $Builtin.Int1, [[FALSE]]
3342+
// CHECK: return [[NE]]
33453343
// CHECK: } // end sil function 'test_cmp_xor_canonicalization'
33463344
sil [ossa] @test_cmp_xor_canonicalization : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 {
33473345
bb0(%0 : $Builtin.Int1):

test/SILOptimizer/simplify_builtin.sil

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -694,3 +694,166 @@ bb0:
694694
return %0
695695
}
696696

697+
// CHECK-LABEL: sil @invert_comparison_eq :
698+
// CHECK: %2 = builtin "cmp_ne_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64)
699+
// CHECK: return %2
700+
// CHECK: } // end sil function 'invert_comparison_eq'
701+
sil @invert_comparison_eq : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
702+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
703+
%2 = builtin "cmp_eq_Int64"(%0, %1) : $Builtin.Int1
704+
%3 = integer_literal $Builtin.Int1, -1
705+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
706+
return %4
707+
}
708+
709+
// CHECK-LABEL: sil @invert_comparison_ne :
710+
// CHECK: %2 = builtin "cmp_eq_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64)
711+
// CHECK: return %2
712+
// CHECK: } // end sil function 'invert_comparison_ne'
713+
sil @invert_comparison_ne : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
714+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
715+
%2 = builtin "cmp_ne_Int64"(%0, %1) : $Builtin.Int1
716+
%3 = integer_literal $Builtin.Int1, -1
717+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
718+
return %4
719+
}
720+
721+
// CHECK-LABEL: sil @invert_comparison_sle :
722+
// CHECK: %2 = builtin "cmp_sgt_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64)
723+
// CHECK: return %2
724+
// CHECK: } // end sil function 'invert_comparison_sle'
725+
sil @invert_comparison_sle : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
726+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
727+
%2 = builtin "cmp_sle_Int64"(%0, %1) : $Builtin.Int1
728+
%3 = integer_literal $Builtin.Int1, -1
729+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
730+
return %4
731+
}
732+
733+
// CHECK-LABEL: sil @invert_comparison_slt :
734+
// CHECK: %2 = builtin "cmp_sge_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64)
735+
// CHECK: return %2
736+
// CHECK: } // end sil function 'invert_comparison_slt'
737+
sil @invert_comparison_slt : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
738+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
739+
%2 = builtin "cmp_slt_Int64"(%0, %1) : $Builtin.Int1
740+
%3 = integer_literal $Builtin.Int1, -1
741+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
742+
return %4
743+
}
744+
745+
// CHECK-LABEL: sil @invert_comparison_sge :
746+
// CHECK: %2 = builtin "cmp_slt_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64)
747+
// CHECK: return %2
748+
// CHECK: } // end sil function 'invert_comparison_sge'
749+
sil @invert_comparison_sge : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
750+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
751+
%2 = builtin "cmp_sge_Int64"(%0, %1) : $Builtin.Int1
752+
%3 = integer_literal $Builtin.Int1, -1
753+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
754+
return %4
755+
}
756+
757+
// CHECK-LABEL: sil @invert_comparison_sgt :
758+
// CHECK: %2 = builtin "cmp_sle_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64)
759+
// CHECK: return %2
760+
// CHECK: } // end sil function 'invert_comparison_sgt'
761+
sil @invert_comparison_sgt : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
762+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
763+
%2 = builtin "cmp_sgt_Int64"(%0, %1) : $Builtin.Int1
764+
%3 = integer_literal $Builtin.Int1, -1
765+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
766+
return %4
767+
}
768+
769+
// CHECK-LABEL: sil @invert_comparison_ule :
770+
// CHECK: %2 = builtin "cmp_ugt_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64)
771+
// CHECK: return %2
772+
// CHECK: } // end sil function 'invert_comparison_ule'
773+
sil @invert_comparison_ule : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
774+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
775+
%2 = builtin "cmp_ule_Int64"(%0, %1) : $Builtin.Int1
776+
%3 = integer_literal $Builtin.Int1, -1
777+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
778+
return %4
779+
}
780+
781+
// CHECK-LABEL: sil @invert_comparison_ult :
782+
// CHECK: %2 = builtin "cmp_uge_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64)
783+
// CHECK: return %2
784+
// CHECK: } // end sil function 'invert_comparison_ult'
785+
sil @invert_comparison_ult : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
786+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
787+
%2 = builtin "cmp_ult_Int64"(%0, %1) : $Builtin.Int1
788+
%3 = integer_literal $Builtin.Int1, -1
789+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
790+
return %4
791+
}
792+
793+
// CHECK-LABEL: sil @invert_comparison_uge :
794+
// CHECK: %2 = builtin "cmp_ult_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64)
795+
// CHECK: return %2
796+
// CHECK: } // end sil function 'invert_comparison_uge'
797+
sil @invert_comparison_uge : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
798+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
799+
%2 = builtin "cmp_uge_Int64"(%0, %1) : $Builtin.Int1
800+
%3 = integer_literal $Builtin.Int1, -1
801+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
802+
return %4
803+
}
804+
805+
// CHECK-LABEL: sil @invert_comparison_ugt :
806+
// CHECK: %2 = builtin "cmp_ule_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64)
807+
// CHECK: return %2
808+
// CHECK: } // end sil function 'invert_comparison_ugt'
809+
sil @invert_comparison_ugt : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
810+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
811+
%2 = builtin "cmp_ugt_Int64"(%0, %1) : $Builtin.Int1
812+
%3 = integer_literal $Builtin.Int1, -1
813+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
814+
return %4
815+
}
816+
817+
// CHECK-LABEL: sil @no_invert_wrong_literal :
818+
// CHECK: builtin "cmp_ugt_Int64"
819+
// CHECK: } // end sil function 'no_invert_wrong_literal'
820+
sil @no_invert_wrong_literal : $@convention(thin) (Builtin.Int64, Builtin.Int64) -> Builtin.Int1 {
821+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64):
822+
%2 = builtin "cmp_ugt_Int64"(%0, %1) : $Builtin.Int1
823+
%3 = integer_literal $Builtin.Int1, 0
824+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
825+
return %4
826+
}
827+
828+
// CHECK-LABEL: sil @no_invert_unknown_rhs :
829+
// CHECK: builtin "cmp_ugt_Int64"
830+
// CHECK: } // end sil function 'no_invert_unknown_rhs'
831+
sil @no_invert_unknown_rhs : $@convention(thin) (Builtin.Int64, Builtin.Int64, Builtin.Int1) -> Builtin.Int1 {
832+
bb0(%0 : $Builtin.Int64, %1 : $Builtin.Int64, %2 : $Builtin.Int1):
833+
%3 = builtin "cmp_ugt_Int64"(%0, %1) : $Builtin.Int1
834+
%4 = builtin "xor_Int1"(%3, %2) : $Builtin.Int1
835+
return %4
836+
}
837+
838+
// CHECK-LABEL: sil @no_invert_no_comparison :
839+
// CHECK: %2 = builtin "xor_Int1"
840+
// CHECK: return %2
841+
// CHECK: } // end sil function 'no_invert_no_comparison'
842+
sil @no_invert_no_comparison : $@convention(thin) (Builtin.Int1) -> Builtin.Int1 {
843+
bb0(%0 : $Builtin.Int1):
844+
%1 = integer_literal $Builtin.Int1, -1
845+
%2 = builtin "xor_Int1"(%0, %1) : $Builtin.Int1
846+
return %2
847+
}
848+
849+
// CHECK-LABEL: sil @no_invert_wrong_comparison :
850+
// CHECK: builtin "fcmp_ord_FPIEEE32"
851+
// CHECK: } // end sil function 'no_invert_wrong_comparison'
852+
sil @no_invert_wrong_comparison : $@convention(thin) (Builtin.FPIEEE32, Builtin.FPIEEE32) -> Builtin.Int1 {
853+
bb0(%0 : $Builtin.FPIEEE32, %1 : $Builtin.FPIEEE32):
854+
%2 = builtin "fcmp_ord_FPIEEE32"(%0 : $Builtin.FPIEEE32, %1 : $Builtin.FPIEEE32) : $Builtin.Int1
855+
%3 = integer_literal $Builtin.Int1, -1
856+
%4 = builtin "xor_Int1"(%2, %3) : $Builtin.Int1
857+
return %4
858+
}
859+
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// RUN: %target-swift-frontend %s -emit-ir -O -disable-availability-checking -enable-experimental-feature Lifetimes | %FileCheck %s --check-prefix=CHECK-IR
2+
3+
// REQUIRES: swift_feature_Lifetimes
4+
// REQUIRES: swift_stdlib_no_asserts, optimized_stdlib
5+
// REQUIRES: CPU=arm64 || CPU=arm64e
6+
7+
// Check that the loop is fully optimized, including bounds check elimination and vectorization.
8+
9+
// CHECK-IR-LABEL: define {{.*}} @"$s24span_bounds_check_tests24loop4over5usingSis4SpanVys5UInt8VG_AFySiGtF"
10+
// CHECK-IR: vector.body:
11+
// CHECK-IR: ret
12+
public func loop(over a: borrowing Span<UInt8>, using b: borrowing Span<Int>) -> Int {
13+
var result = 0
14+
precondition(UInt8.max < b.count)
15+
for i in a.indices {
16+
let idx = Int(a[i])
17+
result &+= b[idx]
18+
}
19+
return result
20+
}
21+

0 commit comments

Comments
 (0)