1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes 2; RUN: opt -ipsccp -S %s | FileCheck %s 3 4; Test cases to ensure argmemonly/inaccessiblemem_or_argmemonly attributes are 5; dropped, if a function argument is replaced by a constant. 6; 7; PR46717 8 9@g = internal global i32 0 10 11; Here the pointer argument %arg will be replaced by a constant. We need to 12; drop argmemonly. 13define internal void @ptrarg.1(i32* %arg, i32 %val) argmemonly nounwind { 14; CHECK: Function Attrs: nounwind 15; CHECK-LABEL: @ptrarg.1( 16; CHECK-NEXT: store i32 10, i32* @g, align 4 17; CHECK-NEXT: ret void 18; 19 store i32 %val, i32* %arg 20 ret void 21} 22 23define i32 @caller.1(i32 %n) { 24; CHECK-LABEL: @caller.1( 25; CHECK-NEXT: store i32 1, i32* @g, align 4 26; CHECK-NEXT: tail call void @ptrarg.1(i32* @g, i32 10) 27; CHECK-NEXT: [[G_VAL:%.*]] = load i32, i32* @g, align 4 28; CHECK-NEXT: ret i32 [[G_VAL]] 29; 30 store i32 1, i32* @g 31 tail call void @ptrarg.1(i32* @g, i32 10) 32 %g.val = load i32, i32* @g 33 ret i32 %g.val 34} 35 36 37; Here only the non-pointer argument %val is replaced, no need 38; to drop the argmemonly attribute. 39define internal void @ptrarg.2(i32* %arg, i32 %val) argmemonly nounwind { 40; CHECK: Function Attrs: argmemonly nounwind 41; CHECK-LABEL: @ptrarg.2( 42; CHECK-NEXT: store i32 10, i32* [[ARG:%.*]], align 4 43; CHECK-NEXT: ret void 44; 45 store i32 %val, i32* %arg 46 ret void 47} 48 49define void @caller.2(i32* %ptr) { 50; CHECK-LABEL: @caller.2( 51; CHECK-NEXT: tail call void @ptrarg.2(i32* [[PTR:%.*]], i32 10) 52; CHECK-NEXT: ret void 53; 54 tail call void @ptrarg.2(i32* %ptr, i32 10) 55 ret void 56} 57 58 59; Here the pointer argument %arg will be replaced by a constant. We need to 60; drop inaccessiblemem_or_argmemonly. 61define internal void @ptrarg.3(i32* %arg, i32 %val) inaccessiblemem_or_argmemonly nounwind { 62; CHECK: Function Attrs: nounwind 63; CHECK-LABEL: @ptrarg.3( 64; CHECK-NEXT: store i32 10, i32* @g, align 4 65; CHECK-NEXT: ret void 66; 67 store i32 %val, i32* %arg 68 ret void 69} 70 71define i32 @caller.3(i32 %n) { 72; CHECK-LABEL: @caller.3( 73; CHECK-NEXT: store i32 1, i32* @g, align 4 74; CHECK-NEXT: tail call void @ptrarg.3(i32* @g, i32 10) 75; CHECK-NEXT: [[G_VAL:%.*]] = load i32, i32* @g, align 4 76; CHECK-NEXT: ret i32 [[G_VAL]] 77; 78 store i32 1, i32* @g 79 tail call void @ptrarg.3(i32* @g, i32 10) 80 %g.val = load i32, i32* @g 81 ret i32 %g.val 82} 83 84 85; Here only the non-pointer argument %val is replaced, no need 86; to drop the inaccessiblemem_or_argmemonly attribute. 87define internal void @ptrarg.4(i32* %arg, i32 %val) inaccessiblemem_or_argmemonly nounwind { 88; CHECK: Function Attrs: inaccessiblemem_or_argmemonly nounwind 89; CHECK-LABEL: @ptrarg.4( 90; CHECK-NEXT: store i32 10, i32* [[ARG:%.*]], align 4 91; CHECK-NEXT: ret void 92; 93 store i32 %val, i32* %arg 94 ret void 95} 96 97define void @caller.4(i32* %ptr) { 98; CHECK-LABEL: @caller.4( 99; CHECK-NEXT: tail call void @ptrarg.4(i32* [[PTR:%.*]], i32 10) 100; CHECK-NEXT: ret void 101; 102 tail call void @ptrarg.4(i32* %ptr, i32 10) 103 ret void 104} 105 106 107; Here the pointer argument %arg will be replaced by a constant. We need to 108; drop inaccessiblemem_or_argmemonly. 109define internal void @ptrarg.5(i32* %arg, i32 %val) argmemonly inaccessiblemem_or_argmemonly nounwind { 110; CHECK: Function Attrs: nounwind 111; CHECK-LABEL: @ptrarg.5( 112; CHECK-NEXT: store i32 10, i32* @g, align 4 113; CHECK-NEXT: ret void 114; 115 store i32 %val, i32* %arg 116 ret void 117} 118 119define i32 @caller.5(i32 %n) { 120; CHECK-LABEL: @caller.5( 121; CHECK-NEXT: store i32 1, i32* @g, align 4 122; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) 123; CHECK-NEXT: [[G_VAL:%.*]] = load i32, i32* @g, align 4 124; CHECK-NEXT: ret i32 [[G_VAL]] 125; 126 store i32 1, i32* @g 127 tail call void @ptrarg.5(i32* @g, i32 10) 128 %g.val = load i32, i32* @g 129 ret i32 %g.val 130} 131 132 133; Make sure callsite attributes are also dropped when a pointer argument is 134; replaced. 135define internal void @ptrarg.6.cs.attributes(i32* %arg, i32 %val) { 136; CHECK-LABEL: @ptrarg.6.cs.attributes( 137; CHECK-NEXT: unreachable 138; 139 store i32 %val, i32* %arg 140 ret void 141} 142 143define i32 @caller.6.cs.attributes(i32 %n) { 144; CHECK-LABEL: @caller.6.cs.attributes( 145; CHECK-NEXT: store i32 1, i32* @g, align 4 146; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) [[NOUNWIND:#[0-9]+]] 147; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) [[NOUNWIND:#[0-9]+]] 148; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) [[NOUNWIND:#[0-9]+]] 149; CHECK-NEXT: tail call void @ptrarg.5(i32* @g, i32 10) [[NOUNWIND:#[0-9]+]] 150; CHECK-NEXT: [[G_VAL:%.*]] = load i32, i32* @g, align 4 151; CHECK-NEXT: ret i32 [[G_VAL]] 152; 153 store i32 1, i32* @g 154 tail call void @ptrarg.5(i32* @g, i32 10) argmemonly inaccessiblemem_or_argmemonly nounwind 155 tail call void @ptrarg.5(i32* @g, i32 10) inaccessiblemem_or_argmemonly nounwind 156 tail call void @ptrarg.5(i32* @g, i32 10) argmemonly nounwind 157 tail call void @ptrarg.5(i32* @g, i32 10) nounwind 158 %g.val = load i32, i32* @g 159 ret i32 %g.val 160} 161 162; CHECK: [[NOUNWIND]] = { nounwind } 163