Index: llvm/trunk/lib/Target/AArch64/AArch64SVEInstrInfo.td =================================================================== --- llvm/trunk/lib/Target/AArch64/AArch64SVEInstrInfo.td +++ llvm/trunk/lib/Target/AArch64/AArch64SVEInstrInfo.td @@ -37,6 +37,7 @@ // 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>; Index: llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp +++ llvm/trunk/lib/Target/AArch64/AsmParser/AArch64AsmParser.cpp @@ -752,6 +752,12 @@ return DiagnosticPredicateTy::NearMatch; } + template DiagnosticPredicate isSVEPreferredLogicalImm() const { + if (isLogicalImm() && !isSVECpyImm()) + return DiagnosticPredicateTy::Match; + return DiagnosticPredicateTy::NoMatch; + } + bool isCondCode() const { return Kind == k_CondCode; } bool isSIMDImmType10() const { Index: llvm/trunk/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp +++ llvm/trunk/lib/Target/AArch64/Disassembler/AArch64Disassembler.cpp @@ -1759,7 +1759,8 @@ // 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; } Index: llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h =================================================================== --- llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h +++ llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.h @@ -172,6 +172,9 @@ template void printImm8OptLsl(const MCInst *MI, unsigned OpNum, const MCSubtargetInfo &STI, raw_ostream &O); + template + 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 Index: llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp =================================================================== --- llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp +++ llvm/trunk/lib/Target/AArch64/InstPrinter/AArch64InstPrinter.cpp @@ -1480,3 +1480,22 @@ printImmSVE(Val, O); } + +template +void AArch64InstPrinter::printSVELogicalImm(const MCInst *MI, unsigned OpNum, + const MCSubtargetInfo &STI, + raw_ostream &O) { + typedef typename std::make_signed::type SignedT; + typedef typename std::make_unsigned::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); +} Index: llvm/trunk/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h =================================================================== --- llvm/trunk/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h +++ llvm/trunk/lib/Target/AArch64/MCTargetDesc/AArch64AddressingModes.h @@ -782,6 +782,33 @@ 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(Vec.D)) + return false; + + if (isSVEMaskOfIdenticalElements(Imm) && + isSVECpyImm(Vec.S[0])) + return false; + + if (isSVEMaskOfIdenticalElements(Imm) && + isSVECpyImm(Vec.H[0])) + return false; + + if (isSVEMaskOfIdenticalElements(Imm) && + isSVECpyImm(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) Index: llvm/trunk/lib/Target/AArch64/SVEInstrFormats.td =================================================================== --- llvm/trunk/lib/Target/AArch64/SVEInstrFormats.td +++ llvm/trunk/lib/Target/AArch64/SVEInstrFormats.td @@ -84,6 +84,51 @@ }]; } +class SVEPreferredLogicalImmOperand : AsmOperandClass { + let Name = "SVEPreferredLogicalImm" # Width; + let PredicateMethod = "isSVEPreferredLogicalImm"; + let RenderMethod = "addLogicalImmOperands"; +} + +def sve_preferred_logical_imm16 : Operand { + let ParserMatchClass = SVEPreferredLogicalImmOperand<16>; + let PrintMethod = "printSVELogicalImm"; + + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Val = AArch64_AM::decodeLogicalImmediate(MCOp.getImm(), 64); + return AArch64_AM::isSVEMaskOfIdenticalElements(Val) && + AArch64_AM::isSVEMoveMaskPreferredLogicalImmediate(Val); + }]; +} + +def sve_preferred_logical_imm32 : Operand { + let ParserMatchClass = SVEPreferredLogicalImmOperand<32>; + let PrintMethod = "printSVELogicalImm"; + + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Val = AArch64_AM::decodeLogicalImmediate(MCOp.getImm(), 64); + return AArch64_AM::isSVEMaskOfIdenticalElements(Val) && + AArch64_AM::isSVEMoveMaskPreferredLogicalImmediate(Val); + }]; +} + +def sve_preferred_logical_imm64 : Operand { + let ParserMatchClass = SVEPreferredLogicalImmOperand<64>; + let PrintMethod = "printSVELogicalImm"; + + let MCOperandPredicate = [{ + if (!MCOp.isImm()) + return false; + int64_t Val = AArch64_AM::decodeLogicalImmediate(MCOp.getImm(), 64); + return AArch64_AM::isSVEMaskOfIdenticalElements(Val) && + AArch64_AM::isSVEMoveMaskPreferredLogicalImmediate(Val); + }]; +} + class SVELogicalImmNotOperand : AsmOperandClass { let Name = "SVELogicalImm" # Width # "Not"; let DiagnosticType = "LogicalSecondSource"; @@ -279,6 +324,40 @@ (!cast(NAME) ZPR64:$Zdn, logical_imm64_not:$imm), 0>; } +class sve_int_dup_mask_imm +: 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 { + def NAME : sve_int_dup_mask_imm; + + def : InstAlias<"dupm $Zd, $imm", + (!cast(NAME) ZPR8:$Zd, sve_logical_imm8:$imm), 4>; + def : InstAlias<"dupm $Zd, $imm", + (!cast(NAME) ZPR16:$Zd, sve_logical_imm16:$imm), 3>; + def : InstAlias<"dupm $Zd, $imm", + (!cast(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(NAME) ZPR16:$Zd, sve_preferred_logical_imm16:$imm), 7>; + def : InstAlias<"mov $Zd, $imm", + (!cast(NAME) ZPR32:$Zd, sve_preferred_logical_imm32:$imm), 6>; + def : InstAlias<"mov $Zd, $imm", + (!cast(NAME) ZPR64:$Zd, sve_preferred_logical_imm64:$imm), 5>; +} + //===----------------------------------------------------------------------===// // SVE Integer Arithmetic - Unpredicated Group. //===----------------------------------------------------------------------===// Index: llvm/trunk/test/MC/AArch64/SVE/dupm-diagnostics.s =================================================================== --- llvm/trunk/test/MC/AArch64/SVE/dupm-diagnostics.s +++ llvm/trunk/test/MC/AArch64/SVE/dupm-diagnostics.s @@ -0,0 +1,39 @@ +// RUN: not llvm-mc -triple=aarch64 -show-encoding -mattr=+sve 2>&1 < %s| FileCheck %s + +// --------------------------------------------------------------------------// +// Immediate not compatible with encode/decode function. + +dupm z5.b, #0xfa +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected compatible register or logical immediate +// CHECK-NEXT: dupm z5.b, #0xfa +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +dupm z5.b, #0xfff9 +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected compatible register or logical immediate +// CHECK-NEXT: dupm z5.b, #0xfff9 +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +dupm z5.h, #0xfffa +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected compatible register or logical immediate +// CHECK-NEXT: dupm z5.h, #0xfffa +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +dupm z5.h, #0xfffffff9 +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected compatible register or logical immediate +// CHECK-NEXT: dupm z5.h, #0xfffffff9 +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +dupm z5.s, #0xfffffffa +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected compatible register or logical immediate +// CHECK-NEXT: dupm z5.s, #0xfffffffa +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +dupm z5.s, #0xffffffffffffff9 +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected compatible register or logical immediate +// CHECK-NEXT: dupm z5.s, #0xffffffffffffff9 +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +dupm z15.d, #0xfffffffffffffffa +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: expected compatible register or logical immediate +// CHECK-NEXT: dupm z15.d, #0xfffffffffffffffa +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: Index: llvm/trunk/test/MC/AArch64/SVE/dupm.s =================================================================== --- llvm/trunk/test/MC/AArch64/SVE/dupm.s +++ llvm/trunk/test/MC/AArch64/SVE/dupm.s @@ -0,0 +1,68 @@ +// RUN: llvm-mc -triple=aarch64 -show-encoding -mattr=+sve < %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK-ENCODING,CHECK-INST +// RUN: not llvm-mc -triple=aarch64 -show-encoding < %s 2>&1 \ +// RUN: | FileCheck %s --check-prefix=CHECK-ERROR +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve < %s \ +// RUN: | llvm-objdump -d -mattr=+sve - | FileCheck %s --check-prefix=CHECK-INST +// RUN: llvm-mc -triple=aarch64 -filetype=obj -mattr=+sve < %s \ +// RUN: | llvm-objdump -d - | FileCheck %s --check-prefix=CHECK-UNKNOWN + +dupm z5.b, #0xf9 +// CHECK-INST: dupm z5.b, #0xf9 +// CHECK-ENCODING: [0xa5,0x2e,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: a5 2e c0 05 + +dupm z5.h, #0xf9f9 +// CHECK-INST: dupm z5.b, #0xf9 +// CHECK-ENCODING: [0xa5,0x2e,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: a5 2e c0 05 + +dupm z5.s, #0xf9f9f9f9 +// CHECK-INST: dupm z5.b, #0xf9 +// CHECK-ENCODING: [0xa5,0x2e,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: a5 2e c0 05 + +dupm z5.d, #0xf9f9f9f9f9f9f9f9 +// CHECK-INST: dupm z5.b, #0xf9 +// CHECK-ENCODING: [0xa5,0x2e,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: a5 2e c0 05 + +dupm z23.h, #0xfff9 +// CHECK-INST: dupm z23.h, #0xfff9 +// CHECK-ENCODING: [0xb7,0x6d,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: b7 6d c0 05 + +dupm z23.s, #0xfff9fff9 +// CHECK-INST: dupm z23.h, #0xfff9 +// CHECK-ENCODING: [0xb7,0x6d,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: b7 6d c0 05 + +dupm z23.d, #0xfff9fff9fff9fff9 +// CHECK-INST: dupm z23.h, #0xfff9 +// CHECK-ENCODING: [0xb7,0x6d,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: b7 6d c0 05 + +dupm z0.s, #0xfffffff9 +// CHECK-INST: dupm z0.s, #0xfffffff9 +// CHECK-ENCODING: [0xa0,0xeb,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: a0 eb c0 05 + +dupm z0.d, #0xfffffff9fffffff9 +// CHECK-INST: dupm z0.s, #0xfffffff9 +// CHECK-ENCODING: [0xa0,0xeb,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: a0 eb c0 05 + +dupm z0.d, #0xfffffffffffffff9 +// CHECK-INST: dupm z0.d, #0xfffffffffffffff9 +// CHECK-ENCODING: [0xa0,0xef,0xc3,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: a0 ef c3 05 Index: llvm/trunk/test/MC/AArch64/SVE/mov-diagnostics.s =================================================================== --- llvm/trunk/test/MC/AArch64/SVE/mov-diagnostics.s +++ llvm/trunk/test/MC/AArch64/SVE/mov-diagnostics.s @@ -85,11 +85,6 @@ // CHECK-NEXT: mov z0.h, #32513 // CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: -mov z0.h, #32768 -// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] -// CHECK-NEXT: mov z0.h, #32768 -// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: - mov z0.h, #128, lsl #8 // CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] // CHECK-NEXT: mov z0.h, #128, lsl #8 @@ -100,11 +95,6 @@ // CHECK-NEXT: mov z0.s, #-33024 // CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: -mov z0.s, #-32769 -// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] -// CHECK-NEXT: mov z0.s, #-32769 -// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: - mov z0.s, #-129, lsl #8 // CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] // CHECK-NEXT: mov z0.s, #-129, lsl #8 @@ -115,11 +105,6 @@ // CHECK-NEXT: mov z0.s, #32513 // CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: -mov z0.s, #32768 -// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] -// CHECK-NEXT: mov z0.s, #32768 -// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: - mov z0.s, #128, lsl #8 // CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] // CHECK-NEXT: mov z0.s, #128, lsl #8 @@ -130,11 +115,6 @@ // CHECK-NEXT: mov z0.d, #-33024 // CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: -mov z0.d, #-32769 -// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] -// CHECK-NEXT: mov z0.d, #-32769 -// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: - mov z0.d, #-129, lsl #8 // CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] // CHECK-NEXT: mov z0.d, #-129, lsl #8 @@ -145,12 +125,32 @@ // CHECK-NEXT: mov z0.d, #32513 // CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: -mov z0.d, #32768 +mov z0.d, #128, lsl #8 // CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] -// CHECK-NEXT: mov z0.d, #32768 +// CHECK-NEXT: mov z0.d, #128, lsl #8 // CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: -mov z0.d, #128, lsl #8 +mov z5.b, #0xfff9 +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 255] with a shift amount of 0 +// CHECK-NEXT: mov z5.b, #0xfff9 +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +mov z5.h, #0xfffa // CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] -// CHECK-NEXT: mov z0.d, #128, lsl #8 +// CHECK-NEXT: mov z5.h, #0xfffa +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +mov z5.h, #0xfffffff9 +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] +// CHECK-NEXT: mov z5.h, #0xfffffff9 +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +mov z5.s, #0xfffffffa +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] +// CHECK-NEXT: mov z5.s, #0xfffffffa +// CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: + +mov z5.s, #0xffffffffffffff9 +// CHECK: [[@LINE-1]]:{{[0-9]+}}: error: immediate must be an integer in range [-128, 127] or a multiple of 256 in range [-32768, 32512] +// CHECK-NEXT: mov z5.s, #0xffffffffffffff9 // CHECK-NOT: [[@LINE-1]]:{{[0-9]+}}: Index: llvm/trunk/test/MC/AArch64/SVE/mov.s =================================================================== --- llvm/trunk/test/MC/AArch64/SVE/mov.s +++ llvm/trunk/test/MC/AArch64/SVE/mov.s @@ -192,3 +192,39 @@ // CHECK-ENCODING: [0xf5,0xef,0xf8,0x25] // CHECK-ERROR: instruction requires: sve // CHECK-UNKNOWN: f5 ef f8 25 + +mov z0.h, #32768 +// CHECK-INST: dupm z0.h, #0x8000 +// CHECK-ENCODING: [0x00,0x0c,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 0c c0 05 + +mov z0.s, #-32769 +// CHECK-INST: mov z0.s, #0xffff7fff +// CHECK-ENCODING: [0xc0,0x83,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: c0 83 c0 05 + +mov z0.s, #32768 +// CHECK-INST: mov z0.s, #32768 +// CHECK-ENCODING: [0x00,0x88,0xc0,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 88 c0 05 + +mov z0.d, #-32769 +// CHECK-INST: mov z0.d, #0xffffffffffff7fff +// CHECK-ENCODING: [0xc0,0x87,0xc3,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: c0 87 c3 05 + +mov z0.d, #32768 +// CHECK-INST: mov z0.d, #32768 +// CHECK-ENCODING: [0x00,0x88,0xc3,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 00 88 c3 05 + +mov z0.d, #0xe0000000000003ff +// CHECK-INST: mov z0.d, #0xe0000000000003ff +// CHECK-ENCODING: [0x80,0x19,0xc2,0x05] +// CHECK-ERROR: instruction requires: sve +// CHECK-UNKNOWN: 80 19 c2 05