Necessary changes to codegen cttz efficiently on PowerPC
authorNate Begeman <natebegeman@mac.com>
Wed, 11 May 2005 23:43:56 +0000 (23:43 +0000)
committerNate Begeman <natebegeman@mac.com>
Wed, 11 May 2005 23:43:56 +0000 (23:43 +0000)
1. Teach LegalizeDAG how to better legalize CTTZ if the target doesn't have
   CTPOP, but does have CTLZ
2. Teach PPC32 how to do sub x, const -> add x, -const for valid consts
3. Teach PPC32 how to do and (xor a, -1) b -> andc b, a
4. Teach PPC32 that ISD::CTLZ -> PPC::CNTLZW

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

lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
lib/Target/PowerPC/PPCISelPattern.cpp

index a511202a534b6e47d438ca6f6aa4c139f4edd8ac..08e8d776fd431778611230e05fcac7ca6382821d 100644 (file)
@@ -1156,15 +1156,25 @@ SDOperand SelectionDAGLegalize::LegalizeOp(SDOperand Op) {
         break;
       }
       case ISD::CTTZ: {
-        // for now, we use: { return popcount(~x & (x - 1)); }
-        // but see also http://www.hackersdelight.org/HDcode/ntz.cc
+        // for now, we use: { return popcount(~x & (x - 1)); } 
+        // unless the target has ctlz but not ctpop, in which case we use:
+        // { return 32 - nlz(~x & (x-1)); }
+        // see also http://www.hackersdelight.org/HDcode/ntz.cc
         MVT::ValueType VT = Tmp1.getValueType();
         Tmp2 = DAG.getConstant(~0ULL, VT);
         Tmp3 = DAG.getNode(ISD::AND, VT, 
                            DAG.getNode(ISD::XOR, VT, Tmp1, Tmp2),
                            DAG.getNode(ISD::SUB, VT, Tmp1,
                                        DAG.getConstant(1, VT)));
-        Result = LegalizeOp(DAG.getNode(ISD::CTPOP, VT, Tmp3));
+        // If ISD::CTLZ is legal and CTPOP isn't, then do that instead
+        if (TLI.getOperationAction(ISD::CTPOP, VT) != TargetLowering::Legal &&
+            TLI.getOperationAction(ISD::CTLZ, VT) == TargetLowering::Legal) {
+          Result = LegalizeOp(DAG.getNode(ISD::SUB, VT, 
+                                        DAG.getConstant(getSizeInBits(VT), VT),
+                                        DAG.getNode(ISD::CTLZ, VT, Tmp3)));
+        } else {
+          Result = LegalizeOp(DAG.getNode(ISD::CTPOP, VT, Tmp3));
+        }
         break;
       }
       default:
index 6d687ef9f3ea4866a018781d22fcdc3ba3e07b6f..536a07710defdb84a00a2896dbe6e1dabcf1c8f9 100644 (file)
@@ -69,10 +69,9 @@ namespace {
       setOperationAction(ISD::FCOS , MVT::f32, Expand);
       setOperationAction(ISD::FSQRT, MVT::f32, Expand);
 
-      //PowerPC has these, but they are not implemented
+      //PowerPC does not have CTPOP or CTTZ
       setOperationAction(ISD::CTPOP, MVT::i32  , Expand);
       setOperationAction(ISD::CTTZ , MVT::i32  , Expand);
-      setOperationAction(ISD::CTLZ , MVT::i32  , Expand);
 
       setSetCCResultContents(ZeroOrOneSetCCResult);
       addLegalFPImmediate(+0.0); // Necessary for FSEL
@@ -654,9 +653,13 @@ static unsigned getImmediateForOpcode(SDOperand N, unsigned Opcode,
     if ((v & 0x0000FFFF) == 0) { Imm = v >> 16; return 2; }
     break;
   case ISD::MUL:
-  case ISD::SUB:
     if (v <= 32767 && v >= -32768) { Imm = v & 0xFFFF; return 1; }
     break;
+  case ISD::SUB:
+    // handle subtract-from separately from subtract, since subi is really addi
+    if (U && v <= 32767 && v >= -32768) { Imm = v & 0xFFFF; return 1; }
+    if (!U && v <= 32768 && v >= -32767) { Imm = (-v) & 0xFFFF; return 1; }
+    break;
   case ISD::SETCC:
     if (U && (v >= 0 && v <= 65535)) { Imm = v & 0xFFFF; return 1; }
     if (!U && (v <= 32767 && v >= -32768)) { Imm = v & 0xFFFF; return 1; }
@@ -1817,6 +1820,11 @@ unsigned ISel::SelectExpr(SDOperand N, bool Recording) {
     }
     return Result;
 
+  case ISD::CTLZ:
+    Tmp1 = SelectExpr(N.getOperand(0));
+    BuildMI(BB, PPC::CNTLZW, 1, Result).addReg(Tmp1);
+    return Result;
+
   case ISD::ADD:
     assert (DestType == MVT::i32 && "Only do arithmetic on i32s!");
     Tmp1 = SelectExpr(N.getOperand(0));
@@ -1851,6 +1859,16 @@ unsigned ISel::SelectExpr(SDOperand N, bool Recording) {
     switch(getImmediateForOpcode(N.getOperand(1), opcode, Tmp2)) {
       default: assert(0 && "unhandled result code");
       case 0: // No immediate
+        // Check for andc: and, (xor a, -1), b
+        if (N.getOperand(0).getOpcode() == ISD::XOR &&
+          N.getOperand(0).getOperand(1).getOpcode() == ISD::Constant &&
+        cast<ConstantSDNode>(N.getOperand(0).getOperand(1))->isAllOnesValue()) {
+          Tmp1 = SelectExpr(N.getOperand(0).getOperand(0));
+          Tmp2 = SelectExpr(N.getOperand(1));
+          BuildMI(BB, PPC::ANDC, 2, Result).addReg(Tmp2).addReg(Tmp1);
+          return Result;
+        }
+        // It wasn't and-with-complement, emit a regular and
         Tmp1 = SelectExpr(N.getOperand(0));
         Tmp2 = SelectExpr(N.getOperand(1));
         Opc = Recording ? PPC::ANDo : PPC::AND;
@@ -1976,11 +1994,15 @@ unsigned ISel::SelectExpr(SDOperand N, bool Recording) {
   }
 
   case ISD::SUB:
-    Tmp2 = SelectExpr(N.getOperand(1));
-    if (1 == getImmediateForOpcode(N.getOperand(0), opcode, Tmp1))
+    if (1 == getImmediateForOpcode(N.getOperand(0), opcode, Tmp1, true)) {
+      Tmp2 = SelectExpr(N.getOperand(1));
       BuildMI(BB, PPC::SUBFIC, 2, Result).addReg(Tmp2).addSImm(Tmp1);
-    else {
+    } else if (1 == getImmediateForOpcode(N.getOperand(1), opcode, Tmp2)) {
       Tmp1 = SelectExpr(N.getOperand(0));
+      BuildMI(BB, PPC::ADDI, 2, Result).addReg(Tmp1).addSImm(Tmp2);
+    } else {
+      Tmp1 = SelectExpr(N.getOperand(0));
+      Tmp2 = SelectExpr(N.getOperand(1));
       BuildMI(BB, PPC::SUBF, 2, Result).addReg(Tmp2).addReg(Tmp1);
     }
     return Result;