mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
* access * accessed * accesses * accessor * acquiring * across * activated * additive * address * addresses' * aggregated * analysis * and * appropriately * archetype * argument * associated * availability * barriers * because * been * beginning * belongs * beneficial * blocks * borrow * builtin * cannot * canonical * canonicalize * clazz * cleanup * coalesceable * coalesced * comparisons * completely * component * computed * concrete * conjunction * conservatively * constituent * construct * consuming * containing * covered * creates * critical * dataflow * declaration * defined * defining * definition * deinitialization * deliberately * dependencies * dependent * deserialized * destroy * deterministic * deterministically * devirtualizes * diagnostic * diagnostics * differentiation * disable * discipline * dominate * dominates * don't * element * eliminate * eliminating * elimination * embedded * encounter * epilogue * epsilon * escape * escaping * essential * evaluating * evaluation * evaluator * executing * existential * existentials * explicit * expression * extended * extension * extract * for * from * function * generic * guarantee * guaranteed * happened * heuristic * however * identifiable * immediately * implementation * improper * include * infinite * initialize * initialized * initializer * inside * instruction * interference * interferes * interleaved * internal * intersection * intractable * intrinsic * invalidates * irreducible * irrelevant * language * lifetime * literal * looks * materialize * meaning * mergeable * might * mimics * modification * modifies * multiple * mutating * necessarily * necessary * needsmultiplecopies * nonetheless * nothing * occurred * occurs * optimization * optimizing * original * outside * overflow * overlapping * overridden * owned * ownership * parallel * parameter * paths * patterns * pipeline * plottable * possible * potentially * practically * preamble * precede * preceding * predecessor * preferable * preparation * probably * projection * properties * property * protocol * reabstraction * reachable * recognized * recursive * recursively * redundant * reentrancy * referenced * registry * reinitialization * reload * represent * requires * response * responsible * retrieving * returned * returning * returns * rewriting * rewritten * sample * scenarios * scope * should * sideeffects * similar * simplify * simplifycfg * somewhat * spaghetti * specialization * specializations * specialized * specially * statistically * substitute * substitution * succeeds * successful * successfully * successor * superfluous * surprisingly * suspension * swift * targeted * that * that our * the * therefore * this * those * threshold * through * transform * transformation * truncated * ultimate * unchecked * uninitialized * unlikely * unmanaged * unoptimized key * updataflow * usefulness * utilities * villain * whenever * writes Signed-off-by: Josh Soref <jsoref@users.noreply.github.com>
266 lines
9.7 KiB
Plaintext
266 lines
9.7 KiB
Plaintext
// RUN: %target-sil-opt -enable-experimental-static-assert %s -dataflow-diagnostics -verify
|
|
|
|
sil_stage canonical
|
|
|
|
import Builtin
|
|
import Swift
|
|
|
|
// Static assertion that "1 + 1 == 2".
|
|
sil @test1 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = integer_literal $Builtin.Int32, 1
|
|
%1 = builtin "add_Int32"(%0 : $Builtin.Int32, %0 : $Builtin.Int32) : $(Builtin.Int32)
|
|
%2 = integer_literal $Builtin.Int32, 2
|
|
%3 = builtin "cmp_eq_Int32"(%1 : $Builtin.Int32, %2 : $Builtin.Int32) : $(Builtin.Int1)
|
|
%4 = string_literal utf8 ""
|
|
%5 = builtin "poundAssert"(%3 : $Builtin.Int1, %4 : $Builtin.RawPointer) : $()
|
|
return undef : $()
|
|
}
|
|
|
|
// Static assertion that "2 + 2 == 5".
|
|
sil @test2 : $@convention(thin) () -> () {
|
|
bb0:
|
|
%0 = integer_literal $Builtin.Int32, 2
|
|
%1 = builtin "add_Int32"(%0 : $Builtin.Int32, %0 : $Builtin.Int32) : $(Builtin.Int32)
|
|
%2 = integer_literal $Builtin.Int32, 5
|
|
%3 = builtin "cmp_eq_Int32"(%1 : $Builtin.Int32, %2 : $Builtin.Int32) : $(Builtin.Int1)
|
|
%4 = string_literal utf8 ""
|
|
// expected-error @+1 {{assertion failed}}
|
|
%5 = builtin "poundAssert"(%3 : $Builtin.Int1, %4 : $Builtin.RawPointer) : $()
|
|
return undef : $()
|
|
}
|
|
|
|
// Tests that piecewise initialization of memory works during flow-sensitive
|
|
// evaluation, by piecewise initializing a tuple in a function.
|
|
sil @piecewiseInitFlowSensitive : $@convention(thin) () -> Bool {
|
|
bb0:
|
|
// Allocate and initialize the tuple to (1, 2).
|
|
%0 = alloc_stack $(Int64, Int64), var, name "tup"
|
|
%1 = tuple_element_addr %0 : $*(Int64, Int64), 0
|
|
%2 = tuple_element_addr %0 : $*(Int64, Int64), 1
|
|
%3 = integer_literal $Builtin.Int64, 1
|
|
%4 = struct $Int64 (%3 : $Builtin.Int64)
|
|
store %4 to %1 : $*Int64
|
|
%6 = integer_literal $Builtin.Int64, 2
|
|
%7 = struct $Int64 (%6 : $Builtin.Int64)
|
|
store %7 to %2 : $*Int64
|
|
|
|
// Read the first element from the tuple.
|
|
%9 = begin_access [read] [static] %0 : $*(Int64, Int64)
|
|
%10 = tuple_element_addr %9 : $*(Int64, Int64), 0
|
|
%11 = load %10 : $*Int64
|
|
end_access %9 : $*(Int64, Int64)
|
|
|
|
// Check that the first element is what we put in.
|
|
%13 = struct_extract %11 : $Int64, #Int64._value
|
|
%14 = builtin "cmp_eq_Int64"(%3 : $Builtin.Int64, %13 : $Builtin.Int64) : $Builtin.Int1
|
|
%15 = struct $Bool (%14 : $Builtin.Int1)
|
|
|
|
// Deallocate and return.
|
|
dealloc_stack %0 : $*(Int64, Int64)
|
|
return %15 : $Bool
|
|
}
|
|
|
|
sil @invokePiecewiseInitFlowSensitiveTest : $@convention(thin) () -> () {
|
|
%0 = function_ref @piecewiseInitFlowSensitive : $@convention(thin) () -> Bool
|
|
%1 = apply %0() : $@convention(thin) () -> Bool
|
|
%2 = struct_extract %1 : $Bool, #Bool._value
|
|
%3 = string_literal utf8 ""
|
|
%4 = builtin "poundAssert"(%2 : $Builtin.Int1, %3 : $Builtin.RawPointer) : $()
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|
|
|
|
// Tests copy_addr interpretation.
|
|
sil @copyAddr : $@convention(thin) () -> Bool {
|
|
// Allocate an initialize an Int64 to 1.
|
|
%0 = alloc_stack $Int64
|
|
%1 = integer_literal $Builtin.Int64, 1
|
|
%2 = struct $Int64 (%1 : $Builtin.Int64)
|
|
store %2 to %0 : $*Int64
|
|
|
|
// Allocate another Int64 and copy to it.
|
|
%4 = alloc_stack $Int64
|
|
copy_addr %0 to %4 : $*Int64
|
|
|
|
// Check that the value is what we put in the original Int64.
|
|
%5 = begin_access [read] [static] %4 : $*Int64
|
|
%6 = load %5 : $*Int64
|
|
end_access %5 : $*Int64
|
|
%8 = struct_extract %6 : $Int64, #Int64._value
|
|
%9 = builtin "cmp_eq_Int64"(%1 : $Builtin.Int64, %8 : $Builtin.Int64) : $Builtin.Int1
|
|
%10 = struct $Bool (%9 : $Builtin.Int1)
|
|
|
|
// Deallocate and return.
|
|
dealloc_stack %4 : $*Int64
|
|
dealloc_stack %0 : $*Int64
|
|
return %10 : $Bool
|
|
}
|
|
|
|
sil @invokeCopyAddrTest : $@convention(thin) () -> () {
|
|
%0 = function_ref @copyAddr : $@convention(thin) () -> Bool
|
|
%1 = apply %0() : $@convention(thin) () -> Bool
|
|
%2 = struct_extract %1 : $Bool, #Bool._value
|
|
%3 = string_literal utf8 ""
|
|
%4 = builtin "poundAssert"(%2 : $Builtin.Int1, %3 : $Builtin.RawPointer) : $()
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|
|
|
|
// A function with @out result to help with some tests.
|
|
sil @setInt64To1 : $@convention(thin) () -> (@out Int64) {
|
|
bb0(%0 : $*Int64):
|
|
%1 = integer_literal $Builtin.Int64, 1
|
|
%2 = struct $Int64 (%1 : $Builtin.Int64)
|
|
store %2 to %0 : $*Int64
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|
|
|
|
// Tests that initialization of memory using `store` works during top-level
|
|
// evaluation.
|
|
sil @storeInitTopLevel : $@convention(thin) () -> () {
|
|
%0 = alloc_stack $Int64
|
|
%1 = integer_literal $Builtin.Int64, 1
|
|
%2 = struct $Int64 (%1 : $Builtin.Int64)
|
|
store %2 to %0 : $*Int64
|
|
%4 = load %0 : $*Int64
|
|
%5 = struct_extract %4 : $Int64, #Int64._value
|
|
%6 = builtin "cmp_eq_Int64"(%1 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int1
|
|
%7 = string_literal utf8 ""
|
|
%8 = builtin "poundAssert"(%6 : $Builtin.Int1, %7 : $Builtin.RawPointer) : $()
|
|
dealloc_stack %0 : $*Int64
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|
|
|
|
// Tests that initialization of memory using `copy_addr` works during top-level
|
|
// evaluation.
|
|
sil @copyInitTopLevel : $@convention(thin) () -> () {
|
|
%0 = alloc_stack $Int64
|
|
%1 = alloc_stack $Int64
|
|
%2 = integer_literal $Builtin.Int64, 1
|
|
%3 = struct $Int64 (%2 : $Builtin.Int64)
|
|
store %3 to %0 : $*Int64
|
|
copy_addr %0 to %1 : $*Int64
|
|
%6 = load %1 : $*Int64
|
|
%7 = struct_extract %6 : $Int64, #Int64._value
|
|
%8 = builtin "cmp_eq_Int64"(%2 : $Builtin.Int64, %7 : $Builtin.Int64) : $Builtin.Int1
|
|
%9 = string_literal utf8 ""
|
|
%10 = builtin "poundAssert"(%8 : $Builtin.Int1, %9 : $Builtin.RawPointer) : $()
|
|
dealloc_stack %1 : $*Int64
|
|
dealloc_stack %0 : $*Int64
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|
|
|
|
// Tests that initialization of memory using `apply` works during top-level
|
|
// evaluation.
|
|
sil @applyInitTopLevel : $@convention(thin) () -> () {
|
|
%0 = alloc_stack $Int64
|
|
%1 = function_ref @setInt64To1: $@convention(thin) () -> (@out Int64)
|
|
%2 = apply %1(%0) : $@convention(thin) () -> (@out Int64)
|
|
%3 = load %0 : $*Int64
|
|
%4 = struct_extract %3 : $Int64, #Int64._value
|
|
%5 = integer_literal $Builtin.Int64, 1
|
|
%6 = builtin "cmp_eq_Int64"(%4 : $Builtin.Int64, %5 : $Builtin.Int64) : $Builtin.Int1
|
|
%7 = string_literal utf8 ""
|
|
%8 = builtin "poundAssert"(%6 : $Builtin.Int1, %7 : $Builtin.RawPointer) : $()
|
|
dealloc_stack %0 : $*Int64
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|
|
|
|
// Tests that piecewise initialization of tuple memory works during top-level
|
|
// evaluation.
|
|
sil @piecewiseInitTopLevel : $@convention(thin) () -> () {
|
|
bb0:
|
|
// Allocate and initialize the tuple to (1, 2).
|
|
%0 = alloc_stack $(Int64, Int64), var, name "tup"
|
|
%1 = tuple_element_addr %0 : $*(Int64, Int64), 0
|
|
%2 = tuple_element_addr %0 : $*(Int64, Int64), 1
|
|
%3 = integer_literal $Builtin.Int64, 1
|
|
%4 = struct $Int64 (%3 : $Builtin.Int64)
|
|
store %4 to %1 : $*Int64
|
|
%6 = integer_literal $Builtin.Int64, 2
|
|
%7 = struct $Int64 (%6 : $Builtin.Int64)
|
|
store %7 to %2 : $*Int64
|
|
|
|
// Read the first element from the tuple.
|
|
// TODO: Allow `begin_access` in top level initialization.
|
|
// %9 = begin_access [read] [static] %0 : $*(Int64, Int64)
|
|
%10 = tuple_element_addr %0 : $*(Int64, Int64), 0
|
|
%11 = load %10 : $*Int64
|
|
// end_access %9 : $*(Int64, Int64)
|
|
|
|
// Check that the first element is what we put in.
|
|
%13 = struct_extract %11 : $Int64, #Int64._value
|
|
%14 = builtin "cmp_eq_Int64"(%3 : $Builtin.Int64, %13 : $Builtin.Int64) : $Builtin.Int1
|
|
%15 = string_literal utf8 ""
|
|
%16 = builtin "poundAssert"(%14 : $Builtin.Int1, %15 : $Builtin.RawPointer) : $()
|
|
|
|
// Deallocate and return.
|
|
dealloc_stack %0 : $*(Int64, Int64)
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|
|
|
|
// Tests that top-level evaluation detects memory that gets written to twice.
|
|
sil @doubleWriteTopLevel : $@convention(thin) () -> () {
|
|
// expected-note @+1 {{top-level value has multiple assignments}}
|
|
%0 = alloc_stack $Int64
|
|
%1 = integer_literal $Builtin.Int64, 1
|
|
%2 = struct $Int64 (%1 : $Builtin.Int64)
|
|
store %2 to %0 : $*Int64
|
|
store %2 to %0 : $*Int64
|
|
%5 = load %0 : $*Int64
|
|
%6 = struct_extract %5 : $Int64, #Int64._value
|
|
%7 = builtin "cmp_eq_Int64"(%1 : $Builtin.Int64, %6 : $Builtin.Int64) : $Builtin.Int1
|
|
%8 = string_literal utf8 ""
|
|
// expected-error @+1 {{#assert condition not constant}}
|
|
%9 = builtin "poundAssert"(%7 : $Builtin.Int1, %8 : $Builtin.RawPointer) : $()
|
|
dealloc_stack %0 : $*Int64
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|
|
|
|
// There was a bug where the evaluator would not detect a double-write to a
|
|
// tuple element at the top level if one of the writes an unknown value.
|
|
sil @doubleWriteTupleElement : $@convention(thin) (Int64) -> () {
|
|
bb0(%arg : $Int64):
|
|
// Allocate and initialize the tuple to (1, 2).
|
|
%0 = alloc_stack $(Int64, Int64), var, name "tup"
|
|
%1 = tuple_element_addr %0 : $*(Int64, Int64), 0
|
|
%2 = tuple_element_addr %0 : $*(Int64, Int64), 1
|
|
%3 = integer_literal $Builtin.Int64, 1
|
|
%4 = struct $Int64 (%3 : $Builtin.Int64)
|
|
store %4 to %1 : $*Int64
|
|
%6 = integer_literal $Builtin.Int64, 2
|
|
%7 = struct $Int64 (%6 : $Builtin.Int64)
|
|
store %7 to %2 : $*Int64
|
|
|
|
// Store %arg, whose value is unknown, to the first element of the tuple.
|
|
%addr = tuple_element_addr %0 : $*(Int64, Int64), 0
|
|
store %arg to %addr : $*Int64
|
|
|
|
// Read the first element from the tuple.
|
|
// TODO: Allow `begin_access` in top level initialization.
|
|
// %9 = begin_access [read] [static] %0 : $*(Int64, Int64)
|
|
%10 = tuple_element_addr %0 : $*(Int64, Int64), 0
|
|
%11 = load %10 : $*Int64
|
|
// end_access %9 : $*(Int64, Int64)
|
|
|
|
// Check that the first element is what we put in.
|
|
%13 = struct_extract %11 : $Int64, #Int64._value
|
|
%14 = builtin "cmp_eq_Int64"(%3 : $Builtin.Int64, %13 : $Builtin.Int64) : $Builtin.Int1
|
|
%15 = string_literal utf8 ""
|
|
// expected-error @+1 {{#assert condition not constant}}
|
|
%16 = builtin "poundAssert"(%14 : $Builtin.Int1, %15 : $Builtin.RawPointer) : $()
|
|
// expected-note @-1 {{cannot evaluate expression as constant here}}
|
|
|
|
// Deallocate and return.
|
|
dealloc_stack %0 : $*(Int64, Int64)
|
|
%ret = tuple ()
|
|
return %ret : $()
|
|
}
|