Skip to content

Commit a33cfae

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 3a8bf75 commit a33cfae

File tree

3 files changed

+227
-0
lines changed

3 files changed

+227
-0
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 {
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)
@@ -224,6 +226,53 @@ private extension BuiltinInst {
224226
}
225227
return false
226228
}
229+
230+
/// Replaces a builtin "xor", which negates its operand comparison
231+
/// ```
232+
/// %3 = builtin "cmp_slt_Int64"(%1, %2) : $Builtin.Int1
233+
/// %4 = integer_literal $Builtin.Int1, -1
234+
/// %5 = builtin "xor_Int1"(%3, %4) : $Builtin.Int1
235+
/// ```
236+
/// with the negated comparison
237+
/// ```
238+
/// %5 = builtin "cmp_ge_Int64"(%1, %2) : $Builtin.Int1
239+
/// ```
240+
func simplifyNegation(_ context: SimplifyContext) {
241+
assert(id == .Xor)
242+
guard let one = arguments[1] as? IntegerLiteralInst,
243+
let oneValue = one.value,
244+
oneValue == -1,
245+
let lhsBuiltin = arguments[0] as? BuiltinInst,
246+
lhsBuiltin.type.isBuiltinInteger,
247+
let negatedBuiltinName = lhsBuiltin.negatedComparisonBuiltinName
248+
else {
249+
return
250+
}
251+
252+
let builder = Builder(before: lhsBuiltin, context)
253+
let negated = builder.createBuiltinBinaryFunction(name: negatedBuiltinName,
254+
operandType: lhsBuiltin.arguments[0].type,
255+
resultType: lhsBuiltin.type,
256+
arguments: Array(lhsBuiltin.arguments))
257+
self.replace(with: negated, context)
258+
}
259+
260+
private var negatedComparisonBuiltinName: String? {
261+
switch id {
262+
case .ICMP_EQ: return "cmp_ne"
263+
case .ICMP_NE: return "cmp_eq"
264+
case .ICMP_SLE: return "cmp_sgt"
265+
case .ICMP_SLT: return "cmp_sge"
266+
case .ICMP_SGE: return "cmp_slt"
267+
case .ICMP_SGT: return "cmp_sle"
268+
case .ICMP_ULE: return "cmp_ugt"
269+
case .ICMP_ULT: return "cmp_uge"
270+
case .ICMP_UGE: return "cmp_ult"
271+
case .ICMP_UGT: return "cmp_ule"
272+
default:
273+
return nil
274+
}
275+
}
227276
}
228277

229278
private extension Value {

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+

test/SILOptimizer/span_bounds_check_tests.swift

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,3 +353,18 @@ public func inout_span_sum_iterate_to_unknown_with_trap_dontopt(_ v: inout Span<
353353
return sum
354354
}
355355

356+
// Check that the loop is fully optimized, including bounds check elimination and vectorization.
357+
358+
// CHECK-IR-LABEL: define {{.*}} @"$s4test4loop4over5usingSis4SpanVys5UInt8VG_AFySiGtF"
359+
// CHECK-IR: vector.body:
360+
// CHECK-IR: ret
361+
public func loop(over a: borrowing Span<UInt8>, using b: borrowing Span<Int>) -> Int {
362+
var result = 0
363+
precondition(UInt8.max < b.count)
364+
for i in a.indices {
365+
let idx = Int(a[i])
366+
result &+= b[idx]
367+
}
368+
return result
369+
}
370+

0 commit comments

Comments
 (0)