Skip to content

Commit 691fa9e

Browse files
committed
SimplifyBuiltin: add constant folding of null pointer checks against string literals
A pointer to a string literal is never null
1 parent 94b6e51 commit 691fa9e

File tree

2 files changed

+118
-0
lines changed

2 files changed

+118
-0
lines changed

SwiftCompilerSources/Sources/Optimizer/InstructionSimplification/SimplifyBuiltin.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ extension BuiltinInst : OnoneSimplifyable {
4949
if context.options.enableEmbeddedSwift {
5050
optimizeArgumentToThinMetatype(argument: 1, context)
5151
}
52+
case .ICMP_EQ:
53+
constantFoldIntegerEquality(isEqual: true, context)
54+
case .ICMP_NE:
55+
constantFoldIntegerEquality(isEqual: false, context)
5256
default:
5357
if let literal = constantFold(context) {
5458
uses.replaceAll(with: literal, context)
@@ -200,6 +204,51 @@ private extension BuiltinInst {
200204
let newMetatype = builder.createMetatype(of: instanceType, representation: .Thin)
201205
operands[argument].set(to: newMetatype, context)
202206
}
207+
208+
func constantFoldIntegerEquality(isEqual: Bool, _ context: SimplifyContext) {
209+
if constantFoldStringNullPointerCheck(isEqual: isEqual, context) {
210+
return
211+
}
212+
if let literal = constantFold(context) {
213+
uses.replaceAll(with: literal, context)
214+
}
215+
}
216+
217+
func constantFoldStringNullPointerCheck(isEqual: Bool, _ context: SimplifyContext) -> Bool {
218+
if operands[1].value.isZeroInteger &&
219+
operands[0].value.lookThroughScalarCasts is StringLiteralInst
220+
{
221+
let builder = Builder(before: self, context)
222+
let result = builder.createIntegerLiteral(isEqual ? 0 : 1, type: type)
223+
uses.replaceAll(with: result, context)
224+
context.erase(instruction: self)
225+
return true
226+
}
227+
return false
228+
}
229+
}
230+
231+
private extension Value {
232+
var isZeroInteger: Bool {
233+
if let literal = self as? IntegerLiteralInst,
234+
let value = literal.value
235+
{
236+
return value == 0
237+
}
238+
return false
239+
}
240+
241+
var lookThroughScalarCasts: Value {
242+
guard let bi = self as? BuiltinInst else {
243+
return self
244+
}
245+
switch bi.id {
246+
case .ZExt, .ZExtOrBitCast, .PtrToInt:
247+
return bi.operands[0].value.lookThroughScalarCasts
248+
default:
249+
return self
250+
}
251+
}
203252
}
204253

205254
private func hasSideEffectForBuiltinOnce(_ instruction: Instruction) -> Bool {

test/SILOptimizer/simplify_builtin.sil

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,74 @@ bb0:
383383
return %4 : $Int8
384384
}
385385

386+
// CHECK-LABEL: sil @string_null_pointer_check :
387+
// CHECK: %0 = integer_literal $Builtin.Int1, 0
388+
// CHECK-NEXT: return %0
389+
// CHECK: } // end sil function 'string_null_pointer_check'
390+
sil @string_null_pointer_check : $@convention(thin) () -> Builtin.Int1 {
391+
bb0:
392+
%0 = string_literal utf8 "hello"
393+
%1 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word
394+
%2 = builtin "zextOrBitCast_Word_Int64"(%1 : $Builtin.Word) : $Builtin.Int64
395+
%3 = integer_literal $Builtin.Int64, 0
396+
%4 = builtin "cmp_eq_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
397+
return %4 : $Builtin.Int1
398+
}
399+
400+
// CHECK-LABEL: sil @string_null_pointer_check_ne :
401+
// CHECK: %0 = integer_literal $Builtin.Int1, -1
402+
// CHECK-NEXT: return %0
403+
// CHECK: } // end sil function 'string_null_pointer_check_ne'
404+
sil @string_null_pointer_check_ne : $@convention(thin) () -> Builtin.Int1 {
405+
bb0:
406+
%0 = string_literal utf8 "hello"
407+
%1 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word
408+
%2 = builtin "zextOrBitCast_Word_Int64"(%1 : $Builtin.Word) : $Builtin.Int64
409+
%3 = integer_literal $Builtin.Int64, 0
410+
%4 = builtin "cmp_ne_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
411+
return %4 : $Builtin.Int1
412+
}
413+
414+
// CHECK-LABEL: sil @string_null_pointer_check_no_integer_literal :
415+
// CHECK: %4 = builtin "cmp_eq_Int64"(%3 : $Builtin.Int64, %0 : $Builtin.Int64)
416+
// CHECK-NEXT: return %4
417+
// CHECK: } // end sil function 'string_null_pointer_check_no_integer_literal'
418+
sil @string_null_pointer_check_no_integer_literal : $@convention(thin) (Builtin.Int64) -> Builtin.Int1 {
419+
bb0(%0 : $Builtin.Int64):
420+
%1 = string_literal utf8 "hello"
421+
%2 = builtin "ptrtoint_Word"(%1 : $Builtin.RawPointer) : $Builtin.Word
422+
%3 = builtin "zextOrBitCast_Word_Int64"(%2 : $Builtin.Word) : $Builtin.Int64
423+
%4 = builtin "cmp_eq_Int64"(%3 : $Builtin.Int64, %0 : $Builtin.Int64) : $Builtin.Int1
424+
return %4 : $Builtin.Int1
425+
}
426+
427+
// CHECK-LABEL: sil @string_null_pointer_check_not_zero :
428+
// CHECK: %4 = builtin "cmp_eq_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64)
429+
// CHECK-NEXT: return %4
430+
// CHECK: } // end sil function 'string_null_pointer_check_not_zero'
431+
sil @string_null_pointer_check_not_zero : $@convention(thin) () -> Builtin.Int1 {
432+
bb0:
433+
%0 = string_literal utf8 "hello"
434+
%1 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word
435+
%2 = builtin "zextOrBitCast_Word_Int64"(%1 : $Builtin.Word) : $Builtin.Int64
436+
%3 = integer_literal $Builtin.Int64, 123
437+
%4 = builtin "cmp_eq_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
438+
return %4 : $Builtin.Int1
439+
}
440+
441+
// CHECK-LABEL: sil @string_null_pointer_check_no_string_literal :
442+
// CHECK: %4 = builtin "cmp_eq_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64)
443+
// CHECK-NEXT: return %4
444+
// CHECK: } // end sil function 'string_null_pointer_check_no_string_literal'
445+
sil @string_null_pointer_check_no_string_literal : $@convention(thin) (Builtin.RawPointer) -> Builtin.Int1 {
446+
bb0(%0 : $Builtin.RawPointer):
447+
%1 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word
448+
%2 = builtin "zextOrBitCast_Word_Int64"(%1 : $Builtin.Word) : $Builtin.Int64
449+
%3 = integer_literal $Builtin.Int64, 0
450+
%4 = builtin "cmp_eq_Int64"(%2 : $Builtin.Int64, %3 : $Builtin.Int64) : $Builtin.Int1
451+
return %4 : $Builtin.Int1
452+
}
453+
386454
// CHECK-LABEL: sil @convert_thick_to_thin1
387455
// CHECK-NOT: metatype $@thick C1<Int>.Type
388456
// CHECK: [[L:%.*]] = metatype $@thin C1<Int>.Type
@@ -490,3 +558,4 @@ bb0(%0 : $Builtin.RawPointer, %1 : $Builtin.Word):
490558
%3 = builtin "destroyArray"<C1<Int>>(%2 : $@thick C1<Int>.Type, %0 : $Builtin.RawPointer, %1 : $Builtin.Word) : $()
491559
return %0 : $Builtin.RawPointer
492560
}
561+

0 commit comments

Comments
 (0)