1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --scrub-attributes 2; RUN: opt -attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=10 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_NPM,NOT_CGSCC_OPM,NOT_TUNIT_NPM,IS__TUNIT____,IS________OPM,IS__TUNIT_OPM 3; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-max-iterations-verify -attributor-annotate-decl-cs -attributor-max-iterations=10 -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_CGSCC_OPM,NOT_CGSCC_NPM,NOT_TUNIT_OPM,IS__TUNIT____,IS________NPM,IS__TUNIT_NPM 4; RUN: opt -attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_NPM,IS__CGSCC____,IS________OPM,IS__CGSCC_OPM 5; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,NOT_TUNIT_NPM,NOT_TUNIT_OPM,NOT_CGSCC_OPM,IS__CGSCC____,IS________NPM,IS__CGSCC_NPM 6; 7; Test cases specifically designed for the "no-capture" argument attribute. 8; We use FIXME's to indicate problems and missing attributes. 9; 10target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 11declare i32* @unknown() 12 13; TEST comparison against NULL 14; 15; int is_null_return(int *p) { 16; return p == 0; 17; } 18; 19; no-capture is missing on %p because it is not dereferenceable 20define i32 @is_null_return(i32* %p) #0 { 21; CHECK-LABEL: define {{[^@]+}}@is_null_return 22; CHECK-SAME: (i32* nofree readnone [[P:%.*]]) 23; CHECK-NEXT: entry: 24; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[P]], null 25; CHECK-NEXT: [[CONV:%.*]] = zext i1 [[CMP]] to i32 26; CHECK-NEXT: ret i32 [[CONV]] 27; 28entry: 29 %cmp = icmp eq i32* %p, null 30 %conv = zext i1 %cmp to i32 31 ret i32 %conv 32} 33 34; TEST comparison against NULL in control flow 35; 36; int is_null_control(int *p) { 37; if (p == 0) 38; return 1; 39; if (0 == p) 40; return 1; 41; return 0; 42; } 43; 44; no-capture is missing on %p because it is not dereferenceable 45define i32 @is_null_control(i32* %p) #0 { 46; CHECK-LABEL: define {{[^@]+}}@is_null_control 47; CHECK-SAME: (i32* nofree [[P:%.*]]) 48; CHECK-NEXT: entry: 49; CHECK-NEXT: [[RETVAL:%.*]] = alloca i32, align 4 50; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[P]], null 51; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 52; CHECK: if.then: 53; CHECK-NEXT: store i32 1, i32* [[RETVAL]], align 4 54; CHECK-NEXT: br label [[RETURN:%.*]] 55; CHECK: if.end: 56; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32* null, [[P]] 57; CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[IF_END3:%.*]] 58; CHECK: if.then2: 59; CHECK-NEXT: store i32 1, i32* [[RETVAL]], align 4 60; CHECK-NEXT: br label [[RETURN]] 61; CHECK: if.end3: 62; CHECK-NEXT: store i32 0, i32* [[RETVAL]], align 4 63; CHECK-NEXT: br label [[RETURN]] 64; CHECK: return: 65; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[RETVAL]], align 4 66; CHECK-NEXT: ret i32 [[TMP0]] 67; 68entry: 69 %retval = alloca i32, align 4 70 %cmp = icmp eq i32* %p, null 71 br i1 %cmp, label %if.then, label %if.end 72 73if.then: ; preds = %entry 74 store i32 1, i32* %retval, align 4 75 br label %return 76 77if.end: ; preds = %entry 78 %cmp1 = icmp eq i32* null, %p 79 br i1 %cmp1, label %if.then2, label %if.end3 80 81if.then2: ; preds = %if.end 82 store i32 1, i32* %retval, align 4 83 br label %return 84 85if.end3: ; preds = %if.end 86 store i32 0, i32* %retval, align 4 87 br label %return 88 89return: ; preds = %if.end3, %if.then2, %if.then 90 %0 = load i32, i32* %retval, align 4 91 ret i32 %0 92} 93 94; TEST singleton SCC 95; 96; double *srec0(double *a) { 97; srec0(a); 98; return 0; 99; } 100; 101define double* @srec0(double* %a) #0 { 102; CHECK-LABEL: define {{[^@]+}}@srec0 103; CHECK-SAME: (double* nocapture nofree readnone [[A:%.*]]) 104; CHECK-NEXT: entry: 105; CHECK-NEXT: unreachable 106; 107entry: 108 %call = call double* @srec0(double* %a) 109 ret double* null 110} 111 112; TEST singleton SCC with lots of nested recursive calls 113; 114; int* srec16(int* a) { 115; return srec16(srec16(srec16(srec16( 116; srec16(srec16(srec16(srec16( 117; srec16(srec16(srec16(srec16( 118; srec16(srec16(srec16(srec16( 119; a 120; )))))))))))))))); 121; } 122; 123; Other arguments are possible here due to the no-return behavior. 124; 125define i32* @srec16(i32* %a) #0 { 126; CHECK-LABEL: define {{[^@]+}}@srec16 127; CHECK-SAME: (i32* nocapture nofree readnone [[A:%.*]]) 128; CHECK-NEXT: entry: 129; CHECK-NEXT: unreachable 130; 131entry: 132 %call = call i32* @srec16(i32* %a) 133 %call1 = call i32* @srec16(i32* %call) 134 %call2 = call i32* @srec16(i32* %call1) 135 %call3 = call i32* @srec16(i32* %call2) 136 %call4 = call i32* @srec16(i32* %call3) 137 %call5 = call i32* @srec16(i32* %call4) 138 %call6 = call i32* @srec16(i32* %call5) 139 %call7 = call i32* @srec16(i32* %call6) 140 %call8 = call i32* @srec16(i32* %call7) 141 %call9 = call i32* @srec16(i32* %call8) 142 %call10 = call i32* @srec16(i32* %call9) 143 %call11 = call i32* @srec16(i32* %call10) 144 %call12 = call i32* @srec16(i32* %call11) 145 %call13 = call i32* @srec16(i32* %call12) 146 %call14 = call i32* @srec16(i32* %call13) 147 %call15 = call i32* @srec16(i32* %call14) 148 ret i32* %call15 149} 150 151; TEST SCC with various calls, casts, and comparisons agains NULL 152; 153; float *scc_A(int *a) { 154; return (float*)(a ? (int*)scc_A((int*)scc_B((double*)scc_C((short*)a))) : a); 155; } 156; 157; long *scc_B(double *a) { 158; return (long*)(a ? scc_C((short*)scc_B((double*)scc_A((int*)a))) : a); 159; } 160; 161; void *scc_C(short *a) { 162; return scc_A((int*)(scc_A(a) ? scc_B((double*)a) : scc_C(a))); 163; } 164define float* @scc_A(i32* dereferenceable_or_null(4) %a) { 165; CHECK-LABEL: define {{[^@]+}}@scc_A 166; CHECK-SAME: (i32* nofree readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" [[A:%.*]]) 167; CHECK-NEXT: entry: 168; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32* [[A]], null 169; CHECK-NEXT: br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] 170; CHECK: cond.true: 171; CHECK-NEXT: [[TMP0:%.*]] = bitcast i32* [[A]] to i16* 172; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(4) i8* @scc_C(i16* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP0]]) 173; CHECK-NEXT: [[TMP1:%.*]] = bitcast i8* [[CALL]] to double* 174; CHECK-NEXT: [[CALL1:%.*]] = call dereferenceable_or_null(8) i64* @scc_B(double* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1]]) 175; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64* [[CALL1]] to i32* 176; CHECK-NEXT: [[CALL2:%.*]] = call float* @scc_A(i32* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP2]]) 177; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[CALL2]] to i32* 178; CHECK-NEXT: br label [[COND_END:%.*]] 179; CHECK: cond.false: 180; CHECK-NEXT: br label [[COND_END]] 181; CHECK: cond.end: 182; CHECK-NEXT: [[COND:%.*]] = phi i32* [ [[TMP3]], [[COND_TRUE]] ], [ [[A]], [[COND_FALSE]] ] 183; CHECK-NEXT: [[TMP4:%.*]] = bitcast i32* [[COND]] to float* 184; CHECK-NEXT: ret float* [[TMP4]] 185; 186entry: 187 %tobool = icmp ne i32* %a, null 188 br i1 %tobool, label %cond.true, label %cond.false 189 190cond.true: ; preds = %entry 191 %0 = bitcast i32* %a to i16* 192 %call = call i8* @scc_C(i16* %0) 193 %1 = bitcast i8* %call to double* 194 %call1 = call i64* @scc_B(double* %1) 195 %2 = bitcast i64* %call1 to i32* 196 %call2 = call float* @scc_A(i32* %2) 197 %3 = bitcast float* %call2 to i32* 198 br label %cond.end 199 200cond.false: ; preds = %entry 201 br label %cond.end 202 203cond.end: ; preds = %cond.false, %cond.true 204 %cond = phi i32* [ %3, %cond.true ], [ %a, %cond.false ] 205 %4 = bitcast i32* %cond to float* 206 ret float* %4 207} 208 209define i64* @scc_B(double* dereferenceable_or_null(8) %a) { 210; CHECK-LABEL: define {{[^@]+}}@scc_B 211; CHECK-SAME: (double* nofree readnone returned dereferenceable_or_null(8) "no-capture-maybe-returned" [[A:%.*]]) 212; CHECK-NEXT: entry: 213; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne double* [[A]], null 214; CHECK-NEXT: br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] 215; CHECK: cond.true: 216; CHECK-NEXT: [[TMP0:%.*]] = bitcast double* [[A]] to i32* 217; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(4) float* @scc_A(i32* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0]]) 218; CHECK-NEXT: [[TMP1:%.*]] = bitcast float* [[CALL]] to double* 219; CHECK-NEXT: [[CALL1:%.*]] = call dereferenceable_or_null(8) i64* @scc_B(double* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP1]]) 220; CHECK-NEXT: [[TMP2:%.*]] = bitcast i64* [[CALL1]] to i16* 221; CHECK-NEXT: [[CALL2:%.*]] = call i8* @scc_C(i16* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP2]]) 222; CHECK-NEXT: br label [[COND_END:%.*]] 223; CHECK: cond.false: 224; CHECK-NEXT: [[TMP3:%.*]] = bitcast double* [[A]] to i8* 225; CHECK-NEXT: br label [[COND_END]] 226; CHECK: cond.end: 227; CHECK-NEXT: [[COND:%.*]] = phi i8* [ [[CALL2]], [[COND_TRUE]] ], [ [[TMP3]], [[COND_FALSE]] ] 228; CHECK-NEXT: [[TMP4:%.*]] = bitcast i8* [[COND]] to i64* 229; CHECK-NEXT: ret i64* [[TMP4]] 230; 231entry: 232 %tobool = icmp ne double* %a, null 233 br i1 %tobool, label %cond.true, label %cond.false 234 235cond.true: ; preds = %entry 236 %0 = bitcast double* %a to i32* 237 %call = call float* @scc_A(i32* %0) 238 %1 = bitcast float* %call to double* 239 %call1 = call i64* @scc_B(double* %1) 240 %2 = bitcast i64* %call1 to i16* 241 %call2 = call i8* @scc_C(i16* %2) 242 br label %cond.end 243 244cond.false: ; preds = %entry 245 %3 = bitcast double* %a to i8* 246 br label %cond.end 247 248cond.end: ; preds = %cond.false, %cond.true 249 %cond = phi i8* [ %call2, %cond.true ], [ %3, %cond.false ] 250 %4 = bitcast i8* %cond to i64* 251 ret i64* %4 252} 253 254define i8* @scc_C(i16* dereferenceable_or_null(2) %a) { 255; CHECK-LABEL: define {{[^@]+}}@scc_C 256; CHECK-SAME: (i16* nofree readnone returned dereferenceable_or_null(4) "no-capture-maybe-returned" [[A:%.*]]) 257; CHECK-NEXT: entry: 258; CHECK-NEXT: [[BC:%.*]] = bitcast i16* [[A]] to i32* 259; CHECK-NEXT: [[CALL:%.*]] = call dereferenceable_or_null(4) float* @scc_A(i32* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[BC]]) 260; CHECK-NEXT: [[BC2:%.*]] = bitcast float* [[CALL]] to i8* 261; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8* [[BC2]], null 262; CHECK-NEXT: br i1 [[TOBOOL]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] 263; CHECK: cond.true: 264; CHECK-NEXT: [[TMP0:%.*]] = bitcast i16* [[A]] to double* 265; CHECK-NEXT: [[CALL1:%.*]] = call dereferenceable_or_null(8) i64* @scc_B(double* noalias nofree nonnull readnone dereferenceable(8) "no-capture-maybe-returned" [[TMP0]]) 266; CHECK-NEXT: [[TMP1:%.*]] = bitcast i64* [[CALL1]] to i8* 267; CHECK-NEXT: br label [[COND_END:%.*]] 268; CHECK: cond.false: 269; CHECK-NEXT: [[CALL2:%.*]] = call dereferenceable_or_null(4) i8* @scc_C(i16* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[A]]) 270; CHECK-NEXT: br label [[COND_END]] 271; CHECK: cond.end: 272; CHECK-NEXT: [[COND:%.*]] = phi i8* [ [[TMP1]], [[COND_TRUE]] ], [ [[CALL2]], [[COND_FALSE]] ] 273; CHECK-NEXT: [[TMP2:%.*]] = bitcast i8* [[COND]] to i32* 274; CHECK-NEXT: [[CALL3:%.*]] = call float* @scc_A(i32* noalias nofree nonnull readnone dereferenceable(4) "no-capture-maybe-returned" [[TMP2]]) 275; CHECK-NEXT: [[TMP3:%.*]] = bitcast float* [[CALL3]] to i8* 276; CHECK-NEXT: ret i8* [[TMP3]] 277; 278entry: 279 %bc = bitcast i16* %a to i32* 280 %call = call float* @scc_A(i32* %bc) 281 %bc2 = bitcast float* %call to i8* 282 %tobool = icmp ne i8* %bc2, null 283 br i1 %tobool, label %cond.true, label %cond.false 284 285cond.true: ; preds = %entry 286 %0 = bitcast i16* %a to double* 287 %call1 = call i64* @scc_B(double* %0) 288 %1 = bitcast i64* %call1 to i8* 289 br label %cond.end 290 291cond.false: ; preds = %entry 292 %call2 = call i8* @scc_C(i16* %a) 293 br label %cond.end 294 295cond.end: ; preds = %cond.false, %cond.true 296 %cond = phi i8* [ %1, %cond.true ], [ %call2, %cond.false ] 297 %2 = bitcast i8* %cond to i32* 298 %call3 = call float* @scc_A(i32* %2) 299 %3 = bitcast float* %call3 to i8* 300 ret i8* %3 301} 302 303 304; TEST call to external function, marked no-capture 305; 306; void external_no_capture(int /* no-capture */ *p); 307; void test_external_no_capture(int *p) { 308; external_no_capture(p); 309; } 310; 311declare void @external_no_capture(i32* nocapture) 312 313define void @test_external_no_capture(i32* %p) #0 { 314; CHECK-LABEL: define {{[^@]+}}@test_external_no_capture 315; CHECK-SAME: (i32* nocapture [[P:%.*]]) 316; CHECK-NEXT: entry: 317; CHECK-NEXT: call void @external_no_capture(i32* nocapture [[P]]) 318; CHECK-NEXT: ret void 319; 320entry: 321 call void @external_no_capture(i32* %p) 322 ret void 323} 324 325; TEST call to external var-args function, marked no-capture 326; 327; void test_var_arg_call(char *p, int a) { 328; printf(p, a); 329; } 330; 331define void @test_var_arg_call(i8* %p, i32 %a) #0 { 332; CHECK-LABEL: define {{[^@]+}}@test_var_arg_call 333; CHECK-SAME: (i8* nocapture [[P:%.*]], i32 [[A:%.*]]) 334; CHECK-NEXT: entry: 335; CHECK-NEXT: [[CALL:%.*]] = call i32 (i8*, ...) @printf(i8* nocapture [[P]], i32 [[A]]) 336; CHECK-NEXT: ret void 337; 338entry: 339 %call = call i32 (i8*, ...) @printf(i8* %p, i32 %a) 340 ret void 341} 342 343declare i32 @printf(i8* nocapture, ...) 344 345 346; TEST "captured" only through return 347; 348; long *not_captured_but_returned_0(long *a) { 349; *a1 = 0; 350; return a; 351; } 352; 353; There should *not* be a no-capture attribute on %a 354define i64* @not_captured_but_returned_0(i64* %a) #0 { 355; CHECK-LABEL: define {{[^@]+}}@not_captured_but_returned_0 356; CHECK-SAME: (i64* nofree nonnull returned writeonly align 8 dereferenceable(8) "no-capture-maybe-returned" [[A:%.*]]) 357; CHECK-NEXT: entry: 358; CHECK-NEXT: store i64 0, i64* [[A]], align 8 359; CHECK-NEXT: ret i64* [[A]] 360; 361entry: 362 store i64 0, i64* %a, align 8 363 ret i64* %a 364} 365 366; TEST "captured" only through return 367; 368; long *not_captured_but_returned_1(long *a) { 369; *(a+1) = 1; 370; return a + 1; 371; } 372; 373; There should *not* be a no-capture attribute on %a 374define i64* @not_captured_but_returned_1(i64* %a) #0 { 375; CHECK-LABEL: define {{[^@]+}}@not_captured_but_returned_1 376; CHECK-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(16) "no-capture-maybe-returned" [[A:%.*]]) 377; CHECK-NEXT: entry: 378; CHECK-NEXT: [[ADD_PTR:%.*]] = getelementptr inbounds i64, i64* [[A]], i64 1 379; CHECK-NEXT: store i64 1, i64* [[ADD_PTR]], align 8 380; CHECK-NEXT: ret i64* [[ADD_PTR]] 381; 382entry: 383 %add.ptr = getelementptr inbounds i64, i64* %a, i64 1 384 store i64 1, i64* %add.ptr, align 8 385 ret i64* %add.ptr 386} 387 388; TEST calls to "captured" only through return functions 389; 390; void test_not_captured_but_returned_calls(long *a) { 391; not_captured_but_returned_0(a); 392; not_captured_but_returned_1(a); 393; } 394; 395define void @test_not_captured_but_returned_calls(i64* %a) #0 { 396; IS__TUNIT____-LABEL: define {{[^@]+}}@test_not_captured_but_returned_calls 397; IS__TUNIT____-SAME: (i64* nocapture nofree writeonly align 8 [[A:%.*]]) 398; IS__TUNIT____-NEXT: entry: 399; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) 400; IS__TUNIT____-NEXT: [[CALL1:%.*]] = call i64* @not_captured_but_returned_1(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) 401; IS__TUNIT____-NEXT: ret void 402; 403; IS__CGSCC____-LABEL: define {{[^@]+}}@test_not_captured_but_returned_calls 404; IS__CGSCC____-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) 405; IS__CGSCC____-NEXT: entry: 406; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A]]) 407; IS__CGSCC____-NEXT: [[CALL1:%.*]] = call i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A]]) 408; IS__CGSCC____-NEXT: ret void 409; 410entry: 411 %call = call i64* @not_captured_but_returned_0(i64* %a) 412 %call1 = call i64* @not_captured_but_returned_1(i64* %a) 413 ret void 414} 415 416; TEST "captured" only through transitive return 417; 418; long* negative_test_not_captured_but_returned_call_0a(long *a) { 419; return not_captured_but_returned_0(a); 420; } 421; 422; There should *not* be a no-capture attribute on %a 423define i64* @negative_test_not_captured_but_returned_call_0a(i64* %a) #0 { 424; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0a 425; IS__TUNIT____-SAME: (i64* nofree returned writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) 426; IS__TUNIT____-NEXT: entry: 427; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) 428; IS__TUNIT____-NEXT: ret i64* [[CALL]] 429; 430; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0a 431; IS__CGSCC____-SAME: (i64* nofree nonnull returned writeonly align 8 dereferenceable(8) [[A:%.*]]) 432; IS__CGSCC____-NEXT: entry: 433; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree nonnull writeonly align 8 dereferenceable(8) [[A]]) 434; IS__CGSCC____-NEXT: ret i64* [[CALL]] 435; 436entry: 437 %call = call i64* @not_captured_but_returned_0(i64* %a) 438 ret i64* %call 439} 440 441; TEST captured through write 442; 443; void negative_test_not_captured_but_returned_call_0b(long *a) { 444; *a = (long)not_captured_but_returned_0(a); 445; } 446; 447; There should *not* be a no-capture attribute on %a 448define void @negative_test_not_captured_but_returned_call_0b(i64* %a) #0 { 449; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0b 450; IS__TUNIT____-SAME: (i64* nofree writeonly align 8 [[A:%.*]]) 451; IS__TUNIT____-NEXT: entry: 452; IS__TUNIT____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) 453; IS__TUNIT____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[CALL]] to i64 454; IS__TUNIT____-NEXT: store i64 [[TMP0]], i64* [[A]], align 8 455; IS__TUNIT____-NEXT: ret void 456; 457; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_0b 458; IS__CGSCC____-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(8) [[A:%.*]]) 459; IS__CGSCC____-NEXT: entry: 460; IS__CGSCC____-NEXT: [[CALL:%.*]] = call i64* @not_captured_but_returned_0(i64* nofree nonnull writeonly align 8 dereferenceable(8) [[A]]) 461; IS__CGSCC____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[CALL]] to i64 462; IS__CGSCC____-NEXT: store i64 [[TMP0]], i64* [[A]], align 8 463; IS__CGSCC____-NEXT: ret void 464; 465entry: 466 %call = call i64* @not_captured_but_returned_0(i64* %a) 467 %0 = ptrtoint i64* %call to i64 468 store i64 %0, i64* %a, align 8 469 ret void 470} 471 472; TEST "captured" only through transitive return 473; 474; long* negative_test_not_captured_but_returned_call_1a(long *a) { 475; return not_captured_but_returned_1(a); 476; } 477; 478; There should *not* be a no-capture attribute on %a 479define i64* @negative_test_not_captured_but_returned_call_1a(i64* %a) #0 { 480; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1a 481; IS__TUNIT____-SAME: (i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A:%.*]]) 482; IS__TUNIT____-NEXT: entry: 483; IS__TUNIT____-NEXT: [[CALL:%.*]] = call nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) 484; IS__TUNIT____-NEXT: ret i64* [[CALL]] 485; 486; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1a 487; IS__CGSCC____-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) 488; IS__CGSCC____-NEXT: entry: 489; IS__CGSCC____-NEXT: [[CALL:%.*]] = call nonnull align 8 dereferenceable(8) i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A]]) 490; IS__CGSCC____-NEXT: ret i64* [[CALL]] 491; 492entry: 493 %call = call i64* @not_captured_but_returned_1(i64* %a) 494 ret i64* %call 495} 496 497; TEST captured through write 498; 499; void negative_test_not_captured_but_returned_call_1b(long *a) { 500; *a = (long)not_captured_but_returned_1(a); 501; } 502; 503; There should *not* be a no-capture attribute on %a 504define void @negative_test_not_captured_but_returned_call_1b(i64* %a) #0 { 505; IS__TUNIT____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1b 506; IS__TUNIT____-SAME: (i64* nofree writeonly align 8 [[A:%.*]]) 507; IS__TUNIT____-NEXT: entry: 508; IS__TUNIT____-NEXT: [[CALL:%.*]] = call align 8 i64* @not_captured_but_returned_1(i64* nofree writeonly align 8 "no-capture-maybe-returned" [[A]]) 509; IS__TUNIT____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[CALL]] to i64 510; IS__TUNIT____-NEXT: store i64 [[TMP0]], i64* [[CALL]], align 8 511; IS__TUNIT____-NEXT: ret void 512; 513; IS__CGSCC____-LABEL: define {{[^@]+}}@negative_test_not_captured_but_returned_call_1b 514; IS__CGSCC____-SAME: (i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A:%.*]]) 515; IS__CGSCC____-NEXT: entry: 516; IS__CGSCC____-NEXT: [[CALL:%.*]] = call align 8 i64* @not_captured_but_returned_1(i64* nofree nonnull writeonly align 8 dereferenceable(16) [[A]]) 517; IS__CGSCC____-NEXT: [[TMP0:%.*]] = ptrtoint i64* [[CALL]] to i64 518; IS__CGSCC____-NEXT: store i64 [[TMP0]], i64* [[CALL]], align 8 519; IS__CGSCC____-NEXT: ret void 520; 521entry: 522 %call = call i64* @not_captured_but_returned_1(i64* %a) 523 %0 = ptrtoint i64* %call to i64 524 store i64 %0, i64* %call, align 8 525 ret void 526} 527 528; TEST return argument or unknown call result 529; 530; int* ret_arg_or_unknown(int* b) { 531; if (b == 0) 532; return b; 533; return unknown(); 534; } 535; 536; Verify we do *not* assume b is returned or not captured. 537; 538 539define i32* @ret_arg_or_unknown(i32* %b) #0 { 540; CHECK-LABEL: define {{[^@]+}}@ret_arg_or_unknown 541; CHECK-SAME: (i32* [[B:%.*]]) 542; CHECK-NEXT: entry: 543; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[B]], null 544; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]] 545; CHECK: ret_arg: 546; CHECK-NEXT: ret i32* [[B]] 547; CHECK: ret_unknown: 548; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown() 549; CHECK-NEXT: ret i32* [[CALL]] 550; 551entry: 552 %cmp = icmp eq i32* %b, null 553 br i1 %cmp, label %ret_arg, label %ret_unknown 554 555ret_arg: 556 ret i32* %b 557 558ret_unknown: 559 %call = call i32* @unknown() 560 ret i32* %call 561} 562 563define i32* @ret_arg_or_unknown_through_phi(i32* %b) #0 { 564; CHECK-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi 565; CHECK-SAME: (i32* [[B:%.*]]) 566; CHECK-NEXT: entry: 567; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32* [[B]], null 568; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]] 569; CHECK: ret_arg: 570; CHECK-NEXT: br label [[R:%.*]] 571; CHECK: ret_unknown: 572; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown() 573; CHECK-NEXT: br label [[R]] 574; CHECK: r: 575; CHECK-NEXT: [[PHI:%.*]] = phi i32* [ [[B]], [[RET_ARG]] ], [ [[CALL]], [[RET_UNKNOWN]] ] 576; CHECK-NEXT: ret i32* [[PHI]] 577; 578entry: 579 %cmp = icmp eq i32* %b, null 580 br i1 %cmp, label %ret_arg, label %ret_unknown 581 582ret_arg: 583 br label %r 584 585ret_unknown: 586 %call = call i32* @unknown() 587 br label %r 588 589r: 590 %phi = phi i32* [ %b, %ret_arg ], [ %call, %ret_unknown ] 591 ret i32* %phi 592} 593 594 595; TEST not captured by readonly external function 596; 597declare i32* @readonly_unknown(i32*, i32*) readonly 598 599define void @not_captured_by_readonly_call(i32* %b) #0 { 600; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call 601; CHECK-SAME: (i32* nocapture readonly [[B:%.*]]) 602; CHECK-NEXT: entry: 603; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown(i32* readonly [[B]], i32* readonly [[B]]) 604; CHECK-NEXT: ret void 605; 606entry: 607 %call = call i32* @readonly_unknown(i32* %b, i32* %b) 608 ret void 609} 610 611 612; TEST not captured by readonly external function if return chain is known 613; 614; Make sure the returned flag on %r is strong enough to justify nocapture on %b but **not** on %r. 615; 616define i32* @not_captured_by_readonly_call_not_returned_either1(i32* %b, i32* returned %r) { 617; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either1 618; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]]) 619; CHECK-NEXT: entry: 620; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown(i32* readonly [[B]], i32* readonly [[R]]) 621; CHECK-NEXT: ret i32* [[CALL]] 622; 623entry: 624 %call = call i32* @readonly_unknown(i32* %b, i32* %r) nounwind 625 ret i32* %call 626} 627 628declare i32* @readonly_unknown_r1a(i32*, i32* returned) readonly 629define i32* @not_captured_by_readonly_call_not_returned_either2(i32* %b, i32* %r) { 630; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either2 631; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]]) 632; CHECK-NEXT: entry: 633; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1a(i32* readonly [[B]], i32* readonly [[R]]) 634; CHECK-NEXT: ret i32* [[CALL]] 635; 636entry: 637 %call = call i32* @readonly_unknown_r1a(i32* %b, i32* %r) nounwind 638 ret i32* %call 639} 640 641declare i32* @readonly_unknown_r1b(i32*, i32* returned) readonly nounwind 642define i32* @not_captured_by_readonly_call_not_returned_either3(i32* %b, i32* %r) { 643; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either3 644; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]]) 645; CHECK-NEXT: entry: 646; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1b(i32* nocapture readonly [[B]], i32* readonly [[R]]) 647; CHECK-NEXT: ret i32* [[CALL]] 648; 649entry: 650 %call = call i32* @readonly_unknown_r1b(i32* %b, i32* %r) 651 ret i32* %call 652} 653 654define i32* @not_captured_by_readonly_call_not_returned_either4(i32* %b, i32* %r) nounwind { 655; CHECK-LABEL: define {{[^@]+}}@not_captured_by_readonly_call_not_returned_either4 656; CHECK-SAME: (i32* nocapture readonly [[B:%.*]], i32* readonly returned [[R:%.*]]) 657; CHECK-NEXT: entry: 658; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_unknown_r1a(i32* readonly [[B]], i32* readonly [[R]]) 659; CHECK-NEXT: ret i32* [[CALL]] 660; 661entry: 662 %call = call i32* @readonly_unknown_r1a(i32* %b, i32* %r) 663 ret i32* %call 664} 665 666 667declare i32* @unknown_i32p(i32*) 668define void @nocapture_is_not_subsumed_1(i32* nocapture %b) { 669; CHECK-LABEL: define {{[^@]+}}@nocapture_is_not_subsumed_1 670; CHECK-SAME: (i32* nocapture [[B:%.*]]) 671; CHECK-NEXT: entry: 672; CHECK-NEXT: [[CALL:%.*]] = call i32* @unknown_i32p(i32* [[B]]) 673; CHECK-NEXT: store i32 0, i32* [[CALL]], align 4 674; CHECK-NEXT: ret void 675; 676entry: 677 %call = call i32* @unknown_i32p(i32* %b) 678 store i32 0, i32* %call 679 ret void 680} 681 682declare i32* @readonly_i32p(i32*) readonly 683define void @nocapture_is_not_subsumed_2(i32* nocapture %b) { 684; CHECK-LABEL: define {{[^@]+}}@nocapture_is_not_subsumed_2 685; CHECK-SAME: (i32* nocapture [[B:%.*]]) 686; CHECK-NEXT: entry: 687; CHECK-NEXT: [[CALL:%.*]] = call i32* @readonly_i32p(i32* readonly [[B]]) 688; CHECK-NEXT: store i32 0, i32* [[CALL]], align 4 689; CHECK-NEXT: ret void 690; 691entry: 692 %call = call i32* @readonly_i32p(i32* %b) 693 store i32 0, i32* %call 694 ret void 695} 696 697attributes #0 = { noinline nounwind uwtable } 698