1; RUN: opt -mtriple amdgcn-unknown-amdhsa -analyze -divergence -use-gpu-divergence-analysis %s | FileCheck %s 2 3; divergent loop (H<header><exiting to X>, B<exiting to Y>) 4; the divergent join point in %exit is obscured by uniform control joining in %X 5define amdgpu_kernel void @hidden_loop_diverge(i32 %n, i32 %a, i32 %b) #0 { 6; CHECK-LABEL: Printing analysis 'Legacy Divergence Analysis' for function 'hidden_loop_diverge': 7; CHECK-NOT: DIVERGENT: %uni. 8; CHECK-NOT: DIVERGENT: br i1 %uni. 9 10entry: 11 %tid = call i32 @llvm.amdgcn.workitem.id.x() 12 %uni.cond = icmp slt i32 %a, 0 13 br i1 %uni.cond, label %X, label %H ; uniform 14 15H: 16 %uni.merge.h = phi i32 [ 0, %entry ], [ %uni.inc, %B ] 17 %div.exitx = icmp slt i32 %tid, 0 18 br i1 %div.exitx, label %X, label %B ; divergent branch 19; CHECK: DIVERGENT: %div.exitx = 20; CHECK: DIVERGENT: br i1 %div.exitx, 21 22B: 23 %uni.inc = add i32 %uni.merge.h, 1 24 %div.exity = icmp sgt i32 %tid, 0 25 br i1 %div.exity, label %Y, label %H ; divergent branch 26; CHECK: DIVERGENT: %div.exity = 27; CHECK: DIVERGENT: br i1 %div.exity, 28 29X: 30 %div.merge.x = phi i32 [ %a, %entry ], [ %uni.merge.h, %H ] ; temporal divergent phi 31 br i1 %uni.cond, label %Y, label %exit 32; CHECK: DIVERGENT: %div.merge.x = 33 34Y: 35 %div.merge.y = phi i32 [ 42, %X ], [ %b, %B ] 36 br label %exit 37; CHECK: DIVERGENT: %div.merge.y = 38 39exit: 40 %div.merge.exit = phi i32 [ %a, %X ], [ %b, %Y ] 41 ret void 42; CHECK: DIVERGENT: %div.merge.exit = 43} 44 45; divergent loop (H<header><exiting to X>, B<exiting to Y>) 46; the phi nodes in X and Y don't actually receive divergent values 47define amdgpu_kernel void @unobserved_loop_diverge(i32 %n, i32 %a, i32 %b) #0 { 48; CHECK-LABEL: Printing analysis 'Legacy Divergence Analysis' for function 'unobserved_loop_diverge': 49; CHECK-NOT: DIVERGENT: %uni. 50; CHECK-NOT: DIVERGENT: br i1 %uni. 51 52entry: 53 %tid = call i32 @llvm.amdgcn.workitem.id.x() 54 %uni.cond = icmp slt i32 %a, 0 55 br i1 %uni.cond, label %X, label %H ; uniform 56 57H: 58 %uni.merge.h = phi i32 [ 0, %entry ], [ %uni.inc, %B ] 59 %div.exitx = icmp slt i32 %tid, 0 60 br i1 %div.exitx, label %X, label %B ; divergent branch 61; CHECK: DIVERGENT: %div.exitx = 62; CHECK: DIVERGENT: br i1 %div.exitx, 63 64B: 65 %uni.inc = add i32 %uni.merge.h, 1 66 %div.exity = icmp sgt i32 %tid, 0 67 br i1 %div.exity, label %Y, label %H ; divergent branch 68; CHECK: DIVERGENT: %div.exity = 69; CHECK: DIVERGENT: br i1 %div.exity, 70 71X: 72 %uni.merge.x = phi i32 [ %a, %entry ], [ %b, %H ] 73 br label %exit 74 75Y: 76 %uni.merge.y = phi i32 [ %b, %B ] 77 br label %exit 78 79exit: 80 %div.merge.exit = phi i32 [ %a, %X ], [ %b, %Y ] 81 ret void 82; CHECK: DIVERGENT: %div.merge.exit = 83} 84 85; divergent loop (G<header>, L<exiting to D>) inside divergent loop (H<header>, B<exiting to X>, C<exiting to Y>, D, G, L) 86; the inner loop has no exit to top level. 87; the outer loop becomes divergent as its exiting branch in C is control-dependent on the inner loop's divergent loop exit in D. 88define amdgpu_kernel void @hidden_nestedloop_diverge(i32 %n, i32 %a, i32 %b) #0 { 89; CHECK-LABEL: Printing analysis 'Legacy Divergence Analysis' for function 'hidden_nestedloop_diverge': 90; CHECK-NOT: DIVERGENT: %uni. 91; CHECK-NOT: DIVERGENT: br i1 %uni. 92 93entry: 94 %tid = call i32 @llvm.amdgcn.workitem.id.x() 95 %uni.cond = icmp slt i32 %a, 0 96 %div.exitx = icmp slt i32 %tid, 0 97 br i1 %uni.cond, label %X, label %H 98 99H: 100 %uni.merge.h = phi i32 [ 0, %entry ], [ %uni.inc, %D ] 101 br i1 %uni.cond, label %G, label %B 102; CHECK: DIVERGENT: %div.exitx = 103 104B: 105 br i1 %uni.cond, label %X, label %C 106 107C: 108 br i1 %uni.cond, label %Y, label %D 109 110D: 111 %uni.inc = add i32 %uni.merge.h, 1 112 br label %H 113 114G: 115 br i1 %div.exitx, label %C, label %L 116; CHECK: DIVERGENT: br i1 %div.exitx, 117 118L: 119 br i1 %uni.cond, label %D, label %G 120 121X: 122 %uni.merge.x = phi i32 [ %a, %entry ], [ %uni.merge.h, %B ] 123 br i1 %uni.cond, label %Y, label %exit 124 125Y: 126 %div.merge.y = phi i32 [ 42, %X ], [ %b, %C ] 127 br label %exit 128; CHECK: DIVERGENT: %div.merge.y = 129 130exit: 131 %div.merge.exit = phi i32 [ %a, %X ], [ %b, %Y ] 132 ret void 133; CHECK: DIVERGENT: %div.merge.exit = 134} 135 136; divergent loop (G<header>, L<exiting to X>) in divergent loop (H<header>, B<exiting to C>, C, G, L) 137; the outer loop has no immediately divergent exiting edge. 138; the inner exiting edge is exiting to top-level through the outer loop causing both to become divergent. 139define amdgpu_kernel void @hidden_doublebreak_diverge(i32 %n, i32 %a, i32 %b) #0 { 140; CHECK-LABEL: Printing analysis 'Legacy Divergence Analysis' for function 'hidden_doublebreak_diverge': 141; CHECK-NOT: DIVERGENT: %uni. 142; CHECK-NOT: DIVERGENT: br i1 %uni. 143 144entry: 145 %tid = call i32 @llvm.amdgcn.workitem.id.x() 146 %uni.cond = icmp slt i32 %a, 0 147 %div.exitx = icmp slt i32 %tid, 0 148 br i1 %uni.cond, label %X, label %H 149 150H: 151 %uni.merge.h = phi i32 [ 0, %entry ], [ %uni.inc, %C ] 152 br i1 %uni.cond, label %G, label %B 153; CHECK: DIVERGENT: %div.exitx = 154 155B: 156 br i1 %uni.cond, label %Y, label %C 157 158C: 159 %uni.inc = add i32 %uni.merge.h, 1 160 br label %H 161 162G: 163 br i1 %div.exitx, label %X, label %L ; two-level break 164; CHECK: DIVERGENT: br i1 %div.exitx, 165 166L: 167 br i1 %uni.cond, label %C, label %G 168 169X: 170 %div.merge.x = phi i32 [ %a, %entry ], [ %uni.merge.h, %G ] ; temporal divergence 171 br label %Y 172; CHECK: DIVERGENT: %div.merge.x = 173 174Y: 175 %div.merge.y = phi i32 [ 42, %X ], [ %b, %B ] 176 ret void 177; CHECK: DIVERGENT: %div.merge.y = 178} 179 180; divergent loop (G<header>, L<exiting to D>) contained inside a uniform loop (H<header>, B, G, L , D<exiting to x>) 181define amdgpu_kernel void @hidden_containedloop_diverge(i32 %n, i32 %a, i32 %b) #0 { 182; CHECK-LABEL: Printing analysis 'Legacy Divergence Analysis' for function 'hidden_containedloop_diverge': 183; CHECK-NOT: DIVERGENT: %uni. 184; CHECK-NOT: DIVERGENT: br i1 %uni. 185 186entry: 187 %tid = call i32 @llvm.amdgcn.workitem.id.x() 188 %uni.cond = icmp slt i32 %a, 0 189 %div.exitx = icmp slt i32 %tid, 0 190 br i1 %uni.cond, label %X, label %H 191 192H: 193 %uni.merge.h = phi i32 [ 0, %entry ], [ %uni.inc.d, %D ] 194 br i1 %uni.cond, label %G, label %B 195; CHECK: DIVERGENT: %div.exitx = 196 197B: 198 %div.merge.b = phi i32 [ 42, %H ], [ %uni.merge.g, %G ] 199 br label %D 200; CHECK: DIVERGENT: %div.merge.b = 201 202G: 203 %uni.merge.g = phi i32 [ 123, %H ], [ %uni.inc.l, %L ] 204 br i1 %div.exitx, label %B, label %L 205; CHECK: DIVERGENT: br i1 %div.exitx, 206 207L: 208 %uni.inc.l = add i32 %uni.merge.g, 1 209 br i1 %uni.cond, label %G, label %D 210 211D: 212 %uni.inc.d = add i32 %uni.merge.h, 1 213 br i1 %uni.cond, label %X, label %H 214 215X: 216 %uni.merge.x = phi i32 [ %a, %entry ], [ %uni.inc.d, %D ] 217 ret void 218} 219 220declare i32 @llvm.amdgcn.workitem.id.x() #0 221 222attributes #0 = { nounwind readnone } 223