blob: fcb958b43b0c5b32c317efcaa3940444cdbc60bc [file] [log] [blame]
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -instcombine -S < %s | FileCheck --check-prefix OPT %s
target triple = "aarch64"
; Most of the testing is covered by the lastb cases, but here we ensure that
; lasta with a predicate having no active lanes is treated as an alias to
; extracting the first vector element.
define i8 @lasta_extractelement_0(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lasta_extractelement_0(
; OPT-NEXT: [[E0:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 0
; OPT-NEXT: ret i8 [[E0]]
;
%e0 = tail call i8 @llvm.aarch64.sve.lasta.nxv16i8(<vscale x 16 x i1> zeroinitializer, <vscale x 16 x i8> %v)
ret i8 %e0
}
; Most of the testing is covered by the lastb cases, but here we check the
; resulting extraction index is one more than the lastb case because lasta
; extracts the element after the last active.
define i8 @lasta_extractelement_8(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lasta_extractelement_8(
; OPT-NEXT: [[E1:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 8
; OPT-NEXT: ret i8 [[E1]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 8)
%e1 = tail call i8 @llvm.aarch64.sve.lasta.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e1
}
define i8 @lastb_extractelement_0(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_0(
; OPT-NEXT: [[E0:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 0
; OPT-NEXT: ret i8 [[E0]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 1)
%e0 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e0
}
define i8 @lastb_extractelement_1(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_1(
; OPT-NEXT: [[E1:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 1
; OPT-NEXT: ret i8 [[E1]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 2)
%e1 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e1
}
define i8 @lastb_extractelement_2(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_2(
; OPT-NEXT: [[E2:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 2
; OPT-NEXT: ret i8 [[E2]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 3)
%e2 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e2
}
define i8 @lastb_extractelement_3(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_3(
; OPT-NEXT: [[E3:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 3
; OPT-NEXT: ret i8 [[E3]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 4)
%e3 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e3
}
define i8 @lastb_extractelement_4(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_4(
; OPT-NEXT: [[E4:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 4
; OPT-NEXT: ret i8 [[E4]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 5)
%e4 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e4
}
define i8 @lastb_extractelement_5(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_5(
; OPT-NEXT: [[E5:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 5
; OPT-NEXT: ret i8 [[E5]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 6)
%e5 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e5
}
define i8 @lastb_extractelement_6(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_6(
; OPT-NEXT: [[E6:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 6
; OPT-NEXT: ret i8 [[E6]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 7)
%e6 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e6
}
define i8 @lastb_extractelement_7(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_7(
; OPT-NEXT: [[E7:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 7
; OPT-NEXT: ret i8 [[E7]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 8)
%e7 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e7
}
define i8 @lastb_extractelement_15(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_15(
; OPT-NEXT: [[E15:%.*]] = extractelement <vscale x 16 x i8> [[V:%.*]], i64 15
; OPT-NEXT: ret i8 [[E15]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 9)
%e15 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e15
}
; No transformation because the requested element is beyond the range of the
; known minimum element count so we maintain the user's intentions.
define i8 @lastb_extractelement_31(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_31(
; OPT-NEXT: [[PG:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 10)
; OPT-NEXT: [[E31:%.*]] = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[V:%.*]])
; OPT-NEXT: ret i8 [[E31]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 10)
%e31 = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e31
}
; No transformation because the ptrue's predicate pattern is bogus and thus
; nothing can be inferred about the result.
define i8 @lastb_extractelement_invalid_predicate_pattern(<vscale x 16 x i8> %v) #0 {
; OPT-LABEL: @lastb_extractelement_invalid_predicate_pattern(
; OPT-NEXT: [[PG:%.*]] = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 15)
; OPT-NEXT: [[E:%.*]] = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG]], <vscale x 16 x i8> [[V:%.*]])
; OPT-NEXT: ret i8 [[E]]
;
%pg = tail call <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32 15)
%e = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %v)
ret i8 %e
}
; Return the splatted value irrespective of the predicate.
define i8 @lasta_splat(<vscale x 16 x i1> %pg, i8 %a) #0 {
; OPT-LABEL: @lasta_splat(
; OPT-NEXT: ret i8 [[A:%.*]]
;
%splat_insert = insertelement <vscale x 16 x i8> poison, i8 %a, i32 0
%splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
%last = tail call i8 @llvm.aarch64.sve.lasta.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %splat)
ret i8 %last
}
define i8 @lastb_splat(<vscale x 16 x i1> %pg, i8 %a) #0 {
; OPT-LABEL: @lastb_splat(
; OPT-NEXT: ret i8 [[A:%.*]]
;
%splat_insert = insertelement <vscale x 16 x i8> poison, i8 %a, i32 0
%splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
%last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %splat)
ret i8 %last
}
; Check that we move the lastb before the binary operation so that the new binary op is scalar.
define i8 @lastb_binop_RHS_splat_sdiv(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
; OPT-LABEL: @lastb_binop_RHS_splat_sdiv(
; OPT-NEXT: [[TMP1:%.*]] = call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[VECTOR:%.*]])
; OPT-NEXT: [[BINOP1:%.*]] = sdiv i8 [[TMP1]], [[SCALAR:%.*]]
; OPT-NEXT: ret i8 [[BINOP1]]
;
%splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
%splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
%binop = sdiv <vscale x 16 x i8> %vector, %splat
%last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
ret i8 %last
}
define i8 @lastb_binop_RHS_splat_sdiv_exact(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
; OPT-LABEL: @lastb_binop_RHS_splat_sdiv_exact(
; OPT-NEXT: [[TMP1:%.*]] = call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[VECTOR:%.*]])
; OPT-NEXT: [[BINOP1:%.*]] = sdiv exact i8 [[TMP1]], [[SCALAR:%.*]]
; OPT-NEXT: ret i8 [[BINOP1]]
;
%splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
%splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
%binop = sdiv exact <vscale x 16 x i8> %vector, %splat
%last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
ret i8 %last
}
define float @lastb_binop_RHS_splat_fdiv_float_fast(<vscale x 4 x i1> %pg, float %scalar, <vscale x 4 x float> %vector) #0 {
; OPT-LABEL: @lastb_binop_RHS_splat_fdiv_float_fast(
; OPT-NEXT: [[TMP1:%.*]] = call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x float> [[VECTOR:%.*]])
; OPT-NEXT: [[BINOP1:%.*]] = fdiv fast float [[TMP1]], [[SCALAR:%.*]]
; OPT-NEXT: ret float [[BINOP1]]
;
%splat_insert = insertelement <vscale x 4 x float> poison, float %scalar, i32 0
%splat = shufflevector <vscale x 4 x float> %splat_insert, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
%binop = fdiv fast <vscale x 4 x float> %vector, %splat
%last = tail call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> %binop)
ret float %last
}
define float @lastb_binop_RHS_splat_fdiv_float(<vscale x 4 x i1> %pg, float %scalar, <vscale x 4 x float> %vector) #0 {
; OPT-LABEL: @lastb_binop_RHS_splat_fdiv_float(
; OPT-NEXT: [[TMP1:%.*]] = call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x float> [[VECTOR:%.*]])
; OPT-NEXT: [[BINOP1:%.*]] = fdiv float [[TMP1]], [[SCALAR:%.*]]
; OPT-NEXT: ret float [[BINOP1]]
;
%splat_insert = insertelement <vscale x 4 x float> poison, float %scalar, i32 0
%splat = shufflevector <vscale x 4 x float> %splat_insert, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
%binop = fdiv <vscale x 4 x float> %vector, %splat
%last = tail call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> %binop)
ret float %last
}
define i8 @lastb_binop_LHS_splat_sdiv(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
; OPT-LABEL: @lastb_binop_LHS_splat_sdiv(
; OPT-NEXT: [[TMP1:%.*]] = call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[VECTOR:%.*]])
; OPT-NEXT: [[BINOP1:%.*]] = sdiv i8 [[SCALAR:%.*]], [[TMP1]]
; OPT-NEXT: ret i8 [[BINOP1]]
;
%splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
%splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
%binop = sdiv <vscale x 16 x i8> %splat, %vector
%last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
ret i8 %last
}
define i8 @lastb_binop_LHS_splat_sdiv_exact(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
; OPT-LABEL: @lastb_binop_LHS_splat_sdiv_exact(
; OPT-NEXT: [[TMP1:%.*]] = call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[VECTOR:%.*]])
; OPT-NEXT: [[BINOP1:%.*]] = sdiv exact i8 [[SCALAR:%.*]], [[TMP1]]
; OPT-NEXT: ret i8 [[BINOP1]]
;
%splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
%splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
%binop = sdiv exact <vscale x 16 x i8> %splat, %vector
%last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
ret i8 %last
}
define float @lastb_binop_LHS_splat_fdiv_float_fast(<vscale x 4 x i1> %pg, float %scalar, <vscale x 4 x float> %vector) #0 {
; OPT-LABEL: @lastb_binop_LHS_splat_fdiv_float_fast(
; OPT-NEXT: [[TMP1:%.*]] = call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x float> [[VECTOR:%.*]])
; OPT-NEXT: [[BINOP1:%.*]] = fdiv fast float [[SCALAR:%.*]], [[TMP1]]
; OPT-NEXT: ret float [[BINOP1]]
;
%splat_insert = insertelement <vscale x 4 x float> poison, float %scalar, i32 0
%splat = shufflevector <vscale x 4 x float> %splat_insert, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
%binop = fdiv fast <vscale x 4 x float> %splat, %vector
%last = tail call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> %binop)
ret float %last
}
define float @lastb_binop_LHS_splat_fdiv_float(<vscale x 4 x i1> %pg, float %scalar, <vscale x 4 x float> %vector) #0 {
; OPT-LABEL: @lastb_binop_LHS_splat_fdiv_float(
; OPT-NEXT: [[TMP1:%.*]] = call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> [[PG:%.*]], <vscale x 4 x float> [[VECTOR:%.*]])
; OPT-NEXT: [[BINOP1:%.*]] = fdiv float [[SCALAR:%.*]], [[TMP1]]
; OPT-NEXT: ret float [[BINOP1]]
;
%splat_insert = insertelement <vscale x 4 x float> poison, float %scalar, i32 0
%splat = shufflevector <vscale x 4 x float> %splat_insert, <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer
%binop = fdiv <vscale x 4 x float> %splat, %vector
%last = tail call float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1> %pg, <vscale x 4 x float> %binop)
ret float %last
}
define i8 @lastb_binop_LHS_RHS_splat_sdiv(<vscale x 16 x i1> %pg, i8 %scalar1, i8 %scalar2) #0 {
; OPT-LABEL: @lastb_binop_LHS_RHS_splat_sdiv(
; OPT-NEXT: [[BINOP1:%.*]] = sdiv i8 [[SCALAR1:%.*]], [[SCALAR2:%.*]]
; OPT-NEXT: ret i8 [[BINOP1]]
;
%splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar1, i8 0
%splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
%splat_insert2 = insertelement <vscale x 16 x i8> poison, i8 %scalar2, i8 0
%splat2 = shufflevector <vscale x 16 x i8> %splat_insert2, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
%binop = sdiv <vscale x 16 x i8> %splat, %splat2
%last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
ret i8 %last
}
; Check that we don't do anything as the binary op has multiple uses.
define i8 @lastb_binop_nochange(<vscale x 16 x i1> %pg, i8 %scalar, <vscale x 16 x i8> %vector) #0 {
; OPT-LABEL: @lastb_binop_nochange(
; OPT-NEXT: [[SPLAT_INSERT:%.*]] = insertelement <vscale x 16 x i8> poison, i8 [[SCALAR:%.*]], i32 0
; OPT-NEXT: [[SPLAT:%.*]] = shufflevector <vscale x 16 x i8> [[SPLAT_INSERT]], <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
; OPT-NEXT: [[BINOP:%.*]] = sdiv <vscale x 16 x i8> [[VECTOR:%.*]], [[SPLAT]]
; OPT-NEXT: [[LAST:%.*]] = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> [[PG:%.*]], <vscale x 16 x i8> [[BINOP]])
; OPT-NEXT: call void @use(<vscale x 16 x i8> [[BINOP]])
; OPT-NEXT: ret i8 [[LAST]]
;
%splat_insert = insertelement <vscale x 16 x i8> poison, i8 %scalar, i32 0
%splat = shufflevector <vscale x 16 x i8> %splat_insert, <vscale x 16 x i8> poison, <vscale x 16 x i32> zeroinitializer
%binop = sdiv <vscale x 16 x i8> %vector, %splat
%last = tail call i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1> %pg, <vscale x 16 x i8> %binop)
call void @use(<vscale x 16 x i8> %binop)
ret i8 %last
}
declare void @use(<vscale x 16 x i8>)
declare <vscale x 16 x i1> @llvm.aarch64.sve.ptrue.nxv16i1(i32)
declare i8 @llvm.aarch64.sve.lasta.nxv16i8(<vscale x 16 x i1>, <vscale x 16 x i8>)
declare i8 @llvm.aarch64.sve.lastb.nxv16i8(<vscale x 16 x i1>, <vscale x 16 x i8>)
declare float @llvm.aarch64.sve.lastb.nxv4f32(<vscale x 4 x i1>, <vscale x 4 x float>)
attributes #0 = { "target-features"="+sve" }