| ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 |
| ; RUN: opt -S -passes=function-attrs < %s | FileCheck %s |
| |
| declare noalias ptr @malloc(i64 %size) |
| declare ptr @not_malloc(i64 %size) |
| declare void @capture(ptr) |
| |
| @g = external global i8 |
| |
| define ptr @return_malloc(i64 %size) { |
| ; CHECK-LABEL: define noalias ptr @return_malloc( |
| ; CHECK-SAME: i64 [[SIZE:%.*]]) { |
| ; CHECK-NEXT: [[A:%.*]] = call ptr @malloc(i64 [[SIZE]]) |
| ; CHECK-NEXT: ret ptr [[A]] |
| ; |
| %a = call ptr @malloc(i64 %size) |
| ret ptr %a |
| } |
| |
| define ptr @return_not_malloc(i64 %size) { |
| ; CHECK-LABEL: define ptr @return_not_malloc( |
| ; CHECK-SAME: i64 [[SIZE:%.*]]) { |
| ; CHECK-NEXT: [[A:%.*]] = call ptr @not_malloc(i64 [[SIZE]]) |
| ; CHECK-NEXT: ret ptr [[A]] |
| ; |
| %a = call ptr @not_malloc(i64 %size) |
| ret ptr %a |
| } |
| |
| define ptr @return_null() { |
| ; CHECK-LABEL: define noalias noundef ptr @return_null( |
| ; CHECK-SAME: ) #[[ATTR0:[0-9]+]] { |
| ; CHECK-NEXT: ret ptr null |
| ; |
| ret ptr null |
| } |
| |
| define ptr @return_poison() { |
| ; CHECK-LABEL: define noalias ptr @return_poison( |
| ; CHECK-SAME: ) #[[ATTR0]] { |
| ; CHECK-NEXT: ret ptr poison |
| ; |
| ret ptr poison |
| } |
| |
| define ptr @return_alloca() { |
| ; CHECK-LABEL: define noalias noundef nonnull ptr @return_alloca( |
| ; CHECK-SAME: ) #[[ATTR0]] { |
| ; CHECK-NEXT: [[A:%.*]] = alloca i8, align 1 |
| ; CHECK-NEXT: ret ptr [[A]] |
| ; |
| %a = alloca i8 |
| ret ptr %a |
| } |
| |
| ; noalias arg does not imply noalias return |
| define ptr @return_noalias_arg(ptr noalias %arg) { |
| ; CHECK-LABEL: define ptr @return_noalias_arg( |
| ; CHECK-SAME: ptr noalias readnone returned captures(ret: address, provenance) [[ARG:%.*]]) #[[ATTR0]] { |
| ; CHECK-NEXT: ret ptr [[ARG]] |
| ; |
| ret ptr %arg |
| } |
| |
| define ptr @return_global() { |
| ; CHECK-LABEL: define noundef nonnull ptr @return_global( |
| ; CHECK-SAME: ) #[[ATTR0]] { |
| ; CHECK-NEXT: ret ptr @g |
| ; |
| ret ptr @g |
| } |
| |
| define ptr @no_return() { |
| ; CHECK-LABEL: define noalias noundef nonnull ptr @no_return( |
| ; CHECK-SAME: ) #[[ATTR1:[0-9]+]] { |
| ; CHECK-NEXT: unreachable |
| ; |
| unreachable |
| } |
| |
| define ptr @return_multiple(i1 %c, i64 %size) { |
| ; CHECK-LABEL: define noalias ptr @return_multiple( |
| ; CHECK-SAME: i1 [[C:%.*]], i64 [[SIZE:%.*]]) { |
| ; CHECK-NEXT: br i1 [[C]], label %[[IF:.*]], label %[[ELSE:.*]] |
| ; CHECK: [[IF]]: |
| ; CHECK-NEXT: [[A:%.*]] = call ptr @malloc(i64 [[SIZE]]) |
| ; CHECK-NEXT: ret ptr [[A]] |
| ; CHECK: [[ELSE]]: |
| ; CHECK-NEXT: [[B:%.*]] = call ptr @malloc(i64 [[SIZE]]) |
| ; CHECK-NEXT: ret ptr [[B]] |
| ; |
| br i1 %c, label %if, label %else |
| |
| if: |
| %a = call ptr @malloc(i64 %size) |
| ret ptr %a |
| |
| else: |
| %b = call ptr @malloc(i64 %size) |
| ret ptr %b |
| } |
| |
| define ptr @return_select(i1 %c, i64 %size) { |
| ; CHECK-LABEL: define noalias ptr @return_select( |
| ; CHECK-SAME: i1 [[C:%.*]], i64 [[SIZE:%.*]]) { |
| ; CHECK-NEXT: [[A:%.*]] = call ptr @malloc(i64 [[SIZE]]) |
| ; CHECK-NEXT: [[SEL:%.*]] = select i1 [[C]], ptr [[A]], ptr null |
| ; CHECK-NEXT: ret ptr [[SEL]] |
| ; |
| %a = call ptr @malloc(i64 %size) |
| %sel = select i1 %c, ptr %a, ptr null |
| ret ptr %sel |
| } |
| |
| define ptr @return_phi(i1 %c, i64 %size) { |
| ; CHECK-LABEL: define noalias ptr @return_phi( |
| ; CHECK-SAME: i1 [[C:%.*]], i64 [[SIZE:%.*]]) { |
| ; CHECK-NEXT: br i1 [[C]], label %[[IF:.*]], label %[[ELSE:.*]] |
| ; CHECK: [[IF]]: |
| ; CHECK-NEXT: [[A:%.*]] = call ptr @malloc(i64 [[SIZE]]) |
| ; CHECK-NEXT: br label %[[JOIN:.*]] |
| ; CHECK: [[ELSE]]: |
| ; CHECK-NEXT: br label %[[JOIN]] |
| ; CHECK: [[JOIN]]: |
| ; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[A]], %[[IF]] ], [ null, %[[ELSE]] ] |
| ; CHECK-NEXT: ret ptr [[PHI]] |
| ; |
| br i1 %c, label %if, label %else |
| |
| if: |
| %a = call ptr @malloc(i64 %size) |
| br label %join |
| |
| else: |
| br label %join |
| |
| join: |
| %phi = phi ptr [ %a, %if ], [ null, %else ] |
| ret ptr %phi |
| } |
| |
| define ptr @return_phi_wrong(i1 %c, i64 %size) { |
| ; CHECK-LABEL: define ptr @return_phi_wrong( |
| ; CHECK-SAME: i1 [[C:%.*]], i64 [[SIZE:%.*]]) { |
| ; CHECK-NEXT: br i1 [[C]], label %[[IF:.*]], label %[[ELSE:.*]] |
| ; CHECK: [[IF]]: |
| ; CHECK-NEXT: [[A:%.*]] = call ptr @malloc(i64 [[SIZE]]) |
| ; CHECK-NEXT: br label %[[JOIN:.*]] |
| ; CHECK: [[ELSE]]: |
| ; CHECK-NEXT: [[B:%.*]] = call ptr @not_malloc(i64 [[SIZE]]) |
| ; CHECK-NEXT: br label %[[JOIN]] |
| ; CHECK: [[JOIN]]: |
| ; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[A]], %[[IF]] ], [ [[B]], %[[ELSE]] ] |
| ; CHECK-NEXT: ret ptr [[PHI]] |
| ; |
| br i1 %c, label %if, label %else |
| |
| if: |
| %a = call ptr @malloc(i64 %size) |
| br label %join |
| |
| else: |
| %b = call ptr @not_malloc(i64 %size) |
| br label %join |
| |
| join: |
| %phi = phi ptr [ %a, %if ], [ %b, %else ] |
| ret ptr %phi |
| } |
| |
| define ptr @return_malloc_with_store(i64 %size) { |
| ; CHECK-LABEL: define noalias noundef ptr @return_malloc_with_store( |
| ; CHECK-SAME: i64 [[SIZE:%.*]]) { |
| ; CHECK-NEXT: [[A:%.*]] = call ptr @malloc(i64 [[SIZE]]) |
| ; CHECK-NEXT: store i8 0, ptr [[A]], align 1 |
| ; CHECK-NEXT: ret ptr [[A]] |
| ; |
| %a = call ptr @malloc(i64 %size) |
| store i8 0, ptr %a |
| ret ptr %a |
| } |
| |
| define ptr @return_malloc_captured(i64 %size) { |
| ; CHECK-LABEL: define ptr @return_malloc_captured( |
| ; CHECK-SAME: i64 [[SIZE:%.*]]) { |
| ; CHECK-NEXT: [[A:%.*]] = call ptr @malloc(i64 [[SIZE]]) |
| ; CHECK-NEXT: call void @capture(ptr [[A]]) |
| ; CHECK-NEXT: ret ptr [[A]] |
| ; |
| %a = call ptr @malloc(i64 %size) |
| call void @capture(ptr %a) |
| ret ptr %a |
| } |
| |
| define ptr @scc1(i1 %c) { |
| ; CHECK-LABEL: define noalias ptr @scc1( |
| ; CHECK-SAME: i1 [[C:%.*]]) { |
| ; CHECK-NEXT: br i1 [[C]], label %[[IF:.*]], label %[[ELSE:.*]] |
| ; CHECK: [[IF]]: |
| ; CHECK-NEXT: [[A:%.*]] = call ptr @malloc(i64 4) |
| ; CHECK-NEXT: ret ptr [[A]] |
| ; CHECK: [[ELSE]]: |
| ; CHECK-NEXT: [[B:%.*]] = call ptr @scc2(i1 [[C]]) |
| ; CHECK-NEXT: ret ptr [[B]] |
| ; |
| br i1 %c, label %if, label %else |
| |
| if: |
| %a = call ptr @malloc(i64 4) |
| ret ptr %a |
| |
| else: |
| %b = call ptr @scc2(i1 %c) |
| ret ptr %b |
| } |
| |
| define ptr @scc2(i1 %c) { |
| ; CHECK-LABEL: define noalias ptr @scc2( |
| ; CHECK-SAME: i1 [[C:%.*]]) { |
| ; CHECK-NEXT: [[A:%.*]] = call ptr @scc1(i1 [[C]]) |
| ; CHECK-NEXT: ret ptr [[A]] |
| ; |
| %a = call ptr @scc1(i1 %c) |
| ret ptr %a |
| } |
| |
| define ptr @return_unknown_call(ptr %fn) { |
| ; CHECK-LABEL: define ptr @return_unknown_call( |
| ; CHECK-SAME: ptr readonly captures(none) [[FN:%.*]]) { |
| ; CHECK-NEXT: [[A:%.*]] = call ptr [[FN]]() |
| ; CHECK-NEXT: ret ptr [[A]] |
| ; |
| %a = call ptr %fn() |
| ret ptr %a |
| } |
| |
| define ptr @return_unknown_noalias_call(ptr %fn) { |
| ; CHECK-LABEL: define noalias ptr @return_unknown_noalias_call( |
| ; CHECK-SAME: ptr readonly captures(none) [[FN:%.*]]) { |
| ; CHECK-NEXT: [[A:%.*]] = call noalias ptr [[FN]]() |
| ; CHECK-NEXT: ret ptr [[A]] |
| ; |
| %a = call noalias ptr %fn() |
| ret ptr %a |
| } |