summaryrefslogtreecommitdiffstats
path: root/llvm/lib
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib')
-rw-r--r--llvm/lib/Target/AArch64/AArch64SVEInstrInfo.td1
-rw-r--r--llvm/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp6
-rw-r--r--llvm/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp3
-rw-r--r--llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp19
-rw-r--r--llvm/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h3
-rw-r--r--llvm/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h27
-rw-r--r--llvm/lib/Target/AArch64/SVEInstrFormats.td79
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.
//===----------------------------------------------------------------------===//
OpenPOWER on IntegriCloud