1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt -S -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -mtriple=x86_64-unknown-unknown -mattr=+bmi < %s | FileCheck %s 3; RUN: opt -S -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -mtriple=x86_64-unknown-unknown -mattr=+lzcnt < %s | FileCheck %s 4; RUN: opt -S -passes=simplifycfg -simplifycfg-require-and-preserve-domtree=1 -mtriple=x86_64-unknown-unknown < %s | FileCheck %s 5 6 7define i64 @test1(i64 %A) { 8; CHECK-LABEL: @test1( 9; CHECK-NEXT: entry: 10; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0 11; CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[A]], i1 true) 12; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]] 13; CHECK-NEXT: ret i64 [[SPEC_SELECT]] 14; 15entry: 16 %tobool = icmp eq i64 %A, 0 17 br i1 %tobool, label %cond.end, label %cond.true 18 19cond.true: ; preds = %entry 20 %0 = tail call i64 @llvm.ctlz.i64(i64 %A, i1 true) 21 br label %cond.end 22 23cond.end: ; preds = %entry, %cond.true 24 %cond = phi i64 [ %0, %cond.true ], [ 64, %entry ] 25 ret i64 %cond 26} 27 28define i32 @test2(i32 %A) { 29; CHECK-LABEL: @test2( 30; CHECK-NEXT: entry: 31; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0 32; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[A]], i1 true) 33; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]] 34; CHECK-NEXT: ret i32 [[SPEC_SELECT]] 35; 36entry: 37 %tobool = icmp eq i32 %A, 0 38 br i1 %tobool, label %cond.end, label %cond.true 39 40cond.true: ; preds = %entry 41 %0 = tail call i32 @llvm.ctlz.i32(i32 %A, i1 true) 42 br label %cond.end 43 44cond.end: ; preds = %entry, %cond.true 45 %cond = phi i32 [ %0, %cond.true ], [ 32, %entry ] 46 ret i32 %cond 47} 48 49 50define signext i16 @test3(i16 signext %A) { 51; CHECK-LABEL: @test3( 52; CHECK-NEXT: entry: 53; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0 54; CHECK-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.ctlz.i16(i16 [[A]], i1 true) 55; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]] 56; CHECK-NEXT: ret i16 [[SPEC_SELECT]] 57; 58entry: 59 %tobool = icmp eq i16 %A, 0 60 br i1 %tobool, label %cond.end, label %cond.true 61 62cond.true: ; preds = %entry 63 %0 = tail call i16 @llvm.ctlz.i16(i16 %A, i1 true) 64 br label %cond.end 65 66cond.end: ; preds = %entry, %cond.true 67 %cond = phi i16 [ %0, %cond.true ], [ 16, %entry ] 68 ret i16 %cond 69} 70 71 72define i64 @test1b(i64 %A) { 73; CHECK-LABEL: @test1b( 74; CHECK-NEXT: entry: 75; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[A:%.*]], 0 76; CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[A]], i1 true) 77; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i64 64, i64 [[TMP0]] 78; CHECK-NEXT: ret i64 [[SPEC_SELECT]] 79; 80entry: 81 %tobool = icmp eq i64 %A, 0 82 br i1 %tobool, label %cond.end, label %cond.true 83 84cond.true: ; preds = %entry 85 %0 = tail call i64 @llvm.cttz.i64(i64 %A, i1 true) 86 br label %cond.end 87 88cond.end: ; preds = %entry, %cond.true 89 %cond = phi i64 [ %0, %cond.true ], [ 64, %entry ] 90 ret i64 %cond 91} 92 93 94define i32 @test2b(i32 %A) { 95; CHECK-LABEL: @test2b( 96; CHECK-NEXT: entry: 97; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A:%.*]], 0 98; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[A]], i1 true) 99; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[TMP0]] 100; CHECK-NEXT: ret i32 [[SPEC_SELECT]] 101; 102entry: 103 %tobool = icmp eq i32 %A, 0 104 br i1 %tobool, label %cond.end, label %cond.true 105 106cond.true: ; preds = %entry 107 %0 = tail call i32 @llvm.cttz.i32(i32 %A, i1 true) 108 br label %cond.end 109 110cond.end: ; preds = %entry, %cond.true 111 %cond = phi i32 [ %0, %cond.true ], [ 32, %entry ] 112 ret i32 %cond 113} 114 115 116define signext i16 @test3b(i16 signext %A) { 117; CHECK-LABEL: @test3b( 118; CHECK-NEXT: entry: 119; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i16 [[A:%.*]], 0 120; CHECK-NEXT: [[TMP0:%.*]] = tail call i16 @llvm.cttz.i16(i16 [[A]], i1 true) 121; CHECK-NEXT: [[SPEC_SELECT:%.*]] = select i1 [[TOBOOL]], i16 16, i16 [[TMP0]] 122; CHECK-NEXT: ret i16 [[SPEC_SELECT]] 123; 124entry: 125 %tobool = icmp eq i16 %A, 0 126 br i1 %tobool, label %cond.end, label %cond.true 127 128cond.true: ; preds = %entry 129 %0 = tail call i16 @llvm.cttz.i16(i16 %A, i1 true) 130 br label %cond.end 131 132cond.end: ; preds = %entry, %cond.true 133 %cond = phi i16 [ %0, %cond.true ], [ 16, %entry ] 134 ret i16 %cond 135} 136 137; The following tests verify that calls to cttz/ctlz are speculated even if 138; basic block %cond.true has an extra zero extend/truncate which is "free" 139; for the target. 140 141define i64 @test1e(i32 %x) { 142; CHECK-LABEL: @test1e( 143; CHECK-NEXT: entry: 144; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0 145; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X]], i1 true) 146; CHECK-NEXT: [[PHITMP2:%.*]] = zext i32 [[TMP0]] to i64 147; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 32, i64 [[PHITMP2]] 148; CHECK-NEXT: ret i64 [[COND]] 149; 150entry: 151 %tobool = icmp eq i32 %x, 0 152 br i1 %tobool, label %cond.end, label %cond.true 153 154cond.true: ; preds = %entry 155 %0 = tail call i32 @llvm.cttz.i32(i32 %x, i1 true) 156 %phitmp2 = zext i32 %0 to i64 157 br label %cond.end 158 159cond.end: ; preds = %entry, %cond.true 160 %cond = phi i64 [ %phitmp2, %cond.true ], [ 32, %entry ] 161 ret i64 %cond 162} 163 164define i32 @test2e(i64 %x) { 165; CHECK-LABEL: @test2e( 166; CHECK-NEXT: entry: 167; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0 168; CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[X]], i1 true) 169; CHECK-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i32 170; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 64, i32 [[CAST]] 171; CHECK-NEXT: ret i32 [[COND]] 172; 173entry: 174 %tobool = icmp eq i64 %x, 0 175 br i1 %tobool, label %cond.end, label %cond.true 176 177cond.true: ; preds = %entry 178 %0 = tail call i64 @llvm.cttz.i64(i64 %x, i1 true) 179 %cast = trunc i64 %0 to i32 180 br label %cond.end 181 182cond.end: ; preds = %entry, %cond.true 183 %cond = phi i32 [ %cast, %cond.true ], [ 64, %entry ] 184 ret i32 %cond 185} 186 187define i64 @test3e(i32 %x) { 188; CHECK-LABEL: @test3e( 189; CHECK-NEXT: entry: 190; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0 191; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X]], i1 true) 192; CHECK-NEXT: [[PHITMP2:%.*]] = zext i32 [[TMP0]] to i64 193; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i64 32, i64 [[PHITMP2]] 194; CHECK-NEXT: ret i64 [[COND]] 195; 196entry: 197 %tobool = icmp eq i32 %x, 0 198 br i1 %tobool, label %cond.end, label %cond.true 199 200cond.true: ; preds = %entry 201 %0 = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true) 202 %phitmp2 = zext i32 %0 to i64 203 br label %cond.end 204 205cond.end: ; preds = %entry, %cond.true 206 %cond = phi i64 [ %phitmp2, %cond.true ], [ 32, %entry ] 207 ret i64 %cond 208} 209 210define i32 @test4e(i64 %x) { 211; CHECK-LABEL: @test4e( 212; CHECK-NEXT: entry: 213; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0 214; CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[X]], i1 true) 215; CHECK-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i32 216; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 64, i32 [[CAST]] 217; CHECK-NEXT: ret i32 [[COND]] 218; 219entry: 220 %tobool = icmp eq i64 %x, 0 221 br i1 %tobool, label %cond.end, label %cond.true 222 223cond.true: ; preds = %entry 224 %0 = tail call i64 @llvm.ctlz.i64(i64 %x, i1 true) 225 %cast = trunc i64 %0 to i32 226 br label %cond.end 227 228cond.end: ; preds = %entry, %cond.true 229 %cond = phi i32 [ %cast, %cond.true ], [ 64, %entry ] 230 ret i32 %cond 231} 232 233define i16 @test5e(i64 %x) { 234; CHECK-LABEL: @test5e( 235; CHECK-NEXT: entry: 236; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0 237; CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[X]], i1 true) 238; CHECK-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i16 239; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 64, i16 [[CAST]] 240; CHECK-NEXT: ret i16 [[COND]] 241; 242entry: 243 %tobool = icmp eq i64 %x, 0 244 br i1 %tobool, label %cond.end, label %cond.true 245 246cond.true: ; preds = %entry 247 %0 = tail call i64 @llvm.ctlz.i64(i64 %x, i1 true) 248 %cast = trunc i64 %0 to i16 249 br label %cond.end 250 251cond.end: ; preds = %entry, %cond.true 252 %cond = phi i16 [ %cast, %cond.true ], [ 64, %entry ] 253 ret i16 %cond 254} 255 256define i16 @test6e(i32 %x) { 257; CHECK-LABEL: @test6e( 258; CHECK-NEXT: entry: 259; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0 260; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[X]], i1 true) 261; CHECK-NEXT: [[CAST:%.*]] = trunc i32 [[TMP0]] to i16 262; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 32, i16 [[CAST]] 263; CHECK-NEXT: ret i16 [[COND]] 264; 265entry: 266 %tobool = icmp eq i32 %x, 0 267 br i1 %tobool, label %cond.end, label %cond.true 268 269cond.true: ; preds = %entry 270 %0 = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true) 271 %cast = trunc i32 %0 to i16 272 br label %cond.end 273 274cond.end: ; preds = %entry, %cond.true 275 %cond = phi i16 [ %cast, %cond.true ], [ 32, %entry ] 276 ret i16 %cond 277} 278 279define i16 @test7e(i64 %x) { 280; CHECK-LABEL: @test7e( 281; CHECK-NEXT: entry: 282; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i64 [[X:%.*]], 0 283; CHECK-NEXT: [[TMP0:%.*]] = tail call i64 @llvm.cttz.i64(i64 [[X]], i1 true) 284; CHECK-NEXT: [[CAST:%.*]] = trunc i64 [[TMP0]] to i16 285; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 64, i16 [[CAST]] 286; CHECK-NEXT: ret i16 [[COND]] 287; 288entry: 289 %tobool = icmp eq i64 %x, 0 290 br i1 %tobool, label %cond.end, label %cond.true 291 292cond.true: ; preds = %entry 293 %0 = tail call i64 @llvm.cttz.i64(i64 %x, i1 true) 294 %cast = trunc i64 %0 to i16 295 br label %cond.end 296 297cond.end: ; preds = %entry, %cond.true 298 %cond = phi i16 [ %cast, %cond.true ], [ 64, %entry ] 299 ret i16 %cond 300} 301 302define i16 @test8e(i32 %x) { 303; CHECK-LABEL: @test8e( 304; CHECK-NEXT: entry: 305; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[X:%.*]], 0 306; CHECK-NEXT: [[TMP0:%.*]] = tail call i32 @llvm.cttz.i32(i32 [[X]], i1 true) 307; CHECK-NEXT: [[CAST:%.*]] = trunc i32 [[TMP0]] to i16 308; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i16 32, i16 [[CAST]] 309; CHECK-NEXT: ret i16 [[COND]] 310; 311entry: 312 %tobool = icmp eq i32 %x, 0 313 br i1 %tobool, label %cond.end, label %cond.true 314 315cond.true: ; preds = %entry 316 %0 = tail call i32 @llvm.cttz.i32(i32 %x, i1 true) 317 %cast = trunc i32 %0 to i16 318 br label %cond.end 319 320cond.end: ; preds = %entry, %cond.true 321 %cond = phi i16 [ %cast, %cond.true ], [ 32, %entry ] 322 ret i16 %cond 323} 324 325 326declare i64 @llvm.ctlz.i64(i64, i1) 327declare i32 @llvm.ctlz.i32(i32, i1) 328declare i16 @llvm.ctlz.i16(i16, i1) 329declare i64 @llvm.cttz.i64(i64, i1) 330declare i32 @llvm.cttz.i32(i32, i1) 331declare i16 @llvm.cttz.i16(i16, i1) 332