diff options
| author | Simon Tatham <simon.tatham@arm.com> | 2019-06-10 15:36:34 +0000 |
|---|---|---|
| committer | Simon Tatham <simon.tatham@arm.com> | 2019-06-10 15:36:34 +0000 |
| commit | baeea9193370deeefb19ea7602606e262fec9be6 (patch) | |
| tree | 89e90d76800c89b18b403f893b27799bbf1a7e90 /llvm/lib/Target/ARM/AsmParser | |
| parent | 05bf5f9328e2bcada093cc36e729621763b68823 (diff) | |
| download | bcm5719-llvm-baeea9193370deeefb19ea7602606e262fec9be6.tar.gz bcm5719-llvm-baeea9193370deeefb19ea7602606e262fec9be6.zip | |
[ARM] Add the non-MVE instructions in Arm v8.1-M.
This adds support for the new family of conditional selection /
increment / negation instructions; the low-overhead branch
instructions (e.g. BF, WLS, DLS); the CLRM instruction to zero a whole
list of registers at once; the new VMRS/VMSR and VLDR/VSTR
instructions to get data in and out of 8.1-M system registers,
particularly including the new VPR register used by MVE vector
predication.
To support this, we also add a register name 'zr' (used by the CSEL
family to force one of the inputs to the constant 0), and operand
types for lists of registers that are also allowed to include APSR or
VPR (used by CLRM). The VLDR/VSTR instructions also need some new
addressing modes.
The low-overhead branch instructions exist in their own separate
architecture extension, which we treat as enabled by default, but you
can say -mattr=-lob or equivalent to turn it off.
Reviewers: dmgreen, samparker, SjoerdMeijer, t.p.northover
Reviewed By: samparker
Subscribers: miyuki, javed.absar, kristof.beyls, hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D62667
llvm-svn: 362953
Diffstat (limited to 'llvm/lib/Target/ARM/AsmParser')
| -rw-r--r-- | llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 297 |
1 files changed, 273 insertions, 24 deletions
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index f8a00f713e4..7451b931c84 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -384,7 +384,7 @@ class ARMAsmParser : public MCTargetAsmParser { int tryParseRegister(); bool tryParseRegisterWithWriteBack(OperandVector &); int tryParseShiftRegister(OperandVector &); - bool parseRegisterList(OperandVector &); + bool parseRegisterList(OperandVector &, bool EnforceOrder = true); bool parseMemory(OperandVector &); bool parseOperand(OperandVector &, StringRef Mnemonic); bool parsePrefix(ARMMCExpr::VariantKind &RefKind); @@ -479,7 +479,9 @@ class ARMAsmParser : public MCTargetAsmParser { bool hasV8MMainline() const { return getSTI().getFeatureBits()[ARM::HasV8MMainlineOps]; } - + bool hasV8_1MMainline() const { + return getSTI().getFeatureBits()[ARM::HasV8_1MMainlineOps]; + } bool has8MSecExt() const { return getSTI().getFeatureBits()[ARM::Feature8MSecExt]; } @@ -660,8 +662,11 @@ class ARMOperand : public MCParsedAsmOperand { k_VectorIndex, k_Register, k_RegisterList, + k_RegisterListWithAPSR, k_DPRRegisterList, k_SPRRegisterList, + k_FPSRegisterListWithVPR, + k_FPDRegisterListWithVPR, k_VectorList, k_VectorListAllLanes, k_VectorListIndexed, @@ -862,8 +867,11 @@ public: } const SmallVectorImpl<unsigned> &getRegList() const { - assert((Kind == k_RegisterList || Kind == k_DPRRegisterList || - Kind == k_SPRRegisterList) && "Invalid access!"); + assert((Kind == k_RegisterList || Kind == k_RegisterListWithAPSR || + Kind == k_DPRRegisterList || Kind == k_SPRRegisterList || + Kind == k_FPSRegisterListWithVPR || + Kind == k_FPDRegisterListWithVPR) && + "Invalid access!"); return Registers; } @@ -1027,6 +1035,9 @@ public: bool isImm8s4() const { return isImmediateS4<-1020, 1020>(); } + bool isImm7s4() const { + return isImmediateS4<-508, 508>(); + } bool isImm0_1020s4() const { return isImmediateS4<0, 1020>(); } @@ -1168,8 +1179,13 @@ public: bool isReg() const override { return Kind == k_Register; } bool isRegList() const { return Kind == k_RegisterList; } + bool isRegListWithAPSR() const { + return Kind == k_RegisterListWithAPSR || Kind == k_RegisterList; + } bool isDPRRegList() const { return Kind == k_DPRRegisterList; } bool isSPRRegList() const { return Kind == k_SPRRegisterList; } + bool isFPSRegListWithVPR() const { return Kind == k_FPSRegisterListWithVPR; } + bool isFPDRegListWithVPR() const { return Kind == k_FPDRegisterListWithVPR; } bool isToken() const override { return Kind == k_Token; } bool isMemBarrierOpt() const { return Kind == k_MemBarrierOpt; } bool isInstSyncBarrierOpt() const { return Kind == k_InstSyncBarrierOpt; } @@ -1250,6 +1266,30 @@ public: return Memory.OffsetRegNum == 0 && Memory.OffsetImm == nullptr && (alignOK || Memory.Alignment == Alignment); } + bool isMemNoOffsetT2(bool alignOK = false, unsigned Alignment = 0) const { + if (!isMem()) + return false; + + if (!ARMMCRegisterClasses[ARM::GPRnopcRegClassID].contains( + Memory.BaseRegNum)) + return false; + + // No offset of any kind. + return Memory.OffsetRegNum == 0 && Memory.OffsetImm == nullptr && + (alignOK || Memory.Alignment == Alignment); + } + bool isMemNoOffsetT2NoSp(bool alignOK = false, unsigned Alignment = 0) const { + if (!isMem()) + return false; + + if (!ARMMCRegisterClasses[ARM::rGPRRegClassID].contains( + Memory.BaseRegNum)) + return false; + + // No offset of any kind. + return Memory.OffsetRegNum == 0 && Memory.OffsetImm == nullptr && + (alignOK || Memory.Alignment == Alignment); + } bool isMemPCRelImm12() const { if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; @@ -1521,7 +1561,22 @@ public: return (Val >= -1020 && Val <= 1020 && (Val & 3) == 0) || Val == std::numeric_limits<int32_t>::min(); } - + bool isMemImm7s4Offset() const { + // If we have an immediate that's not a constant, treat it as a label + // reference needing a fixup. If it is a constant, it's something else + // and we reject it. + if (isImm() && !isa<MCConstantExpr>(getImm())) + return true; + if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0 || + !ARMMCRegisterClasses[ARM::GPRnopcRegClassID].contains( + Memory.BaseRegNum)) + return false; + // Immediate offset a multiple of 4 in range [-508, 508]. + if (!Memory.OffsetImm) return true; + int64_t Val = Memory.OffsetImm->getValue(); + // Special case, #-0 is INT32_MIN. + return (Val >= -508 && Val <= 508 && (Val & 3) == 0) || Val == INT32_MIN; + } bool isMemImm0_1020s4Offset() const { if (!isMem() || Memory.OffsetRegNum != 0 || Memory.Alignment != 0) return false; @@ -1993,6 +2048,12 @@ public: return (Value % Angle == Remainder && Value <= 270); } + bool isITCondCodeNoAL() const { + if (!isITCondCode()) return false; + auto CC = (ARMCC::CondCodes) getCondCode(); + return CC != ARMCC::AL; + } + void addExpr(MCInst &Inst, const MCExpr *Expr) const { // Add as immediates when possible. Null MCExpr = 0. if (!Expr) @@ -2045,6 +2106,11 @@ public: Inst.addOperand(MCOperand::createImm(unsigned(getCondCode()))); } + void addITCondCodeInvOperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createImm(unsigned(ARMCC::getOppositeCondition(getCondCode())))); + } + void addCCOutOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); Inst.addOperand(MCOperand::createReg(getReg())); @@ -2090,6 +2156,14 @@ public: Inst.addOperand(MCOperand::createReg(*I)); } + void addRegListWithAPSROperands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + const SmallVectorImpl<unsigned> &RegList = getRegList(); + for (SmallVectorImpl<unsigned>::const_iterator + I = RegList.begin(), E = RegList.end(); I != E; ++I) + Inst.addOperand(MCOperand::createReg(*I)); + } + void addDPRRegListOperands(MCInst &Inst, unsigned N) const { addRegListOperands(Inst, N); } @@ -2098,6 +2172,14 @@ public: addRegListOperands(Inst, N); } + void addFPSRegListWithVPROperands(MCInst &Inst, unsigned N) const { + addRegListOperands(Inst, N); + } + + void addFPDRegListWithVPROperands(MCInst &Inst, unsigned N) const { + addRegListOperands(Inst, N); + } + void addRotImmOperands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // Encoded as val>>3. The printer handles display as 8, 16, 24. @@ -2185,6 +2267,14 @@ public: Inst.addOperand(MCOperand::createImm(CE->getValue())); } + void addImm7s4Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + // FIXME: We really want to scale the value here, but the VSTR/VLDR_VSYSR + // instruction don't encode operands that way yet. + const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(getImm()); + Inst.addOperand(MCOperand::createImm(CE->getValue())); + } + void addImm0_1020s4Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); // The immediate is scaled by four in the encoding and is stored @@ -2319,6 +2409,11 @@ public: Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); } + void addMemNoOffsetT2Operands(MCInst &Inst, unsigned N) const { + assert(N == 1 && "Invalid number of operands!"); + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + } + void addMemPCRelImm12Operands(MCInst &Inst, unsigned N) const { assert(N == 1 && "Invalid number of operands!"); int32_t Imm = Memory.OffsetImm->getValue(); @@ -2536,6 +2631,22 @@ public: Inst.addOperand(MCOperand::createImm(Val)); } + void addMemImm7s4OffsetOperands(MCInst &Inst, unsigned N) const { + assert(N == 2 && "Invalid number of operands!"); + // If we have an immediate that's not a constant, treat it as a label + // reference needing a fixup. If it is a constant, it's something else + // and we reject it. + if (isImm()) { + Inst.addOperand(MCOperand::createExpr(getImm())); + Inst.addOperand(MCOperand::createImm(0)); + return; + } + + int64_t Val = Memory.OffsetImm ? Memory.OffsetImm->getValue() : 0; + Inst.addOperand(MCOperand::createReg(Memory.BaseRegNum)); + Inst.addOperand(MCOperand::createImm(Val)); + } + void addMemImm0_1020s4OffsetOperands(MCInst &Inst, unsigned N) const { assert(N == 2 && "Invalid number of operands!"); // The lower two bits are always zero and as such are not encoded. @@ -3045,19 +3156,31 @@ public: assert(Regs.size() > 0 && "RegList contains no registers?"); KindTy Kind = k_RegisterList; - if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains(Regs.front().second)) - Kind = k_DPRRegisterList; - else if (ARMMCRegisterClasses[ARM::SPRRegClassID]. - contains(Regs.front().second)) - Kind = k_SPRRegisterList; + if (ARMMCRegisterClasses[ARM::DPRRegClassID].contains( + Regs.front().second)) { + if (Regs.back().second == ARM::VPR) + Kind = k_FPDRegisterListWithVPR; + else + Kind = k_DPRRegisterList; + } else if (ARMMCRegisterClasses[ARM::SPRRegClassID].contains( + Regs.front().second)) { + if (Regs.back().second == ARM::VPR) + Kind = k_FPSRegisterListWithVPR; + else + Kind = k_SPRRegisterList; + } // Sort based on the register encoding values. array_pod_sort(Regs.begin(), Regs.end()); + if (Kind == k_RegisterList && Regs.back().second == ARM::APSR) + Kind = k_RegisterListWithAPSR; + auto Op = make_unique<ARMOperand>(Kind); for (SmallVectorImpl<std::pair<unsigned, unsigned>>::const_iterator I = Regs.begin(), E = Regs.end(); I != E; ++I) Op->Registers.push_back(I->second); + Op->StartLoc = StartLoc; Op->EndLoc = EndLoc; return Op; @@ -3325,8 +3448,11 @@ void ARMOperand::print(raw_ostream &OS) const { << ", width: " << Bitfield.Width << ">"; break; case k_RegisterList: + case k_RegisterListWithAPSR: case k_DPRRegisterList: - case k_SPRRegisterList: { + case k_SPRRegisterList: + case k_FPSRegisterListWithVPR: + case k_FPDRegisterListWithVPR: { OS << "<register_list "; const SmallVectorImpl<unsigned> &RegList = getRegList(); @@ -3753,7 +3879,8 @@ static unsigned getNextRegister(unsigned Reg) { } /// Parse a register list. -bool ARMAsmParser::parseRegisterList(OperandVector &Operands) { +bool ARMAsmParser::parseRegisterList(OperandVector &Operands, + bool EnforceOrder) { MCAsmParser &Parser = getParser(); if (Parser.getTok().isNot(AsmToken::LCurly)) return TokError("Token is not a Left Curly Brace"); @@ -3786,6 +3913,8 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands) { RC = &ARMMCRegisterClasses[ARM::DPRRegClassID]; else if (ARMMCRegisterClasses[ARM::SPRRegClassID].contains(Reg)) RC = &ARMMCRegisterClasses[ARM::SPRRegClassID]; + else if (ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID].contains(Reg)) + RC = &ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID]; else return Error(RegLoc, "invalid register in register list"); @@ -3839,14 +3968,32 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands) { Reg = getDRegFromQReg(Reg); isQReg = true; } + if (!RC->contains(Reg) && + RC->getID() == ARMMCRegisterClasses[ARM::GPRRegClassID].getID() && + ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID].contains(Reg)) { + // switch the register classes, as GPRwithAPSRnospRegClassID is a partial + // subset of GPRRegClassId except it contains APSR as well. + RC = &ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID]; + } + if (Reg == ARM::VPR && (RC == &ARMMCRegisterClasses[ARM::SPRRegClassID] || + RC == &ARMMCRegisterClasses[ARM::DPRRegClassID])) { + RC = &ARMMCRegisterClasses[ARM::FPWithVPRRegClassID]; + EReg = MRI->getEncodingValue(Reg); + Registers.push_back(std::pair<unsigned, unsigned>(EReg, Reg)); + continue; + } // The register must be in the same register class as the first. if (!RC->contains(Reg)) return Error(RegLoc, "invalid register in register list"); - // List must be monotonically increasing. - if (MRI->getEncodingValue(Reg) < MRI->getEncodingValue(OldReg)) { + // In most cases, the list must be monotonically increasing. An + // exception is CLRM, which is order-independent anyway, so + // there's no potential for confusion if you write clrm {r2,r1} + // instead of clrm {r1,r2}. + if (EnforceOrder && + MRI->getEncodingValue(Reg) < MRI->getEncodingValue(OldReg)) { if (ARMMCRegisterClasses[ARM::GPRRegClassID].contains(Reg)) Warning(RegLoc, "register list not in ascending order"); - else + else if (!ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID].contains(Reg)) return Error(RegLoc, "register list not in ascending order"); } if (MRI->getEncodingValue(Reg) == MRI->getEncodingValue(OldReg)) { @@ -3856,6 +4003,7 @@ bool ARMAsmParser::parseRegisterList(OperandVector &Operands) { } // VFP register lists must also be contiguous. if (RC != &ARMMCRegisterClasses[ARM::GPRRegClassID] && + RC != &ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID] && Reg != OldReg + 1) return Error(RegLoc, "non-contiguous register range"); EReg = MRI->getEncodingValue(Reg); @@ -5464,7 +5612,7 @@ bool ARMAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { case AsmToken::LBrac: return parseMemory(Operands); case AsmToken::LCurly: - return parseRegisterList(Operands); + return parseRegisterList(Operands, !Mnemonic.startswith("clr")); case AsmToken::Dollar: case AsmToken::Hash: // #42 -> immediate. @@ -5653,7 +5801,12 @@ StringRef ARMAsmParser::splitMnemonic(StringRef Mnemonic, Mnemonic == "bxns" || Mnemonic == "blxns" || Mnemonic == "vudot" || Mnemonic == "vsdot" || Mnemonic == "vcmla" || Mnemonic == "vcadd" || - Mnemonic == "vfmal" || Mnemonic == "vfmsl") + Mnemonic == "vfmal" || Mnemonic == "vfmsl" || + Mnemonic == "wls" || Mnemonic == "le" || Mnemonic == "dls" || + Mnemonic == "csel" || Mnemonic == "csinc" || + Mnemonic == "csinv" || Mnemonic == "csneg" || Mnemonic == "cinc" || + Mnemonic == "cinv" || Mnemonic == "cneg" || Mnemonic == "cset" || + Mnemonic == "csetm") return Mnemonic; // First, split out any predication code. Ignore mnemonics we know aren't @@ -5746,7 +5899,12 @@ void ARMAsmParser::getMnemonicAcceptInfo(StringRef Mnemonic, StringRef FullInst, Mnemonic == "vcmla" || Mnemonic == "vcadd" || Mnemonic == "vfmal" || Mnemonic == "vfmsl" || Mnemonic == "sb" || Mnemonic == "ssbb" || - Mnemonic == "pssbb") { + Mnemonic == "pssbb" || + Mnemonic == "bfcsel" || Mnemonic == "wls" || + Mnemonic == "dls" || Mnemonic == "le" || Mnemonic == "csel" || + Mnemonic == "csinc" || Mnemonic == "csinv" || Mnemonic == "csneg" || + Mnemonic == "cinc" || Mnemonic == "cinv" || Mnemonic == "cneg" || + Mnemonic == "cset" || Mnemonic == "csetm") { // These mnemonics are never predicable CanAcceptPredicationCode = false; } else if (!isThumb()) { @@ -6478,7 +6636,8 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, } else if (isThumbTwo() && MCID.isPredicable() && Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() != ARMCC::AL && Inst.getOpcode() != ARM::tBcc && - Inst.getOpcode() != ARM::t2Bcc) { + Inst.getOpcode() != ARM::t2Bcc && + Inst.getOpcode() != ARM::t2BFic) { return Error(Loc, "predicated instructions must be in IT block"); } else if (!isThumb() && !useImplicitITARM() && MCID.isPredicable() && Inst.getOperand(MCID.findFirstPredOperandIdx()).getImm() != @@ -6876,6 +7035,77 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, "code specified"); break; } + case ARM::t2WLS: { + int idx = Opcode == ARM::t2WLS ? 3 : 4; + if (!static_cast<ARMOperand &>(*Operands[idx]).isUnsignedOffset<11, 1>()) + return Error(Operands[idx]->getStartLoc(), + "loop end is out of range or not a positive multiple of 2"); + break; + } + case ARM::t2LEUpdate: { + if (Inst.getOperand(2).isImm() && + !(Inst.getOperand(2).getImm() < 0 && + Inst.getOperand(2).getImm() >= -4094 && + (Inst.getOperand(2).getImm() & 1) == 0)) + return Error(Operands[2]->getStartLoc(), + "loop start is out of range or not a negative multiple of 2"); + break; + } + case ARM::t2BFi: + case ARM::t2BFr: + case ARM::t2BFLi: + case ARM::t2BFLr: { + if (!static_cast<ARMOperand &>(*Operands[2]).isUnsignedOffset<4, 1>() || + (Inst.getOperand(0).isImm() && Inst.getOperand(0).getImm() == 0)) + return Error(Operands[2]->getStartLoc(), + "branch location out of range or not a multiple of 2"); + + if (Opcode == ARM::t2BFi) { + if (!static_cast<ARMOperand &>(*Operands[3]).isSignedOffset<16, 1>()) + return Error(Operands[3]->getStartLoc(), + "branch target out of range or not a multiple of 2"); + } else if (Opcode == ARM::t2BFLi) { + if (!static_cast<ARMOperand &>(*Operands[3]).isSignedOffset<18, 1>()) + return Error(Operands[3]->getStartLoc(), + "branch target out of range or not a multiple of 2"); + } + break; + } + case ARM::t2BFic: { + if (!static_cast<ARMOperand &>(*Operands[1]).isUnsignedOffset<4, 1>() || + (Inst.getOperand(0).isImm() && Inst.getOperand(0).getImm() == 0)) + return Error(Operands[1]->getStartLoc(), + "branch location out of range or not a multiple of 2"); + + if (!static_cast<ARMOperand &>(*Operands[2]).isSignedOffset<16, 1>()) + return Error(Operands[2]->getStartLoc(), + "branch target out of range or not a multiple of 2"); + + assert(Inst.getOperand(0).isImm() == Inst.getOperand(2).isImm() && + "branch location and else branch target should either both be " + "immediates or both labels"); + + if (Inst.getOperand(0).isImm() && Inst.getOperand(2).isImm()) { + int Diff = Inst.getOperand(2).getImm() - Inst.getOperand(0).getImm(); + if (Diff != 4 && Diff != 2) + return Error( + Operands[3]->getStartLoc(), + "else branch target must be 2 or 4 greater than the branch location"); + } + break; + } + case ARM::t2CLRM: { + for (unsigned i = 2; i < Inst.getNumOperands(); i++) { + if (Inst.getOperand(i).isReg() && + !ARMMCRegisterClasses[ARM::GPRwithAPSRnospRegClassID].contains( + Inst.getOperand(i).getReg())) { + return Error(Operands[2]->getStartLoc(), + "invalid register in register list. Valid registers are " + "r0-r12, lr/r14 and APSR."); + } + } + break; + } case ARM::DSB: case ARM::t2DSB: { @@ -9169,11 +9399,29 @@ unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) { return Match_RequiresV8; } - // Use of SP for VMRS/VMSR is only allowed in ARM mode with the exception of - // ARMv8-A. - if ((Inst.getOpcode() == ARM::VMRS || Inst.getOpcode() == ARM::VMSR) && - Inst.getOperand(0).getReg() == ARM::SP && (isThumb() && !hasV8Ops())) - return Match_InvalidOperand; + switch (Inst.getOpcode()) { + case ARM::VMRS: + case ARM::VMSR: + case ARM::VMRS_FPCXTS: + case ARM::VMRS_FPCXTNS: + case ARM::VMSR_FPCXTS: + case ARM::VMSR_FPCXTNS: + case ARM::VMRS_FPSCR_NZCVQC: + case ARM::VMSR_FPSCR_NZCVQC: + case ARM::FMSTAT: + case ARM::VMRS_VPR: + case ARM::VMRS_P0: + case ARM::VMSR_VPR: + case ARM::VMSR_P0: + // Use of SP for VMRS/VMSR is only allowed in ARM mode with the exception of + // ARMv8-A. + if (Inst.getOperand(0).isReg() && Inst.getOperand(0).getReg() == ARM::SP && + (isThumb() && !hasV8Ops())) + return Match_InvalidOperand; + break; + default: + break; + } for (unsigned I = 0; I < MCID.NumOperands; ++I) if (MCID.OpInfo[I].RegClass == ARM::rGPRRegClassID) { @@ -10636,6 +10884,7 @@ bool ARMAsmParser::parseDirectiveArchExtension(SMLoc L) { { ARM::AEK_FP16, {Feature_HasV8_2aBit}, {ARM::FeatureFPARMv8, ARM::FeatureFullFP16} }, { ARM::AEK_RAS, {Feature_HasV8Bit}, {ARM::FeatureRAS} }, + { ARM::AEK_LOB, {Feature_HasV8_1MMainlineBit}, {ARM::FeatureLOB} }, // FIXME: Unsupported extensions. { ARM::AEK_OS, {}, {} }, { ARM::AEK_IWMMXT, {}, {} }, |

