[Sparc] Add support for parsing fcmp with %fcc registers.
authorVenkatraman Govindaraju <venkatra@cs.wisc.edu>
Sun, 2 Mar 2014 03:39:39 +0000 (03:39 +0000)
committerVenkatraman Govindaraju <venkatra@cs.wisc.edu>
Sun, 2 Mar 2014 03:39:39 +0000 (03:39 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202610 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
lib/Target/Sparc/SparcInstrAliases.td
lib/Target/Sparc/SparcInstrFormats.td
lib/Target/Sparc/SparcInstrInfo.td
test/MC/Disassembler/Sparc/sparc-fp.txt
test/MC/Sparc/sparc-fp-instructions.s
test/MC/Sparc/sparcv8-instructions.s [new file with mode: 0644]

index 65d9228ad94e712645d471965f9e9455f71d12c0..9cbece93a3c43c5227184bf9504ecefa87cf8545 100644 (file)
@@ -68,7 +68,8 @@ class SparcAsmParser : public MCTargetAsmParser {
                StringRef Name);
 
   OperandMatchResultTy
-  parseSparcAsmOperand(SparcOperand *&Operand, bool isCall = false);
+  parseSparcAsmOperand(SparcOperand *&Operand, bool isCall = false,
+                       bool createTokenForFCC = true);
 
   OperandMatchResultTy
   parseBranchModifiers(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
@@ -631,7 +632,10 @@ parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
   }
 
   SparcOperand *Op = 0;
-  ResTy = parseSparcAsmOperand(Op, (Mnemonic == "call"));
+
+  bool createTokenForFCC = !(Mnemonic == "fcmps" || Mnemonic == "fcmpd"
+                             || Mnemonic == "fcmpq");
+  ResTy = parseSparcAsmOperand(Op, (Mnemonic == "call"), createTokenForFCC);
   if (ResTy != MatchOperand_Success || !Op)
     return MatchOperand_ParseFail;
 
@@ -642,7 +646,8 @@ parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
 }
 
 SparcAsmParser::OperandMatchResultTy
-SparcAsmParser::parseSparcAsmOperand(SparcOperand *&Op, bool isCall)
+SparcAsmParser::parseSparcAsmOperand(SparcOperand *&Op, bool isCall,
+                                     bool createTokenForFCC)
 {
 
   SMLoc S = Parser.getTok().getLoc();
@@ -677,9 +682,11 @@ SparcAsmParser::parseSparcAsmOperand(SparcOperand *&Op, bool isCall)
         break;
 
       case Sparc::FCC0:
-        assert(name == "fcc0" && "Cannot handle %fcc other than %fcc0 yet");
-        Op = SparcOperand::CreateToken("%fcc0", S);
-        break;
+        if (createTokenForFCC) {
+          assert(name == "fcc0" && "Cannot handle %fcc other than %fcc0 yet");
+          Op = SparcOperand::CreateToken("%fcc0", S);
+          break;
+        }
       }
       break;
     }
@@ -783,7 +790,7 @@ bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
         && !name.substr(3).getAsInteger(10, intVal)
         && intVal < 4) {
       // FIXME: check 64bit and  handle %fcc1 - %fcc3
-      RegNo = Sparc::FCC0;
+      RegNo = Sparc::FCC0 + intVal;
       RegKind = SparcOperand::rk_CCReg;
       return true;
     }
index e8314f23842e32d708c1efb06d516a7eb1fe146c..e01196cbccbff867541c16e11ec392e56dc445e7 100644 (file)
@@ -113,6 +113,9 @@ static const unsigned QFPRegDecoderTable[] = {
   SP::Q6,  SP::Q14,  ~0U,  ~0U,
   SP::Q7,  SP::Q15,  ~0U,  ~0U } ;
 
+static const unsigned FCCRegDecoderTable[] = {
+  SP::FCC0, SP::FCC1, SP::FCC2, SP::FCC3 };
+
 static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst,
                                                unsigned RegNo,
                                                uint64_t Address,
@@ -174,6 +177,16 @@ static DecodeStatus DecodeQFPRegsRegisterClass(MCInst &Inst,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus DecodeFCCRegsRegisterClass(MCInst &Inst, unsigned RegNo,
+                                               uint64_t Address,
+                                               const void *Decoder) {
+  if (RegNo > 3)
+    return MCDisassembler::Fail;
+  Inst.addOperand(MCOperand::CreateReg(FCCRegDecoderTable[RegNo]));
+  return MCDisassembler::Success;
+}
+
+
 static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address,
                                   const void *Decoder);
 static DecodeStatus DecodeLoadFP(MCInst &Inst, unsigned insn, uint64_t Address,
index f887b945a368286e38189a1cd9200219d3224e00..66b4b519f7efed3967e5501bb621fb9e2791bdde 100644 (file)
@@ -32,6 +32,10 @@ namespace Sparc {
 #define PRINT_ALIAS_INSTR
 #include "SparcGenAsmWriter.inc"
 
+bool SparcInstPrinter::isV9() const {
+  return (STI.getFeatureBits() & Sparc::FeatureV9) != 0;
+}
+
 void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const
 {
   OS << '%' << StringRef(getRegisterName(RegNo)).lower();
@@ -65,6 +69,26 @@ bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI, raw_ostream &O)
       return true;
     }
   }
+  case SP::V9FCMPS:
+  case SP::V9FCMPD:
+  case SP::V9FCMPQ: {
+    if (isV9()
+        || (MI->getNumOperands() != 3)
+        || (!MI->getOperand(0).isReg())
+        || (MI->getOperand(0).getReg() != SP::FCC0))
+      return false;
+    // if V8, skip printing %fcc0.
+    switch(MI->getOpcode()) {
+    default:
+    case SP::V9FCMPS: O << "\tfcmps "; break;
+    case SP::V9FCMPD: O << "\tfcmpd "; break;
+    case SP::V9FCMPQ: O << "\tfcmpq "; break;
+    }
+    printOperand(MI, 1, O);
+    O << ", ";
+    printOperand(MI, 2, O);
+    return true;
+  }
   }
 }
 
index 63ed41a4c12ca5c784b46bf57702d1bd87ffcc02..45ee6c027f9dd72e7d92f29a594cd721b3a433ba 100644 (file)
 #define SparcINSTPRINTER_H
 
 #include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCSubtargetInfo.h"
 
 namespace llvm {
 
 class MCOperand;
 
 class SparcInstPrinter : public MCInstPrinter {
+  const MCSubtargetInfo &STI;
 public:
  SparcInstPrinter(const MCAsmInfo &MAI,
                   const MCInstrInfo &MII,
-                  const MCRegisterInfo &MRI)
-   : MCInstPrinter(MAI, MII, MRI) {}
+                  const MCRegisterInfo &MRI,
+                  const MCSubtargetInfo &sti)
+   : MCInstPrinter(MAI, MII, MRI), STI(sti) {}
 
   virtual void printRegName(raw_ostream &OS, unsigned RegNo) const;
   virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot);
   bool printSparcAliasInstr(const MCInst *MI, raw_ostream &OS);
+  bool isV9() const;
 
   // Autogenerated by tblgen.
   void printInstruction(const MCInst *MI, raw_ostream &O);
index 1961254e48a9a627e4c9b615a2d0eedf922b9232..c69af56bb004626e56492a18f47b35f4ceb21688 100644 (file)
@@ -153,7 +153,7 @@ static MCInstPrinter *createSparcMCInstPrinter(const Target &T,
                                               const MCInstrInfo &MII,
                                               const MCRegisterInfo &MRI,
                                               const MCSubtargetInfo &STI) {
-  return new SparcInstPrinter(MAI, MII, MRI);
+  return new SparcInstPrinter(MAI, MII, MRI, STI);
 }
 
 extern "C" void LLVMInitializeSparcTargetMC() {
index 2fc6b7120f8f52ccbda89c9cf9bcbe4ba8851c9f..4d7acd5d4e53bccc29878d79208525d0b2a7d84e 100644 (file)
@@ -228,3 +228,9 @@ def : MnemonicAlias<"addccc", "addxcc">, Requires<[HasV9]>;
 
 def : MnemonicAlias<"subc", "subx">, Requires<[HasV9]>;
 def : MnemonicAlias<"subccc", "subxcc">, Requires<[HasV9]>;
+
+
+def : InstAlias<"fcmps $rs1, $rs2", (V9FCMPS FCC0, FPRegs:$rs1, FPRegs:$rs2)>;
+def : InstAlias<"fcmpd $rs1, $rs2", (V9FCMPD FCC0, DFPRegs:$rs1, DFPRegs:$rs2)>;
+def : InstAlias<"fcmpq $rs1, $rs2", (V9FCMPQ FCC0, QFPRegs:$rs1, QFPRegs:$rs2)>,
+                Requires<[HasHardQuad]>;
index 761ff15d04fc5171f707872348f768a6c9580a41..39ff325abcce3dfdfda4945ca0d715c98d76ddf2 100644 (file)
@@ -153,7 +153,6 @@ class F3_3c<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins,
 
   let op         = opVal;
   let op3        = op3val;
-  let rd         = 0;
 
   let Inst{13-5} = opfval;   // fp opcode
   let Inst{4-0}  = rs2;
index 690a5bf818471d31d76d8283acf9eb6cd926ef63..638e9d53582069cb77061ad945e35dc63c01a1d4 100644 (file)
@@ -864,7 +864,7 @@ def FDIVQ  : F3_3<2, 0b110100, 0b001001111,
 // This behavior is modeled with a forced noop after the instruction in
 // DelaySlotFiller.
 
-let Defs = [FCC0] in {
+let Defs = [FCC0], rd = 0, isCodeGenOnly = 1 in {
   def FCMPS  : F3_3c<2, 0b110101, 0b001010001,
                    (outs), (ins FPRegs:$rs1, FPRegs:$rs2),
                    "fcmps $rs1, $rs2",
@@ -1014,6 +1014,19 @@ let Predicates = [HasV9] in {
                    Requires<[HasHardQuad]>;
 }
 
+// Floating-point compare instruction with %fcc0-%fcc1
+def V9FCMPS  : F3_3c<2, 0b110101, 0b001010001,
+               (outs FCCRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
+               "fcmps $rd, $rs1, $rs2", []>;
+def V9FCMPD  : F3_3c<2, 0b110101, 0b001010010,
+                (outs FCCRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+                "fcmpd $rd, $rs1, $rs2", []>;
+def V9FCMPQ  : F3_3c<2, 0b110101, 0b001010011,
+                (outs FCCRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+                "fcmpq $rd, $rs1, $rs2", []>,
+                 Requires<[HasHardQuad]>;
+
+
 // POPCrr - This does a ctpop of a 64-bit register.  As such, we have to clear
 // the top 32-bits before using it.  To do this clearing, we use a SRLri X,0.
 let rs1 = 0 in
index b8a5017383d7184f61ba44e8e8793847ec77f9fe..b279da86a52eba03ca9b555353da5383239fa05b 100644 (file)
 # CHECK: fdivq %f0, %f4, %f8
 0x91 0xa0 0x09 0xe4
 
-# CHECK: fcmps %f0, %f4
+# CHECK: fcmps %fcc0, %f0, %f4
 0x81 0xa8 0x0a 0x24
 
-# CHECK: fcmpd %f0, %f4
+# CHECK: fcmpd %fcc0, %f0, %f4
 0x81 0xa8 0x0a 0x44
 
-# CHECK: fcmpq %f0, %f4
+# CHECK: fcmpq %fcc0, %f0, %f4
 0x81 0xa8 0x0a 0x64
 
 # CHECK: fxtos %f0, %f4
index 7435a0a5e833122e781f00e8c4b9dee54744a980..88a055d7fcc04fd31bb47cedf7647fca13ae66c1 100644 (file)
         fdivd %f0, %f4, %f8
         fdivq %f0, %f4, %f8
 
-        ! CHECK: fcmps %f0, %f4                  ! encoding: [0x81,0xa8,0x0a,0x24]
-        ! CHECK: fcmpd %f0, %f4                  ! encoding: [0x81,0xa8,0x0a,0x44]
-        ! CHECK: fcmpq %f0, %f4                  ! encoding: [0x81,0xa8,0x0a,0x64]
+        ! CHECK: fcmps %fcc0, %f0, %f4                  ! encoding: [0x81,0xa8,0x0a,0x24]
+        ! CHECK: fcmpd %fcc0, %f0, %f4                  ! encoding: [0x81,0xa8,0x0a,0x44]
+        ! CHECK: fcmpq %fcc0, %f0, %f4                  ! encoding: [0x81,0xa8,0x0a,0x64]
         fcmps %f0, %f4
         fcmpd %f0, %f4
         fcmpq %f0, %f4
 
+        ! CHECK: fcmps %fcc2, %f0, %f4                  ! encoding: [0x85,0xa8,0x0a,0x24]
+        ! CHECK: fcmpd %fcc2, %f0, %f4                  ! encoding: [0x85,0xa8,0x0a,0x44]
+        ! CHECK: fcmpq %fcc2, %f0, %f4                  ! encoding: [0x85,0xa8,0x0a,0x64]
+        fcmps %fcc2, %f0, %f4
+        fcmpd %fcc2, %f0, %f4
+        fcmpq %fcc2, %f0, %f4
+
         ! CHECK: fxtos %f0, %f4                  ! encoding: [0x89,0xa0,0x10,0x80]
         ! CHECK: fxtod %f0, %f4                  ! encoding: [0x89,0xa0,0x11,0x00]
         ! CHECK: fxtoq %f0, %f4                  ! encoding: [0x89,0xa0,0x11,0x80]
diff --git a/test/MC/Sparc/sparcv8-instructions.s b/test/MC/Sparc/sparcv8-instructions.s
new file mode 100644 (file)
index 0000000..27b3297
--- /dev/null
@@ -0,0 +1,8 @@
+! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s
+
+        ! CHECK: fcmps %f0, %f4           ! encoding: [0x81,0xa8,0x0a,0x24]
+        ! CHECK: fcmpd %f0, %f4           ! encoding: [0x81,0xa8,0x0a,0x44]
+        ! CHECK: fcmpq %f0, %f4           ! encoding: [0x81,0xa8,0x0a,0x64]
+        fcmps %f0, %f4
+        fcmpd %f0, %f4
+        fcmpq %f0, %f4