1212
1313import SIL
1414
15- extension BuiltinInst : OnoneSimplifiable {
15+ extension BuiltinInst : OnoneSimplifiable , SILCombineSimplifiable {
1616 func simplify( _ context: SimplifyContext ) {
1717 switch id {
1818 case . IsConcrete:
@@ -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)
@@ -165,6 +167,11 @@ private extension BuiltinInst {
165167 case . Sizeof:
166168 value = ty. getStaticSize ( context: context)
167169 case . Strideof:
170+ if isUsedAsStrideOfIndexRawPointer ( context) {
171+ // Constant folding `stride` would prevent index_raw_pointer simplification.
172+ // See `simplifyIndexRawPointer` in SimplifyPointerToAddress.swift.
173+ return
174+ }
168175 value = ty. getStaticStride ( context: context)
169176 case . Alignof:
170177 value = ty. getStaticAlignment ( context: context)
@@ -181,7 +188,33 @@ private extension BuiltinInst {
181188 uses. replaceAll ( with: literal, context)
182189 context. erase ( instruction: self )
183190 }
184-
191+
192+ private func isUsedAsStrideOfIndexRawPointer( _ context: SimplifyContext ) -> Bool {
193+ var worklist = ValueWorklist ( context)
194+ defer { worklist. deinitialize ( ) }
195+ worklist. pushIfNotVisited ( self )
196+ while let v = worklist. pop ( ) {
197+ for use in v. uses {
198+ switch use. instruction {
199+ case let builtin as BuiltinInst :
200+ switch builtin. id {
201+ case . SMulOver, . TruncOrBitCast, . SExtOrBitCast, . ZExtOrBitCast:
202+ worklist. pushIfNotVisited ( builtin)
203+ default :
204+ break
205+ }
206+ case let tupleExtract as TupleExtractInst where tupleExtract. fieldIndex == 0 :
207+ worklist. pushIfNotVisited ( tupleExtract)
208+ case is IndexRawPointerInst :
209+ return true
210+ default :
211+ break
212+ }
213+ }
214+ }
215+ return false
216+ }
217+
185218 func optimizeArgumentToThinMetatype( argument: Int , _ context: SimplifyContext ) {
186219 let type : Type
187220
@@ -224,6 +257,53 @@ private extension BuiltinInst {
224257 }
225258 return false
226259 }
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+ }
227307}
228308
229309private extension Value {
0 commit comments