I like to use LLVM because the code it generates tells you a bit more explicitly what it's doing:
The actual code is below, because it's kind of a long read. Yes, LLVM creates guard condition variables for static values. notice how static_initialization
/bb:
acquires the guard, checks to see if its a certain value corresponding with already initialized, and either branches to bb1 if it needs to initialize, or bb2 if it doesn't. This isn't the only way to possibly solve the single initialization requirement, but it's the usual way.
; ModuleID = '/tmp/webcompile/_31867_0.bc'
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64"
target triple = "x86_64-linux-gnu"
@guard variable for static_initialization(int)::value = internal global i64 0 ; <i64*> [#uses=3]
@static_initialization(int)::value = internal global i32 0 ; <i32*> [#uses=1]
define void @no_static_initialization()() nounwind {
entry:
br label %return
return: ; preds = %entry
ret void
}
define void @static_initialization(int)(i32 %new_value) nounwind {
entry:
%new_value_addr = alloca i32 ; <i32*> [#uses=2]
%0 = alloca i8 ; <i8*> [#uses=2]
%retval.1 = alloca i8 ; <i8*> [#uses=2]
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
store i32 %new_value, i32* %new_value_addr
%1 = load i8* bitcast (i64* @guard variable for static_initialization(int)::value to i8*), align 1 ; <i8> [#uses=1]
%2 = icmp eq i8 %1, 0 ; <i1> [#uses=1]
br i1 %2, label %bb, label %bb2
bb: ; preds = %entry
%3 = call i32 @__cxa_guard_acquire(i64* @guard variable for static_initialization(int)::value) nounwind ; <i32> [#uses=1]
%4 = icmp ne i32 %3, 0 ; <i1> [#uses=1]
%5 = zext i1 %4 to i8 ; <i8> [#uses=1]
store i8 %5, i8* %retval.1, align 1
%6 = load i8* %retval.1, align 1 ; <i8> [#uses=1]
%toBool = icmp ne i8 %6, 0 ; <i1> [#uses=1]
br i1 %toBool, label %bb1, label %bb2
bb1: ; preds = %bb
store i8 0, i8* %0, align 1
%7 = load i32* %new_value_addr, align 4 ; <i32> [#uses=1]
store i32 %7, i32* @static_initialization(int)::value, align 4
store i8 1, i8* %0, align 1
call void @__cxa_guard_release(i64* @guard variable for static_initialization(int)::value) nounwind
br label %bb2
bb2: ; preds = %bb1, %bb, %entry
br label %return
return: ; preds = %bb2
ret void
}
declare i32 @__cxa_guard_acquire(i64*) nounwind
declare void @__cxa_guard_release(i64*) nounwind
define i32 @main() nounwind {
entry:
%retval = alloca i32 ; <i32*> [#uses=2]
%0 = alloca i32 ; <i32*> [#uses=2]
%"alloca point" = bitcast i32 0 to i32 ; <i32> [#uses=0]
call void @no_static_initialization()() nounwind
call void @static_initialization(int)(i32 1) nounwind
%1 = call i32 @rand() nounwind ; <i32> [#uses=1]
call void @static_initialization(int)(i32 %1) nounwind
store i32 0, i32* %0, align 4
%2 = load i32* %0, align 4 ; <i32> [#uses=1]
store i32 %2, i32* %retval, align 4
br label %return
return: ; preds = %entry
%retval1 = load i32* %retval ; <i32> [#uses=1]
ret i32 %retval1
}
declare i32 @rand() nounwind