diff --git a/llvm/test/CodeGen/X86/icmp-in-unsigned-bounds.ll b/llvm/test/CodeGen/X86/icmp-in-unsigned-bounds.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/X86/icmp-in-unsigned-bounds.ll @@ -0,0 +1,466 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2 +; RUN: llc < %s -mtriple=x86_64-- | FileCheck %s --check-prefixes=CHECK + +define i1 @and_bounds_uge_lb_ult_ub_add(i32 %val, i32 %lb, i32 %sz) nounwind { +; CHECK-LABEL: and_bounds_uge_lb_ult_ub_add: +; CHECK: # %bb.0: +; CHECK-NEXT: addl %esi, %edx +; CHECK-NEXT: cmpl %esi, %edi +; CHECK-NEXT: setae %cl +; CHECK-NEXT: cmpl %edx, %edi +; CHECK-NEXT: setb %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %ub = add nuw i32 %lb, %sz + %r0 = icmp uge i32 %val, %lb + %r1 = icmp ult i32 %val, %ub + %r = and i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_uge_lb_ult_ub_add_fail_no_nuw(i32 %val, i32 %lb, i32 %sz) nounwind { +; CHECK-LABEL: and_bounds_uge_lb_ult_ub_add_fail_no_nuw: +; CHECK: # %bb.0: +; CHECK-NEXT: addl %esi, %edx +; CHECK-NEXT: cmpl %esi, %edi +; CHECK-NEXT: setae %cl +; CHECK-NEXT: cmpl %edx, %edi +; CHECK-NEXT: setb %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %ub = add nsw i32 %lb, %sz + %r0 = icmp uge i32 %val, %lb + %r1 = icmp ult i32 %val, %ub + %r = and i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_uge_lb_ult_ub_lshr(i32 %val, i32 %ub, i32 %sz) nounwind { +; CHECK-LABEL: or_bounds_uge_lb_ult_ub_lshr: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %ecx +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx +; CHECK-NEXT: shrl %cl, %eax +; CHECK-NEXT: cmpl %edi, %eax +; CHECK-NEXT: seta %cl +; CHECK-NEXT: cmpl %esi, %edi +; CHECK-NEXT: setae %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %lb = lshr i32 %ub, %sz + %r0 = icmp ugt i32 %lb, %val + %r1 = icmp uge i32 %val, %ub + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_uge_lb_ult_ub_lshr_fail_bad_bounds(i32 %val, i32 %ub, i32 %sz) nounwind { +; CHECK-LABEL: or_bounds_uge_lb_ult_ub_lshr_fail_bad_bounds: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %ecx +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx +; CHECK-NEXT: shrl %cl, %eax +; CHECK-NEXT: cmpl %edi, %eax +; CHECK-NEXT: seta %cl +; CHECK-NEXT: cmpl %esi, %edi +; CHECK-NEXT: setb %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %lb = lshr i32 %ub, %sz + %r0 = icmp ugt i32 %lb, %val + %r1 = icmp ult i32 %val, %ub + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_uge_lb_ult_ub_sub(i32 %val, i32 %ub, i32 %sz_in) nounwind { +; CHECK-LABEL: and_bounds_uge_lb_ult_ub_sub: +; CHECK: # %bb.0: +; CHECK-NEXT: orl $1, %edx +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: subl %edx, %eax +; CHECK-NEXT: cmpl %eax, %edi +; CHECK-NEXT: seta %cl +; CHECK-NEXT: cmpl %esi, %edi +; CHECK-NEXT: setb %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %sz = or i32 %sz_in, 1 + %lb = sub nuw i32 %ub, %sz + %r0 = icmp ugt i32 %val, %lb + %r1 = icmp ult i32 %val, %ub + %r = and i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_uge_lb_ult_ub_sub_fail_maybe_z(i32 %val, i32 %ub, i32 %sz_in) nounwind { +; CHECK-LABEL: and_bounds_uge_lb_ult_ub_sub_fail_maybe_z: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: subl %edx, %eax +; CHECK-NEXT: cmpl %eax, %edi +; CHECK-NEXT: seta %cl +; CHECK-NEXT: cmpl %esi, %edi +; CHECK-NEXT: setb %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %sz = or i32 %sz_in, 0 + %lb = sub nuw i32 %ub, %sz + %r0 = icmp ugt i32 %val, %lb + %r1 = icmp ult i32 %val, %ub + %r = and i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_uge_lb_ult_ub_udiv(i32 %val, i32 %ub_in, i32 %sz_in) nounwind { +; CHECK-LABEL: or_bounds_uge_lb_ult_ub_udiv: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %ecx +; CHECK-NEXT: orl $1, %esi +; CHECK-NEXT: orl $2, %ecx +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: xorl %edx, %edx +; CHECK-NEXT: divl %ecx +; CHECK-NEXT: cmpl %edi, %eax +; CHECK-NEXT: setae %cl +; CHECK-NEXT: cmpl %edi, %esi +; CHECK-NEXT: setb %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %ub = or i32 %ub_in, 1 + %sz = or i32 %sz_in, 2 + %lb = udiv i32 %ub, %sz + %r0 = icmp uge i32 %lb, %val + %r1 = icmp ult i32 %ub, %val + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_uge_lb_ult_ub_udiv_fail_maybe_eq(i32 %val, i32 %ub_in, i32 %sz_in) nounwind { +; CHECK-LABEL: or_bounds_uge_lb_ult_ub_udiv_fail_maybe_eq: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %ecx +; CHECK-NEXT: orl $1, %esi +; CHECK-NEXT: orl $1, %ecx +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: xorl %edx, %edx +; CHECK-NEXT: divl %ecx +; CHECK-NEXT: cmpl %edi, %eax +; CHECK-NEXT: setae %cl +; CHECK-NEXT: cmpl %edi, %esi +; CHECK-NEXT: setb %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %ub = or i32 %ub_in, 1 + %sz = or i32 %sz_in, 1 + %lb = udiv i32 %ub, %sz + %r0 = icmp uge i32 %lb, %val + %r1 = icmp ult i32 %ub, %val + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_uge_lb_ult_ub_udiv_fail_maybe_eq2(i32 %val, i32 %ub_in, i32 %sz_in) nounwind { +; CHECK-LABEL: or_bounds_uge_lb_ult_ub_udiv_fail_maybe_eq2: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %ecx +; CHECK-NEXT: orl $2, %ecx +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: xorl %edx, %edx +; CHECK-NEXT: divl %ecx +; CHECK-NEXT: cmpl %edi, %eax +; CHECK-NEXT: setae %cl +; CHECK-NEXT: cmpl %edi, %esi +; CHECK-NEXT: setb %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %ub = or i32 %ub_in, 0 + %sz = or i32 %sz_in, 2 + %lb = udiv i32 %ub, %sz + %r0 = icmp uge i32 %lb, %val + %r1 = icmp ult i32 %ub, %val + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_uge_lb_uge_ub_or(i32 %val, i32 %lb, i32 %sz) nounwind { +; CHECK-LABEL: and_bounds_uge_lb_uge_ub_or: +; CHECK: # %bb.0: +; CHECK-NEXT: orl %esi, %edx +; CHECK-NEXT: cmpl %esi, %edi +; CHECK-NEXT: setae %cl +; CHECK-NEXT: cmpl %edi, %edx +; CHECK-NEXT: setae %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %ub = or i32 %lb, %sz + %r0 = icmp uge i32 %val, %lb + %r1 = icmp uge i32 %ub, %val + %r = and i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_uge_lb_uge_ub_or_fail_mismatch_val(i32 %val2, i32 %val, i32 %lb, i32 %sz) nounwind { +; CHECK-LABEL: and_bounds_uge_lb_uge_ub_or_fail_mismatch_val: +; CHECK: # %bb.0: +; CHECK-NEXT: orl %edx, %ecx +; CHECK-NEXT: cmpl %edx, %esi +; CHECK-NEXT: setae %dl +; CHECK-NEXT: cmpl %edi, %ecx +; CHECK-NEXT: setae %al +; CHECK-NEXT: orb %dl, %al +; CHECK-NEXT: retq + %ub = or i32 %lb, %sz + %r0 = icmp uge i32 %val, %lb + %r1 = icmp uge i32 %ub, %val2 + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_ult_lb_uge_ub_mul(i32 %val, i32 %lb_in, i32 %sz_in) nounwind { +; CHECK-LABEL: or_bounds_ult_lb_uge_ub_mul: +; CHECK: # %bb.0: +; CHECK-NEXT: orl $1, %esi +; CHECK-NEXT: orl $2, %edx +; CHECK-NEXT: imull %esi, %edx +; CHECK-NEXT: cmpl %edi, %esi +; CHECK-NEXT: setae %cl +; CHECK-NEXT: cmpl %edi, %edx +; CHECK-NEXT: setb %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %lb = or i32 %lb_in, 1 + %sz = or i32 %sz_in, 2 + %ub = mul nuw i32 %lb, %sz + %r0 = icmp uge i32 %lb, %val + %r1 = icmp ult i32 %ub, %val + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_ult_lb_uge_ub_mul_fail_need_ugt1(i32 %val, i32 %lb_in, i32 %sz_in) nounwind { +; CHECK-LABEL: or_bounds_ult_lb_uge_ub_mul_fail_need_ugt1: +; CHECK: # %bb.0: +; CHECK-NEXT: orl $2, %esi +; CHECK-NEXT: orl $1, %edx +; CHECK-NEXT: imull %esi, %edx +; CHECK-NEXT: cmpl %edi, %esi +; CHECK-NEXT: setae %cl +; CHECK-NEXT: cmpl %edi, %edx +; CHECK-NEXT: setb %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %lb = or i32 %lb_in, 2 + %sz = or i32 %sz_in, 1 + %ub = mul nuw i32 %lb, %sz + %r0 = icmp uge i32 %lb, %val + %r1 = icmp ult i32 %ub, %val + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_ult_lb_uge_ub_mul_fail_need_nz(i32 %val, i32 %lb_in, i32 %sz_in) nounwind { +; CHECK-LABEL: or_bounds_ult_lb_uge_ub_mul_fail_need_nz: +; CHECK: # %bb.0: +; CHECK-NEXT: orl $2, %edx +; CHECK-NEXT: imull %esi, %edx +; CHECK-NEXT: cmpl %edi, %esi +; CHECK-NEXT: setae %cl +; CHECK-NEXT: cmpl %edi, %edx +; CHECK-NEXT: setb %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %lb = or i32 %lb_in, 0 + %sz = or i32 %sz_in, 2 + %ub = mul nuw i32 %lb, %sz + %r0 = icmp uge i32 %lb, %val + %r1 = icmp ult i32 %ub, %val + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_ult_lb_ugt_ub_shl(i32 %val, i32 %lb_in, i32 %sz_in) nounwind { +; CHECK-LABEL: and_bounds_ult_lb_ugt_ub_shl: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %ecx +; CHECK-NEXT: orl $1, %esi +; CHECK-NEXT: orb $1, %cl +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx +; CHECK-NEXT: shll %cl, %eax +; CHECK-NEXT: cmpl %edi, %esi +; CHECK-NEXT: setb %cl +; CHECK-NEXT: cmpl %eax, %edi +; CHECK-NEXT: setb %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %lb = or i32 %lb_in, 1 + %sz = or i32 %sz_in, 1 + %ub = shl nuw i32 %lb, %sz + %r0 = icmp ult i32 %lb, %val + %r1 = icmp ult i32 %val, %ub + %r = and i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_ult_lb_ugt_ub_shl_fail_need_non_zero(i32 %val, i32 %lb_in, i32 %sz_in) nounwind { +; CHECK-LABEL: and_bounds_ult_lb_ugt_ub_shl_fail_need_non_zero: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %ecx +; CHECK-NEXT: orb $1, %cl +; CHECK-NEXT: movl %esi, %eax +; CHECK-NEXT: # kill: def $cl killed $cl killed $ecx +; CHECK-NEXT: shll %cl, %eax +; CHECK-NEXT: cmpl %edi, %esi +; CHECK-NEXT: setb %cl +; CHECK-NEXT: cmpl %eax, %edi +; CHECK-NEXT: setb %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %lb = or i32 %lb_in, 0 + %sz = or i32 %sz_in, 1 + %ub = shl nuw i32 %lb, %sz + %r0 = icmp ult i32 %lb, %val + %r1 = icmp ult i32 %val, %ub + %r = and i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_gep(ptr %val, ptr %lb, i32 %sz_in) nounwind { +; CHECK-LABEL: or_bounds_gep: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %eax +; CHECK-NEXT: leaq (%rsi,%rax,8), %rax +; CHECK-NEXT: cmpq %rdi, %rsi +; CHECK-NEXT: seta %cl +; CHECK-NEXT: cmpq %rax, %rdi +; CHECK-NEXT: setae %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %sz = zext i32 %sz_in to i64 + %ub = getelementptr inbounds i64, ptr %lb, i64 %sz + %r0 = icmp ugt ptr %lb, %val + %r1 = icmp uge ptr %val, %ub + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_gep2(ptr %val, ptr %lb, i32 %sz_in) nounwind { +; CHECK-LABEL: and_bounds_gep2: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %eax +; CHECK-NEXT: orq $1, %rax +; CHECK-NEXT: addq %rsi, %rax +; CHECK-NEXT: cmpq %rdi, %rsi +; CHECK-NEXT: setb %cl +; CHECK-NEXT: cmpq %rax, %rdi +; CHECK-NEXT: setb %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %sz_in64 = zext i32 %sz_in to i64 + %sz = or i64 %sz_in64, 1 + %ub = getelementptr inbounds i8, ptr %lb, i64 %sz + %r0 = icmp ult ptr %lb, %val + %r1 = icmp ult ptr %val, %ub + %r = and i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_gep3(ptr %val, ptr %lb, i32 %sz_in) nounwind { +; CHECK-LABEL: or_bounds_gep3: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %eax +; CHECK-NEXT: shlq $4, %rax +; CHECK-NEXT: orq $16, %rax +; CHECK-NEXT: addq %rsi, %rax +; CHECK-NEXT: cmpq %rdi, %rsi +; CHECK-NEXT: setae %cl +; CHECK-NEXT: cmpq %rax, %rdi +; CHECK-NEXT: seta %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %sz_in64 = zext i32 %sz_in to i64 + %sz = or i64 %sz_in64, 1 + %ub = getelementptr inbounds i128, ptr %lb, i64 %sz + %r0 = icmp uge ptr %lb, %val + %r1 = icmp ugt ptr %val, %ub + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_gep3_fail_maybe_zero(ptr %val, ptr %lb, i32 %sz_in) nounwind { +; CHECK-LABEL: and_bounds_gep3_fail_maybe_zero: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %eax +; CHECK-NEXT: shlq $4, %rax +; CHECK-NEXT: addq %rsi, %rax +; CHECK-NEXT: cmpq %rdi, %rsi +; CHECK-NEXT: setb %cl +; CHECK-NEXT: cmpq %rax, %rdi +; CHECK-NEXT: setbe %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %sz = zext i32 %sz_in to i64 + %ub = getelementptr inbounds i128, ptr %lb, i64 %sz + %r0 = icmp ult ptr %lb, %val + %r1 = icmp ule ptr %val, %ub + %r = and i1 %r0, %r1 + ret i1 %r +} + +define i1 @or_bounds_gep4(ptr %val, ptr %lb, i32 %sz_in) nounwind { +; CHECK-LABEL: or_bounds_gep4: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %eax +; CHECK-NEXT: leaq (%rsi,%rax,4), %rax +; CHECK-NEXT: cmpq %rdi, %rsi +; CHECK-NEXT: seta %cl +; CHECK-NEXT: cmpq %rax, %rdi +; CHECK-NEXT: seta %al +; CHECK-NEXT: orb %cl, %al +; CHECK-NEXT: retq + %sz = zext i32 %sz_in to i64 + %ub = getelementptr inbounds i32, ptr %lb, i64 %sz + %r0 = icmp ugt ptr %lb, %val + %r1 = icmp ugt ptr %val, %ub + %r = or i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_gep_fail_maybe_neg(ptr %val, ptr %lb, i64 %sz) nounwind { +; CHECK-LABEL: and_bounds_gep_fail_maybe_neg: +; CHECK: # %bb.0: +; CHECK-NEXT: leaq (%rsi,%rdx,8), %rax +; CHECK-NEXT: cmpq %rdi, %rsi +; CHECK-NEXT: setbe %cl +; CHECK-NEXT: cmpq %rax, %rdi +; CHECK-NEXT: setb %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %ub = getelementptr inbounds i64, ptr %lb, i64 %sz + %r0 = icmp ule ptr %lb, %val + %r1 = icmp ult ptr %val, %ub + %r = and i1 %r0, %r1 + ret i1 %r +} + +define i1 @and_bounds_gep_fail_no_inbounds(ptr %val, ptr %lb, i32 %sz_in) nounwind { +; CHECK-LABEL: and_bounds_gep_fail_no_inbounds: +; CHECK: # %bb.0: +; CHECK-NEXT: movl %edx, %eax +; CHECK-NEXT: leaq (%rsi,%rax,8), %rax +; CHECK-NEXT: cmpq %rdi, %rsi +; CHECK-NEXT: setbe %cl +; CHECK-NEXT: cmpq %rax, %rdi +; CHECK-NEXT: setb %al +; CHECK-NEXT: andb %cl, %al +; CHECK-NEXT: retq + %sz = zext i32 %sz_in to i64 + %ub = getelementptr i64, ptr %lb, i64 %sz + %r0 = icmp ule ptr %lb, %val + %r1 = icmp ult ptr %val, %ub + %r = and i1 %r0, %r1 + ret i1 %r +}