1; RUN: opt -loop-idiom -mtriple=armv7a < %s -S | FileCheck -check-prefix=LZCNT --check-prefix=ALL %s 2; RUN: opt -loop-idiom -mtriple=armv4t < %s -S | FileCheck -check-prefix=NOLZCNT --check-prefix=ALL %s 3 4; Recognize CTLZ builtin pattern. 5; Here we'll just convert loop to countable, 6; so do not insert builtin if CPU do not support CTLZ 7; 8; int ctlz_and_other(int n, char *a) 9; { 10; n = n >= 0 ? n : -n; 11; int i = 0, n0 = n; 12; while(n >>= 1) { 13; a[i] = (n0 & (1 << i)) ? 1 : 0; 14; i++; 15; } 16; return i; 17; } 18; 19; LZCNT: entry 20; LZCNT: %0 = call i32 @llvm.ctlz.i32(i32 %shr8, i1 true) 21; LZCNT-NEXT: %1 = sub i32 32, %0 22; LZCNT-NEXT: %2 = zext i32 %1 to i64 23; LZCNT: %indvars.iv.next.lcssa = phi i64 [ %2, %while.body ] 24; LZCNT: %4 = trunc i64 %indvars.iv.next.lcssa to i32 25; LZCNT: %i.0.lcssa = phi i32 [ 0, %entry ], [ %4, %while.end.loopexit ] 26; LZCNT: ret i32 %i.0.lcssa 27 28; NOLZCNT: entry 29; NOLZCNT-NOT: @llvm.ctlz 30 31; Function Attrs: norecurse nounwind uwtable 32define i32 @ctlz_and_other(i32 %n, i8* nocapture %a) { 33entry: 34 %c = icmp sgt i32 %n, 0 35 %negn = sub nsw i32 0, %n 36 %abs_n = select i1 %c, i32 %n, i32 %negn 37 %shr8 = lshr i32 %abs_n, 1 38 %tobool9 = icmp eq i32 %shr8, 0 39 br i1 %tobool9, label %while.end, label %while.body.preheader 40 41while.body.preheader: ; preds = %entry 42 br label %while.body 43 44while.body: ; preds = %while.body.preheader, %while.body 45 %indvars.iv = phi i64 [ %indvars.iv.next, %while.body ], [ 0, %while.body.preheader ] 46 %shr11 = phi i32 [ %shr, %while.body ], [ %shr8, %while.body.preheader ] 47 %0 = trunc i64 %indvars.iv to i32 48 %shl = shl i32 1, %0 49 %and = and i32 %shl, %abs_n 50 %tobool1 = icmp ne i32 %and, 0 51 %conv = zext i1 %tobool1 to i8 52 %arrayidx = getelementptr inbounds i8, i8* %a, i64 %indvars.iv 53 store i8 %conv, i8* %arrayidx, align 1 54 %indvars.iv.next = add nuw i64 %indvars.iv, 1 55 %shr = ashr i32 %shr11, 1 56 %tobool = icmp eq i32 %shr, 0 57 br i1 %tobool, label %while.end.loopexit, label %while.body 58 59while.end.loopexit: ; preds = %while.body 60 %1 = trunc i64 %indvars.iv.next to i32 61 br label %while.end 62 63while.end: ; preds = %while.end.loopexit, %entry 64 %i.0.lcssa = phi i32 [ 0, %entry ], [ %1, %while.end.loopexit ] 65 ret i32 %i.0.lcssa 66} 67 68; Recognize CTLZ builtin pattern. 69; Here it will replace the loop - 70; assume builtin is always profitable. 71; 72; int ctlz_zero_check(int n) 73; { 74; n = n >= 0 ? n : -n; 75; int i = 0; 76; while(n) { 77; n >>= 1; 78; i++; 79; } 80; return i; 81; } 82; 83; ALL: entry 84; ALL: %0 = call i32 @llvm.ctlz.i32(i32 %abs_n, i1 true) 85; ALL-NEXT: %1 = sub i32 32, %0 86; ALL: %inc.lcssa = phi i32 [ %1, %while.body ] 87; ALL: %i.0.lcssa = phi i32 [ 0, %entry ], [ %inc.lcssa, %while.end.loopexit ] 88; ALL: ret i32 %i.0.lcssa 89 90; Function Attrs: norecurse nounwind readnone uwtable 91define i32 @ctlz_zero_check(i32 %n) { 92entry: 93 %c = icmp sgt i32 %n, 0 94 %negn = sub nsw i32 0, %n 95 %abs_n = select i1 %c, i32 %n, i32 %negn 96 %tobool4 = icmp eq i32 %abs_n, 0 97 br i1 %tobool4, label %while.end, label %while.body.preheader 98 99while.body.preheader: ; preds = %entry 100 br label %while.body 101 102while.body: ; preds = %while.body.preheader, %while.body 103 %i.06 = phi i32 [ %inc, %while.body ], [ 0, %while.body.preheader ] 104 %n.addr.05 = phi i32 [ %shr, %while.body ], [ %abs_n, %while.body.preheader ] 105 %shr = ashr i32 %n.addr.05, 1 106 %inc = add nsw i32 %i.06, 1 107 %tobool = icmp eq i32 %shr, 0 108 br i1 %tobool, label %while.end.loopexit, label %while.body 109 110while.end.loopexit: ; preds = %while.body 111 br label %while.end 112 113while.end: ; preds = %while.end.loopexit, %entry 114 %i.0.lcssa = phi i32 [ 0, %entry ], [ %inc, %while.end.loopexit ] 115 ret i32 %i.0.lcssa 116} 117 118; Recognize CTLZ builtin pattern. 119; Here it will replace the loop - 120; assume builtin is always profitable. 121; 122; int ctlz(int n) 123; { 124; n = n >= 0 ? n : -n; 125; int i = 0; 126; while(n >>= 1) { 127; i++; 128; } 129; return i; 130; } 131; 132; ALL: entry 133; ALL: %0 = ashr i32 %abs_n, 1 134; ALL-NEXT: %1 = call i32 @llvm.ctlz.i32(i32 %0, i1 false) 135; ALL-NEXT: %2 = sub i32 32, %1 136; ALL-NEXT: %3 = add i32 %2, 1 137; ALL: %i.0.lcssa = phi i32 [ %2, %while.cond ] 138; ALL: ret i32 %i.0.lcssa 139 140; Function Attrs: norecurse nounwind readnone uwtable 141define i32 @ctlz(i32 %n) { 142entry: 143 %c = icmp sgt i32 %n, 0 144 %negn = sub nsw i32 0, %n 145 %abs_n = select i1 %c, i32 %n, i32 %negn 146 br label %while.cond 147 148while.cond: ; preds = %while.cond, %entry 149 %n.addr.0 = phi i32 [ %abs_n, %entry ], [ %shr, %while.cond ] 150 %i.0 = phi i32 [ 0, %entry ], [ %inc, %while.cond ] 151 %shr = ashr i32 %n.addr.0, 1 152 %tobool = icmp eq i32 %shr, 0 153 %inc = add nsw i32 %i.0, 1 154 br i1 %tobool, label %while.end, label %while.cond 155 156while.end: ; preds = %while.cond 157 ret i32 %i.0 158} 159 160; Recognize CTLZ builtin pattern. 161; Here it will replace the loop - 162; assume builtin is always profitable. 163; 164; int ctlz_add(int n, int i0) 165; { 166; n = n >= 0 ? n : -n; 167; int i = i0; 168; while(n >>= 1) { 169; i++; 170; } 171; return i; 172; } 173; 174; ALL: entry 175; ALL: %0 = ashr i32 %abs_n, 1 176; ALL-NEXT: %1 = call i32 @llvm.ctlz.i32(i32 %0, i1 false) 177; ALL-NEXT: %2 = sub i32 32, %1 178; ALL-NEXT: %3 = add i32 %2, 1 179; ALL-NEXT: %4 = add i32 %2, %i0 180; ALL: %i.0.lcssa = phi i32 [ %4, %while.cond ] 181; ALL: ret i32 %i.0.lcssa 182; 183; Function Attrs: norecurse nounwind readnone uwtable 184define i32 @ctlz_add(i32 %n, i32 %i0) { 185entry: 186 %c = icmp sgt i32 %n, 0 187 %negn = sub nsw i32 0, %n 188 %abs_n = select i1 %c, i32 %n, i32 %negn 189 br label %while.cond 190 191while.cond: ; preds = %while.cond, %entry 192 %n.addr.0 = phi i32 [ %abs_n, %entry ], [ %shr, %while.cond ] 193 %i.0 = phi i32 [ %i0, %entry ], [ %inc, %while.cond ] 194 %shr = ashr i32 %n.addr.0, 1 195 %tobool = icmp eq i32 %shr, 0 196 %inc = add nsw i32 %i.0, 1 197 br i1 %tobool, label %while.end, label %while.cond 198 199while.end: ; preds = %while.cond 200 ret i32 %i.0 201} 202 203; Recognize CTLZ builtin pattern. 204; Here it will replace the loop - 205; assume builtin is always profitable. 206; 207; int ctlz_sext(short in) 208; { 209; int n = in; 210; if (in < 0) 211; n = -n; 212; int i = 0; 213; while(n >>= 1) { 214; i++; 215; } 216; return i; 217; } 218; 219; ALL: entry 220; ALL: %0 = ashr i32 %abs_n, 1 221; ALL-NEXT: %1 = call i32 @llvm.ctlz.i32(i32 %0, i1 false) 222; ALL-NEXT: %2 = sub i32 32, %1 223; ALL-NEXT: %3 = add i32 %2, 1 224; ALL: %i.0.lcssa = phi i32 [ %2, %while.cond ] 225; ALL: ret i32 %i.0.lcssa 226 227; Function Attrs: norecurse nounwind readnone uwtable 228define i32 @ctlz_sext(i16 %in) { 229entry: 230 %n = sext i16 %in to i32 231 %c = icmp sgt i16 %in, 0 232 %negn = sub nsw i32 0, %n 233 %abs_n = select i1 %c, i32 %n, i32 %negn 234 br label %while.cond 235 236while.cond: ; preds = %while.cond, %entry 237 %n.addr.0 = phi i32 [ %abs_n, %entry ], [ %shr, %while.cond ] 238 %i.0 = phi i32 [ 0, %entry ], [ %inc, %while.cond ] 239 %shr = ashr i32 %n.addr.0, 1 240 %tobool = icmp eq i32 %shr, 0 241 %inc = add nsw i32 %i.0, 1 242 br i1 %tobool, label %while.end, label %while.cond 243 244while.end: ; preds = %while.cond 245 ret i32 %i.0 246} 247