-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[clang] Skip auto-init on scalar vars that have a non-constant Init and no self-ref #94642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
23ee93a
c847f9d
e529d26
97c7424
fcfda76
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
// 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( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nit, if "UNINIT-LABEL", "ZERO-LABEL", and "PATTERN-LABEL" are always the same, just define a common label like "CHECK-LABEL:" to avoid redundancy? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not sure if a common "CHECK-LABEL:" would have the same semantics and help split the stream for matching when there is a different prefix like "ZERO: " (or "PATTERN:") that follows, or if the CHECK and the ZERO end up as a independent scans. If it's an independent scan, then "CHECK-LABEL" wouldn't have the same semantics as "ZERO-LABEL:" (which helps split the stream for the "ZERO:" checks that follow -- e.g., in case there a multiple places that could match something generic like "store i32 0, ", the preceding ZERO-LABEL help disambiguate which to match). I'd prefer to keep the redundancy just to be safe and more clear that the X-LABEL are for the X that it's associated with, unless you're pretty sure it can cross over different check prefixes. |
||
// 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"} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we have both the test cases in which scalar variables are auto-inited and where the initialization is skipped?
Something along the lines of:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure! Added those cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM