================
@@ -0,0 +1,587 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
UTC_ARGS: --version 6
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown -ftrivial-auto-var-init=zero
%s -emit-llvm -o - | FileCheck %s --check-prefix=ZERO
+// RUN: %clang_cc1 -triple x86_64-unknown-unknown
-ftrivial-auto-var-init=pattern %s -emit-llvm -o - | FileCheck %s
--check-prefix=PATTERN
+
+// A variable whose declaration is bypassed by a goto or switch is initialized
+// at each bypassing jump, since the jump re-enters the variable's scope. C
uses
+// the same rule as C++ here; see CodeGenCXX/trivial-auto-var-init.cpp. Note
+// that this deliberately does not model C 6.2.4p6, under which the lifetime
+// would instead begin at entry into the enclosing block.
+
+void use(int *);
+
+// Not bypassed: initialized at the declaration, as usual.
+// ZERO-LABEL: define dso_local i32 @no_bypass(
+// ZERO-SAME: ) #[[ATTR0:[0-9]+]] {
+// ZERO-NEXT: [[ENTRY:.*:]]
+// ZERO-NEXT: [[X:%.*]] = alloca i32, align 4
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1:![0-9]+]]
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: [[TMP0:%.*]] = load i32, ptr [[X]], align 4
+// ZERO-NEXT: ret i32 [[TMP0]]
+//
+// PATTERN-LABEL: define dso_local i32 @no_bypass(
+// PATTERN-SAME: ) #[[ATTR0:[0-9]+]] {
+// PATTERN-NEXT: [[ENTRY:.*:]]
+// PATTERN-NEXT: [[X:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1:![0-9]+]]
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: [[TMP0:%.*]] = load i32, ptr [[X]], align 4
+// PATTERN-NEXT: ret i32 [[TMP0]]
+//
+int no_bypass(void) {
+ int x;
+ use(&x);
+ return x;
+}
+
+// Forward goto over the declaration.
+// ZERO-LABEL: define dso_local i32 @goto_bypass(
+// ZERO-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// ZERO-NEXT: [[ENTRY:.*:]]
+// ZERO-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// ZERO-NEXT: [[X:%.*]] = alloca i32, align 4
+// ZERO-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// ZERO-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// ZERO-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+// ZERO-NEXT: br i1 [[TOBOOL]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
+// ZERO: [[IF_THEN]]:
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: br label %[[SKIP:.*]]
+// ZERO: [[IF_END]]:
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: br label %[[SKIP]]
+// ZERO: [[SKIP]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: [[TMP1:%.*]] = load i32, ptr [[X]], align 4
+// ZERO-NEXT: ret i32 [[TMP1]]
+//
+// PATTERN-LABEL: define dso_local i32 @goto_bypass(
+// PATTERN-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// PATTERN-NEXT: [[ENTRY:.*:]]
+// PATTERN-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: [[X:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// PATTERN-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// PATTERN-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+// PATTERN-NEXT: br i1 [[TOBOOL]], label %[[IF_THEN:.*]], label
%[[IF_END:.*]]
+// PATTERN: [[IF_THEN]]:
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: br label %[[SKIP:.*]]
+// PATTERN: [[IF_END]]:
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: br label %[[SKIP]]
+// PATTERN: [[SKIP]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: [[TMP1:%.*]] = load i32, ptr [[X]], align 4
+// PATTERN-NEXT: ret i32 [[TMP1]]
+//
+int goto_bypass(int c) {
+ if (c)
+ goto SKIP;
+ int x;
+SKIP:
+ use(&x);
+ return x;
+}
+
+// Declaration before the first case label: every case bypasses it.
+// ZERO-LABEL: define dso_local i32 @switch_bypass(
+// ZERO-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// ZERO-NEXT: [[ENTRY:.*:]]
+// ZERO-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// ZERO-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// ZERO-NEXT: [[X:%.*]] = alloca i32, align 4
+// ZERO-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// ZERO-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: switch i32 [[TMP0]], label %[[SW_EPILOG:.*]] [
+// ZERO-NEXT: i32 1, label %[[SW_BB:.*]]
+// ZERO-NEXT: i32 2, label %[[SW_BB1:.*]]
+// ZERO-NEXT: ]
+// ZERO: [[SW_BB]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: [[TMP1:%.*]] = load i32, ptr [[X]], align 4
+// ZERO-NEXT: store i32 [[TMP1]], ptr [[RETVAL]], align 4
+// ZERO-NEXT: br label %[[RETURN:.*]]
+// ZERO: [[SW_BB1]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4
+// ZERO-NEXT: store i32 [[TMP2]], ptr [[RETVAL]], align 4
+// ZERO-NEXT: br label %[[RETURN]]
+// ZERO: [[SW_EPILOG]]:
+// ZERO-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// ZERO-NEXT: br label %[[RETURN]]
+// ZERO: [[RETURN]]:
+// ZERO-NEXT: [[TMP3:%.*]] = load i32, ptr [[RETVAL]], align 4
+// ZERO-NEXT: ret i32 [[TMP3]]
+//
+// PATTERN-LABEL: define dso_local i32 @switch_bypass(
+// PATTERN-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// PATTERN-NEXT: [[ENTRY:.*:]]
+// PATTERN-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: [[X:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// PATTERN-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: switch i32 [[TMP0]], label %[[SW_EPILOG:.*]] [
+// PATTERN-NEXT: i32 1, label %[[SW_BB:.*]]
+// PATTERN-NEXT: i32 2, label %[[SW_BB1:.*]]
+// PATTERN-NEXT: ]
+// PATTERN: [[SW_BB]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: [[TMP1:%.*]] = load i32, ptr [[X]], align 4
+// PATTERN-NEXT: store i32 [[TMP1]], ptr [[RETVAL]], align 4
+// PATTERN-NEXT: br label %[[RETURN:.*]]
+// PATTERN: [[SW_BB1]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: [[TMP2:%.*]] = load i32, ptr [[X]], align 4
+// PATTERN-NEXT: store i32 [[TMP2]], ptr [[RETVAL]], align 4
+// PATTERN-NEXT: br label %[[RETURN]]
+// PATTERN: [[SW_EPILOG]]:
+// PATTERN-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// PATTERN-NEXT: br label %[[RETURN]]
+// PATTERN: [[RETURN]]:
+// PATTERN-NEXT: [[TMP3:%.*]] = load i32, ptr [[RETVAL]], align 4
+// PATTERN-NEXT: ret i32 [[TMP3]]
+//
+int switch_bypass(int c) {
+ switch (c) {
+ int x;
+ case 1:
+ use(&x);
+ return x;
+ case 2:
+ use(&x);
+ return x;
+ }
+ return 0;
+}
+
+// A case label inside a nested block jumps into the middle of that block's
+// scope, so case 1 bypasses the declaration while case 0 reaches it.
+// ZERO-LABEL: define dso_local void @switch_bypass_into_block(
+// ZERO-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// ZERO-NEXT: [[ENTRY:.*:]]
+// ZERO-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// ZERO-NEXT: [[X:%.*]] = alloca i32, align 4
+// ZERO-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// ZERO-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: switch i32 [[TMP0]], label %[[SW_EPILOG:.*]] [
+// ZERO-NEXT: i32 0, label %[[SW_BB:.*]]
+// ZERO-NEXT: i32 1, label %[[SW_BB1:.*]]
+// ZERO-NEXT: ]
+// ZERO: [[SW_BB]]:
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: br label %[[SW_BB1]]
+// ZERO: [[SW_BB1]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: br label %[[SW_EPILOG]]
+// ZERO: [[SW_EPILOG]]:
+// ZERO-NEXT: ret void
+//
+// PATTERN-LABEL: define dso_local void @switch_bypass_into_block(
+// PATTERN-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// PATTERN-NEXT: [[ENTRY:.*:]]
+// PATTERN-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: [[X:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// PATTERN-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: switch i32 [[TMP0]], label %[[SW_EPILOG:.*]] [
+// PATTERN-NEXT: i32 0, label %[[SW_BB:.*]]
+// PATTERN-NEXT: i32 1, label %[[SW_BB1:.*]]
+// PATTERN-NEXT: ]
+// PATTERN: [[SW_BB]]:
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: br label %[[SW_BB1]]
+// PATTERN: [[SW_BB1]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: br label %[[SW_EPILOG]]
+// PATTERN: [[SW_EPILOG]]:
+// PATTERN-NEXT: ret void
+//
+void switch_bypass_into_block(int c) {
+ switch (c) {
+ case 0: {
+ int x;
+ case 1:
+ use(&x);
+ }
+ }
+}
+
+// Bypassed inside a loop: reinitialized on every iteration, not once.
+// ZERO-LABEL: define dso_local void @loop_bypass(
+// ZERO-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] {
+// ZERO-NEXT: [[ENTRY:.*:]]
+// ZERO-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
+// ZERO-NEXT: [[X:%.*]] = alloca i32, align 4
+// ZERO-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4
+// ZERO-NEXT: br label %[[WHILE_COND:.*]]
+// ZERO: [[WHILE_COND]]:
+// ZERO-NEXT: [[TMP0:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// ZERO-NEXT: [[DEC:%.*]] = add nsw i32 [[TMP0]], -1
+// ZERO-NEXT: store i32 [[DEC]], ptr [[N_ADDR]], align 4
+// ZERO-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+// ZERO-NEXT: br i1 [[TOBOOL]], label %[[WHILE_BODY:.*]], label
%[[WHILE_END:.*]]
+// ZERO: [[WHILE_BODY]]:
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: br label %[[SKIP:.*]]
+// ZERO: [[SKIP]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: br label %[[WHILE_COND]], !llvm.loop [[LOOP2:![0-9]+]]
+// ZERO: [[WHILE_END]]:
+// ZERO-NEXT: ret void
+//
+// PATTERN-LABEL: define dso_local void @loop_bypass(
+// PATTERN-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] {
+// PATTERN-NEXT: [[ENTRY:.*:]]
+// PATTERN-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: [[X:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4
+// PATTERN-NEXT: br label %[[WHILE_COND:.*]]
+// PATTERN: [[WHILE_COND]]:
+// PATTERN-NEXT: [[TMP0:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// PATTERN-NEXT: [[DEC:%.*]] = add nsw i32 [[TMP0]], -1
+// PATTERN-NEXT: store i32 [[DEC]], ptr [[N_ADDR]], align 4
+// PATTERN-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+// PATTERN-NEXT: br i1 [[TOBOOL]], label %[[WHILE_BODY:.*]], label
%[[WHILE_END:.*]]
+// PATTERN: [[WHILE_BODY]]:
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: br label %[[SKIP:.*]]
+// PATTERN: [[SKIP]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: br label %[[WHILE_COND]], !llvm.loop [[LOOP2:![0-9]+]]
+// PATTERN: [[WHILE_END]]:
+// PATTERN-NEXT: ret void
+//
+void loop_bypass(int n) {
+ while (n--) {
+ goto SKIP;
+ int x;
+ SKIP:
+ use(&x);
+ }
+}
+
+// ZERO-LABEL: define dso_local i32 @backward_goto_around_decl(
+// ZERO-SAME: ) #[[ATTR0]] {
+// ZERO-NEXT: [[ENTRY:.*:]]
+// ZERO-NEXT: [[B:%.*]] = alloca i32, align 4
+// ZERO-NEXT: [[P:%.*]] = alloca ptr, align 8
+// ZERO-NEXT: store i32 0, ptr [[B]], align 4
+// ZERO-NEXT: br label %[[BEGIN:.*]]
+// ZERO: [[BEGIN]]:
+// ZERO-NEXT: store ptr null, ptr [[P]], align 8, !annotation [[META1]]
+// ZERO-NEXT: br label %[[CONT:.*]]
+// ZERO: [[CONT]]:
+// ZERO-NEXT: [[TMP0:%.*]] = load i32, ptr [[B]], align 4
+// ZERO-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+// ZERO-NEXT: br i1 [[TOBOOL]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
+// ZERO: [[IF_THEN]]:
+// ZERO-NEXT: [[TMP1:%.*]] = load ptr, ptr [[P]], align 8
+// ZERO-NEXT: store i32 10, ptr [[TMP1]], align 4
+// ZERO-NEXT: br label %[[IF_END]]
+// ZERO: [[IF_END]]:
+// ZERO-NEXT: store ptr [[B]], ptr [[P]], align 8
+// ZERO-NEXT: [[TMP2:%.*]] = load i32, ptr [[B]], align 4
+// ZERO-NEXT: [[TOBOOL1:%.*]] = icmp ne i32 [[TMP2]], 0
+// ZERO-NEXT: br i1 [[TOBOOL1]], label %[[IF_END3:.*]], label
%[[IF_THEN2:.*]]
+// ZERO: [[IF_THEN2]]:
+// ZERO-NEXT: store i32 1, ptr [[B]], align 4
+// ZERO-NEXT: br label %[[BEGIN]]
+// ZERO: [[IF_END3]]:
+// ZERO-NEXT: [[TMP3:%.*]] = load i32, ptr [[B]], align 4
+// ZERO-NEXT: ret i32 [[TMP3]]
+//
+// PATTERN-LABEL: define dso_local i32 @backward_goto_around_decl(
+// PATTERN-SAME: ) #[[ATTR0]] {
+// PATTERN-NEXT: [[ENTRY:.*:]]
+// PATTERN-NEXT: [[B:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: [[P:%.*]] = alloca ptr, align 8
+// PATTERN-NEXT: store i32 0, ptr [[B]], align 4
+// PATTERN-NEXT: br label %[[BEGIN:.*]]
+// PATTERN: [[BEGIN]]:
+// PATTERN-NEXT: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr
[[P]], align 8, !annotation [[META1]]
+// PATTERN-NEXT: br label %[[CONT:.*]]
+// PATTERN: [[CONT]]:
+// PATTERN-NEXT: [[TMP0:%.*]] = load i32, ptr [[B]], align 4
+// PATTERN-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+// PATTERN-NEXT: br i1 [[TOBOOL]], label %[[IF_THEN:.*]], label
%[[IF_END:.*]]
+// PATTERN: [[IF_THEN]]:
+// PATTERN-NEXT: [[TMP1:%.*]] = load ptr, ptr [[P]], align 8
+// PATTERN-NEXT: store i32 10, ptr [[TMP1]], align 4
+// PATTERN-NEXT: br label %[[IF_END]]
+// PATTERN: [[IF_END]]:
+// PATTERN-NEXT: store ptr [[B]], ptr [[P]], align 8
+// PATTERN-NEXT: [[TMP2:%.*]] = load i32, ptr [[B]], align 4
+// PATTERN-NEXT: [[TOBOOL1:%.*]] = icmp ne i32 [[TMP2]], 0
+// PATTERN-NEXT: br i1 [[TOBOOL1]], label %[[IF_END3:.*]], label
%[[IF_THEN2:.*]]
+// PATTERN: [[IF_THEN2]]:
+// PATTERN-NEXT: store i32 1, ptr [[B]], align 4
+// PATTERN-NEXT: br label %[[BEGIN]]
+// PATTERN: [[IF_END3]]:
+// PATTERN-NEXT: [[TMP3:%.*]] = load i32, ptr [[B]], align 4
+// PATTERN-NEXT: ret i32 [[TMP3]]
+//
+int backward_goto_around_decl(void) {
+ int b = 0;
+BEGIN:;
+ goto CONT;
+ int *p;
+CONT:
+ if (b)
+ *p = 10;
+ p = &b;
+ if (!b) {
+ b = 1;
+ goto BEGIN;
+ }
+ return b;
+}
+
+// A computed goto can land anywhere, so the bypassing jumps can't be
+// identified. Fall back to a single initialization in the entry block.
+// ZERO-LABEL: define dso_local void @computed_goto(
+// ZERO-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] {
+// ZERO-NEXT: [[ENTRY:.*:]]
+// ZERO-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
+// ZERO-NEXT: [[TARGET:%.*]] = alloca ptr, align 8
+// ZERO-NEXT: [[X:%.*]] = alloca i32, align 4
+// ZERO-NEXT: store ptr null, ptr [[TARGET]], align 8, !annotation [[META1]]
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4
+// ZERO-NEXT: store ptr blockaddress(@computed_goto, %[[SKIP:.*]]), ptr
[[TARGET]], align 8
+// ZERO-NEXT: [[TMP0:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// ZERO-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+// ZERO-NEXT: br i1 [[TOBOOL]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
+// ZERO: [[IF_THEN]]:
+// ZERO-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TARGET]], align 8
+// ZERO-NEXT: br label %[[INDIRECTGOTO:.*]]
+// ZERO: [[IF_END]]:
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: br label %[[SKIP]]
+// ZERO: [[SKIP]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: ret void
+// ZERO: [[INDIRECTGOTO]]:
+// ZERO-NEXT: [[INDIRECT_GOTO_DEST:%.*]] = phi ptr [ [[TMP1]], %[[IF_THEN]]
]
+// ZERO-NEXT: indirectbr ptr [[INDIRECT_GOTO_DEST]], [label %[[SKIP]]]
+//
+// PATTERN-LABEL: define dso_local void @computed_goto(
+// PATTERN-SAME: i32 noundef [[N:%.*]]) #[[ATTR0]] {
+// PATTERN-NEXT: [[ENTRY:.*:]]
+// PATTERN-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: [[TARGET:%.*]] = alloca ptr, align 8
+// PATTERN-NEXT: [[X:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr
[[TARGET]], align 8, !annotation [[META1]]
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4
+// PATTERN-NEXT: store ptr blockaddress(@computed_goto, %[[SKIP:.*]]), ptr
[[TARGET]], align 8
+// PATTERN-NEXT: [[TMP0:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// PATTERN-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP0]], 0
+// PATTERN-NEXT: br i1 [[TOBOOL]], label %[[IF_THEN:.*]], label
%[[IF_END:.*]]
+// PATTERN: [[IF_THEN]]:
+// PATTERN-NEXT: [[TMP1:%.*]] = load ptr, ptr [[TARGET]], align 8
+// PATTERN-NEXT: br label %[[INDIRECTGOTO:.*]]
+// PATTERN: [[IF_END]]:
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: br label %[[SKIP]]
+// PATTERN: [[SKIP]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: ret void
+// PATTERN: [[INDIRECTGOTO]]:
+// PATTERN-NEXT: [[INDIRECT_GOTO_DEST:%.*]] = phi ptr [ [[TMP1]],
%[[IF_THEN]] ]
+// PATTERN-NEXT: indirectbr ptr [[INDIRECT_GOTO_DEST]], [label %[[SKIP]]]
+//
+void computed_goto(int n) {
+ void *target = &&SKIP;
+ if (n)
+ goto *target;
+ int x;
+SKIP:
+ use(&x);
+}
+
+// Fallthrough between cases must not re-initialize. `case 1:` is reached two
+// ways: from the switch dispatch, which bypasses the declaration, and by
+// falling out of `case 0:`, which does not. Initializing at the label would
+// fire on both and clobber the 42 written by case 0, so the init goes ahead of
+// the dispatch instead. Expect exactly one annotated store, before the switch.
+// ZERO-LABEL: define dso_local void @switch_fallthrough(
+// ZERO-SAME: i32 noundef [[Y:%.*]]) #[[ATTR0]] {
+// ZERO-NEXT: [[ENTRY:.*:]]
+// ZERO-NEXT: [[Y_ADDR:%.*]] = alloca i32, align 4
+// ZERO-NEXT: [[X:%.*]] = alloca i32, align 4
+// ZERO-NEXT: store i32 [[Y]], ptr [[Y_ADDR]], align 4
+// ZERO-NEXT: [[TMP0:%.*]] = load i32, ptr [[Y_ADDR]], align 4
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: switch i32 [[TMP0]], label %[[SW_EPILOG:.*]] [
+// ZERO-NEXT: i32 0, label %[[SW_BB:.*]]
+// ZERO-NEXT: i32 1, label %[[SW_BB1:.*]]
+// ZERO-NEXT: ]
+// ZERO: [[SW_BB]]:
+// ZERO-NEXT: store i32 42, ptr [[X]], align 4
+// ZERO-NEXT: br label %[[SW_BB1]]
+// ZERO: [[SW_BB1]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: br label %[[SW_EPILOG]]
+// ZERO: [[SW_EPILOG]]:
+// ZERO-NEXT: ret void
+//
+// PATTERN-LABEL: define dso_local void @switch_fallthrough(
+// PATTERN-SAME: i32 noundef [[Y:%.*]]) #[[ATTR0]] {
+// PATTERN-NEXT: [[ENTRY:.*:]]
+// PATTERN-NEXT: [[Y_ADDR:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: [[X:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: store i32 [[Y]], ptr [[Y_ADDR]], align 4
+// PATTERN-NEXT: [[TMP0:%.*]] = load i32, ptr [[Y_ADDR]], align 4
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: switch i32 [[TMP0]], label %[[SW_EPILOG:.*]] [
+// PATTERN-NEXT: i32 0, label %[[SW_BB:.*]]
+// PATTERN-NEXT: i32 1, label %[[SW_BB1:.*]]
+// PATTERN-NEXT: ]
+// PATTERN: [[SW_BB]]:
+// PATTERN-NEXT: store i32 42, ptr [[X]], align 4
+// PATTERN-NEXT: br label %[[SW_BB1]]
+// PATTERN: [[SW_BB1]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: br label %[[SW_EPILOG]]
+// PATTERN: [[SW_EPILOG]]:
+// PATTERN-NEXT: ret void
+//
+void switch_fallthrough(int y) {
+ switch (y) {
+ int x;
+ case 0:
+ x = 42;
+ // fallthrough
+ case 1:
+ use(&x);
+ break;
+ }
+}
+
+// ZERO-LABEL: define dso_local void @equivalence_switch_form(
+// ZERO-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// ZERO-NEXT: [[ENTRY:.*:]]
+// ZERO-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// ZERO-NEXT: [[X:%.*]] = alloca i32, align 4
+// ZERO-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// ZERO-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: switch i32 [[TMP0]], label %[[SW_DEFAULT:.*]] [
+// ZERO-NEXT: i32 0, label %[[SW_BB:.*]]
+// ZERO-NEXT: ]
+// ZERO: [[SW_BB]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: br label %[[SW_DEFAULT]]
+// ZERO: [[SW_DEFAULT]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: br label %[[SW_EPILOG:.*]]
+// ZERO: [[SW_EPILOG]]:
+// ZERO-NEXT: ret void
+//
+// PATTERN-LABEL: define dso_local void @equivalence_switch_form(
+// PATTERN-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// PATTERN-NEXT: [[ENTRY:.*:]]
+// PATTERN-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: [[X:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// PATTERN-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: switch i32 [[TMP0]], label %[[SW_DEFAULT:.*]] [
+// PATTERN-NEXT: i32 0, label %[[SW_BB:.*]]
+// PATTERN-NEXT: ]
+// PATTERN: [[SW_BB]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: br label %[[SW_DEFAULT]]
+// PATTERN: [[SW_DEFAULT]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: br label %[[SW_EPILOG:.*]]
+// PATTERN: [[SW_EPILOG]]:
+// PATTERN-NEXT: ret void
+//
+void equivalence_switch_form(int c) {
+ switch (c) {
+ int x;
+ case 0:
+ use(&x);
+ default:
+ use(&x);
+ }
+}
+
+// ZERO-LABEL: define dso_local void @equivalence_goto_form(
+// ZERO-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// ZERO-NEXT: [[ENTRY:.*:]]
+// ZERO-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// ZERO-NEXT: [[X:%.*]] = alloca i32, align 4
+// ZERO-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// ZERO-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// ZERO-NEXT: switch i32 [[TMP0]], label %[[SW_DEFAULT:.*]] [
+// ZERO-NEXT: i32 0, label %[[SW_BB:.*]]
+// ZERO-NEXT: ]
+// ZERO: [[SW_BB]]:
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: br label %[[CASE0:.*]]
+// ZERO: [[SW_DEFAULT]]:
+// ZERO-NEXT: store i32 0, ptr [[X]], align 4, !annotation [[META1]]
+// ZERO-NEXT: br label %[[DEFAULT:.*]]
+// ZERO: [[CASE0]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: br label %[[DEFAULT]]
+// ZERO: [[DEFAULT]]:
+// ZERO-NEXT: call void @use(ptr noundef [[X]])
+// ZERO-NEXT: ret void
+//
+// PATTERN-LABEL: define dso_local void @equivalence_goto_form(
+// PATTERN-SAME: i32 noundef [[C:%.*]]) #[[ATTR0]] {
+// PATTERN-NEXT: [[ENTRY:.*:]]
+// PATTERN-NEXT: [[C_ADDR:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: [[X:%.*]] = alloca i32, align 4
+// PATTERN-NEXT: store i32 [[C]], ptr [[C_ADDR]], align 4
+// PATTERN-NEXT: [[TMP0:%.*]] = load i32, ptr [[C_ADDR]], align 4
+// PATTERN-NEXT: switch i32 [[TMP0]], label %[[SW_DEFAULT:.*]] [
+// PATTERN-NEXT: i32 0, label %[[SW_BB:.*]]
+// PATTERN-NEXT: ]
+// PATTERN: [[SW_BB]]:
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: br label %[[CASE0:.*]]
+// PATTERN: [[SW_DEFAULT]]:
+// PATTERN-NEXT: store i32 -1431655766, ptr [[X]], align 4, !annotation
[[META1]]
+// PATTERN-NEXT: br label %[[DEFAULT:.*]]
+// PATTERN: [[CASE0]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: br label %[[DEFAULT]]
+// PATTERN: [[DEFAULT]]:
+// PATTERN-NEXT: call void @use(ptr noundef [[X]])
+// PATTERN-NEXT: ret void
+//
+void equivalence_goto_form(int c) {
+ switch (c) {
+ case 0:
+ goto CASE0;
+ default:
+ goto DEFAULT;
+ }
+ {
+ int x;
+ CASE0:
+ use(&x);
+ DEFAULT:
+ use(&x);
+ }
+}
+//.
+// ZERO: [[META1]] = !{!"auto-init"}
+// ZERO: [[LOOP2]] = distinct !{[[LOOP2]], [[META3:![0-9]+]]}
+// ZERO: [[META3]] = !{!"llvm.loop.mustprogress"}
+//.
+// PATTERN: [[META1]] = !{!"auto-init"}
+// PATTERN: [[LOOP2]] = distinct !{[[LOOP2]], [[META3:![0-9]+]]}
+// PATTERN: [[META3]] = !{!"llvm.loop.mustprogress"}
+//.
----------------
nickdesaulniers wrote:
Mind adding a test for:
```c
void f(void) {
while (({ goto L; 1; })) {}
int x;
L:
use(&x);
}
```
And verify that with an assertions enabled build?
https://github.com/llvm/llvm-project/pull/181937
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits