mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-13 20:32:21 +00:00
ARM64: implement cunning optimisation from AArch64
A vector extract followed by a dup can become a single instruction even if the types don't match. AArch64 handled this in ISelLowering, but a few reasonably simple patterns can take care of it in TableGen, so that's where I've put it. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@206573 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
e7ec66e56b
commit
70b63374f2
@ -3026,6 +3026,59 @@ def : Pat<(v4f32 (ARM64duplane32 (v4f32 V128:$Rn), VectorIndexS:$imm)),
|
|||||||
def : Pat<(v2f64 (ARM64duplane64 (v2f64 V128:$Rn), VectorIndexD:$imm)),
|
def : Pat<(v2f64 (ARM64duplane64 (v2f64 V128:$Rn), VectorIndexD:$imm)),
|
||||||
(DUPv2i64lane V128:$Rn, VectorIndexD:$imm)>;
|
(DUPv2i64lane V128:$Rn, VectorIndexD:$imm)>;
|
||||||
|
|
||||||
|
// If there's an (ARM64dup (vector_extract ...) ...), we can use a duplane
|
||||||
|
// instruction even if the types don't match: we just have to remap the lane
|
||||||
|
// carefully. N.b. this trick only applies to truncations.
|
||||||
|
def VecIndex_x2 : SDNodeXForm<imm, [{
|
||||||
|
return CurDAG->getTargetConstant(2 * N->getZExtValue(), MVT::i64);
|
||||||
|
}]>;
|
||||||
|
def VecIndex_x4 : SDNodeXForm<imm, [{
|
||||||
|
return CurDAG->getTargetConstant(4 * N->getZExtValue(), MVT::i64);
|
||||||
|
}]>;
|
||||||
|
def VecIndex_x8 : SDNodeXForm<imm, [{
|
||||||
|
return CurDAG->getTargetConstant(8 * N->getZExtValue(), MVT::i64);
|
||||||
|
}]>;
|
||||||
|
|
||||||
|
multiclass DUPWithTruncPats<ValueType ResVT, ValueType Src64VT,
|
||||||
|
ValueType Src128VT, ValueType ScalVT,
|
||||||
|
Instruction DUP, SDNodeXForm IdxXFORM> {
|
||||||
|
def : Pat<(ResVT (ARM64dup (ScalVT (vector_extract (Src128VT V128:$Rn),
|
||||||
|
imm:$idx)))),
|
||||||
|
(DUP V128:$Rn, (IdxXFORM imm:$idx))>;
|
||||||
|
|
||||||
|
def : Pat<(ResVT (ARM64dup (ScalVT (vector_extract (Src64VT V64:$Rn),
|
||||||
|
imm:$idx)))),
|
||||||
|
(DUP (SUBREG_TO_REG (i64 0), V64:$Rn, dsub), (IdxXFORM imm:$idx))>;
|
||||||
|
}
|
||||||
|
|
||||||
|
defm : DUPWithTruncPats<v8i8, v4i16, v8i16, i32, DUPv8i8lane, VecIndex_x2>;
|
||||||
|
defm : DUPWithTruncPats<v8i8, v2i32, v4i32, i32, DUPv8i8lane, VecIndex_x4>;
|
||||||
|
defm : DUPWithTruncPats<v4i16, v2i32, v4i32, i32, DUPv4i16lane, VecIndex_x2>;
|
||||||
|
|
||||||
|
defm : DUPWithTruncPats<v16i8, v4i16, v8i16, i32, DUPv16i8lane, VecIndex_x2>;
|
||||||
|
defm : DUPWithTruncPats<v16i8, v2i32, v4i32, i32, DUPv16i8lane, VecIndex_x4>;
|
||||||
|
defm : DUPWithTruncPats<v8i16, v2i32, v4i32, i32, DUPv8i16lane, VecIndex_x2>;
|
||||||
|
|
||||||
|
multiclass DUPWithTrunci64Pats<ValueType ResVT, Instruction DUP,
|
||||||
|
SDNodeXForm IdxXFORM> {
|
||||||
|
def : Pat<(ResVT (ARM64dup (i32 (trunc (vector_extract (v2i64 V128:$Rn),
|
||||||
|
imm:$idx))))),
|
||||||
|
(DUP V128:$Rn, (IdxXFORM imm:$idx))>;
|
||||||
|
|
||||||
|
def : Pat<(ResVT (ARM64dup (i32 (trunc (vector_extract (v1i64 V64:$Rn),
|
||||||
|
imm:$idx))))),
|
||||||
|
(DUP (SUBREG_TO_REG (i64 0), V64:$Rn, dsub), (IdxXFORM imm:$idx))>;
|
||||||
|
}
|
||||||
|
|
||||||
|
defm : DUPWithTrunci64Pats<v8i8, DUPv8i8lane, VecIndex_x8>;
|
||||||
|
defm : DUPWithTrunci64Pats<v4i16, DUPv4i16lane, VecIndex_x4>;
|
||||||
|
defm : DUPWithTrunci64Pats<v2i32, DUPv2i32lane, VecIndex_x2>;
|
||||||
|
|
||||||
|
defm : DUPWithTrunci64Pats<v16i8, DUPv16i8lane, VecIndex_x8>;
|
||||||
|
defm : DUPWithTrunci64Pats<v8i16, DUPv8i16lane, VecIndex_x4>;
|
||||||
|
defm : DUPWithTrunci64Pats<v4i32, DUPv4i32lane, VecIndex_x2>;
|
||||||
|
|
||||||
|
// SMOV and UMOV definitions, with some extra patterns for convenience
|
||||||
defm SMOV : SMov;
|
defm SMOV : SMov;
|
||||||
defm UMOV : UMov;
|
defm UMOV : UMov;
|
||||||
|
|
||||||
|
@ -297,10 +297,11 @@ define <2 x i64> @h(i64 %a, i64 %b) nounwind readnone {
|
|||||||
; the scalar corresponding to the vector type is illegal (e.g. a <4 x i16>
|
; the scalar corresponding to the vector type is illegal (e.g. a <4 x i16>
|
||||||
; BUILD_VECTOR will have an i32 as its source). In that case, the operation is
|
; BUILD_VECTOR will have an i32 as its source). In that case, the operation is
|
||||||
; not a simple "dup vD.4h, vN.h[idx]" after all, and we crashed.
|
; not a simple "dup vD.4h, vN.h[idx]" after all, and we crashed.
|
||||||
|
;
|
||||||
|
; *However*, it is a dup vD.4h, vN.h[2*idx].
|
||||||
define <4 x i16> @test_build_illegal(<4 x i32> %in) {
|
define <4 x i16> @test_build_illegal(<4 x i32> %in) {
|
||||||
; CHECK-LABEL: test_build_illegal:
|
; CHECK-LABEL: test_build_illegal:
|
||||||
; CHECK: umov.s [[WTMP:w[0-9]+]], v0[3]
|
; CHECK: dup.4h v0, v0[6]
|
||||||
; CHECK: dup.4h v0, [[WTMP]]
|
|
||||||
%val = extractelement <4 x i32> %in, i32 3
|
%val = extractelement <4 x i32> %in, i32 3
|
||||||
%smallval = trunc i32 %val to i16
|
%smallval = trunc i32 %val to i16
|
||||||
%vec = insertelement <4x i16> undef, i16 %smallval, i32 3
|
%vec = insertelement <4x i16> undef, i16 %smallval, i32 3
|
||||||
|
Loading…
Reference in New Issue
Block a user