llvm/llvm/test/Transforms/CorrelatedValuePropagation/vectors.ll

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

define <2 x i1> @cmp1(<2 x i8> %a) {
; CHECK-LABEL: define <2 x i1> @cmp1(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ADD:%.*]] = add nuw <2 x i8> [[A]], <i8 1, i8 1>
; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
;
  %add = add nuw <2 x i8> %a, splat (i8 1)
  %cmp = icmp ne <2 x i8> %add, zeroinitializer
  ret <2 x i1> %cmp
}

define <2 x i1> @cmp2(<2 x i8> %a) {
; CHECK-LABEL: define <2 x i1> @cmp2(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ADD:%.*]] = add nuw <2 x i8> [[A]], <i8 5, i8 5>
; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
;
  %add = add nuw <2 x i8> %a, splat (i8 5)
  %cmp = icmp ugt <2 x i8> %add, splat (i8 2)
  ret <2 x i1> %cmp
}

define <2 x i1> @cmp_nonsplat(<2 x i8> %a) {
; CHECK-LABEL: define <2 x i1> @cmp_nonsplat(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ADD:%.*]] = add nuw <2 x i8> [[A]], <i8 4, i8 5>
; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
;
  %add = add nuw <2 x i8> %a, <i8 4, i8 5>
  %cmp = icmp ugt <2 x i8> %add, <i8 2, i8 3>
  ret <2 x i1> %cmp
}

; Handling this would require keeping track of ranges on a per-element basis.
define <2 x i1> @cmp_nonsplat_fail(<2 x i8> %a) {
; CHECK-LABEL: define <2 x i1> @cmp_nonsplat_fail(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ADD:%.*]] = add nuw <2 x i8> [[A]], <i8 3, i8 4>
; CHECK-NEXT:    [[CMP:%.*]] = icmp ugt <2 x i8> [[ADD]], <i8 2, i8 3>
; CHECK-NEXT:    ret <2 x i1> [[CMP]]
;
  %add = add nuw <2 x i8> %a, <i8 3, i8 4>
  %cmp = icmp ugt <2 x i8> %add, <i8 2, i8 3>
  ret <2 x i1> %cmp
}

define <2 x i1> @cmp_signedness(<2 x i8> %a) {
; CHECK-LABEL: define <2 x i1> @cmp_signedness(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[CMP:%.*]] = icmp ult <2 x i16> [[ZEXT]], <i16 5, i16 5>
; CHECK-NEXT:    ret <2 x i1> [[CMP]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %cmp = icmp slt <2 x i16> %zext, splat (i16 5)
  ret <2 x i1> %cmp
}

define <2 x i16> @infer_nowrap(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 1, 257) <2 x i16> @infer_nowrap(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES:%.*]] = add nuw nsw <2 x i16> [[ZEXT]], <i16 1, i16 1>
; CHECK-NEXT:    ret <2 x i16> [[RES]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = add <2 x i16> %zext, splat (i16 1)
  ret <2 x i16> %res
}

define <2 x i16> @infer_nowrap_nonsplat(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 1, 258) <2 x i16> @infer_nowrap_nonsplat(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES:%.*]] = add nuw nsw <2 x i16> [[ZEXT]], <i16 1, i16 2>
; CHECK-NEXT:    ret <2 x i16> [[RES]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = add <2 x i16> %zext, <i16 1, i16 2>
  ret <2 x i16> %res
}

define <vscale x 2 x i16> @infer_nowrap_scalable(<vscale x 2 x i8> %a) {
; CHECK-LABEL: define range(i16 1, 257) <vscale x 2 x i16> @infer_nowrap_scalable(
; CHECK-SAME: <vscale x 2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <vscale x 2 x i8> [[A]] to <vscale x 2 x i16>
; CHECK-NEXT:    [[RES:%.*]] = add nuw nsw <vscale x 2 x i16> [[ZEXT]], shufflevector (<vscale x 2 x i16> insertelement (<vscale x 2 x i16> poison, i16 1, i64 0), <vscale x 2 x i16> poison, <vscale x 2 x i32> zeroinitializer)
; CHECK-NEXT:    ret <vscale x 2 x i16> [[RES]]
;
  %zext = zext <vscale x 2 x i8> %a to <vscale x 2 x i16>
  %res = add <vscale x 2 x i16> %zext, splat (i16 1)
  ret <vscale x 2 x i16> %res
}

define <2 x i16> @infer_nowrap_poison(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 1, 257) <2 x i16> @infer_nowrap_poison(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES:%.*]] = add nuw nsw <2 x i16> [[ZEXT]], <i16 1, i16 poison>
; CHECK-NEXT:    ret <2 x i16> [[RES]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = add <2 x i16> %zext, <i16 1, i16 poison>
  ret <2 x i16> %res
}

define <2 x i16> @infer_nowrap_nonsplat_nsw_only(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 -1, 257) <2 x i16> @infer_nowrap_nonsplat_nsw_only(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES:%.*]] = add nsw <2 x i16> [[ZEXT]], <i16 1, i16 -1>
; CHECK-NEXT:    ret <2 x i16> [[RES]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = add <2 x i16> %zext, <i16 1, i16 -1>
  ret <2 x i16> %res
}

define <2 x i16> @abs(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 0, 256) <2 x i16> @abs(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    ret <2 x i16> [[ZEXT]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = call <2 x i16> @llvm.abs(<2 x i16> %zext, i1 false)
  ret <2 x i16> %res
}

define <2 x i16> @saturating(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 1, 257) <2 x i16> @saturating(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES:%.*]] = add nuw nsw <2 x i16> [[ZEXT]], <i16 1, i16 1>
; CHECK-NEXT:    ret <2 x i16> [[RES]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = call <2 x i16> @llvm.uadd.sat(<2 x i16> %zext, <2 x i16> splat (i16 1))
  ret <2 x i16> %res
}

define {<2 x i16>, <2 x i1>} @with_overflow(<2 x i8> %a) {
; CHECK-LABEL: define { <2 x i16>, <2 x i1> } @with_overflow(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES1:%.*]] = add nuw nsw <2 x i16> [[ZEXT]], <i16 1, i16 1>
; CHECK-NEXT:    [[RES:%.*]] = insertvalue { <2 x i16>, <2 x i1> } { <2 x i16> poison, <2 x i1> zeroinitializer }, <2 x i16> [[RES1]], 0
; CHECK-NEXT:    ret { <2 x i16>, <2 x i1> } [[RES]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = call {<2 x i16>, <2 x i1>} @llvm.uadd.with.overflow(<2 x i16> %zext, <2 x i16> splat (i16 1))
  ret {<2 x i16>, <2 x i1>} %res
}

define <2 x i16> @srem1(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 0, 42) <2 x i16> @srem1(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES1_LHS_TRUNC:%.*]] = trunc <2 x i16> [[ZEXT]] to <2 x i8>
; CHECK-NEXT:    [[RES12:%.*]] = urem <2 x i8> [[RES1_LHS_TRUNC]], <i8 42, i8 42>
; CHECK-NEXT:    [[RES:%.*]] = zext <2 x i8> [[RES12]] to <2 x i16>
; CHECK-NEXT:    ret <2 x i16> [[RES]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = srem <2 x i16> %zext, splat (i16 42)
  ret <2 x i16> %res
}

define <2 x i16> @srem2(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 -41, 42) <2 x i16> @srem2(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = sext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES_LHS_TRUNC:%.*]] = trunc <2 x i16> [[ZEXT]] to <2 x i8>
; CHECK-NEXT:    [[RES1:%.*]] = srem <2 x i8> [[RES_LHS_TRUNC]], <i8 42, i8 42>
; CHECK-NEXT:    [[RES:%.*]] = sext <2 x i8> [[RES1]] to <2 x i16>
; CHECK-NEXT:    ret <2 x i16> [[RES]]
;
  %zext = sext <2 x i8> %a to <2 x i16>
  %res = srem <2 x i16> %zext, splat (i16 42)
  ret <2 x i16> %res
}

define <2 x i16> @ashr(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 0, 128) <2 x i16> @ashr(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES:%.*]] = lshr <2 x i16> [[ZEXT]], <i16 1, i16 1>
; CHECK-NEXT:    ret <2 x i16> [[RES]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = ashr <2 x i16> %zext, splat (i16 1)
  ret <2 x i16> %res
}

define <2 x i32> @sext(<2 x i8> %a) {
; CHECK-LABEL: define range(i32 0, 256) <2 x i32> @sext(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES:%.*]] = zext nneg <2 x i16> [[ZEXT]] to <2 x i32>
; CHECK-NEXT:    ret <2 x i32> [[RES]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = sext <2 x i16> %zext to <2 x i32>
  ret <2 x i32> %res
}

define <2 x float> @sitofp(<2 x i8> %a) {
; CHECK-LABEL: define <2 x float> @sitofp(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    [[RES:%.*]] = uitofp nneg <2 x i16> [[ZEXT]] to <2 x float>
; CHECK-NEXT:    ret <2 x float> [[RES]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = sitofp <2 x i16> %zext to <2 x float>
  ret <2 x float> %res
}

define <2 x i16> @and(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 0, 256) <2 x i16> @and(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    ret <2 x i16> [[ZEXT]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = and <2 x i16> %zext, splat (i16 u0xff)
  ret <2 x i16> %res
}

define <2 x i16> @and_with_poison(<2 x i8> %a) {
; CHECK-LABEL: define range(i16 0, 256) <2 x i16> @and_with_poison(
; CHECK-SAME: <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    ret <2 x i16> [[ZEXT]]
;
  %zext = zext <2 x i8> %a to <2 x i16>
  %res = and <2 x i16> %zext, <i16 u0xff, i16 poison>
  ret <2 x i16> %res
}

define <4 x i64> @issue_97674_getConstantOnEdge(i1 %cond) {
; CHECK-LABEL: define range(i64 0, 2) <4 x i64> @issue_97674_getConstantOnEdge(
; CHECK-SAME: i1 [[COND:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_END:.*]]
; CHECK:       [[IF_THEN]]:
; CHECK-NEXT:    [[FOLDS:%.*]] = add nuw nsw <4 x i64> zeroinitializer, <i64 1, i64 1, i64 1, i64 1>
; CHECK-NEXT:    br label %[[IF_END]]
; CHECK:       [[IF_END]]:
; CHECK-NEXT:    [[R:%.*]] = phi <4 x i64> [ <i64 1, i64 1, i64 1, i64 1>, %[[IF_THEN]] ], [ zeroinitializer, %[[ENTRY]] ]
; CHECK-NEXT:    ret <4 x i64> [[R]]
;
entry:
  br i1 %cond, label %if.then, label %if.end

if.then:
  %folds = add <4 x i64> zeroinitializer, <i64 1, i64 1, i64 1, i64 1>
  br label %if.end

if.end:
  %r = phi <4 x i64> [ %folds, %if.then ], [ zeroinitializer, %entry ]
  ret <4 x i64> %r
}

define <4 x i64> @issue_97674_getConstant() {
; CHECK-LABEL: define <4 x i64> @issue_97674_getConstant() {
; CHECK-NEXT:  [[ENTRY:.*:]]
; CHECK-NEXT:    [[FOLDS:%.*]] = add nuw nsw <4 x i64> zeroinitializer, zeroinitializer
; CHECK-NEXT:    ret <4 x i64> zeroinitializer
;
entry:
  %folds = add <4 x i64> zeroinitializer, zeroinitializer
  ret <4 x i64> %folds
}

define <2 x i16> @phi_merge1(i1 %c, <2 x i8> %a) {
; CHECK-LABEL: define range(i16 2, 259) <2 x i16> @phi_merge1(
; CHECK-SAME: i1 [[C:%.*]], <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    br i1 [[C]], label %[[IF:.*]], label %[[JOIN:.*]]
; CHECK:       [[IF]]:
; CHECK-NEXT:    br label %[[JOIN]]
; CHECK:       [[JOIN]]:
; CHECK-NEXT:    [[PHI:%.*]] = phi <2 x i16> [ [[ZEXT]], %[[ENTRY]] ], [ <i16 1, i16 2>, %[[IF]] ]
; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw <2 x i16> [[PHI]], <i16 2, i16 3>
; CHECK-NEXT:    ret <2 x i16> [[ADD]]
;
entry:
  %zext = zext <2 x i8> %a to <2 x i16>
  br i1 %c, label %if, label %join

if:
  br label %join

join:
  %phi = phi <2 x i16> [ %zext, %entry ], [ <i16 1, i16 2>, %if ]
  %add = add <2 x i16> %phi, <i16 2, i16 3>
  ret <2 x i16> %add
}

define <2 x i16> @phi_merge2(i1 %c, <2 x i8> %a) {
; CHECK-LABEL: define range(i16 2, 259) <2 x i16> @phi_merge2(
; CHECK-SAME: i1 [[C:%.*]], <2 x i8> [[A:%.*]]) {
; CHECK-NEXT:  [[ENTRY:.*]]:
; CHECK-NEXT:    [[ZEXT:%.*]] = zext <2 x i8> [[A]] to <2 x i16>
; CHECK-NEXT:    br i1 [[C]], label %[[IF:.*]], label %[[JOIN:.*]]
; CHECK:       [[IF]]:
; CHECK-NEXT:    br label %[[JOIN]]
; CHECK:       [[JOIN]]:
; CHECK-NEXT:    [[PHI:%.*]] = phi <2 x i16> [ <i16 1, i16 2>, %[[ENTRY]] ], [ [[ZEXT]], %[[IF]] ]
; CHECK-NEXT:    [[ADD:%.*]] = add nuw nsw <2 x i16> [[PHI]], <i16 2, i16 3>
; CHECK-NEXT:    ret <2 x i16> [[ADD]]
;
entry:
  %zext = zext <2 x i8> %a to <2 x i16>
  br i1 %c, label %if, label %join

if:
  br label %join

join:
  %phi = phi <2 x i16> [ <i16 1, i16 2>, %entry ], [ %zext, %if ]
  %add = add <2 x i16> %phi, <i16 2, i16 3>
  ret <2 x i16> %add
}

;; Check if ICMP instruction is constant folded or not.
define <2 x i1> @insertelement_fold1() {
; CHECK-LABEL: define <2 x i1> @insertelement_fold1() {
; CHECK-NEXT:    [[IE1:%.*]] = insertelement <2 x i32> poison, i32 10, i64 0
; CHECK-NEXT:    [[IE2:%.*]] = insertelement <2 x i32> [[IE1]], i32 20, i64 1
; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
;
  %ie1 = insertelement <2 x i32> poison, i32 10, i64 0
  %ie2 = insertelement <2 x i32> %ie1, i32 20, i64 1
  %icmp1 = icmp slt <2 x i32> %ie2, <i32 1024, i32 1024>
  ret <2 x i1> %icmp1
}

;; Check if LVI is able to handle constant vector operands
;; in InsertElementInst and CVP is able to fold ICMP instruction.
define <2 x i1> @insertelement_fold2() {
; CHECK-LABEL: define <2 x i1> @insertelement_fold2() {
; CHECK-NEXT:    [[IE1:%.*]] = insertelement <2 x i32> <i32 poison, i32 20>, i32 10, i64 0
; CHECK-NEXT:    ret <2 x i1> <i1 true, i1 true>
;
  %ie1 = insertelement <2 x i32> <i32 poison, i32 20>, i32 10, i64 0
  %icmp1 = icmp slt <2 x i32> %ie1, <i32 1024, i32 1024>
  ret <2 x i1> %icmp1
}