diff options
| author | Reid Kleckner <reid@kleckner.net> | 2013-09-10 20:14:30 +0000 |
|---|---|---|
| committer | Reid Kleckner <reid@kleckner.net> | 2013-09-10 20:14:30 +0000 |
| commit | d8110b6558ad111a1c1c1542c12122900791311e (patch) | |
| tree | f33978db28811dcedd14fcba833b925738598b84 /clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp | |
| parent | 1cee407a9b5cec3251157378e9d44dacae51b68d (diff) | |
| download | bcm5719-llvm-d8110b6558ad111a1c1c1542c12122900791311e.tar.gz bcm5719-llvm-d8110b6558ad111a1c1c1542c12122900791311e.zip | |
[ms-cxxabi] Implement guard variables for static initialization
Static locals requiring initialization are not thread safe on Windows.
Unfortunately, it's possible to create static locals that are actually
externally visible with inline functions and templates. As a result, we
have to implement an initialization guard scheme that is compatible with
TUs built by MSVC, which makes thread safety prohibitively difficult.
MSVC's scheme is that every function that requires a guard gets an i32
bitfield. Each static local is assigned a bit that indicates if it has
been initialized, up to 32 bits, at which point a new bitfield is
created. MSVC rejects inline functions with more than 32 static locals,
and the externally visible mangling (?_B) only allows for one guard
variable per function.
On Eli's recommendation, I used MangleNumberingContext to track which
bit each static corresponds to.
Implements PR16888.
Reviewers: rjmccall, eli.friedman
Differential Revision: http://llvm-reviews.chandlerc.com/D1416
llvm-svn: 190427
Diffstat (limited to 'clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp')
| -rw-r--r-- | clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp | 111 |
1 files changed, 104 insertions, 7 deletions
diff --git a/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp b/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp index 56536b1a570..6c4e9e72f4a 100644 --- a/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp +++ b/clang/test/CodeGenCXX/microsoft-abi-static-initializers.cpp @@ -5,19 +5,81 @@ // CHECK: { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_a }] struct S { - S() {} - ~S() {} -} s; + S(); + ~S(); +}; + +S s; // CHECK: define internal void [[INIT_s:@.*global_var.*]] [[NUW:#[0-9]+]] // CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ" -// CHECK: call i32 @atexit(void ()* @"__dtor_\01?s@@3US@@A") +// CHECK: call i32 @atexit(void ()* @"\01??__Fs@@YAXXZ") // CHECK: ret void -// CHECK: define internal void @"__dtor_\01?s@@3US@@A"() [[NUW]] { +// CHECK: define internal void @"\01??__Fs@@YAXXZ"() [[NUW]] { // CHECK: call x86_thiscallcc void @"\01??1S@@QAE@XZ" // CHECK: ret void +void StaticLocal() { + static S TheS; +} +// CHECK-LABEL: define void @"\01?StaticLocal@@YAXXZ"() +// CHECK: load i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA" +// CHECK: store i32 {{.*}}, i32* @"\01?$S1@?1??StaticLocal@@YAXXZ@4IA" +// CHECK: ret + +void MultipleStatics() { + static S S1; + static S S2; + static S S3; + static S S4; + static S S5; + static S S6; + static S S7; + static S S8; + static S S9; + static S S10; + static S S11; + static S S12; + static S S13; + static S S14; + static S S15; + static S S16; + static S S17; + static S S18; + static S S19; + static S S20; + static S S21; + static S S22; + static S S23; + static S S24; + static S S25; + static S S26; + static S S27; + static S S28; + static S S29; + static S S30; + static S S31; + static S S32; + static S S33; + static S S34; + static S S35; +} +// CHECK-LABEL: define void @"\01?MultipleStatics@@YAXXZ"() +// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA" +// CHECK: and i32 {{.*}}, 1 +// CHECK: and i32 {{.*}}, 2 +// CHECK: and i32 {{.*}}, 4 +// CHECK: and i32 {{.*}}, 8 +// CHECK: and i32 {{.*}}, 16 +// ... +// CHECK: and i32 {{.*}}, -2147483648 +// CHECK: load i32* @"\01?$S1@?1??MultipleStatics@@YAXXZ@4IA1" +// CHECK: and i32 {{.*}}, 1 +// CHECK: and i32 {{.*}}, 2 +// CHECK: and i32 {{.*}}, 4 +// CHECK: ret + // Force WeakODRLinkage by using templates class A { public: @@ -33,20 +95,55 @@ class B { template<typename T> A B<T>::foo; +inline S &UnreachableStatic() { + if (0) { + static S s; // bit 1 + return s; + } + static S s; // bit 2 + return s; +} + +// CHECK-LABEL: define linkonce_odr %struct.S* @"\01?UnreachableStatic@@YAAAUS@@XZ"() +// CHECK: and i32 {{.*}}, 2 +// CHECK: or i32 {{.*}}, 2 +// CHECK: ret + +inline S &getS() { + static S TheS; + return TheS; +} + +// CHECK-LABEL: define linkonce_odr %struct.S* @"\01?getS@@YAAAUS@@XZ" +// CHECK: load i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51" +// CHECK: and i32 {{.*}}, 1 +// CHECK: icmp ne i32 {{.*}}, 0 +// CHECK: br i1 +// init: +// CHECK: or i32 {{.*}}, 1 +// CHECK: store i32 {{.*}}, i32* @"\01??_B?1??getS@@YAAAUS@@XZ@51" +// CHECK: call x86_thiscallcc %struct.S* @"\01??0S@@QAE@XZ"(%struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A") +// CHECK: call i32 @atexit(void ()* @"\01??__FTheS@?1??getS@@YAAAUS@@XZ@YAXXZ") +// CHECK: br label +// init.end: +// CHECK: ret %struct.S* @"\01?TheS@?1??getS@@YAAAUS@@XZ@4U2@A" + void force_usage() { + UnreachableStatic(); + getS(); (void)B<int>::foo; // (void) - force usage } // CHECK: define internal void [[INIT_foo]]() [[NUW]] // CHECK: %{{[.0-9A-Z_a-z]+}} = call x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ" -// CHECK: call i32 @atexit(void ()* [[FOO_DTOR:@"__dtor_.*foo@.*]]) +// CHECK: call i32 @atexit(void ()* @"\01??__Ffoo@?$B@H@@YAXXZ") // CHECK: ret void // CHECK: define linkonce_odr x86_thiscallcc %class.A* @"\01??0A@@QAE@XZ" // CHECK: define linkonce_odr x86_thiscallcc void @"\01??1A@@QAE@XZ" -// CHECK: define internal void [[FOO_DTOR]] +// CHECK: define internal void @"\01??__Ffoo@?$B@H@@YAXXZ" // CHECK: call x86_thiscallcc void @"\01??1A@@QAE@XZ"{{.*}}foo // CHECK: ret void |

