================
@@ -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

Reply via email to