Skip to content

Instantly share code, notes, and snippets.

@hamishknight
Last active April 13, 2017 12:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hamishknight/6be785520105349f1458a3fcec6ff731 to your computer and use it in GitHub Desktop.
Save hamishknight/6be785520105349f1458a3fcec6ff731 to your computer and use it in GitHub Desktop.

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
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment