Add support for the Sparc implementation-defined "ASR" registers.
authorJames Y Knight <jyknight@google.com>
Mon, 18 May 2015 16:29:48 +0000 (16:29 +0000)
committerJames Y Knight <jyknight@google.com>
Mon, 18 May 2015 16:29:48 +0000 (16:29 +0000)
(Note that register "Y" is essentially just ASR0).

Also added some test cases for divide and multiply, which had none before.

Differential Revision: http://reviews.llvm.org/D8670

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@237580 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
lib/Target/Sparc/SparcISelDAGToDAG.cpp
lib/Target/Sparc/SparcInstrInfo.td
lib/Target/Sparc/SparcRegisterInfo.td
test/CodeGen/SPARC/basictest.ll
test/MC/Disassembler/Sparc/sparc.txt
test/MC/Sparc/sparc-special-registers.s [new file with mode: 0644]

index 92311026c8c87db0f8a43ffeb6ea3b41ba604646..de1066794306999bd5bd5879b9402f20b793a76a 100644 (file)
@@ -124,6 +124,15 @@ public:
     Sparc::Q8,  Sparc::Q9,  Sparc::Q10, Sparc::Q11,
     Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 };
 
+  static unsigned ASRRegs[32] = {
+    SP::Y,     SP::ASR1,  SP::ASR2,  SP::ASR3,
+    SP::ASR4,  SP::ASR5,  SP::ASR6, SP::ASR7,
+    SP::ASR8,  SP::ASR9,  SP::ASR10, SP::ASR11,
+    SP::ASR12, SP::ASR13, SP::ASR14, SP::ASR15,
+    SP::ASR16, SP::ASR17, SP::ASR18, SP::ASR19,
+    SP::ASR20, SP::ASR21, SP::ASR22, SP::ASR23,
+    SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27,
+    SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31};
 
 /// SparcOperand - Instances of this class represent a parsed Sparc machine
 /// instruction.
@@ -136,7 +145,7 @@ public:
     rk_DoubleReg,
     rk_QuadReg,
     rk_CCReg,
-    rk_Y
+    rk_ASRReg
   };
 private:
   enum KindTy {
@@ -661,9 +670,6 @@ SparcAsmParser::parseSparcAsmOperand(std::unique_ptr<SparcOperand> &Op,
       default:
         Op = SparcOperand::CreateReg(RegNo, RegKind, S, E);
         break;
-      case Sparc::Y:
-        Op = SparcOperand::CreateToken("%y", S);
-        break;
 
       case Sparc::ICC:
         if (name == "xcc")
@@ -753,7 +759,15 @@ bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
 
     if (name.equals("y")) {
       RegNo = Sparc::Y;
-      RegKind = SparcOperand::rk_Y;
+      RegKind = SparcOperand::rk_ASRReg;
+      return true;
+    }
+
+    if (name.substr(0, 3).equals_lower("asr")
+        && !name.substr(3).getAsInteger(10, intVal)
+        && intVal > 0 && intVal < 32) {
+      RegNo = ASRRegs[intVal];
+      RegKind = SparcOperand::rk_ASRReg;
       return true;
     }
 
index 4ac34b2b90dfc2fb587694e1297430be15fa0e76..b3a60381a83507ade650e81bd1792225783d934c 100644 (file)
@@ -107,6 +107,16 @@ static const unsigned QFPRegDecoderTable[] = {
 static const unsigned FCCRegDecoderTable[] = {
   SP::FCC0, SP::FCC1, SP::FCC2, SP::FCC3 };
 
+static const unsigned ASRRegDecoderTable[] = {
+  SP::Y,     SP::ASR1,  SP::ASR2,  SP::ASR3,
+  SP::ASR4,  SP::ASR5,  SP::ASR6,  SP::ASR7,
+  SP::ASR8,  SP::ASR9,  SP::ASR10, SP::ASR11,
+  SP::ASR12, SP::ASR13, SP::ASR14, SP::ASR15,
+  SP::ASR16, SP::ASR17, SP::ASR18, SP::ASR19,
+  SP::ASR20, SP::ASR21, SP::ASR22, SP::ASR23,
+  SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27,
+  SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31};
+
 static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst,
                                                unsigned RegNo,
                                                uint64_t Address,
@@ -177,6 +187,15 @@ static DecodeStatus DecodeFCCRegsRegisterClass(MCInst &Inst, unsigned RegNo,
   return MCDisassembler::Success;
 }
 
+static DecodeStatus DecodeASRRegsRegisterClass(MCInst &Inst, unsigned RegNo,
+                                               uint64_t Address,
+                                               const void *Decoder) {
+  if (RegNo > 31)
+    return MCDisassembler::Fail;
+  Inst.addOperand(MCOperand::createReg(ASRRegDecoderTable[RegNo]));
+  return MCDisassembler::Success;
+}
+
 
 static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address,
                                   const void *Decoder);
index 53eb91a8812ceeb67eb9bccbbad2a437ed4de22e..9c594a9f0f653d884aa9d580af93d7ab0f779a5f 100644 (file)
@@ -168,8 +168,10 @@ SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
     } else {
       TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
     }
-    TopPart = SDValue(CurDAG->getMachineNode(SP::WRYrr, dl, MVT::Glue, TopPart,
-                                     CurDAG->getRegister(SP::G0, MVT::i32)), 0);
+    TopPart = SDValue(CurDAG->getMachineNode(SP::WRASRrr, dl, MVT::i32,
+                                 TopPart,
+                                 CurDAG->getRegister(SP::G0, MVT::i32)), 0);
+    TopPart = CurDAG->getCopyToReg(TopPart, dl, SP::Y, TopPart, SDValue()).getValue(1);
 
     // FIXME: Handle div by immediate.
     unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr;
@@ -185,7 +187,9 @@ SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
     SDNode *Mul = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::Glue,
                                          MulLHS, MulRHS);
     // The high part is in the Y register.
-    return CurDAG->SelectNodeTo(N, SP::RDY, MVT::i32, SDValue(Mul, 1));
+    return CurDAG->SelectNodeTo(N, SP::RDASR, MVT::i32,
+                                CurDAG->getRegister(SP::Y, MVT::i32),
+                                SDValue(Mul, 1));
   }
   }
 
index c877758cfff9355002a74dfeffa16eef4484f4f2..ea17174e11a3a5d848f3ed32e9afa5a3e6c61396 100644 (file)
@@ -705,20 +705,19 @@ let Uses = [O6],
 }
 
 // Section B.28 - Read State Register Instructions
-let Uses = [Y], rs1 = 0, rs2 = 0 in
-  def RDY : F3_1<2, 0b101000,
-                 (outs IntRegs:$dst), (ins),
-                 "rd %y, $dst", []>;
+let rs2 = 0 in
+  def RDASR : F3_1<2, 0b101000,
+                 (outs IntRegs:$rd), (ins ASRRegs:$rs1),
+                 "rd $rs1, $rd", []>;
 
 // Section B.29 - Write State Register Instructions
-let Defs = [Y], rd = 0 in {
-  def WRYrr : F3_1<2, 0b110000,
-                   (outs), (ins IntRegs:$rs1, IntRegs:$rs2),
-                   "wr $rs1, $rs2, %y", []>;
-  def WRYri : F3_2<2, 0b110000,
-                   (outs), (ins IntRegs:$rs1, simm13Op:$simm13),
-                   "wr $rs1, $simm13, %y", []>;
-}
+def WRASRrr : F3_1<2, 0b110000,
+                 (outs ASRRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
+                 "wr $rs1, $rs2, $rd", []>;
+def WRASRri : F3_2<2, 0b110000,
+                 (outs ASRRegs:$rd), (ins IntRegs:$rs1, simm13Op:$simm13),
+                 "wr $rs1, $simm13, $rd", []>;
+
 // Convert Integer to Floating-point Instructions, p. 141
 def FITOS : F3_3u<2, 0b110100, 0b011000100,
                  (outs FPRegs:$rd), (ins FPRegs:$rs2),
index 2cadff1ef7bb5d18aa9b2a52ec65bc16c69c0c5a..0c12399e360e45b4130af5d5e7a01b7c501c662c 100644 (file)
@@ -56,6 +56,38 @@ foreach I = 0-3 in
 
 // Y register
 def Y : SparcCtrlReg<0, "Y">, DwarfRegNum<[64]>;
+// Ancillary state registers (implementation defined)
+def ASR1 : SparcCtrlReg<1, "ASR1">;
+def ASR2 : SparcCtrlReg<2, "ASR2">;
+def ASR3 : SparcCtrlReg<3, "ASR3">;
+def ASR4 : SparcCtrlReg<4, "ASR4">;
+def ASR5 : SparcCtrlReg<5, "ASR5">;
+def ASR6 : SparcCtrlReg<6, "ASR6">;
+def ASR7 : SparcCtrlReg<7, "ASR7">;
+def ASR8 : SparcCtrlReg<8, "ASR8">;
+def ASR9 : SparcCtrlReg<9, "ASR9">;
+def ASR10 : SparcCtrlReg<10, "ASR10">;
+def ASR11 : SparcCtrlReg<11, "ASR11">;
+def ASR12 : SparcCtrlReg<12, "ASR12">;
+def ASR13 : SparcCtrlReg<13, "ASR13">;
+def ASR14 : SparcCtrlReg<14, "ASR14">;
+def ASR15 : SparcCtrlReg<15, "ASR15">;
+def ASR16 : SparcCtrlReg<16, "ASR16">;
+def ASR17 : SparcCtrlReg<17, "ASR17">;
+def ASR18 : SparcCtrlReg<18, "ASR18">;
+def ASR19 : SparcCtrlReg<19, "ASR19">;
+def ASR20 : SparcCtrlReg<20, "ASR20">;
+def ASR21 : SparcCtrlReg<21, "ASR21">;
+def ASR22 : SparcCtrlReg<22, "ASR22">;
+def ASR23 : SparcCtrlReg<23, "ASR23">;
+def ASR24 : SparcCtrlReg<24, "ASR24">;
+def ASR25 : SparcCtrlReg<25, "ASR25">;
+def ASR26 : SparcCtrlReg<26, "ASR26">;
+def ASR27 : SparcCtrlReg<27, "ASR27">;
+def ASR28 : SparcCtrlReg<28, "ASR28">;
+def ASR29 : SparcCtrlReg<29, "ASR29">;
+def ASR30 : SparcCtrlReg<30, "ASR30">;
+def ASR31 : SparcCtrlReg<31, "ASR31">;
 
 // Integer registers
 def G0 : Ri< 0, "G0">, DwarfRegNum<[0]>;
@@ -209,3 +241,7 @@ def QFPRegs : RegisterClass<"SP", [f128], 128, (sequence "Q%u", 0, 15)>;
 
 // Floating point control register classes.
 def FCCRegs : RegisterClass<"SP", [i1], 1, (sequence "FCC%u", 0, 3)>;
+
+// Ancillary state registers
+def ASRRegs : RegisterClass<"SP", [i32], 32,
+                            (add Y, (sequence "ASR%u", 1, 31))>;
index 68f7c367203455f15f695b78e4f5cd26816547c0..7b540074a35f926b2c25ebd217e2f6c2f5cdd684 100644 (file)
@@ -36,3 +36,51 @@ entry:
   ret i32 0
 }
 
+; CHECK-LABEL: signed_divide:
+; CHECK: sra %o0, 31, %o2
+; CHECK: wr %o2, %g0, %y
+; CHECK: sdiv %o0, %o1, %o0
+define i32 @signed_divide(i32 %a, i32 %b) {
+  %r = sdiv i32 %a, %b
+  ret i32 %r
+}
+
+; CHECK-LABEL: unsigned_divide:
+; CHECK: wr %g0, %g0, %y
+; CHECK: udiv %o0, %o1, %o0
+define i32 @unsigned_divide(i32 %a, i32 %b) {
+  %r = udiv i32 %a, %b
+  ret i32 %r
+}
+
+; CHECK-LABEL: multiply_32x32:
+; CHECK: smul %o0, %o1, %o0
+define i32 @multiply_32x32(i32 %a, i32 %b) {
+  %r = mul i32 %a, %b
+  ret i32 %r
+}
+
+; CHECK-LABEL: signed_multiply_32x32_64:
+; CHECK: smul %o0, %o1, %o1
+; CHECK: rd %y, %o0
+define i64 @signed_multiply_32x32_64(i32 %a, i32 %b) {
+  %xa = sext i32 %a to i64
+  %xb = sext i32 %b to i64
+  %r = mul i64 %xa, %xb
+  ret i64 %r
+}
+
+; CHECK-LABEL: unsigned_multiply_32x32_64:
+; CHECK: umul %o0, %o1, %o2
+; CHECK: rd %y, %o2
+;FIXME: the smul in the output is totally redundant and should not there.
+; CHECK: smul %o0, %o1, %o1
+; CHECK: retl
+; CHECK: mov      %o2, %o0
+define i64 @unsigned_multiply_32x32_64(i32 %a, i32 %b) {
+  %xa = zext i32 %a to i64
+  %xb = zext i32 %b to i64
+  %r = mul i64 %xa, %xb
+  ret i64 %r
+}
+
index a9420246361fb22dac5d2a455132a2ac50199984..038aef53d51deec43442724a17d553623efd5e2c 100644 (file)
 
 # CHECK:  rett %i7+8
 0x81 0xcf 0xe0 0x08
+
+# CHECK: rd %y, %i0
+0xb1 0x40 0x00 0x00
+
+# CHECK: rd %asr1, %i0
+0xb1 0x40 0x40 0x00
+
+# CHECK: wr %i0, 5, %y
+0x81 0x86 0x20 0x05
+
+# CHECK: wr %i0, %i1, %asr15
+0x9f 0x86 0x00 0x19
+
+# CHECK: stbar
+0x81 0x43 0xc0 0x00
diff --git a/test/MC/Sparc/sparc-special-registers.s b/test/MC/Sparc/sparc-special-registers.s
new file mode 100644 (file)
index 0000000..74e4fc6
--- /dev/null
@@ -0,0 +1,17 @@
+! RUN: llvm-mc %s -arch=sparc -show-encoding | FileCheck %s
+! RUN: llvm-mc %s -arch=sparcv9 -show-encoding | FileCheck %s
+
+        ! CHECK: rd %y, %i0            ! encoding: [0xb1,0x40,0x00,0x00]
+        rd %y, %i0
+
+        ! CHECK: rd %asr1, %i0         ! encoding: [0xb1,0x40,0x40,0x00]
+        rd %asr1, %i0
+
+        ! CHECK: wr %i0, 5, %y         ! encoding: [0x81,0x86,0x20,0x05]
+        wr %i0, 5, %y
+
+        ! CHECK: wr %i0, %i1, %asr15   ! encoding: [0x9f,0x86,0x00,0x19]
+        wr %i0, %i1, %asr15
+
+        ! CHECK: rd %asr15, %g0        ! encoding: [0x81,0x43,0xc0,0x00]
+        rd %asr15, %g0