[llvm-commits] CVS: llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp PPC64ISelPattern.cpp PowerPCInstrInfo.td

Nate Begeman natebegeman at mac.com
Tue Apr 5 17:25:38 PDT 2005



Changes in directory llvm/lib/Target/PowerPC:

PPC32ISelPattern.cpp updated: 1.46 -> 1.47
PPC64ISelPattern.cpp updated: 1.2 -> 1.3
PowerPCInstrInfo.td updated: 1.54 -> 1.55
---
Log message:

Add support for MULHS and MULHU nodes
Have LegalizeDAG handle SREM and UREM for us
Codegen SDIV and UDIV by constant as a multiply by magic constant instead
of integer divide, which is very slow.


---
Diffs of the changes:  (+194 -21)

 PPC32ISelPattern.cpp |  212 ++++++++++++++++++++++++++++++++++++++++++++++-----
 PPC64ISelPattern.cpp |    1 
 PowerPCInstrInfo.td  |    2 
 3 files changed, 194 insertions(+), 21 deletions(-)


Index: llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp
diff -u llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp:1.46 llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp:1.47
--- llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp:1.46	Mon Apr  4 23:32:16 2005
+++ llvm/lib/Target/PowerPC/PPC32ISelPattern.cpp	Tue Apr  5 19:25:27 2005
@@ -8,6 +8,8 @@
 //===----------------------------------------------------------------------===//
 //
 // This file defines a pattern matching instruction selector for 32 bit PowerPC.
+// Magic number generation for integer divide from the PowerPC Compiler Writer's
+// Guide, section 3.2.3.5
 //
 //===----------------------------------------------------------------------===//
 
@@ -54,6 +56,10 @@
       // PowerPC has an i16 but no i8 (or i1) SEXTLOAD
       setOperationAction(ISD::SEXTLOAD, MVT::i1, Expand);
       setOperationAction(ISD::SEXTLOAD, MVT::i8, Expand);
+      
+      // PowerPC has no SREM/UREM instructions
+      setOperationAction(ISD::SREM, MVT::i32, Expand);
+      setOperationAction(ISD::UREM, MVT::i32, Expand);
 
       setShiftAmountFlavor(Extend);   // shl X, 32 == 0
       addLegalFPImmediate(+0.0); // Necessary for FSEL
@@ -439,9 +445,10 @@
 /// SelectionDAG operations.
 //===--------------------------------------------------------------------===//
 class ISel : public SelectionDAGISel {
-  
-  /// Comment Here.
   PPC32TargetLowering PPC32Lowering;
+  SelectionDAG *ISelDAG;  // Hack to support us having a dag->dag transform
+                          // for sdiv and udiv until it is put into the future
+                          // dag combiner.
   
   /// ExprMap - As shared expressions are codegen'd, we keep track of which
   /// vreg the value is produced in, so we only emit one copy of each compiled
@@ -452,8 +459,8 @@
   bool GlobalBaseInitialized;
   
 public:
-  ISel(TargetMachine &TM) : SelectionDAGISel(PPC32Lowering), PPC32Lowering(TM) 
-  {}
+  ISel(TargetMachine &TM) : SelectionDAGISel(PPC32Lowering), PPC32Lowering(TM),
+                            ISelDAG(0) {}
   
   /// runOnFunction - Override this function in order to reset our per-function
   /// variables.
@@ -468,11 +475,17 @@
   virtual void InstructionSelectBasicBlock(SelectionDAG &DAG) {
     DEBUG(BB->dump());
     // Codegen the basic block.
+    ISelDAG = &DAG;
     Select(DAG.getRoot());
     
     // Clear state used for selection.
     ExprMap.clear();
+    ISelDAG = 0;
   }
+
+  // dag -> dag expanders for integer divide by constant
+  SDOperand BuildSDIVSequence(SDOperand N);
+  SDOperand BuildUDIVSequence(SDOperand N);
   
   unsigned getGlobalBaseReg();
   unsigned getConstDouble(double floatVal, unsigned Result);
@@ -504,7 +517,8 @@
 /// of 1 indicates that the constant may be used in normal immediate form.  A
 /// return value of 2 indicates that the constant may be used in shifted
 /// immediate form.  A return value of 3 indicates that log base 2 of the
-/// constant may be used.
+/// constant may be used.  A return value of 4 indicates that the constant is
+/// suitable for conversion into a magic number for integer division.
 ///
 static unsigned getImmediateForOpcode(SDOperand N, unsigned Opcode,
                                       unsigned& Imm, bool U = false) {
@@ -534,6 +548,10 @@
     break;
   case ISD::SDIV:
     if ((Imm = ExactLog2(v))) { return 3; }
+    if (v <= -2 || v >= 2) { return 4; }
+    break;
+  case ISD::UDIV:
+    if (v != 0) { return 4; }
     break;
   }
   return 0;
@@ -574,6 +592,156 @@
   }
   return 0;
 }
+
+// Structure used to return the necessary information to codegen an SDIV as 
+// a multiply.
+struct ms {
+  int m; // magic number
+  int s; // shift amount
+};
+
+struct mu {
+  unsigned int m; // magic number
+  int a;          // add indicator
+  int s;          // shift amount
+};
+
+/// magic - calculate the magic numbers required to codegen an integer sdiv as
+/// a sequence of multiply and shifts.  Requires that the divisor not be 0, 1, 
+/// or -1.
+static struct ms magic(int d) {
+  int p;
+  unsigned int ad, anc, delta, q1, r1, q2, r2, t;
+  const unsigned int two31 = 2147483648U; // 2^31
+  struct ms mag;
+  
+  ad = abs(d);
+  t = two31 + ((unsigned int)d >> 31);
+  anc = t - 1 - t%ad;   // absolute value of nc
+  p = 31;               // initialize p
+  q1 = two31/anc;       // initialize q1 = 2p/abs(nc)
+  r1 = two31 - q1*anc;  // initialize r1 = rem(2p,abs(nc))
+  q2 = two31/ad;        // initialize q2 = 2p/abs(d)
+  r2 = two31 - q2*ad;   // initialize r2 = rem(2p,abs(d))
+  do {
+    p = p + 1;
+    q1 = 2*q1;        // update q1 = 2p/abs(nc)
+    r1 = 2*r1;        // update r1 = rem(2p/abs(nc))
+    if (r1 >= anc) {  // must be unsigned comparison
+      q1 = q1 + 1;
+      r1 = r1 - anc;
+    }
+    q2 = 2*q2;        // update q2 = 2p/abs(d)
+    r2 = 2*r2;        // update r2 = rem(2p/abs(d))
+    if (r2 >= ad) {   // must be unsigned comparison
+      q2 = q2 + 1;
+      r2 = r2 - ad;
+    }
+    delta = ad - r2;
+  } while (q1 < delta || (q1 == delta && r1 == 0));
+
+  mag.m = q2 + 1;
+  if (d < 0) mag.m = -mag.m; // resulting magic number
+  mag.s = p - 32;            // resulting shift
+  return mag;
+}
+
+/// magicu - calculate the magic numbers required to codegen an integer udiv as
+/// a sequence of multiply, add and shifts.  Requires that the divisor not be 0.
+static struct mu magicu(unsigned d)
+{
+  int p;
+  unsigned int nc, delta, q1, r1, q2, r2;
+  struct mu magu;
+  magu.a = 0;               // initialize "add" indicator
+  nc = - 1 - (-d)%d;
+  p = 31;                   // initialize p
+  q1 = 0x80000000/nc;       // initialize q1 = 2p/nc
+  r1 = 0x80000000 - q1*nc;  // initialize r1 = rem(2p,nc)
+  q2 = 0x7FFFFFFF/d;        // initialize q2 = (2p-1)/d
+  r2 = 0x7FFFFFFF - q2*d;   // initialize r2 = rem((2p-1),d)
+  do {
+    p = p + 1;
+    if (r1 >= nc - r1 ) {
+      q1 = 2*q1 + 1;  // update q1
+      r1 = 2*r1 - nc; // update r1
+    }
+    else {
+      q1 = 2*q1; // update q1
+      r1 = 2*r1; // update r1
+    }
+    if (r2 + 1 >= d - r2) {
+      if (q2 >= 0x7FFFFFFF) magu.a = 1;
+      q2 = 2*q2 + 1;     // update q2
+      r2 = 2*r2 + 1 - d; // update r2
+    }
+    else {
+      if (q2 >= 0x80000000) magu.a = 1;
+      q2 = 2*q2;     // update q2
+      r2 = 2*r2 + 1; // update r2
+    }
+    delta = d - 1 - r2;
+  } while (p < 64 && (q1 < delta || (q1 == delta && r1 == 0)));
+  magu.m = q2 + 1; // resulting magic number
+  magu.s = p - 32;  // resulting shift
+  return magu;
+}
+}
+
+/// BuildSDIVSequence - Given an ISD::SDIV node expressing a divide by constant,
+/// return a DAG expression to select that will generate the same value by
+/// multiplying by a magic number.  See:
+/// <http://the.wall.riscom.net/books/proc/ppc/cwg/code2.html>
+SDOperand ISel::BuildSDIVSequence(SDOperand N) {
+  int d = (int)cast<ConstantSDNode>(N.getOperand(1))->getSignExtended();
+  ms magics = magic(d);
+  // Multiply the numerator (operand 0) by the magic value
+  SDOperand Q = ISelDAG->getNode(ISD::MULHS, MVT::i32, N.getOperand(0), 
+                                 ISelDAG->getConstant(magics.m, MVT::i32));
+  // If d > 0 and m < 0, add the numerator
+  if (d > 0 && magics.m < 0)
+    Q = ISelDAG->getNode(ISD::ADD, MVT::i32, Q, N.getOperand(0));
+  // If d < 0 and m > 0, subtract the numerator.
+  if (d < 0 && magics.m > 0)
+    Q = ISelDAG->getNode(ISD::SUB, MVT::i32, Q, N.getOperand(0));
+  // Shift right algebraic if shift value is nonzero
+  if (magics.s > 0)
+    Q = ISelDAG->getNode(ISD::SRA, MVT::i32, Q, 
+                         ISelDAG->getConstant(magics.s, MVT::i32));
+  // Extract the sign bit and add it to the quotient
+  SDOperand T = 
+    ISelDAG->getNode(ISD::SRL, MVT::i32, Q, ISelDAG->getConstant(31, MVT::i32));
+  Q = ISelDAG->getNode(ISD::ADD, MVT::i32, Q, T);
+  // Compute the remainder
+  T = ISelDAG->getNode(ISD::MUL, MVT::i32, Q, N.getOperand(1));
+  return ISelDAG->getNode(ISD::SUB, MVT::i32, N.getOperand(0), T);
+}
+
+/// BuildUDIVSequence - Given an ISD::UDIV node expressing a divide by constant,
+/// return a DAG expression to select that will generate the same value by
+/// multiplying by a magic number.  See:
+/// <http://the.wall.riscom.net/books/proc/ppc/cwg/code2.html>
+SDOperand ISel::BuildUDIVSequence(SDOperand N) {
+  unsigned d = 
+    (unsigned)cast<ConstantSDNode>(N.getOperand(1))->getSignExtended();
+  mu magics = magicu(d);
+  // Multiply the numerator (operand 0) by the magic value
+  SDOperand Q = ISelDAG->getNode(ISD::MULHU, MVT::i32, N.getOperand(0), 
+                                 ISelDAG->getConstant(magics.m, MVT::i32));
+  if (magics.a == 0) {
+    Q = ISelDAG->getNode(ISD::SRL, MVT::i32, Q, 
+                         ISelDAG->getConstant(magics.s, MVT::i32));
+  } else {
+    SDOperand NPQ = ISelDAG->getNode(ISD::SUB, MVT::i32, N.getOperand(0), Q);
+    NPQ = ISelDAG->getNode(ISD::SRL, MVT::i32, NPQ, 
+                           ISelDAG->getConstant(1, MVT::i32));
+    NPQ = ISelDAG->getNode(ISD::ADD, MVT::i32, NPQ, Q);
+    Q = ISelDAG->getNode(ISD::SRL, MVT::i32, NPQ, 
+                           ISelDAG->getConstant(magics.s-1, MVT::i32));
+  }
+  // Compute the remainder
+  SDOperand T = ISelDAG->getNode(ISD::MUL, MVT::i32, Q, N.getOperand(1));
+  return ISelDAG->getNode(ISD::SUB, MVT::i32, N.getOperand(0), T);
 }
 
 /// getGlobalBaseReg - Output the instructions required to put the
@@ -1091,7 +1259,6 @@
     MVT::ValueType TypeBeingLoaded = (ISD::LOAD == opcode) ?
       Node->getValueType(0) : cast<MVTSDNode>(Node)->getExtraValueType();
     bool sext = (ISD::SEXTLOAD == opcode);
-    bool byte = (MVT::i8 == TypeBeingLoaded);
     
     // Make sure we generate both values.
     if (Result != 1)
@@ -1413,14 +1580,32 @@
     }
     return Result;
 
+  case ISD::MULHS:
+  case ISD::MULHU:
+    Tmp1 = SelectExpr(N.getOperand(0));
+    Tmp2 = SelectExpr(N.getOperand(1));
+    Opc = (ISD::MULHU == opcode) ? PPC::MULHWU : PPC::MULHW;
+    BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
+    return Result;
+
   case ISD::SDIV:
   case ISD::UDIV:
-    if (3 == getImmediateForOpcode(N.getOperand(1), opcode, Tmp3)) {
+    switch (getImmediateForOpcode(N.getOperand(1), opcode, Tmp3)) {
+    default: break;
+    // If this is an sdiv by a power of two, we can use an srawi/addze pair.
+    case 3:
       Tmp1 = MakeReg(MVT::i32);
       Tmp2 = SelectExpr(N.getOperand(0));
       BuildMI(BB, PPC::SRAWI, 2, Tmp1).addReg(Tmp2).addImm(Tmp3);
       BuildMI(BB, PPC::ADDZE, 1, Result).addReg(Tmp1);
       return Result;
+    // If this is a divide by constant, we can emit code using some magic
+    // constants to implement it as a multiply instead.
+    case 4:
+      if (opcode == ISD::SDIV)
+        return SelectExpr(BuildSDIVSequence(N));
+      else
+        return SelectExpr(BuildUDIVSequence(N));
     }
     Tmp1 = SelectExpr(N.getOperand(0));
     Tmp2 = SelectExpr(N.getOperand(1));
@@ -1428,19 +1613,6 @@
     BuildMI(BB, Opc, 2, Result).addReg(Tmp1).addReg(Tmp2);
     return Result;
 
-  case ISD::UREM:
-  case ISD::SREM: {
-    Tmp1 = SelectExpr(N.getOperand(0));
-    Tmp2 = SelectExpr(N.getOperand(1));
-    Tmp3 = MakeReg(MVT::i32);
-    unsigned Tmp4 = MakeReg(MVT::i32);
-    Opc = (ISD::UREM == opcode) ? PPC::DIVWU : PPC::DIVW;
-    BuildMI(BB, Opc, 2, Tmp3).addReg(Tmp1).addReg(Tmp2);
-    BuildMI(BB, PPC::MULLW, 2, Tmp4).addReg(Tmp3).addReg(Tmp2);
-    BuildMI(BB, PPC::SUBF, 2, Result).addReg(Tmp4).addReg(Tmp1);
-    return Result;
-  }
-
   case ISD::ADD_PARTS:
   case ISD::SUB_PARTS: {
     assert(N.getNumOperands() == 4 && N.getValueType() == MVT::i32 &&


Index: llvm/lib/Target/PowerPC/PPC64ISelPattern.cpp
diff -u llvm/lib/Target/PowerPC/PPC64ISelPattern.cpp:1.2 llvm/lib/Target/PowerPC/PPC64ISelPattern.cpp:1.3
--- llvm/lib/Target/PowerPC/PPC64ISelPattern.cpp:1.2	Tue Apr  5 12:32:30 2005
+++ llvm/lib/Target/PowerPC/PPC64ISelPattern.cpp	Tue Apr  5 19:25:27 2005
@@ -1069,7 +1069,6 @@
     MVT::ValueType TypeBeingLoaded = (ISD::LOAD == opcode) ?
       Node->getValueType(0) : cast<MVTSDNode>(Node)->getExtraValueType();
     bool sext = (ISD::SEXTLOAD == opcode);
-    bool byte = (MVT::i8 == TypeBeingLoaded);
     
     // Make sure we generate both values.
     if (Result != 1)


Index: llvm/lib/Target/PowerPC/PowerPCInstrInfo.td
diff -u llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.54 llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.55
--- llvm/lib/Target/PowerPC/PowerPCInstrInfo.td:1.54	Mon Apr  4 18:01:51 2005
+++ llvm/lib/Target/PowerPC/PowerPCInstrInfo.td	Tue Apr  5 19:25:27 2005
@@ -368,6 +368,8 @@
                      "divw $rT, $rA, $rB">;
 def DIVWU : XOForm_1<31, 459, 0, 0, 0, 0, (ops GPRC:$rT, GPRC:$rA, GPRC:$rB),
                      "divwu $rT, $rA, $rB">;
+def MULHW : XOForm_1<31, 75, 0, 0, 0, 0, (ops GPRC:$rT, GPRC:$rA, GPRC:$rB),
+                     "mulhw $rT, $rA, $rB">;
 def MULHWU : XOForm_1<31, 11, 0, 0, 0, 0, (ops GPRC:$rT, GPRC:$rA, GPRC:$rB),
                      "mulhwu $rT, $rA, $rB">;
 def MULLD : XOForm_1<31, 233, 0, 0, 1, 0, (ops GPRC:$rT, GPRC:$rA, GPRC:$rB),






More information about the llvm-commits mailing list