[llvm] [GlobalIsel] Combine ADDE (PR #82413)

Amara Emerson via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 22 23:53:27 PST 2024


================
@@ -6906,3 +6923,195 @@ bool CombinerHelper::matchOr(MachineInstr &MI, BuildFnTy &MatchInfo) {
 
   return false;
 }
+
+bool CombinerHelper::isZExtOrTruncLegal(LLT ToTy, LLT FromTy) const {
+  // Copy.
+  if (ToTy == FromTy)
+    return true;
+
+  if (isLegalOrBeforeLegalizer({TargetOpcode::G_ZEXT, {ToTy, FromTy}}))
+    return true;
+
+  if (isLegalOrBeforeLegalizer({TargetOpcode::G_TRUNC, {ToTy, FromTy}}))
+    return true;
+
+  return false;
+}
+
+bool CombinerHelper::matchAddCarryInOut(MachineInstr &MI,
+                                        BuildFnTy &MatchInfo) {
+  GAddCarryInOut *Add = cast<GAddCarryInOut>(&MI);
+
+  // adde has no flags.
+  Register Dst = Add->getDstReg();
+  Register Carry = Add->getCarryOutReg();
+  Register CarryIn = Add->getCarryInReg();
+  Register LHS = Add->getLHSReg();
+  Register RHS = Add->getRHSReg();
+  bool IsSigned = Add->isSigned();
+  LLT DstTy = MRI.getType(Dst);
+  LLT CarryTy = MRI.getType(Carry);
+  LLT OperandTy = MRI.getType(LHS);
+  LLT CarryInTy = MRI.getType(CarryIn);
+
+  // FIXME: handle undef
+
+  // fold sadde, if the carry is dead -> add(add(LHS, RHS),
+  // zextOrTrunc(CarryIn)), undef.
+  if (MRI.use_nodbg_empty(Carry) && IsSigned && MRI.hasOneNonDBGUse(Dst) &&
+      isLegalOrBeforeLegalizer({TargetOpcode::G_ADD, {DstTy}}) &&
+      isZExtOrTruncLegal(DstTy, CarryInTy)) {
+    MatchInfo = [=](MachineIRBuilder &B) {
+      auto A = B.buildAdd(DstTy, LHS, RHS);
+      Register AReg = A.getReg(0);
+      auto ZextCarryIn = B.buildZExtOrTrunc(DstTy, CarryIn);
+      Register ZextCarryInReg = ZextCarryIn.getReg(0);
+      B.buildAdd(Dst, AReg, ZextCarryInReg);
+      B.buildUndef(Carry);
+    };
+    return true;
+  }
+
+  // We want do fold the [u|s]adde.
+  if (!MRI.hasOneNonDBGUse(Dst) || !MRI.hasOneNonDBGUse(Carry))
+    return false;
+
+  // The parameters of the adde must be integer-like.
+  std::optional<APInt> MaybeLHS = getConstantOrConstantSplatVector(LHS);
+  std::optional<APInt> MaybeRHS = getConstantOrConstantSplatVector(RHS);
+  std::optional<APInt> MaybeCarryIn = getConstantOrConstantSplatVector(CarryIn);
+
+  // fold adde(c, c, c) -> c, carry
+  if (MaybeLHS && MaybeRHS && MaybeCarryIn &&
+      isConstantLegalOrBeforeLegalizer(DstTy) &&
+      isConstantLegalOrBeforeLegalizer(CarryTy)) {
+    // They must all have the same bitwidth. Otherwise APInt might
+    // assert. Prelegalization, they may have widely different bitwidths.
+    unsigned BitWidth =
+        std::max(std::max(MaybeLHS->getBitWidth(), MaybeRHS->getBitWidth()),
+                 MaybeCarryIn->getBitWidth());
+    if (IsSigned) {
+      APInt LHS = MaybeLHS->sext(BitWidth);
+      APInt RHS = MaybeRHS->sext(BitWidth);
+      APInt CarryIn = MaybeCarryIn->zext(BitWidth);
+      bool FirstOverflowed = false;
+      bool SecondOverflowed = false;
+      APInt Result =
+          LHS.sadd_ov(RHS, FirstOverflowed).sadd_ov(CarryIn, SecondOverflowed);
+      MatchInfo = [=](MachineIRBuilder &B) {
+        B.buildConstant(Dst, Result);
+        B.buildConstant(Carry, FirstOverflowed | SecondOverflowed);
+      };
+      return true;
+    } else if (!IsSigned) {
----------------
aemerson wrote:

`if (!IsSigned)` is redundant.

https://github.com/llvm/llvm-project/pull/82413


More information about the llvm-commits mailing list