================
@@ -318,6 +309,412 @@ void test_huge_larger_init() {
   used(big);
 }
 
+// UNINIT-LABEL:  test_goto_multiple_bypassed(
+// ZERO-LABEL:    test_goto_multiple_bypassed(
+// ZERO: %a = alloca i32, align 4
+// ZERO: %b = alloca i32, align 4
+// ZERO-DAG: store i32 0, ptr %a, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO-DAG: store i32 0, ptr %b, align 4, !annotation [[AUTO_INIT:!.+]]
+// PATTERN-LABEL: test_goto_multiple_bypassed(
+// PATTERN: %a = alloca i32, align 4
+// PATTERN: %b = alloca i32, align 4
+// PATTERN-DAG: store i32 -1431655766, ptr %a, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN-DAG: store i32 -1431655766, ptr %b, align 4, !annotation 
[[AUTO_INIT:!.+]]
+void test_goto_multiple_bypassed() {
+  goto jump;
+  int a;
+  int b;
+ jump:
+  used(a);
+  used(b);
+}
+
+// UNINIT-LABEL:  test_goto_bypassed_uninitialized_attr(
+// ZERO-LABEL:    test_goto_bypassed_uninitialized_attr(
+// ZERO-NOT: store {{.*}}%skip_me
+// ZERO: call void @{{.*}}used
+// PATTERN-LABEL: test_goto_bypassed_uninitialized_attr(
+// PATTERN-NOT: store {{.*}}%skip_me
+// PATTERN: call void @{{.*}}used
+void test_goto_bypassed_uninitialized_attr() {
+  goto jump;
+  [[clang::uninitialized]] int skip_me;
+ jump:
+  used(skip_me);
+}
+
+// UNINIT-LABEL:  test_switch_between_cases(
+// ZERO-LABEL:    test_switch_between_cases(
+// ZERO: %x = alloca i32, align 4
+// ZERO: store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// PATTERN-LABEL: test_switch_between_cases(
+// PATTERN: %x = alloca i32, align 4
+// PATTERN: store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+void test_switch_between_cases(int c) {
+  switch (c) {
+  case 0:
+    int x;
+    x = 42;
+    used(x);
+    break;
+  case 1:
+    used(x);
+    break;
+  }
+}
+
+// UNINIT-LABEL:  test_switch_precase(
+// ZERO-LABEL:    test_switch_precase(
+// ZERO: %x = alloca i32, align 4
+// ZERO: store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// PATTERN-LABEL: test_switch_precase(
+// PATTERN: %x = alloca i32, align 4
+// PATTERN: store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+void test_switch_precase(int c) {
+  switch (c) {
+    int x;
+  case 0:
+    x = 1;
+    used(x);
+    break;
+  }
+}
+
+// UNINIT-LABEL:  test_computed_goto(
+// ZERO-LABEL:    test_computed_goto(
+// ZERO: %y = alloca i32, align 4
+// ZERO: store i32 0, ptr %y, align 4, !annotation [[AUTO_INIT:!.+]]
+// PATTERN-LABEL: test_computed_goto(
+// PATTERN: %y = alloca i32, align 4
+// PATTERN: store i32 -1431655766, ptr %y, align 4, !annotation 
[[AUTO_INIT:!.+]]
+void test_computed_goto(int x) {
+  void *targets[] = {&&label1, &&label2};
+  goto *targets[x];
+  int y;
+label1:
+  used(y);
+  return;
+label2:
+  return;
+}
+
+// UNINIT-LABEL:  test_loop_bypass(
+// ZERO-LABEL:    test_loop_bypass(
+// ZERO: %x = alloca i32, align 4
+// ZERO: while.body:
+// ZERO: store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO: br label %X
+// PATTERN-LABEL: test_loop_bypass(
+// PATTERN: %x = alloca i32, align 4
+// PATTERN: while.body:
+// PATTERN: store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN: br label %X
+void test_loop_bypass() {
+  while (true) {
+    goto X;
+    int x;
+    X:
+    used(x);
+    if (x) break;
+  }
+}
+
+// UNINIT-LABEL:  test_complex_multi_goto(
+// ZERO-LABEL:    test_complex_multi_goto(
+// ZERO:      Z:
+// ZERO-NEXT: store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO-NEXT: br label %Y
+// ZERO:      X:
+// ZERO-NEXT: store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO-NEXT: br label %Y
+// ZERO:      sw.bb:
+// ZERO-NOT:  store {{.*}}%x
+// ZERO:      br label %X
+// ZERO:      sw.bb1:
+// ZERO-NOT:  store {{.*}}%x
+// ZERO:      br label %Z
+// ZERO:      sw.epilog:
+// ZERO-NOT:  store {{.*}}%x
+// ZERO:      br label %Y
+// PATTERN-LABEL: test_complex_multi_goto(
+// PATTERN:      Z:
+// PATTERN-NEXT: store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN-NEXT: br label %Y
+// PATTERN:      X:
+// PATTERN-NEXT: store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN-NEXT: br label %Y
+// PATTERN:      sw.bb:
+// PATTERN-NOT:  store {{.*}}%x
+// PATTERN:      br label %X
+// PATTERN:      sw.bb1:
+// PATTERN-NOT:  store {{.*}}%x
+// PATTERN:      br label %Z
+// PATTERN:      sw.epilog:
+// PATTERN-NOT:  store {{.*}}%x
+// PATTERN:      br label %Y
+void test_complex_multi_goto(int g(int*)) {
+  while (true) {
+    Z:
+    goto Y;
+    X:
+    goto Y;
+    int x;
+    Y:
+    switch (g(&x)) {
+    case 0:
+      goto X;
+    case 1:
+      goto Z;
+    }
+    goto Y;
+  }
+}
+
+// UNINIT-LABEL:  test_no_reinit_in_scope(
+// ZERO-LABEL:    test_no_reinit_in_scope(
+// ZERO:      while.body:
+// ZERO-NEXT: store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO-NEXT: br label %Y
+// ZERO:      if.end:
+// ZERO-NOT:  store {{.*}}%x
+// ZERO:      br label %Y
+// PATTERN-LABEL: test_no_reinit_in_scope(
+// PATTERN:      while.body:
+// PATTERN-NEXT: store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN-NEXT: br label %Y
+// PATTERN:      if.end:
+// PATTERN-NOT:  store {{.*}}%x
+// PATTERN:      br label %Y
+void test_no_reinit_in_scope(int g(int*)) {
+  while (true) {
+    goto Y;
+    int x;
+    Y:
+    if (g(&x))
+      break;
+    goto Y;
+  }
+}
+
+// Backward goto: x is already in scope, no bypass init should occur at the
+// goto.
+// UNINIT-LABEL:  test_backward_goto_no_init(
+// ZERO-LABEL:    test_backward_goto_no_init(
+// ZERO:      store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO:      L:
+// ZERO-NOT:  store {{.*}}%x
+// ZERO:      if.then:
+// ZERO-NOT:  store {{.*}}%x
+// ZERO:      br label %L
+// PATTERN-LABEL: test_backward_goto_no_init(
+// PATTERN:      store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN:      L:
+// PATTERN-NOT:  store {{.*}}%x
+// PATTERN:      if.then:
+// PATTERN-NOT:  store {{.*}}%x
+// PATTERN:      br label %L
+void test_backward_goto_no_init() {
+  int x;
+ L:
+  used(x);
+  if (x)
+    goto L;
+}
+
+// Switch with default case bypassing a variable declared in case 0. The init
+// goes ahead of the dispatch, not at the bypassing label: a label is also
+// reached by falling through from the case above it, and that edge bypasses
+// nothing. Case 0 reaches the declaration and initializes there as usual.
+// UNINIT-LABEL:  test_switch_default_bypass(
+// ZERO-LABEL:    test_switch_default_bypass(
+// ZERO:      store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO-NEXT: switch i32
+// ZERO:      sw.default:
+// ZERO-NOT:  !annotation
+// ZERO:      call void @_Z4usedIiEvRT_
+// PATTERN-LABEL: test_switch_default_bypass(
+// PATTERN:      store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN-NEXT: switch i32
+// PATTERN:      sw.default:
+// PATTERN-NOT:  !annotation
+// PATTERN:      call void @_Z4usedIiEvRT_
+void test_switch_default_bypass(int c) {
+  switch (c) {
+  case 0:
+    int x;
+    x = 10;
+    used(x);
+    break;
+  default:
+    used(x);
+    break;
+  }
+}
+
+// Multipe variables bypassed by the same goto so both must be initialized.
+// UNINIT-LABEL:  test_goto_multiple_vars(
+// ZERO-LABEL:    test_goto_multiple_vars(
+// ZERO: %a = alloca i32, align 4
+// ZERO: %b = alloca i32, align 4
+// ZERO: store i32 0, ptr %a, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO: store i32 0, ptr %b, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO: br label %jump
+// PATTERN-LABEL: test_goto_multiple_vars(
+// PATTERN: %a = alloca i32, align 4
+// PATTERN: %b = alloca i32, align 4
+// PATTERN: store i32 -1431655766, ptr %a, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN: store i32 -1431655766, ptr %b, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN: br label %jump
+void test_goto_multiple_vars() {
+  goto jump;
+  int a;
+  int b;
+ jump:
+  used(a);
+  used(b);
+}
+
+// UNINIT-LABEL:  test_backward_goto_bypass(
+// ZERO-LABEL:    test_backward_goto_bypass(
+// ZERO:      jump:
+// ZERO:      call void @{{.*}}used
+// ZERO:      call void @{{.*}}used
+// ZERO-DAG:  store i32 0, ptr %b, align 4
+// ZERO-DAG:  store i32 0, ptr %a, align 4
+// ZERO:      br label %jump
+// PATTERN-LABEL: test_backward_goto_bypass(
+// PATTERN:      jump:
+// PATTERN:      call void @{{.*}}used
+// PATTERN:      call void @{{.*}}used
+// PATTERN-DAG:  store i32 -1431655766, ptr %b
+// PATTERN-DAG:  store i32 -1431655766, ptr %a
+// PATTERN:      br label %jump
+void test_backward_goto_bypass() {
+  {
+    int a;
+    int b;
+jump:
+    used(a);
+    used(b);
+  }
+  goto jump;
+}
+
+// C++ [basic.stc.auto]: scope re-entry restarts the lifetime, so the init is
+// emitted at the goto source and reruns each iteration (store in BEGIN, not
+// entry). Contrast the C version, which inits once in entry and returns 10.
+// UNINIT-LABEL:  test_backward_goto_around_decl(
+// ZERO-LABEL:    test_backward_goto_around_decl(
+// ZERO:      entry:
+// ZERO-NOT:  !annotation
+// ZERO:      BEGIN:
+// ZERO:      store ptr null, ptr %p, align 8, !annotation [[AUTO_INIT:!.+]]
+// PATTERN-LABEL: test_backward_goto_around_decl(
+// PATTERN:      entry:
+// PATTERN-NOT:  !annotation
+// PATTERN:      BEGIN:
+// PATTERN:      store ptr inttoptr (i64 -6148914691236517206 to ptr), ptr %p, 
align 8, !annotation [[AUTO_INIT:!.+]]
+int test_backward_goto_around_decl(int b) {
+BEGIN:;
+  goto CONT;
+  int *p;
+CONT:
+  if (b)
+    *p = 10;
+  p = &b;
+  if (!b) {
+    b = 1;
+    goto BEGIN;
+  }
+  return b;
+}
+
+// Nested loops: goto source is in the inner body, so reinit lands there
+// (while.body3), every inner iteration.
+// UNINIT-LABEL:  nested_loops(
+// ZERO-LABEL:    nested_loops(
+// ZERO:      entry:
+// ZERO-NOT:  store {{.*}}%x{{.*}}!annotation
+// ZERO:      while.body3:
+// ZERO:      store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// PATTERN-LABEL: nested_loops(
+// PATTERN:      entry:
+// PATTERN-NOT:  store {{.*}}%x{{.*}}!annotation
+// PATTERN:      while.body3:
+// PATTERN:      store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+void nested_loops(int n) {
+  while (n) {
+    while (n) {
+      goto X;
+      int x;
+    X:
+      used(x);
+      n--;
+    }
+  }
+}
+
+// Nested loops + switch: the init sits ahead of the dispatch, inside the inner
+// loop body, so it runs once per iteration rather than once per case.
+// UNINIT-LABEL:  nested_loops_switch(
+// ZERO-LABEL:    nested_loops_switch(
+// ZERO:      while.body3:
+// ZERO:      store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO-NEXT: switch i32
+// PATTERN-LABEL: nested_loops_switch(
+// PATTERN:      while.body3:
+// PATTERN:      store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN-NEXT: switch i32
+void nested_loops_switch(int n, int c) {
+  while (n) {
+    while (n) {
+      switch (c) {
+        int x;
+      case 0:
+        x = 1;
+        used(x);
+        break;
+      default:
+        used(x);
+        break;
+      }
+      n--;
+    }
+  }
+}
+
+// Computed goto with multiple scopes: jump sources are unknown, so all 
bypassed
+// variables fall back to a single function-scope init in entry. Even though a
+// regular switch is also present, its case targets must NOT reinitialize -- 
that
+// could clobber a variable still live across the computed jump. One init in
+// entry, none after the indirectbr.
+// UNINIT-LABEL:  test_computed_goto_multi_scope(
+// ZERO-LABEL:    test_computed_goto_multi_scope(
+// ZERO:      entry:
+// ZERO:      store i32 0, ptr %x, align 4, !annotation [[AUTO_INIT:!.+]]
+// ZERO:      indirectbr
+// ZERO-NOT:  store i32 0, ptr %x, align 4, !annotation
+// PATTERN-LABEL: test_computed_goto_multi_scope(
+// PATTERN:      entry:
+// PATTERN:      store i32 -1431655766, ptr %x, align 4, !annotation 
[[AUTO_INIT:!.+]]
+// PATTERN:      indirectbr
+// PATTERN-NOT:  store i32 -1431655766, ptr %x, align 4, !annotation
+void test_computed_goto_multi_scope(int n, int c) {
+  void *targets[] = {&&L1, &&L2};
+  goto *targets[n];
+  int x;
+  switch (c) {
+  case 0:
+  L1:
+    used(x);
+    break;
+  default:
+  L2:
+    used(x);
+    break;
+  }
+}
----------------
nickdesaulniers wrote:

Please add a test case for:

```c++
struct Big {
  int a[8];
};
    
Big test_nrvo_bypass(int cond) {
  if (cond)
    goto skip;
  Big s;
skip:
  return s;
}
```

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