From 5957cf9f11bf28591196730cb639e29a11e76abb Mon Sep 17 00:00:00 2001 From: Johannes Doerfert Date: Mon, 12 Jul 2021 22:14:36 -0500 Subject: [PATCH] [Attributor] Simplify to values in the genericValueTraversal We already simplified to a constant, given the new interface we can also simplify to a generic value. --- .../Transforms/IPO/AttributorAttributes.cpp | 14 ++- .../IPConstantProp/return-argument.ll | 12 +- .../Transforms/Attributor/memory_locations.ll | 106 ++++++++++++++---- llvm/test/Transforms/Attributor/readattrs.ll | 4 +- 4 files changed, 98 insertions(+), 38 deletions(-) diff --git a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp index 229f09c5d5da..ceb69f5a40c6 100644 --- a/llvm/lib/Transforms/IPO/AttributorAttributes.cpp +++ b/llvm/lib/Transforms/IPO/AttributorAttributes.cpp @@ -352,13 +352,15 @@ static bool genericValueTraversal( if (UseValueSimplify && !isa(V)) { bool UsedAssumedInformation = false; - Optional C = - A.getAssumedConstant(*V, QueryingAA, UsedAssumedInformation); - if (!C.hasValue()) - continue; - if (Value *NewV = C.getValue()) { - Worklist.push_back({NewV, CtxI}); + Optional SimpleV = + A.getAssumedSimplified(*V, QueryingAA, UsedAssumedInformation); + if (!SimpleV.hasValue()) continue; + if (Value *NewV = SimpleV.getValue()) { + if (NewV != V) { + Worklist.push_back({NewV, CtxI}); + continue; + } } } diff --git a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll index d59605ef299f..3be108a2b8b4 100644 --- a/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll +++ b/llvm/test/Transforms/Attributor/IPConstantProp/return-argument.ll @@ -88,11 +88,11 @@ define internal { i32, i32 } @foo(i32 %A, i32 %B) { } define void @caller(i1 %C) personality i32 (...)* @__gxx_personality_v0 { -; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind willreturn +; IS__TUNIT_OPM: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT_OPM-LABEL: define {{[^@]+}}@caller -; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] personality i32 (...)* @__gxx_personality_v0 { +; IS__TUNIT_OPM-SAME: (i1 [[C:%.*]]) #[[ATTR1]] personality i32 (...)* @__gxx_personality_v0 { ; IS__TUNIT_OPM-NEXT: [[Q:%.*]] = alloca i32, align 4 -; IS__TUNIT_OPM-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2]] +; IS__TUNIT_OPM-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]] ; IS__TUNIT_OPM-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR1]] ; IS__TUNIT_OPM-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 ; IS__TUNIT_OPM-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR1]] @@ -107,11 +107,11 @@ define void @caller(i1 %C) personality i32 (...)* @__gxx_personality_v0 { ; IS__TUNIT_OPM: RET: ; IS__TUNIT_OPM-NEXT: ret void ; -; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind willreturn +; IS__TUNIT_NPM: Function Attrs: nofree nosync nounwind readnone willreturn ; IS__TUNIT_NPM-LABEL: define {{[^@]+}}@caller -; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]]) #[[ATTR2:[0-9]+]] personality i32 (...)* @__gxx_personality_v0 { +; IS__TUNIT_NPM-SAME: (i1 [[C:%.*]]) #[[ATTR1]] personality i32 (...)* @__gxx_personality_v0 { ; IS__TUNIT_NPM-NEXT: [[Q:%.*]] = alloca i32, align 4 -; IS__TUNIT_NPM-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2]] +; IS__TUNIT_NPM-NEXT: [[W:%.*]] = call align 4 i32* @incdec(i1 [[C]], i32* noalias nofree noundef nonnull align 4 dereferenceable(4) "no-capture-maybe-returned" [[Q]]) #[[ATTR2:[0-9]+]] ; IS__TUNIT_NPM-NEXT: [[S1:%.*]] = call { i32, i32 } @foo(i32 noundef 1, i32 noundef 2) #[[ATTR1]] ; IS__TUNIT_NPM-NEXT: [[X1:%.*]] = extractvalue { i32, i32 } [[S1]], 0 ; IS__TUNIT_NPM-NEXT: [[S2:%.*]] = call { i32, i32 } @foo(i32 noundef 3, i32 noundef 4) #[[ATTR1]] diff --git a/llvm/test/Transforms/Attributor/memory_locations.ll b/llvm/test/Transforms/Attributor/memory_locations.ll index d213db32a1c4..c135d02dc918 100644 --- a/llvm/test/Transforms/Attributor/memory_locations.ll +++ b/llvm/test/Transforms/Attributor/memory_locations.ll @@ -491,7 +491,7 @@ define void @writeonly_global() { ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@writeonly_global ; IS__CGSCC____-SAME: () #[[ATTR6]] { -; IS__CGSCC____-NEXT: call void @write_global() #[[ATTR10:[0-9]+]] +; IS__CGSCC____-NEXT: call void @write_global() #[[ATTR11:[0-9]+]] ; IS__CGSCC____-NEXT: ret void ; call void @write_global() @@ -507,7 +507,7 @@ define void @writeonly_global_via_arg() { ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@writeonly_global_via_arg ; IS__CGSCC____-SAME: () #[[ATTR6]] { -; IS__CGSCC____-NEXT: call void @write_global_via_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) @G) #[[ATTR10]] +; IS__CGSCC____-NEXT: call void @write_global_via_arg(i32* nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) @G) #[[ATTR11]] ; IS__CGSCC____-NEXT: ret void ; call void @write_global_via_arg(i32* @G) @@ -525,7 +525,7 @@ define void @writeonly_global_via_arg_internal() { ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@writeonly_global_via_arg_internal ; IS__CGSCC____-SAME: () #[[ATTR6]] { -; IS__CGSCC____-NEXT: call void @write_global_via_arg_internal() #[[ATTR10]] +; IS__CGSCC____-NEXT: call void @write_global_via_arg_internal() #[[ATTR11]] ; IS__CGSCC____-NEXT: ret void ; call void @write_global_via_arg_internal(i32* @G) @@ -551,7 +551,7 @@ define i8 @recursive_not_readnone(i8* %ptr, i1 %c) { ; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1 ; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] ; IS__CGSCC____: t: -; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR11:[0-9]+]], !range [[RNG0:![0-9]+]] +; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR12:[0-9]+]], !range [[RNG0:![0-9]+]] ; IS__CGSCC____-NEXT: ret i8 1 ; IS__CGSCC____: f: ; IS__CGSCC____-NEXT: store i8 1, i8* [[PTR]], align 1 @@ -587,7 +587,7 @@ define internal i8 @recursive_not_readnone_internal(i8* %ptr, i1 %c) { ; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1 ; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] ; IS__CGSCC____: t: -; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR11]], !range [[RNG0]] +; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR12]], !range [[RNG0]] ; IS__CGSCC____-NEXT: ret i8 1 ; IS__CGSCC____: f: ; IS__CGSCC____-NEXT: store i8 1, i8* [[PTR]], align 1 @@ -616,7 +616,7 @@ define i8 @readnone_caller(i1 %c) { ; IS__CGSCC____-LABEL: define {{[^@]+}}@readnone_caller ; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR9:[0-9]+]] { ; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i8, align 1 -; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_not_readnone_internal(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[A]], i1 [[C]]) #[[ATTR12:[0-9]+]], !range [[RNG0]] +; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_not_readnone_internal(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[A]], i1 [[C]]) #[[ATTR13:[0-9]+]], !range [[RNG0]] ; IS__CGSCC____-NEXT: ret i8 [[R]] ; %a = alloca i8 @@ -624,26 +624,26 @@ define i8 @readnone_caller(i1 %c) { ret i8 %r } -define internal i8 @recursive_not_readnone_internal2(i8* %ptr, i1 %c) { -; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind writeonly -; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_not_readnone_internal2 -; IS__TUNIT____-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR8]] { +define internal i8 @recursive_readnone_internal2(i8* %ptr, i1 %c) { +; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone +; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_readnone_internal2 +; IS__TUNIT____-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR9]] { ; IS__TUNIT____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1 ; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] ; IS__TUNIT____: t: -; IS__TUNIT____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal2(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR10]], !range [[RNG0]] +; IS__TUNIT____-NEXT: [[TMP1:%.*]] = call i8 @recursive_readnone_internal2(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR9]], !range [[RNG0]] ; IS__TUNIT____-NEXT: ret i8 1 ; IS__TUNIT____: f: ; IS__TUNIT____-NEXT: store i8 1, i8* [[PTR]], align 1 ; IS__TUNIT____-NEXT: ret i8 0 ; -; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind writeonly -; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_not_readnone_internal2 -; IS__CGSCC____-SAME: (i8* nocapture nofree nonnull writeonly [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR8]] { +; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone willreturn +; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_readnone_internal2 +; IS__CGSCC____-SAME: (i8* noalias nocapture nofree nonnull readnone [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR10:[0-9]+]] { ; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1 ; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] ; IS__CGSCC____: t: -; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal2(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR11]], !range [[RNG0]] +; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_readnone_internal2(i8* noalias nocapture nofree noundef nonnull readnone dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR9]], !range [[RNG0]] ; IS__CGSCC____-NEXT: ret i8 1 ; IS__CGSCC____: f: ; IS__CGSCC____-NEXT: store i8 1, i8* [[PTR]], align 1 @@ -652,7 +652,7 @@ define internal i8 @recursive_not_readnone_internal2(i8* %ptr, i1 %c) { %alloc = alloca i8 br i1 %c, label %t, label %f t: - call i8 @recursive_not_readnone_internal2(i8* %alloc, i1 false) + call i8 @recursive_readnone_internal2(i8* %alloc, i1 false) %r = load i8, i8* %alloc ret i8 %r f: @@ -664,16 +664,72 @@ define i8 @readnone_caller2(i1 %c) { ; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone ; IS__TUNIT____-LABEL: define {{[^@]+}}@readnone_caller2 ; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR9]] { -; IS__TUNIT____-NEXT: [[R:%.*]] = call noundef i8 @recursive_not_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR10]], !range [[RNG0]] +; IS__TUNIT____-NEXT: [[R:%.*]] = call noundef i8 @recursive_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR9]], !range [[RNG0]] +; IS__TUNIT____-NEXT: ret i8 [[R]] +; +; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone willreturn +; IS__CGSCC____-LABEL: define {{[^@]+}}@readnone_caller2 +; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR10]] { +; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR14:[0-9]+]], !range [[RNG0]] +; IS__CGSCC____-NEXT: ret i8 [[R]] +; + %r = call i8 @recursive_readnone_internal2(i8* undef, i1 %c) + ret i8 %r +} + +define internal i8 @recursive_not_readnone_internal3(i8* %ptr, i1 %c) { +; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind writeonly +; IS__TUNIT____-LABEL: define {{[^@]+}}@recursive_not_readnone_internal3 +; IS__TUNIT____-SAME: (i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR8]] { +; IS__TUNIT____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1 +; IS__TUNIT____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] +; IS__TUNIT____: t: +; IS__TUNIT____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal3(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR10]], !range [[RNG0]] +; IS__TUNIT____-NEXT: ret i8 1 +; IS__TUNIT____: f: +; IS__TUNIT____-NEXT: store i8 1, i8* [[PTR]], align 1 +; IS__TUNIT____-NEXT: ret i8 0 +; +; IS__CGSCC____: Function Attrs: argmemonly nofree nosync nounwind writeonly +; IS__CGSCC____-LABEL: define {{[^@]+}}@recursive_not_readnone_internal3 +; IS__CGSCC____-SAME: (i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[PTR:%.*]], i1 [[C:%.*]]) #[[ATTR8]] { +; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1 +; IS__CGSCC____-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] +; IS__CGSCC____: t: +; IS__CGSCC____-NEXT: [[TMP1:%.*]] = call i8 @recursive_not_readnone_internal3(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 noundef false) #[[ATTR12]], !range [[RNG0]] +; IS__CGSCC____-NEXT: ret i8 1 +; IS__CGSCC____: f: +; IS__CGSCC____-NEXT: store i8 1, i8* [[PTR]], align 1 +; IS__CGSCC____-NEXT: ret i8 0 +; + %alloc = alloca i8 + br i1 %c, label %t, label %f +t: + call i8 @recursive_not_readnone_internal3(i8* %alloc, i1 false) + %r = load i8, i8* %alloc + ret i8 %r +f: + store i8 1, i8* %ptr + ret i8 0 +} + +define i8 @readnone_caller3(i1 %c) { +; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone +; IS__TUNIT____-LABEL: define {{[^@]+}}@readnone_caller3 +; IS__TUNIT____-SAME: (i1 [[C:%.*]]) #[[ATTR9]] { +; IS__TUNIT____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1 +; IS__TUNIT____-NEXT: [[R:%.*]] = call noundef i8 @recursive_not_readnone_internal3(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 [[C]]) #[[ATTR10]], !range [[RNG0]] ; IS__TUNIT____-NEXT: ret i8 [[R]] ; ; IS__CGSCC____: Function Attrs: nofree nosync nounwind readnone -; IS__CGSCC____-LABEL: define {{[^@]+}}@readnone_caller2 +; IS__CGSCC____-LABEL: define {{[^@]+}}@readnone_caller3 ; IS__CGSCC____-SAME: (i1 [[C:%.*]]) #[[ATTR9]] { -; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_not_readnone_internal2(i8* undef, i1 [[C]]) #[[ATTR12]], !range [[RNG0]] +; IS__CGSCC____-NEXT: [[ALLOC:%.*]] = alloca i8, align 1 +; IS__CGSCC____-NEXT: [[R:%.*]] = call noundef i8 @recursive_not_readnone_internal3(i8* noalias nocapture nofree noundef nonnull writeonly dereferenceable(1) [[ALLOC]], i1 [[C]]) #[[ATTR13]], !range [[RNG0]] ; IS__CGSCC____-NEXT: ret i8 [[R]] ; - %r = call i8 @recursive_not_readnone_internal2(i8* undef, i1 %c) + %alloc = alloca i8 + %r = call i8 @recursive_not_readnone_internal3(i8* %alloc, i1 %c) ret i8 %r } @@ -704,7 +760,7 @@ define void @argmemonky_caller() { ; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind willreturn writeonly ; IS__CGSCC____-LABEL: define {{[^@]+}}@argmemonky_caller ; IS__CGSCC____-SAME: () #[[ATTR6]] { -; IS__CGSCC____-NEXT: call void @argmemonly_before_ipconstprop() #[[ATTR10]] +; IS__CGSCC____-NEXT: call void @argmemonly_before_ipconstprop() #[[ATTR11]] ; IS__CGSCC____-NEXT: ret void ; call void @argmemonly_before_ipconstprop(i32* @G) @@ -733,9 +789,11 @@ define void @argmemonky_caller() { ; IS__CGSCC____: attributes #[[ATTR7]] = { argmemonly nofree norecurse nosync nounwind willreturn writeonly } ; IS__CGSCC____: attributes #[[ATTR8]] = { argmemonly nofree nosync nounwind writeonly } ; IS__CGSCC____: attributes #[[ATTR9]] = { nofree nosync nounwind readnone } -; IS__CGSCC____: attributes #[[ATTR10]] = { nounwind willreturn writeonly } -; IS__CGSCC____: attributes #[[ATTR11]] = { nofree nosync nounwind writeonly } -; IS__CGSCC____: attributes #[[ATTR12]] = { nounwind writeonly } +; IS__CGSCC____: attributes #[[ATTR10]] = { nofree nosync nounwind readnone willreturn } +; IS__CGSCC____: attributes #[[ATTR11]] = { nounwind willreturn writeonly } +; IS__CGSCC____: attributes #[[ATTR12]] = { nofree nosync nounwind writeonly } +; IS__CGSCC____: attributes #[[ATTR13]] = { nounwind writeonly } +; IS__CGSCC____: attributes #[[ATTR14]] = { nounwind readnone willreturn } ;. ; CHECK: [[META0:![0-9]+]] = !{i8 0, i8 2} ;. diff --git a/llvm/test/Transforms/Attributor/readattrs.ll b/llvm/test/Transforms/Attributor/readattrs.ll index ced99bf38a42..5d24e2507447 100644 --- a/llvm/test/Transforms/Attributor/readattrs.ll +++ b/llvm/test/Transforms/Attributor/readattrs.ll @@ -139,9 +139,9 @@ entry: } define void @test8_2(i32* %p) { -; IS__TUNIT____: Function Attrs: nofree nosync nounwind willreturn writeonly +; IS__TUNIT____: Function Attrs: argmemonly nofree nosync nounwind willreturn writeonly ; IS__TUNIT____-LABEL: define {{[^@]+}}@test8_2 -; IS__TUNIT____-SAME: (i32* nocapture nofree writeonly [[P:%.*]]) #[[ATTR0]] { +; IS__TUNIT____-SAME: (i32* nocapture nofree writeonly [[P:%.*]]) #[[ATTR3]] { ; IS__TUNIT____-NEXT: entry: ; IS__TUNIT____-NEXT: store i32 10, i32* [[P]], align 4 ; IS__TUNIT____-NEXT: ret void