1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py 2; RUN: opt < %s -passes=instcombine -S | FileCheck %s 3 4; Here we subtract two values, check that subtraction did not overflow AND 5; that the result is non-zero. This can be simplified just to a comparison 6; between the base and offset. 7 8declare void @use8(i8) 9declare void @use64(i64) 10declare void @use1(i1) 11 12declare {i8, i1} @llvm.usub.with.overflow(i8, i8) 13declare void @useagg({i8, i1}) 14 15declare void @llvm.assume(i1) 16 17; There is a number of base patterns.. 18 19define i1 @t0_noncanonical_ignoreme(i8 %base, i8 %offset) { 20; CHECK-LABEL: @t0_noncanonical_ignoreme( 21; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 22; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 23; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[OFFSET]], [[BASE]] 24; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 25; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 26; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 27; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[OFFSET]], [[BASE]] 28; CHECK-NEXT: ret i1 [[R]] 29; 30 %adjusted = sub i8 %base, %offset 31 call void @use8(i8 %adjusted) 32 %no_underflow = icmp ule i8 %adjusted, %base 33 call void @use1(i1 %no_underflow) 34 %not_null = icmp ne i8 %adjusted, 0 35 call void @use1(i1 %not_null) 36 %r = and i1 %not_null, %no_underflow 37 ret i1 %r 38} 39 40define i1 @t0_noncanonical_ignoreme_logical(i8 %base, i8 %offset) { 41; CHECK-LABEL: @t0_noncanonical_ignoreme_logical( 42; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 43; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 44; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[OFFSET]], [[BASE]] 45; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 46; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 47; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 48; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[OFFSET]], [[BASE]] 49; CHECK-NEXT: ret i1 [[R]] 50; 51 %adjusted = sub i8 %base, %offset 52 call void @use8(i8 %adjusted) 53 %no_underflow = icmp ule i8 %adjusted, %base 54 call void @use1(i1 %no_underflow) 55 %not_null = icmp ne i8 %adjusted, 0 56 call void @use1(i1 %not_null) 57 %r = select i1 %not_null, i1 %no_underflow, i1 false 58 ret i1 %r 59} 60 61define i1 @t1(i8 %base, i8 %offset) { 62; CHECK-LABEL: @t1( 63; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 64; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 65; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]] 66; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 67; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 68; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 69; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]] 70; CHECK-NEXT: ret i1 [[R]] 71; 72 %adjusted = sub i8 %base, %offset 73 call void @use8(i8 %adjusted) 74 %no_underflow = icmp uge i8 %base, %offset 75 call void @use1(i1 %no_underflow) 76 %not_null = icmp ne i8 %adjusted, 0 77 call void @use1(i1 %not_null) 78 %r = and i1 %not_null, %no_underflow 79 ret i1 %r 80} 81 82define i1 @t1_logical(i8 %base, i8 %offset) { 83; CHECK-LABEL: @t1_logical( 84; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 85; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 86; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]] 87; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 88; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 89; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 90; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]] 91; CHECK-NEXT: ret i1 [[R]] 92; 93 %adjusted = sub i8 %base, %offset 94 call void @use8(i8 %adjusted) 95 %no_underflow = icmp uge i8 %base, %offset 96 call void @use1(i1 %no_underflow) 97 %not_null = icmp ne i8 %adjusted, 0 98 call void @use1(i1 %not_null) 99 %r = select i1 %not_null, i1 %no_underflow, i1 false 100 ret i1 %r 101} 102define i1 @t1_strict(i8 %base, i8 %offset) { 103; CHECK-LABEL: @t1_strict( 104; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 105; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 106; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]] 107; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 108; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 109; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 110; CHECK-NEXT: ret i1 [[NO_UNDERFLOW]] 111; 112 %adjusted = sub i8 %base, %offset 113 call void @use8(i8 %adjusted) 114 %no_underflow = icmp ugt i8 %base, %offset ; same is valid for strict predicate 115 call void @use1(i1 %no_underflow) 116 %not_null = icmp ne i8 %adjusted, 0 117 call void @use1(i1 %not_null) 118 %r = and i1 %not_null, %no_underflow 119 ret i1 %r 120} 121 122define i1 @t1_strict_logical(i8 %base, i8 %offset) { 123; CHECK-LABEL: @t1_strict_logical( 124; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 125; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 126; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]] 127; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 128; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 129; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 130; CHECK-NEXT: ret i1 [[NO_UNDERFLOW]] 131; 132 %adjusted = sub i8 %base, %offset 133 call void @use8(i8 %adjusted) 134 %no_underflow = icmp ugt i8 %base, %offset ; same is valid for strict predicate 135 call void @use1(i1 %no_underflow) 136 %not_null = icmp ne i8 %adjusted, 0 137 call void @use1(i1 %not_null) 138 %r = select i1 %not_null, i1 %no_underflow, i1 false 139 ret i1 %r 140} 141 142define i1 @t2(i8 %base, i8 %offset) { 143; CHECK-LABEL: @t2( 144; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]]) 145; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]]) 146; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0 147; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 148; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1 149; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 150; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = xor i1 [[UNDERFLOW]], true 151; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 152; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 153; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] 154; CHECK-NEXT: ret i1 [[R]] 155; 156 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset) 157 call void @useagg({i8, i1} %agg) 158 %adjusted = extractvalue {i8, i1} %agg, 0 159 call void @use8(i8 %adjusted) 160 %underflow = extractvalue {i8, i1} %agg, 1 161 call void @use1(i1 %underflow) 162 %no_underflow = xor i1 %underflow, -1 163 call void @use1(i1 %no_underflow) 164 %not_null = icmp ne i8 %adjusted, 0 165 %r = and i1 %not_null, %no_underflow 166 ret i1 %r 167} 168 169define i1 @t2_logical(i8 %base, i8 %offset) { 170; CHECK-LABEL: @t2_logical( 171; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]]) 172; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]]) 173; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0 174; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 175; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1 176; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 177; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = xor i1 [[UNDERFLOW]], true 178; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 179; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 180; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] 181; CHECK-NEXT: ret i1 [[R]] 182; 183 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset) 184 call void @useagg({i8, i1} %agg) 185 %adjusted = extractvalue {i8, i1} %agg, 0 186 call void @use8(i8 %adjusted) 187 %underflow = extractvalue {i8, i1} %agg, 1 188 call void @use1(i1 %underflow) 189 %no_underflow = xor i1 %underflow, -1 190 call void @use1(i1 %no_underflow) 191 %not_null = icmp ne i8 %adjusted, 0 192 %r = select i1 %not_null, i1 %no_underflow, i1 false 193 ret i1 %r 194} 195 196; Commutativity 197 198define i1 @t3_commutability0(i8 %base, i8 %offset) { 199; CHECK-LABEL: @t3_commutability0( 200; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 201; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 202; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[OFFSET]], [[BASE]] 203; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 204; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 205; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 206; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[OFFSET]], [[BASE]] 207; CHECK-NEXT: ret i1 [[R]] 208; 209 %adjusted = sub i8 %base, %offset 210 call void @use8(i8 %adjusted) 211 %no_underflow = icmp ule i8 %offset, %base ; swapped 212 call void @use1(i1 %no_underflow) 213 %not_null = icmp ne i8 %adjusted, 0 214 call void @use1(i1 %not_null) 215 %r = and i1 %not_null, %no_underflow 216 ret i1 %r 217} 218 219define i1 @t3_commutability0_logical(i8 %base, i8 %offset) { 220; CHECK-LABEL: @t3_commutability0_logical( 221; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 222; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 223; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[OFFSET]], [[BASE]] 224; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 225; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 226; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 227; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[OFFSET]], [[BASE]] 228; CHECK-NEXT: ret i1 [[R]] 229; 230 %adjusted = sub i8 %base, %offset 231 call void @use8(i8 %adjusted) 232 %no_underflow = icmp ule i8 %offset, %base ; swapped 233 call void @use1(i1 %no_underflow) 234 %not_null = icmp ne i8 %adjusted, 0 235 call void @use1(i1 %not_null) 236 %r = select i1 %not_null, i1 %no_underflow, i1 false 237 ret i1 %r 238} 239define i1 @t4_commutability1(i8 %base, i8 %offset) { 240; CHECK-LABEL: @t4_commutability1( 241; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 242; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 243; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]] 244; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 245; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 246; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 247; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]] 248; CHECK-NEXT: ret i1 [[R]] 249; 250 %adjusted = sub i8 %base, %offset 251 call void @use8(i8 %adjusted) 252 %no_underflow = icmp uge i8 %base, %offset 253 call void @use1(i1 %no_underflow) 254 %not_null = icmp ne i8 %adjusted, 0 255 call void @use1(i1 %not_null) 256 %r = and i1 %no_underflow, %not_null ; swapped 257 ret i1 %r 258} 259 260define i1 @t4_commutability1_logical(i8 %base, i8 %offset) { 261; CHECK-LABEL: @t4_commutability1_logical( 262; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 263; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 264; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]] 265; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 266; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 267; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 268; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]] 269; CHECK-NEXT: ret i1 [[R]] 270; 271 %adjusted = sub i8 %base, %offset 272 call void @use8(i8 %adjusted) 273 %no_underflow = icmp uge i8 %base, %offset 274 call void @use1(i1 %no_underflow) 275 %not_null = icmp ne i8 %adjusted, 0 276 call void @use1(i1 %not_null) 277 %r = select i1 %no_underflow, i1 %not_null, i1 false ; swapped 278 ret i1 %r 279} 280define i1 @t5_commutability2(i8 %base, i8 %offset) { 281; CHECK-LABEL: @t5_commutability2( 282; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 283; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 284; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[OFFSET]], [[BASE]] 285; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 286; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 287; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 288; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]] 289; CHECK-NEXT: ret i1 [[R]] 290; 291 %adjusted = sub i8 %base, %offset 292 call void @use8(i8 %adjusted) 293 %no_underflow = icmp ule i8 %offset, %base ; swapped 294 call void @use1(i1 %no_underflow) 295 %not_null = icmp ne i8 %adjusted, 0 296 call void @use1(i1 %not_null) 297 %r = and i1 %no_underflow, %not_null ; swapped 298 ret i1 %r 299} 300 301define i1 @t5_commutability2_logical(i8 %base, i8 %offset) { 302; CHECK-LABEL: @t5_commutability2_logical( 303; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 304; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 305; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ule i8 [[OFFSET]], [[BASE]] 306; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 307; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[BASE]], [[OFFSET]] 308; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 309; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[BASE]], [[OFFSET]] 310; CHECK-NEXT: ret i1 [[R]] 311; 312 %adjusted = sub i8 %base, %offset 313 call void @use8(i8 %adjusted) 314 %no_underflow = icmp ule i8 %offset, %base ; swapped 315 call void @use1(i1 %no_underflow) 316 %not_null = icmp ne i8 %adjusted, 0 317 call void @use1(i1 %not_null) 318 %r = select i1 %no_underflow, i1 %not_null, i1 false ; swapped 319 ret i1 %r 320} 321 322define i1 @t6_commutability(i8 %base, i8 %offset) { 323; CHECK-LABEL: @t6_commutability( 324; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]]) 325; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]]) 326; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0 327; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 328; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1 329; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 330; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = xor i1 [[UNDERFLOW]], true 331; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 332; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 333; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] 334; CHECK-NEXT: ret i1 [[R]] 335; 336 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset) 337 call void @useagg({i8, i1} %agg) 338 %adjusted = extractvalue {i8, i1} %agg, 0 339 call void @use8(i8 %adjusted) 340 %underflow = extractvalue {i8, i1} %agg, 1 341 call void @use1(i1 %underflow) 342 %no_underflow = xor i1 %underflow, -1 343 call void @use1(i1 %no_underflow) 344 %not_null = icmp ne i8 %adjusted, 0 345 %r = and i1 %no_underflow, %not_null ; swapped 346 ret i1 %r 347} 348 349define i1 @t6_commutability_logical(i8 %base, i8 %offset) { 350; CHECK-LABEL: @t6_commutability_logical( 351; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]]) 352; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]]) 353; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0 354; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 355; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1 356; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 357; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = xor i1 [[UNDERFLOW]], true 358; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 359; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i8 [[ADJUSTED]], 0 360; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] 361; CHECK-NEXT: ret i1 [[R]] 362; 363 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset) 364 call void @useagg({i8, i1} %agg) 365 %adjusted = extractvalue {i8, i1} %agg, 0 366 call void @use8(i8 %adjusted) 367 %underflow = extractvalue {i8, i1} %agg, 1 368 call void @use1(i1 %underflow) 369 %no_underflow = xor i1 %underflow, -1 370 call void @use1(i1 %no_underflow) 371 %not_null = icmp ne i8 %adjusted, 0 372 %r = select i1 %no_underflow, i1 %not_null, i1 false ; swapped 373 ret i1 %r 374} 375 376; What if we were checking the opposite question, that we either got null, 377; or overflow happened? 378 379define i1 @t7(i8 %base, i8 %offset) { 380; CHECK-LABEL: @t7( 381; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 382; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 383; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]] 384; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 385; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[BASE]], [[OFFSET]] 386; CHECK-NEXT: call void @use1(i1 [[NULL]]) 387; CHECK-NEXT: [[R:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]] 388; CHECK-NEXT: ret i1 [[R]] 389; 390 %adjusted = sub i8 %base, %offset 391 call void @use8(i8 %adjusted) 392 %underflow = icmp ult i8 %base, %offset 393 call void @use1(i1 %underflow) 394 %null = icmp eq i8 %adjusted, 0 395 call void @use1(i1 %null) 396 %r = or i1 %null, %underflow 397 ret i1 %r 398} 399 400define i1 @t7_logical(i8 %base, i8 %offset) { 401; CHECK-LABEL: @t7_logical( 402; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 403; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 404; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]] 405; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 406; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[BASE]], [[OFFSET]] 407; CHECK-NEXT: call void @use1(i1 [[NULL]]) 408; CHECK-NEXT: [[R:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]] 409; CHECK-NEXT: ret i1 [[R]] 410; 411 %adjusted = sub i8 %base, %offset 412 call void @use8(i8 %adjusted) 413 %underflow = icmp ult i8 %base, %offset 414 call void @use1(i1 %underflow) 415 %null = icmp eq i8 %adjusted, 0 416 call void @use1(i1 %null) 417 %r = select i1 %null, i1 true, i1 %underflow 418 ret i1 %r 419} 420define i1 @t7_nonstrict(i8 %base, i8 %offset) { 421; CHECK-LABEL: @t7_nonstrict( 422; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 423; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 424; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]] 425; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 426; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[BASE]], [[OFFSET]] 427; CHECK-NEXT: call void @use1(i1 [[NULL]]) 428; CHECK-NEXT: ret i1 [[UNDERFLOW]] 429; 430 %adjusted = sub i8 %base, %offset 431 call void @use8(i8 %adjusted) 432 %underflow = icmp ule i8 %base, %offset ; same is valid for non-strict predicate 433 call void @use1(i1 %underflow) 434 %null = icmp eq i8 %adjusted, 0 435 call void @use1(i1 %null) 436 %r = or i1 %null, %underflow 437 ret i1 %r 438} 439 440define i1 @t7_nonstrict_logical(i8 %base, i8 %offset) { 441; CHECK-LABEL: @t7_nonstrict_logical( 442; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 443; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 444; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]] 445; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 446; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[BASE]], [[OFFSET]] 447; CHECK-NEXT: call void @use1(i1 [[NULL]]) 448; CHECK-NEXT: ret i1 [[UNDERFLOW]] 449; 450 %adjusted = sub i8 %base, %offset 451 call void @use8(i8 %adjusted) 452 %underflow = icmp ule i8 %base, %offset ; same is valid for non-strict predicate 453 call void @use1(i1 %underflow) 454 %null = icmp eq i8 %adjusted, 0 455 call void @use1(i1 %null) 456 %r = select i1 %null, i1 true, i1 %underflow 457 ret i1 %r 458} 459 460define i1 @t8(i8 %base, i8 %offset) { 461; CHECK-LABEL: @t8( 462; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]]) 463; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]]) 464; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0 465; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 466; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1 467; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 468; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0 469; CHECK-NEXT: [[R:%.*]] = or i1 [[NULL]], [[UNDERFLOW]] 470; CHECK-NEXT: ret i1 [[R]] 471; 472 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset) 473 call void @useagg({i8, i1} %agg) 474 %adjusted = extractvalue {i8, i1} %agg, 0 475 call void @use8(i8 %adjusted) 476 %underflow = extractvalue {i8, i1} %agg, 1 477 call void @use1(i1 %underflow) 478 %null = icmp eq i8 %adjusted, 0 479 %r = or i1 %null, %underflow 480 ret i1 %r 481} 482 483define i1 @t8_logical(i8 %base, i8 %offset) { 484; CHECK-LABEL: @t8_logical( 485; CHECK-NEXT: [[AGG:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[BASE:%.*]], i8 [[OFFSET:%.*]]) 486; CHECK-NEXT: call void @useagg({ i8, i1 } [[AGG]]) 487; CHECK-NEXT: [[ADJUSTED:%.*]] = extractvalue { i8, i1 } [[AGG]], 0 488; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 489; CHECK-NEXT: [[UNDERFLOW:%.*]] = extractvalue { i8, i1 } [[AGG]], 1 490; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 491; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[ADJUSTED]], 0 492; CHECK-NEXT: [[R:%.*]] = or i1 [[NULL]], [[UNDERFLOW]] 493; CHECK-NEXT: ret i1 [[R]] 494; 495 %agg = call {i8, i1} @llvm.usub.with.overflow(i8 %base, i8 %offset) 496 call void @useagg({i8, i1} %agg) 497 %adjusted = extractvalue {i8, i1} %agg, 0 498 call void @use8(i8 %adjusted) 499 %underflow = extractvalue {i8, i1} %agg, 1 500 call void @use1(i1 %underflow) 501 %null = icmp eq i8 %adjusted, 0 502 %r = select i1 %null, i1 true, i1 %underflow 503 ret i1 %r 504} 505 506; And these patterns also have commutative variants 507 508define i1 @t9_commutative(i8 %base, i8 %offset) { 509; CHECK-LABEL: @t9_commutative( 510; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 511; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 512; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]] 513; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 514; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[BASE]], [[OFFSET]] 515; CHECK-NEXT: call void @use1(i1 [[NULL]]) 516; CHECK-NEXT: [[R:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]] 517; CHECK-NEXT: ret i1 [[R]] 518; 519 %adjusted = sub i8 %base, %offset 520 call void @use8(i8 %adjusted) 521 %underflow = icmp ult i8 %base, %adjusted ; swapped 522 call void @use1(i1 %underflow) 523 %null = icmp eq i8 %adjusted, 0 524 call void @use1(i1 %null) 525 %r = or i1 %null, %underflow 526 ret i1 %r 527} 528 529define i1 @t9_commutative_logical(i8 %base, i8 %offset) { 530; CHECK-LABEL: @t9_commutative_logical( 531; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 532; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 533; CHECK-NEXT: [[UNDERFLOW:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]] 534; CHECK-NEXT: call void @use1(i1 [[UNDERFLOW]]) 535; CHECK-NEXT: [[NULL:%.*]] = icmp eq i8 [[BASE]], [[OFFSET]] 536; CHECK-NEXT: call void @use1(i1 [[NULL]]) 537; CHECK-NEXT: [[R:%.*]] = icmp ule i8 [[BASE]], [[OFFSET]] 538; CHECK-NEXT: ret i1 [[R]] 539; 540 %adjusted = sub i8 %base, %offset 541 call void @use8(i8 %adjusted) 542 %underflow = icmp ult i8 %base, %adjusted ; swapped 543 call void @use1(i1 %underflow) 544 %null = icmp eq i8 %adjusted, 0 545 call void @use1(i1 %null) 546 %r = select i1 %null, i1 true, i1 %underflow 547 ret i1 %r 548} 549 550;------------------------------------------------------------------------------- 551 552define i1 @t10(i64 %base, ptr nonnull %offsetptr) { 553; CHECK-LABEL: @t10( 554; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint ptr [[OFFSETPTR:%.*]] to i64 555; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]] 556; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]]) 557; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i64 [[BASE]], [[OFFSET]] 558; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 559; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[BASE]], [[OFFSET]] 560; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 561; CHECK-NEXT: [[R:%.*]] = icmp ugt i64 [[BASE]], [[OFFSET]] 562; CHECK-NEXT: ret i1 [[R]] 563; 564 %offset = ptrtoint ptr %offsetptr to i64 565 566 %adjusted = sub i64 %base, %offset 567 call void @use64(i64 %adjusted) 568 %no_underflow = icmp ult i64 %adjusted, %base 569 call void @use1(i1 %no_underflow) 570 %not_null = icmp ne i64 %adjusted, 0 571 call void @use1(i1 %not_null) 572 %r = and i1 %not_null, %no_underflow 573 ret i1 %r 574} 575 576define i1 @t10_logical(i64 %base, ptr nonnull %offsetptr) { 577; CHECK-LABEL: @t10_logical( 578; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint ptr [[OFFSETPTR:%.*]] to i64 579; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]] 580; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]]) 581; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i64 [[BASE]], [[OFFSET]] 582; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 583; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[BASE]], [[OFFSET]] 584; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 585; CHECK-NEXT: [[R:%.*]] = icmp ugt i64 [[BASE]], [[OFFSET]] 586; CHECK-NEXT: ret i1 [[R]] 587; 588 %offset = ptrtoint ptr %offsetptr to i64 589 590 %adjusted = sub i64 %base, %offset 591 call void @use64(i64 %adjusted) 592 %no_underflow = icmp ult i64 %adjusted, %base 593 call void @use1(i1 %no_underflow) 594 %not_null = icmp ne i64 %adjusted, 0 595 call void @use1(i1 %not_null) 596 %r = select i1 %not_null, i1 %no_underflow, i1 false 597 ret i1 %r 598} 599define i1 @t11_commutative(i64 %base, ptr nonnull %offsetptr) { 600; CHECK-LABEL: @t11_commutative( 601; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint ptr [[OFFSETPTR:%.*]] to i64 602; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]] 603; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]]) 604; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i64 [[BASE]], [[OFFSET]] 605; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 606; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[BASE]], [[OFFSET]] 607; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 608; CHECK-NEXT: [[R:%.*]] = icmp ugt i64 [[BASE]], [[OFFSET]] 609; CHECK-NEXT: ret i1 [[R]] 610; 611 %offset = ptrtoint ptr %offsetptr to i64 612 613 %adjusted = sub i64 %base, %offset 614 call void @use64(i64 %adjusted) 615 %no_underflow = icmp ugt i64 %base, %adjusted ; swapped 616 call void @use1(i1 %no_underflow) 617 %not_null = icmp ne i64 %adjusted, 0 618 call void @use1(i1 %not_null) 619 %r = and i1 %not_null, %no_underflow 620 ret i1 %r 621} 622 623define i1 @t11_commutative_logical(i64 %base, ptr nonnull %offsetptr) { 624; CHECK-LABEL: @t11_commutative_logical( 625; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint ptr [[OFFSETPTR:%.*]] to i64 626; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]] 627; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]]) 628; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp uge i64 [[BASE]], [[OFFSET]] 629; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 630; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[BASE]], [[OFFSET]] 631; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 632; CHECK-NEXT: [[R:%.*]] = icmp ugt i64 [[BASE]], [[OFFSET]] 633; CHECK-NEXT: ret i1 [[R]] 634; 635 %offset = ptrtoint ptr %offsetptr to i64 636 637 %adjusted = sub i64 %base, %offset 638 call void @use64(i64 %adjusted) 639 %no_underflow = icmp ugt i64 %base, %adjusted ; swapped 640 call void @use1(i1 %no_underflow) 641 %not_null = icmp ne i64 %adjusted, 0 642 call void @use1(i1 %not_null) 643 %r = select i1 %not_null, i1 %no_underflow, i1 false 644 ret i1 %r 645} 646 647define i1 @t12(i64 %base, ptr nonnull %offsetptr) { 648; CHECK-LABEL: @t12( 649; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint ptr [[OFFSETPTR:%.*]] to i64 650; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]] 651; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]]) 652; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i64 [[BASE]], [[OFFSET]] 653; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 654; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i64 [[BASE]], [[OFFSET]] 655; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 656; CHECK-NEXT: [[R:%.*]] = icmp ule i64 [[BASE]], [[OFFSET]] 657; CHECK-NEXT: ret i1 [[R]] 658; 659 %offset = ptrtoint ptr %offsetptr to i64 660 661 %adjusted = sub i64 %base, %offset 662 call void @use64(i64 %adjusted) 663 %no_underflow = icmp uge i64 %adjusted, %base 664 call void @use1(i1 %no_underflow) 665 %not_null = icmp eq i64 %adjusted, 0 666 call void @use1(i1 %not_null) 667 %r = or i1 %not_null, %no_underflow 668 ret i1 %r 669} 670 671define i1 @t12_logical(i64 %base, ptr nonnull %offsetptr) { 672; CHECK-LABEL: @t12_logical( 673; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint ptr [[OFFSETPTR:%.*]] to i64 674; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]] 675; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]]) 676; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i64 [[BASE]], [[OFFSET]] 677; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 678; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i64 [[BASE]], [[OFFSET]] 679; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 680; CHECK-NEXT: [[R:%.*]] = icmp ule i64 [[BASE]], [[OFFSET]] 681; CHECK-NEXT: ret i1 [[R]] 682; 683 %offset = ptrtoint ptr %offsetptr to i64 684 685 %adjusted = sub i64 %base, %offset 686 call void @use64(i64 %adjusted) 687 %no_underflow = icmp uge i64 %adjusted, %base 688 call void @use1(i1 %no_underflow) 689 %not_null = icmp eq i64 %adjusted, 0 690 call void @use1(i1 %not_null) 691 %r = select i1 %not_null, i1 true, i1 %no_underflow 692 ret i1 %r 693} 694define i1 @t13(i64 %base, ptr nonnull %offsetptr) { 695; CHECK-LABEL: @t13( 696; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint ptr [[OFFSETPTR:%.*]] to i64 697; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]] 698; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]]) 699; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i64 [[BASE]], [[OFFSET]] 700; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 701; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i64 [[BASE]], [[OFFSET]] 702; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 703; CHECK-NEXT: [[R:%.*]] = icmp ule i64 [[BASE]], [[OFFSET]] 704; CHECK-NEXT: ret i1 [[R]] 705; 706 %offset = ptrtoint ptr %offsetptr to i64 707 708 %adjusted = sub i64 %base, %offset 709 call void @use64(i64 %adjusted) 710 %no_underflow = icmp ule i64 %base, %adjusted ; swapped 711 call void @use1(i1 %no_underflow) 712 %not_null = icmp eq i64 %adjusted, 0 713 call void @use1(i1 %not_null) 714 %r = or i1 %not_null, %no_underflow 715 ret i1 %r 716} 717 718define i1 @t13_logical(i64 %base, ptr nonnull %offsetptr) { 719; CHECK-LABEL: @t13_logical( 720; CHECK-NEXT: [[OFFSET:%.*]] = ptrtoint ptr [[OFFSETPTR:%.*]] to i64 721; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET]] 722; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]]) 723; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i64 [[BASE]], [[OFFSET]] 724; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 725; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp eq i64 [[BASE]], [[OFFSET]] 726; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 727; CHECK-NEXT: [[R:%.*]] = icmp ule i64 [[BASE]], [[OFFSET]] 728; CHECK-NEXT: ret i1 [[R]] 729; 730 %offset = ptrtoint ptr %offsetptr to i64 731 732 %adjusted = sub i64 %base, %offset 733 call void @use64(i64 %adjusted) 734 %no_underflow = icmp ule i64 %base, %adjusted ; swapped 735 call void @use1(i1 %no_underflow) 736 %not_null = icmp eq i64 %adjusted, 0 737 call void @use1(i1 %not_null) 738 %r = select i1 %not_null, i1 true, i1 %no_underflow 739 ret i1 %r 740} 741 742define i1 @t14_bad(i64 %base, i64 %offset) { 743; CHECK-LABEL: @t14_bad( 744; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET:%.*]] 745; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]]) 746; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE]] 747; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 748; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[BASE]], [[OFFSET]] 749; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 750; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] 751; CHECK-NEXT: ret i1 [[R]] 752; 753 %adjusted = sub i64 %base, %offset 754 call void @use64(i64 %adjusted) 755 %no_underflow = icmp ult i64 %adjusted, %base 756 call void @use1(i1 %no_underflow) 757 %not_null = icmp ne i64 %adjusted, 0 758 call void @use1(i1 %not_null) 759 %r = and i1 %not_null, %no_underflow 760 ret i1 %r 761} 762 763define i1 @t14_bad_logical(i64 %base, i64 %offset) { 764; CHECK-LABEL: @t14_bad_logical( 765; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i64 [[BASE:%.*]], [[OFFSET:%.*]] 766; CHECK-NEXT: call void @use64(i64 [[ADJUSTED]]) 767; CHECK-NEXT: [[NO_UNDERFLOW:%.*]] = icmp ult i64 [[ADJUSTED]], [[BASE]] 768; CHECK-NEXT: call void @use1(i1 [[NO_UNDERFLOW]]) 769; CHECK-NEXT: [[NOT_NULL:%.*]] = icmp ne i64 [[BASE]], [[OFFSET]] 770; CHECK-NEXT: call void @use1(i1 [[NOT_NULL]]) 771; CHECK-NEXT: [[R:%.*]] = and i1 [[NOT_NULL]], [[NO_UNDERFLOW]] 772; CHECK-NEXT: ret i1 [[R]] 773; 774 %adjusted = sub i64 %base, %offset 775 call void @use64(i64 %adjusted) 776 %no_underflow = icmp ult i64 %adjusted, %base 777 call void @use1(i1 %no_underflow) 778 %not_null = icmp ne i64 %adjusted, 0 779 call void @use1(i1 %not_null) 780 %r = select i1 %not_null, i1 %no_underflow, i1 false 781 ret i1 %r 782} 783 784define i1 @base_ult_offset(i8 %base, i8 %offset) { 785; CHECK-LABEL: @base_ult_offset( 786; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 787; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 788; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]] 789; CHECK-NEXT: ret i1 [[R]] 790; 791 %adjusted = sub i8 %base, %offset 792 call void @use8(i8 %adjusted) 793 %not_null = icmp ne i8 %adjusted, 0 794 %no_underflow = icmp ule i8 %base, %offset 795 %r = and i1 %no_underflow, %not_null 796 ret i1 %r 797} 798 799define i1 @base_ult_offset_logical(i8 %base, i8 %offset) { 800; CHECK-LABEL: @base_ult_offset_logical( 801; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 802; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 803; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[BASE]], [[OFFSET]] 804; CHECK-NEXT: ret i1 [[R]] 805; 806 %adjusted = sub i8 %base, %offset 807 call void @use8(i8 %adjusted) 808 %not_null = icmp ne i8 %adjusted, 0 809 %no_underflow = icmp ule i8 %base, %offset 810 %r = select i1 %no_underflow, i1 %not_null, i1 false 811 ret i1 %r 812} 813define i1 @base_uge_offset(i8 %base, i8 %offset) { 814; CHECK-LABEL: @base_uge_offset( 815; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 816; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 817; CHECK-NEXT: [[R:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]] 818; CHECK-NEXT: ret i1 [[R]] 819; 820 %adjusted = sub i8 %base, %offset 821 call void @use8(i8 %adjusted) 822 %not_null = icmp eq i8 %adjusted, 0 823 %no_underflow = icmp ugt i8 %base, %offset 824 %r = or i1 %no_underflow, %not_null 825 ret i1 %r 826} 827 828define i1 @base_uge_offset_logical(i8 %base, i8 %offset) { 829; CHECK-LABEL: @base_uge_offset_logical( 830; CHECK-NEXT: [[ADJUSTED:%.*]] = sub i8 [[BASE:%.*]], [[OFFSET:%.*]] 831; CHECK-NEXT: call void @use8(i8 [[ADJUSTED]]) 832; CHECK-NEXT: [[R:%.*]] = icmp uge i8 [[BASE]], [[OFFSET]] 833; CHECK-NEXT: ret i1 [[R]] 834; 835 %adjusted = sub i8 %base, %offset 836 call void @use8(i8 %adjusted) 837 %not_null = icmp eq i8 %adjusted, 0 838 %no_underflow = icmp ugt i8 %base, %offset 839 %r = select i1 %no_underflow, i1 true, i1 %not_null 840 ret i1 %r 841} 842