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