diff --git a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp index f0b69b0b09809..0f7858a3be9f9 100644 --- a/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp +++ b/llvm/lib/Target/ARM/ARMExpandPseudoInsts.cpp @@ -1470,13 +1470,19 @@ void ARMExpandPseudo::CMSESaveClearFPRegsV8( // Lazy store all fp registers to the stack. // This executes as NOP in the absence of floating-point support. - MachineInstrBuilder VLSTM = BuildMI(MBB, MBBI, DL, TII->get(ARM::VLSTM)) - .addReg(ARM::SP) - .add(predOps(ARMCC::AL)); - for (auto R : {ARM::VPR, ARM::FPSCR, ARM::FPSCR_NZCV, ARM::Q0, ARM::Q1, - ARM::Q2, ARM::Q3, ARM::Q4, ARM::Q5, ARM::Q6, ARM::Q7}) - VLSTM.addReg(R, RegState::Implicit | - (LiveRegs.contains(R) ? 0 : RegState::Undef)); + MachineInstrBuilder VLSTM = + BuildMI(MBB, MBBI, DL, TII->get(ARM::VLSTM)) + .addReg(ARM::SP) + .add(predOps(ARMCC::AL)) + .addImm(0); // Represents a pseoudo register list, has no effect on + // the encoding. + // Mark non-live registers as undef + for (MachineOperand &MO : VLSTM->implicit_operands()) { + if (MO.isReg() && !MO.isDef()) { + Register Reg = MO.getReg(); + MO.setIsUndef(!LiveRegs.contains(Reg)); + } + } // Restore all arguments for (const auto &Regs : ClearedFPRegs) { @@ -1564,13 +1570,19 @@ void ARMExpandPseudo::CMSESaveClearFPRegsV81(MachineBasicBlock &MBB, .add(predOps(ARMCC::AL)); // Lazy store all FP registers to the stack - MachineInstrBuilder VLSTM = BuildMI(MBB, MBBI, DL, TII->get(ARM::VLSTM)) - .addReg(ARM::SP) - .add(predOps(ARMCC::AL)); - for (auto R : {ARM::VPR, ARM::FPSCR, ARM::FPSCR_NZCV, ARM::Q0, ARM::Q1, - ARM::Q2, ARM::Q3, ARM::Q4, ARM::Q5, ARM::Q6, ARM::Q7}) - VLSTM.addReg(R, RegState::Implicit | - (LiveRegs.contains(R) ? 0 : RegState::Undef)); + MachineInstrBuilder VLSTM = + BuildMI(MBB, MBBI, DL, TII->get(ARM::VLSTM)) + .addReg(ARM::SP) + .add(predOps(ARMCC::AL)) + .addImm(0); // Represents a pseoudo register list, has no effect on + // the encoding. + // Mark non-live registers as undef + for (MachineOperand &MO : VLSTM->implicit_operands()) { + if (MO.isReg() && MO.isImplicit() && !MO.isDef()) { + Register Reg = MO.getReg(); + MO.setIsUndef(!LiveRegs.contains(Reg)); + } + } } else { // Push all the callee-saved registers (s16-s31). MachineInstrBuilder VPUSH = @@ -1673,9 +1685,12 @@ void ARMExpandPseudo::CMSERestoreFPRegsV8( // Lazy load fp regs from stack. // This executes as NOP in the absence of floating-point support. - MachineInstrBuilder VLLDM = BuildMI(MBB, MBBI, DL, TII->get(ARM::VLLDM)) - .addReg(ARM::SP) - .add(predOps(ARMCC::AL)); + MachineInstrBuilder VLLDM = + BuildMI(MBB, MBBI, DL, TII->get(ARM::VLLDM)) + .addReg(ARM::SP) + .add(predOps(ARMCC::AL)) + .addImm(0); // Represents a pseoudo register list, has no effect on + // the encoding. if (STI->fixCMSE_CVE_2021_35465()) { auto Bundler = MIBundleBuilder(MBB, VLLDM); @@ -1757,7 +1772,9 @@ void ARMExpandPseudo::CMSERestoreFPRegsV81( // Load FP registers from stack. BuildMI(MBB, MBBI, DL, TII->get(ARM::VLLDM)) .addReg(ARM::SP) - .add(predOps(ARMCC::AL)); + .add(predOps(ARMCC::AL)) + .addImm(0); // Represents a pseoudo register list, has no effect on the + // encoding. // Pop the stack space BuildMI(MBB, MBBI, DL, TII->get(ARM::tADDspi), ARM::SP) diff --git a/llvm/lib/Target/ARM/ARMInstrFormats.td b/llvm/lib/Target/ARM/ARMInstrFormats.td index 14e315534570d..404085820a666 100644 --- a/llvm/lib/Target/ARM/ARMInstrFormats.td +++ b/llvm/lib/Target/ARM/ARMInstrFormats.td @@ -1749,6 +1749,37 @@ class AXSI4 + : InstARM { + // Instruction operands. + bits<4> Rn; + bits<13> regs; // Does not affect encoding, for assembly/disassembly only. + list Predicates = [HasVFP2]; + let OutOperandList = (outs); + let InOperandList = (ins GPRnopc:$Rn, pred:$p, dpr_reglist:$regs); + let AsmString = asm; + let Pattern = []; + let DecoderNamespace = "VFP"; + // Encode instruction operands. + let Inst{19-16} = Rn; + let Inst{31-28} = 0b1110; + let Inst{27-25} = 0b110; + let Inst{24} = 0b0; + let Inst{23} = 0b0; + let Inst{22} = 0b0; + let Inst{21} = 0b1; + let Inst{20} = load; // Distinguishes vlldm from vlstm + let Inst{15-12} = 0b0000; + let Inst{11-9} = 0b101; + let Inst{8} = 0; // Single precision + let Inst{7} = et; // encoding type, 0 for T1 and 1 for T2. + let Inst{6-0} = 0b0000000; + let mayLoad = load; + let mayStore = !eq(load, 0); +} + // Double precision, unary class ADuI opcod1, bits<2> opcod2, bits<4> opcod3, bits<2> opcod4, bit opcod5, dag oops, dag iops, InstrItinClass itin, string opc, diff --git a/llvm/lib/Target/ARM/ARMInstrVFP.td b/llvm/lib/Target/ARM/ARMInstrVFP.td index 55d3efbd9b9a2..3094a4db2b4d1 100644 --- a/llvm/lib/Target/ARM/ARMInstrVFP.td +++ b/llvm/lib/Target/ARM/ARMInstrVFP.td @@ -313,29 +313,51 @@ def : MnemonicAlias<"vstm", "vstmia">; //===----------------------------------------------------------------------===// // Lazy load / store multiple Instructions // -def VLLDM : AXSI4<(outs), (ins GPRnopc:$Rn, pred:$p), IndexModeNone, - NoItinerary, "vlldm${p}\t$Rn", "", []>, +// VLLDM and VLSTM: +// 2 encoding options: +// T1 (bit 7 is 0): +// T1 takes an optional dpr_reglist, must be '{d0-d15}' (exactly) +// T1 require v8-M.Main, secure state, target with 16 D registers (or with no D registers - NOP) +// T2 (bit 7 is 1): +// T2 takes a mandatory dpr_reglist, must be '{d0-d31}' (exactly) +// T2 require v8.1-M.Main, secure state, target with 16/32 D registers (or with no D registers - NOP) +// (source: Arm v8-M ARM, DDI0553B.v ID16122022) + +def VLLDM : AXSI4FR<"vlldm${p}\t$Rn, $regs", 0, 1>, Requires<[HasV8MMainline, Has8MSecExt]> { - let Inst{24-23} = 0b00; - let Inst{22} = 0; - let Inst{21} = 1; - let Inst{20} = 1; - let Inst{15-12} = 0; - let Inst{7-0} = 0; - let mayLoad = 1; - let Defs = [Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, VPR, FPSCR, FPSCR_NZCV]; -} - -def VLSTM : AXSI4<(outs), (ins GPRnopc:$Rn, pred:$p), IndexModeNone, - NoItinerary, "vlstm${p}\t$Rn", "", []>, + let Defs = [VPR, FPSCR, FPSCR_NZCV, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15]; + let DecoderMethod = "DecodeLazyLoadStoreMul"; +} +// T1: assembly does not contains the register list. +def : InstAlias<"vlldm${p}\t$Rn", (VLLDM GPRnopc:$Rn, pred:$p, 0)>, + Requires<[HasV8MMainline, Has8MSecExt]>; +// T2: assembly must contains the register list. +// The register list has no effect on the encoding, it is for assembly/disassembly purposes only. +def VLLDM_T2 : AXSI4FR<"vlldm${p}\t$Rn, $regs", 1, 1>, + Requires<[HasV8_1MMainline, Has8MSecExt]> { + let Defs = [VPR, FPSCR, FPSCR_NZCV, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, + D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31]; + let DecoderMethod = "DecodeLazyLoadStoreMul"; +} +// T1: assembly contains the register list. +// The register list has no effect on the encoding, it is for assembly/disassembly purposes only. +def VLSTM : AXSI4FR<"vlstm${p}\t$Rn, $regs", 0, 0>, Requires<[HasV8MMainline, Has8MSecExt]> { - let Inst{24-23} = 0b00; - let Inst{22} = 0; - let Inst{21} = 1; - let Inst{20} = 0; - let Inst{15-12} = 0; - let Inst{7-0} = 0; - let mayStore = 1; + let Defs = [VPR, FPSCR, FPSCR_NZCV]; + let Uses = [VPR, FPSCR, FPSCR_NZCV, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15]; + let DecoderMethod = "DecodeLazyLoadStoreMul"; +} +// T1: assembly does not contain the register list. +def : InstAlias<"vlstm${p}\t$Rn", (VLSTM GPRnopc:$Rn, pred:$p, 0)>, + Requires<[HasV8MMainline, Has8MSecExt]>; +// T2: assembly must contain the register list. +// The register list has no effect on the encoding, it is for assembly/disassembly purposes only. +def VLSTM_T2 : AXSI4FR<"vlstm${p}\t$Rn, $regs", 1, 0>, + Requires<[HasV8_1MMainline, Has8MSecExt]> { + let Defs = [VPR, FPSCR, FPSCR_NZCV]; + let Uses = [VPR, FPSCR, FPSCR_NZCV, D0, D1, D2, D3, D4, D5, D6, D7, D8, D9, D10, D11, D12, D13, D14, D15, + D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26, D27, D28, D29, D30, D31]; + let DecoderMethod = "DecodeLazyLoadStoreMul"; } def : InstAlias<"vpush${p} $r", (VSTMDDB_UPD SP, pred:$p, dpr_reglist:$r), 0>, diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index efec163c6ed63..c320bf723c88b 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -450,11 +450,12 @@ class ARMAsmParser : public MCTargetAsmParser { bool validatetSTMRegList(const MCInst &Inst, const OperandVector &Operands, unsigned ListNo); - int tryParseRegister(); + int tryParseRegister(bool AllowOutofBoundReg = false); bool tryParseRegisterWithWriteBack(OperandVector &); int tryParseShiftRegister(OperandVector &); bool parseRegisterList(OperandVector &, bool EnforceOrder = true, - bool AllowRAAC = false); + bool AllowRAAC = false, + bool AllowOutOfBoundReg = false); bool parseMemory(OperandVector &); bool parseOperand(OperandVector &, StringRef Mnemonic); bool parseImmExpr(int64_t &Out); @@ -4073,7 +4074,7 @@ ParseStatus ARMAsmParser::tryParseRegister(MCRegister &Reg, SMLoc &StartLoc, /// Try to parse a register name. The token must be an Identifier when called, /// and if it is a register name the token is eaten and the register number is /// returned. Otherwise return -1. -int ARMAsmParser::tryParseRegister() { +int ARMAsmParser::tryParseRegister(bool AllowOutOfBoundReg) { MCAsmParser &Parser = getParser(); const AsmToken &Tok = Parser.getTok(); if (Tok.isNot(AsmToken::Identifier)) return -1; @@ -4117,7 +4118,8 @@ int ARMAsmParser::tryParseRegister() { } // Some FPUs only have 16 D registers, so D16-D31 are invalid - if (!hasD32() && RegNum >= ARM::D16 && RegNum <= ARM::D31) + if (!AllowOutOfBoundReg && !hasD32() && RegNum >= ARM::D16 && + RegNum <= ARM::D31) return -1; Parser.Lex(); // Eat identifier token. @@ -4457,7 +4459,7 @@ insertNoDuplicates(SmallVectorImpl> &Regs, /// Parse a register list. bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder, - bool AllowRAAC) { + bool AllowRAAC, bool AllowOutOfBoundReg) { MCAsmParser &Parser = getParser(); if (Parser.getTok().isNot(AsmToken::LCurly)) return TokError("Token is not a Left Curly Brace"); @@ -4511,7 +4513,7 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder, return Error(RegLoc, "pseudo-register not allowed"); Parser.Lex(); // Eat the minus. SMLoc AfterMinusLoc = Parser.getTok().getLoc(); - int EndReg = tryParseRegister(); + int EndReg = tryParseRegister(AllowOutOfBoundReg); if (EndReg == -1) return Error(AfterMinusLoc, "register expected"); if (EndReg == ARM::RA_AUTH_CODE) @@ -4546,7 +4548,7 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands, bool EnforceOrder, RegLoc = Parser.getTok().getLoc(); int OldReg = Reg; const AsmToken RegTok = Parser.getTok(); - Reg = tryParseRegister(); + Reg = tryParseRegister(AllowOutOfBoundReg); if (Reg == -1) return Error(RegLoc, "register expected"); if (!AllowRAAC && Reg == ARM::RA_AUTH_CODE) @@ -6086,8 +6088,11 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { } case AsmToken::LBrac: return parseMemory(Operands); - case AsmToken::LCurly: - return parseRegisterList(Operands, !Mnemonic.starts_with("clr")); + case AsmToken::LCurly: { + bool AllowOutOfBoundReg = Mnemonic == "vlldm" || Mnemonic == "vlstm"; + return parseRegisterList(Operands, !Mnemonic.starts_with("clr"), false, + AllowOutOfBoundReg); + } case AsmToken::Dollar: case AsmToken::Hash: { // #42 -> immediate @@ -7597,6 +7602,33 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, const unsigned Opcode = Inst.getOpcode(); switch (Opcode) { + case ARM::VLLDM: + case ARM::VLLDM_T2: + case ARM::VLSTM: + case ARM::VLSTM_T2: { + // Since in some cases both T1 and T2 are valid, tablegen can not always + // pick the correct instruction. + if (Operands.size() == 4) { // a register list has been provided + ARMOperand &Op = static_cast( + *Operands[3]); // the register list, a dpr_reglist + assert(Op.isDPRRegList()); + auto &RegList = Op.getRegList(); + // T2 requires v8.1-M.Main (cannot be handled by tablegen) + if (RegList.size() == 32 && !hasV8_1MMainline()) { + return Error(Op.getEndLoc(), "T2 version requires v8.1-M.Main"); + } + // When target has 32 D registers, T1 is undefined. + if (hasD32() && RegList.size() != 32) { + return Error(Op.getEndLoc(), "operand must be exactly {d0-d31}"); + } + // When target has 16 D registers, both T1 and T2 are valid. + if (!hasD32() && (RegList.size() != 16 && RegList.size() != 32)) { + return Error(Op.getEndLoc(), + "operand must be exactly {d0-d15} (T1) or {d0-d31} (T2)"); + } + } + return false; + } case ARM::t2IT: { // Encoding is unpredictable if it ever results in a notional 'NV' // predicate. Since we don't parse 'NV' directly this means an 'AL' @@ -8732,6 +8764,32 @@ bool ARMAsmParser::processInstruction(MCInst &Inst, } switch (Inst.getOpcode()) { + case ARM::VLLDM: + case ARM::VLSTM: { + // In some cases both T1 and T2 are valid, causing tablegen pick T1 instead + // of T2 + if (Operands.size() == 4) { // a register list has been provided + ARMOperand &Op = static_cast( + *Operands[3]); // the register list, a dpr_reglist + assert(Op.isDPRRegList()); + auto &RegList = Op.getRegList(); + // When the register list is {d0-d31} the instruction has to be the T2 + // variant + if (RegList.size() == 32) { + const unsigned Opcode = + (Inst.getOpcode() == ARM::VLLDM) ? ARM::VLLDM_T2 : ARM::VLSTM_T2; + MCInst TmpInst; + TmpInst.setOpcode(Opcode); + TmpInst.addOperand(Inst.getOperand(0)); + TmpInst.addOperand(Inst.getOperand(1)); + TmpInst.addOperand(Inst.getOperand(2)); + TmpInst.addOperand(Inst.getOperand(3)); + Inst = TmpInst; + return true; + } + } + return false; + } // Alias for alternate form of 'ldr{,b}t Rt, [Rn], #imm' instruction. case ARM::LDRT_POST: case ARM::LDRBT_POST: { diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp index 604f22d711190..705f3cbce12f0 100644 --- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp +++ b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp @@ -700,6 +700,9 @@ DecodeMVEOverlappingLongShift(MCInst &Inst, unsigned Insn, uint64_t Address, static DecodeStatus DecodeT2AddSubSPImm(MCInst &Inst, unsigned Insn, uint64_t Address, const MCDisassembler *Decoder); +static DecodeStatus DecodeLazyLoadStoreMul(MCInst &Inst, unsigned Insn, + uint64_t Address, + const MCDisassembler *Decoder); #include "ARMGenDisassemblerTables.inc" @@ -7030,3 +7033,23 @@ static DecodeStatus DecodeT2AddSubSPImm(MCInst &Inst, unsigned Insn, return DS; } + +static DecodeStatus DecodeLazyLoadStoreMul(MCInst &Inst, unsigned Insn, + uint64_t Address, + const MCDisassembler *Decoder) { + DecodeStatus S = MCDisassembler::Success; + + const unsigned Rn = fieldFromInstruction(Insn, 16, 4); + // Adding Rn, holding memory location to save/load to/from, the only argument + // that is being encoded. + // '$Rn' in the assembly. + if (!Check(S, DecodeGPRRegisterClass(Inst, Rn, Address, Decoder))) + return MCDisassembler::Fail; + // An optional predicate, '$p' in the assembly. + DecodePredicateOperand(Inst, ARMCC::AL, Address, Decoder); + // An immediate that represents a floating point registers list. '$regs' in + // the assembly. + Inst.addOperand(MCOperand::createImm(0)); // Arbitrary value, has no effect. + + return S; +} diff --git a/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp b/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp index fbd067d79af0b..24e627cd9a4e1 100644 --- a/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp +++ b/llvm/lib/Target/ARM/MCTargetDesc/ARMInstPrinter.cpp @@ -91,6 +91,38 @@ void ARMInstPrinter::printInst(const MCInst *MI, uint64_t Address, unsigned Opcode = MI->getOpcode(); switch (Opcode) { + case ARM::VLLDM: { + const MCOperand &Reg = MI->getOperand(0); + O << '\t' << "vlldm" << '\t'; + printRegName(O, Reg.getReg()); + O << ", " + << "{d0 - d15}"; + return; + } + case ARM::VLLDM_T2: { + const MCOperand &Reg = MI->getOperand(0); + O << '\t' << "vlldm" << '\t'; + printRegName(O, Reg.getReg()); + O << ", " + << "{d0 - d31}"; + return; + } + case ARM::VLSTM: { + const MCOperand &Reg = MI->getOperand(0); + O << '\t' << "vlstm" << '\t'; + printRegName(O, Reg.getReg()); + O << ", " + << "{d0 - d15}"; + return; + } + case ARM::VLSTM_T2: { + const MCOperand &Reg = MI->getOperand(0); + O << '\t' << "vlstm" << '\t'; + printRegName(O, Reg.getReg()); + O << ", " + << "{d0 - d31}"; + return; + } // Check for MOVs and print canonical forms, instead. case ARM::MOVsr: { // FIXME: Thumb variants? diff --git a/llvm/test/CodeGen/ARM/cmse-vlldm-no-reorder.mir b/llvm/test/CodeGen/ARM/cmse-vlldm-no-reorder.mir index 2bc4288884f19..3d49fee8fdaf4 100644 --- a/llvm/test/CodeGen/ARM/cmse-vlldm-no-reorder.mir +++ b/llvm/test/CodeGen/ARM/cmse-vlldm-no-reorder.mir @@ -89,7 +89,7 @@ body: | # CHECK: $sp = t2STMDB_UPD $sp, 14 /* CC::al */, $noreg, $r4, $r5, $r6, undef $r7, $r8, $r9, $r10, $r11 # CHECK-NEXT: $r0 = t2BICri $r0, 1, 14 /* CC::al */, $noreg, $noreg # CHECK-NEXT: $sp = tSUBspi $sp, 34, 14 /* CC::al */, $noreg -# CHECK-NEXT: VLSTM $sp, 14 /* CC::al */, $noreg, implicit undef $vpr, implicit undef $fpscr, implicit undef $fpscr_nzcv, implicit undef $q0, implicit undef $q1, implicit undef $q2, implicit undef $q3, implicit undef $q4, implicit undef $q5, implicit undef $q6, implicit undef $q7 +# CHECK-NEXT: VLSTM $sp, 14 /* CC::al */, $noreg, 0, implicit-def $vpr, implicit-def $fpscr, implicit-def $fpscr_nzcv, implicit undef $vpr, implicit undef $fpscr, implicit undef $fpscr_nzcv, implicit undef $d0, implicit undef $d1, implicit undef $d2, implicit undef $d3, implicit undef $d4, implicit undef $d5, implicit undef $d6, implicit undef $d7, implicit $d8, implicit $d9, implicit $d10, implicit $d11, implicit $d12, implicit $d13, implicit $d14, implicit $d15 # CHECK-NEXT: $r1 = tMOVr $r0, 14 /* CC::al */, $noreg # CHECK-NEXT: $r2 = tMOVr $r0, 14 /* CC::al */, $noreg # CHECK-NEXT: $r3 = tMOVr $r0, 14 /* CC::al */, $noreg @@ -105,8 +105,7 @@ body: | # CHECK-NEXT: t2MSR_M 3072, $r0, 14 /* CC::al */, $noreg, implicit-def $cpsr # CHECK-NEXT: tBLXNSr 14 /* CC::al */, $noreg, killed $r0, csr_aapcs, implicit-def $lr, implicit $sp, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $s0 # CHECK-NEXT: $r12 = VMOVRS $s0, 14 /* CC::al */, $noreg -# CHECK-NEXT: VLLDM $sp, 14 /* CC::al */, $noreg, implicit-def $q0, implicit-def $q1, implicit-def $q2, implicit-def $q3, implicit-def $q4, implicit-def $q5, implicit-def $q6, implicit-def $q7, implicit-def $vpr, implicit-def $fpscr, implicit-def $fpscr_nzcv +# CHECK-NEXT: VLLDM $sp, 14 /* CC::al */, $noreg, 0, implicit-def $vpr, implicit-def $fpscr, implicit-def $fpscr_nzcv, implicit-def $d0, implicit-def $d1, implicit-def $d2, implicit-def $d3, implicit-def $d4, implicit-def $d5, implicit-def $d6, implicit-def $d7, implicit-def $d8, implicit-def $d9, implicit-def $d10, implicit-def $d11, implicit-def $d12, implicit-def $d13, implicit-def $d14, implicit-def $d15 # CHECK-NEXT: $s0 = VMOVSR $r12, 14 /* CC::al */, $noreg # CHECK-NEXT: $sp = tADDspi $sp, 34, 14 /* CC::al */, $noreg # CHECK-NEXT: $sp = t2LDMIA_UPD $sp, 14 /* CC::al */, $noreg, def $r4, def $r5, def $r6, def $r7, def $r8, def $r9, def $r10, def $r11 - diff --git a/llvm/test/CodeGen/ARM/vlldm-vlstm-uops.mir b/llvm/test/CodeGen/ARM/vlldm-vlstm-uops.mir index 8c49a53167411..8fa9337eae6cd 100644 --- a/llvm/test/CodeGen/ARM/vlldm-vlstm-uops.mir +++ b/llvm/test/CodeGen/ARM/vlldm-vlstm-uops.mir @@ -60,9 +60,9 @@ body: | $sp = t2STMDB_UPD $sp, 14, $noreg, $r4, killed $r5, killed $r6, killed $r7, killed $r8, killed $r9, killed $r10, killed $r11 $r4 = t2BICri $r4, 1, 14, $noreg, $noreg $sp = tSUBspi $sp, 34, 14, $noreg - VLSTM $sp, 14, $noreg - tBLXNSr 14, $noreg, killed $r4, csr_aapcs, implicit-def $lr, implicit $sp, implicit-def dead $lr, implicit $sp, implicit-def $sp - VLLDM $sp, 14, $noreg, implicit-def $q0, implicit-def $q1, implicit-def $q2, implicit-def $q3, implicit-def $q4, implicit-def $q5, implicit-def $q6, implicit-def $q7, implicit-def $vpr, implicit-def $fpscr, implicit-def $fpscr_nzcv + VLSTM $sp, 14 /* CC::al */, $noreg, 0, implicit-def $vpr, implicit-def $fpscr, implicit-def $fpscr_nzcv, implicit undef $vpr, implicit undef $fpscr, implicit undef $fpscr_nzcv, implicit undef $d0, implicit undef $d1, implicit undef $d2, implicit undef $d3, implicit undef $d4, implicit undef $d5, implicit undef $d6, implicit undef $d7, implicit $d8, implicit $d9, implicit $d10, implicit $d11, implicit $d12, implicit $d13, implicit $d14, implicit $d15 + tBLXNSr 14, $noreg, killed $r4, csr_aapcs, implicit-def $lr, implicit $sp, implicit-def dead $lr, implicit $sp, implicit-def $sp, implicit-def $q0, implicit-def $q1, implicit-def $q2, implicit-def $q3, implicit-def $q4, implicit-def $q5, implicit-def $q6, implicit-def $q7 + VLLDM $sp, 14 /* CC::al */, $noreg, 0, implicit-def $vpr, implicit-def $fpscr, implicit-def $fpscr_nzcv, implicit-def $d0, implicit-def $d1, implicit-def $d2, implicit-def $d3, implicit-def $d4, implicit-def $d5, implicit-def $d6, implicit-def $d7, implicit-def $d8, implicit-def $d9, implicit-def $d10, implicit-def $d11, implicit-def $d12, implicit-def $d13, implicit-def $d14, implicit-def $d15 $sp = tADDspi $sp, 34, 14, $noreg $sp = t2LDMIA_UPD $sp, 14, $noreg, def $r4, def $r5, def $r6, def $r7, def $r8, def $r9, def $r10, def $r11 $sp = t2LDMIA_RET $sp, 14, $noreg, def $r4, def $pc diff --git a/llvm/test/MC/ARM/thumbv8m.s b/llvm/test/MC/ARM/thumbv8m.s index 0e9ab4a9b3bf9..f03dd03dae3a4 100644 --- a/llvm/test/MC/ARM/thumbv8m.s +++ b/llvm/test/MC/ARM/thumbv8m.s @@ -184,13 +184,13 @@ ttat r0, r1 // 'Lazy Load/Store Multiple' // UNDEF-BASELINE: error: instruction requires: armv8m.main -// CHECK-MAINLINE: vlldm r5 @ encoding: [0x35,0xec,0x00,0x0a] -// CHECK-MAINLINE_DSP: vlldm r5 @ encoding: [0x35,0xec,0x00,0x0a] +// CHECK-MAINLINE: vlldm r5, {d0 - d15} @ encoding: [0x35,0xec,0x00,0x0a] +// CHECK-MAINLINE_DSP: vlldm r5, {d0 - d15} @ encoding: [0x35,0xec,0x00,0x0a] vlldm r5 // UNDEF-BASELINE: error: instruction requires: armv8m.main -// CHECK-MAINLINE: vlstm r10 @ encoding: [0x2a,0xec,0x00,0x0a] -// CHECK-MAINLINE_DSP: vlstm r10 @ encoding: [0x2a,0xec,0x00,0x0a] +// CHECK-MAINLINE: vlstm r10, {d0 - d15} @ encoding: [0x2a,0xec,0x00,0x0a] +// CHECK-MAINLINE_DSP: vlstm r10, {d0 - d15} @ encoding: [0x2a,0xec,0x00,0x0a] vlstm r10 // New SYSm's diff --git a/llvm/test/MC/ARM/vlstm-vlldm-8.1m.s b/llvm/test/MC/ARM/vlstm-vlldm-8.1m.s new file mode 100644 index 0000000000000..4e35883ffe433 --- /dev/null +++ b/llvm/test/MC/ARM/vlstm-vlldm-8.1m.s @@ -0,0 +1,11 @@ +// RUN: llvm-mc -triple=armv8.1m.main-arm-none-eabi -mcpu=generic -show-encoding %s \ +// RUN: | FileCheck --check-prefixes=CHECK %s + +// RUN: llvm-mc -triple=thumbv8.1m.main-none-eabi -mcpu=generic -show-encoding %s \ +// RUN: | FileCheck --check-prefixes=CHECK %s + +vlstm r8, {d0 - d31} +// CHECK: vlstm r8, {d0 - d31} @ encoding: [0x28,0xec,0x80,0x0a] + +vlldm r8, {d0 - d31} +// CHECK: vlldm r8, {d0 - d31} @ encoding: [0x38,0xec,0x80,0x0a] diff --git a/llvm/test/MC/ARM/vlstm-vlldm-8m.s b/llvm/test/MC/ARM/vlstm-vlldm-8m.s new file mode 100644 index 0000000000000..bbc95318aeb3d --- /dev/null +++ b/llvm/test/MC/ARM/vlstm-vlldm-8m.s @@ -0,0 +1,17 @@ +// RUN: llvm-mc -triple=armv8m.main-arm-none-eabi -mcpu=generic -show-encoding %s \ +// RUN: | FileCheck --check-prefixes=CHECK %s + +// RUN: llvm-mc -triple=thumbv8m.main-none-eabi -mcpu=generic -show-encoding %s \ +// RUN: | FileCheck --check-prefixes=CHECK %s + +vlstm r8, {d0 - d15} +// CHECK: vlstm r8, {d0 - d15} @ encoding: [0x28,0xec,0x00,0x0a] + +vlldm r8, {d0 - d15} +// CHECK: vlldm r8, {d0 - d15} @ encoding: [0x38,0xec,0x00,0x0a] + +vlstm r8 +// CHECK: vlstm r8, {d0 - d15} @ encoding: [0x28,0xec,0x00,0x0a] + +vlldm r8 +// CHECK: vlldm r8, {d0 - d15} @ encoding: [0x38,0xec,0x00,0x0a] diff --git a/llvm/test/MC/ARM/vlstm-vlldm-diag.s b/llvm/test/MC/ARM/vlstm-vlldm-diag.s new file mode 100644 index 0000000000000..b57f535c6a25c --- /dev/null +++ b/llvm/test/MC/ARM/vlstm-vlldm-diag.s @@ -0,0 +1,61 @@ +// RUN: not llvm-mc -triple=armv8.1m.main-arm-none-eabi -mcpu=generic -show-encoding %s 2>&1 >/dev/null \ +// RUN: | FileCheck --check-prefixes=ERR %s + +// RUN: not llvm-mc -triple=armv8.1m.main-arm-none-eabi -mcpu=generic -show-encoding %s 2>&1 >/dev/null \ +// RUN: | FileCheck --check-prefixes=ERRT2 %s + +vlstm r8, {d0 - d11} +// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2) +// ERR-NEXT: vlstm r8, {d0 - d11} + +vlldm r8, {d0 - d11} +// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2) +// ERR-NEXT: vlldm r8, {d0 - d11} + +vlstm r8, {d3 - d15} +// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2) +// ERR-NEXT: vlstm r8, {d3 - d15} + +vlldm r8, {d3 - d15} +// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2) +// ERR-NEXT: vlldm r8, {d3 - d15} + +vlstm r8, {d0 - d29} +// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2) +// ERR-NEXT: vlstm r8, {d0 - d29} + +vlldm r8, {d0 - d29} +// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2) +// ERR-NEXT: vlldm r8, {d0 - d29} + +vlstm r8, {d3 - d31} +// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2) +// ERR-NEXT: vlstm r8, {d3 - d31} + +vlldm r8, {d3 - d31} +// ERR: error: operand must be exactly {d0-d15} (T1) or {d0-d31} (T2) +// ERR-NEXT: vlldm r8, {d3 - d31} + +vlstm r8, {d0 - d35} +// ERR: error: register expected +// ERR-NEXT: vlstm r8, {d0 - d35} + +vlldm r8, {d0 - d35} +// ERR: error: register expected +// ERR-NEXT: vlldm r8, {d0 - d35} + +vlstm pc +// ERR: error: operand must be a register in range [r0, r14] +// ERR-NEXT: vlstm pc + +vlldm pc +// ERR: error: operand must be a register in range [r0, r14] +// ERR-NEXT: vlldm pc + +vlstm pc +// ERRT2: error: operand must be a register in range [r0, r14] +// ERRT2-NEXT: vlstm pc + +vlldm pc +// ERRT2: error: operand must be a register in range [r0, r14] +// ERRT2-NEXT: vlldm pc \ No newline at end of file diff --git a/llvm/test/MC/Disassembler/ARM/armv8.1m-vlldm_vlstm-8.1.main.txt b/llvm/test/MC/Disassembler/ARM/armv8.1m-vlldm_vlstm-8.1.main.txt new file mode 100644 index 0000000000000..6b9882454c06a --- /dev/null +++ b/llvm/test/MC/Disassembler/ARM/armv8.1m-vlldm_vlstm-8.1.main.txt @@ -0,0 +1,11 @@ +// RUN: llvm-mc -triple=armv8.1m.main-arm-none-eabi -mcpu=generic -show-encoding -disassemble %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK-DISS + +// RUN: llvm-mc -triple=thumbv8.1m.main-none-eabi -mcpu=generic -show-encoding -disassemble %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK-DISS + +[0x28,0xec,0x80,0x0a] +// CHECK-DISS: vlstm r8, {d0 - d31} @ encoding: [0x28,0xec,0x80,0x0a] + +[0x38,0xec,0x80,0x0a] +// CHECK-DISS: vlldm r8, {d0 - d31} @ encoding: [0x38,0xec,0x80,0x0a] \ No newline at end of file diff --git a/llvm/test/MC/Disassembler/ARM/armv8.1m-vlldm_vlstm-8.main.txt b/llvm/test/MC/Disassembler/ARM/armv8.1m-vlldm_vlstm-8.main.txt new file mode 100644 index 0000000000000..1e28d5284c5b2 --- /dev/null +++ b/llvm/test/MC/Disassembler/ARM/armv8.1m-vlldm_vlstm-8.main.txt @@ -0,0 +1,17 @@ +// RUN: llvm-mc -triple=armv8m.main-arm-none-eabi -mcpu=generic -show-encoding -disassemble %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK-DISS + +// RUN: llvm-mc -triple=thumbv8m.main-none-eabi -mcpu=generic -show-encoding -disassemble %s \ +// RUN: | FileCheck %s --check-prefixes=CHECK-DISS + +[0x28,0xec,0x00,0x0a] +// CHECK-DISS: vlstm r8, {d0 - d15} @ encoding: [0x28,0xec,0x00,0x0a] + +[0x38,0xec,0x00,0x0a] +// CHECK-DISS: vlldm r8, {d0 - d15} @ encoding: [0x38,0xec,0x00,0x0a] + +[0x28,0xec,0x00,0x0a] +// CHECK-DISS: vlstm r8, {d0 - d15} @ encoding: [0x28,0xec,0x00,0x0a] + +[0x38,0xec,0x00,0x0a] +// CHECK-DISS: vlldm r8, {d0 - d15} @ encoding: [0x38,0xec,0x00,0x0a] \ No newline at end of file diff --git a/llvm/unittests/Target/ARM/MachineInstrTest.cpp b/llvm/unittests/Target/ARM/MachineInstrTest.cpp index aeb25bf012d03..3a76054ca4f36 100644 --- a/llvm/unittests/Target/ARM/MachineInstrTest.cpp +++ b/llvm/unittests/Target/ARM/MachineInstrTest.cpp @@ -1126,7 +1126,9 @@ TEST(MachineInstr, HasSideEffects) { VLDR_VPR_post, VLDR_VPR_pre, VLLDM, + VLLDM_T2, VLSTM, + VLSTM_T2, VMRS, VMRS_FPCXTNS, VMRS_FPCXTS,