diff options
Diffstat (limited to 'clang/test/CodeGenCXX/trivial-auto-var-init.cpp')
-rw-r--r-- | clang/test/CodeGenCXX/trivial-auto-var-init.cpp | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/clang/test/CodeGenCXX/trivial-auto-var-init.cpp b/clang/test/CodeGenCXX/trivial-auto-var-init.cpp new file mode 100644 index 00000000000..8b35fdb441a --- /dev/null +++ b/clang/test/CodeGenCXX/trivial-auto-var-init.cpp @@ -0,0 +1,216 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fblocks %s -emit-llvm -o - | FileCheck %s -check-prefix=UNINIT +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -fblocks -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO + +// None of the synthesized globals should contain `undef`. +// PATTERN-NOT: undef +// ZERO-NOT: undef + +template<typename T> void used(T &) noexcept; + +extern "C" { + +// UNINIT-LABEL: test_selfinit( +// ZERO-LABEL: test_selfinit( +// ZERO: store i32 0, i32* %self, align 4 +// PATTERN-LABEL: test_selfinit( +// PATTERN: store i32 -1431655766, i32* %self, align 4 +void test_selfinit() { + int self = self + 1; + used(self); +} + +// UNINIT-LABEL: test_block( +// ZERO-LABEL: test_block( +// ZERO: store i32 0, i32* %block, align 4 +// PATTERN-LABEL: test_block( +// PATTERN: store i32 -1431655766, i32* %block, align 4 +void test_block() { + __block int block; + used(block); +} + +// This type of code is currently not handled by zero / pattern initialization. +// The test will break when that is fixed. +// UNINIT-LABEL: test_goto_unreachable_value( +// ZERO-LABEL: test_goto_unreachable_value( +// ZERO-NOT: store {{.*}}%oops +// PATTERN-LABEL: test_goto_unreachable_value( +// PATTERN-NOT: store {{.*}}%oops +void test_goto_unreachable_value() { + goto jump; + int oops; + jump: + used(oops); +} + +// This type of code is currently not handled by zero / pattern initialization. +// The test will break when that is fixed. +// UNINIT-LABEL: test_goto( +// ZERO-LABEL: test_goto( +// ZERO: if.then: +// ZERO: br label %jump +// ZERO: store i32 0, i32* %oops, align 4 +// ZERO: br label %jump +// ZERO: jump: +// PATTERN-LABEL: test_goto( +// PATTERN: if.then: +// PATTERN: br label %jump +// PATTERN: store i32 -1431655766, i32* %oops, align 4 +// PATTERN: br label %jump +// PATTERN: jump: +void test_goto(int i) { + if (i) + goto jump; + int oops; + jump: + used(oops); +} + +// This type of code is currently not handled by zero / pattern initialization. +// The test will break when that is fixed. +// UNINIT-LABEL: test_switch( +// ZERO-LABEL: test_switch( +// ZERO: sw.bb: +// ZERO-NEXT: store i32 0, i32* %oops, align 4 +// ZERO: sw.bb1: +// ZERO-NEXT: call void @{{.*}}used +// PATTERN-LABEL: test_switch( +// PATTERN: sw.bb: +// PATTERN-NEXT: store i32 -1431655766, i32* %oops, align 4 +// PATTERN: sw.bb1: +// PATTERN-NEXT: call void @{{.*}}used +void test_switch(int i) { + switch (i) { + case 0: + int oops; + break; + case 1: + used(oops); + } +} + +// UNINIT-LABEL: test_vla( +// ZERO-LABEL: test_vla( +// ZERO: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 4 +// ZERO: call void @llvm.memset{{.*}}(i8* align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false) +// PATTERN-LABEL: test_vla( +// PATTERN: %vla.iszerosized = icmp eq i64 %{{.*}}, 0 +// PATTERN: br i1 %vla.iszerosized, label %vla-init.cont, label %vla-setup.loop +// PATTERN: vla-setup.loop: +// PATTERN: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 4 +// PATTERN: %vla.begin = bitcast i32* %vla to i8* +// PATTERN: %vla.end = getelementptr inbounds i8, i8* %vla.begin, i64 %[[SIZE]] +// PATTERN: br label %vla-init.loop +// PATTERN: vla-init.loop: +// PATTERN: %vla.cur = phi i8* [ %vla.begin, %vla-setup.loop ], [ %vla.next, %vla-init.loop ] +// PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_vla.vla +// PATTERN: %vla.next = getelementptr inbounds i8, i8* %vla.cur, i64 4 +// PATTERN: %vla-init.isdone = icmp eq i8* %vla.next, %vla.end +// PATTERN: br i1 %vla-init.isdone, label %vla-init.cont, label %vla-init.loop +// PATTERN: vla-init.cont: +// PATTERN: call void @{{.*}}used +void test_vla(int size) { + // Variable-length arrays can't have a zero size according to C11 6.7.6.2/5. + // Neither can they be negative-sized. + // + // We don't use the former fact because some code creates zero-sized VLAs and + // doesn't use them. clang makes these share locations with other stack + // values, which leads to initialization of the wrong values. + // + // We rely on the later fact because it generates better code. + // + // Both cases are caught by UBSan. + int vla[size]; + int *ptr = vla; + used(ptr); +} + +// UNINIT-LABEL: test_struct_vla( +// ZERO-LABEL: test_struct_vla( +// ZERO: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 16 +// ZERO: call void @llvm.memset{{.*}}(i8* align 16 %{{.*}}, i8 0, i64 %[[SIZE]], i1 false) +// PATTERN-LABEL: test_struct_vla( +// PATTERN: %vla.iszerosized = icmp eq i64 %{{.*}}, 0 +// PATTERN: br i1 %vla.iszerosized, label %vla-init.cont, label %vla-setup.loop +// PATTERN: vla-setup.loop: +// PATTERN: %[[SIZE:[0-9]+]] = mul nuw i64 %{{.*}}, 16 +// PATTERN: %vla.begin = bitcast %struct.anon* %vla to i8* +// PATTERN: %vla.end = getelementptr inbounds i8, i8* %vla.begin, i64 %[[SIZE]] +// PATTERN: br label %vla-init.loop +// PATTERN: vla-init.loop: +// PATTERN: %vla.cur = phi i8* [ %vla.begin, %vla-setup.loop ], [ %vla.next, %vla-init.loop ] +// PATTERN: call void @llvm.memcpy{{.*}} %vla.cur, {{.*}}@__const.test_struct_vla.vla +// PATTERN: %vla.next = getelementptr inbounds i8, i8* %vla.cur, i64 16 +// PATTERN: %vla-init.isdone = icmp eq i8* %vla.next, %vla.end +// PATTERN: br i1 %vla-init.isdone, label %vla-init.cont, label %vla-init.loop +// PATTERN: vla-init.cont: +// PATTERN: call void @{{.*}}used +void test_struct_vla(int size) { + // Same as above, but with a struct that doesn't just memcpy. + struct { + float f; + char c; + void *ptr; + } vla[size]; + void *ptr = static_cast<void*>(vla); + used(ptr); +} + +// UNINIT-LABEL: test_zsa( +// ZERO-LABEL: test_zsa( +// ZERO: %zsa = alloca [0 x i32], align 4 +// ZERO-NOT: %zsa +// ZERO: call void @{{.*}}used +// PATTERN-LABEL: test_zsa( +// PATTERN: %zsa = alloca [0 x i32], align 4 +// PATTERN-NOT: %zsa +// PATTERN: call void @{{.*}}used +void test_zsa(int size) { + // Technically not valid, but as long as clang accepts them we should do + // something sensible (i.e. not store to the zero-size array). + int zsa[0]; + used(zsa); +} + +// UNINIT-LABEL: test_huge_uninit( +// ZERO-LABEL: test_huge_uninit( +// ZERO: call void @llvm.memset{{.*}}, i8 0, i64 65536, +// PATTERN-LABEL: test_huge_uninit( +// PATTERN: call void @llvm.memset{{.*}}, i8 -86, i64 65536, +void test_huge_uninit() { + // We can't emit this as an inline constant to a store instruction because + // SDNode hits an internal size limit. + char big[65536]; + used(big); +} + +// UNINIT-LABEL: test_huge_small_init( +// ZERO-LABEL: test_huge_small_init( +// ZERO: call void @llvm.memset{{.*}}, i8 0, i64 65536, +// ZERO: store i8 97, +// ZERO: store i8 98, +// ZERO: store i8 99, +// ZERO: store i8 100, +// PATTERN-LABEL: test_huge_small_init( +// PATTERN: call void @llvm.memset{{.*}}, i8 0, i64 65536, +// PATTERN: store i8 97, +// PATTERN: store i8 98, +// PATTERN: store i8 99, +// PATTERN: store i8 100, +void test_huge_small_init() { + char big[65536] = { 'a', 'b', 'c', 'd' }; + used(big); +} + +// UNINIT-LABEL: test_huge_larger_init( +// ZERO-LABEL: test_huge_larger_init( +// ZERO: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, {{.*}}, i64 65536, +// PATTERN-LABEL: test_huge_larger_init( +// PATTERN: call void @llvm.memcpy{{.*}} @__const.test_huge_larger_init.big, {{.*}}, i64 65536, +void test_huge_larger_init() { + char big[65536] = { 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; + used(big); +} + +} // extern "C" |