For the following code:
struct Hat {
init() {}
}
struct HatInjector {
static var hat = Hat()
}
HatInjector.hat = Hat()
The relevant SIL emitted for the static property's accessor + property initialiser expression:
sil private @globalinit_33_12232F587A4C5CD8B1EEDF696793A4FC_func0 : $@convention(thin) () -> () {
bb0:
// simply initialise the storage for the static variable, and get the address of the storage.
alloc_global @static main.HatInjector.hat : main.Hat
%1 = global_addr @static main.HatInjector.hat : main.Hat : $*Hat
// call Hat's initialiser, and store the resultant instance in the static variable's storage.
%2 = function_ref @main.Hat.init () -> main.Hat : $@convention(method) (@thin Hat.Type) -> Hat
%3 = metatype $@thin Hat.Type
%4 = apply %2(%3) : $@convention(method) (@thin Hat.Type) -> Hat
store %4 to %1 : $*Hat
%6 = tuple ()
return %6 : $()
}
sil hidden [global_init] @main.HatInjector.hat.unsafeMutableAddressor : main.Hat : $@convention(thin) () -> Builtin.RawPointer {
bb0:
// get a pointer to a global flag determining whether HatInjector.hat has been initialised.
%0 = global_addr @globalinit_33_12232F587A4C5CD8B1EEDF696793A4FC_token0 : $*Builtin.Word
%1 = address_to_pointer %0 : $*Builtin.Word to $Builtin.RawPointer
// get a reference to the function used to initialise HatInjector.hat.
%2 = function_ref @globalinit_33_12232F587A4C5CD8B1EEDF696793A4FC_func0 : $@convention(thin) () -> ()
// call the builtin "once" operation (will be replaced by a call to swift_once in IR Gen) with the pointer to the
// flag, and the function to initialise HatInjector.hat.
%3 = builtin "once"(%1 : $Builtin.RawPointer, %2 : $@convention(thin) () -> ()) : $()
// get and return a pointer to the static variable's storage.
%4 = global_addr @static main.HatInjector.hat : main.Hat : $*Hat
%5 = address_to_pointer %4 : $*Hat to $Builtin.RawPointer
return %5 : $Builtin.RawPointer
}
Examining the IR reveals that the builtin "once" operation calls swift_once
:
define hidden i8* @main.HatInjector.hat.unsafeMutableAddressor : main.Hat() #0 {
entry:
%0 = load i64, i64* @globalinit_33_12232F587A4C5CD8B1EEDF696793A4FC_token0, align 8
%1 = icmp eq i64 %0, -1
br i1 %1, label %once_done, label %once_not_done
once_not_done: ; preds = %entry
call void @swift_once(i64* @globalinit_33_12232F587A4C5CD8B1EEDF696793A4FC_token0, i8* bitcast (void ()* @globalinit_33_12232F587A4C5CD8B1EEDF696793A4FC_func0 to i8*))
br label %once_done
once_done: ; preds = %once_not_done, %entry
%2 = load i64, i64* @globalinit_33_12232F587A4C5CD8B1EEDF696793A4FC_token0, align 8
%3 = icmp eq i64 %2, -1
call void @llvm.assume(i1 %3)
ret i8* undef
}