1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --function-signature --check-attributes --check-globals 2; RUN: opt -aa-pipeline=basic-aa -passes=attributor -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,TUNIT 3; RUN: opt -aa-pipeline=basic-aa -passes=attributor-cgscc -attributor-manifest-internal -attributor-annotate-decl-cs -S < %s | FileCheck %s --check-prefixes=CHECK,CGSCC 4; 5; Test cases specifically designed for the "returned" argument attribute. 6; We use FIXME's to indicate problems and missing attributes. 7; 8 9; TEST SCC test returning an integer value argument 10; 11; int scc_r1(int a, int b, int r); 12; int scc_r2(int a, int b, int r); 13; 14; __attribute__((noinline)) int sink_r0(int r) { 15; return r; 16; } 17; 18; __attribute__((noinline)) int scc_r1(int a, int r, int b) { 19; return scc_r2(r, a, sink_r0(r)); 20; } 21; 22; __attribute__((noinline)) int scc_r2(int a, int b, int r) { 23; if (a > b) 24; return scc_r2(b, a, sink_r0(r)); 25; if (a < b) 26; return scc_r1(sink_r0(b), scc_r2(scc_r1(a, b, r), scc_r1(a, scc_r2(r, r, r), r), scc_r2(a, b, r)), scc_r1(a, b, r)); 27; return a == b ? r : scc_r2(a, b, r); 28; } 29; __attribute__((noinline)) int scc_rX(int a, int b, int r) { 30; if (a > b) 31; return scc_r2(b, a, sink_r0(r)); 32; if (a < b) // V Diff to scc_r2 33; return scc_r1(sink_r0(b), scc_r2(scc_r1(a, b, r), scc_r1(a, scc_r2(r, r, r), r), scc_r1(a, b, r)), scc_r1(a, b, r)); 34; return a == b ? r : scc_r2(a, b, r); 35; } 36target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" 37 38;. 39; CHECK: @G = external global i8 40; CHECK: @_ZTI1X = external dso_local constant { ptr, ptr }, align 8 41; CHECK: @_ZTI1Y = external dso_local constant { ptr, ptr, ptr }, align 8 42;. 43define i32 @sink_r0(i32 %r) #0 { 44; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 45; CHECK-LABEL: define {{[^@]+}}@sink_r0 46; CHECK-SAME: (i32 returned [[R:%.*]]) #[[ATTR0:[0-9]+]] { 47; CHECK-NEXT: entry: 48; CHECK-NEXT: ret i32 [[R]] 49; 50entry: 51 ret i32 %r 52} 53 54define i32 @scc_r1(i32 %a, i32 %r, i32 %b) #0 { 55; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 56; TUNIT-LABEL: define {{[^@]+}}@scc_r1 57; TUNIT-SAME: (i32 [[A:%.*]], i32 returned [[R:%.*]], i32 [[B:%.*]]) #[[ATTR1:[0-9]+]] { 58; TUNIT-NEXT: entry: 59; TUNIT-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[A]], i32 [[R]]) #[[ATTR8:[0-9]+]] 60; TUNIT-NEXT: ret i32 [[R]] 61; 62; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 63; CGSCC-LABEL: define {{[^@]+}}@scc_r1 64; CGSCC-SAME: (i32 [[A:%.*]], i32 returned [[R:%.*]], i32 [[B:%.*]]) #[[ATTR1:[0-9]+]] { 65; CGSCC-NEXT: entry: 66; CGSCC-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[A]], i32 [[R]]) #[[ATTR7:[0-9]+]] 67; CGSCC-NEXT: ret i32 [[R]] 68; 69entry: 70 %call = call i32 @sink_r0(i32 %r) 71 %call1 = call i32 @scc_r2(i32 %r, i32 %a, i32 %call) 72 ret i32 %call1 73} 74 75define i32 @scc_r2(i32 %a, i32 %b, i32 %r) #0 { 76; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 77; TUNIT-LABEL: define {{[^@]+}}@scc_r2 78; TUNIT-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]]) #[[ATTR1]] { 79; TUNIT-NEXT: entry: 80; TUNIT-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] 81; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 82; TUNIT: if.then: 83; TUNIT-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR8]] 84; TUNIT-NEXT: br label [[RETURN:%.*]] 85; TUNIT: if.end: 86; TUNIT-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] 87; TUNIT-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] 88; TUNIT: if.then3: 89; TUNIT-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR8]] 90; TUNIT-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR8]] 91; TUNIT-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 undef) #[[ATTR8]] 92; TUNIT-NEXT: [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR8]] 93; TUNIT-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[R]]) #[[ATTR8]] 94; TUNIT-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[R]], i32 undef) #[[ATTR8]] 95; TUNIT-NEXT: br label [[RETURN]] 96; TUNIT: if.end12: 97; TUNIT-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] 98; TUNIT-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] 99; TUNIT: cond.true: 100; TUNIT-NEXT: br label [[COND_END:%.*]] 101; TUNIT: cond.false: 102; TUNIT-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR8]] 103; TUNIT-NEXT: br label [[COND_END]] 104; TUNIT: cond.end: 105; TUNIT-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ] 106; TUNIT-NEXT: br label [[RETURN]] 107; TUNIT: return: 108; TUNIT-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ] 109; TUNIT-NEXT: ret i32 [[R]] 110; 111; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 112; CGSCC-LABEL: define {{[^@]+}}@scc_r2 113; CGSCC-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 returned [[R:%.*]]) #[[ATTR1]] { 114; CGSCC-NEXT: entry: 115; CGSCC-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] 116; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 117; CGSCC: if.then: 118; CGSCC-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR7]] 119; CGSCC-NEXT: br label [[RETURN:%.*]] 120; CGSCC: if.end: 121; CGSCC-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] 122; CGSCC-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] 123; CGSCC: if.then3: 124; CGSCC-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR7]] 125; CGSCC-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR7]] 126; CGSCC-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 undef) #[[ATTR7]] 127; CGSCC-NEXT: [[CALL8:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]] 128; CGSCC-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[R]]) #[[ATTR7]] 129; CGSCC-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[R]], i32 undef) #[[ATTR7]] 130; CGSCC-NEXT: br label [[RETURN]] 131; CGSCC: if.end12: 132; CGSCC-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] 133; CGSCC-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] 134; CGSCC: cond.true: 135; CGSCC-NEXT: br label [[COND_END:%.*]] 136; CGSCC: cond.false: 137; CGSCC-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]] 138; CGSCC-NEXT: br label [[COND_END]] 139; CGSCC: cond.end: 140; CGSCC-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ] 141; CGSCC-NEXT: br label [[RETURN]] 142; CGSCC: return: 143; CGSCC-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ] 144; CGSCC-NEXT: ret i32 [[R]] 145; 146entry: 147 %cmp = icmp sgt i32 %a, %b 148 br i1 %cmp, label %if.then, label %if.end 149 150if.then: ; preds = %entry 151 %call = call i32 @sink_r0(i32 %r) 152 %call1 = call i32 @scc_r2(i32 %b, i32 %a, i32 %call) 153 br label %return 154 155if.end: ; preds = %entry 156 %cmp2 = icmp slt i32 %a, %b 157 br i1 %cmp2, label %if.then3, label %if.end12 158 159if.then3: ; preds = %if.end 160 %call4 = call i32 @sink_r0(i32 %b) 161 %call5 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r) 162 %call6 = call i32 @scc_r2(i32 %r, i32 %r, i32 %r) 163 %call7 = call i32 @scc_r1(i32 %a, i32 %call6, i32 %r) 164 %call8 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r) 165 %call9 = call i32 @scc_r2(i32 %call5, i32 %call7, i32 %call8) 166 %call10 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r) 167 %call11 = call i32 @scc_r1(i32 %call4, i32 %call9, i32 %call10) 168 br label %return 169 170if.end12: ; preds = %if.end 171 %cmp13 = icmp eq i32 %a, %b 172 br i1 %cmp13, label %cond.true, label %cond.false 173 174cond.true: ; preds = %if.end12 175 br label %cond.end 176 177cond.false: ; preds = %if.end12 178 %call14 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r) 179 br label %cond.end 180 181cond.end: ; preds = %cond.false, %cond.true 182 %cond = phi i32 [ %r, %cond.true ], [ %call14, %cond.false ] 183 br label %return 184 185return: ; preds = %cond.end, %if.then3, %if.then 186 %retval.0 = phi i32 [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ] 187 ret i32 %retval.0 188} 189 190define i32 @scc_rX(i32 %a, i32 %b, i32 %r) #0 { 191; TUNIT: Function Attrs: nofree noinline norecurse nosync nounwind memory(none) uwtable 192; TUNIT-LABEL: define {{[^@]+}}@scc_rX 193; TUNIT-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]]) #[[ATTR2:[0-9]+]] { 194; TUNIT-NEXT: entry: 195; TUNIT-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] 196; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 197; TUNIT: if.then: 198; TUNIT-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR8]] 199; TUNIT-NEXT: br label [[RETURN:%.*]] 200; TUNIT: if.end: 201; TUNIT-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] 202; TUNIT-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] 203; TUNIT: if.then3: 204; TUNIT-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR8]] 205; TUNIT-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR8]] 206; TUNIT-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 undef) #[[ATTR8]] 207; TUNIT-NEXT: [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 undef) #[[ATTR8]] 208; TUNIT-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[B]]) #[[ATTR8]] 209; TUNIT-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[B]], i32 undef) #[[ATTR8]] 210; TUNIT-NEXT: br label [[RETURN]] 211; TUNIT: if.end12: 212; TUNIT-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] 213; TUNIT-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] 214; TUNIT: cond.true: 215; TUNIT-NEXT: br label [[COND_END:%.*]] 216; TUNIT: cond.false: 217; TUNIT-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR8]] 218; TUNIT-NEXT: br label [[COND_END]] 219; TUNIT: cond.end: 220; TUNIT-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ] 221; TUNIT-NEXT: br label [[RETURN]] 222; TUNIT: return: 223; TUNIT-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[R]], [[IF_THEN]] ], [ [[B]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ] 224; TUNIT-NEXT: ret i32 [[RETVAL_0]] 225; 226; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 227; CGSCC-LABEL: define {{[^@]+}}@scc_rX 228; CGSCC-SAME: (i32 [[A:%.*]], i32 [[B:%.*]], i32 [[R:%.*]]) #[[ATTR1]] { 229; CGSCC-NEXT: entry: 230; CGSCC-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], [[B]] 231; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 232; CGSCC: if.then: 233; CGSCC-NEXT: [[CALL1:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[A]], i32 [[R]]) #[[ATTR7]] 234; CGSCC-NEXT: br label [[RETURN:%.*]] 235; CGSCC: if.end: 236; CGSCC-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B]] 237; CGSCC-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] 238; CGSCC: if.then3: 239; CGSCC-NEXT: [[CALL5:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]] 240; CGSCC-NEXT: [[CALL6:%.*]] = call i32 @scc_r2(i32 [[R]], i32 [[R]], i32 [[R]]) #[[ATTR7]] 241; CGSCC-NEXT: [[CALL7:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[R]], i32 [[R]]) #[[ATTR7]] 242; CGSCC-NEXT: [[CALL8:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]] 243; CGSCC-NEXT: [[CALL9:%.*]] = call i32 @scc_r2(i32 [[B]], i32 [[R]], i32 [[B]]) #[[ATTR7]] 244; CGSCC-NEXT: [[CALL10:%.*]] = call i32 @scc_r1(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]] 245; CGSCC-NEXT: [[CALL11:%.*]] = call i32 @scc_r1(i32 [[B]], i32 [[B]], i32 [[B]]) #[[ATTR7]] 246; CGSCC-NEXT: br label [[RETURN]] 247; CGSCC: if.end12: 248; CGSCC-NEXT: [[CMP13:%.*]] = icmp eq i32 [[A]], [[B]] 249; CGSCC-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] 250; CGSCC: cond.true: 251; CGSCC-NEXT: br label [[COND_END:%.*]] 252; CGSCC: cond.false: 253; CGSCC-NEXT: [[CALL14:%.*]] = call i32 @scc_r2(i32 [[A]], i32 [[B]], i32 [[R]]) #[[ATTR7]] 254; CGSCC-NEXT: br label [[COND_END]] 255; CGSCC: cond.end: 256; CGSCC-NEXT: [[COND:%.*]] = phi i32 [ [[R]], [[COND_TRUE]] ], [ [[CALL14]], [[COND_FALSE]] ] 257; CGSCC-NEXT: br label [[RETURN]] 258; CGSCC: return: 259; CGSCC-NEXT: [[RETVAL_0:%.*]] = phi i32 [ [[CALL1]], [[IF_THEN]] ], [ [[CALL11]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ] 260; CGSCC-NEXT: ret i32 [[RETVAL_0]] 261; 262entry: 263 %cmp = icmp sgt i32 %a, %b 264 br i1 %cmp, label %if.then, label %if.end 265 266if.then: ; preds = %entry 267 %call = call i32 @sink_r0(i32 %r) 268 %call1 = call i32 @scc_r2(i32 %b, i32 %a, i32 %call) 269 br label %return 270 271if.end: ; preds = %entry 272 %cmp2 = icmp slt i32 %a, %b 273 br i1 %cmp2, label %if.then3, label %if.end12 274 275if.then3: ; preds = %if.end 276 %call4 = call i32 @sink_r0(i32 %b) 277 %call5 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r) 278 %call6 = call i32 @scc_r2(i32 %r, i32 %r, i32 %r) 279 %call7 = call i32 @scc_r1(i32 %a, i32 %call6, i32 %r) 280 %call8 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r) 281 %call9 = call i32 @scc_r2(i32 %call5, i32 %call7, i32 %call8) 282 %call10 = call i32 @scc_r1(i32 %a, i32 %b, i32 %r) 283 %call11 = call i32 @scc_r1(i32 %call4, i32 %call9, i32 %call10) 284 br label %return 285 286if.end12: ; preds = %if.end 287 %cmp13 = icmp eq i32 %a, %b 288 br i1 %cmp13, label %cond.true, label %cond.false 289 290cond.true: ; preds = %if.end12 291 br label %cond.end 292 293cond.false: ; preds = %if.end12 294 %call14 = call i32 @scc_r2(i32 %a, i32 %b, i32 %r) 295 br label %cond.end 296 297cond.end: ; preds = %cond.false, %cond.true 298 %cond = phi i32 [ %r, %cond.true ], [ %call14, %cond.false ] 299 br label %return 300 301return: ; preds = %cond.end, %if.then3, %if.then 302 %retval.0 = phi i32 [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ] 303 ret i32 %retval.0 304} 305 306 307; TEST SCC test returning a pointer value argument 308; 309; double* ptr_scc_r1(double* a, double* b, double* r); 310; double* ptr_scc_r2(double* a, double* b, double* r); 311; 312; __attribute__((noinline)) double* ptr_sink_r0(double* r) { 313; return r; 314; } 315; 316; __attribute__((noinline)) double* ptr_scc_r1(double* a, double* r, double* b) { 317; return ptr_scc_r2(r, a, ptr_sink_r0(r)); 318; } 319; 320; __attribute__((noinline)) double* ptr_scc_r2(double* a, double* b, double* r) { 321; if (a > b) 322; return ptr_scc_r2(b, a, ptr_sink_r0(r)); 323; if (a < b) 324; return ptr_scc_r1(ptr_sink_r0(b), ptr_scc_r2(ptr_scc_r1(a, b, r), ptr_scc_r1(a, ptr_scc_r2(r, r, r), r), ptr_scc_r2(a, b, r)), ptr_scc_r1(a, b, r)); 325; return a == b ? r : ptr_scc_r2(a, b, r); 326; } 327define ptr @ptr_sink_r0(ptr %r) #0 { 328; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 329; CHECK-LABEL: define {{[^@]+}}@ptr_sink_r0 330; CHECK-SAME: (ptr nofree readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR0]] { 331; CHECK-NEXT: entry: 332; CHECK-NEXT: ret ptr [[R]] 333; 334entry: 335 ret ptr %r 336} 337 338define ptr @ptr_scc_r1(ptr %a, ptr %r, ptr %b) #0 { 339; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 340; TUNIT-LABEL: define {{[^@]+}}@ptr_scc_r1 341; TUNIT-SAME: (ptr nofree readnone captures(none) [[A:%.*]], ptr nofree readnone returned "no-capture-maybe-returned" [[R:%.*]], ptr nofree readnone captures(none) [[B:%.*]]) #[[ATTR1]] { 342; TUNIT-NEXT: entry: 343; TUNIT-NEXT: [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[R]], ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]] 344; TUNIT-NEXT: ret ptr [[R]] 345; 346; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 347; CGSCC-LABEL: define {{[^@]+}}@ptr_scc_r1 348; CGSCC-SAME: (ptr nofree readnone captures(none) [[A:%.*]], ptr nofree readnone returned [[R:%.*]], ptr nofree readnone captures(none) [[B:%.*]]) #[[ATTR1]] { 349; CGSCC-NEXT: entry: 350; CGSCC-NEXT: [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[R]], ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree readnone [[R]]) #[[ATTR7]] 351; CGSCC-NEXT: ret ptr [[R]] 352; 353entry: 354 %call = call ptr @ptr_sink_r0(ptr %r) 355 %call1 = call ptr @ptr_scc_r2(ptr %r, ptr %a, ptr %call) 356 ret ptr %call1 357} 358 359define ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r) #0 { 360; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 361; TUNIT-LABEL: define {{[^@]+}}@ptr_scc_r2 362; TUNIT-SAME: (ptr nofree readnone captures(none) [[A:%.*]], ptr nofree readnone captures(none) [[B:%.*]], ptr nofree readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR1]] { 363; TUNIT-NEXT: entry: 364; TUNIT-NEXT: [[CMP:%.*]] = icmp ugt ptr [[A]], [[B]] 365; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 366; TUNIT: if.then: 367; TUNIT-NEXT: [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[B]], ptr noalias nofree nonnull readnone captures(none) [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]] 368; TUNIT-NEXT: br label [[RETURN:%.*]] 369; TUNIT: if.end: 370; TUNIT-NEXT: [[CMP2:%.*]] = icmp ult ptr [[A]], [[B]] 371; TUNIT-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] 372; TUNIT: if.then3: 373; TUNIT-NEXT: [[CALL5:%.*]] = call ptr @ptr_scc_r1(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree nonnull readnone "no-capture-maybe-returned" [[B]], ptr noalias nofree readnone captures(none) undef) #[[ATTR8]] 374; TUNIT-NEXT: [[CALL6:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[R]], ptr noalias nofree readnone captures(none) [[R]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]] 375; TUNIT-NEXT: [[CALL7:%.*]] = call ptr @ptr_scc_r1(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]], ptr noalias nofree readnone captures(none) undef) #[[ATTR8]] 376; TUNIT-NEXT: [[CALL8:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree nonnull readnone captures(none) [[B]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]] 377; TUNIT-NEXT: [[CALL9:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[B]], ptr noalias nofree readnone captures(none) [[R]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]] 378; TUNIT-NEXT: [[CALL11:%.*]] = call ptr @ptr_scc_r1(ptr noalias nofree readnone captures(none) [[B]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]], ptr noalias nofree readnone captures(none) undef) #[[ATTR8]] 379; TUNIT-NEXT: br label [[RETURN]] 380; TUNIT: if.end12: 381; TUNIT-NEXT: [[CMP13:%.*]] = icmp eq ptr [[A]], [[B]] 382; TUNIT-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] 383; TUNIT: cond.true: 384; TUNIT-NEXT: br label [[COND_END:%.*]] 385; TUNIT: cond.false: 386; TUNIT-NEXT: [[CALL14:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree readnone captures(none) [[B]], ptr noalias nofree readnone "no-capture-maybe-returned" [[R]]) #[[ATTR8]] 387; TUNIT-NEXT: br label [[COND_END]] 388; TUNIT: cond.end: 389; TUNIT-NEXT: [[COND:%.*]] = phi ptr [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ] 390; TUNIT-NEXT: br label [[RETURN]] 391; TUNIT: return: 392; TUNIT-NEXT: [[RETVAL_0:%.*]] = phi ptr [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ] 393; TUNIT-NEXT: ret ptr [[R]] 394; 395; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 396; CGSCC-LABEL: define {{[^@]+}}@ptr_scc_r2 397; CGSCC-SAME: (ptr nofree readnone captures(none) [[A:%.*]], ptr nofree readnone captures(none) [[B:%.*]], ptr nofree readnone returned [[R:%.*]]) #[[ATTR1]] { 398; CGSCC-NEXT: entry: 399; CGSCC-NEXT: [[CMP:%.*]] = icmp ugt ptr [[A]], [[B]] 400; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 401; CGSCC: if.then: 402; CGSCC-NEXT: [[CALL1:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[B]], ptr noalias nofree nonnull readnone captures(none) [[A]], ptr noalias nofree readnone [[R]]) #[[ATTR7]] 403; CGSCC-NEXT: br label [[RETURN:%.*]] 404; CGSCC: if.end: 405; CGSCC-NEXT: [[CMP2:%.*]] = icmp ult ptr [[A]], [[B]] 406; CGSCC-NEXT: br i1 [[CMP2]], label [[IF_THEN3:%.*]], label [[IF_END12:%.*]] 407; CGSCC: if.then3: 408; CGSCC-NEXT: [[CALL5:%.*]] = call ptr @ptr_scc_r1(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree nonnull readnone [[B]], ptr noalias nofree readnone captures(none) undef) #[[ATTR7]] 409; CGSCC-NEXT: [[CALL6:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[R]], ptr noalias nofree readnone captures(none) [[R]], ptr noalias nofree readnone [[R]]) #[[ATTR7]] 410; CGSCC-NEXT: [[CALL7:%.*]] = call ptr @ptr_scc_r1(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree readnone [[R]], ptr noalias nofree readnone captures(none) undef) #[[ATTR7]] 411; CGSCC-NEXT: [[CALL8:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree nonnull readnone captures(none) [[B]], ptr noalias nofree readnone [[R]]) #[[ATTR7]] 412; CGSCC-NEXT: [[CALL9:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[B]], ptr noalias nofree readnone captures(none) [[R]], ptr noalias nofree readnone [[R]]) #[[ATTR7]] 413; CGSCC-NEXT: [[CALL11:%.*]] = call ptr @ptr_scc_r1(ptr noalias nofree nonnull readnone captures(none) [[B]], ptr noalias nofree readnone [[R]], ptr noalias nofree readnone captures(none) undef) #[[ATTR7]] 414; CGSCC-NEXT: br label [[RETURN]] 415; CGSCC: if.end12: 416; CGSCC-NEXT: [[CMP13:%.*]] = icmp eq ptr [[A]], [[B]] 417; CGSCC-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]] 418; CGSCC: cond.true: 419; CGSCC-NEXT: br label [[COND_END:%.*]] 420; CGSCC: cond.false: 421; CGSCC-NEXT: [[CALL14:%.*]] = call ptr @ptr_scc_r2(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree readnone captures(none) [[B]], ptr noalias nofree readnone [[R]]) #[[ATTR7]] 422; CGSCC-NEXT: br label [[COND_END]] 423; CGSCC: cond.end: 424; CGSCC-NEXT: [[COND:%.*]] = phi ptr [ [[R]], [[COND_TRUE]] ], [ [[R]], [[COND_FALSE]] ] 425; CGSCC-NEXT: br label [[RETURN]] 426; CGSCC: return: 427; CGSCC-NEXT: [[RETVAL_0:%.*]] = phi ptr [ [[R]], [[IF_THEN]] ], [ [[R]], [[IF_THEN3]] ], [ [[R]], [[COND_END]] ] 428; CGSCC-NEXT: ret ptr [[R]] 429; 430entry: 431 %cmp = icmp ugt ptr %a, %b 432 br i1 %cmp, label %if.then, label %if.end 433 434if.then: ; preds = %entry 435 %call = call ptr @ptr_sink_r0(ptr %r) 436 %call1 = call ptr @ptr_scc_r2(ptr %b, ptr %a, ptr %call) 437 br label %return 438 439if.end: ; preds = %entry 440 %cmp2 = icmp ult ptr %a, %b 441 br i1 %cmp2, label %if.then3, label %if.end12 442 443if.then3: ; preds = %if.end 444 %call4 = call ptr @ptr_sink_r0(ptr %b) 445 %call5 = call ptr @ptr_scc_r1(ptr %a, ptr %b, ptr %r) 446 %call6 = call ptr @ptr_scc_r2(ptr %r, ptr %r, ptr %r) 447 %call7 = call ptr @ptr_scc_r1(ptr %a, ptr %call6, ptr %r) 448 %call8 = call ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r) 449 %call9 = call ptr @ptr_scc_r2(ptr %call5, ptr %call7, ptr %call8) 450 %call10 = call ptr @ptr_scc_r1(ptr %a, ptr %b, ptr %r) 451 %call11 = call ptr @ptr_scc_r1(ptr %call4, ptr %call9, ptr %call10) 452 br label %return 453 454if.end12: ; preds = %if.end 455 %cmp13 = icmp eq ptr %a, %b 456 br i1 %cmp13, label %cond.true, label %cond.false 457 458cond.true: ; preds = %if.end12 459 br label %cond.end 460 461cond.false: ; preds = %if.end12 462 %call14 = call ptr @ptr_scc_r2(ptr %a, ptr %b, ptr %r) 463 br label %cond.end 464 465cond.end: ; preds = %cond.false, %cond.true 466 %cond = phi ptr [ %r, %cond.true ], [ %call14, %cond.false ] 467 br label %return 468 469return: ; preds = %cond.end, %if.then3, %if.then 470 %retval.0 = phi ptr [ %call1, %if.then ], [ %call11, %if.then3 ], [ %cond, %cond.end ] 471 ret ptr %retval.0 472} 473 474 475; TEST a no-return singleton SCC 476; 477; int* rt0(int *a) { 478; return *a ? a : rt0(a); 479; } 480; 481define ptr @rt0(ptr %a) #0 { 482; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(argmem: read) uwtable 483; TUNIT-LABEL: define {{[^@]+}}@rt0 484; TUNIT-SAME: (ptr nofree noundef nonnull readonly returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR3:[0-9]+]] { 485; TUNIT-NEXT: entry: 486; TUNIT-NEXT: [[CALL:%.*]] = call ptr @rt0(ptr nofree noundef nonnull readonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[A]]) #[[ATTR10:[0-9]+]] 487; TUNIT-NEXT: ret ptr [[A]] 488; 489; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(argmem: read) uwtable 490; CGSCC-LABEL: define {{[^@]+}}@rt0 491; CGSCC-SAME: (ptr nofree noundef nonnull readonly returned align 4 dereferenceable(4) "no-capture-maybe-returned" [[A:%.*]]) #[[ATTR2:[0-9]+]] { 492; CGSCC-NEXT: entry: 493; CGSCC-NEXT: [[CALL:%.*]] = call ptr @rt0(ptr nofree noundef nonnull readonly align 4 dereferenceable(4) "no-capture-maybe-returned" [[A]]) #[[ATTR8:[0-9]+]] 494; CGSCC-NEXT: ret ptr [[A]] 495; 496entry: 497 %v = load i32, ptr %a, align 4 498 %tobool = icmp ne i32 %v, 0 499 %call = call ptr @rt0(ptr %a) 500 %sel = select i1 %tobool, ptr %a, ptr %call 501 ret ptr %sel 502} 503 504; TEST a no-return singleton SCC 505; 506; int* rt1(int *a) { 507; return *a ? undef : rt1(a); 508; } 509; 510define ptr @rt1(ptr %a) #0 { 511; TUNIT: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 512; TUNIT-LABEL: define {{[^@]+}}@rt1 513; TUNIT-SAME: (ptr nofree nonnull readnone align 4 captures(none) dereferenceable(4) [[A:%.*]]) #[[ATTR4:[0-9]+]] { 514; TUNIT-NEXT: entry: 515; TUNIT-NEXT: ret ptr undef 516; 517; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 518; CGSCC-LABEL: define {{[^@]+}}@rt1 519; CGSCC-SAME: (ptr nofree nonnull readnone align 4 captures(none) dereferenceable(4) [[A:%.*]]) #[[ATTR3:[0-9]+]] { 520; CGSCC-NEXT: entry: 521; CGSCC-NEXT: ret ptr undef 522; 523entry: 524 %v = load i32, ptr %a, align 4 525 %tobool = icmp ne i32 %v, 0 526 %call = call ptr @rt1(ptr %a) 527 %sel = select i1 %tobool, ptr undef, ptr %call 528 ret ptr %sel 529} 530 531; TEST another SCC test 532; 533define ptr @rt2_helper(ptr %a) #0 { 534; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 535; TUNIT-LABEL: define {{[^@]+}}@rt2_helper 536; TUNIT-SAME: (ptr nofree readnone returned [[A:%.*]]) #[[ATTR1]] { 537; TUNIT-NEXT: entry: 538; TUNIT-NEXT: [[CALL:%.*]] = call ptr @rt2(ptr noalias nofree readnone [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[A]]) #[[ATTR8]] 539; TUNIT-NEXT: ret ptr [[A]] 540; 541; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 542; CGSCC-LABEL: define {{[^@]+}}@rt2_helper 543; CGSCC-SAME: (ptr nofree readnone returned [[A:%.*]]) #[[ATTR1]] { 544; CGSCC-NEXT: entry: 545; CGSCC-NEXT: [[CALL:%.*]] = call ptr @rt2(ptr noalias nofree readnone [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[A]]) #[[ATTR7]] 546; CGSCC-NEXT: ret ptr [[A]] 547; 548entry: 549 %call = call ptr @rt2(ptr %a, ptr %a) 550 ret ptr %call 551} 552 553define ptr @rt2(ptr %a, ptr %b) #0 { 554; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 555; TUNIT-LABEL: define {{[^@]+}}@rt2 556; TUNIT-SAME: (ptr nofree readnone [[A:%.*]], ptr nofree readnone "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR1]] { 557; TUNIT-NEXT: entry: 558; TUNIT-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], null 559; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 560; TUNIT: if.then: 561; TUNIT-NEXT: [[CALL:%.*]] = call ptr @rt2_helper(ptr noalias nofree readnone [[A]]) #[[ATTR8]] 562; TUNIT-NEXT: br label [[IF_END]] 563; TUNIT: if.end: 564; TUNIT-NEXT: [[SEL:%.*]] = phi ptr [ [[B]], [[ENTRY:%.*]] ], [ [[A]], [[IF_THEN]] ] 565; TUNIT-NEXT: ret ptr [[SEL]] 566; 567; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 568; CGSCC-LABEL: define {{[^@]+}}@rt2 569; CGSCC-SAME: (ptr nofree readnone [[A:%.*]], ptr nofree readnone "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR1]] { 570; CGSCC-NEXT: entry: 571; CGSCC-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], null 572; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 573; CGSCC: if.then: 574; CGSCC-NEXT: [[CALL:%.*]] = call ptr @rt2_helper(ptr noalias nofree readnone [[A]]) #[[ATTR7]] 575; CGSCC-NEXT: br label [[IF_END]] 576; CGSCC: if.end: 577; CGSCC-NEXT: [[SEL:%.*]] = phi ptr [ [[B]], [[ENTRY:%.*]] ], [ [[A]], [[IF_THEN]] ] 578; CGSCC-NEXT: ret ptr [[SEL]] 579; 580entry: 581 %cmp = icmp eq ptr %a, null 582 br i1 %cmp, label %if.then, label %if.end 583 584if.then: 585 %call = call ptr @rt2_helper(ptr %a) 586 br label %if.end 587 588if.end: 589 %sel = phi ptr [ %b, %entry], [%call, %if.then] 590 ret ptr %sel 591} 592 593; TEST another SCC test 594; 595define ptr @rt3_helper(ptr %a, ptr %b) #0 { 596; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 597; TUNIT-LABEL: define {{[^@]+}}@rt3_helper 598; TUNIT-SAME: (ptr nofree readnone captures(none) [[A:%.*]], ptr nofree readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR1]] { 599; TUNIT-NEXT: entry: 600; TUNIT-NEXT: [[CALL:%.*]] = call ptr @rt3(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[B]]) #[[ATTR8]] 601; TUNIT-NEXT: ret ptr [[B]] 602; 603; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 604; CGSCC-LABEL: define {{[^@]+}}@rt3_helper 605; CGSCC-SAME: (ptr nofree readnone captures(none) [[A:%.*]], ptr nofree readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR1]] { 606; CGSCC-NEXT: entry: 607; CGSCC-NEXT: [[CALL:%.*]] = call ptr @rt3(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[B]]) #[[ATTR7]] 608; CGSCC-NEXT: ret ptr [[B]] 609; 610entry: 611 %call = call ptr @rt3(ptr %a, ptr %b) 612 ret ptr %call 613} 614 615define ptr @rt3(ptr %a, ptr %b) #0 { 616; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 617; TUNIT-LABEL: define {{[^@]+}}@rt3 618; TUNIT-SAME: (ptr nofree readnone captures(none) [[A:%.*]], ptr nofree readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR1]] { 619; TUNIT-NEXT: entry: 620; TUNIT-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], null 621; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 622; TUNIT: if.then: 623; TUNIT-NEXT: [[CALL:%.*]] = call ptr @rt3_helper(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[B]]) #[[ATTR8]] 624; TUNIT-NEXT: br label [[IF_END]] 625; TUNIT: if.end: 626; TUNIT-NEXT: [[SEL:%.*]] = phi ptr [ [[B]], [[ENTRY:%.*]] ], [ [[B]], [[IF_THEN]] ] 627; TUNIT-NEXT: ret ptr [[B]] 628; 629; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 630; CGSCC-LABEL: define {{[^@]+}}@rt3 631; CGSCC-SAME: (ptr nofree readnone captures(none) [[A:%.*]], ptr nofree readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR1]] { 632; CGSCC-NEXT: entry: 633; CGSCC-NEXT: [[CMP:%.*]] = icmp eq ptr [[A]], null 634; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 635; CGSCC: if.then: 636; CGSCC-NEXT: [[CALL:%.*]] = call ptr @rt3_helper(ptr noalias nofree readnone captures(none) [[A]], ptr noalias nofree readnone "no-capture-maybe-returned" [[B]]) #[[ATTR7]] 637; CGSCC-NEXT: br label [[IF_END]] 638; CGSCC: if.end: 639; CGSCC-NEXT: [[SEL:%.*]] = phi ptr [ [[B]], [[ENTRY:%.*]] ], [ [[B]], [[IF_THEN]] ] 640; CGSCC-NEXT: ret ptr [[B]] 641; 642entry: 643 %cmp = icmp eq ptr %a, null 644 br i1 %cmp, label %if.then, label %if.end 645 646if.then: 647 %call = call ptr @rt3_helper(ptr %a, ptr %b) 648 br label %if.end 649 650if.end: 651 %sel = phi ptr [ %b, %entry], [%call, %if.then] 652 ret ptr %sel 653} 654 655; TEST address taken function with call to an external functions 656; 657; void unknown_fn(void *); 658; 659; int* calls_unknown_fn(int *r) { 660; unknown_fn(&calls_unknown_fn); 661; return r; 662; } 663; 664declare void @unknown_fn(ptr) #0 665 666define ptr @calls_unknown_fn(ptr %r) #0 { 667; TUNIT: Function Attrs: noinline nounwind uwtable 668; TUNIT-LABEL: define {{[^@]+}}@calls_unknown_fn 669; TUNIT-SAME: (ptr nofree readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR5:[0-9]+]] { 670; TUNIT-NEXT: tail call void @unknown_fn(ptr noundef nonnull @calls_unknown_fn) #[[ATTR11:[0-9]+]] 671; TUNIT-NEXT: ret ptr [[R]] 672; 673; CGSCC: Function Attrs: noinline nounwind uwtable 674; CGSCC-LABEL: define {{[^@]+}}@calls_unknown_fn 675; CGSCC-SAME: (ptr nofree readnone returned "no-capture-maybe-returned" [[R:%.*]]) #[[ATTR4:[0-9]+]] { 676; CGSCC-NEXT: tail call void @unknown_fn(ptr noundef nonnull @calls_unknown_fn) #[[ATTR9:[0-9]+]] 677; CGSCC-NEXT: ret ptr [[R]] 678; 679 tail call void @unknown_fn(ptr nonnull @calls_unknown_fn) 680 ret ptr %r 681} 682 683 684; TEST call to a function that might be redifined at link time 685; 686; int *maybe_redefined_fn(int *r) { 687; return r; 688; } 689; 690; int *calls_maybe_redefined_fn(int *r) { 691; maybe_redefined_fn(r); 692; return r; 693; } 694; 695; Verify the maybe-redefined function is not annotated: 696; 697define linkonce_odr ptr @maybe_redefined_fn(ptr %r) #0 { 698; TUNIT: Function Attrs: noinline nounwind uwtable 699; TUNIT-LABEL: define {{[^@]+}}@maybe_redefined_fn 700; TUNIT-SAME: (ptr [[R:%.*]]) #[[ATTR5]] { 701; TUNIT-NEXT: entry: 702; TUNIT-NEXT: ret ptr [[R]] 703; 704; CGSCC: Function Attrs: noinline nounwind uwtable 705; CGSCC-LABEL: define {{[^@]+}}@maybe_redefined_fn 706; CGSCC-SAME: (ptr [[R:%.*]]) #[[ATTR4]] { 707; CGSCC-NEXT: entry: 708; CGSCC-NEXT: ret ptr [[R]] 709; 710entry: 711 ret ptr %r 712} 713 714define ptr @calls_maybe_redefined_fn(ptr %r) #0 { 715; TUNIT: Function Attrs: noinline nounwind uwtable 716; TUNIT-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn 717; TUNIT-SAME: (ptr returned [[R:%.*]]) #[[ATTR5]] { 718; TUNIT-NEXT: entry: 719; TUNIT-NEXT: [[CALL:%.*]] = call ptr @maybe_redefined_fn(ptr [[R]]) #[[ATTR11]] 720; TUNIT-NEXT: ret ptr [[R]] 721; 722; CGSCC: Function Attrs: noinline nounwind uwtable 723; CGSCC-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn 724; CGSCC-SAME: (ptr returned [[R:%.*]]) #[[ATTR4]] { 725; CGSCC-NEXT: entry: 726; CGSCC-NEXT: [[CALL:%.*]] = call ptr @maybe_redefined_fn(ptr [[R]]) #[[ATTR9]] 727; CGSCC-NEXT: ret ptr [[R]] 728; 729entry: 730 %call = call ptr @maybe_redefined_fn(ptr %r) 731 ret ptr %r 732} 733 734; TEST return call to a function that might be redifined at link time 735; 736; int *maybe_redefined_fn2(int *r) { 737; return r; 738; } 739; 740; int *calls_maybe_redefined_fn2(int *r) { 741; return maybe_redefined_fn2(r); 742; } 743; 744; Verify the maybe-redefined function is not annotated: 745; 746define linkonce_odr ptr @maybe_redefined_fn2(ptr %r) #0 { 747; TUNIT: Function Attrs: noinline nounwind uwtable 748; TUNIT-LABEL: define {{[^@]+}}@maybe_redefined_fn2 749; TUNIT-SAME: (ptr [[R:%.*]]) #[[ATTR5]] { 750; TUNIT-NEXT: entry: 751; TUNIT-NEXT: ret ptr [[R]] 752; 753; CGSCC: Function Attrs: noinline nounwind uwtable 754; CGSCC-LABEL: define {{[^@]+}}@maybe_redefined_fn2 755; CGSCC-SAME: (ptr [[R:%.*]]) #[[ATTR4]] { 756; CGSCC-NEXT: entry: 757; CGSCC-NEXT: ret ptr [[R]] 758; 759entry: 760 ret ptr %r 761} 762 763define ptr @calls_maybe_redefined_fn2(ptr %r) #0 { 764; TUNIT: Function Attrs: noinline nounwind uwtable 765; TUNIT-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn2 766; TUNIT-SAME: (ptr [[R:%.*]]) #[[ATTR5]] { 767; TUNIT-NEXT: entry: 768; TUNIT-NEXT: [[CALL:%.*]] = call ptr @maybe_redefined_fn2(ptr [[R]]) #[[ATTR11]] 769; TUNIT-NEXT: ret ptr [[CALL]] 770; 771; CGSCC: Function Attrs: noinline nounwind uwtable 772; CGSCC-LABEL: define {{[^@]+}}@calls_maybe_redefined_fn2 773; CGSCC-SAME: (ptr [[R:%.*]]) #[[ATTR4]] { 774; CGSCC-NEXT: entry: 775; CGSCC-NEXT: [[CALL:%.*]] = call ptr @maybe_redefined_fn2(ptr [[R]]) #[[ATTR9]] 776; CGSCC-NEXT: ret ptr [[CALL]] 777; 778entry: 779 %call = call ptr @maybe_redefined_fn2(ptr %r) 780 ret ptr %call 781} 782 783 784; TEST returned argument goes through select and phi 785; 786; double select_and_phi(double b) { 787; double x = b; 788; if (b > 0) 789; x = b; 790; return b == 0? b : x; 791; } 792; 793define double @select_and_phi(double %b) #0 { 794; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 795; CHECK-LABEL: define {{[^@]+}}@select_and_phi 796; CHECK-SAME: (double returned [[B:%.*]]) #[[ATTR0]] { 797; CHECK-NEXT: entry: 798; CHECK-NEXT: [[CMP:%.*]] = fcmp ogt double [[B]], 0.000000e+00 799; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 800; CHECK: if.then: 801; CHECK-NEXT: br label [[IF_END]] 802; CHECK: if.end: 803; CHECK-NEXT: [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ] 804; CHECK-NEXT: ret double [[B]] 805; 806entry: 807 %cmp = fcmp ogt double %b, 0.000000e+00 808 br i1 %cmp, label %if.then, label %if.end 809 810if.then: ; preds = %entry 811 br label %if.end 812 813if.end: ; preds = %if.then, %entry 814 %phi = phi double [ %b, %if.then ], [ %b, %entry ] 815 %cmp1 = fcmp oeq double %b, 0.000000e+00 816 %sel = select i1 %cmp1, double %b, double %phi 817 ret double %sel 818} 819 820 821; TEST returned argument goes through recursion, select, and phi 822; 823; double recursion_select_and_phi(int a, double b) { 824; double x = b; 825; if (a-- > 0) 826; x = recursion_select_and_phi(a, b); 827; return b == 0? b : x; 828; } 829; 830define double @recursion_select_and_phi(i32 %a, double %b) #0 { 831; TUNIT: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 832; TUNIT-LABEL: define {{[^@]+}}@recursion_select_and_phi 833; TUNIT-SAME: (i32 [[A:%.*]], double returned [[B:%.*]]) #[[ATTR1]] { 834; TUNIT-NEXT: entry: 835; TUNIT-NEXT: [[DEC:%.*]] = add nsw i32 [[A]], -1 836; TUNIT-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 0 837; TUNIT-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 838; TUNIT: if.then: 839; TUNIT-NEXT: [[CALL:%.*]] = call double @recursion_select_and_phi(i32 [[DEC]], double [[B]]) #[[ATTR8]] 840; TUNIT-NEXT: br label [[IF_END]] 841; TUNIT: if.end: 842; TUNIT-NEXT: [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ] 843; TUNIT-NEXT: ret double [[B]] 844; 845; CGSCC: Function Attrs: nofree noinline nosync nounwind memory(none) uwtable 846; CGSCC-LABEL: define {{[^@]+}}@recursion_select_and_phi 847; CGSCC-SAME: (i32 [[A:%.*]], double returned [[B:%.*]]) #[[ATTR1]] { 848; CGSCC-NEXT: entry: 849; CGSCC-NEXT: [[DEC:%.*]] = add nsw i32 [[A]], -1 850; CGSCC-NEXT: [[CMP:%.*]] = icmp sgt i32 [[A]], 0 851; CGSCC-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 852; CGSCC: if.then: 853; CGSCC-NEXT: [[CALL:%.*]] = call double @recursion_select_and_phi(i32 [[DEC]], double [[B]]) #[[ATTR7]] 854; CGSCC-NEXT: br label [[IF_END]] 855; CGSCC: if.end: 856; CGSCC-NEXT: [[PHI:%.*]] = phi double [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ] 857; CGSCC-NEXT: ret double [[B]] 858; 859entry: 860 %dec = add nsw i32 %a, -1 861 %cmp = icmp sgt i32 %a, 0 862 br i1 %cmp, label %if.then, label %if.end 863 864if.then: ; preds = %entry 865 %call = call double @recursion_select_and_phi(i32 %dec, double %b) 866 br label %if.end 867 868if.end: ; preds = %if.then, %entry 869 %phi = phi double [ %call, %if.then ], [ %b, %entry ] 870 %cmp1 = fcmp oeq double %b, 0.000000e+00 871 %sel = select i1 %cmp1, double %b, double %phi 872 ret double %sel 873} 874 875 876; TEST returned argument goes through bitcasts 877; 878; double* bitcast(int* b) { 879; return (double*)b; 880; } 881; 882define ptr @bitcast(ptr %b) #0 { 883; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 884; CHECK-LABEL: define {{[^@]+}}@bitcast 885; CHECK-SAME: (ptr nofree readnone returned "no-capture-maybe-returned" [[B:%.*]]) #[[ATTR0]] { 886; CHECK-NEXT: entry: 887; CHECK-NEXT: ret ptr [[B]] 888; 889entry: 890 ret ptr %b 891} 892 893 894; TEST returned argument goes through select and phi interleaved with bitcasts 895; 896; double* bitcasts_select_and_phi(int* b) { 897; double* x = b; 898; if (b == 0) 899; x = b; 900; return b != 0 ? b : x; 901; } 902; 903define ptr @bitcasts_select_and_phi(ptr %b) #0 { 904; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 905; CHECK-LABEL: define {{[^@]+}}@bitcasts_select_and_phi 906; CHECK-SAME: (ptr nofree readnone returned [[B:%.*]]) #[[ATTR0]] { 907; CHECK-NEXT: entry: 908; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[B]], null 909; CHECK-NEXT: br i1 [[CMP]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] 910; CHECK: if.then: 911; CHECK-NEXT: br label [[IF_END]] 912; CHECK: if.end: 913; CHECK-NEXT: [[PHI:%.*]] = phi ptr [ [[B]], [[IF_THEN]] ], [ [[B]], [[ENTRY:%.*]] ] 914; CHECK-NEXT: ret ptr [[B]] 915; 916entry: 917 %cmp = icmp eq ptr %b, null 918 br i1 %cmp, label %if.then, label %if.end 919 920if.then: ; preds = %entry 921 br label %if.end 922 923if.end: ; preds = %if.then, %entry 924 %phi = phi ptr [ %b, %if.then ], [ %b, %entry ] 925 %cmp2 = icmp ne ptr %b, null 926 %sel = select i1 %cmp2, ptr %phi, ptr %b 927 ret ptr %sel 928} 929 930 931; TEST return argument or argument or undef 932; 933; double* ret_arg_arg_undef(int* b) { 934; if (b == 0) 935; return (double*)b; 936; if (b == 0) 937; return (double*)b; 938; /* return undef */ 939; } 940; 941define ptr @ret_arg_arg_undef(ptr %b) #0 { 942; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 943; CHECK-LABEL: define {{[^@]+}}@ret_arg_arg_undef 944; CHECK-SAME: (ptr nofree readnone returned [[B:%.*]]) #[[ATTR0]] { 945; CHECK-NEXT: entry: 946; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[B]], null 947; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG0:%.*]], label [[IF_END:%.*]] 948; CHECK: ret_arg0: 949; CHECK-NEXT: ret ptr [[B]] 950; CHECK: if.end: 951; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG1:%.*]], label [[RET_UNDEF:%.*]] 952; CHECK: ret_arg1: 953; CHECK-NEXT: ret ptr [[B]] 954; CHECK: ret_undef: 955; CHECK-NEXT: ret ptr undef 956; 957entry: 958 %cmp = icmp eq ptr %b, null 959 br i1 %cmp, label %ret_arg0, label %if.end 960 961ret_arg0: 962 ret ptr %b 963 964if.end: 965 br i1 %cmp, label %ret_arg1, label %ret_undef 966 967ret_arg1: 968 ret ptr %b 969 970ret_undef: 971 ret ptr undef 972} 973 974 975; TEST return undef or argument or argument 976; 977; double* ret_undef_arg_arg(int* b) { 978; if (b == 0) 979; return (double*)b; 980; if (b == 0) 981; return (double*)b; 982; /* return undef */ 983; } 984; 985define ptr @ret_undef_arg_arg(ptr %b) #0 { 986; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 987; CHECK-LABEL: define {{[^@]+}}@ret_undef_arg_arg 988; CHECK-SAME: (ptr nofree readnone returned [[B:%.*]]) #[[ATTR0]] { 989; CHECK-NEXT: entry: 990; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[B]], null 991; CHECK-NEXT: br i1 [[CMP]], label [[RET_UNDEF:%.*]], label [[IF_END:%.*]] 992; CHECK: ret_undef: 993; CHECK-NEXT: ret ptr undef 994; CHECK: if.end: 995; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG0:%.*]], label [[RET_ARG1:%.*]] 996; CHECK: ret_arg0: 997; CHECK-NEXT: ret ptr [[B]] 998; CHECK: ret_arg1: 999; CHECK-NEXT: ret ptr [[B]] 1000; 1001entry: 1002 %cmp = icmp eq ptr %b, null 1003 br i1 %cmp, label %ret_undef, label %if.end 1004 1005ret_undef: 1006 ret ptr undef 1007 1008if.end: 1009 br i1 %cmp, label %ret_arg0, label %ret_arg1 1010 1011ret_arg0: 1012 ret ptr %b 1013 1014ret_arg1: 1015 ret ptr %b 1016} 1017 1018 1019; TEST return undef or argument or undef 1020; 1021; double* ret_undef_arg_undef(int* b) { 1022; if (b == 0) 1023; /* return undef */ 1024; if (b == 0) 1025; return (double*)b; 1026; /* return undef */ 1027; } 1028; 1029define ptr @ret_undef_arg_undef(ptr %b) #0 { 1030; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 1031; CHECK-LABEL: define {{[^@]+}}@ret_undef_arg_undef 1032; CHECK-SAME: (ptr nofree readnone returned [[B:%.*]]) #[[ATTR0]] { 1033; CHECK-NEXT: entry: 1034; CHECK-NEXT: [[CMP:%.*]] = icmp eq ptr [[B]], null 1035; CHECK-NEXT: br i1 [[CMP]], label [[RET_UNDEF0:%.*]], label [[IF_END:%.*]] 1036; CHECK: ret_undef0: 1037; CHECK-NEXT: ret ptr undef 1038; CHECK: if.end: 1039; CHECK-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNDEF1:%.*]] 1040; CHECK: ret_arg: 1041; CHECK-NEXT: ret ptr [[B]] 1042; CHECK: ret_undef1: 1043; CHECK-NEXT: ret ptr undef 1044; 1045entry: 1046 %cmp = icmp eq ptr %b, null 1047 br i1 %cmp, label %ret_undef0, label %if.end 1048 1049ret_undef0: 1050 ret ptr undef 1051 1052if.end: 1053 br i1 %cmp, label %ret_arg, label %ret_undef1 1054 1055ret_arg: 1056 ret ptr %b 1057 1058ret_undef1: 1059 ret ptr undef 1060} 1061 1062; TEST return argument or unknown call result 1063; 1064; int* ret_arg_or_unknown(int* b) { 1065; if (b == 0) 1066; return b; 1067; return unknown(); 1068; } 1069; 1070; Verify we do not assume b is returned 1071; 1072declare ptr @unknown(ptr) 1073 1074define ptr @ret_arg_or_unknown(ptr %b) #0 { 1075; TUNIT: Function Attrs: noinline nounwind uwtable 1076; TUNIT-LABEL: define {{[^@]+}}@ret_arg_or_unknown 1077; TUNIT-SAME: (ptr [[B:%.*]]) #[[ATTR5]] { 1078; TUNIT-NEXT: entry: 1079; TUNIT-NEXT: [[CMP:%.*]] = icmp eq ptr [[B]], null 1080; TUNIT-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]] 1081; TUNIT: ret_arg: 1082; TUNIT-NEXT: ret ptr [[B]] 1083; TUNIT: ret_unknown: 1084; TUNIT-NEXT: [[CALL:%.*]] = call ptr @unknown(ptr nonnull [[B]]) 1085; TUNIT-NEXT: ret ptr [[CALL]] 1086; 1087; CGSCC: Function Attrs: noinline nounwind uwtable 1088; CGSCC-LABEL: define {{[^@]+}}@ret_arg_or_unknown 1089; CGSCC-SAME: (ptr [[B:%.*]]) #[[ATTR4]] { 1090; CGSCC-NEXT: entry: 1091; CGSCC-NEXT: [[CMP:%.*]] = icmp eq ptr [[B]], null 1092; CGSCC-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]] 1093; CGSCC: ret_arg: 1094; CGSCC-NEXT: ret ptr [[B]] 1095; CGSCC: ret_unknown: 1096; CGSCC-NEXT: [[CALL:%.*]] = call ptr @unknown(ptr nonnull [[B]]) 1097; CGSCC-NEXT: ret ptr [[CALL]] 1098; 1099entry: 1100 %cmp = icmp eq ptr %b, null 1101 br i1 %cmp, label %ret_arg, label %ret_unknown 1102 1103ret_arg: 1104 ret ptr %b 1105 1106ret_unknown: 1107 %call = call ptr @unknown(ptr %b) 1108 ret ptr %call 1109} 1110 1111define ptr @ret_arg_or_unknown_through_phi(ptr %b) #0 { 1112; TUNIT: Function Attrs: noinline nounwind uwtable 1113; TUNIT-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi 1114; TUNIT-SAME: (ptr [[B:%.*]]) #[[ATTR5]] { 1115; TUNIT-NEXT: entry: 1116; TUNIT-NEXT: [[CMP:%.*]] = icmp eq ptr [[B]], null 1117; TUNIT-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]] 1118; TUNIT: ret_arg: 1119; TUNIT-NEXT: br label [[R:%.*]] 1120; TUNIT: ret_unknown: 1121; TUNIT-NEXT: [[CALL:%.*]] = call ptr @unknown(ptr nonnull [[B]]) 1122; TUNIT-NEXT: br label [[R]] 1123; TUNIT: r: 1124; TUNIT-NEXT: [[PHI:%.*]] = phi ptr [ [[B]], [[RET_ARG]] ], [ [[CALL]], [[RET_UNKNOWN]] ] 1125; TUNIT-NEXT: ret ptr [[PHI]] 1126; 1127; CGSCC: Function Attrs: noinline nounwind uwtable 1128; CGSCC-LABEL: define {{[^@]+}}@ret_arg_or_unknown_through_phi 1129; CGSCC-SAME: (ptr [[B:%.*]]) #[[ATTR4]] { 1130; CGSCC-NEXT: entry: 1131; CGSCC-NEXT: [[CMP:%.*]] = icmp eq ptr [[B]], null 1132; CGSCC-NEXT: br i1 [[CMP]], label [[RET_ARG:%.*]], label [[RET_UNKNOWN:%.*]] 1133; CGSCC: ret_arg: 1134; CGSCC-NEXT: br label [[R:%.*]] 1135; CGSCC: ret_unknown: 1136; CGSCC-NEXT: [[CALL:%.*]] = call ptr @unknown(ptr nonnull [[B]]) 1137; CGSCC-NEXT: br label [[R]] 1138; CGSCC: r: 1139; CGSCC-NEXT: [[PHI:%.*]] = phi ptr [ [[B]], [[RET_ARG]] ], [ [[CALL]], [[RET_UNKNOWN]] ] 1140; CGSCC-NEXT: ret ptr [[PHI]] 1141; 1142entry: 1143 %cmp = icmp eq ptr %b, null 1144 br i1 %cmp, label %ret_arg, label %ret_unknown 1145 1146ret_arg: 1147 br label %r 1148 1149ret_unknown: 1150 %call = call ptr @unknown(ptr %b) 1151 br label %r 1152 1153r: 1154 %phi = phi ptr [ %b, %ret_arg ], [ %call, %ret_unknown ] 1155 ret ptr %phi 1156} 1157 1158; TEST inconsistent IR in dead code. 1159; 1160define i32 @deadblockcall1(i32 %A) #0 { 1161; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 1162; CHECK-LABEL: define {{[^@]+}}@deadblockcall1 1163; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] { 1164; CHECK-NEXT: entry: 1165; CHECK-NEXT: ret i32 [[A]] 1166; CHECK: unreachableblock: 1167; CHECK-NEXT: unreachable 1168; 1169entry: 1170 ret i32 %A 1171unreachableblock: 1172 %B = call i32 @deadblockcall1(i32 %B) 1173 ret i32 %B 1174} 1175 1176declare i32 @deadblockcall_helper(i32 returned %A); 1177 1178define i32 @deadblockcall2(i32 %A) #0 { 1179; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 1180; CHECK-LABEL: define {{[^@]+}}@deadblockcall2 1181; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] { 1182; CHECK-NEXT: entry: 1183; CHECK-NEXT: ret i32 [[A]] 1184; CHECK: unreachableblock1: 1185; CHECK-NEXT: unreachable 1186; CHECK: unreachableblock2: 1187; CHECK-NEXT: unreachable 1188; 1189entry: 1190 ret i32 %A 1191unreachableblock1: 1192 %B = call i32 @deadblockcall_helper(i32 %B) 1193 ret i32 %B 1194unreachableblock2: 1195 %C = call i32 @deadblockcall1(i32 %C) 1196 ret i32 %C 1197} 1198 1199define i32 @deadblockphi1(i32 %A) #0 { 1200; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 1201; CHECK-LABEL: define {{[^@]+}}@deadblockphi1 1202; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] { 1203; CHECK-NEXT: entry: 1204; CHECK-NEXT: br label [[R:%.*]] 1205; CHECK: unreachableblock1: 1206; CHECK-NEXT: unreachable 1207; CHECK: unreachableblock2: 1208; CHECK-NEXT: unreachable 1209; CHECK: r: 1210; CHECK-NEXT: ret i32 [[A]] 1211; 1212entry: 1213 br label %r 1214unreachableblock1: 1215 %B = call i32 @deadblockcall_helper(i32 %B) 1216 ret i32 %B 1217unreachableblock2: 1218 %C = call i32 @deadblockcall1(i32 %C) 1219 br label %r 1220r: 1221 %PHI = phi i32 [%A, %entry], [%C, %unreachableblock2] 1222 ret i32 %PHI 1223} 1224 1225define i32 @deadblockphi2(i32 %A) #0 { 1226; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 1227; CHECK-LABEL: define {{[^@]+}}@deadblockphi2 1228; CHECK-SAME: (i32 returned [[A:%.*]]) #[[ATTR0]] { 1229; CHECK-NEXT: entry: 1230; CHECK-NEXT: br label [[R:%.*]] 1231; CHECK: unreachableblock1: 1232; CHECK-NEXT: unreachable 1233; CHECK: unreachableblock2: 1234; CHECK-NEXT: unreachable 1235; CHECK: unreachableblock3: 1236; CHECK-NEXT: unreachable 1237; CHECK: r: 1238; CHECK-NEXT: ret i32 [[A]] 1239; 1240entry: 1241 br label %r 1242unreachableblock1: 1243 %B = call i32 @deadblockcall_helper(i32 %B) 1244 br label %unreachableblock3 1245unreachableblock2: 1246 %C = call i32 @deadblockcall1(i32 %C) 1247 br label %unreachableblock3 1248unreachableblock3: 1249 %PHI1 = phi i32 [%B, %unreachableblock1], [%C, %unreachableblock2] 1250 br label %r 1251r: 1252 %PHI2 = phi i32 [%A, %entry], [%PHI1, %unreachableblock3] 1253 ret i32 %PHI2 1254} 1255 1256declare void @noreturn() noreturn; 1257 1258define i32 @deadblockphi3(i32 %A, i1 %c) #0 { 1259; TUNIT: Function Attrs: noinline nounwind uwtable 1260; TUNIT-LABEL: define {{[^@]+}}@deadblockphi3 1261; TUNIT-SAME: (i32 returned [[A:%.*]], i1 noundef [[C:%.*]]) #[[ATTR5]] { 1262; TUNIT-NEXT: entry: 1263; TUNIT-NEXT: br i1 [[C]], label [[R:%.*]], label [[UNREACHABLECALL:%.*]] 1264; TUNIT: unreachablecall: 1265; TUNIT-NEXT: call void @noreturn() #[[ATTR6:[0-9]+]] 1266; TUNIT-NEXT: unreachable 1267; TUNIT: unreachableblock2: 1268; TUNIT-NEXT: unreachable 1269; TUNIT: unreachableblock3: 1270; TUNIT-NEXT: unreachable 1271; TUNIT: r: 1272; TUNIT-NEXT: ret i32 [[A]] 1273; 1274; CGSCC: Function Attrs: noinline nounwind uwtable 1275; CGSCC-LABEL: define {{[^@]+}}@deadblockphi3 1276; CGSCC-SAME: (i32 returned [[A:%.*]], i1 noundef [[C:%.*]]) #[[ATTR4]] { 1277; CGSCC-NEXT: entry: 1278; CGSCC-NEXT: br i1 [[C]], label [[R:%.*]], label [[UNREACHABLECALL:%.*]] 1279; CGSCC: unreachablecall: 1280; CGSCC-NEXT: call void @noreturn() #[[ATTR5:[0-9]+]] 1281; CGSCC-NEXT: unreachable 1282; CGSCC: unreachableblock2: 1283; CGSCC-NEXT: unreachable 1284; CGSCC: unreachableblock3: 1285; CGSCC-NEXT: unreachable 1286; CGSCC: r: 1287; CGSCC-NEXT: ret i32 [[A]] 1288; 1289entry: 1290 br i1 %c, label %r, label %unreachablecall 1291unreachablecall: 1292 call void @noreturn(); 1293 %B = call i32 @deadblockcall_helper(i32 0) 1294 br label %unreachableblock3 1295unreachableblock2: 1296 %C = call i32 @deadblockcall1(i32 %C) 1297 br label %unreachableblock3 1298unreachableblock3: 1299 %PHI1 = phi i32 [%B, %unreachablecall], [%C, %unreachableblock2] 1300 br label %r 1301r: 1302 %PHI2 = phi i32 [%A, %entry], [%PHI1, %unreachableblock3] 1303 ret i32 %PHI2 1304} 1305 1306define weak_odr i32 @non_exact_0() { 1307; CHECK-LABEL: define {{[^@]+}}@non_exact_0() { 1308; CHECK-NEXT: ret i32 0 1309; 1310 ret i32 0 1311} 1312define weak_odr i32 @non_exact_1(i32 %a) { 1313; CHECK-LABEL: define {{[^@]+}}@non_exact_1 1314; CHECK-SAME: (i32 [[A:%.*]]) { 1315; CHECK-NEXT: ret i32 [[A]] 1316; 1317 ret i32 %a 1318} 1319define weak_odr i32 @non_exact_2(i32 returned %a) { 1320; CHECK-LABEL: define {{[^@]+}}@non_exact_2 1321; CHECK-SAME: (i32 returned [[A:%.*]]) { 1322; CHECK-NEXT: ret i32 [[A]] 1323; 1324 ret i32 %a 1325} 1326define weak_odr align 16 ptr @non_exact_3(ptr align 32 returned %a) { 1327; CHECK-LABEL: define {{[^@]+}}@non_exact_3 1328; CHECK-SAME: (ptr returned align 32 [[A:%.*]]) { 1329; CHECK-NEXT: ret ptr [[A]] 1330; 1331 ret ptr %a 1332} 1333define weak_odr align 16 ptr @non_exact_4(ptr align 32 %a) { 1334; CHECK-LABEL: define {{[^@]+}}@non_exact_4 1335; CHECK-SAME: (ptr align 32 [[A:%.*]]) { 1336; CHECK-NEXT: ret ptr [[A]] 1337; 1338 ret ptr %a 1339} 1340; We can use the alignment information of the weak function non_exact_3 argument 1341; because it was given to us and not derived. 1342; We can use the return information of the weak function non_exact_4. 1343; %c2 and %c3 should be replaced but not %c0 or %c1! 1344define i32 @exact(ptr align 8 %a, ptr align 8 %b) { 1345; CHECK-LABEL: define {{[^@]+}}@exact 1346; CHECK-SAME: (ptr align 8 [[A:%.*]], ptr align 8 [[B:%.*]]) { 1347; CHECK-NEXT: [[C0:%.*]] = call i32 @non_exact_0() 1348; CHECK-NEXT: [[C1:%.*]] = call i32 @non_exact_1(i32 noundef 1) 1349; CHECK-NEXT: [[C2:%.*]] = call i32 @non_exact_2(i32 noundef 2) 1350; CHECK-NEXT: [[C3:%.*]] = call align 32 ptr @non_exact_3(ptr align 32 [[A]]) 1351; CHECK-NEXT: [[C4:%.*]] = call align 16 ptr @non_exact_4(ptr align 32 [[B]]) 1352; CHECK-NEXT: [[C3L:%.*]] = load i32, ptr [[A]], align 32 1353; CHECK-NEXT: [[C4L:%.*]] = load i32, ptr [[C4]], align 16 1354; CHECK-NEXT: [[ADD1:%.*]] = add i32 [[C0]], [[C1]] 1355; CHECK-NEXT: [[ADD2:%.*]] = add i32 [[ADD1]], 2 1356; CHECK-NEXT: [[ADD3:%.*]] = add i32 [[ADD2]], [[C3L]] 1357; CHECK-NEXT: [[ADD4:%.*]] = add i32 [[ADD3]], [[C4L]] 1358; CHECK-NEXT: ret i32 [[ADD4]] 1359; 1360 %c0 = call i32 @non_exact_0() 1361 %c1 = call i32 @non_exact_1(i32 1) 1362 %c2 = call i32 @non_exact_2(i32 2) 1363 %c3 = call ptr @non_exact_3(ptr %a) 1364 %c4 = call ptr @non_exact_4(ptr %b) 1365 %c3l = load i32, ptr %c3 1366 %c4l = load i32, ptr %c4 1367 %add1 = add i32 %c0, %c1 1368 %add2 = add i32 %add1, %c2 1369 %add3 = add i32 %add2, %c3l 1370 %add4 = add i32 %add3, %c4l 1371 ret i32 %add4 1372} 1373 1374@G = external global i8 1375define ptr @ret_const() #0 { 1376; CHECK: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 1377; CHECK-LABEL: define {{[^@]+}}@ret_const 1378; CHECK-SAME: () #[[ATTR0]] { 1379; CHECK-NEXT: ret ptr @G 1380; 1381 ret ptr @G 1382} 1383define ptr @use_const() #0 { 1384; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 1385; TUNIT-LABEL: define {{[^@]+}}@use_const 1386; TUNIT-SAME: () #[[ATTR0]] { 1387; TUNIT-NEXT: ret ptr @G 1388; 1389; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 1390; CGSCC-LABEL: define {{[^@]+}}@use_const 1391; CGSCC-SAME: () #[[ATTR3]] { 1392; CGSCC-NEXT: [[C:%.*]] = call noundef nonnull dereferenceable(1) ptr @ret_const() #[[ATTR10:[0-9]+]] 1393; CGSCC-NEXT: ret ptr [[C]] 1394; 1395 %c = call ptr @ret_const() 1396 ret ptr %c 1397} 1398define ptr @dont_use_const() #0 { 1399; TUNIT: Function Attrs: mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable 1400; TUNIT-LABEL: define {{[^@]+}}@dont_use_const 1401; TUNIT-SAME: () #[[ATTR0]] { 1402; TUNIT-NEXT: ret ptr @G 1403; 1404; CGSCC: Function Attrs: mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable 1405; CGSCC-LABEL: define {{[^@]+}}@dont_use_const 1406; CGSCC-SAME: () #[[ATTR3]] { 1407; CGSCC-NEXT: [[C:%.*]] = musttail call noundef nonnull dereferenceable(1) ptr @ret_const() #[[ATTR10]] 1408; CGSCC-NEXT: ret ptr [[C]] 1409; 1410 %c = musttail call ptr @ret_const() 1411 ret ptr %c 1412} 1413 1414; UTC_ARGS: --disable 1415; 1416; Verify we do not derive constraints for @_Z3fooP1X as if it was returning `null`. 1417; 1418; CHEKC-NOT: noalias 1419; CHECK-NOT: align 536870912 1420 1421%struct.Y = type { %struct.X } 1422%struct.X = type { ptr } 1423 1424@_ZTI1X = external dso_local constant { ptr, ptr }, align 8 1425@_ZTI1Y = external dso_local constant { ptr, ptr, ptr }, align 8 1426 1427define internal ptr @_ZN1Y3barEv(ptr %this) align 2 { 1428entry: 1429 ret ptr %this 1430} 1431 1432define dso_local ptr @_Z3fooP1X(ptr %x) { 1433entry: 1434 %0 = icmp eq ptr %x, null 1435 br i1 %0, label %dynamic_cast.null, label %dynamic_cast.notnull 1436 1437dynamic_cast.notnull: ; preds = %entry 1438 %1 = call ptr @__dynamic_cast(ptr %x, ptr @_ZTI1X, ptr @_ZTI1Y, i64 0) #2 1439 br label %dynamic_cast.end 1440 1441dynamic_cast.null: ; preds = %entry 1442 br label %dynamic_cast.end 1443 1444dynamic_cast.end: ; preds = %dynamic_cast.null, %dynamic_cast.notnull 1445 %QQ5 = phi ptr [ %1, %dynamic_cast.notnull ], [ null, %dynamic_cast.null ] 1446 %call = call ptr @_ZN1Y3barEv(ptr %QQ5) 1447 ret ptr %call 1448} 1449 1450declare dso_local ptr @__dynamic_cast(ptr, ptr, ptr, i64) 1451 1452; UTC_ARGS: --enable 1453 1454; This does not return %arg, @recGood does. 1455 1456define internal i32 @recBad(i1 %c, i32 %arg) { 1457; TUNIT: Function Attrs: nofree nosync nounwind memory(none) 1458; TUNIT-LABEL: define {{[^@]+}}@recBad 1459; TUNIT-SAME: (i1 noundef [[C:%.*]], i32 [[ARG:%.*]]) #[[ATTR8]] { 1460; TUNIT-NEXT: [[ADD:%.*]] = add i32 [[ARG]], 1 1461; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 1462; TUNIT: t: 1463; TUNIT-NEXT: [[R:%.*]] = call i32 @recBad(i1 noundef false, i32 [[ADD]]) #[[ATTR8]] 1464; TUNIT-NEXT: ret i32 [[ADD]] 1465; TUNIT: f: 1466; TUNIT-NEXT: ret i32 [[ARG]] 1467; 1468; CGSCC: Function Attrs: nofree nosync nounwind memory(none) 1469; CGSCC-LABEL: define {{[^@]+}}@recBad 1470; CGSCC-SAME: (i1 noundef [[C:%.*]], i32 [[ARG:%.*]]) #[[ATTR7]] { 1471; CGSCC-NEXT: [[ADD:%.*]] = add i32 [[ARG]], 1 1472; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 1473; CGSCC: t: 1474; CGSCC-NEXT: [[R:%.*]] = call i32 @recBad(i1 noundef false, i32 [[ADD]]) #[[ATTR7]] 1475; CGSCC-NEXT: ret i32 [[ADD]] 1476; CGSCC: f: 1477; CGSCC-NEXT: ret i32 [[ARG]] 1478; 1479 %add = add i32 %arg, 1 1480 br i1 %c, label %t, label %f 1481t: 1482 %r = call i32 @recBad(i1 false, i32 %add) 1483 ret i32 %r 1484f: 1485 ret i32 %arg 1486} 1487 1488define i32 @recBadCaller(i1 %cQ, i32 %argQ) { 1489; TUNIT: Function Attrs: nofree norecurse nosync nounwind memory(none) 1490; TUNIT-LABEL: define {{[^@]+}}@recBadCaller 1491; TUNIT-SAME: (i1 [[CQ:%.*]], i32 [[ARGQ:%.*]]) #[[ATTR9:[0-9]+]] { 1492; TUNIT-NEXT: [[RQ:%.*]] = call i32 @recBad(i1 noundef [[CQ]], i32 [[ARGQ]]) #[[ATTR8]] 1493; TUNIT-NEXT: ret i32 [[RQ]] 1494; 1495; CGSCC: Function Attrs: nofree nosync nounwind memory(none) 1496; CGSCC-LABEL: define {{[^@]+}}@recBadCaller 1497; CGSCC-SAME: (i1 noundef [[CQ:%.*]], i32 [[ARGQ:%.*]]) #[[ATTR7]] { 1498; CGSCC-NEXT: [[RQ:%.*]] = call i32 @recBad(i1 noundef [[CQ]], i32 [[ARGQ]]) #[[ATTR7]] 1499; CGSCC-NEXT: ret i32 [[RQ]] 1500; 1501 %rQ = call i32 @recBad(i1 %cQ, i32 %argQ) 1502 ret i32 %rQ 1503} 1504 1505define internal i32 @recGood(i1 %c, i32 %arg) { 1506; TUNIT: Function Attrs: nofree nosync nounwind memory(none) 1507; TUNIT-LABEL: define {{[^@]+}}@recGood 1508; TUNIT-SAME: (i1 noundef [[C:%.*]], i32 returned [[ARG:%.*]]) #[[ATTR8]] { 1509; TUNIT-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 1510; TUNIT: t: 1511; TUNIT-NEXT: [[R:%.*]] = call i32 @recGood(i1 noundef false, i32 [[ARG]]) #[[ATTR8]] 1512; TUNIT-NEXT: ret i32 [[ARG]] 1513; TUNIT: f: 1514; TUNIT-NEXT: ret i32 [[ARG]] 1515; 1516; CGSCC: Function Attrs: nofree nosync nounwind memory(none) 1517; CGSCC-LABEL: define {{[^@]+}}@recGood 1518; CGSCC-SAME: (i1 noundef [[C:%.*]], i32 returned [[ARG:%.*]]) #[[ATTR7]] { 1519; CGSCC-NEXT: br i1 [[C]], label [[T:%.*]], label [[F:%.*]] 1520; CGSCC: t: 1521; CGSCC-NEXT: [[R:%.*]] = call i32 @recGood(i1 noundef false, i32 [[ARG]]) #[[ATTR7]] 1522; CGSCC-NEXT: ret i32 [[ARG]] 1523; CGSCC: f: 1524; CGSCC-NEXT: ret i32 [[ARG]] 1525; 1526 br i1 %c, label %t, label %f 1527t: 1528 %r = call i32 @recGood(i1 false, i32 %arg) 1529 ret i32 %r 1530f: 1531 ret i32 %arg 1532} 1533 1534define i32 @recGoodCaller(i1 %cQ, i32 %argQ) { 1535; TUNIT: Function Attrs: nofree norecurse nosync nounwind memory(none) 1536; TUNIT-LABEL: define {{[^@]+}}@recGoodCaller 1537; TUNIT-SAME: (i1 [[CQ:%.*]], i32 returned [[ARGQ:%.*]]) #[[ATTR9]] { 1538; TUNIT-NEXT: [[RQ:%.*]] = call i32 @recGood(i1 noundef [[CQ]], i32 [[ARGQ]]) #[[ATTR8]] 1539; TUNIT-NEXT: ret i32 [[ARGQ]] 1540; 1541; CGSCC: Function Attrs: nofree nosync nounwind memory(none) 1542; CGSCC-LABEL: define {{[^@]+}}@recGoodCaller 1543; CGSCC-SAME: (i1 noundef [[CQ:%.*]], i32 [[ARGQ:%.*]]) #[[ATTR7]] { 1544; CGSCC-NEXT: [[RQ:%.*]] = call i32 @recGood(i1 noundef [[CQ]], i32 [[ARGQ]]) #[[ATTR7]] 1545; CGSCC-NEXT: ret i32 [[RQ]] 1546; 1547 %rQ = call i32 @recGood(i1 %cQ, i32 %argQ) 1548 ret i32 %rQ 1549} 1550 1551attributes #0 = { noinline nounwind uwtable } 1552;. 1553; TUNIT: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable } 1554; TUNIT: attributes #[[ATTR1]] = { nofree noinline nosync nounwind memory(none) uwtable } 1555; TUNIT: attributes #[[ATTR2]] = { nofree noinline norecurse nosync nounwind memory(none) uwtable } 1556; TUNIT: attributes #[[ATTR3]] = { nofree noinline nosync nounwind memory(argmem: read) uwtable } 1557; TUNIT: attributes #[[ATTR4]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable } 1558; TUNIT: attributes #[[ATTR5]] = { noinline nounwind uwtable } 1559; TUNIT: attributes #[[ATTR6]] = { noreturn } 1560; TUNIT: attributes #[[ATTR7:[0-9]+]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 1561; TUNIT: attributes #[[ATTR8]] = { nofree nosync nounwind memory(none) } 1562; TUNIT: attributes #[[ATTR9]] = { nofree norecurse nosync nounwind memory(none) } 1563; TUNIT: attributes #[[ATTR10]] = { nofree nosync nounwind memory(read) } 1564; TUNIT: attributes #[[ATTR11]] = { nounwind } 1565; TUNIT: attributes #[[ATTR12:[0-9]+]] = { nounwind memory(none) } 1566;. 1567; CGSCC: attributes #[[ATTR0]] = { mustprogress nofree noinline norecurse nosync nounwind willreturn memory(none) uwtable } 1568; CGSCC: attributes #[[ATTR1]] = { nofree noinline nosync nounwind memory(none) uwtable } 1569; CGSCC: attributes #[[ATTR2]] = { nofree noinline nosync nounwind memory(argmem: read) uwtable } 1570; CGSCC: attributes #[[ATTR3]] = { mustprogress nofree noinline nosync nounwind willreturn memory(none) uwtable } 1571; CGSCC: attributes #[[ATTR4]] = { noinline nounwind uwtable } 1572; CGSCC: attributes #[[ATTR5]] = { noreturn } 1573; CGSCC: attributes #[[ATTR6:[0-9]+]] = { mustprogress nofree norecurse nosync nounwind willreturn memory(none) } 1574; CGSCC: attributes #[[ATTR7]] = { nofree nosync nounwind memory(none) } 1575; CGSCC: attributes #[[ATTR8]] = { nofree nosync nounwind memory(read) } 1576; CGSCC: attributes #[[ATTR9]] = { nounwind } 1577; CGSCC: attributes #[[ATTR10]] = { nofree nosync willreturn } 1578;. 1579