mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
f07815e348
With regards to overrunning, the langref (llvm/docs/LangRef.rst) specifies: (llvm.experimental.vector.insert) Elements ``idx`` through (``idx`` + num_elements(``subvec``) - 1) must be valid ``vec`` indices. If this condition cannot be determined statically but is false at runtime, then the result vector is undefined. (llvm.experimental.vector.extract) Elements ``idx`` through (``idx`` + num_elements(result_type) - 1) must be valid vector indices. If this condition cannot be determined statically but is false at runtime, then the result vector is undefined. For the non-mixed cases (e.g. inserting/extracting a scalable into/from another scalable, or inserting/extracting a fixed into/from another fixed), it is possible to statically check whether or not the above conditions are met. This was previously missing from the verifier, and if the conditions were found to be false, the result of the insertion/extraction would be replaced with an undef. With regards to invalid indices, the langref (llvm/docs/LangRef.rst) specifies: (llvm.experimental.vector.insert) ``idx`` represents the starting element number at which ``subvec`` will be inserted. ``idx`` must be a constant multiple of ``subvec``'s known minimum vector length. (llvm.experimental.vector.extract) The ``idx`` specifies the starting element number within ``vec`` from which a subvector is extracted. ``idx`` must be a constant multiple of the known-minimum vector length of the result type. Similarly, these conditions were not previously enforced in the verifier. In some circumstances, invalid indices were permitted silently, and in other circumstances, an undef was spawned where a verifier error would have been preferred. This commit adds verifier checks to enforce the constraints above. Differential Revision: https://reviews.llvm.org/D104468
125 lines
7.1 KiB
LLVM
125 lines
7.1 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt < %s -instcombine -S | FileCheck %s
|
|
|
|
; llvm.experimental.vector.insert canonicalizes to shufflevector in the fixed case. In the
|
|
; scalable case, we lower to the INSERT_SUBVECTOR ISD node.
|
|
|
|
declare <8 x i32> @llvm.experimental.vector.insert.v8i32.v2i32(<8 x i32> %vec, <2 x i32> %subvec, i64 %idx)
|
|
declare <8 x i32> @llvm.experimental.vector.insert.v8i32.v3i32(<8 x i32> %vec, <3 x i32> %subvec, i64 %idx)
|
|
declare <8 x i32> @llvm.experimental.vector.insert.v8i32.v4i32(<8 x i32> %vec, <4 x i32> %subvec, i64 %idx)
|
|
declare <8 x i32> @llvm.experimental.vector.insert.v8i32.v8i32(<8 x i32> %vec, <8 x i32> %subvec, i64 %idx)
|
|
declare <vscale x 4 x i32> @llvm.experimental.vector.insert.nxv4i32.v4i32(<vscale x 4 x i32> %vec, <4 x i32> %subvec, i64 %idx)
|
|
|
|
; ============================================================================ ;
|
|
; Trivial cases
|
|
; ============================================================================ ;
|
|
|
|
; An insert that entirely overwrites an <n x ty> with another <n x ty> is a
|
|
; nop.
|
|
define <8 x i32> @trivial_nop(<8 x i32> %vec, <8 x i32> %subvec) {
|
|
; CHECK-LABEL: @trivial_nop(
|
|
; CHECK-NEXT: ret <8 x i32> [[SUBVEC:%.*]]
|
|
;
|
|
%1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v8i32(<8 x i32> %vec, <8 x i32> %subvec, i64 0)
|
|
ret <8 x i32> %1
|
|
}
|
|
|
|
; ============================================================================ ;
|
|
; Valid canonicalizations
|
|
; ============================================================================ ;
|
|
|
|
define <8 x i32> @valid_insertion_a(<8 x i32> %vec, <2 x i32> %subvec) {
|
|
; CHECK-LABEL: @valid_insertion_a(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i32> [[SUBVEC:%.*]], <2 x i32> poison, <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[TMP1]], <8 x i32> [[VEC:%.*]], <8 x i32> <i32 0, i32 1, i32 10, i32 11, i32 12, i32 13, i32 14, i32 15>
|
|
; CHECK-NEXT: ret <8 x i32> [[TMP2]]
|
|
;
|
|
%1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v2i32(<8 x i32> %vec, <2 x i32> %subvec, i64 0)
|
|
ret <8 x i32> %1
|
|
}
|
|
|
|
define <8 x i32> @valid_insertion_b(<8 x i32> %vec, <2 x i32> %subvec) {
|
|
; CHECK-LABEL: @valid_insertion_b(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i32> [[SUBVEC:%.*]], <2 x i32> poison, <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[VEC:%.*]], <8 x i32> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 8, i32 9, i32 4, i32 5, i32 6, i32 7>
|
|
; CHECK-NEXT: ret <8 x i32> [[TMP2]]
|
|
;
|
|
%1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v2i32(<8 x i32> %vec, <2 x i32> %subvec, i64 2)
|
|
ret <8 x i32> %1
|
|
}
|
|
|
|
define <8 x i32> @valid_insertion_c(<8 x i32> %vec, <2 x i32> %subvec) {
|
|
; CHECK-LABEL: @valid_insertion_c(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i32> [[SUBVEC:%.*]], <2 x i32> poison, <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[VEC:%.*]], <8 x i32> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 6, i32 7>
|
|
; CHECK-NEXT: ret <8 x i32> [[TMP2]]
|
|
;
|
|
%1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v2i32(<8 x i32> %vec, <2 x i32> %subvec, i64 4)
|
|
ret <8 x i32> %1
|
|
}
|
|
|
|
define <8 x i32> @valid_insertion_d(<8 x i32> %vec, <2 x i32> %subvec) {
|
|
; CHECK-LABEL: @valid_insertion_d(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i32> [[SUBVEC:%.*]], <2 x i32> poison, <8 x i32> <i32 0, i32 1, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[VEC:%.*]], <8 x i32> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 8, i32 9>
|
|
; CHECK-NEXT: ret <8 x i32> [[TMP2]]
|
|
;
|
|
%1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v2i32(<8 x i32> %vec, <2 x i32> %subvec, i64 6)
|
|
ret <8 x i32> %1
|
|
}
|
|
|
|
define <8 x i32> @valid_insertion_e(<8 x i32> %vec, <4 x i32> %subvec) {
|
|
; CHECK-LABEL: @valid_insertion_e(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x i32> [[SUBVEC:%.*]], <4 x i32> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[TMP1]], <8 x i32> [[VEC:%.*]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 12, i32 13, i32 14, i32 15>
|
|
; CHECK-NEXT: ret <8 x i32> [[TMP2]]
|
|
;
|
|
%1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v4i32(<8 x i32> %vec, <4 x i32> %subvec, i64 0)
|
|
ret <8 x i32> %1
|
|
}
|
|
|
|
define <8 x i32> @valid_insertion_f(<8 x i32> %vec, <4 x i32> %subvec) {
|
|
; CHECK-LABEL: @valid_insertion_f(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x i32> [[SUBVEC:%.*]], <4 x i32> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 undef, i32 undef, i32 undef, i32 undef>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[VEC:%.*]], <8 x i32> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 2, i32 3, i32 8, i32 9, i32 10, i32 11>
|
|
; CHECK-NEXT: ret <8 x i32> [[TMP2]]
|
|
;
|
|
%1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v4i32(<8 x i32> %vec, <4 x i32> %subvec, i64 4)
|
|
ret <8 x i32> %1
|
|
}
|
|
|
|
define <8 x i32> @valid_insertion_g(<8 x i32> %vec, <3 x i32> %subvec) {
|
|
; CHECK-LABEL: @valid_insertion_g(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x i32> [[SUBVEC:%.*]], <3 x i32> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[TMP1]], <8 x i32> [[VEC:%.*]], <8 x i32> <i32 0, i32 1, i32 2, i32 11, i32 12, i32 13, i32 14, i32 15>
|
|
; CHECK-NEXT: ret <8 x i32> [[TMP2]]
|
|
;
|
|
%1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v3i32(<8 x i32> %vec, <3 x i32> %subvec, i64 0)
|
|
ret <8 x i32> %1
|
|
}
|
|
|
|
define <8 x i32> @valid_insertion_h(<8 x i32> %vec, <3 x i32> %subvec) {
|
|
; CHECK-LABEL: @valid_insertion_h(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <3 x i32> [[SUBVEC:%.*]], <3 x i32> poison, <8 x i32> <i32 0, i32 1, i32 2, i32 undef, i32 undef, i32 undef, i32 undef, i32 undef>
|
|
; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <8 x i32> [[VEC:%.*]], <8 x i32> [[TMP1]], <8 x i32> <i32 0, i32 1, i32 2, i32 8, i32 9, i32 10, i32 6, i32 7>
|
|
; CHECK-NEXT: ret <8 x i32> [[TMP2]]
|
|
;
|
|
%1 = call <8 x i32> @llvm.experimental.vector.insert.v8i32.v3i32(<8 x i32> %vec, <3 x i32> %subvec, i64 3)
|
|
ret <8 x i32> %1
|
|
}
|
|
|
|
; ============================================================================ ;
|
|
; Scalable cases
|
|
; ============================================================================ ;
|
|
|
|
; Scalable insertions should not be canonicalized. This will be lowered to the
|
|
; INSERT_SUBVECTOR ISD node later.
|
|
define <vscale x 4 x i32> @scalable_insert(<vscale x 4 x i32> %vec, <4 x i32> %subvec) {
|
|
; CHECK-LABEL: @scalable_insert(
|
|
; CHECK-NEXT: [[TMP1:%.*]] = call <vscale x 4 x i32> @llvm.experimental.vector.insert.nxv4i32.v4i32(<vscale x 4 x i32> [[VEC:%.*]], <4 x i32> [[SUBVEC:%.*]], i64 0)
|
|
; CHECK-NEXT: ret <vscale x 4 x i32> [[TMP1]]
|
|
;
|
|
%1 = call <vscale x 4 x i32> @llvm.experimental.vector.insert.nxv4i32.v4i32(<vscale x 4 x i32> %vec, <4 x i32> %subvec, i64 0)
|
|
ret <vscale x 4 x i32> %1
|
|
}
|