blob: 5d1ea317298e6434c3cea8ec242184f38ab8d95b [file] [log] [blame]
// RUN: %target-sil-opt -test-constant-evaluator %s 2>&1 | %FileCheck %s
/// Tests for the constant evaluator in stepwise evaluation mode (also referred
/// to as flow-sensitive mode) in which instructions are evaluated following
/// the control flow of the program. The evaluator will be run on every function
/// whose name starts with `interpret` prefix and outputs the constant value
/// returned by the function or diagnostics if the evaluation fails.
sil_stage canonical
import Builtin
import Swift
// Test builtin literals and operations.
// CHECK-LABEL: @interpretBuiltinIntLiteral
sil @interpretBuiltinIntLiteral : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = integer_literal $Builtin.Int64, 17
return %0 : $(Builtin.Int64)
} // CHECK: Returns int: 17
// CHECK-LABEL: @interpretBuiltinAddition
sil @interpretBuiltinAddition : $@convention(thin) () -> Builtin.Int32 {
bb0:
%0 = integer_literal $Builtin.Int32, 1
%1 = builtin "add_Int32"(%0 : $Builtin.Int32, %0 : $Builtin.Int32) : $(Builtin.Int32)
return %1 : $(Builtin.Int32)
} // CHECK: Returns int: 2
// CHECK-LABEL: @interpretBuiltinAddWrapAround
sil @interpretBuiltinAddWrapAround : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = integer_literal $Builtin.Int8, 127
%1 = integer_literal $Builtin.Int8, 1
%2 = builtin "add_Int32"(%0 : $Builtin.Int8, %1 : $Builtin.Int8) : $(Builtin.Int8)
return %2 : $(Builtin.Int8)
} // CHECK: Returns int: -128
// CHECK-LABEL: @interpretBuiltinMultiplication
sil @interpretBuiltinMultiplication : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = integer_literal $Builtin.Int64, 10
%1 = integer_literal $Builtin.Int64, 11
%2 = builtin "mul_Int64"(%0 : $Builtin.Int64, %1 : $Builtin.Int64) : $(Builtin.Int64)
return %2 : $(Builtin.Int64)
} // CHECK: Returns int: 110
// CHECK-LABEL: @interpretBuiltinDivision
sil @interpretBuiltinDivision : $@convention(thin) () -> Builtin.Int16 {
bb0:
%0 = integer_literal $Builtin.Int16, 10
%1 = integer_literal $Builtin.Int16, 11
%2 = builtin "sdiv_Int16"(%1 : $Builtin.Int16, %0 : $Builtin.Int16) : $(Builtin.Int16)
return %2 : $(Builtin.Int16)
} // CHECK: Returns int: 1
// CHECK-LABEL: @interpretBuiltinModulo
sil @interpretBuiltinModulo : $@convention(thin) () -> Builtin.Int16 {
bb0:
%0 = integer_literal $Builtin.Int16, 23
%1 = integer_literal $Builtin.Int16, 6
%2 = builtin "srem_Int16"(%0 : $Builtin.Int16, %1 : $Builtin.Int16) : $(Builtin.Int16)
return %2 : $(Builtin.Int16)
} // CHECK: Returns int: 5
// CHECK-LABEL: @interpretBuiltinLeftShift
sil @interpretBuiltinLeftShift : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = integer_literal $Builtin.Int8, 10
%1 = integer_literal $Builtin.Int8, 2
%2 = builtin "shl_Int8"(%0 : $Builtin.Int8, %1: $Builtin.Int8) : $(Builtin.Int8)
return %2 : $(Builtin.Int8)
} // CHECK: Returns int: 40
// CHECK-LABEL: @interpretBuiltinRightShift
sil @interpretBuiltinRightShift : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = integer_literal $Builtin.Int8, 10
%1 = integer_literal $Builtin.Int8, 2
%2 = builtin "ashr_Int8"(%0 : $Builtin.Int8, %1: $Builtin.Int8) : $(Builtin.Int8)
return %2 : $(Builtin.Int8)
} // CHECK: Returns int: 2
// CHECK-LABEL: @interpretBuiltinBitWiseAnd
sil @interpretBuiltinBitWiseAnd : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = integer_literal $Builtin.Int8, 10
%1 = integer_literal $Builtin.Int8, 8
%2 = builtin "and_Int8"(%0 : $Builtin.Int8, %1: $Builtin.Int8) : $(Builtin.Int8)
return %2 : $(Builtin.Int8)
} // CHECK: Returns int: 8
// CHECK-LABEL: @interpretBuiltinBitWiseOr
sil @interpretBuiltinBitWiseOr : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = integer_literal $Builtin.Int8, 10
%1 = integer_literal $Builtin.Int8, 8
%2 = builtin "or_Int8"(%0 : $Builtin.Int8, %1: $Builtin.Int8) : $(Builtin.Int8)
return %2 : $(Builtin.Int8)
} // CHECK: Returns int: 10
// Test conditional branches and comparison operators.
// CHECK-LABEL: @interpretFalseBranch
sil hidden @interpretFalseBranch : $@convention(thin) () -> Builtin.Int64 {
bb0:
%1 = integer_literal $Builtin.Int64, 100
%2 = integer_literal $Builtin.Int64, 0
%3 = builtin "cmp_slt_Int64"(%1 : $Builtin.Int64, %2 : $Builtin.Int64) : $Builtin.Int1
cond_br %3, bb1, bb2
bb1:
%8 = integer_literal $Builtin.Int64, 0
br bb3(%8 : $Builtin.Int64)
bb2:
br bb3(%1 : $Builtin.Int64)
bb3(%12 : $Builtin.Int64):
return %12 : $Builtin.Int64
} // CHECK: Returns int: 100
// CHECK-LABEL: @interpretTrueBranch
sil hidden @interpretTrueBranch : $@convention(thin) () -> Builtin.Int64 {
bb0:
%1 = integer_literal $Builtin.Int64, 100
%2 = integer_literal $Builtin.Int64, 0
%3 = builtin "cmp_slt_Int64"(%1 : $Builtin.Int64, %2 : $Builtin.Int64) : $Builtin.Int1
%4 = integer_literal $Builtin.Int1, -1
%5 = builtin "xor_Int1"(%3 : $Builtin.Int1, %4 : $Builtin.Int1) : $Builtin.Int1
cond_br %5, bb1, bb2
bb1:
%8 = integer_literal $Builtin.Int64, 0
br bb3(%8 : $Builtin.Int64)
bb2:
br bb3(%1 : $Builtin.Int64)
bb3(%12 : $Builtin.Int64):
return %12 : $Builtin.Int64
} // CHECK: Returns int: 0
// Test builtin truncation and extension.
// CHECK-LABEL: @interpretSignedTruncation
sil @interpretSignedTruncation : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = integer_literal $Builtin.Int64, -1
%1 = builtin "s_to_s_checked_trunc_Int64_Int8"(%0 : $Builtin.Int64) : $(Builtin.Int8, Builtin.Int1)
%2 = tuple_extract %1 : $(Builtin.Int8, Builtin.Int1), 0
return %2 : $(Builtin.Int8)
} // CHECK: Returns int: -1
// CHECK-LABEL: @interpretSignedTruncWithIntLiteral
sil @interpretSignedTruncWithIntLiteral : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = integer_literal $Builtin.IntLiteral, 5
%1 = builtin "s_to_s_checked_trunc_IntLiteral_Int64"(%0 : $Builtin.IntLiteral) : $(Builtin.Int64, Builtin.Int1)
%2 = tuple_extract %1 : $(Builtin.Int64, Builtin.Int1), 0
return %2 : $(Builtin.Int64)
} // CHECK: Returns int: 5
// CHECK-LABEL: @interpretSignedExtend
sil @interpretSignedExtend : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = integer_literal $Builtin.Int8, -1
%1 = builtin "sext_Int8_Int64"(%0 : $Builtin.Int8) : $Builtin.Int64
return %1 : $(Builtin.Int64)
} // CHECK: Returns int: -1
// CHECK-LABEL: @interpretZeroExtend
sil @interpretZeroExtend : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = integer_literal $Builtin.Int8, -1
%1 = builtin "zext_Int8_Int64"(%0 : $Builtin.Int8) : $Builtin.Int64
return %1 : $(Builtin.Int64)
} // CHECK: Returns int: 255
// FIXME: assertion failure in conversion of s_to_s_checked_trunc_IntLiteral.
sil @xfailInterpretBuiltinIntLiteralTrunc : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = integer_literal $Builtin.IntLiteral, 2
%2 = builtin "s_to_s_checked_trunc_IntLiteral_Int8"(%0 : $Builtin.IntLiteral) : $(Builtin.Int8, Builtin.Int1)
%3 = tuple_extract %2 : $(Builtin.Int8, Builtin.Int1), 0
return %3 : $(Builtin.Int8)
}
// Test overflow diagnostics.
// FIXME: Imprecision: the following builtin operations return a tuple where
// the second element indicate whether an overflow happened or not.
// The interpreter currently makes the entire tuple unknown in the case of
// overflow. This should be replaced by the correct semantics of the builtin
// which produces a trucated value for the first element and returns true for
// the second element.
// CHECK-LABEL: @interpretSignedTruncationError
sil @interpretSignedTruncationError : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = integer_literal $Builtin.Int64, -1
%1 = builtin "s_to_u_checked_trunc_Int64_Int8"(%0 : $Builtin.Int64) : $(Builtin.Int8, Builtin.Int1)
// CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: integer overflow detected
%2 = tuple_extract %1 : $(Builtin.Int8, Builtin.Int1), 0
return %2 : $(Builtin.Int8)
}
// CHECK-LABEL: @interpretBuiltinAddOverflow
sil @interpretBuiltinAddOverflow : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = integer_literal $Builtin.Int8, 127
%1 = integer_literal $Builtin.Int8, 1
%2 = integer_literal $Builtin.Int1, -1
%3 = builtin "sadd_with_overflow_Int8"(%0 : $Builtin.Int8, %1 : $Builtin.Int8, %2: $Builtin.Int1) : $(Builtin.Int8, Builtin.Int1)
// CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: integer overflow detected
%4 = tuple_extract %3 : $(Builtin.Int8, Builtin.Int1), 0
return %4 : $(Builtin.Int8)
}
// Test function calls
sil hidden @identity : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
bb0(%0 : $Builtin.Int64):
return %0 : $Builtin.Int64
}
// CHECK-LABEL: @interpretCallTest
sil hidden @interpretCallTest : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = integer_literal $Builtin.Int64, 10
%2 = function_ref @identity : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
%3 = apply %2(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
return %3 : $Builtin.Int64
} // CHECK: Returns int: 10
// A function that computes factorial of a Builtin.Int64 and traps on overflow.
sil hidden @factorial : $@convention(thin) (Builtin.Int64) -> Builtin.Int64 {
bb0(%0 : $Builtin.Int64):
%2 = integer_literal $Builtin.Int64, 0
%4 = builtin "cmp_eq_Int64"(%0 : $Builtin.Int64, %2 : $Builtin.Int64) : $Builtin.Int1
cond_br %4, bb1, bb2
bb1:
%8 = integer_literal $Builtin.Int64, 1
br bb3(%8 : $Builtin.Int64)
bb2:
%11 = integer_literal $Builtin.Int64, 1
%13 = integer_literal $Builtin.Int1, -1
%14 = builtin "usub_with_overflow_Int64"(%0 : $Builtin.Int64, %11 : $Builtin.Int64, %13 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%15 = tuple_extract %14 : $(Builtin.Int64, Builtin.Int1), 0
%16 = tuple_extract %14 : $(Builtin.Int64, Builtin.Int1), 1
cond_fail %16 : $Builtin.Int1
%19 = function_ref @factorial : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
%20 = apply %19(%15) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
%23 = integer_literal $Builtin.Int1, -1
%24 = builtin "umul_with_overflow_Int64"(%0 : $Builtin.Int64, %20 : $Builtin.Int64, %23 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%25 = tuple_extract %24 : $(Builtin.Int64, Builtin.Int1), 0
%26 = tuple_extract %24 : $(Builtin.Int64, Builtin.Int1), 1
cond_fail %26 : $Builtin.Int1
br bb3(%25 : $Builtin.Int64)
bb3(%30 : $Builtin.Int64):
return %30 : $Builtin.Int64
}
// CHECK-LABEL: @interpretFactorialCall
sil hidden @interpretFactorialCall : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = integer_literal $Builtin.Int64, 5
%2 = function_ref @factorial : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
%3 = apply %2(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
return %3 : $Builtin.Int64
} // CHECK: Returns int: 120
// CHECK-LABEL: @interpretAndDiagnoseLongRecursion
sil hidden @interpretAndDiagnoseLongRecursion : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = integer_literal $Builtin.Int64, -5
%2 = function_ref @factorial : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
%3 = apply %2(%0) : $@convention(thin) (Builtin.Int64) -> Builtin.Int64
// CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: exceeded instruction limit: {{.*}} when evaluating the expression at compile time
// CHECK: {{.*}}: note: limit exceeded here
return %3 : $Builtin.Int64
}
// Test meta types.
// CHECK-LABEL: @interpretIntMetatype
sil @interpretIntMetatype : $@convention(thin) () -> @thin Int.Type {
bb0:
%0 = metatype $@thin Int.Type
return %0 : $@thin Int.Type
} // CHECK: Returns metatype: Int
// CHECK-LABEL: @interpretStringMetatype
sil @interpretStringMetatype : $@convention(thin) () -> @thin String.Type {
bb0:
%0 = metatype $@thin String.Type
return %0 : $@thin String.Type
} // CHECK: Returns metatype: String
// Test standard integers.
// CHECK-LABEL: @interpretIntInit
sil @interpretIntInit : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = integer_literal $Builtin.Int64, 122
%1 = struct $Int64 (%0 : $Builtin.Int64)
%2 = struct_extract %1 : $Int64, #Int64._value
return %2 : $Builtin.Int64
} // CHECK: Returns int: 122
sil @mockInt8Init : $@convention(thin) (Builtin.Int64, @thin Int8.Type) -> Int8 {
bb0(%0 : $Builtin.Int64, %1 : $@thin Int8.Type):
%2 = builtin "s_to_s_checked_trunc_Int64_Int8"(%0 : $Builtin.Int64) : $(Builtin.Int8, Builtin.Int1)
%3 = tuple_extract %2 : $(Builtin.Int8, Builtin.Int1), 0
%4 = struct $Int8 (%3 : $Builtin.Int8)
return %4 : $Int8
}
// CHECK-LABEL: @interpretInt8Init
sil @interpretInt8Init : $@convention(thin) () -> Builtin.Int8 {
bb0:
%0 = integer_literal $Builtin.Int64, 122
%1 = metatype $@thin Int8.Type
%2 = function_ref @mockInt8Init : $@convention(thin) (Builtin.Int64, @thin Int8.Type) -> Int8
%3 = apply %2(%0, %1) : $@convention(thin) (Builtin.Int64, @thin Int8.Type) -> Int8
%4 = struct_extract %3 : $Int8, #Int8._value
return %4 : $Builtin.Int8
} // CHECK: Returns int: 122
sil @boolEquals : $@convention(method) (Bool, Bool, @thin Bool.Type) -> Bool {
bb0(%0 : $Bool, %1 : $Bool, %2 : $@thin Bool.Type):
%3 = struct_extract %0 : $Bool, #Bool._value
%4 = struct_extract %1 : $Bool, #Bool._value
%5 = builtin "cmp_eq_Int1"(%3 : $Builtin.Int1, %4 : $Builtin.Int1) : $Builtin.Int1
%6 = struct $Bool (%5 : $Builtin.Int1)
return %6 : $Bool
}
// CHECK-LABEL: @interpretBoolEquals
sil @interpretBoolEquals : $@convention(thin) () -> Builtin.Int1 {
bb0:
%0 = integer_literal $Builtin.Int1, 0
%1 = struct $Bool (%0 : $Builtin.Int1)
%2 = integer_literal $Builtin.Int1, -1
%3 = struct $Bool (%2 : $Builtin.Int1)
%4 = metatype $@thin Bool.Type
%5 = function_ref @boolEquals : $@convention(method) (Bool, Bool, @thin Bool.Type) -> Bool
%6 = apply %5(%1, %3, %4) : $@convention(method) (Bool, Bool, @thin Bool.Type) -> Bool
%7 = struct_extract %6 : $Bool, #Bool._value
return %7 : $Builtin.Int1
} // CHECK: Returns int: 0
// Test custom structs.
struct InnerStruct {
var z: Int64
var w: Bool
}
struct CustomStruct {
let x: (Int64, Int64)
let y: InnerStruct
}
sil @innerStructInit : $@convention(method) (Int64, Bool, @thin InnerStruct.Type) -> InnerStruct {
bb0(%0 : $Int64, %1 : $Bool, %2 : $@thin InnerStruct.Type):
%3 = struct $InnerStruct (%0 : $Int64, %1 : $Bool)
return %3 : $InnerStruct
}
sil @customStructInit : $@convention(method) (Int64, Int64, InnerStruct, @thin CustomStruct.Type) -> CustomStruct {
bb0(%0 : $Int64, %1 : $Int64, %2 : $InnerStruct, %3 : $@thin CustomStruct.Type):
%4 = tuple (%0 : $Int64, %1 : $Int64)
%5 = struct $CustomStruct (%4 : $(Int64, Int64), %2 : $InnerStruct)
return %5 : $CustomStruct
}
sil @constructCustomStruct : $@convention(thin) () -> CustomStruct {
bb0:
%0 = metatype $@thin CustomStruct.Type
%1 = integer_literal $Builtin.Int64, 1
%2 = struct $Int64 (%1 : $Builtin.Int64)
%3 = integer_literal $Builtin.Int64, 2
%4 = struct $Int64 (%3 : $Builtin.Int64)
%5 = metatype $@thin InnerStruct.Type
%6 = integer_literal $Builtin.Int64, 3
%7 = struct $Int64 (%6 : $Builtin.Int64)
%8 = integer_literal $Builtin.Int1, -1
%9 = struct $Bool (%8 : $Builtin.Int1)
%10 = function_ref @innerStructInit : $@convention(method) (Int64, Bool, @thin InnerStruct.Type) -> InnerStruct
%11 = apply %10(%7, %9, %5) : $@convention(method) (Int64, Bool, @thin InnerStruct.Type) -> InnerStruct
%12 = function_ref @customStructInit : $@convention(method) (Int64, Int64, InnerStruct, @thin CustomStruct.Type) -> CustomStruct
%13 = apply %12(%2, %4, %11, %0) : $@convention(method) (Int64, Int64, InnerStruct, @thin CustomStruct.Type) -> CustomStruct
return %13 : $CustomStruct
}
// CHECK-LABEL: @interpretCustomStruct
sil @interpretCustomStruct : $@convention(thin) () -> Builtin.Int64 {
bb0:
%1 = function_ref @constructCustomStruct : $@convention(thin) () -> CustomStruct
%2 = apply %1() : $@convention(thin) () -> CustomStruct
%3 = struct_extract %2 : $CustomStruct, #CustomStruct.x
%4 = tuple_extract %3 : $(Int64, Int64), 0
%5 = struct_extract %4 : $Int64, #Int64._value
return %5 : $Builtin.Int64
} // CHECK: Returns int: 1
// CHECK-LABEL: @interpretCustomStruct2
sil @interpretCustomStruct2 : $@convention(thin) () -> Builtin.Int64 {
bb0:
%1 = function_ref @constructCustomStruct : $@convention(thin) () -> CustomStruct
%2 = apply %1() : $@convention(thin) () -> CustomStruct
%3 = struct_extract %2 : $CustomStruct, #CustomStruct.x
%4 = tuple_extract %3 : $(Int64, Int64), 1
%5 = struct_extract %4 : $Int64, #Int64._value
return %5 : $Builtin.Int64
} // CHECK: Returns int: 2
// CHECK-LABEL: @interpretCustomStruct3
sil @interpretCustomStruct3 : $@convention(thin) () -> Builtin.Int64 {
bb0:
%1 = function_ref @constructCustomStruct : $@convention(thin) () -> CustomStruct
%2 = apply %1() : $@convention(thin) () -> CustomStruct
%3 = struct_extract %2 : $CustomStruct, #CustomStruct.y
%4 = struct_extract %3 : $InnerStruct, #InnerStruct.z
%5 = struct_extract %4 : $Int64, #Int64._value
return %5 : $Builtin.Int64
} // CHECK: Returns int: 3
// CHECK-LABEL: @interpretCustomStruct4
sil @interpretCustomStruct4 : $@convention(thin) () -> Builtin.Int1 {
bb0:
%1 = function_ref @constructCustomStruct : $@convention(thin) () -> CustomStruct
%2 = apply %1() : $@convention(thin) () -> CustomStruct
%3 = struct_extract %2 : $CustomStruct, #CustomStruct.y
%4 = struct_extract %3 : $InnerStruct, #InnerStruct.w
%5 = struct_extract %4 : $Bool, #Bool._value
return %5 : $Builtin.Int1
} // CHECK: Returns int: -1
// Test non-constant diagnostics.
// CHECK-LABEL: @interpretAndDiagnoseNonConstantVars
sil hidden @interpretAndDiagnoseNonConstantVars : $@convention(thin) (Int) -> () {
bb0(%0 : $Int):
%4 = struct_extract %0 : $Int, #Int._value
// CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: encountered use of a variable not tracked by the evaluator
%10 = tuple ()
return %10 : $()
}
sil @$ss8readLine16strippingNewlineSSSgSb_tF : $@convention(thin) (Bool) -> @owned Optional<String>
// CHECK-LABEL: @interpretAndDiagnoseNonConstantCalls
sil @interpretAndDiagnoseNonConstantCalls : $@convention(thin) () -> () {
bb0:
%0 = integer_literal $Builtin.Int1, -1
%1 = struct $Bool (%0 : $Builtin.Int1)
// function_ref readLine(strippingNewline:)
%2 = function_ref @$ss8readLine16strippingNewlineSSSgSb_tF : $@convention(thin) (Bool) -> @owned Optional<String>
%3 = apply %2(%1) : $@convention(thin) (Bool) -> @owned Optional<String>
// CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: encountered call to 'Swift.readLine(strippingNewline: Swift.Bool) -> Swift.Optional<Swift.String>' whose body is not available
release_value %3 : $Optional<String>
%5 = tuple ()
return %5 : $()
}
// Test loop diagnostics.
// CHECK-LABEL: @interpretAndDiagnoseLoops
sil hidden @interpretAndDiagnoseLoops : $@convention(thin) () -> () {
bb0:
br bb1
bb1:
%3 = integer_literal $Builtin.Int64, 0
%4 = integer_literal $Builtin.Int64, 100
%5 = builtin "cmp_slt_Int64"(%3 : $Builtin.Int64, %4 : $Builtin.Int64) : $Builtin.Int1
cond_br %5, bb2, bb3
bb2:
br bb1
// CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: control-flow loop found during evaluation
bb3:
%10 = tuple ()
return %10 : $()
}
// Test stack allocation and memory access.
// CHECK-LABEL: @interpretLoadStore
sil hidden @interpretLoadStore : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = alloc_stack $Builtin.Int64, var, name "i"
%1 = integer_literal $Builtin.Int64, 11
store %1 to %0 : $*Builtin.Int64
%3 = load %0 : $*Builtin.Int64
dealloc_stack %0 : $*Builtin.Int64
return %3 : $Builtin.Int64
} // CHECK: Returns int: 11
// CHECK-LABEL: @interpretBeginEndAccess
sil hidden @interpretBeginEndAccess : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = alloc_stack $Builtin.Int64, var, name "i"
%1 = integer_literal $Builtin.Int64, 11
%3 = begin_access [modify] [static] %0 : $*Builtin.Int64
store %1 to %3 : $*Builtin.Int64
end_access %3 : $*Builtin.Int64
%5 = load %0 : $*Builtin.Int64
dealloc_stack %0 : $*Builtin.Int64
return %5 : $Builtin.Int64
} // CHECK: Returns int: 11
// Test structs with mutating functions.
sil hidden @increment : $@convention(thin) (@inout Int32) -> () {
bb0(%0 : $*Int32):
%2 = integer_literal $Builtin.Int32, 1
%3 = begin_access [modify] [static] %0 : $*Int32
%4 = struct_element_addr %3 : $*Int32, #Int32._value
%5 = load %4 : $*Builtin.Int32
%6 = integer_literal $Builtin.Int1, -1
%7 = builtin "sadd_with_overflow_Int32"(%5 : $Builtin.Int32, %2 : $Builtin.Int32, %6 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%8 = tuple_extract %7 : $(Builtin.Int32, Builtin.Int1), 0
%9 = tuple_extract %7 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %9 : $Builtin.Int1
%11 = struct $Int32 (%8 : $Builtin.Int32)
store %11 to %3 : $*Int32
%13 = tuple ()
end_access %3 : $*Int32
%15 = tuple ()
return %15 : $()
}
// CHECK-LABEL: @interpretIntInOut
sil hidden @interpretIntInOut : $@convention(thin) () -> Builtin.Int32 {
bb0:
%0 = alloc_stack $Int32, var, name "i"
%1 = integer_literal $Builtin.Int32, 13
%2 = struct $Int32 (%1 : $Builtin.Int32)
store %2 to %0 : $*Int32
%4 = begin_access [modify] [static] %0 : $*Int32
%5 = function_ref @increment : $@convention(thin) (@inout Int32) -> ()
%6 = apply %5(%4) : $@convention(thin) (@inout Int32) -> ()
end_access %4 : $*Int32
%7 = load %0 : $*Int32
%8 = struct_extract %7 : $Int32, #Int32._value
dealloc_stack %0 : $*Int32
return %8 : $Builtin.Int32
} // CHECK: Returns int: 14
// CHECK-LABEL: @interpretNoAliasingTest
sil hidden @interpretNoAliasingTest : $@convention(thin) () -> Builtin.Int32 {
bb0:
%0 = alloc_stack $Int32, var, name "x"
%1 = integer_literal $Builtin.Int32, 1
%2 = struct $Int32 (%1 : $Builtin.Int32)
store %2 to %0 : $*Int32
%4 = alloc_stack $Int32, var, name "y"
%5 = begin_access [read] [static] %0 : $*Int32
store %2 to %4 : $*Int32
end_access %5 : $*Int32
%8 = begin_access [modify] [static] %0 : $*Int32
%9 = function_ref @increment : $@convention(thin) (@inout Int32) -> ()
%10 = apply %9(%8) : $@convention(thin) (@inout Int32) -> ()
end_access %8 : $*Int32
%12 = begin_access [read] [static] %0 : $*Int32
%13 = load %12 : $*Int32
end_access %12 : $*Int32
%15 = begin_access [read] [static] %4 : $*Int32
end_access %15 : $*Int32
%17 = struct_extract %13 : $Int32, #Int32._value
%18 = integer_literal $Builtin.Int1, -1
%19 = builtin "sadd_with_overflow_Int32"(%17 : $Builtin.Int32, %1 : $Builtin.Int32, %18 : $Builtin.Int1) : $(Builtin.Int32, Builtin.Int1)
%20 = tuple_extract %19 : $(Builtin.Int32, Builtin.Int1), 0
%21 = tuple_extract %19 : $(Builtin.Int32, Builtin.Int1), 1
cond_fail %21 : $Builtin.Int1
dealloc_stack %4 : $*Int32
dealloc_stack %0 : $*Int32
return %20 : $Builtin.Int32
} // CHECK: Returns int: 3
// Test strings.
// CHECK-LABEL: @interpretStringLiteral
sil hidden @interpretStringLiteral : $@convention(thin) () -> Builtin.RawPointer {
bb0:
%0 = string_literal utf8 "plain string"
return %0 : $Builtin.RawPointer
} // CHECK: Returns string: "plain string"
// CHECK-LABEL: @interpretStringLiteralUnicode
sil hidden @interpretStringLiteralUnicode : $@convention(thin) () -> Builtin.RawPointer {
bb0:
%0 = string_literal utf8 "\u{1F496}"
return %0 : $Builtin.RawPointer
} // CHECK: Returns string: "💖"
// String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
// The semantics attribute is used by the interpreter.
sil [serialized] [always_inline] [readonly] [_semantics "string.makeUTF8"] @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
// CHECK-LABEL: @interpretStringInitIntrinsic
sil hidden @interpretStringInitIntrinsic : $@convention(thin) () -> @owned String {
bb0:
%0 = string_literal utf8 "plain string"
%1 = integer_literal $Builtin.Word, 12
%2 = integer_literal $Builtin.Int1, -1
%3 = metatype $@thin String.Type
%4 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%5 = apply %4(%0, %1, %2, %3) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
return %5 : $String
} // CHECK: Returns string: "plain string"
// TODO: Provide a more descriptive note that mentions the actual error.
// CHECK-LABEL: @interpretAndDiagnoseStringInitError
sil hidden @interpretAndDiagnoseStringInitError: $@convention(thin) () -> @owned String {
bb0:
%0 = string_literal utf8 "\u{1F496}"
%1 = integer_literal $Builtin.Word, 1 // The byte length of the literal is wrong.
%2 = integer_literal $Builtin.Int1, 0
%3 = metatype $@thin String.Type
%4 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%5 = apply %4(%0, %1, %2, %3) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
// CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: operation with invalid operands encountered during evaluation
return %5 : $String
}
// String.append(_:_:)
// The semantics attribute is used by the interpreter.
sil [serialized] [_semantics "string.append"] @$sSS6appendyySSF : $@convention(method) (@guaranteed String, @inout String) -> ()
// CHECK-LABEL: @interpretStringAppend
sil @interpretStringAppend: $@convention(thin) () -> @owned String {
bb0:
%0 = alloc_stack $String, var, name "a"
%1 = string_literal utf8 "a"
%2 = integer_literal $Builtin.Word, 1
%3 = integer_literal $Builtin.Int1, -1
%4 = metatype $@thin String.Type
%5 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%6 = apply %5(%1, %2, %3, %4) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
store %6 to %0 : $*String
%8 = metatype $@thin String.Type
%9 = string_literal utf8 "b"
%10 = integer_literal $Builtin.Word, 1
%11 = integer_literal $Builtin.Int1, -1
%12 = metatype $@thin String.Type
%13 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%14 = apply %13(%9, %10, %11, %12) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%15 = begin_access [modify] [static] %0 : $*String
// function_ref static String.append (_:_:)
%16 = function_ref @$sSS6appendyySSF : $@convention(method) (@guaranteed String, @inout String) -> ()
%17 = apply %16(%14, %15) : $@convention(method) (@guaranteed String, @inout String) -> ()
end_access %15 : $*String
release_value %14 : $String
%20 = begin_access [read] [static] %0 : $*String
%21 = load %20 : $*String
retain_value %21 : $String
end_access %20 : $*String
destroy_addr %0 : $*String
dealloc_stack %0 : $*String
return %21 : $String
} // CHECK: Returns string: "ab"
// CHECK-LABEL: @interpretStringAppendUnicode
sil @interpretStringAppendUnicode: $@convention(thin) () -> @owned String {
bb0:
%0 = alloc_stack $String, var, name "a"
%1 = string_literal utf8 "\u{1F1FA}"
%2 = integer_literal $Builtin.Word, 4
%3 = integer_literal $Builtin.Int1, 0
%4 = metatype $@thin String.Type
%5 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%6 = apply %5(%1, %2, %3, %4) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
store %6 to %0 : $*String
%8 = metatype $@thin String.Type
%9 = string_literal utf8 "\u{1F1F8}"
%10 = integer_literal $Builtin.Word, 4
%11 = integer_literal $Builtin.Int1, 0
%12 = metatype $@thin String.Type
%13 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%14 = apply %13(%9, %10, %11, %12) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%15 = begin_access [modify] [static] %0 : $*String
// function_ref static String.+= infix(_:_:)
%16 = function_ref @$sSS6appendyySSF : $@convention(method) (@guaranteed String, @inout String) -> ()
%17 = apply %16(%14, %15) : $@convention(method) (@guaranteed String, @inout String) -> ()
end_access %15 : $*String
release_value %14 : $String
%20 = begin_access [read] [static] %0 : $*String
%21 = load %20 : $*String
retain_value %21 : $String
end_access %20 : $*String
destroy_addr %0 : $*String
dealloc_stack %0 : $*String
return %21 : $String
} // CHECK: Returns string: "🇺🇸"
// Test Enums.
public enum Shape {
case square(Int64)
case rectangle(Int64, Int64)
}
// CHECK-LABEL: @interpretShapeArea
sil @interpretShapeArea : $@convention(thin) () -> Builtin.Int64 {
bb0:
%1 = integer_literal $Builtin.Int64, 10
%2 = struct $Int64 (%1 : $Builtin.Int64)
%3 = enum $Shape, #Shape.square!enumelt.1, %2 : $Int64
switch_enum %3 : $Shape, case #Shape.square!enumelt.1: bb1, case #Shape.rectangle!enumelt.1: bb2
bb1(%4 : $Int64):
debug_value %4 : $Int64, let, name "side"
%5 = struct_extract %4 : $Int64, #Int64._value
%6 = struct_extract %4 : $Int64, #Int64._value
%7 = integer_literal $Builtin.Int1, -1
%8 = builtin "smul_with_overflow_Int64"(%5 : $Builtin.Int64, %6 : $Builtin.Int64, %7 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%9 = tuple_extract %8 : $(Builtin.Int64, Builtin.Int1), 0
%10 = tuple_extract %8 : $(Builtin.Int64, Builtin.Int1), 1
cond_fail %10 : $Builtin.Int1
br bb3(%9 : $Builtin.Int64)
bb2(%15 : $(Int64, Int64)):
%16 = tuple_extract %15 : $(Int64, Int64), 0
%17 = tuple_extract %15 : $(Int64, Int64), 1
debug_value %16 : $Int64, let, name "length"
debug_value %17 : $Int64, let, name "width"
%20 = struct_extract %16 : $Int64, #Int64._value // user: %23
%21 = struct_extract %17 : $Int64, #Int64._value // user: %23
%22 = integer_literal $Builtin.Int1, -1
%23 = builtin "smul_with_overflow_Int64"(%20 : $Builtin.Int64, %21 : $Builtin.Int64, %22 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
%24 = tuple_extract %23 : $(Builtin.Int64, Builtin.Int1), 0
%25 = tuple_extract %23 : $(Builtin.Int64, Builtin.Int1), 1
cond_fail %25 : $Builtin.Int1
br bb3(%24 : $Builtin.Int64)
bb3(%30 : $Builtin.Int64):
return %30 : $Builtin.Int64
} // CHECK: Returns int: 100
// Test inject_enum_addr instruction.
public enum Direction {
case north
case south
case east
case west
}
sil @isNorth : $@convention(thin) (@in_guaranteed Direction) -> Builtin.Int32 {
bb0(%0 : $*Direction):
switch_enum_addr %0 : $*Direction, case #Direction.north!enumelt: bb1, default bb2
bb1:
%3 = integer_literal $Builtin.Int32, 1
br bb3(%3 : $Builtin.Int32)
bb2:
%6 = integer_literal $Builtin.Int32, 0
br bb3(%6 : $Builtin.Int32)
bb3(%9 : $Builtin.Int32):
return %9 : $Builtin.Int32
}
// CHECK: @interpretTestInjectEnumAddr
sil hidden @interpretTestInjectEnumAddr : $@convention(thin) () -> Builtin.Int32 {
bb0:
%1 = alloc_stack $Direction
inject_enum_addr %1 : $*Direction, #Direction.north!enumelt
%2 = function_ref @isNorth : $@convention(thin) (@in_guaranteed Direction) -> Builtin.Int32
%3 = apply %2(%1) : $@convention(thin) (@in_guaranteed Direction) -> Builtin.Int32
destroy_addr %1 : $*Direction
dealloc_stack %1 : $*Direction
return %3 : $Builtin.Int32
} // CHECK: Returns int: 1
// Test select_enum and select_enum_addr instructions.
// CHECK: @interpretTestSelectEnum
sil hidden @interpretTestSelectEnum : $@convention(thin) () -> Builtin.Int32 {
bb0:
%1 = enum $Direction, #Direction.north!enumelt
%2 = integer_literal $Builtin.Int32, 1
%3 = integer_literal $Builtin.Int32, 0
%4 = select_enum %1 : $Direction, case #Direction.north!enumelt: %2, default %3 : $Builtin.Int32
return %4 : $Builtin.Int32
} // CHECK: Returns int: 1
// CHECK: @interpretTestSelectEnumAddr
sil hidden @interpretTestSelectEnumAddr : $@convention(thin) () -> Builtin.Int32 {
bb0:
%1 = alloc_stack $Direction
inject_enum_addr %1 : $*Direction, #Direction.north!enumelt
%2 = integer_literal $Builtin.Int32, 1
%3 = integer_literal $Builtin.Int32, 0
%4 = select_enum_addr %1 : $*Direction, case #Direction.north!enumelt: %2, default %3 : $Builtin.Int32
destroy_addr %1 : $*Direction
dealloc_stack %1 : $*Direction
return %4 : $Builtin.Int32
} // CHECK: Returns int: 1
// Test calling conventions.
// Test struct with a string property. The struct will be passed and returned
// @guaranteed when its methods are called.
struct S {
var prop: String
}
sil hidden @initS : $@convention(thin) () -> @owned S {
bb0:
%2 = string_literal utf8 "something"
%3 = integer_literal $Builtin.Word, 9
%4 = integer_literal $Builtin.Int1, -1
%5 = metatype $@thin String.Type
// String.init(_builtinStringLiteral:utf8CodeUnitCount:isASCII:)
%6 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%7 = apply %6(%2, %3, %4, %5) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%12 = struct $S (%7 : $String)
retain_value %12 : $S
return %12 : $S
}
sil @getProp : $@convention(method) (@guaranteed S) -> @owned String {
bb0(%0 : $S):
%2 = struct_extract %0 : $S, #S.prop
retain_value %2 : $String
return %2 : $String
}
// CHECK: @interpretGuaranteedConvention
sil @interpretGuaranteedConvention : $@convention(thin) () -> @owned String {
bb0:
%1 = function_ref @initS : $@convention(thin) () -> @owned S
%2 = apply %1() : $@convention(thin) () -> @owned S
%4 = function_ref @getProp : $@convention(method) (@guaranteed S) -> @owned String
%5 = apply %4(%2) : $@convention(method) (@guaranteed S) -> @owned String
release_value %2 : $S
return %5 : $String
} // CHECK: Returns string: "something"
// TODO: add tests for generic functions, generic structs and generic enums.
// A composite test that mimics the format specifier construction used by
// os log APIs.
enum IntFormat {
case decimal
case hex
case octal
}
// getIntegerFormatSpecifier(IntFormat:isPrivate:bitWidth:isSigned:)
sil @getIntegerFormatSpecifier : $@convention(thin) (IntFormat, Bool, Int64, Bool) -> @owned String {
bb0(%0 : $IntFormat, %1 : $Bool, %2 : $Int64, %3 : $Bool):
%10 = alloc_stack $String, var, name "formatSpecifier"
%11 = struct_extract %1 : $Bool, #Bool._value
cond_br %11, bb1, bb2
bb1:
%13 = string_literal utf8 "%{private}"
%14 = integer_literal $Builtin.Word, 10
%15 = integer_literal $Builtin.Int1, -1
%16 = metatype $@thin String.Type
%17 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%18 = apply %17(%13, %14, %15, %16) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
br bb3(%18 : $String)
bb2:
%20 = string_literal utf8 "%{public}"
%21 = integer_literal $Builtin.Word, 9
%22 = integer_literal $Builtin.Int1, -1
%23 = metatype $@thin String.Type
%24 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%25 = apply %24(%20, %21, %22, %23) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
br bb3(%25 : $String)
bb3(%27 : $String):
store %27 to %10 : $*String
%29 = integer_literal $Builtin.Int64, 64
%30 = struct_extract %2 : $Int64, #Int64._value
%31 = builtin "cmp_eq_Int64"(%30 : $Builtin.Int64, %29 : $Builtin.Int64) : $Builtin.Int1
%32 = struct $Bool (%31 : $Builtin.Int1)
%33 = struct_extract %32 : $Bool, #Bool._value
cond_br %33, bb4, bb5
bb4:
%35 = metatype $@thin String.Type
%36 = string_literal utf8 "ll"
%37 = integer_literal $Builtin.Word, 2
%38 = integer_literal $Builtin.Int1, -1
%39 = metatype $@thin String.Type
%40 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%41 = apply %40(%36, %37, %38, %39) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%42 = begin_access [modify] [static] %10 : $*String
%43 = function_ref @$sSS6appendyySSF : $@convention(method) (@guaranteed String, @inout String) -> ()
%44 = apply %43(%41, %42) : $@convention(method) (@guaranteed String, @inout String) -> ()
end_access %42 : $*String
release_value %41 : $String
br bb6
bb5:
br bb6
bb6:
switch_enum %0 : $IntFormat, case #IntFormat.hex!enumelt: bb7, case #IntFormat.octal!enumelt: bb8, default bb9
bb7:
%50 = metatype $@thin String.Type
%51 = string_literal utf8 "x"
%52 = integer_literal $Builtin.Word, 1
%53 = integer_literal $Builtin.Int1, -1
%54 = metatype $@thin String.Type
%55 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%56 = apply %55(%51, %52, %53, %54) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%57 = begin_access [modify] [static] %10 : $*String
%58 = function_ref @$sSS6appendyySSF : $@convention(method) (@guaranteed String, @inout String) -> ()
%59 = apply %58(%56, %57) : $@convention(method) (@guaranteed String, @inout String) -> ()
end_access %57 : $*String
release_value %56 : $String
br bb13
bb8:
%63 = metatype $@thin String.Type
%64 = string_literal utf8 "o"
%65 = integer_literal $Builtin.Word, 1
%66 = integer_literal $Builtin.Int1, -1
%67 = metatype $@thin String.Type
%68 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%69 = apply %68(%64, %65, %66, %67) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%70 = begin_access [modify] [static] %10 : $*String
%71 = function_ref @$sSS6appendyySSF : $@convention(method) (@guaranteed String, @inout String) -> ()
%72 = apply %71(%69, %70) : $@convention(method) (@guaranteed String, @inout String) -> ()
end_access %70 : $*String
release_value %69 : $String
br bb13
bb9:
%76 = metatype $@thin String.Type
%77 = struct_extract %3 : $Bool, #Bool._value
cond_br %77, bb10, bb11
bb10:
%79 = string_literal utf8 "d"
%80 = integer_literal $Builtin.Word, 1
%81 = integer_literal $Builtin.Int1, -1
%82 = metatype $@thin String.Type
%83 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%84 = apply %83(%79, %80, %81, %82) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
br bb12(%84 : $String)
bb11:
%86 = string_literal utf8 "u"
%87 = integer_literal $Builtin.Word, 1
%88 = integer_literal $Builtin.Int1, -1
%89 = metatype $@thin String.Type
%90 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%91 = apply %90(%86, %87, %88, %89) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
br bb12(%91 : $String)
bb12(%93 : $String):
%94 = begin_access [modify] [static] %10 : $*String
%95 = function_ref @$sSS6appendyySSF : $@convention(method) (@guaranteed String, @inout String) -> ()
%96 = apply %95(%93, %94) : $@convention(method) (@guaranteed String, @inout String) -> ()
end_access %94 : $*String
release_value %93 : $String
br bb13
bb13:
%100 = begin_access [read] [static] %10 : $*String
%101 = load %100 : $*String
retain_value %101 : $String
end_access %100 : $*String
destroy_addr %10 : $*String
dealloc_stack %10 : $*String
return %101 : $String
}
// CHECK-LABEL: @interpretGetPrivateInt64FormatString
sil @interpretGetPrivateInt64FormatString : $@convention(thin) () -> @owned String {
bb0:
%2 = metatype $@thin IntFormat.Type
%3 = enum $IntFormat, #IntFormat.decimal!enumelt
%4 = integer_literal $Builtin.Int1, -1
%5 = struct $Bool (%4 : $Builtin.Int1)
%6 = integer_literal $Builtin.Int64, 64
%7 = struct $Int64 (%6 : $Builtin.Int64)
%8 = integer_literal $Builtin.Int1, -1
%9 = struct $Bool (%8 : $Builtin.Int1)
%10 = function_ref @getIntegerFormatSpecifier : $@convention(thin) (IntFormat, Bool, Int64, Bool) -> @owned String
%11 = apply %10(%3, %5, %7, %9) : $@convention(thin) (IntFormat, Bool, Int64, Bool) -> @owned String
return %11 : $String
} // CHECK: Returns string: "%{private}lld"
// CHECK-LABEL: @interpretGetPrivateHexInt64FormatString
sil @interpretGetPrivateHexInt64FormatString : $@convention(thin) () -> @owned String {
bb0:
%2 = metatype $@thin IntFormat.Type
%3 = enum $IntFormat, #IntFormat.hex!enumelt
%4 = integer_literal $Builtin.Int1, -1
%5 = struct $Bool (%4 : $Builtin.Int1)
%6 = integer_literal $Builtin.Int64, 64
%7 = struct $Int64 (%6 : $Builtin.Int64)
%8 = integer_literal $Builtin.Int1, -1
%9 = struct $Bool (%8 : $Builtin.Int1)
%10 = function_ref @getIntegerFormatSpecifier : $@convention(thin) (IntFormat, Bool, Int64, Bool) -> @owned String
%11 = apply %10(%3, %5, %7, %9) : $@convention(thin) (IntFormat, Bool, Int64, Bool) -> @owned String
return %11 : $String
} // CHECK: Returns string: "%{private}llx"
// CHECK-LABEL: @interpretGetPublicOctalInt32FormatString
sil @interpretGetPublicOctalInt32FormatString : $@convention(thin) () -> @owned String {
bb0:
%2 = metatype $@thin IntFormat.Type
%3 = enum $IntFormat, #IntFormat.octal!enumelt
%4 = integer_literal $Builtin.Int1, 0
%5 = struct $Bool (%4 : $Builtin.Int1)
%6 = integer_literal $Builtin.Int64, 32
%7 = struct $Int64 (%6 : $Builtin.Int64)
%8 = integer_literal $Builtin.Int1, -1
%9 = struct $Bool (%8 : $Builtin.Int1)
%10 = function_ref @getIntegerFormatSpecifier : $@convention(thin) (IntFormat, Bool, Int64, Bool) -> @owned String
%11 = apply %10(%3, %5, %7, %9) : $@convention(thin) (IntFormat, Bool, Int64, Bool) -> @owned String
return %11 : $String
} // CHECK: Returns string: "%{public}o"
// CHECK-LABEL: @interpretGetUInt64FormatString
sil @interpretGetUInt64FormatString : $@convention(thin) () -> @owned String {
bb0:
%2 = metatype $@thin IntFormat.Type
%3 = enum $IntFormat, #IntFormat.decimal!enumelt
%4 = integer_literal $Builtin.Int1, 0
%5 = struct $Bool (%4 : $Builtin.Int1)
%6 = integer_literal $Builtin.Int64, 64
%7 = struct $Int64 (%6 : $Builtin.Int64)
%8 = integer_literal $Builtin.Int1, 0
%9 = struct $Bool (%8 : $Builtin.Int1)
%10 = function_ref @getIntegerFormatSpecifier : $@convention(thin) (IntFormat, Bool, Int64, Bool) -> @owned String
%11 = apply %10(%3, %5, %7, %9) : $@convention(thin) (IntFormat, Bool, Int64, Bool) -> @owned String
return %11 : $String
} // CHECK: Returns string: "%{public}llu"
// String.percentEscapedString.getter
// The semantics attribute is used by the interpreter.
sil [serialized] [readonly] [_semantics "string.escapePercent.get"] @$sSS14OSLogPrototypeE20percentEscapedStringSSvg : $@convention(method) (@guaranteed String) -> @owned String
// CHECK-LABEL: @interpretStringPercentEscape
sil @interpretStringPercentEscape : $@convention(thin) () -> @owned String {
bb0:
%1 = string_literal utf8 "a%"
%2 = integer_literal $Builtin.Word, 2
%3 = integer_literal $Builtin.Int1, -1
%4 = metatype $@thin String.Type
%5 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%6 = apply %5(%1, %2, %3, %4) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%8 = function_ref @$sSS14OSLogPrototypeE20percentEscapedStringSSvg : $@convention(method) (@guaranteed String) -> @owned String
%9 = apply %8(%6) : $@convention(method) (@guaranteed String) -> @owned String
return %9 : $String
} // CHECK: Returns string: "a%%"
// CHECK-LABEL: @interpretEscapeMutiplePercent
sil @interpretEscapeMutiplePercent : $@convention(thin) () -> @owned String {
bb0:
%1 = string_literal utf8 "%%%a% %%b%"
%2 = integer_literal $Builtin.Word, 10
%3 = integer_literal $Builtin.Int1, -1
%4 = metatype $@thin String.Type
%5 = function_ref @$sSS21_builtinStringLiteral17utf8CodeUnitCount7isASCIISSBp_BwBi1_tcfC : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%6 = apply %5(%1, %2, %3, %4) : $@convention(method) (Builtin.RawPointer, Builtin.Word, Builtin.Int1, @thin String.Type) -> @owned String
%8 = function_ref @$sSS14OSLogPrototypeE20percentEscapedStringSSvg : $@convention(method) (@guaranteed String) -> @owned String
%9 = apply %8(%6) : $@convention(method) (@guaranteed String) -> @owned String
return %9 : $String
} // CHECK: Returns string: "%%%%%%a%% %%%%b%%"
// Tests for Ownership SIL.
// CHECK-LABEL: @interpretDestructureInt64
sil [ossa] @interpretDestructureInt64 : $@convention(thin) () -> Builtin.Int64 {
%1 = integer_literal $Builtin.Int64, 12
%2 = struct $Int64 (%1 : $Builtin.Int64)
%3 = destructure_struct %2 : $Int64
return %3 : $Builtin.Int64
} // CHECK: Returns int: 12
struct IntPair {
var first: Builtin.Int64
var second: Builtin.Int64
}
// CHECK-LABEL: @interpretIntPairStruct
sil [ossa] @interpretIntPairStruct : $@convention(thin) () -> Builtin.Int64 {
bb0:
%0 = integer_literal $Builtin.Int64, 17
%1 = integer_literal $Builtin.Int64, 34
%2 = struct $IntPair (%0: $Builtin.Int64, %1: $Builtin.Int64)
(%3, %4) = destructure_struct %2 : $IntPair
return %4 : $Builtin.Int64
} // CHECK: Returns int: 34
sil [ossa] @constructCustomStructOSSA : $@convention(thin) () -> CustomStruct {
bb0:
%1 = integer_literal $Builtin.Int64, 11
%2 = struct $Int64 (%1 : $Builtin.Int64)
%3 = integer_literal $Builtin.Int64, 12
%4 = struct $Int64 (%3 : $Builtin.Int64)
%6 = integer_literal $Builtin.Int64, 13
%7 = struct $Int64 (%6 : $Builtin.Int64)
%8 = integer_literal $Builtin.Int1, 0
%9 = struct $Bool (%8 : $Builtin.Int1)
%10 = struct $InnerStruct (%7 : $Int64, %9 : $Bool)
%11 = tuple (%2 : $Int64, %4 : $Int64)
%12 = struct $CustomStruct (%11 : $(Int64, Int64), %10 : $InnerStruct)
return %12 : $CustomStruct
}
// CHECK-LABEL: @interpretCustomStructOSSA
sil [ossa] @interpretCustomStructOSSA : $@convention(thin) () -> Builtin.Int64 {
bb0:
%1 = function_ref @constructCustomStructOSSA : $@convention(thin) () -> CustomStruct
%2 = apply %1() : $@convention(thin) () -> CustomStruct
(%3, %4) = destructure_struct %2 : $CustomStruct
(%5, %6) = destructure_tuple %3 : $(Int64, Int64)
(%7, %8) = destructure_struct %4 : $InnerStruct
%9 = destructure_struct %5 : $Int64
%10 = destructure_struct %6 : $Int64
%11 = destructure_struct %7 : $Int64
%12 = destructure_struct %8 : $Bool
cond_fail %12 : $Builtin.Int1
%13 = integer_literal $Builtin.Int1, -1
%14 = builtin "sadd_with_overflow_Int64"(%9 : $Builtin.Int64, %10 : $Builtin.Int64, %13 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
(%15, %16) = destructure_tuple %14 : $(Builtin.Int64, Builtin.Int1)
cond_fail %16 : $Builtin.Int1
%17 = builtin "sadd_with_overflow_Int64"(%15 : $Builtin.Int64, %11 : $Builtin.Int64, %13 : $Builtin.Int1) : $(Builtin.Int64, Builtin.Int1)
(%18, %19) = destructure_tuple %17 : $(Builtin.Int64, Builtin.Int1)
cond_fail %19 : $Builtin.Int1
return %18 : $Builtin.Int64
} // CHECK: Returns int: 36
// Tests for builtin "ptrtoint_Word", which is supported only for string
// constants in order to handle 'StaticString' construction.
// CHECK-LABEL: @interpretPtrToInt
sil @interpretPtrToInt : $@convention(thin) () -> Builtin.Word {
%0 = string_literal utf8 "Fatal error"
%1 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word
return %1 : $Builtin.Word
} // CHECK: Returns string: "Fatal error"
// CHECK-LABEL: @interpretStaticStringInit
sil @interpretStaticStringInit : $@convention(thin) () -> Builtin.Word {
%0 = string_literal utf8 "static error message"
%1 = integer_literal $Builtin.Word, 11
%2 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word
%3 = integer_literal $Builtin.Int8, 2
%4 = struct $StaticString (%2 : $Builtin.Word, %1 : $Builtin.Word, %3 : $Builtin.Int8)
%5 = struct_extract %4 : $StaticString, #StaticString._startPtrOrData
return %5 : $Builtin.Word
} // CHECK: Returns string: "static error message"
// Tests for builtin "assert_configuration". Constant evaluator evaluates this
// builtin to 0, meaning that the the configuration is "debug".
// CHECK-LABEL: @interpretAssertConfiguration
sil @interpretAssertConfiguration : $@convention(thin) () -> Builtin.Int32 {
%0 = builtin "assert_configuration"() : $Builtin.Int32
return %0 : $Builtin.Int32
} // CHECK: Returns int: 0
// Tests for "assertionFailure" stdlib functions. Such functions have the
// @_semantics attribute: "programtermination_point"
sil [noinline] [_semantics "programtermination_point"] [canonical] @$assertionFailure : $@convention(thin) (StaticString, StaticString, UInt64) -> Never
// CHECK-LABEL: @interpretAssertionFailure
sil @interpretAssertionFailure : $@convention(thin) () -> Never {
// Construct error prefix.
%0 = string_literal utf8 "error-prefix"
%1 = integer_literal $Builtin.Word, 12
%2 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word
%3 = integer_literal $Builtin.Int8, 2
%4 = struct $StaticString (%2 : $Builtin.Word, %1 : $Builtin.Word, %3 : $Builtin.Int8)
// Construct error message.
%10 = string_literal utf8 "message"
%11 = integer_literal $Builtin.Word, 7
%12 = builtin "ptrtoint_Word"(%10 : $Builtin.RawPointer) : $Builtin.Word
%13 = integer_literal $Builtin.Int8, 2
%14 = struct $StaticString (%12 : $Builtin.Word, %11 : $Builtin.Word, %13 : $Builtin.Int8)
// Construct line number.
%20 = integer_literal $Builtin.Int64, 1208
%21 = struct $UInt64 (%20 : $Builtin.Int64)
%22 = function_ref @$assertionFailure : $@convention(thin) (StaticString, StaticString, UInt64) -> Never
%23 = apply %22(%4, %14, %21) : $@convention(thin) (StaticString, StaticString, UInt64) -> Never
// CHECK: {{.*}}:[[@LINE-1]]:{{.*}}: note: error-prefix: message
unreachable
}
// Tests for arrays.
// Array.init()
sil [serialized] [_semantics "array.init.empty"] @$sS2ayxGycfC : $@convention(method) _0_0> (@thin Array_0_0>.Type) -> @owned Array_0_0>
// _allocateUninitializedArray<A>(_:)
sil [serialized] [always_inline] [_semantics "array.uninitialized_intrinsic"] @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
sil @interpretArrayInit : $@convention(thin) () -> @owned Array<Int> {
bb0:
%0 = metatype $@thin Array<Int>.Type
// function_ref Array.init()
%1 = function_ref @$sS2ayxGycfC : $@convention(method) _0_0> (@thin Array_0_0>.Type) -> @owned Array_0_0>
%2 = apply %1<Int>(%0) : $@convention(method) _0_0> (@thin Array_0_0>.Type) -> @owned Array_0_0>
return %2 : $Array<Int>
} // CHECK: Returns Array<Int>
// CHECK: size: 0 contents []
sil [ossa] @interpretEmptyArrayLiteral : $@convention(thin) () -> @owned Array<String> {
bb0:
%0 = integer_literal $Builtin.Word, 0
// function_ref _allocateUninitializedArray<A>(_:)
%1 = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
%2 = apply %1<String>(%0) : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
(%3, %4) = destructure_tuple %2 : $(Array<String>, Builtin.RawPointer)
return %3 : $Array<String>
} // CHECK: Returns Array<String>
// CHECK: size: 0 contents []
sil [ossa] @initializeArrayWithLiterals : $@convention(thin) () -> @owned Array<Int64> {
bb0:
%0 = integer_literal $Builtin.Int64, 11 // element 1
%1 = struct $Int64 (%0 : $Builtin.Int64)
%2 = integer_literal $Builtin.Int64, 12 // element 2
%3 = struct $Int64 (%2 : $Builtin.Int64)
%4 = integer_literal $Builtin.Int64, 14 // element 3
%5 = struct $Int64 (%4 : $Builtin.Int64)
%6 = integer_literal $Builtin.Word, 3 // array literal size
// function_ref _allocateUninitializedArray<A>(_:)
%7 = function_ref @$ss27_allocateUninitializedArrayySayxG_BptBwlF : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
%8 = apply %7<Int64>(%6) : $@convention(thin) _0_0> (Builtin.Word) -> (@owned Array_0_0>, Builtin.RawPointer)
(%9, %10) = destructure_tuple %8 : $(Array<Int64>, Builtin.RawPointer)
%11 = pointer_to_address %10 : $Builtin.RawPointer to [strict] $*Int64
store %1 to [trivial] %11 : $*Int64
%13 = integer_literal $Builtin.Word, 1 // Index: 1
%14 = index_addr %11 : $*Int64, %13 : $Builtin.Word
store %3 to [trivial] %14 : $*Int64
%16 = integer_literal $Builtin.Word, 2 // Index: 2
%17 = index_addr %11 : $*Int64, %16 : $Builtin.Word
store %5 to [trivial] %17 : $*Int64
return %9 : $Array<Int64>
}
sil [ossa] @interpretArrayLiteral : $@convention(thin) () -> @owned Array<Int64> {
bb0:
%7 = function_ref @initializeArrayWithLiterals : $@convention(thin) () -> @owned Array<Int64>
%8 = apply %7() : $@convention(thin) () -> @owned Array<Int64>
return %8 : $Array<Int64>
} // CHECK: Returns Array<Int64>
// CHECK: size: 3
// CHECK: agg: 1 elt: int: 11
// CHECK: agg: 1 elt: int: 12
// CHECK: agg: 1 elt: int: 14
// Array.append(_:)
sil [serialized] [_semantics "array.append_element"] @$sSa6appendyyxnF : $@convention(method) _0_0> (@in τ_0_0, @inout Array_0_0>) -> ()
sil [ossa] @interpretArrayAppend : $@convention(thin) () -> @owned Array<Int64> {
%0 = integer_literal $Builtin.Int64, 71
%1 = struct $Int64 (%0 : $Builtin.Int64)
%2 = alloc_stack $Array<Int64>, var, name "a"
%3 = metatype $@thin Array<Int64>.Type
// function_ref Array.init()
%4 = function_ref @$sS2ayxGycfC : $@convention(method) _0_0> (@thin Array_0_0>.Type) -> @owned Array_0_0>
%5 = apply %4<Int64>(%3) : $@convention(method) _0_0> (@thin Array_0_0>.Type) -> @owned Array_0_0>
store %5 to [init] %2 : $*Array<Int64>
%10 = alloc_stack $Int64
store %1 to [trivial] %10 : $*Int64
// function_ref Array.append(_:)
%13 = function_ref @$sSa6appendyyxnF : $@convention(method) _0_0> (@in τ_0_0, @inout Array_0_0>) -> ()
%14 = apply %13<Int64>(%10, %2) : $@convention(method) _0_0> (@in τ_0_0, @inout Array_0_0>) -> ()
dealloc_stack %10 : $*Int64
%18 = load [copy] %2 : $*Array<Int64>
destroy_addr %2 : $*Array<Int64>
dealloc_stack %2 : $*Array<Int64>
return %18 : $Array<Int64>
} // CHECK: Returns Array<Int64>
// CHECK: size: 1
// CHECK: agg: 1 elt: int: 71
sil [ossa] @interpretArrayAppendNonEmpty : $@convention(thin) () -> @owned Array<Int64> {
bb0:
%0 = integer_literal $Builtin.Int64, 100
%1 = struct $Int64 (%0 : $Builtin.Int64)
%2 = alloc_stack $Array<Int64>, var, name "a"
%3 = metatype $@thin Array<Int64>.Type
%4 = function_ref @initializeArrayWithLiterals : $@convention(thin) () -> @owned Array<Int64>
%5 = apply %4() : $@convention(thin) () -> @owned Array<Int64>
store %5 to [init] %2 : $*Array<Int64>
%10 = alloc_stack $Int64
store %1 to [trivial] %10 : $*Int64
// function_ref Array.append(_:)
%13 = function_ref @$sSa6appendyyxnF : $@convention(method) _0_0> (@in τ_0_0, @inout Array_0_0>) -> ()
%14 = apply %13<Int64>(%10, %2) : $@convention(method) _0_0> (@in τ_0_0, @inout Array_0_0>) -> ()
dealloc_stack %10 : $*Int64
%18 = load [copy] %2 : $*Array<Int64>
destroy_addr %2 : $*Array<Int64>
dealloc_stack %2 : $*Array<Int64>
return %18 : $Array<Int64>
} // CHECK: Returns Array<Int64>
// CHECK: size: 4
// CHECK: agg: 1 elt: int: 11
// CHECK: agg: 1 elt: int: 12
// CHECK: agg: 1 elt: int: 14
// CHECK: agg: 1 elt: int: 100
/// Test appending of a static string to an array. The construction of a static
/// string is a bit complicated due to the use of instructions like "ptrtoint".
/// This tests that array append works with such complex constant values as well.
sil @interpretArrayAppendStaticString : $@convention(thin) () -> @owned Array<StaticString> {
%0 = string_literal utf8 "constant" // string to be appended.
// Initialize an empty array
%2 = alloc_stack $Array<StaticString>, var, name "a"
%3 = metatype $@thin Array<StaticString>.Type
// function_ref Array.init()
%4 = function_ref @$sS2ayxGycfC : $@convention(method) _0_0> (@thin Array_0_0>.Type) -> @owned Array_0_0>
%5 = apply %4<StaticString>(%3) : $@convention(method) _0_0> (@thin Array_0_0>.Type) -> @owned Array_0_0>
store %5 to %2 : $*Array<StaticString>
// Initialize a static string.
%6 = integer_literal $Builtin.Word, 8
%7 = builtin "ptrtoint_Word"(%0 : $Builtin.RawPointer) : $Builtin.Word
%8 = integer_literal $Builtin.Int8, 2
%9 = struct $StaticString (%7 : $Builtin.Word, %6 : $Builtin.Word, %8 : $Builtin.Int8)
%10 = alloc_stack $StaticString
store %9 to %10 : $*StaticString
// function_ref Array.append(_:)
%13 = function_ref @$sSa6appendyyxnF : $@convention(method) _0_0> (@in τ_0_0, @inout Array_0_0>) -> ()
%14 = apply %13<StaticString>(%10, %2) : $@convention(method) _0_0> (@in τ_0_0, @inout Array_0_0>) -> ()
dealloc_stack %10 : $*StaticString
%18 = load %2 : $*Array<StaticString>
destroy_addr %2 : $*Array<StaticString>
dealloc_stack %2 : $*Array<StaticString>
return %18 : $Array<StaticString>
} // CHECK: Returns Array<StaticString>
// CHECK: size: 1
// CHECK: string: "constant"