[llvm-commits] [llvm] r73477 - in /llvm/trunk: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp test/CodeGen/CellSPU/mul-with-overflow.ll test/CodeGen/PowerPC/mul-with-overflow.ll test/CodeGen/X86/umul-with-overflow.ll

Eli Friedman eli.friedman at gmail.com
Mon Jun 15 23:58:29 PDT 2009


Author: efriedma
Date: Tue Jun 16 01:58:29 2009
New Revision: 73477

URL: http://llvm.org/viewvc/llvm-project?rev=73477&view=rev
Log:
Add some generic expansion logic for SMULO and UMULO.  Fixes UMULO 
support for x86, and UMULO/SMULO for many architectures, including PPC 
(PR4201), ARM, and Cell. The resulting expansion isn't perfect, but it's
not bad.


Added:
    llvm/trunk/test/CodeGen/CellSPU/mul-with-overflow.ll
    llvm/trunk/test/CodeGen/PowerPC/mul-with-overflow.ll
    llvm/trunk/test/CodeGen/X86/umul-with-overflow.ll
Modified:
    llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp

Modified: llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp?rev=73477&r1=73476&r2=73477&view=diff

==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp Tue Jun 16 01:58:29 2009
@@ -2768,6 +2768,53 @@
                                    ISD::SETULT : ISD::SETUGT));
     break;
   }
+  case ISD::UMULO:
+  case ISD::SMULO: {
+    MVT VT = Node->getValueType(0);
+    SDValue LHS = Node->getOperand(0);
+    SDValue RHS = Node->getOperand(1);
+    SDValue BottomHalf;
+    SDValue TopHalf;
+    static unsigned Ops[2][3] =
+        { { ISD::MULHU, ISD::UMUL_LOHI, ISD::ZERO_EXTEND },
+          { ISD::MULHS, ISD::SMUL_LOHI, ISD::SIGN_EXTEND }};
+    bool isSigned = Node->getOpcode() == ISD::SMULO;
+    if (TLI.isOperationLegalOrCustom(Ops[isSigned][0], VT)) {
+      BottomHalf = DAG.getNode(ISD::MUL, dl, VT, LHS, RHS);
+      TopHalf = DAG.getNode(Ops[isSigned][0], dl, VT, LHS, RHS);
+    } else if (TLI.isOperationLegalOrCustom(Ops[isSigned][1], VT)) {
+      BottomHalf = DAG.getNode(Ops[isSigned][1], dl, DAG.getVTList(VT, VT), LHS,
+                               RHS);
+      TopHalf = BottomHalf.getValue(1);
+    } else if (TLI.isTypeLegal(MVT::getIntegerVT(VT.getSizeInBits() * 2))) {
+      MVT WideVT = MVT::getIntegerVT(VT.getSizeInBits() * 2);
+      LHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, LHS);
+      RHS = DAG.getNode(Ops[isSigned][2], dl, WideVT, RHS);
+      Tmp1 = DAG.getNode(ISD::MUL, dl, WideVT, LHS, RHS);
+      BottomHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Tmp1,
+                               DAG.getIntPtrConstant(0));
+      TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Tmp1,
+                            DAG.getIntPtrConstant(1));
+    } else {
+      // FIXME: We should be able to fall back to a libcall with an illegal
+      // type in some cases cases.
+      // Also, we can fall back to a division in some cases, but that's a big
+      // performance hit in the general case.
+      assert(0 && "Don't know how to expand this operation yet!");
+    }
+    if (isSigned) {
+      Tmp1 = DAG.getConstant(VT.getSizeInBits() - 1, TLI.getShiftAmountTy());
+      Tmp1 = DAG.getNode(ISD::SRA, dl, VT, BottomHalf, Tmp1);
+      TopHalf = DAG.getSetCC(dl, TLI.getSetCCResultType(VT), TopHalf, Tmp1,
+                             ISD::SETNE);
+    } else {
+      TopHalf = DAG.getSetCC(dl, TLI.getSetCCResultType(VT), TopHalf,
+                             DAG.getConstant(0, VT), ISD::SETNE);
+    }
+    Results.push_back(BottomHalf);
+    Results.push_back(TopHalf);
+    break;
+  }
   case ISD::BUILD_PAIR: {
     MVT PairTy = Node->getValueType(0);
     Tmp1 = DAG.getNode(ISD::ZERO_EXTEND, dl, PairTy, Node->getOperand(0));

Added: llvm/trunk/test/CodeGen/CellSPU/mul-with-overflow.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/CellSPU/mul-with-overflow.ll?rev=73477&view=auto

==============================================================================
--- llvm/trunk/test/CodeGen/CellSPU/mul-with-overflow.ll (added)
+++ llvm/trunk/test/CodeGen/CellSPU/mul-with-overflow.ll Tue Jun 16 01:58:29 2009
@@ -0,0 +1,15 @@
+; RUN: llvm-as < %s | llc -march=cellspu
+
+declare {i16, i1} @llvm.smul.with.overflow.i16(i16 %a, i16 %b)
+define i1 @a(i16 %x) zeroext nounwind {
+  %res = call {i16, i1} @llvm.smul.with.overflow.i16(i16 %x, i16 3)
+  %obil = extractvalue {i16, i1} %res, 1
+  ret i1 %obil
+}
+
+declare {i16, i1} @llvm.umul.with.overflow.i16(i16 %a, i16 %b)
+define i1 @b(i16 %x) zeroext nounwind {
+  %res = call {i16, i1} @llvm.umul.with.overflow.i16(i16 %x, i16 3)
+  %obil = extractvalue {i16, i1} %res, 1
+  ret i1 %obil
+}

Added: llvm/trunk/test/CodeGen/PowerPC/mul-with-overflow.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/PowerPC/mul-with-overflow.ll?rev=73477&view=auto

==============================================================================
--- llvm/trunk/test/CodeGen/PowerPC/mul-with-overflow.ll (added)
+++ llvm/trunk/test/CodeGen/PowerPC/mul-with-overflow.ll Tue Jun 16 01:58:29 2009
@@ -0,0 +1,15 @@
+; RUN: llvm-as < %s | llc -march=ppc32
+
+declare {i32, i1} @llvm.umul.with.overflow.i32(i32 %a, i32 %b)
+define i1 @a(i32 %x) zeroext nounwind {
+  %res = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 3)
+  %obil = extractvalue {i32, i1} %res, 1
+  ret i1 %obil
+}
+
+declare {i32, i1} @llvm.smul.with.overflow.i32(i32 %a, i32 %b)
+define i1 @b(i32 %x) zeroext nounwind {
+  %res = call {i32, i1} @llvm.smul.with.overflow.i32(i32 %x, i32 3)
+  %obil = extractvalue {i32, i1} %res, 1
+  ret i1 %obil
+}

Added: llvm/trunk/test/CodeGen/X86/umul-with-overflow.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/X86/umul-with-overflow.ll?rev=73477&view=auto

==============================================================================
--- llvm/trunk/test/CodeGen/X86/umul-with-overflow.ll (added)
+++ llvm/trunk/test/CodeGen/X86/umul-with-overflow.ll Tue Jun 16 01:58:29 2009
@@ -0,0 +1,8 @@
+; RUN: llvm-as < %s | llc -march=x86 | grep "\\\\\\\<mul"
+
+declare {i32, i1} @llvm.umul.with.overflow.i32(i32 %a, i32 %b)
+define i1 @a(i32 %x) zeroext nounwind {
+  %res = call {i32, i1} @llvm.umul.with.overflow.i32(i32 %x, i32 3)
+  %obil = extractvalue {i32, i1} %res, 1
+  ret i1 %obil
+}





More information about the llvm-commits mailing list