diff options
Diffstat (limited to 'llvm/lib')
7 files changed, 137 insertions, 1 deletions
diff --git a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td index 513b4f7a257..3207be74968 100644 --- a/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td +++ b/llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td @@ -37,6 +37,7 @@ let Predicates = [HasSVE] in { // Splat immediate (unpredicated) defm DUP_ZI : sve_int_dup_imm<"dup">; + defm DUPM_ZI : sve_int_dup_mask_imm<"dupm">; // continuous load with reg+immediate defm LD1B_IMM : sve_mem_cld_si<0b0000, "ld1b", Z_b, ZPR8>; diff --git a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp index 77aff4fccc8..031de490885 100644 --- a/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ b/llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -752,6 +752,12 @@ public: return DiagnosticPredicateTy::NearMatch; } + template <typename T> DiagnosticPredicate isSVEPreferredLogicalImm() const { + if (isLogicalImm<T>() && !isSVECpyImm<T>()) + return DiagnosticPredicateTy::Match; + return DiagnosticPredicateTy::NoMatch; + } + bool isCondCode() const { return Kind == k_CondCode; } bool isSIMDImmType10() const { diff --git a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp index ecb51cf695f..f9c9c56cd60 100644 --- a/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp +++ b/llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp @@ -1759,7 +1759,8 @@ static DecodeStatus DecodeSVELogicalImmInstruction(llvm::MCInst &Inst, // The same (tied) operand is added twice to the instruction. DecodeZPRRegisterClass(Inst, Zdn, Addr, Decoder); - DecodeZPRRegisterClass(Inst, Zdn, Addr, Decoder); + if (Inst.getOpcode() != AArch64::DUPM_ZI) + DecodeZPRRegisterClass(Inst, Zdn, Addr, Decoder); Inst.addOperand(MCOperand::createImm(imm)); return Success; } diff --git a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp index 1f3dc0c39b4..67584d1cbfe 100644 --- a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp +++ b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp @@ -1480,3 +1480,22 @@ void AArch64InstPrinter::printImm8OptLsl(const MCInst *MI, unsigned OpNum, printImmSVE(Val, O); } + +template <typename T> +void AArch64InstPrinter::printSVELogicalImm(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, + raw_ostream &O) { + typedef typename std::make_signed<T>::type SignedT; + typedef typename std::make_unsigned<T>::type UnsignedT; + + uint64_t Val = MI->getOperand(OpNum).getImm(); + UnsignedT PrintVal = AArch64_AM::decodeLogicalImmediate(Val, 64); + + // Prefer the default format for 16bit values, hex otherwise. + if ((int16_t)PrintVal == (SignedT)PrintVal) + printImmSVE((T)PrintVal, O); + else if ((uint16_t)PrintVal == PrintVal) + printImmSVE(PrintVal, O); + else + O << '#' << formatHex((uint64_t)PrintVal); +} diff --git a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h index 4c8bf4fc826..ca108308c71 100644 --- a/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h +++ b/llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h @@ -172,6 +172,9 @@ protected: template <typename T> void printImm8OptLsl(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, raw_ostream &O); + template <typename T> + void printSVELogicalImm(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, raw_ostream &O); void printSVEPattern(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, raw_ostream &O); template <char = 0> diff --git a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h index 177ead2e28b..16c3a037455 100644 --- a/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h +++ b/llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h @@ -782,6 +782,33 @@ static inline bool isSVEAddSubImm(int64_t Imm) { return uint8_t(Imm) == Imm || (!IsInt8t && uint16_t(Imm & ~0xff) == Imm); } +/// Return true if Imm is valid for DUPM and has no single CPY/DUP equivalent. +static inline bool isSVEMoveMaskPreferredLogicalImmediate(int64_t Imm) { + union { + int64_t D; + int32_t S[2]; + int16_t H[4]; + int8_t B[8]; + } Vec = { Imm }; + + if (isSVECpyImm<int64_t>(Vec.D)) + return false; + + if (isSVEMaskOfIdenticalElements<int32_t>(Imm) && + isSVECpyImm<int32_t>(Vec.S[0])) + return false; + + if (isSVEMaskOfIdenticalElements<int16_t>(Imm) && + isSVECpyImm<int16_t>(Vec.H[0])) + return false; + + if (isSVEMaskOfIdenticalElements<int8_t>(Imm) && + isSVECpyImm<int8_t>(Vec.B[0])) + return false; + + return isLogicalImmediate(Vec.D, 64); +} + inline static bool isAnyMOVZMovAlias(uint64_t Value, int RegWidth) { for (int Shift = 0; Shift <= RegWidth - 16; Shift += 16) if ((Value & ~(0xffffULL << Shift)) == 0) diff --git a/llvm/lib/Target/AArch64/SVEInstrFormats.td b/llvm/lib/Target/AArch64/SVEInstrFormats.td index 7f0dbdc89d5..8794522c2c6 100644 --- a/llvm/lib/Target/AArch64/SVEInstrFormats.td +++ b/llvm/lib/Target/AArch64/SVEInstrFormats.td @@ -84,6 +84,51 @@ def sve_logical_imm32 : Operand<i64> { }]; } +class SVEPreferredLogicalImmOperand<int Width> : AsmOperandClass { + let Name = "SVEPreferredLogicalImm" # Width; + let PredicateMethod = "isSVEPreferredLogicalImm<int" # Width # "_t>"; + let RenderMethod = "addLogicalImmOperands<int" # Width # "_t>"; +} + +def sve_preferred_logical_imm16 : Operand<i64> { + let ParserMatchClass = SVEPreferredLogicalImmOperand<16>; + let PrintMethod = "printSVELogicalImm<int16_t>"; + + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Val = AArch64_AM::decodeLogicalImmediate(MCOp.getImm(), 64); + return AArch64_AM::isSVEMaskOfIdenticalElements<int16_t>(Val) && + AArch64_AM::isSVEMoveMaskPreferredLogicalImmediate(Val); + }]; +} + +def sve_preferred_logical_imm32 : Operand<i64> { + let ParserMatchClass = SVEPreferredLogicalImmOperand<32>; + let PrintMethod = "printSVELogicalImm<int32_t>"; + + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Val = AArch64_AM::decodeLogicalImmediate(MCOp.getImm(), 64); + return AArch64_AM::isSVEMaskOfIdenticalElements<int32_t>(Val) && + AArch64_AM::isSVEMoveMaskPreferredLogicalImmediate(Val); + }]; +} + +def sve_preferred_logical_imm64 : Operand<i64> { + let ParserMatchClass = SVEPreferredLogicalImmOperand<64>; + let PrintMethod = "printSVELogicalImm<int64_t>"; + + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Val = AArch64_AM::decodeLogicalImmediate(MCOp.getImm(), 64); + return AArch64_AM::isSVEMaskOfIdenticalElements<int64_t>(Val) && + AArch64_AM::isSVEMoveMaskPreferredLogicalImmediate(Val); + }]; +} + class SVELogicalImmNotOperand<int Width> : AsmOperandClass { let Name = "SVELogicalImm" # Width # "Not"; let DiagnosticType = "LogicalSecondSource"; @@ -279,6 +324,40 @@ multiclass sve_int_log_imm<bits<2> opc, string asm, string alias> { (!cast<Instruction>(NAME) ZPR64:$Zdn, logical_imm64_not:$imm), 0>; } +class sve_int_dup_mask_imm<string asm> +: I<(outs ZPR64:$Zd), (ins logical_imm64:$imms), + asm, "\t$Zd, $imms", + "", + []>, Sched<[]> { + bits<5> Zd; + bits<13> imms; + let Inst{31-18} = 0b00000101110000; + let Inst{17-5} = imms; + let Inst{4-0} = Zd; + + let isReMaterializable = 1; + let DecoderMethod = "DecodeSVELogicalImmInstruction"; +} + +multiclass sve_int_dup_mask_imm<string asm> { + def NAME : sve_int_dup_mask_imm<asm>; + + def : InstAlias<"dupm $Zd, $imm", + (!cast<Instruction>(NAME) ZPR8:$Zd, sve_logical_imm8:$imm), 4>; + def : InstAlias<"dupm $Zd, $imm", + (!cast<Instruction>(NAME) ZPR16:$Zd, sve_logical_imm16:$imm), 3>; + def : InstAlias<"dupm $Zd, $imm", + (!cast<Instruction>(NAME) ZPR32:$Zd, sve_logical_imm32:$imm), 2>; + + // All Zd.b forms have a CPY/DUP equivalent, hence no byte alias here. + def : InstAlias<"mov $Zd, $imm", + (!cast<Instruction>(NAME) ZPR16:$Zd, sve_preferred_logical_imm16:$imm), 7>; + def : InstAlias<"mov $Zd, $imm", + (!cast<Instruction>(NAME) ZPR32:$Zd, sve_preferred_logical_imm32:$imm), 6>; + def : InstAlias<"mov $Zd, $imm", + (!cast<Instruction>(NAME) ZPR64:$Zd, sve_preferred_logical_imm64:$imm), 5>; +} + //===----------------------------------------------------------------------===// // SVE Integer Arithmetic - Unpredicated Group. //===----------------------------------------------------------------------===// |

