[llvm] r360303 - [SelectionDAG] Expand ADD/SUBCARRY

Leonard Chan via llvm-commits llvm-commits at lists.llvm.org
Wed May 8 18:17:48 PDT 2019


Author: leonardchan
Date: Wed May  8 18:17:48 2019
New Revision: 360303

URL: http://llvm.org/viewvc/llvm-project?rev=360303&view=rev
Log:
[SelectionDAG] Expand ADD/SUBCARRY

This patch allows for expansion of ADDCARRY and SUBCARRY when the target does not support it.

Differential Revision: https://reviews.llvm.org/D61411

Added:
    llvm/trunk/test/CodeGen/RISCV/addcarry.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=360303&r1=360302&r2=360303&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp (original)
+++ llvm/trunk/lib/CodeGen/SelectionDAG/LegalizeDAG.cpp Wed May  8 18:17:48 2019
@@ -3273,6 +3273,48 @@ bool SelectionDAGLegalize::ExpandNode(SD
   case ISD::UMULFIX:
     Results.push_back(TLI.expandFixedPointMul(Node, DAG));
     break;
+  case ISD::ADDCARRY:
+  case ISD::SUBCARRY: {
+    SDValue LHS = Node->getOperand(0);
+    SDValue RHS = Node->getOperand(1);
+    SDValue Carry = Node->getOperand(2);
+
+    bool IsAdd = Node->getOpcode() == ISD::ADDCARRY;
+
+    // Initial add of the 2 operands.
+    unsigned Op = IsAdd ? ISD::ADD : ISD::SUB;
+    EVT VT = LHS.getValueType();
+    SDValue Sum = DAG.getNode(Op, dl, VT, LHS, RHS);
+
+    // Initial check for overflow.
+    EVT CarryType = Node->getValueType(1);
+    EVT SetCCType = getSetCCResultType(Node->getValueType(0));
+    ISD::CondCode CC = IsAdd ? ISD::SETULT : ISD::SETUGT;
+    SDValue Overflow = DAG.getSetCC(dl, SetCCType, Sum, LHS, CC);
+
+    // Add of the sum and the carry.
+    SDValue CarryExt =
+        DAG.getZeroExtendInReg(DAG.getZExtOrTrunc(Carry, dl, VT), dl, MVT::i1);
+    SDValue Sum2 = DAG.getNode(Op, dl, VT, Sum, CarryExt);
+
+    // Second check for overflow. If we are adding, we can only overflow if the
+    // initial sum is all 1s ang the carry is set, resulting in a new sum of 0.
+    // If we are subtracting, we can only overflow if the initial sum is 0 and
+    // the carry is set, resulting in a new sum of all 1s.
+    SDValue Zero = DAG.getConstant(0, dl, VT);
+    SDValue Overflow2 =
+        IsAdd ? DAG.getSetCC(dl, SetCCType, Sum2, Zero, ISD::SETEQ)
+              : DAG.getSetCC(dl, SetCCType, Sum, Zero, ISD::SETEQ);
+    Overflow2 = DAG.getNode(ISD::AND, dl, SetCCType, Overflow2,
+                            DAG.getZExtOrTrunc(Carry, dl, SetCCType));
+
+    SDValue ResultCarry =
+        DAG.getNode(ISD::OR, dl, SetCCType, Overflow, Overflow2);
+
+    Results.push_back(Sum2);
+    Results.push_back(DAG.getBoolExtOrTrunc(ResultCarry, dl, CarryType, VT));
+    break;
+  }
   case ISD::SADDO:
   case ISD::SSUBO: {
     SDValue LHS = Node->getOperand(0);

Added: llvm/trunk/test/CodeGen/RISCV/addcarry.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/addcarry.ll?rev=360303&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/addcarry.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/addcarry.ll Wed May  8 18:17:48 2019
@@ -0,0 +1,44 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc < %s -mtriple=riscv32 -mattr=+m | FileCheck %s --check-prefix=RISCV32
+
+; Test ADDCARRY node expansion on a target that does not currently support ADDCARRY.
+; Signed fixed point multiplication eventually expands down to an ADDCARRY.
+
+declare  i64 @llvm.smul.fix.i64  (i64, i64, i32)
+
+define i64 @addcarry(i64 %x, i64 %y) {
+; RISCV32-LABEL: addcarry:
+; RISCV32:       # %bb.0:
+; RISCV32-NEXT:    mul a4, a0, a3
+; RISCV32-NEXT:    mulhu a5, a0, a2
+; RISCV32-NEXT:    add a4, a5, a4
+; RISCV32-NEXT:    sltu a6, a4, a5
+; RISCV32-NEXT:    mulhu a5, a0, a3
+; RISCV32-NEXT:    add a6, a5, a6
+; RISCV32-NEXT:    mulhu a5, a1, a2
+; RISCV32-NEXT:    add a7, a6, a5
+; RISCV32-NEXT:    mul a5, a1, a2
+; RISCV32-NEXT:    add a6, a4, a5
+; RISCV32-NEXT:    sltu a4, a6, a4
+; RISCV32-NEXT:    add a4, a7, a4
+; RISCV32-NEXT:    mul a5, a1, a3
+; RISCV32-NEXT:    add a5, a4, a5
+; RISCV32-NEXT:    bgez a1, .LBB0_2
+; RISCV32-NEXT:  # %bb.1:
+; RISCV32-NEXT:    sub a5, a5, a2
+; RISCV32-NEXT:  .LBB0_2:
+; RISCV32-NEXT:    bgez a3, .LBB0_4
+; RISCV32-NEXT:  # %bb.3:
+; RISCV32-NEXT:    sub a5, a5, a0
+; RISCV32-NEXT:  .LBB0_4:
+; RISCV32-NEXT:    mul a0, a0, a2
+; RISCV32-NEXT:    srli a0, a0, 2
+; RISCV32-NEXT:    slli a1, a6, 30
+; RISCV32-NEXT:    or a0, a0, a1
+; RISCV32-NEXT:    srli a1, a6, 2
+; RISCV32-NEXT:    slli a2, a5, 30
+; RISCV32-NEXT:    or a1, a1, a2
+; RISCV32-NEXT:    ret
+  %tmp = call i64 @llvm.smul.fix.i64(i64 %x, i64 %y, i32 2);
+  ret i64 %tmp;
+}




More information about the llvm-commits mailing list