| // RUN: %target-sil-opt -enable-sil-verify-all %s -global-opt | %FileCheck %s |
| |
| // This tests GlobalOpt of a trivial global variable |
| // Loads of trivial global variable initialized with a constant is replaced with the constant in GlobalOpt |
| // This also tests GlobalOpt to be a no-op for a non-trivial global variable used in the same way |
| // The difference in GlobalOpt for trivial v/s non-trivial values is shown in $bartrivial and $barnontrivial |
| |
| sil_stage canonical |
| |
| import Builtin |
| import Swift |
| import SwiftShims |
| |
| public struct TStruct { |
| let x: Int32 |
| init(x: Int32) |
| } |
| |
| let trivialglobal: TStruct |
| |
| public class TClass { |
| final let x: Int32 |
| init(x: Int32) |
| deinit |
| } |
| |
| let nontrivialglobal: TClass |
| |
| // CHECK-LABEL: sil_global hidden [let] @$trivialglobal : $TStruct = { |
| // CHECK: [[CONST:%.*]] = integer_literal $Builtin.Int32, 10 |
| // CHECK: [[INT:%.*]] = struct $Int32 ([[CONST]] : $Builtin.Int32) |
| // CHECK: %initval = struct $TStruct ([[INT]] : $Int32) |
| sil_global private @globalinit_trivialglobal_token : $Builtin.Word |
| |
| sil_global hidden [let] @$trivialglobal : $TStruct |
| |
| sil_global private @globalinit_nontrivialglobal_token : $Builtin.Word |
| |
| sil_global hidden [let] @$nontrivialglobal : $TClass |
| |
| sil private [global_init_once_fn] @globalinit_trivialglobal_func : $@convention(c) () -> () { |
| bb0: |
| alloc_global @$trivialglobal |
| %1 = global_addr @$trivialglobal : $*TStruct |
| %2 = integer_literal $Builtin.Int32, 10 |
| %3 = struct $Int32 (%2 : $Builtin.Int32) |
| %4 = struct $TStruct (%3 : $Int32) |
| store %4 to %1 : $*TStruct |
| %6 = tuple () |
| return %6 : $() |
| } |
| |
| // CHECK-LABEL: sil hidden [global_init] @$trivialglobal_unsafemutableaddressor : |
| // CHECK: [[GLOBL:%.*]] = global_addr @$trivialglobal : $*TStruct |
| // CHECK: [[GLOBL_ADDR:%.*]] = address_to_pointer [[GLOBL]] : $*TStruct to $Builtin.RawPointer |
| // CHECK: return [[GLOBL_ADDR]] : $Builtin.RawPointer |
| // CHECK: } // end sil function '$trivialglobal_unsafemutableaddressor' |
| sil hidden [global_init] @$trivialglobal_unsafemutableaddressor : $@convention(thin) () -> Builtin.RawPointer { |
| bb0: |
| %0 = global_addr @globalinit_trivialglobal_token : $*Builtin.Word |
| %1 = address_to_pointer %0 : $*Builtin.Word to $Builtin.RawPointer |
| %2 = function_ref @globalinit_trivialglobal_func : $@convention(c) () -> () |
| %3 = builtin "once"(%1 : $Builtin.RawPointer, %2 : $@convention(c) () -> ()) : $() |
| %4 = global_addr @$trivialglobal : $*TStruct |
| %5 = address_to_pointer %4 : $*TStruct to $Builtin.RawPointer |
| return %5 : $Builtin.RawPointer |
| } |
| |
| // $bartrivial's access to the trivial global variable via the accessor is optimized to the rhs of the init value |
| |
| // CHECK-LABEL: sil hidden [noinline] @$bartrivial : |
| // CHECK: [[CONST:%.*]] = integer_literal $Builtin.Int32, 10 |
| // CHECK: [[INT:%.*]] = struct $Int32 ([[CONST]] : $Builtin.Int32) |
| // CHECK: return [[INT]] : $Int32 |
| // CHECK-LABEL: } // end sil function '$bartrivial' |
| sil hidden [noinline] @$bartrivial : $@convention(thin) () -> Int32 { |
| bb0: |
| %0 = function_ref @$trivialglobal_unsafemutableaddressor : $@convention(thin) () -> Builtin.RawPointer |
| %1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer |
| %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*TStruct |
| %3 = struct_element_addr %2 : $*TStruct, #TStruct.x |
| %4 = load %3 : $*Int32 |
| return %4 : $Int32 |
| } |
| |
| // CHECK-LABEL: sil private [global_init_once_fn] @globalinit_nontrivialglobal_func : |
| // CHECK: alloc_global @$nontrivialglobal |
| // CHECK: [[GLOBL_ADDR:%.*]] = global_addr @$nontrivialglobal : $*TClass |
| // CHECK: [[REF:%.*]] = alloc_ref $TClass |
| // CHECK: store [[REF]] to [[GLOBL_ADDR]] : $*TClass |
| // CHECK: } // end sil function 'globalinit_nontrivialglobal_func' |
| sil private [global_init_once_fn] @globalinit_nontrivialglobal_func : $@convention(c) () -> () { |
| bb0: |
| alloc_global @$nontrivialglobal |
| %1 = global_addr @$nontrivialglobal : $*TClass |
| %2 = integer_literal $Builtin.Int32, 10 |
| %3 = struct $Int32 (%2 : $Builtin.Int32) |
| %4 = alloc_ref $TClass |
| %7 = ref_element_addr %4 : $TClass, #TClass.x |
| store %3 to %7 : $*Int32 |
| store %4 to %1 : $*TClass |
| %10 = tuple () |
| return %10 : $() |
| } |
| |
| sil hidden [global_init] @$nontrivialglobal_unsafemutableaccessor : $@convention(thin) () -> Builtin.RawPointer { |
| bb0: |
| %0 = global_addr @globalinit_nontrivialglobal_token : $*Builtin.Word |
| %1 = address_to_pointer %0 : $*Builtin.Word to $Builtin.RawPointer |
| %2 = function_ref @globalinit_nontrivialglobal_func : $@convention(c) () -> () |
| %3 = builtin "once"(%1 : $Builtin.RawPointer, %2 : $@convention(c) () -> ()) : $() |
| %4 = global_addr @$nontrivialglobal : $*TClass |
| %5 = address_to_pointer %4 : $*TClass to $Builtin.RawPointer |
| return %5 : $Builtin.RawPointer |
| } |
| |
| // $barnontrivial's access to the non-trivial global variable does not get optimized away |
| |
| // CHECK-LABEL: sil hidden [noinline] @$barnontrivial : |
| // CHECK: [[FUNC_REF:%.*]] = function_ref @$nontrivialglobal_unsafemutableaccessor : |
| // CHECK: [[APPLY:%.*]] = apply [[FUNC_REF]]() : |
| // CHECK-LABEL: } // end sil function '$barnontrivial' |
| sil hidden [noinline] @$barnontrivial : $@convention(thin) () -> Int32 { |
| bb0: |
| %0 = function_ref @$nontrivialglobal_unsafemutableaccessor : $@convention(thin) () -> Builtin.RawPointer |
| %1 = apply %0() : $@convention(thin) () -> Builtin.RawPointer |
| %2 = pointer_to_address %1 : $Builtin.RawPointer to [strict] $*TClass |
| %3 = load %2 : $*TClass |
| %4 = ref_element_addr %3 : $TClass, #TClass.x |
| %5 = load %4 : $*Int32 |
| return %5 : $Int32 |
| } |
| |