| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals |
| ; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT |
| ; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC |
| |
| declare void @unknown() nocallback |
| |
| define i32 @many_writes_nosycn(i1 %c0, i1 %c1, i1 %c2) nosync { |
| ; CHECK: Function Attrs: norecurse nosync |
| ; CHECK-LABEL: define {{[^@]+}}@many_writes_nosycn |
| ; CHECK-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR1:[0-9]+]] { |
| ; CHECK-NEXT: [[P:%.*]] = alloca i32, align 4 |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: br i1 [[C0]], label [[T0:%.*]], label [[F0:%.*]] |
| ; CHECK: t0: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: br i1 [[C1]], label [[T1:%.*]], label [[M1:%.*]] |
| ; CHECK: f0: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: br i1 [[C2]], label [[F1:%.*]], label [[M1]] |
| ; CHECK: t1: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: store i32 7, ptr [[P]], align 4 |
| ; CHECK-NEXT: br label [[M2:%.*]] |
| ; CHECK: f1: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: store i32 9, ptr [[P]], align 4 |
| ; CHECK-NEXT: br label [[M2]] |
| ; CHECK: m1: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: store i32 11, ptr [[P]], align 4 |
| ; CHECK-NEXT: br label [[M2]] |
| ; CHECK: m2: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[P]], align 4 |
| ; CHECK-NEXT: ret i32 [[L]] |
| ; |
| %p = alloca i32 |
| store i32 0, ptr %p |
| call void @unknown() |
| store i32 1, ptr %p |
| br i1 %c0, label %t0, label %f0 |
| t0: |
| store i32 2, ptr %p |
| call void @unknown() |
| store i32 3, ptr %p |
| br i1 %c1, label %t1, label %m1 |
| f0: |
| store i32 4, ptr %p |
| call void @unknown() |
| store i32 5, ptr %p |
| br i1 %c2, label %f1, label %m1 |
| t1: |
| store i32 6, ptr %p |
| call void @unknown() |
| store i32 7, ptr %p |
| br label %m2 |
| f1: |
| store i32 8, ptr %p |
| call void @unknown() |
| store i32 9, ptr %p |
| br label %m2 |
| m1: |
| store i32 10, ptr %p |
| call void @unknown() |
| store i32 11, ptr %p |
| br label %m2 |
| m2: |
| call void @unknown() |
| %l = load i32, ptr %p |
| ret i32 %l |
| } |
| |
| define i32 @many_writes(i1 %c0, i1 %c1, i1 %c2) { |
| ; CHECK: Function Attrs: norecurse |
| ; CHECK-LABEL: define {{[^@]+}}@many_writes |
| ; CHECK-SAME: (i1 [[C0:%.*]], i1 [[C1:%.*]], i1 [[C2:%.*]]) #[[ATTR2:[0-9]+]] { |
| ; CHECK-NEXT: [[P:%.*]] = alloca i32, align 4 |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: br i1 [[C0]], label [[T0:%.*]], label [[F0:%.*]] |
| ; CHECK: t0: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: br i1 [[C1]], label [[T1:%.*]], label [[M1:%.*]] |
| ; CHECK: f0: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: br i1 [[C2]], label [[F1:%.*]], label [[M1]] |
| ; CHECK: t1: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: store i32 7, ptr [[P]], align 4 |
| ; CHECK-NEXT: br label [[M2:%.*]] |
| ; CHECK: f1: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: store i32 9, ptr [[P]], align 4 |
| ; CHECK-NEXT: br label [[M2]] |
| ; CHECK: m1: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: store i32 11, ptr [[P]], align 4 |
| ; CHECK-NEXT: br label [[M2]] |
| ; CHECK: m2: |
| ; CHECK-NEXT: call void @unknown() |
| ; CHECK-NEXT: [[L:%.*]] = load i32, ptr [[P]], align 4 |
| ; CHECK-NEXT: ret i32 [[L]] |
| ; |
| %p = alloca i32 |
| store i32 0, ptr %p |
| call void @unknown() |
| store i32 1, ptr %p |
| br i1 %c0, label %t0, label %f0 |
| t0: |
| store i32 2, ptr %p |
| call void @unknown() |
| store i32 3, ptr %p |
| br i1 %c1, label %t1, label %m1 |
| f0: |
| store i32 4, ptr %p |
| call void @unknown() |
| store i32 5, ptr %p |
| br i1 %c2, label %f1, label %m1 |
| t1: |
| store i32 6, ptr %p |
| call void @unknown() |
| store i32 7, ptr %p |
| br label %m2 |
| f1: |
| store i32 8, ptr %p |
| call void @unknown() |
| store i32 9, ptr %p |
| br label %m2 |
| m1: |
| store i32 10, ptr %p |
| call void @unknown() |
| store i32 11, ptr %p |
| br label %m2 |
| m2: |
| call void @unknown() |
| %l = load i32, ptr %p |
| ret i32 %l |
| } |
| |
| declare void @usei32(i32) nocallback |
| ; Ensure we use 42, not undef, for %l in the usei32 call and %r in the return. |
| define internal i32 @remote_write_and_read(ptr %p) norecurse { |
| ; TUNIT: Function Attrs: norecurse |
| ; TUNIT-LABEL: define {{[^@]+}}@remote_write_and_read |
| ; TUNIT-SAME: (ptr noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR2]] { |
| ; TUNIT-NEXT: call void @usei32(i32 noundef 42) |
| ; TUNIT-NEXT: ret i32 undef |
| ; |
| ; CGSCC: Function Attrs: norecurse |
| ; CGSCC-LABEL: define {{[^@]+}}@remote_write_and_read |
| ; CGSCC-SAME: (ptr noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[P:%.*]]) #[[ATTR2]] { |
| ; CGSCC-NEXT: store i32 42, ptr [[P]], align 4 |
| ; CGSCC-NEXT: [[L:%.*]] = load i32, ptr [[P]], align 4 |
| ; CGSCC-NEXT: call void @usei32(i32 [[L]]) |
| ; CGSCC-NEXT: ret i32 [[L]] |
| ; |
| store i32 42, ptr %p |
| %l = load i32, ptr %p |
| call void @usei32(i32 %l) |
| ret i32 %l |
| } |
| |
| define i32 @local_stack_remote_write_and_read() norecurse { |
| ; TUNIT: Function Attrs: norecurse |
| ; TUNIT-LABEL: define {{[^@]+}}@local_stack_remote_write_and_read |
| ; TUNIT-SAME: () #[[ATTR2]] { |
| ; TUNIT-NEXT: [[A:%.*]] = alloca i32, align 4 |
| ; TUNIT-NEXT: [[R:%.*]] = call i32 @remote_write_and_read(ptr noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) |
| ; TUNIT-NEXT: ret i32 42 |
| ; |
| ; CGSCC: Function Attrs: norecurse |
| ; CGSCC-LABEL: define {{[^@]+}}@local_stack_remote_write_and_read |
| ; CGSCC-SAME: () #[[ATTR2]] { |
| ; CGSCC-NEXT: [[A:%.*]] = alloca i32, align 4 |
| ; CGSCC-NEXT: [[R:%.*]] = call i32 @remote_write_and_read(ptr noalias nocapture nofree noundef nonnull align 4 dereferenceable(4) [[A]]) |
| ; CGSCC-NEXT: ret i32 [[R]] |
| ; |
| %a = alloca i32 |
| %r = call i32 @remote_write_and_read(ptr %a) |
| ret i32 %r |
| } |
| ;. |
| ; CHECK: attributes #[[ATTR0:[0-9]+]] = { nocallback } |
| ; CHECK: attributes #[[ATTR1]] = { norecurse nosync } |
| ; CHECK: attributes #[[ATTR2]] = { norecurse } |
| ;. |