Skip to content

Commit 9f63dc3

Browse files
[SVE] Fix shift-by-imm patterns used by asr, lsl & lsr intrinsics.
Right shift patterns will no longer incorrectly accept a shift amount of zero. At the same time they will allow larger shift amounts that are now saturated to their upper bound. Patterns have been extended to enable immediate forms for shifts taking an arbitrary predicate. This patch also unifies the code path for immediate parsing so the i64 based shifts are no longer treated specially. Differential Revision: https://reviews.llvm.org/D86084
1 parent 5eb705d commit 9f63dc3

File tree

4 files changed

+633
-186
lines changed

4 files changed

+633
-186
lines changed

llvm/lib/Target/AArch64/AArch64ISelDAGToDAG.cpp

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -190,9 +190,9 @@ class AArch64DAGToDAGISel : public SelectionDAGISel {
190190
return SelectSVELogicalImm(N, VT, Imm);
191191
}
192192

193-
template <unsigned Low, unsigned High>
194-
bool SelectSVEShiftImm64(SDValue N, SDValue &Imm) {
195-
return SelectSVEShiftImm64(N, Low, High, Imm);
193+
template <unsigned Low, unsigned High, bool AllowSaturation = false>
194+
bool SelectSVEShiftImm(SDValue N, SDValue &Imm) {
195+
return SelectSVEShiftImm(N, Low, High, AllowSaturation, Imm);
196196
}
197197

198198
// Returns a suitable CNT/INC/DEC/RDVL multiplier to calculate VSCALE*N.
@@ -323,8 +323,8 @@ class AArch64DAGToDAGISel : public SelectionDAGISel {
323323
bool SelectSVELogicalImm(SDValue N, MVT VT, SDValue &Imm);
324324

325325
bool SelectSVESignedArithImm(SDValue N, SDValue &Imm);
326-
bool SelectSVEShiftImm64(SDValue N, uint64_t Low, uint64_t High,
327-
SDValue &Imm);
326+
bool SelectSVEShiftImm(SDValue N, uint64_t Low, uint64_t High,
327+
bool AllowSaturation, SDValue &Imm);
328328

329329
bool SelectSVEArithImm(SDValue N, SDValue &Imm);
330330
bool SelectSVERegRegAddrMode(SDValue N, unsigned Scale, SDValue &Base,
@@ -3177,19 +3177,30 @@ bool AArch64DAGToDAGISel::SelectSVELogicalImm(SDValue N, MVT VT, SDValue &Imm) {
31773177
return false;
31783178
}
31793179

3180-
// This method is only needed to "cast" i64s into i32s when the value
3181-
// is a valid shift which has been splatted into a vector with i64 elements.
3182-
// Every other type is fine in tablegen.
3183-
bool AArch64DAGToDAGISel::SelectSVEShiftImm64(SDValue N, uint64_t Low,
3184-
uint64_t High, SDValue &Imm) {
3180+
// SVE shift intrinsics allow shift amounts larger than the element's bitwidth.
3181+
// Rather than attempt to normalise everything we can sometimes saturate the
3182+
// shift amount during selection. This function also allows for consistent
3183+
// isel patterns by ensuring the resulting "Imm" node is of the i32 type
3184+
// required by the instructions.
3185+
bool AArch64DAGToDAGISel::SelectSVEShiftImm(SDValue N, uint64_t Low,
3186+
uint64_t High, bool AllowSaturation,
3187+
SDValue &Imm) {
31853188
if (auto *CN = dyn_cast<ConstantSDNode>(N)) {
31863189
uint64_t ImmVal = CN->getZExtValue();
3187-
SDLoc DL(N);
31883190

3189-
if (ImmVal >= Low && ImmVal <= High) {
3190-
Imm = CurDAG->getTargetConstant(ImmVal, DL, MVT::i32);
3191-
return true;
3191+
// Reject shift amounts that are too small.
3192+
if (ImmVal < Low)
3193+
return false;
3194+
3195+
// Reject or saturate shift amounts that are too big.
3196+
if (ImmVal > High) {
3197+
if (!AllowSaturation)
3198+
return false;
3199+
ImmVal = High;
31923200
}
3201+
3202+
Imm = CurDAG->getTargetConstant(ImmVal, SDLoc(N), MVT::i32);
3203+
return true;
31933204
}
31943205

31953206
return false;

llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,10 +1343,10 @@ multiclass sve_prefetch<SDPatternOperator prefetch, ValueType PredTy, Instructio
13431343
defm LSL_WIDE_ZZZ : sve_int_bin_cons_shift_wide<0b11, "lsl">;
13441344

13451345
// Predicated shifts
1346-
defm ASR_ZPmI : sve_int_bin_pred_shift_imm_right<0b0000, "asr", "ASR_ZPZI">;
1347-
defm LSR_ZPmI : sve_int_bin_pred_shift_imm_right<0b0001, "lsr", "LSR_ZPZI">;
1348-
defm LSL_ZPmI : sve_int_bin_pred_shift_imm_left< 0b0011, "lsl">;
1349-
defm ASRD_ZPmI : sve_int_bin_pred_shift_imm_right<0b0100, "asrd", "ASRD_ZPZI", int_aarch64_sve_asrd>;
1346+
defm ASR_ZPmI : sve_int_bin_pred_shift_imm_right_dup<0b0000, "asr", "ASR_ZPZI", int_aarch64_sve_asr>;
1347+
defm LSR_ZPmI : sve_int_bin_pred_shift_imm_right_dup<0b0001, "lsr", "LSR_ZPZI", int_aarch64_sve_lsr>;
1348+
defm LSL_ZPmI : sve_int_bin_pred_shift_imm_left_dup< 0b0011, "lsl", "LSL_ZPZI", int_aarch64_sve_lsl>;
1349+
defm ASRD_ZPmI : sve_int_bin_pred_shift_imm_right< 0b0100, "asrd", "ASRD_ZPZI", int_aarch64_sve_asrd>;
13501350

13511351
let Predicates = [HasSVE, UseExperimentalZeroingPseudos] in {
13521352
defm ASR_ZPZZ : sve_int_bin_pred_zeroing_bhsd<int_aarch64_sve_asr>;
@@ -2385,11 +2385,11 @@ let Predicates = [HasSVE2] in {
23852385
}
23862386

23872387
// SVE2 predicated shifts
2388-
defm SQSHL_ZPmI : sve_int_bin_pred_shift_imm_left< 0b0110, "sqshl", "SQSHL_ZPZI">;
2389-
defm UQSHL_ZPmI : sve_int_bin_pred_shift_imm_left< 0b0111, "uqshl", "UQSHL_ZPZI">;
2390-
defm SRSHR_ZPmI : sve_int_bin_pred_shift_imm_right<0b1100, "srshr", "SRSHR_ZPZI", int_aarch64_sve_srshr>;
2391-
defm URSHR_ZPmI : sve_int_bin_pred_shift_imm_right<0b1101, "urshr", "URSHR_ZPZI", int_aarch64_sve_urshr>;
2392-
defm SQSHLU_ZPmI : sve2_int_bin_pred_shift_imm_left< 0b1111, "sqshlu", "SQSHLU_ZPZI", int_aarch64_sve_sqshlu>;
2388+
defm SQSHL_ZPmI : sve_int_bin_pred_shift_imm_left< 0b0110, "sqshl", "SQSHL_ZPZI">;
2389+
defm UQSHL_ZPmI : sve_int_bin_pred_shift_imm_left< 0b0111, "uqshl", "UQSHL_ZPZI">;
2390+
defm SRSHR_ZPmI : sve_int_bin_pred_shift_imm_right<0b1100, "srshr", "SRSHR_ZPZI", int_aarch64_sve_srshr>;
2391+
defm URSHR_ZPmI : sve_int_bin_pred_shift_imm_right<0b1101, "urshr", "URSHR_ZPZI", int_aarch64_sve_urshr>;
2392+
defm SQSHLU_ZPmI : sve_int_bin_pred_shift_imm_left< 0b1111, "sqshlu", "SQSHLU_ZPZI", int_aarch64_sve_sqshlu>;
23932393

23942394
// SVE2 integer add/subtract long
23952395
defm SADDLB_ZZZ : sve2_wide_int_arith_long<0b00000, "saddlb", int_aarch64_sve_saddlb>;

llvm/lib/Target/AArch64/SVEInstrFormats.td

Lines changed: 54 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,14 @@ def SVE8BitLslImm : ComplexPattern<i32, 2, "SelectSVE8BitLslImm", [imm]>;
209209
def SVEArithUImmPat : ComplexPattern<i32, 1, "SelectSVEArithImm", []>;
210210
def SVEArithSImmPat : ComplexPattern<i32, 1, "SelectSVESignedArithImm", []>;
211211

212-
def SVEShiftImm64 : ComplexPattern<i32, 1, "SelectSVEShiftImm64<0, 64>", []>;
212+
def SVEShiftImmL8 : ComplexPattern<i32, 1, "SelectSVEShiftImm<0, 7>", []>;
213+
def SVEShiftImmL16 : ComplexPattern<i32, 1, "SelectSVEShiftImm<0, 15>", []>;
214+
def SVEShiftImmL32 : ComplexPattern<i32, 1, "SelectSVEShiftImm<0, 31>", []>;
215+
def SVEShiftImmL64 : ComplexPattern<i32, 1, "SelectSVEShiftImm<0, 63>", []>;
216+
def SVEShiftImmR8 : ComplexPattern<i32, 1, "SelectSVEShiftImm<1, 8, true>", []>;
217+
def SVEShiftImmR16 : ComplexPattern<i32, 1, "SelectSVEShiftImm<1, 16, true>", []>;
218+
def SVEShiftImmR32 : ComplexPattern<i32, 1, "SelectSVEShiftImm<1, 32, true>", []>;
219+
def SVEShiftImmR64 : ComplexPattern<i32, 1, "SelectSVEShiftImm<1, 64, true>", []>;
213220

214221
class SVEExactFPImm<string Suffix, string ValA, string ValB> : AsmOperandClass {
215222
let Name = "SVEExactFPImmOperand" # Suffix;
@@ -315,11 +322,6 @@ class SVE_1_Op_Imm_OptLsl_Pat<ValueType vt, SDPatternOperator op, ZPRRegOp zprty
315322
: Pat<(vt (op (vt zprty:$Op1), (vt (AArch64dup (it (cpx i32:$imm, i32:$shift)))))),
316323
(inst $Op1, i32:$imm, i32:$shift)>;
317324

318-
class SVE_1_Op_Imm_Shift_Pred_Pat<ValueType vt, ValueType pt, SDPatternOperator op,
319-
ZPRRegOp zprty, Operand ImmTy, Instruction inst>
320-
: Pat<(vt (op (pt (AArch64ptrue 31)), (vt zprty:$Op1), (vt (AArch64dup (ImmTy:$imm))))),
321-
(inst $Op1, ImmTy:$imm)>;
322-
323325
class SVE_1_Op_Imm_Arith_Pred_Pat<ValueType vt, ValueType pt, SDPatternOperator op,
324326
ZPRRegOp zprty, ValueType it, ComplexPattern cpx, Instruction inst>
325327
: Pat<(vt (op (pt (AArch64ptrue 31)), (vt zprty:$Op1), (vt (AArch64dup (it (cpx i32:$imm)))))),
@@ -409,6 +411,18 @@ class SVE_InReg_Extend<ValueType vt, SDPatternOperator op, ValueType pt,
409411
: Pat<(vt (op pt:$Pg, vt:$Src, inreg_vt, vt:$PassThru)),
410412
(inst $PassThru, $Pg, $Src)>;
411413

414+
class SVE_Shift_DupImm_Pred_Pat<ValueType vt, SDPatternOperator op,
415+
ValueType pt, ValueType it,
416+
ComplexPattern cast, Instruction inst>
417+
: Pat<(vt (op pt:$Pg, vt:$Rn, (vt (AArch64dup (it (cast i32:$imm)))))),
418+
(inst $Pg, $Rn, i32:$imm)>;
419+
420+
class SVE_Shift_DupImm_All_Active_Pat<ValueType vt, SDPatternOperator op,
421+
ValueType pt, ValueType it,
422+
ComplexPattern cast, Instruction inst>
423+
: Pat<(vt (op (pt (AArch64ptrue 31)), vt:$Rn, (vt (AArch64dup (it (cast i32:$imm)))))),
424+
(inst $Rn, i32:$imm)>;
425+
412426
//
413427
// Pseudo -> Instruction mappings
414428
//
@@ -4761,38 +4775,19 @@ class sve_int_bin_pred_shift_imm<bits<4> tsz8_64, bits<4> opc, string asm,
47614775
let ElementSize = zprty.ElementSize;
47624776
}
47634777

4764-
multiclass sve_int_bin_pred_shift_imm_left<bits<4> opc, string asm, string psName=""> {
4765-
def _B : SVEPseudo2Instr<psName # _B, 1>,
4778+
multiclass sve_int_bin_pred_shift_imm_left<bits<4> opc, string asm, string Ps,
4779+
SDPatternOperator op = null_frag> {
4780+
def _B : SVEPseudo2Instr<Ps # _B, 1>,
47664781
sve_int_bin_pred_shift_imm<{0,0,0,1}, opc, asm, ZPR8, vecshiftL8>;
4767-
def _H : SVEPseudo2Instr<psName # _H, 1>,
4768-
sve_int_bin_pred_shift_imm<{0,0,1,?}, opc, asm, ZPR16, vecshiftL16> {
4769-
let Inst{8} = imm{3};
4770-
}
4771-
def _S : SVEPseudo2Instr<psName # _S, 1>,
4772-
sve_int_bin_pred_shift_imm<{0,1,?,?}, opc, asm, ZPR32, vecshiftL32> {
4773-
let Inst{9-8} = imm{4-3};
4774-
}
4775-
def _D : SVEPseudo2Instr<psName # _D, 1>,
4776-
sve_int_bin_pred_shift_imm<{1,?,?,?}, opc, asm, ZPR64, vecshiftL64> {
4777-
let Inst{22} = imm{5};
4778-
let Inst{9-8} = imm{4-3};
4779-
}
4780-
}
4781-
4782-
multiclass sve2_int_bin_pred_shift_imm_left<bits<4> opc, string asm,
4783-
string psName,
4784-
SDPatternOperator op> {
4785-
4786-
def _B : SVEPseudo2Instr<psName # _B, 1>, sve_int_bin_pred_shift_imm<{0,0,0,1}, opc, asm, ZPR8, vecshiftL8>;
4787-
def _H : SVEPseudo2Instr<psName # _H, 1>,
4782+
def _H : SVEPseudo2Instr<Ps # _H, 1>,
47884783
sve_int_bin_pred_shift_imm<{0,0,1,?}, opc, asm, ZPR16, vecshiftL16> {
47894784
let Inst{8} = imm{3};
47904785
}
4791-
def _S : SVEPseudo2Instr<psName # _S, 1>,
4786+
def _S : SVEPseudo2Instr<Ps # _S, 1>,
47924787
sve_int_bin_pred_shift_imm<{0,1,?,?}, opc, asm, ZPR32, vecshiftL32> {
47934788
let Inst{9-8} = imm{4-3};
47944789
}
4795-
def _D : SVEPseudo2Instr<psName # _D, 1>,
4790+
def _D : SVEPseudo2Instr<Ps # _D, 1>,
47964791
sve_int_bin_pred_shift_imm<{1,?,?,?}, opc, asm, ZPR64, vecshiftL64> {
47974792
let Inst{22} = imm{5};
47984793
let Inst{9-8} = imm{4-3};
@@ -4804,6 +4799,16 @@ multiclass sve2_int_bin_pred_shift_imm_left<bits<4> opc, string asm,
48044799
def : SVE_3_Op_Imm_Pat<nxv2i64, op, nxv2i1, nxv2i64, i32, tvecshiftL64, !cast<Instruction>(NAME # _D)>;
48054800
}
48064801

4802+
// As above but shift amount takes the form of a "vector immediate".
4803+
multiclass sve_int_bin_pred_shift_imm_left_dup<bits<4> opc, string asm,
4804+
string Ps, SDPatternOperator op>
4805+
: sve_int_bin_pred_shift_imm_left<opc, asm, Ps, null_frag> {
4806+
def : SVE_Shift_DupImm_Pred_Pat<nxv16i8, op, nxv16i1, i32, SVEShiftImmL8, !cast<Instruction>(NAME # _B)>;
4807+
def : SVE_Shift_DupImm_Pred_Pat<nxv8i16, op, nxv8i1, i32, SVEShiftImmL16, !cast<Instruction>(NAME # _H)>;
4808+
def : SVE_Shift_DupImm_Pred_Pat<nxv4i32, op, nxv4i1, i32, SVEShiftImmL32, !cast<Instruction>(NAME # _S)>;
4809+
def : SVE_Shift_DupImm_Pred_Pat<nxv2i64, op, nxv2i1, i64, SVEShiftImmL64, !cast<Instruction>(NAME # _D)>;
4810+
}
4811+
48074812
multiclass sve_int_bin_pred_shift_imm_left_zeroing_bhsd<SDPatternOperator op> {
48084813
def _ZERO_B : PredTwoOpImmPseudo<NAME # _B, ZPR8, tvecshiftL8, FalseLanesZero>;
48094814
def _ZERO_H : PredTwoOpImmPseudo<NAME # _H, ZPR16, tvecshiftL16, FalseLanesZero>;
@@ -4840,6 +4845,16 @@ multiclass sve_int_bin_pred_shift_imm_right<bits<4> opc, string asm, string Ps,
48404845
def : SVE_3_Op_Imm_Pat<nxv2i64, op, nxv2i1, nxv2i64, i32, tvecshiftR64, !cast<Instruction>(NAME # _D)>;
48414846
}
48424847

4848+
// As above but shift amount takes the form of a "vector immediate".
4849+
multiclass sve_int_bin_pred_shift_imm_right_dup<bits<4> opc, string asm,
4850+
string Ps, SDPatternOperator op>
4851+
: sve_int_bin_pred_shift_imm_right<opc, asm, Ps, null_frag> {
4852+
def : SVE_Shift_DupImm_Pred_Pat<nxv16i8, op, nxv16i1, i32, SVEShiftImmR8, !cast<Instruction>(NAME # _B)>;
4853+
def : SVE_Shift_DupImm_Pred_Pat<nxv8i16, op, nxv8i1, i32, SVEShiftImmR16, !cast<Instruction>(NAME # _H)>;
4854+
def : SVE_Shift_DupImm_Pred_Pat<nxv4i32, op, nxv4i1, i32, SVEShiftImmR32, !cast<Instruction>(NAME # _S)>;
4855+
def : SVE_Shift_DupImm_Pred_Pat<nxv2i64, op, nxv2i1, i64, SVEShiftImmR64, !cast<Instruction>(NAME # _D)>;
4856+
}
4857+
48434858
multiclass sve_int_bin_pred_shift_imm_right_zeroing_bhsd<SDPatternOperator op = null_frag> {
48444859
def _ZERO_B : PredTwoOpImmPseudo<NAME # _B, ZPR8, vecshiftR8, FalseLanesZero>;
48454860
def _ZERO_H : PredTwoOpImmPseudo<NAME # _H, ZPR16, vecshiftR16, FalseLanesZero>;
@@ -4980,10 +4995,10 @@ multiclass sve_int_bin_cons_shift_imm_left<bits<2> opc, string asm,
49804995
let Inst{20-19} = imm{4-3};
49814996
}
49824997

4983-
def : SVE_1_Op_Imm_Shift_Pred_Pat<nxv16i8, nxv16i1, op, ZPR8, vecshiftL8, !cast<Instruction>(NAME # _B)>;
4984-
def : SVE_1_Op_Imm_Shift_Pred_Pat<nxv8i16, nxv8i1, op, ZPR16, vecshiftL16, !cast<Instruction>(NAME # _H)>;
4985-
def : SVE_1_Op_Imm_Shift_Pred_Pat<nxv4i32, nxv4i1, op, ZPR32, vecshiftL32, !cast<Instruction>(NAME # _S)>;
4986-
def : SVE_1_Op_Imm_Arith_Pred_Pat<nxv2i64, nxv2i1, op, ZPR64, i64, SVEShiftImm64, !cast<Instruction>(NAME # _D)>;
4998+
def : SVE_Shift_DupImm_All_Active_Pat<nxv16i8, op, nxv16i1, i32, SVEShiftImmL8, !cast<Instruction>(NAME # _B)>;
4999+
def : SVE_Shift_DupImm_All_Active_Pat<nxv8i16, op, nxv8i1, i32, SVEShiftImmL16, !cast<Instruction>(NAME # _H)>;
5000+
def : SVE_Shift_DupImm_All_Active_Pat<nxv4i32, op, nxv4i1, i32, SVEShiftImmL32, !cast<Instruction>(NAME # _S)>;
5001+
def : SVE_Shift_DupImm_All_Active_Pat<nxv2i64, op, nxv2i1, i64, SVEShiftImmL64, !cast<Instruction>(NAME # _D)>;
49875002
}
49885003

49895004
multiclass sve_int_bin_cons_shift_imm_right<bits<2> opc, string asm,
@@ -5000,10 +5015,10 @@ multiclass sve_int_bin_cons_shift_imm_right<bits<2> opc, string asm,
50005015
let Inst{20-19} = imm{4-3};
50015016
}
50025017

5003-
def : SVE_1_Op_Imm_Shift_Pred_Pat<nxv16i8, nxv16i1, op, ZPR8, vecshiftR8, !cast<Instruction>(NAME # _B)>;
5004-
def : SVE_1_Op_Imm_Shift_Pred_Pat<nxv8i16, nxv8i1, op, ZPR16, vecshiftR16, !cast<Instruction>(NAME # _H)>;
5005-
def : SVE_1_Op_Imm_Shift_Pred_Pat<nxv4i32, nxv4i1, op, ZPR32, vecshiftR32, !cast<Instruction>(NAME # _S)>;
5006-
def : SVE_1_Op_Imm_Arith_Pred_Pat<nxv2i64, nxv2i1, op, ZPR64, i64, SVEShiftImm64, !cast<Instruction>(NAME # _D)>;
5018+
def : SVE_Shift_DupImm_All_Active_Pat<nxv16i8, op, nxv16i1, i32, SVEShiftImmR8, !cast<Instruction>(NAME # _B)>;
5019+
def : SVE_Shift_DupImm_All_Active_Pat<nxv8i16, op, nxv8i1, i32, SVEShiftImmR16, !cast<Instruction>(NAME # _H)>;
5020+
def : SVE_Shift_DupImm_All_Active_Pat<nxv4i32, op, nxv4i1, i32, SVEShiftImmR32, !cast<Instruction>(NAME # _S)>;
5021+
def : SVE_Shift_DupImm_All_Active_Pat<nxv2i64, op, nxv2i1, i64, SVEShiftImmR64, !cast<Instruction>(NAME # _D)>;
50075022
}
50085023
//===----------------------------------------------------------------------===//
50095024
// SVE Memory - Store Group

0 commit comments

Comments
 (0)