
In that scalar case, the Init should initialize the auto var before use. The Init might use uninitialized memory from other sources (e.g., heap) but auto-init did not help us in that case because the auto-init would have been overwritten by the Init before use. For non-scalars e.g., classes, the Init expr might be a ctor call that leaves uninitialized members, so we leave the auto-init there. The motivation is to have less IR for the optimizer to later remove, which may not be until a fairly late pass (DSE) or may not get optimized in lower optimization levels like O1 (no DSE) or sometimes due to derefinement. This is ~10% less left-over auto-init in O1 in a few examples checked.
122 lines
4.0 KiB
C++
122 lines
4.0 KiB
C++
// RUN: %clang_cc1 -triple x86_64-unknown-unknown %s -emit-llvm -o - | FileCheck %s -check-prefix=UNINIT
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s -check-prefix=PATTERN
|
|
// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=zero %s -emit-llvm -o - | FileCheck %s -check-prefix=ZERO
|
|
|
|
template<typename T> void used(T &) noexcept;
|
|
|
|
extern "C" {
|
|
|
|
extern int get_int(int) noexcept;
|
|
struct C {
|
|
int x;
|
|
int y;
|
|
};
|
|
extern C make_c() noexcept;
|
|
|
|
// Scalar with a self-reference: does need auto-init.
|
|
// UNINIT-LABEL: test_selfinit_call(
|
|
// ZERO-LABEL: test_selfinit_call(
|
|
// ZERO: store i32 0, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]]
|
|
// PATTERN-LABEL: test_selfinit_call(
|
|
// PATTERN: store i32 -1431655766, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]]
|
|
void test_selfinit_call() {
|
|
int self = get_int(self);
|
|
used(self);
|
|
}
|
|
|
|
// Scalar without a self-reference: no auto-init needed.
|
|
// UNINIT-LABEL: test_nonself_call(
|
|
// ZERO-LABEL: test_nonself_call(
|
|
// ZERO-NOT: !annotation [[AUTO_INIT:!.+]]
|
|
// PATTERN-LABEL: test_nonself_call(
|
|
// PATTERN-NOT: !annotation [[AUTO_INIT:!.+]]
|
|
void test_nonself_call() {
|
|
int x = get_int(2);
|
|
used(x);
|
|
}
|
|
|
|
// Scalar with a self-reference: does need auto-init.
|
|
// UNINIT-LABEL: test_selfinit_lambda_call(
|
|
// ZERO-LABEL: test_selfinit_lambda_call(
|
|
// ZERO: store i32 0, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]]
|
|
// PATTERN-LABEL: test_selfinit_lambda_call(
|
|
// PATTERN: store i32 -1431655766, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]]
|
|
void test_selfinit_lambda_call() {
|
|
int self = [&](){ return self; }();
|
|
used(self);
|
|
}
|
|
|
|
// Scalar with a self-reference: does need auto-init.
|
|
// UNINIT-LABEL: test_selfinit_gnu_stmt_expression(
|
|
// ZERO-LABEL: test_selfinit_gnu_stmt_expression(
|
|
// ZERO: store i32 0, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]]
|
|
// PATTERN-LABEL: test_selfinit_gnu_stmt_expression(
|
|
// PATTERN: store i32 -1431655766, ptr %self, align 4, !annotation [[AUTO_INIT:!.+]]
|
|
void test_selfinit_gnu_stmt_expression() {
|
|
int self = ({int x = self; x + 1; });
|
|
used(self);
|
|
}
|
|
|
|
// Not a scalar: auto-init just in case
|
|
// UNINIT-LABEL: test_nonscalar_call(
|
|
// ZERO-LABEL: test_nonscalar_call(
|
|
// ZERO: call void @llvm.memset{{.*}}, i8 0, i64 8, {{.*}} !annotation [[AUTO_INIT:!.+]]
|
|
// PATTERN-LABEL: test_nonscalar_call(
|
|
// PATTERN: call void @llvm.memcpy{{.*}}, i64 8, {{.*}} !annotation [[AUTO_INIT:!.+]]
|
|
void test_nonscalar_call() {
|
|
C c = make_c();
|
|
used(c);
|
|
}
|
|
|
|
// Scalar with a self-reference: does need auto-init.
|
|
// UNINIT-LABEL: test_self_ptr(
|
|
// ZERO-LABEL: test_self_ptr(
|
|
// ZERO: store ptr null, ptr %self, align 8, !annotation [[AUTO_INIT:!.+]]
|
|
// PATTERN-LABEL: test_self_ptr(
|
|
// PATTERN: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr %self, align 8, !annotation [[AUTO_INIT:!.+]]
|
|
void test_self_ptr() {
|
|
void* self = self;
|
|
used(self);
|
|
}
|
|
|
|
// Scalar without a self-reference: no auto-init needed.
|
|
// UNINIT-LABEL: test_nonself_ptr(
|
|
// ZERO-LABEL: test_nonself_ptr(
|
|
// ZERO-NOT: !annotation [[AUTO_INIT:!.+]]
|
|
// PATTERN-LABEL: test_nonself_ptr(
|
|
// PATTERN-NOT: !annotation [[AUTO_INIT:!.+]]
|
|
void test_nonself_ptr() {
|
|
int y = 0;
|
|
void* x = &y;
|
|
used(x);
|
|
}
|
|
|
|
// Scalar with a self-reference: does need auto-init.
|
|
// UNINIT-LABEL: test_self_complex(
|
|
// ZERO-LABEL: test_self_complex(
|
|
// ZERO: call void @llvm.memset{{.*}} !annotation [[AUTO_INIT:!.+]]
|
|
// PATTERN-LABEL: test_self_complex(
|
|
// PATTERN: call void @llvm.memcpy{{.*}} !annotation [[AUTO_INIT:!.+]]
|
|
void test_self_complex() {
|
|
_Complex float self = 3.0 * 3.0 * self;
|
|
used(self);
|
|
}
|
|
|
|
// Scalar without a self-reference: no auto-init needed.
|
|
// UNINIT-LABEL: test_nonself_complex(
|
|
// ZERO-LABEL: test_nonself_complex(
|
|
// ZERO-NOT: !annotation [[AUTO_INIT:!.+]]
|
|
// PATTERN-LABEL: test_nonself_complex(
|
|
// PATTERN-NOT: !annotation [[AUTO_INIT:!.+]]
|
|
void test_nonself_complex() {
|
|
_Complex float y = 0.0;
|
|
_Complex float x = 3.0 * 3.0 * y;
|
|
used(x);
|
|
}
|
|
|
|
} // extern "C"
|
|
|
|
// ZERO: [[AUTO_INIT]] = !{!"auto-init"}
|
|
// PATTERN: [[AUTO_INIT]] = !{!"auto-init"}
|
|
|