[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