1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=x86_64-- | FileCheck %s 3 4; CodeGenPrepare is expected to form overflow intrinsics to improve DAG/isel. 5 6define i1 @usubo_ult_i64(i64 %x, i64 %y, i64* %p) nounwind { 7; CHECK-LABEL: usubo_ult_i64: 8; CHECK: # %bb.0: 9; CHECK-NEXT: subq %rsi, %rdi 10; CHECK-NEXT: setb %al 11; CHECK-NEXT: movq %rdi, (%rdx) 12; CHECK-NEXT: retq 13 %s = sub i64 %x, %y 14 store i64 %s, i64* %p 15 %ov = icmp ult i64 %x, %y 16 ret i1 %ov 17} 18 19; Verify insertion point for single-BB. Toggle predicate. 20 21define i1 @usubo_ugt_i32(i32 %x, i32 %y, i32* %p) nounwind { 22; CHECK-LABEL: usubo_ugt_i32: 23; CHECK: # %bb.0: 24; CHECK-NEXT: subl %esi, %edi 25; CHECK-NEXT: setb %al 26; CHECK-NEXT: movl %edi, (%rdx) 27; CHECK-NEXT: retq 28 %ov = icmp ugt i32 %y, %x 29 %s = sub i32 %x, %y 30 store i32 %s, i32* %p 31 ret i1 %ov 32} 33 34; Constant operand should match. 35 36define i1 @usubo_ugt_constant_op0_i8(i8 %x, i8* %p) nounwind { 37; CHECK-LABEL: usubo_ugt_constant_op0_i8: 38; CHECK: # %bb.0: 39; CHECK-NEXT: movb $42, %cl 40; CHECK-NEXT: subb %dil, %cl 41; CHECK-NEXT: setb %al 42; CHECK-NEXT: movb %cl, (%rsi) 43; CHECK-NEXT: retq 44 %s = sub i8 42, %x 45 %ov = icmp ugt i8 %x, 42 46 store i8 %s, i8* %p 47 ret i1 %ov 48} 49 50; Compare with constant operand 0 is canonicalized by commuting, but verify match for non-canonical form. 51 52define i1 @usubo_ult_constant_op0_i16(i16 %x, i16* %p) nounwind { 53; CHECK-LABEL: usubo_ult_constant_op0_i16: 54; CHECK: # %bb.0: 55; CHECK-NEXT: movw $43, %cx 56; CHECK-NEXT: subw %di, %cx 57; CHECK-NEXT: setb %al 58; CHECK-NEXT: movw %cx, (%rsi) 59; CHECK-NEXT: retq 60 %s = sub i16 43, %x 61 %ov = icmp ult i16 43, %x 62 store i16 %s, i16* %p 63 ret i1 %ov 64} 65 66; Subtract with constant operand 1 is canonicalized to add. 67 68define i1 @usubo_ult_constant_op1_i16(i16 %x, i16* %p) nounwind { 69; CHECK-LABEL: usubo_ult_constant_op1_i16: 70; CHECK: # %bb.0: 71; CHECK-NEXT: subw $44, %di 72; CHECK-NEXT: setb %al 73; CHECK-NEXT: movw %di, (%rsi) 74; CHECK-NEXT: retq 75 %s = add i16 %x, -44 76 %ov = icmp ult i16 %x, 44 77 store i16 %s, i16* %p 78 ret i1 %ov 79} 80 81define i1 @usubo_ugt_constant_op1_i8(i8 %x, i8* %p) nounwind { 82; CHECK-LABEL: usubo_ugt_constant_op1_i8: 83; CHECK: # %bb.0: 84; CHECK-NEXT: subb $45, %dil 85; CHECK-NEXT: setb %al 86; CHECK-NEXT: movb %dil, (%rsi) 87; CHECK-NEXT: retq 88 %ov = icmp ugt i8 45, %x 89 %s = add i8 %x, -45 90 store i8 %s, i8* %p 91 ret i1 %ov 92} 93 94; Special-case: subtract 1 changes the compare predicate and constant. 95 96define i1 @usubo_eq_constant1_op1_i32(i32 %x, i32* %p) nounwind { 97; CHECK-LABEL: usubo_eq_constant1_op1_i32: 98; CHECK: # %bb.0: 99; CHECK-NEXT: subl $1, %edi 100; CHECK-NEXT: setb %al 101; CHECK-NEXT: movl %edi, (%rsi) 102; CHECK-NEXT: retq 103 %s = add i32 %x, -1 104 %ov = icmp eq i32 %x, 0 105 store i32 %s, i32* %p 106 ret i1 %ov 107} 108 109; Special-case: subtract from 0 (negate) changes the compare predicate. 110 111define i1 @usubo_ne_constant0_op1_i32(i32 %x, i32* %p) { 112; CHECK-LABEL: usubo_ne_constant0_op1_i32: 113; CHECK: # %bb.0: 114; CHECK-NEXT: negl %edi 115; CHECK-NEXT: setb %al 116; CHECK-NEXT: movl %edi, (%rsi) 117; CHECK-NEXT: retq 118 %s = sub i32 0, %x 119 %ov = icmp ne i32 %x, 0 120 store i32 %s, i32* %p 121 ret i1 %ov 122} 123 124; This used to verify insertion point for multi-BB, but now we just bail out. 125 126declare void @call(i1) 127 128define i1 @usubo_ult_sub_dominates_i64(i64 %x, i64 %y, i64* %p, i1 %cond) nounwind { 129; CHECK-LABEL: usubo_ult_sub_dominates_i64: 130; CHECK: # %bb.0: # %entry 131; CHECK-NEXT: testb $1, %cl 132; CHECK-NEXT: je .LBB8_2 133; CHECK-NEXT: # %bb.1: # %t 134; CHECK-NEXT: movq %rdi, %rax 135; CHECK-NEXT: subq %rsi, %rax 136; CHECK-NEXT: movq %rax, (%rdx) 137; CHECK-NEXT: testb $1, %cl 138; CHECK-NEXT: je .LBB8_2 139; CHECK-NEXT: # %bb.3: # %end 140; CHECK-NEXT: cmpq %rsi, %rdi 141; CHECK-NEXT: setb %al 142; CHECK-NEXT: retq 143; CHECK-NEXT: .LBB8_2: # %f 144; CHECK-NEXT: movl %ecx, %eax 145; CHECK-NEXT: retq 146entry: 147 br i1 %cond, label %t, label %f 148 149t: 150 %s = sub i64 %x, %y 151 store i64 %s, i64* %p 152 br i1 %cond, label %end, label %f 153 154f: 155 ret i1 %cond 156 157end: 158 %ov = icmp ult i64 %x, %y 159 ret i1 %ov 160} 161 162define i1 @usubo_ult_cmp_dominates_i64(i64 %x, i64 %y, i64* %p, i1 %cond) nounwind { 163; CHECK-LABEL: usubo_ult_cmp_dominates_i64: 164; CHECK: # %bb.0: # %entry 165; CHECK-NEXT: pushq %rbp 166; CHECK-NEXT: pushq %r15 167; CHECK-NEXT: pushq %r14 168; CHECK-NEXT: pushq %rbx 169; CHECK-NEXT: pushq %rax 170; CHECK-NEXT: movl %ecx, %ebp 171; CHECK-NEXT: testb $1, %bpl 172; CHECK-NEXT: je .LBB9_2 173; CHECK-NEXT: # %bb.1: # %t 174; CHECK-NEXT: movq %rdx, %r14 175; CHECK-NEXT: movq %rsi, %r15 176; CHECK-NEXT: movq %rdi, %rbx 177; CHECK-NEXT: xorl %edi, %edi 178; CHECK-NEXT: cmpq %rsi, %rbx 179; CHECK-NEXT: setb %dil 180; CHECK-NEXT: callq call 181; CHECK-NEXT: subq %r15, %rbx 182; CHECK-NEXT: jae .LBB9_2 183; CHECK-NEXT: # %bb.4: # %end 184; CHECK-NEXT: setb %al 185; CHECK-NEXT: movq %rbx, (%r14) 186; CHECK-NEXT: jmp .LBB9_3 187; CHECK-NEXT: .LBB9_2: # %f 188; CHECK-NEXT: movl %ebp, %eax 189; CHECK-NEXT: .LBB9_3: # %f 190; CHECK-NEXT: addq $8, %rsp 191; CHECK-NEXT: popq %rbx 192; CHECK-NEXT: popq %r14 193; CHECK-NEXT: popq %r15 194; CHECK-NEXT: popq %rbp 195; CHECK-NEXT: retq 196entry: 197 br i1 %cond, label %t, label %f 198 199t: 200 %ov = icmp ult i64 %x, %y 201 call void @call(i1 %ov) 202 br i1 %ov, label %end, label %f 203 204f: 205 ret i1 %cond 206 207end: 208 %s = sub i64 %x, %y 209 store i64 %s, i64* %p 210 ret i1 %ov 211} 212 213define void @PR41129(i64* %p64) { 214; CHECK-LABEL: PR41129: 215; CHECK: # %bb.0: # %entry 216; CHECK-NEXT: movq (%rdi), %rax 217; CHECK-NEXT: testq %rax, %rax 218; CHECK-NEXT: je .LBB10_2 219; CHECK-NEXT: # %bb.1: # %false 220; CHECK-NEXT: andl $7, %eax 221; CHECK-NEXT: movq %rax, (%rdi) 222; CHECK-NEXT: retq 223; CHECK-NEXT: .LBB10_2: # %true 224; CHECK-NEXT: decq %rax 225; CHECK-NEXT: movq %rax, (%rdi) 226; CHECK-NEXT: retq 227entry: 228 %key = load i64, i64* %p64, align 8 229 %cond17 = icmp eq i64 %key, 0 230 br i1 %cond17, label %true, label %false 231 232false: 233 %andval = and i64 %key, 7 234 store i64 %andval, i64* %p64 235 br label %exit 236 237true: 238 %svalue = add i64 %key, -1 239 store i64 %svalue, i64* %p64 240 br label %exit 241 242exit: 243 ret void 244} 245 246define i32 @PR42571(i32 %x, i32 %y) { 247; CHECK-LABEL: PR42571: 248; CHECK: # %bb.0: 249; CHECK-NEXT: # kill: def $edi killed $edi def $rdi 250; CHECK-NEXT: leal -1(%rdi), %eax 251; CHECK-NEXT: andl %edi, %eax 252; CHECK-NEXT: cmpl $1, %edi 253; CHECK-NEXT: cmovbl %esi, %eax 254; CHECK-NEXT: retq 255 %tobool = icmp eq i32 %x, 0 256 %sub = add nsw i32 %x, -1 257 %and = and i32 %sub, %x 258 %cond = select i1 %tobool, i32 %y, i32 %and 259 ret i32 %cond 260} 261