blob: 8f094f633febba6a125c84cea9cfdbd35945083f [file] [log] [blame]
// 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
}