[llvm-commits] [llvm] r128696 - in /llvm/trunk: include/llvm/CodeGen/RuntimeLibcalls.h lib/CodeGen/SelectionDAG/LegalizeDAG.cpp lib/CodeGen/SelectionDAG/TargetLowering.cpp lib/Target/ARM/ARMISelLowering.cpp

Evan Cheng evan.cheng at apple.com
Thu Mar 31 17:42:02 PDT 2011


Author: evancheng
Date: Thu Mar 31 19:42:02 2011
New Revision: 128696

URL: http://llvm.org/viewvc/llvm-project?rev=128696&view=rev
Log:
Issue libcalls __udivmod*i4 / __divmod*i4 for div / rem pairs.

rdar://8911343

Modified:
    llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h
    llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
    llvm/trunk/lib/CodeGen/SelectionDAG/TargetLowering.cpp
    llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp

Modified: llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h?rev=128696&r1=128695&r2=128696&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h (original)
+++ llvm/trunk/include/llvm/CodeGen/RuntimeLibcalls.h Thu Mar 31 19:42:02 2011
@@ -66,6 +66,16 @@
     UREM_I32,
     UREM_I64,
     UREM_I128,
+    SDIVREM_I8,
+    SDIVREM_I16,
+    SDIVREM_I32,
+    SDIVREM_I64,
+    SDIVREM_I128,
+    UDIVREM_I8,
+    UDIVREM_I16,
+    UDIVREM_I32,
+    UDIVREM_I64,
+    UDIVREM_I128,
     NEG_I32,
     NEG_I64,
 

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp?rev=128696&r1=128695&r2=128696&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp Thu Mar 31 19:42:02 2011
@@ -153,6 +153,7 @@
                            RTLIB::Libcall Call_I32,
                            RTLIB::Libcall Call_I64,
                            RTLIB::Libcall Call_I128);
+  SDValue ExpandDivRemLibCall(SDNode *Node, bool isSigned, bool isDIV);
 
   SDValue EmitStackConvert(SDValue SrcOp, EVT SlotVT, EVT DestVT, DebugLoc dl);
   SDValue ExpandBUILD_VECTOR(SDNode *Node);
@@ -786,7 +787,7 @@
       }
     }
   }
-  return SDValue();
+  return SDValue(0, 0);
 }
 
 /// LegalizeOp - We know that the specified value has a legal type, and
@@ -2114,6 +2115,116 @@
   return ExpandLibCall(LC, Node, isSigned);
 }
 
+/// ExpandDivRemLibCall - Issue libcalls to __{u}divmod to compute div / rem
+/// pairs.
+SDValue SelectionDAGLegalize::ExpandDivRemLibCall(SDNode *Node, bool isSigned,
+                                                  bool isDIV) {
+  RTLIB::Libcall LC;
+  switch (Node->getValueType(0).getSimpleVT().SimpleTy) {
+  default: assert(0 && "Unexpected request for libcall!");
+  case MVT::i8:   LC= isSigned ? RTLIB::SDIVREM_I8  : RTLIB::UDIVREM_I8;  break;
+  case MVT::i16:  LC= isSigned ? RTLIB::SDIVREM_I16 : RTLIB::UDIVREM_I16; break;
+  case MVT::i32:  LC= isSigned ? RTLIB::SDIVREM_I32 : RTLIB::UDIVREM_I32; break;
+  case MVT::i64:  LC= isSigned ? RTLIB::SDIVREM_I64 : RTLIB::UDIVREM_I64; break;
+  case MVT::i128: LC= isSigned ? RTLIB::SDIVREM_I128:RTLIB::UDIVREM_I128; break;
+  }
+
+  if (!TLI.getLibcallName(LC))
+    return SDValue();
+
+  // Only issue divrem libcall if both quotient and remainder are needed.
+  unsigned OtherOpcode = 0;
+  if (isSigned) {
+    OtherOpcode = isDIV ? ISD::SREM : ISD::SDIV;
+  } else {
+    OtherOpcode = isDIV ? ISD::UREM : ISD::UDIV;
+  }
+  SDNode *OtherNode = 0;
+  SDValue Op0 = Node->getOperand(0);
+  SDValue Op1 = Node->getOperand(1);
+  for (SDNode::use_iterator UI = Op0.getNode()->use_begin(),
+         UE = Op0.getNode()->use_end(); UI != UE; ++UI) {
+    SDNode *User = *UI;
+    if (User == Node)
+      continue;
+    if (User->getOpcode() == OtherOpcode &&
+        User->getOperand(0) == Op0 &&
+        User->getOperand(1) == Op1) {
+      OtherNode = User;
+      break;
+    }
+  }
+  if (!OtherNode)
+    return SDValue();
+
+  // If the libcall is already generated, no need to issue it again.
+  DenseMap<SDValue, SDValue>::iterator I
+    = LegalizedNodes.find(SDValue(OtherNode,0));
+  if (I != LegalizedNodes.end()) {
+    OtherNode = I->second.getNode();
+    SDNode *Chain = OtherNode->getOperand(0).getNode();
+    for (SDNode::use_iterator UI = Chain->use_begin(), UE = Chain->use_end();
+         UI != UE; ++UI) {
+      SDNode *User = *UI;
+      if (User == OtherNode)
+        continue;
+      if (isDIV) {
+        assert(User->getOpcode() == ISD::CopyFromReg);
+      } else {
+        assert(User->getOpcode() == ISD::LOAD);
+      }
+      return SDValue(User, 0);
+    }
+  }
+
+  // The input chain to this libcall is the entry node of the function.
+  // Legalizing the call will automatically add the previous call to the
+  // dependence.
+  SDValue InChain = DAG.getEntryNode();
+
+  EVT RetVT = Node->getValueType(0);
+  const Type *RetTy = RetVT.getTypeForEVT(*DAG.getContext());
+
+  TargetLowering::ArgListTy Args;
+  TargetLowering::ArgListEntry Entry;
+  for (unsigned i = 0, e = Node->getNumOperands(); i != e; ++i) {
+    EVT ArgVT = Node->getOperand(i).getValueType();
+    const Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext());
+    Entry.Node = Node->getOperand(i); Entry.Ty = ArgTy;
+    Entry.isSExt = isSigned;
+    Entry.isZExt = !isSigned;
+    Args.push_back(Entry);
+  }
+
+  // Also pass the return address of the remainder.
+  SDValue FIPtr = DAG.CreateStackTemporary(RetVT);
+  Entry.Node = FIPtr;
+  Entry.Ty = RetTy->getPointerTo();
+  Entry.isSExt = isSigned;
+  Entry.isZExt = !isSigned;
+  Args.push_back(Entry);
+
+  SDValue Callee = DAG.getExternalSymbol(TLI.getLibcallName(LC),
+                                         TLI.getPointerTy());
+
+  // Splice the libcall in wherever FindInputOutputChains tells us to.
+  DebugLoc dl = Node->getDebugLoc();
+  std::pair<SDValue, SDValue> CallInfo =
+    TLI.LowerCallTo(InChain, RetTy, isSigned, !isSigned, false, false,
+                    0, TLI.getLibcallCallingConv(LC), /*isTailCall=*/false,
+                    /*isReturnValueUsed=*/true, Callee, Args, DAG, dl);
+
+  // Legalize the call sequence, starting with the chain.  This will advance
+  // the LastCALLSEQ_END to the legalized version of the CALLSEQ_END node that
+  // was added by LowerCallTo (guaranteeing proper serialization of calls).
+  LegalizeOp(CallInfo.second);
+
+  // Remainder is loaded back from the stack frame.
+  SDValue Rem = DAG.getLoad(RetVT, dl, LastCALLSEQ_END, FIPtr,
+                            MachinePointerInfo(), false, false, 0);
+  return isDIV ? CallInfo.first : Rem;
+}
+
 /// ExpandLegalINT_TO_FP - This function is responsible for legalizing a
 /// INT_TO_FP operation of the specified operand when the target requests that
 /// we expand it.  At this point, we know that the result and operand types are
@@ -3095,15 +3206,19 @@
       Tmp1 = DAG.getNode(ISD::MUL, dl, VT, Tmp1, Tmp3);
       Tmp1 = DAG.getNode(ISD::SUB, dl, VT, Tmp2, Tmp1);
     } else if (isSigned) {
-      Tmp1 = ExpandIntLibCall(Node, true,
-                              RTLIB::SREM_I8,
-                              RTLIB::SREM_I16, RTLIB::SREM_I32,
-                              RTLIB::SREM_I64, RTLIB::SREM_I128);
+      Tmp1 = ExpandDivRemLibCall(Node, true, false);
+      if (!Tmp1.getNode())
+        Tmp1 = ExpandIntLibCall(Node, true,
+                                RTLIB::SREM_I8,
+                                RTLIB::SREM_I16, RTLIB::SREM_I32,
+                                RTLIB::SREM_I64, RTLIB::SREM_I128);
     } else {
-      Tmp1 = ExpandIntLibCall(Node, false,
-                              RTLIB::UREM_I8,
-                              RTLIB::UREM_I16, RTLIB::UREM_I32,
-                              RTLIB::UREM_I64, RTLIB::UREM_I128);
+      Tmp1 = ExpandDivRemLibCall(Node, false, false);
+      if (!Tmp1.getNode())
+        Tmp1 = ExpandIntLibCall(Node, false,
+                                RTLIB::UREM_I8,
+                                RTLIB::UREM_I16, RTLIB::UREM_I32,
+                                RTLIB::UREM_I64, RTLIB::UREM_I128);
     }
     Results.push_back(Tmp1);
     break;
@@ -3117,16 +3232,23 @@
     if (TLI.isOperationLegalOrCustom(DivRemOpc, VT))
       Tmp1 = DAG.getNode(DivRemOpc, dl, VTs, Node->getOperand(0),
                          Node->getOperand(1));
-    else if (isSigned)
-      Tmp1 = ExpandIntLibCall(Node, true,
-                              RTLIB::SDIV_I8,
-                              RTLIB::SDIV_I16, RTLIB::SDIV_I32,
-                              RTLIB::SDIV_I64, RTLIB::SDIV_I128);
-    else
-      Tmp1 = ExpandIntLibCall(Node, false,
-                              RTLIB::UDIV_I8,
-                              RTLIB::UDIV_I16, RTLIB::UDIV_I32,
-                              RTLIB::UDIV_I64, RTLIB::UDIV_I128);
+    else if (isSigned) {
+      Tmp1 = ExpandDivRemLibCall(Node, true, true);
+      if (!Tmp1.getNode()) {
+        Tmp1 = ExpandIntLibCall(Node, true,
+                                RTLIB::SDIV_I8,
+                                RTLIB::SDIV_I16, RTLIB::SDIV_I32,
+                                RTLIB::SDIV_I64, RTLIB::SDIV_I128);
+      }
+    } else {
+      Tmp1 = ExpandDivRemLibCall(Node, false, true);
+      if (!Tmp1.getNode()) {
+        Tmp1 = ExpandIntLibCall(Node, false,
+                                RTLIB::UDIV_I8,
+                                RTLIB::UDIV_I16, RTLIB::UDIV_I32,
+                                RTLIB::UDIV_I64, RTLIB::UDIV_I128);
+      }
+    }
     Results.push_back(Tmp1);
     break;
   }

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/TargetLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/TargetLowering.cpp?rev=128696&r1=128695&r2=128696&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/TargetLowering.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/TargetLowering.cpp Thu Mar 31 19:42:02 2011
@@ -93,6 +93,19 @@
   Names[RTLIB::UREM_I32] = "__umodsi3";
   Names[RTLIB::UREM_I64] = "__umoddi3";
   Names[RTLIB::UREM_I128] = "__umodti3";
+
+  // These are generally not available.
+  Names[RTLIB::SDIVREM_I8] = 0;
+  Names[RTLIB::SDIVREM_I16] = 0;
+  Names[RTLIB::SDIVREM_I32] = 0;
+  Names[RTLIB::SDIVREM_I64] = 0;
+  Names[RTLIB::SDIVREM_I128] = 0;
+  Names[RTLIB::UDIVREM_I8] = 0;
+  Names[RTLIB::UDIVREM_I16] = 0;
+  Names[RTLIB::UDIVREM_I32] = 0;
+  Names[RTLIB::UDIVREM_I64] = 0;
+  Names[RTLIB::UDIVREM_I128] = 0;
+
   Names[RTLIB::NEG_I32] = "__negsi2";
   Names[RTLIB::NEG_I64] = "__negdi2";
   Names[RTLIB::ADD_F32] = "__addsf3";

Modified: llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp?rev=128696&r1=128695&r2=128696&view=diff
==============================================================================
--- llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/ARM/ARMISelLowering.cpp Thu Mar 31 19:42:02 2011
@@ -72,6 +72,11 @@
   cl::desc("Enable / disable ARM interworking (for debugging only)"),
   cl::init(true));
 
+static cl::opt<bool>
+UseDivMod("arm-divmod-libcall", cl::Hidden,
+  cl::desc("Use __{u}divmod libcalls for div / rem pairs"),
+  cl::init(false));
+
 void ARMTargetLowering::addTypeForNEON(EVT VT, EVT PromotedLdStVT,
                                        EVT PromotedBitwiseVT) {
   if (VT != PromotedLdStVT) {
@@ -393,6 +398,11 @@
     setLibcallCallingConv(RTLIB::UDIV_I32, CallingConv::ARM_AAPCS);
   }
 
+  if (UseDivMod) {
+    setLibcallName(RTLIB::SDIVREM_I32, "__divmodsi4");
+    setLibcallName(RTLIB::UDIVREM_I32, "__udivmodsi4");
+  }
+
   if (Subtarget->isThumb1Only())
     addRegisterClass(MVT::i32, ARM::tGPRRegisterClass);
   else





More information about the llvm-commits mailing list