; 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 }