|  | ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes --version 2 | 
|  | ; RUN: opt -passes=function-attrs -S < %s | FileCheck --check-prefixes=COMMON,FNATTRS %s | 
|  | ; RUN: opt -passes=attributor-light -S < %s | FileCheck --check-prefixes=COMMON,ATTRIBUTOR %s | 
|  |  | 
|  | @g = global i32 20 | 
|  |  | 
|  | define void @test_no_read_or_write() { | 
|  | ; COMMON: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) | 
|  | ; COMMON-LABEL: define void @test_no_read_or_write | 
|  | ; COMMON-SAME: () #[[ATTR0:[0-9]+]] { | 
|  | ; COMMON-NEXT:  entry: | 
|  | ; COMMON-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define i32 @test_only_read_arg(ptr %ptr) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; FNATTRS-LABEL: define i32 @test_only_read_arg | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4 | 
|  | ; FNATTRS-NEXT:    ret i32 [[L]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; ATTRIBUTOR-LABEL: define i32 @test_only_read_arg | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR1:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret i32 [[L]] | 
|  | ; | 
|  | entry: | 
|  | %l = load i32, ptr %ptr | 
|  | ret i32 %l | 
|  | } | 
|  |  | 
|  | define i32 @test_only_read_arg_already_has_argmemonly(ptr %ptr) argmemonly { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; FNATTRS-LABEL: define i32 @test_only_read_arg_already_has_argmemonly | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4 | 
|  | ; FNATTRS-NEXT:    ret i32 [[L]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; ATTRIBUTOR-LABEL: define i32 @test_only_read_arg_already_has_argmemonly | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret i32 [[L]] | 
|  | ; | 
|  | entry: | 
|  | %l = load i32, ptr %ptr | 
|  | ret i32 %l | 
|  | } | 
|  |  | 
|  | define i32 @test_read_global() { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, argmem: none, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define i32 @test_read_global | 
|  | ; FNATTRS-SAME: () #[[ATTR2:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[L:%.*]] = load i32, ptr @g, align 4 | 
|  | ; FNATTRS-NEXT:    ret i32 [[L]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read) | 
|  | ; ATTRIBUTOR-LABEL: define i32 @test_read_global | 
|  | ; ATTRIBUTOR-SAME: () #[[ATTR2:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[L:%.*]] = load i32, ptr @g, align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret i32 [[L]] | 
|  | ; | 
|  | entry: | 
|  | %l = load i32, ptr @g | 
|  | ret i32 %l | 
|  | } | 
|  |  | 
|  | define i32 @test_read_loaded_ptr(ptr %ptr) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define i32 @test_read_loaded_ptr | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[L:%.*]] = load ptr, ptr [[PTR]], align 8 | 
|  | ; FNATTRS-NEXT:    [[L_2:%.*]] = load i32, ptr [[L]], align 4 | 
|  | ; FNATTRS-NEXT:    ret i32 [[L_2]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read) | 
|  | ; ATTRIBUTOR-LABEL: define i32 @test_read_loaded_ptr | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR2]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[L:%.*]] = load ptr, ptr [[PTR]], align 8 | 
|  | ; ATTRIBUTOR-NEXT:    [[L_2:%.*]] = load i32, ptr [[L]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret i32 [[L_2]] | 
|  | ; | 
|  | entry: | 
|  | %l = load ptr, ptr %ptr | 
|  | %l.2 = load i32, ptr %l | 
|  | ret i32 %l.2 | 
|  | } | 
|  |  | 
|  | define void @test_only_write_arg(ptr %ptr) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) | 
|  | ; FNATTRS-LABEL: define void @test_only_write_arg | 
|  | ; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[PTR:%.*]]) #[[ATTR4:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    store i32 0, ptr [[PTR]], align 4 | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: write) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_only_write_arg | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly captures(none) [[PTR:%.*]]) #[[ATTR3:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    store i32 0, ptr [[PTR]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | store i32 0, ptr %ptr | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test_write_global() { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write, argmem: none, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define void @test_write_global | 
|  | ; FNATTRS-SAME: () #[[ATTR5:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    store i32 0, ptr @g, align 4 | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(write) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_write_global | 
|  | ; ATTRIBUTOR-SAME: () #[[ATTR4:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    store i32 0, ptr @g, align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | store i32 0, ptr @g | 
|  | ret void | 
|  | } | 
|  |  | 
|  | declare void @fn_may_access_memory() | 
|  |  | 
|  | define void @test_call_may_access_memory() { | 
|  | ; COMMON-LABEL: define void @test_call_may_access_memory() { | 
|  | ; COMMON-NEXT:  entry: | 
|  | ; COMMON-NEXT:    call void @fn_may_access_memory() | 
|  | ; COMMON-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | call void @fn_may_access_memory() | 
|  | ret void | 
|  | } | 
|  |  | 
|  | declare i32 @fn_readnone() readnone | 
|  |  | 
|  | define void @test_call_readnone(ptr %ptr) { | 
|  | ; FNATTRS: Function Attrs: memory(argmem: write) | 
|  | ; FNATTRS-LABEL: define void @test_call_readnone | 
|  | ; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[PTR:%.*]]) #[[ATTR7:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[C:%.*]] = call i32 @fn_readnone() | 
|  | ; FNATTRS-NEXT:    store i32 [[C]], ptr [[PTR]], align 4 | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: nosync memory(argmem: write) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_call_readnone | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[PTR:%.*]]) #[[ATTR6:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[C:%.*]] = call i32 @fn_readnone() #[[ATTR18:[0-9]+]] | 
|  | ; ATTRIBUTOR-NEXT:    store i32 [[C]], ptr [[PTR]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | %c = call i32 @fn_readnone() | 
|  | store i32 %c, ptr %ptr | 
|  | ret void | 
|  | } | 
|  |  | 
|  | declare i32 @fn_argmemonly(ptr) argmemonly | 
|  |  | 
|  | define i32 @test_call_argmemonly(ptr %ptr) { | 
|  | ; FNATTRS: Function Attrs: memory(argmem: readwrite) | 
|  | ; FNATTRS-LABEL: define i32 @test_call_argmemonly | 
|  | ; FNATTRS-SAME: (ptr [[PTR:%.*]]) #[[ATTR8:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[C:%.*]] = call i32 @fn_argmemonly(ptr [[PTR]]) | 
|  | ; FNATTRS-NEXT:    ret i32 [[C]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: memory(argmem: readwrite) | 
|  | ; ATTRIBUTOR-LABEL: define i32 @test_call_argmemonly | 
|  | ; ATTRIBUTOR-SAME: (ptr [[PTR:%.*]]) #[[ATTR7:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[C:%.*]] = call i32 @fn_argmemonly(ptr [[PTR]]) | 
|  | ; ATTRIBUTOR-NEXT:    ret i32 [[C]] | 
|  | ; | 
|  | entry: | 
|  | %c = call i32 @fn_argmemonly(ptr %ptr) | 
|  | ret i32 %c | 
|  | } | 
|  |  | 
|  | define i32 @test_call_fn_where_argmemonly_can_be_inferred(ptr %ptr) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; FNATTRS-LABEL: define i32 @test_call_fn_where_argmemonly_can_be_inferred | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[C:%.*]] = call i32 @test_only_read_arg(ptr [[PTR]]) | 
|  | ; FNATTRS-NEXT:    ret i32 [[C]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; ATTRIBUTOR-LABEL: define i32 @test_call_fn_where_argmemonly_can_be_inferred | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[C:%.*]] = call i32 @test_only_read_arg(ptr nofree readonly captures(none) [[PTR]]) #[[ATTR19:[0-9]+]] | 
|  | ; ATTRIBUTOR-NEXT:    ret i32 [[C]] | 
|  | ; | 
|  | entry: | 
|  | %c = call i32 @test_only_read_arg(ptr %ptr) | 
|  | ret i32 %c | 
|  | } | 
|  |  | 
|  | define void @test_memcpy_argonly(ptr %dst, ptr %src) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) | 
|  | ; FNATTRS-LABEL: define void @test_memcpy_argonly | 
|  | ; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[DST:%.*]], ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR9:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[DST]], ptr [[SRC]], i64 32, i1 false) | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_memcpy_argonly | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[DST:%.*]], ptr nofree readonly captures(none) [[SRC:%.*]]) #[[ATTR8:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr writeonly captures(none) [[DST]], ptr readonly captures(none) [[SRC]], i64 32, i1 false) #[[ATTR20:[0-9]+]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr %src, i64 32, i1 false) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1) | 
|  |  | 
|  | @arr = global [32 x i8] zeroinitializer | 
|  |  | 
|  | define void @test_memcpy_src_global(ptr %dst) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define void @test_memcpy_src_global | 
|  | ; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 32)) [[DST:%.*]]) #[[ATTR11:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr [[DST]], ptr @arr, i64 32, i1 false) | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn | 
|  | ; ATTRIBUTOR-LABEL: define void @test_memcpy_src_global | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree writeonly captures(none) [[DST:%.*]]) #[[ATTR10:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr writeonly captures(none) [[DST]], ptr readonly @arr, i64 32, i1 false) #[[ATTR20]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | call void @llvm.memcpy.p0.p0.i64(ptr %dst, ptr @arr, i64 32, i1 false) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test_memcpy_dst_global(ptr %src) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(readwrite, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define void @test_memcpy_dst_global | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[SRC:%.*]]) #[[ATTR11]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr @arr, ptr [[SRC]], i64 32, i1 false) | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn | 
|  | ; ATTRIBUTOR-LABEL: define void @test_memcpy_dst_global | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree readonly captures(none) [[SRC:%.*]]) #[[ATTR10]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    call void @llvm.memcpy.p0.p0.i64(ptr writeonly @arr, ptr readonly captures(none) [[SRC]], i64 32, i1 false) #[[ATTR20]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | entry: | 
|  | call void @llvm.memcpy.p0.p0.i64(ptr @arr, ptr %src, i64 32, i1 false) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define i32 @test_read_arg_access_alloca(ptr %ptr) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; FNATTRS-LABEL: define i32 @test_read_arg_access_alloca | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[PTR:%.*]]) #[[ATTR1]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[A:%.*]] = alloca i32, align 4 | 
|  | ; FNATTRS-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4 | 
|  | ; FNATTRS-NEXT:    store i32 [[L]], ptr [[A]], align 4 | 
|  | ; FNATTRS-NEXT:    [[L_2:%.*]] = load i32, ptr [[A]], align 4 | 
|  | ; FNATTRS-NEXT:    ret i32 [[L_2]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: readwrite) | 
|  | ; ATTRIBUTOR-LABEL: define i32 @test_read_arg_access_alloca | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[PTR:%.*]]) #[[ATTR8]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[A:%.*]] = alloca i32, align 4 | 
|  | ; ATTRIBUTOR-NEXT:    [[L:%.*]] = load i32, ptr [[PTR]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    store i32 [[L]], ptr [[A]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    [[L_2:%.*]] = load i32, ptr [[A]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret i32 [[L_2]] | 
|  | ; | 
|  | entry: | 
|  | %a = alloca i32 | 
|  | %l = load i32, ptr %ptr | 
|  | store i32 %l, ptr %a | 
|  | %l.2 = load i32, ptr %a | 
|  | ret i32 %l.2 | 
|  | } | 
|  |  | 
|  | declare void @fn_inaccessiblememonly() inaccessiblememonly | 
|  |  | 
|  | define void @test_inaccessiblememonly() { | 
|  | ; FNATTRS: Function Attrs: memory(inaccessiblemem: readwrite) | 
|  | ; FNATTRS-LABEL: define void @test_inaccessiblememonly | 
|  | ; FNATTRS-SAME: () #[[ATTR12:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:    call void @fn_inaccessiblememonly() | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: memory(inaccessiblemem: readwrite) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_inaccessiblememonly | 
|  | ; ATTRIBUTOR-SAME: () #[[ATTR11:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:    call void @fn_inaccessiblememonly() | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | call void @fn_inaccessiblememonly() | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test_inaccessiblememonly_readonly() { | 
|  | ; FNATTRS: Function Attrs: nofree memory(inaccessiblemem: read) | 
|  | ; FNATTRS-LABEL: define void @test_inaccessiblememonly_readonly | 
|  | ; FNATTRS-SAME: () #[[ATTR13:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR19:[0-9]+]] | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: nosync memory(inaccessiblemem: read) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_inaccessiblememonly_readonly | 
|  | ; ATTRIBUTOR-SAME: () #[[ATTR12:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR21:[0-9]+]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | call void @fn_inaccessiblememonly() readonly | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test_inaccessibleorargmemonly_readonly(ptr %arg) { | 
|  | ; FNATTRS: Function Attrs: nofree memory(argmem: read, inaccessiblemem: read) | 
|  | ; FNATTRS-LABEL: define void @test_inaccessibleorargmemonly_readonly | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[ARG:%.*]]) #[[ATTR14:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARG]], align 4 | 
|  | ; FNATTRS-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR19]] | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: nosync memory(argmem: read, inaccessiblemem: read) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_inaccessibleorargmemonly_readonly | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[ARG:%.*]]) #[[ATTR13:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = load i32, ptr [[ARG]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR21]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | load i32, ptr %arg | 
|  | call void @fn_inaccessiblememonly() readonly | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test_inaccessibleorargmemonly_readwrite(ptr %arg) { | 
|  | ; FNATTRS: Function Attrs: memory(argmem: write, inaccessiblemem: read) | 
|  | ; FNATTRS-LABEL: define void @test_inaccessibleorargmemonly_readwrite | 
|  | ; FNATTRS-SAME: (ptr writeonly captures(none) initializes((0, 4)) [[ARG:%.*]]) #[[ATTR15:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:    store i32 0, ptr [[ARG]], align 4 | 
|  | ; FNATTRS-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR19]] | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: nosync memory(argmem: readwrite, inaccessiblemem: readwrite) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_inaccessibleorargmemonly_readwrite | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull writeonly captures(none) [[ARG:%.*]]) #[[ATTR14:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:    store i32 0, ptr [[ARG]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    call void @fn_inaccessiblememonly() #[[ATTR21]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | store i32 0, ptr %arg | 
|  | call void @fn_inaccessiblememonly() readonly | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test_recursive_argmem_read(ptr %p) { | 
|  | ; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define void @test_recursive_argmem_read | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 | 
|  | ; FNATTRS-NEXT:    call void @test_recursive_argmem_read(ptr [[PVAL]]) | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_read | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR15:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 | 
|  | ; ATTRIBUTOR-NEXT:    call void @test_recursive_argmem_read(ptr nofree readonly captures(none) [[PVAL]]) #[[ATTR15]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | %pval = load ptr, ptr %p | 
|  | call void @test_recursive_argmem_read(ptr %pval) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test_recursive_argmem_readwrite(ptr %p) { | 
|  | ; FNATTRS: Function Attrs: nofree nosync nounwind memory(readwrite, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define void @test_recursive_argmem_readwrite | 
|  | ; FNATTRS-SAME: (ptr captures(none) [[P:%.*]]) #[[ATTR17:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 | 
|  | ; FNATTRS-NEXT:    store i32 0, ptr [[P]], align 4 | 
|  | ; FNATTRS-NEXT:    call void @test_recursive_argmem_readwrite(ptr [[PVAL]]) | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind | 
|  | ; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_readwrite | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull captures(none) [[P:%.*]]) #[[ATTR16:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 | 
|  | ; ATTRIBUTOR-NEXT:    store i32 0, ptr [[P]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    call void @test_recursive_argmem_readwrite(ptr nofree captures(none) [[PVAL]]) #[[ATTR16]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | %pval = load ptr, ptr %p | 
|  | store i32 0, ptr %p | 
|  | call void @test_recursive_argmem_readwrite(ptr %pval) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test_recursive_argmem_read_alloca(ptr %p) { | 
|  | ; FNATTRS: Function Attrs: nofree nosync nounwind memory(argmem: read) | 
|  | ; FNATTRS-LABEL: define void @test_recursive_argmem_read_alloca | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR18:[0-9]+]] { | 
|  | ; FNATTRS-NEXT:    [[A:%.*]] = alloca ptr, align 8 | 
|  | ; FNATTRS-NEXT:    [[TMP1:%.*]] = load i32, ptr [[P]], align 4 | 
|  | ; FNATTRS-NEXT:    call void @test_recursive_argmem_read_alloca(ptr [[A]]) | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(argmem: read) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_recursive_argmem_read_alloca | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR17:[0-9]+]] { | 
|  | ; ATTRIBUTOR-NEXT:    [[A:%.*]] = alloca ptr, align 8 | 
|  | ; ATTRIBUTOR-NEXT:    [[TMP1:%.*]] = load i32, ptr [[P]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    call void @test_recursive_argmem_read_alloca(ptr nofree nonnull readonly captures(none) [[A]]) #[[ATTR15]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | %a = alloca ptr | 
|  | load i32, ptr %p | 
|  | call void @test_recursive_argmem_read_alloca(ptr %a) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test_scc_argmem_read_1(ptr %p) { | 
|  | ; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define void @test_scc_argmem_read_1 | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16]] { | 
|  | ; FNATTRS-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 | 
|  | ; FNATTRS-NEXT:    call void @test_scc_argmem_read_2(ptr [[PVAL]]) | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_scc_argmem_read_1 | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree nonnull readonly captures(none) [[P:%.*]]) #[[ATTR15]] { | 
|  | ; ATTRIBUTOR-NEXT:    [[PVAL:%.*]] = load ptr, ptr [[P]], align 8 | 
|  | ; ATTRIBUTOR-NEXT:    call void @test_scc_argmem_read_2(ptr nofree readonly captures(none) [[PVAL]]) #[[ATTR15]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | %pval = load ptr, ptr %p | 
|  | call void @test_scc_argmem_read_2(ptr %pval) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define void @test_scc_argmem_read_2(ptr %p) { | 
|  | ; FNATTRS: Function Attrs: nofree nosync nounwind memory(read, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define void @test_scc_argmem_read_2 | 
|  | ; FNATTRS-SAME: (ptr readonly captures(none) [[P:%.*]]) #[[ATTR16]] { | 
|  | ; FNATTRS-NEXT:    call void @test_scc_argmem_read_1(ptr [[P]]) | 
|  | ; FNATTRS-NEXT:    ret void | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: nofree nosync nounwind memory(read) | 
|  | ; ATTRIBUTOR-LABEL: define void @test_scc_argmem_read_2 | 
|  | ; ATTRIBUTOR-SAME: (ptr nofree readonly captures(none) [[P:%.*]]) #[[ATTR15]] { | 
|  | ; ATTRIBUTOR-NEXT:    call void @test_scc_argmem_read_1(ptr nofree readonly captures(none) [[P]]) #[[ATTR15]] | 
|  | ; ATTRIBUTOR-NEXT:    ret void | 
|  | ; | 
|  | call void @test_scc_argmem_read_1(ptr %p) | 
|  | ret void | 
|  | } | 
|  |  | 
|  | define i64 @select_same_obj(i1 %c, ptr %p, i64 %x) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; FNATTRS-LABEL: define i64 @select_same_obj | 
|  | ; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] | 
|  | ; FNATTRS-NEXT:    [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]] | 
|  | ; FNATTRS-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4 | 
|  | ; FNATTRS-NEXT:    ret i64 [[R]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) | 
|  | ; ATTRIBUTOR-LABEL: define i64 @select_same_obj | 
|  | ; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR0]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] | 
|  | ; ATTRIBUTOR-NEXT:    [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]] | 
|  | ; ATTRIBUTOR-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret i64 [[R]] | 
|  | ; | 
|  | entry: | 
|  | %p2 = getelementptr i8, ptr %p, i64 %x | 
|  | %p3 = select i1 %c, ptr %p, ptr %p2 | 
|  | %r = load i64, ptr %p3 | 
|  | ret i64 %r | 
|  | } | 
|  |  | 
|  | ; FIXME: This could be `memory(argmem: read)`. | 
|  | define i64 @select_different_obj(i1 %c, ptr %p, ptr %p2) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define i64 @select_different_obj | 
|  | ; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR3]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]] | 
|  | ; FNATTRS-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4 | 
|  | ; FNATTRS-NEXT:    ret i64 [[R]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) | 
|  | ; ATTRIBUTOR-LABEL: define i64 @select_different_obj | 
|  | ; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], ptr nofree readonly captures(none) [[P2:%.*]]) #[[ATTR0]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[P3:%.*]] = select i1 [[C]], ptr [[P]], ptr [[P2]] | 
|  | ; ATTRIBUTOR-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret i64 [[R]] | 
|  | ; | 
|  | entry: | 
|  | %p3 = select i1 %c, ptr %p, ptr %p2 | 
|  | %r = load i64, ptr %p3 | 
|  | ret i64 %r | 
|  | } | 
|  |  | 
|  | define i64 @phi_same_obj(i1 %c, ptr %p, i64 %x) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; FNATTRS-LABEL: define i64 @phi_same_obj | 
|  | ; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] | 
|  | ; FNATTRS-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] | 
|  | ; FNATTRS:       if: | 
|  | ; FNATTRS-NEXT:    br label [[JOIN]] | 
|  | ; FNATTRS:       join: | 
|  | ; FNATTRS-NEXT:    [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ] | 
|  | ; FNATTRS-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4 | 
|  | ; FNATTRS-NEXT:    ret i64 [[R]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; ATTRIBUTOR-LABEL: define i64 @phi_same_obj | 
|  | ; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], i64 [[X:%.*]]) #[[ATTR1]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    [[P2:%.*]] = getelementptr i8, ptr [[P]], i64 [[X]] | 
|  | ; ATTRIBUTOR-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] | 
|  | ; ATTRIBUTOR:       if: | 
|  | ; ATTRIBUTOR-NEXT:    br label [[JOIN]] | 
|  | ; ATTRIBUTOR:       join: | 
|  | ; ATTRIBUTOR-NEXT:    [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ] | 
|  | ; ATTRIBUTOR-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret i64 [[R]] | 
|  | ; | 
|  | entry: | 
|  | %p2 = getelementptr i8, ptr %p, i64 %x | 
|  | br i1 %c, label %if, label %join | 
|  | if: | 
|  | br label %join | 
|  | join: | 
|  | %p3 = phi ptr [ %p, %if ], [ %p2, %entry ] | 
|  | %r = load i64, ptr %p3 | 
|  | ret i64 %r | 
|  | } | 
|  |  | 
|  | ; FIXME: This could be `memory(argmem: read)`. | 
|  | define i64 @phi_different_obj(i1 %c, ptr %p, ptr %p2) { | 
|  | ; FNATTRS: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(read, inaccessiblemem: none) | 
|  | ; FNATTRS-LABEL: define i64 @phi_different_obj | 
|  | ; FNATTRS-SAME: (i1 [[C:%.*]], ptr readonly captures(none) [[P:%.*]], ptr readonly captures(none) [[P2:%.*]]) #[[ATTR3]] { | 
|  | ; FNATTRS-NEXT:  entry: | 
|  | ; FNATTRS-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] | 
|  | ; FNATTRS:       if: | 
|  | ; FNATTRS-NEXT:    br label [[JOIN]] | 
|  | ; FNATTRS:       join: | 
|  | ; FNATTRS-NEXT:    [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ] | 
|  | ; FNATTRS-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4 | 
|  | ; FNATTRS-NEXT:    ret i64 [[R]] | 
|  | ; | 
|  | ; ATTRIBUTOR: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(argmem: read) | 
|  | ; ATTRIBUTOR-LABEL: define i64 @phi_different_obj | 
|  | ; ATTRIBUTOR-SAME: (i1 [[C:%.*]], ptr nofree readonly captures(none) [[P:%.*]], ptr nofree readonly captures(none) [[P2:%.*]]) #[[ATTR1]] { | 
|  | ; ATTRIBUTOR-NEXT:  entry: | 
|  | ; ATTRIBUTOR-NEXT:    br i1 [[C]], label [[IF:%.*]], label [[JOIN:%.*]] | 
|  | ; ATTRIBUTOR:       if: | 
|  | ; ATTRIBUTOR-NEXT:    br label [[JOIN]] | 
|  | ; ATTRIBUTOR:       join: | 
|  | ; ATTRIBUTOR-NEXT:    [[P3:%.*]] = phi ptr [ [[P]], [[IF]] ], [ [[P2]], [[ENTRY:%.*]] ] | 
|  | ; ATTRIBUTOR-NEXT:    [[R:%.*]] = load i64, ptr [[P3]], align 4 | 
|  | ; ATTRIBUTOR-NEXT:    ret i64 [[R]] | 
|  | ; | 
|  | entry: | 
|  | br i1 %c, label %if, label %join | 
|  | if: | 
|  | br label %join | 
|  | join: | 
|  | %p3 = phi ptr [ %p, %if ], [ %p2, %entry ] | 
|  | %r = load i64, ptr %p3 | 
|  | ret i64 %r | 
|  | } | 
|  |  | 
|  | ; An `alloca` that won't be handled by `getModRefInfoMask` | 
|  | define i64 @alloca_with_phis(i64 %arg, i1 %cmp) { | 
|  | ; COMMON: Function Attrs: mustprogress nofree norecurse nosync nounwind willreturn memory(none) | 
|  | ; COMMON-LABEL: define i64 @alloca_with_phis | 
|  | ; COMMON-SAME: (i64 [[ARG:%.*]], i1 [[CMP:%.*]]) #[[ATTR0]] { | 
|  | ; COMMON-NEXT:  bb: | 
|  | ; COMMON-NEXT:    [[I:%.*]] = alloca i64, align 8 | 
|  | ; COMMON-NEXT:    store i64 [[ARG]], ptr [[I]], align 4 | 
|  | ; COMMON-NEXT:    br i1 [[CMP]], label [[BB1:%.*]], label [[BB4:%.*]] | 
|  | ; COMMON:       bb1: | 
|  | ; COMMON-NEXT:    br i1 [[CMP]], label [[BB8:%.*]], label [[BB2:%.*]] | 
|  | ; COMMON:       bb2: | 
|  | ; COMMON-NEXT:    br i1 [[CMP]], label [[BB8]], label [[BB3:%.*]] | 
|  | ; COMMON:       bb3: | 
|  | ; COMMON-NEXT:    br i1 [[CMP]], label [[BB8]], label [[BB6:%.*]] | 
|  | ; COMMON:       bb4: | 
|  | ; COMMON-NEXT:    br i1 [[CMP]], label [[BB8]], label [[BB5:%.*]] | 
|  | ; COMMON:       bb5: | 
|  | ; COMMON-NEXT:    br i1 [[CMP]], label [[BB8]], label [[BB6]] | 
|  | ; COMMON:       bb6: | 
|  | ; COMMON-NEXT:    [[I7:%.*]] = phi ptr [ [[I]], [[BB3]] ], [ [[I]], [[BB5]] ] | 
|  | ; COMMON-NEXT:    br label [[BB8]] | 
|  | ; COMMON:       bb8: | 
|  | ; COMMON-NEXT:    [[I9:%.*]] = phi ptr [ [[I]], [[BB1]] ], [ [[I]], [[BB2]] ], [ [[I]], [[BB3]] ], [ [[I]], [[BB4]] ], [ [[I]], [[BB5]] ], [ [[I7]], [[BB6]] ] | 
|  | ; COMMON-NEXT:    [[RET:%.*]] = load i64, ptr [[I9]], align 4 | 
|  | ; COMMON-NEXT:    ret i64 [[RET]] | 
|  | ; | 
|  | bb: | 
|  | %i = alloca i64 | 
|  | store i64 %arg, ptr %i | 
|  | br i1 %cmp, label %bb1, label %bb4 | 
|  |  | 
|  | bb1:                                              ; preds = %bb | 
|  | br i1 %cmp, label %bb8, label %bb2 | 
|  |  | 
|  | bb2:                                              ; preds = %bb1 | 
|  | br i1 %cmp, label %bb8, label %bb3 | 
|  |  | 
|  | bb3:                                              ; preds = %bb2 | 
|  | br i1 %cmp, label %bb8, label %bb6 | 
|  |  | 
|  | bb4:                                              ; preds = %bb | 
|  | br i1 %cmp, label %bb8, label %bb5 | 
|  |  | 
|  | bb5:                                              ; preds = %bb4 | 
|  | br i1 %cmp, label %bb8, label %bb6 | 
|  |  | 
|  | bb6:                                              ; preds = %bb5, %bb3 | 
|  | %i7 = phi ptr [ %i, %bb3 ], [ %i, %bb5 ] | 
|  | br label %bb8 | 
|  |  | 
|  | bb8:                                              ; preds = %bb6, %bb5, %bb4, %bb3, %bb2, %bb1 | 
|  | %i9 = phi ptr [ %i, %bb1 ], [ %i, %bb2 ], [ %i, %bb3 ], [ %i, %bb4 ], [ %i, %bb5 ], [ %i7, %bb6 ] | 
|  | %ret = load i64, ptr %i9 | 
|  | ret i64 %ret | 
|  | } |