llvm/llvm/test/Transforms/InstCombine/set-lowbits-mask-canonicalize.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt < %s -passes=instcombine -S | FileCheck %s

; https://bugs.llvm.org/show_bug.cgi?id=37603

; Pattern:
;   (1 << NBits) - 1
; Should be transformed into:
;   ~(-(1 << NBits))
; The `not` may end up being folded into `and`

; ============================================================================ ;
; Most basic positive tests
; ============================================================================ ;

; No no-wrap tags on shl

define i32 @shl_add(i32 %NBits) {
; CHECK-LABEL: @shl_add(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[NOTMASK]], -1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl i32 1, %NBits
  %ret = add i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_add_nsw(i32 %NBits) {
; CHECK-LABEL: @shl_add_nsw(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[NOTMASK]], -1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl i32 1, %NBits
  %ret = add nsw i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_add_nuw(i32 %NBits) {
; CHECK-LABEL: @shl_add_nuw(
; CHECK-NEXT:    ret i32 -1
;
  %setbit = shl i32 1, %NBits
  %ret = add nuw i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_add_nsw_nuw(i32 %NBits) {
; CHECK-LABEL: @shl_add_nsw_nuw(
; CHECK-NEXT:    ret i32 -1
;
  %setbit = shl i32 1, %NBits
  %ret = add nuw nsw i32 %setbit, -1
  ret i32 %ret
}

; shl is nsw

define i32 @shl_nsw_add(i32 %NBits) {
; CHECK-LABEL: @shl_nsw_add(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[NOTMASK]], -1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl nsw i32 1, %NBits
  %ret = add i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_nsw_add_nsw(i32 %NBits) {
; CHECK-LABEL: @shl_nsw_add_nsw(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[NOTMASK]], -1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl nsw i32 1, %NBits
  %ret = add nsw i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_nsw_add_nuw(i32 %NBits) {
; CHECK-LABEL: @shl_nsw_add_nuw(
; CHECK-NEXT:    ret i32 -1
;
  %setbit = shl nsw i32 1, %NBits
  %ret = add nuw i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_nsw_add_nsw_nuw(i32 %NBits) {
; CHECK-LABEL: @shl_nsw_add_nsw_nuw(
; CHECK-NEXT:    ret i32 -1
;
  %setbit = shl nsw i32 1, %NBits
  %ret = add nuw nsw i32 %setbit, -1
  ret i32 %ret
}

; shl is nuw

define i32 @shl_nuw_add(i32 %NBits) {
; CHECK-LABEL: @shl_nuw_add(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[NOTMASK]], -1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl nuw i32 1, %NBits
  %ret = add i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_nuw_add_nsw(i32 %NBits) {
; CHECK-LABEL: @shl_nuw_add_nsw(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[NOTMASK]], -1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl nuw i32 1, %NBits
  %ret = add nsw i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_nuw_add_nuw(i32 %NBits) {
; CHECK-LABEL: @shl_nuw_add_nuw(
; CHECK-NEXT:    ret i32 -1
;
  %setbit = shl nuw i32 1, %NBits
  %ret = add nuw i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_nuw_add_nsw_nuw(i32 %NBits) {
; CHECK-LABEL: @shl_nuw_add_nsw_nuw(
; CHECK-NEXT:    ret i32 -1
;
  %setbit = shl nuw i32 1, %NBits
  %ret = add nuw nsw i32 %setbit, -1
  ret i32 %ret
}

; shl is nuw nsw

define i32 @shl_nsw_nuw_add(i32 %NBits) {
; CHECK-LABEL: @shl_nsw_nuw_add(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[NOTMASK]], -1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl nuw nsw i32 1, %NBits
  %ret = add i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_nsw_nuw_add_nsw(i32 %NBits) {
; CHECK-LABEL: @shl_nsw_nuw_add_nsw(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw i32 -1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor i32 [[NOTMASK]], -1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl nuw nsw i32 1, %NBits
  %ret = add nsw i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_nsw_nuw_add_nuw(i32 %NBits) {
; CHECK-LABEL: @shl_nsw_nuw_add_nuw(
; CHECK-NEXT:    ret i32 -1
;
  %setbit = shl nuw nsw i32 1, %NBits
  %ret = add nuw i32 %setbit, -1
  ret i32 %ret
}

define i32 @shl_nsw_nuw_add_nsw_nuw(i32 %NBits) {
; CHECK-LABEL: @shl_nsw_nuw_add_nsw_nuw(
; CHECK-NEXT:    ret i32 -1
;
  %setbit = shl nuw nsw i32 1, %NBits
  %ret = add nuw nsw i32 %setbit, -1
  ret i32 %ret
}

; ============================================================================ ;
; Vectors
; ============================================================================ ;

define <2 x i32> @shl_add_vec(<2 x i32> %NBits) {
; CHECK-LABEL: @shl_add_vec(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw <2 x i32> <i32 -1, i32 -1>, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor <2 x i32> [[NOTMASK]], <i32 -1, i32 -1>
; CHECK-NEXT:    ret <2 x i32> [[RET]]
;
  %setbit = shl <2 x i32> <i32 1, i32 1>, %NBits
  %ret = add <2 x i32> %setbit, <i32 -1, i32 -1>
  ret <2 x i32> %ret
}

define <3 x i32> @shl_add_vec_poison0(<3 x i32> %NBits) {
; CHECK-LABEL: @shl_add_vec_poison0(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw <3 x i32> <i32 -1, i32 -1, i32 -1>, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor <3 x i32> [[NOTMASK]], <i32 -1, i32 -1, i32 -1>
; CHECK-NEXT:    ret <3 x i32> [[RET]]
;
  %setbit = shl <3 x i32> <i32 1, i32 poison, i32 1>, %NBits
  %ret = add <3 x i32> %setbit, <i32 -1, i32 -1, i32 -1>
  ret <3 x i32> %ret
}

define <3 x i32> @shl_add_vec_poison1(<3 x i32> %NBits) {
; CHECK-LABEL: @shl_add_vec_poison1(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw <3 x i32> <i32 -1, i32 -1, i32 -1>, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor <3 x i32> [[NOTMASK]], <i32 -1, i32 -1, i32 -1>
; CHECK-NEXT:    ret <3 x i32> [[RET]]
;
  %setbit = shl <3 x i32> <i32 1, i32 1, i32 1>, %NBits
  %ret = add <3 x i32> %setbit, <i32 -1, i32 poison, i32 -1>
  ret <3 x i32> %ret
}

define <3 x i32> @shl_add_vec_poison2(<3 x i32> %NBits) {
; CHECK-LABEL: @shl_add_vec_poison2(
; CHECK-NEXT:    [[NOTMASK:%.*]] = shl nsw <3 x i32> <i32 -1, i32 -1, i32 -1>, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = xor <3 x i32> [[NOTMASK]], <i32 -1, i32 -1, i32 -1>
; CHECK-NEXT:    ret <3 x i32> [[RET]]
;
  %setbit = shl <3 x i32> <i32 1, i32 poison, i32 1>, %NBits
  %ret = add <3 x i32> %setbit, <i32 -1, i32 poison, i32 -1>
  ret <3 x i32> %ret
}

; ============================================================================ ;
; Negative tests. Should not be folded.
; ============================================================================ ;

declare void @use32(i32)

; One use only.
define i32 @bad_oneuse0(i32 %NBits) {
; CHECK-LABEL: @bad_oneuse0(
; CHECK-NEXT:    [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]]
; CHECK-NEXT:    call void @use32(i32 [[SETBIT]])
; CHECK-NEXT:    [[RET:%.*]] = add i32 [[SETBIT]], -1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl i32 1, %NBits
  call void @use32(i32 %setbit)
  %ret = add i32 %setbit, -1
  ret i32 %ret
}

; shift base is not `1` constant

define i32 @bad_shl(i32 %base, i32 %NBits) {
; CHECK-LABEL: @bad_shl(
; CHECK-NEXT:    [[SETBIT:%.*]] = shl i32 [[BASE:%.*]], [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = add i32 [[SETBIT]], -1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl i32 %base, %NBits ; %base instead of 1
  %ret = add i32 %setbit, -1
  ret i32 %ret
}

; Second `add` operand is not `-1` constant

define i32 @bad_add0(i32 %NBits, i32 %addop2) {
; CHECK-LABEL: @bad_add0(
; CHECK-NEXT:    [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = add i32 [[SETBIT]], [[ADDOP2:%.*]]
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl i32 1, %NBits
  %ret = add i32 %setbit, %addop2
  ret i32 %ret
}

; Bad add constant

define i32 @bad_add1(i32 %NBits) {
; CHECK-LABEL: @bad_add1(
; CHECK-NEXT:    [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = add nuw i32 [[SETBIT]], 1
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl i32 1, %NBits
  %ret = add i32 %setbit, 1 ; not -1
  ret i32 %ret
}

define i32 @bad_add2(i32 %NBits) {
; CHECK-LABEL: @bad_add2(
; CHECK-NEXT:    [[SETBIT:%.*]] = shl nuw i32 1, [[NBITS:%.*]]
; CHECK-NEXT:    [[RET:%.*]] = add i32 [[SETBIT]], -2
; CHECK-NEXT:    ret i32 [[RET]]
;
  %setbit = shl i32 1, %NBits
  %ret = add i32 %setbit, -2 ; not -1
  ret i32 %ret
}