[ARM] Fix assembly and disassembly for VMRS/VMSR

Reviewed by: t.p.northover
Differential Revision: https://reviews.llvm.org/D36306

llvm-svn: 313979
diff --git a/llvm/lib/Target/ARM/ARMInstrVFP.td b/llvm/lib/Target/ARM/ARMInstrVFP.td
index b43216f..0549a19 100644
--- a/llvm/lib/Target/ARM/ARMInstrVFP.td
+++ b/llvm/lib/Target/ARM/ARMInstrVFP.td
@@ -2164,28 +2164,32 @@
 def FMSTAT : MovFromVFP<0b0001 /* fpscr */, (outs), (ins),
                         "vmrs", "\tAPSR_nzcv, fpscr", [(arm_fmstat)]>;
 
-// Application level FPSCR -> GPR
-let hasSideEffects = 1, Uses = [FPSCR] in
-def VMRS : MovFromVFP<0b0001 /* fpscr */, (outs GPR:$Rt), (ins),
-                      "vmrs", "\t$Rt, fpscr",
-                      [(set GPR:$Rt, (int_arm_get_fpscr))]>;
+let DecoderMethod = "DecodeForVMRSandVMSR" in {
+ // Application level FPSCR -> GPR
+ let hasSideEffects = 1, Uses = [FPSCR] in
+ def VMRS :  MovFromVFP<0b0001 /* fpscr */, (outs GPRnopc:$Rt), (ins),
+                        "vmrs", "\t$Rt, fpscr",
+                        [(set GPRnopc:$Rt, (int_arm_get_fpscr))]>;
 
-// System level FPEXC, FPSID -> GPR
-let Uses = [FPSCR] in {
-  def VMRS_FPEXC : MovFromVFP<0b1000 /* fpexc */, (outs GPR:$Rt), (ins),
-                              "vmrs", "\t$Rt, fpexc", []>;
-  def VMRS_FPSID : MovFromVFP<0b0000 /* fpsid */, (outs GPR:$Rt), (ins),
-                              "vmrs", "\t$Rt, fpsid", []>;
-  def VMRS_MVFR0 : MovFromVFP<0b0111 /* mvfr0 */, (outs GPR:$Rt), (ins),
+ // System level FPEXC, FPSID -> GPR
+ let Uses = [FPSCR] in {
+   def VMRS_FPEXC : MovFromVFP<0b1000 /* fpexc */, (outs GPRnopc:$Rt), (ins),
+                               "vmrs", "\t$Rt, fpexc", []>;
+   def VMRS_FPSID : MovFromVFP<0b0000 /* fpsid */, (outs GPRnopc:$Rt), (ins),
+                               "vmrs", "\t$Rt, fpsid", []>;
+   def VMRS_MVFR0 : MovFromVFP<0b0111 /* mvfr0 */, (outs GPRnopc:$Rt), (ins),
                               "vmrs", "\t$Rt, mvfr0", []>;
-  def VMRS_MVFR1 : MovFromVFP<0b0110 /* mvfr1 */, (outs GPR:$Rt), (ins),
-                              "vmrs", "\t$Rt, mvfr1", []>;
-  def VMRS_MVFR2 : MovFromVFP<0b0101 /* mvfr2 */, (outs GPR:$Rt), (ins),
-                              "vmrs", "\t$Rt, mvfr2", []>, Requires<[HasFPARMv8]>;
-  def VMRS_FPINST : MovFromVFP<0b1001 /* fpinst */, (outs GPR:$Rt), (ins),
-                              "vmrs", "\t$Rt, fpinst", []>;
-  def VMRS_FPINST2 : MovFromVFP<0b1010 /* fpinst2 */, (outs GPR:$Rt), (ins),
-                                "vmrs", "\t$Rt, fpinst2", []>;
+   def VMRS_MVFR1 : MovFromVFP<0b0110 /* mvfr1 */, (outs GPRnopc:$Rt), (ins),
+                               "vmrs", "\t$Rt, mvfr1", []>;
+   let Predicates = [HasFPARMv8] in {
+     def VMRS_MVFR2 : MovFromVFP<0b0101 /* mvfr2 */, (outs GPRnopc:$Rt), (ins),
+                                 "vmrs", "\t$Rt, mvfr2", []>;
+   }
+   def VMRS_FPINST : MovFromVFP<0b1001 /* fpinst */, (outs GPRnopc:$Rt), (ins),
+                                "vmrs", "\t$Rt, fpinst", []>;
+   def VMRS_FPINST2 : MovFromVFP<0b1010 /* fpinst2 */, (outs GPRnopc:$Rt),
+                                 (ins), "vmrs", "\t$Rt, fpinst2", []>;
+ }
 }
 
 //===----------------------------------------------------------------------===//
@@ -2209,21 +2213,23 @@
   let Inst{4}     = 1;
 }
 
-let Defs = [FPSCR] in {
-  // Application level GPR -> FPSCR
-  def VMSR : MovToVFP<0b0001 /* fpscr */, (outs), (ins GPR:$src),
-                      "vmsr", "\tfpscr, $src", [(int_arm_set_fpscr GPR:$src)]>;
-  // System level GPR -> FPEXC
-  def VMSR_FPEXC : MovToVFP<0b1000 /* fpexc */, (outs), (ins GPR:$src),
-                      "vmsr", "\tfpexc, $src", []>;
-  // System level GPR -> FPSID
-  def VMSR_FPSID : MovToVFP<0b0000 /* fpsid */, (outs), (ins GPR:$src),
-                      "vmsr", "\tfpsid, $src", []>;
-
-  def VMSR_FPINST : MovToVFP<0b1001 /* fpinst */, (outs), (ins GPR:$src),
+let DecoderMethod = "DecodeForVMRSandVMSR" in {
+ let Defs = [FPSCR] in {
+   // Application level GPR -> FPSCR
+   def VMSR : MovToVFP<0b0001 /* fpscr */, (outs), (ins GPRnopc:$src),
+                       "vmsr", "\tfpscr, $src",
+                       [(int_arm_set_fpscr GPRnopc:$src)]>;
+   // System level GPR -> FPEXC
+   def VMSR_FPEXC : MovToVFP<0b1000 /* fpexc */, (outs), (ins GPRnopc:$src),
+                               "vmsr", "\tfpexc, $src", []>;
+   // System level GPR -> FPSID
+   def VMSR_FPSID : MovToVFP<0b0000 /* fpsid */, (outs), (ins GPRnopc:$src),
+                             "vmsr", "\tfpsid, $src", []>;
+   def VMSR_FPINST : MovToVFP<0b1001 /* fpinst */, (outs), (ins GPRnopc:$src),
                               "vmsr", "\tfpinst, $src", []>;
-  def VMSR_FPINST2 : MovToVFP<0b1010 /* fpinst2 */, (outs), (ins GPR:$src),
-                                "vmsr", "\tfpinst2, $src", []>;
+   def VMSR_FPINST2 : MovToVFP<0b1010 /* fpinst2 */, (outs), (ins GPRnopc:$src),
+                               "vmsr", "\tfpinst2, $src", []>;
+ }
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
index 4b10874..287ed20 100644
--- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
+++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp
@@ -8805,6 +8805,12 @@
       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;
+
   for (unsigned I = 0; I < MCID.NumOperands; ++I)
     if (MCID.OpInfo[I].RegClass == ARM::rGPRRegClassID) {
       // rGPRRegClass excludes PC, and also excluded SP before ARMv8
diff --git a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
index e8bfa6b..e385498 100644
--- a/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
+++ b/llvm/lib/Target/ARM/Disassembler/ARMDisassembler.cpp
@@ -400,6 +400,8 @@
                                 uint64_t Address, const void *Decoder);
 static DecodeStatus DecoderForMRRC2AndMCRR2(MCInst &Inst, unsigned Val,
                                             uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeForVMRSandVMSR(MCInst &Inst, unsigned Val,
+                                         uint64_t Address, const void *Decoder);
 
 #include "ARMGenDisassemblerTables.inc"
 
@@ -5284,3 +5286,25 @@
 
   return S;
 }
+
+static DecodeStatus DecodeForVMRSandVMSR(MCInst &Inst, unsigned Val,
+                                         uint64_t Address,
+                                         const void *Decoder) {
+  const FeatureBitset &featureBits =
+      ((const MCDisassembler *)Decoder)->getSubtargetInfo().getFeatureBits();
+  DecodeStatus S = MCDisassembler::Success;
+
+  unsigned Rt = fieldFromInstruction(Val, 12, 4);
+
+  if (featureBits[ARM::ModeThumb] && !featureBits[ARM::HasV8Ops]) {
+    if (Rt == 13 || Rt == 15)
+      S = MCDisassembler::SoftFail;
+    Check(S, DecodeGPRRegisterClass(Inst, Rt, Address, Decoder));
+  } else
+    Check(S, DecodeGPRnopcRegisterClass(Inst, Rt, Address, Decoder));
+
+  Inst.addOperand(MCOperand::createImm(ARMCC::AL));
+  Inst.addOperand(MCOperand::createReg(0));
+
+  return S;
+}