Add support for ext and ins.
authorAkira Hatanaka <ahatanak@gmail.com>
Wed, 17 Aug 2011 02:05:42 +0000 (02:05 +0000)
committerAkira Hatanaka <ahatanak@gmail.com>
Wed, 17 Aug 2011 02:05:42 +0000 (02:05 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@137804 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/Mips/MipsISelLowering.cpp
lib/Target/Mips/MipsISelLowering.h
lib/Target/Mips/MipsInstrFormats.td
lib/Target/Mips/MipsInstrInfo.td
test/CodeGen/Mips/extins.ll [new file with mode: 0644]

index 28ab854c38b55b7b70dc085b2e6b1df34dfb343e..d2a5541bc9497d77faf7b5a9fe5d0e3b4ae70c65 100644 (file)
 #include "llvm/Support/ErrorHandling.h"
 using namespace llvm;
 
+namespace {
+  // If I is a shifted mask, set the size (Size) and the first bit of the 
+  // mask (Pos), and return true.
+  bool IsShiftedMask(uint64_t I, unsigned SizeInBits, uint64_t &Pos,
+                     uint64_t &Size) {
+    assert(SizeInBits == 32 || SizeInBits == 64);
+    bool Is32Bits = (SizeInBits == 32);
+
+    if ((Is32Bits == 32 && !isShiftedMask_32(I)) ||
+        (!Is32Bits && !isShiftedMask_64(I)))
+      return false;
+
+    Size = Is32Bits ? CountPopulation_32(I) : CountPopulation_64(I);
+    Pos = Is32Bits ? CountTrailingZeros_32(I) : CountTrailingZeros_64(I);
+    return true;
+  }
+}
+
 const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const {
   switch (Opcode) {
   case MipsISD::JmpLink:           return "MipsISD::JmpLink";
@@ -62,6 +80,8 @@ const char *MipsTargetLowering::getTargetNodeName(unsigned Opcode) const {
   case MipsISD::WrapperPIC:        return "MipsISD::WrapperPIC";
   case MipsISD::DynAlloc:          return "MipsISD::DynAlloc";
   case MipsISD::Sync:              return "MipsISD::Sync";
+  case MipsISD::Ext:               return "MipsISD::Ext";
+  case MipsISD::Ins:               return "MipsISD::Ins";
   default:                         return NULL;
   }
 }
@@ -111,6 +131,8 @@ MipsTargetLowering(MipsTargetMachine &TM)
   setOperationAction(ISD::BRCOND,             MVT::Other, Custom);
   setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32,   Custom);
   setOperationAction(ISD::VASTART,            MVT::Other, Custom);
+  setOperationAction(ISD::AND,                MVT::i32,   Custom);
+  setOperationAction(ISD::OR,                 MVT::i32,   Custom);
 
   setOperationAction(ISD::SDIV, MVT::i32, Expand);
   setOperationAction(ISD::SREM, MVT::i32, Expand);
@@ -539,6 +561,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const
     case ISD::FRAMEADDR:          return LowerFRAMEADDR(Op, DAG);
     case ISD::MEMBARRIER:         return LowerMEMBARRIER(Op, DAG);
     case ISD::ATOMIC_FENCE:       return LowerATOMIC_FENCE(Op, DAG);
+    case ISD::AND:                return LowerAND(Op, DAG);
+    case ISD::OR:                 return LowerOR(Op, DAG);
   }
   return SDValue();
 }
@@ -1556,6 +1580,98 @@ SDValue MipsTargetLowering::LowerATOMIC_FENCE(SDValue Op,
                      DAG.getConstant(SType, MVT::i32));
 }
 
+SDValue MipsTargetLowering::LowerAND(SDValue Op, SelectionDAG& DAG) const {
+  // Pattern match EXT.
+  //  $dst = and ((sra or srl) $src , pos), (2**size - 1)
+  //  => ext $dst, $src, size, pos
+  if (!Subtarget->isMips32r2())
+    return Op;
+
+  SDValue ShiftRight = Op.getOperand(0), Mask = Op.getOperand(1);
+  
+  // Op's first operand must be a shift right.
+  if (ShiftRight.getOpcode() != ISD::SRA && ShiftRight.getOpcode() != ISD::SRL)
+    return Op;
+
+  // The second operand of the shift must be an immediate.
+  uint64_t Pos;
+  ConstantSDNode *CN;
+  if (!(CN = dyn_cast<ConstantSDNode>(ShiftRight.getOperand(1))))
+    return Op;
+  
+  Pos = CN->getZExtValue();
+
+  uint64_t SMPos, SMSize;
+  // Op's second operand must be a shifted mask.
+  if (!(CN = dyn_cast<ConstantSDNode>(Mask)) ||
+      !IsShiftedMask(CN->getZExtValue(), 32, SMPos, SMSize))
+    return Op;
+
+  // Return if the shifted mask does not start at bit 0 or the sum of its size
+  // and Pos exceeds the word's size.
+  if (SMPos != 0 || Pos + SMSize > 32)
+    return Op;
+
+  return DAG.getNode(MipsISD::Ext, Op.getDebugLoc(), MVT::i32,
+                     ShiftRight.getOperand(0),
+                     DAG.getConstant(SMSize, MVT::i32),
+                     DAG.getConstant(Pos, MVT::i32));
+}
+
+SDValue MipsTargetLowering::LowerOR(SDValue Op, SelectionDAG& DAG) const {
+  // Pattern match INS.
+  //  $dst = or (and $src1 , mask0), (and (shl $src, pos), mask1),
+  //  where mask1 = (2**size - 1) << pos, mask0 = ~mask1 
+  //  => ins $dst, $src, size, pos
+  if (!Subtarget->isMips32r2())
+    return Op;
+
+  SDValue And0 = Op.getOperand(0), And1 = Op.getOperand(1);
+  uint64_t SMPos0, SMSize0, SMPos1, SMSize1;
+  ConstantSDNode *CN;
+
+  // See if Op's first operand matches (and $src1 , mask0).
+  if (And0.getOpcode() != ISD::AND)
+    return Op;
+
+  if (!(CN = dyn_cast<ConstantSDNode>(And0.getOperand(1))) ||
+      !IsShiftedMask(~CN->getZExtValue(), 32, SMPos0, SMSize0))
+    return Op;
+
+  // See if Op's second operand matches (and (shl $src, pos), mask1).
+  if (And1.getOpcode() != ISD::AND)
+    return Op;
+  
+  if (!(CN = dyn_cast<ConstantSDNode>(And1.getOperand(1))) ||
+      !IsShiftedMask(CN->getZExtValue(), CN->getValueSizeInBits(0), SMPos1,
+                     SMSize1))
+    return Op;
+
+  // The shift masks must have the same position and size.
+  if (SMPos0 != SMPos1 || SMSize0 != SMSize1)
+    return Op;
+
+  SDValue Shl = And1.getOperand(0);
+  if (Shl.getOpcode() != ISD::SHL)
+    return Op;
+
+  if (!(CN = dyn_cast<ConstantSDNode>(Shl.getOperand(1))))
+    return Op;
+
+  unsigned Shamt = CN->getZExtValue();
+
+  // Return if the shift amount and the first bit position of mask are not the
+  // same.  
+  if (Shamt != SMPos0)
+    return Op;
+  
+  return DAG.getNode(MipsISD::Ins, Op.getDebugLoc(), MVT::i32,
+                     Shl.getOperand(0),
+                     DAG.getConstant(SMSize0, MVT::i32),
+                     DAG.getConstant(SMPos0, MVT::i32),
+                     And0.getOperand(0));  
+}
+
 //===----------------------------------------------------------------------===//
 //                      Calling Convention Implementation
 //===----------------------------------------------------------------------===//
index 2d8661987a32844594ac340dfac2bfdb889014cd..7e4c1f400bd8505c6cc157712d6febab4702fef7 100644 (file)
@@ -83,7 +83,10 @@ namespace llvm {
 
       DynAlloc,
 
-      Sync
+      Sync,
+
+      Ext,
+      Ins
     };
   }
 
@@ -134,6 +137,8 @@ namespace llvm {
     SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) const;
     SDValue LowerMEMBARRIER(SDValue Op, SelectionDAG& DAG) const;
     SDValue LowerATOMIC_FENCE(SDValue Op, SelectionDAG& DAG) const;
+    SDValue LowerAND(SDValue Op, SelectionDAG& DAG) const;
+    SDValue LowerOR(SDValue Op, SelectionDAG& DAG) const;
 
     virtual SDValue
       LowerFormalArguments(SDValue Chain,
index 9f55fb38b959c23f908593e52deae3ae862135a2..fd6422048d9ad35b5aae47f33bf898b2bb41f888 100644 (file)
@@ -102,6 +102,28 @@ class FJ<bits<6> op, dag outs, dag ins, string asmstr, list<dag> pattern,
   let Inst{25-0} = addr;
 }
 
+// Ext and Ins
+class ExtIns<bits<6> _funct, string instr_asm, dag Outs, dag Ins,
+             list<dag> pattern, InstrItinClass itin>:
+  MipsInst<Outs, Ins, !strconcat(instr_asm, "\t$dst, $src, $pos, $size"),
+           pattern, itin>
+{
+  bits<5>  rt;
+  bits<5>  rs;
+  bits<5>  sz;
+  bits<5>  pos;
+  bits<6>  funct;
+
+  let opcode = 0x1f;
+  let funct  = _funct;
+
+  let Inst{25-21} = rs;
+  let Inst{20-16} = rt;
+  let Inst{15-11} = sz;
+  let Inst{10-6}  = pos;
+  let Inst{5-0}   = funct;
+}
+
 //===----------------------------------------------------------------------===//
 //
 //  FLOATING POINT INSTRUCTION FORMATS
index 0680c36b6f95b7cee8a6f34c792caf8e045ab402..a30761dbbabedf5475c14720ff8c97abc27884ed 100644 (file)
@@ -43,6 +43,12 @@ def SDT_MipsDynAlloc    : SDTypeProfile<1, 1, [SDTCisVT<0, i32>,
                                                SDTCisVT<1, iPTR>]>;
 def SDT_Sync             : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>;
 
+def SDT_Ext : SDTypeProfile<1, 3, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>,
+                                   SDTCisInt<2>, SDTCisSameAs<2, 3>]>;
+def SDT_Ins : SDTypeProfile<1, 4, [SDTCisVT<0, i32>, SDTCisSameAs<0, 1>,
+                                   SDTCisInt<2>, SDTCisSameAs<2, 3>,
+                                   SDTCisSameAs<0, 4>]>;
+
 // Call
 def MipsJmpLink : SDNode<"MipsISD::JmpLink",SDT_MipsJmpLink,
                          [SDNPHasChain, SDNPOutGlue, SDNPOptInGlue,
@@ -109,6 +115,9 @@ def MipsDynAlloc  : SDNode<"MipsISD::DynAlloc", SDT_MipsDynAlloc,
 
 def MipsSync : SDNode<"MipsISD::Sync", SDT_Sync, [SDNPHasChain]>;
 
+def MipsExt :  SDNode<"MipsISD::Ext", SDT_Ext>;
+def MipsIns :  SDNode<"MipsISD::Ins", SDT_Ins>;
+
 //===----------------------------------------------------------------------===//
 // Mips Instruction Predicate Definitions.
 //===----------------------------------------------------------------------===//
@@ -661,6 +670,23 @@ def MUL   : ArithR<0x1c, 0x02, "mul", mul, IIImul, 1>, Requires<[IsMips32]>;
 
 def RDHWR : ReadHardware;
 
+let Predicates = [IsMips32r2] in {
+  def Ext : ExtIns<0b000000, "ext", (outs CPURegs:$dst),
+                   (ins CPURegs:$src, uimm16:$size, uimm16:$pos),
+                   [(set CPURegs:$dst,
+                     (MipsExt CPURegs:$src, immZExt5:$size, immZExt5:$pos))],
+                   NoItinerary>;
+  let Constraints = "$src1 = $dst" in
+  def Ins : ExtIns<0b000100, "ins",
+                   (outs CPURegs:$dst),
+                   (ins CPURegs:$src, uimm16:$size, uimm16:$pos,
+                    CPURegs:$src1),
+                   [(set CPURegs:$dst,
+                     (MipsIns CPURegs:$src, immZExt5:$size, immZExt5:$pos,
+                      CPURegs:$src1))],
+                   NoItinerary>;
+}
+
 //===----------------------------------------------------------------------===//
 //  Arbitrary patterns that map to one or more instructions
 //===----------------------------------------------------------------------===//
diff --git a/test/CodeGen/Mips/extins.ll b/test/CodeGen/Mips/extins.ll
new file mode 100644 (file)
index 0000000..69f53e5
--- /dev/null
@@ -0,0 +1,21 @@
+; RUN: llc -march=mips -mcpu=4ke < %s | FileCheck %s
+
+define i32 @ext0_5_9(i32 %s, i32 %pos, i32 %sz) nounwind readnone {
+entry:
+; CHECK: ext ${{[0-9]+}}, $4, 5, 9
+  %shr = lshr i32 %s, 5
+  %and = and i32 %shr, 511
+  ret i32 %and
+}
+
+define void @ins2_5_9(i32 %s, i32* nocapture %d) nounwind {
+entry:
+; CHECK: ins ${{[0-9]+}}, $4, 5, 9
+  %and = shl i32 %s, 5
+  %shl = and i32 %and, 16352
+  %tmp3 = load i32* %d, align 4
+  %and5 = and i32 %tmp3, -16353
+  %or = or i32 %and5, %shl
+  store i32 %or, i32* %d, align 4
+  ret void
+}