[llvm] [GlobalIsel] Combine ADDE (PR #82413)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Feb 20 12:24:52 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-amdgpu
@llvm/pr-subscribers-backend-aarch64
Author: Thorsten Schütt (tschuett)
<details>
<summary>Changes</summary>
Clang has them as builtins (__builtin_addc). The middle end has no intrinsics for them. They are used in legalization operations.
AArch64: ADCS Add with carry and set flags
On Neoverse V2, they run at half the throughput of basic arithmetic and have a limited set of pipelines.
---
Patch is 192.73 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/82413.diff
8 Files Affected:
- (modified) llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h (+8-2)
- (modified) llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h (+17)
- (modified) llvm/include/llvm/Target/GlobalISel/Combine.td (+7-1)
- (modified) llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp (+209)
- (added) llvm/test/CodeGen/AArch64/GlobalISel/combine-adde.mir (+300)
- (modified) llvm/test/CodeGen/AMDGPU/GlobalISel/addo.ll (+36-12)
- (modified) llvm/test/CodeGen/AMDGPU/GlobalISel/mul.ll (+1043-702)
- (modified) llvm/test/CodeGen/AMDGPU/GlobalISel/uaddsat.ll (+715-260)
``````````diff
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
index 23728636498ba0..abc2ebdfd878c2 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/CombinerHelper.h
@@ -810,12 +810,15 @@ class CombinerHelper {
/// Combine selects.
bool matchSelect(MachineInstr &MI, BuildFnTy &MatchInfo);
- /// Combine ands,
+ /// Combine ands.
bool matchAnd(MachineInstr &MI, BuildFnTy &MatchInfo);
- /// Combine ors,
+ /// Combine ors.
bool matchOr(MachineInstr &MI, BuildFnTy &MatchInfo);
+ /// Combine addes.
+ bool matchAddCarryInOut(MachineInstr &MI, BuildFnTy &MatchInfo);
+
private:
/// Checks for legality of an indexed variant of \p LdSt.
bool isIndexedLoadStoreLegal(GLoadStore &LdSt) const;
@@ -919,6 +922,7 @@ class CombinerHelper {
bool isZeroOrZeroSplat(Register Src, bool AllowUndefs);
bool isConstantSplatVector(Register Src, int64_t SplatValue,
bool AllowUndefs);
+ bool isConstantOrConstantVectorI(Register Src);
std::optional<APInt> getConstantOrConstantSplatVector(Register Src);
@@ -930,6 +934,8 @@ class CombinerHelper {
// Simplify (cmp cc0 x, y) (&& or ||) (cmp cc1 x, y) -> cmp cc2 x, y.
bool tryFoldLogicOfFCmps(GLogicalBinOp *Logic, BuildFnTy &MatchInfo);
+
+ bool isZExtOrTruncLegal(LLT ToTy, LLT FromTy) const;
};
} // namespace llvm
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
index f5a6528d10a973..e46d2d1aac0e86 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
@@ -359,6 +359,8 @@ class GBinOpCarryOut : public GenericMachineInstr {
Register getCarryOutReg() const { return getReg(1); }
MachineOperand &getLHS() { return getOperand(2); }
MachineOperand &getRHS() { return getOperand(3); }
+ Register getLHSReg() { return getOperand(2).getReg(); }
+ Register getRHSReg() { return getOperand(3).getReg(); }
static bool classof(const MachineInstr *MI) {
switch (MI->getOpcode()) {
@@ -448,6 +450,21 @@ class GAddSubCarryInOut : public GAddSubCarryOut {
}
};
+/// Represents overflowing add operations that also consume a carry-in.
+/// G_UADDE, G_SADDE
+class GAddCarryInOut : public GAddSubCarryInOut {
+public:
+ static bool classof(const MachineInstr *MI) {
+ switch (MI->getOpcode()) {
+ case TargetOpcode::G_UADDE:
+ case TargetOpcode::G_SADDE:
+ return true;
+ default:
+ return false;
+ }
+ }
+};
+
/// Represents a call to an intrinsic.
class GIntrinsic final : public GenericMachineInstr {
public:
diff --git a/llvm/include/llvm/Target/GlobalISel/Combine.td b/llvm/include/llvm/Target/GlobalISel/Combine.td
index 7eadb718f16415..3a82bc14885beb 100644
--- a/llvm/include/llvm/Target/GlobalISel/Combine.td
+++ b/llvm/include/llvm/Target/GlobalISel/Combine.td
@@ -1253,6 +1253,12 @@ def match_ors : GICombineRule<
[{ return Helper.matchOr(*${root}, ${matchinfo}); }]),
(apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+def match_addes : GICombineRule<
+ (defs root:$root, build_fn_matchinfo:$matchinfo),
+ (match (wip_match_opcode G_SADDE, G_UADDE):$root,
+ [{ return Helper.matchAddCarryInOut(*${root}, ${matchinfo}); }]),
+ (apply [{ Helper.applyBuildFn(*${root}, ${matchinfo}); }])>;
+
// Combines concat operations
def concat_matchinfo : GIDefMatchData<"SmallVector<Register>">;
def combine_concat_vector : GICombineRule<
@@ -1335,7 +1341,7 @@ def all_combines : GICombineGroup<[trivial_combines, insert_vec_elt_combines,
and_or_disjoint_mask, fma_combines, fold_binop_into_select,
sub_add_reg, select_to_minmax, redundant_binop_in_equality,
fsub_to_fneg, commute_constant_to_rhs, match_ands, match_ors,
- combine_concat_vector]>;
+ combine_concat_vector, match_addes]>;
// A combine group used to for prelegalizer combiners at -O0. The combines in
// this group have been selected based on experiments to balance code size and
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index 779ec49f4d13a7..2cfc7387ed976d 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -6342,6 +6342,23 @@ CombinerHelper::getConstantOrConstantSplatVector(Register Src) {
return Value;
}
+bool CombinerHelper::isConstantOrConstantVectorI(Register Src) {
+ auto IConstant = getIConstantVRegValWithLookThrough(Src, MRI);
+ if (IConstant)
+ return true;
+ GBuildVector *BuildVector = getOpcodeDef<GBuildVector>(Src, MRI);
+ if (!BuildVector)
+ return false;
+ unsigned NumSources = BuildVector->getNumSources();
+ for (unsigned I = 0; I < NumSources; ++I) {
+ std::optional<ValueAndVReg> IConstant =
+ getIConstantVRegValWithLookThrough(BuildVector->getSourceReg(I), MRI);
+ if (!IConstant)
+ return false;
+ }
+ return true; // FIXME: G_SPLAT_VECTOR
+}
+
// TODO: use knownbits to determine zeros
bool CombinerHelper::tryFoldSelectOfConstants(GSelect *Select,
BuildFnTy &MatchInfo) {
@@ -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) {
+ APInt LHS = MaybeLHS->zext(BitWidth);
+ APInt RHS = MaybeRHS->zext(BitWidth);
+ APInt CarryIn = MaybeCarryIn->zext(BitWidth);
+ bool FirstOverflowed = false;
+ bool SecondOverflowed = false;
+ APInt Result =
+ LHS.uadd_ov(RHS, FirstOverflowed).uadd_ov(CarryIn, SecondOverflowed);
+ MatchInfo = [=](MachineIRBuilder &B) {
+ B.buildConstant(Dst, Result);
+ B.buildConstant(Carry, FirstOverflowed | SecondOverflowed);
+ };
+ return true;
+ }
+ }
+
+ // canonicalize constant to RHS.
+ if (isConstantOrConstantVectorI(LHS) && !isConstantOrConstantVectorI(RHS)) {
+ if (IsSigned) {
+ MatchInfo = [=](MachineIRBuilder &B) {
+ B.buildSAdde(Dst, Carry, RHS, LHS, CarryIn);
+ };
+ return true;
+ } else {
+ MatchInfo = [=](MachineIRBuilder &B) {
+ B.buildUAdde(Dst, Carry, RHS, LHS, CarryIn);
+ };
+ return true;
+ }
+ }
+
+ // fold adde(LHS, RHS, 0) -> addo(LHS, RHS)
+ if (MaybeCarryIn && *MaybeCarryIn == 0) {
+ if (IsSigned && isLegalOrBeforeLegalizer(
+ {TargetOpcode::G_SADDO, {DstTy, CarryTy, OperandTy}})) {
+ MatchInfo = [=](MachineIRBuilder &B) {
+ B.buildSAddo(Dst, Carry, LHS, RHS);
+ };
+ return true;
+ } else if (!IsSigned &&
+ isLegalOrBeforeLegalizer(
+ {TargetOpcode::G_UADDO, {DstTy, CarryTy, OperandTy}}))
+ MatchInfo = [=](MachineIRBuilder &B) {
+ B.buildUAddo(Dst, Carry, LHS, RHS);
+ };
+ return true;
+ }
+
+ // fold adde(LHS, 0, Carry) -> addo(LHS, Carry)
+ if (MaybeRHS && *MaybeRHS == 0) {
+ if (IsSigned &&
+ isLegalOrBeforeLegalizer(
+ {TargetOpcode::G_SADDO, {DstTy, CarryTy, OperandTy}}) &&
+ isZExtOrTruncLegal(OperandTy, CarryInTy)) {
+ MatchInfo = [=](MachineIRBuilder &B) {
+ auto ZextCarryIn = B.buildZExtOrTrunc(OperandTy, CarryIn);
+ Register ZextCarryInReg = ZextCarryIn.getReg(0);
+ B.buildSAddo(Dst, Carry, LHS, ZextCarryInReg);
+ };
+ return true;
+ } else if (!IsSigned &&
+ isLegalOrBeforeLegalizer(
+ {TargetOpcode::G_UADDO, {DstTy, CarryTy, OperandTy}}) &&
+ isZExtOrTruncLegal(OperandTy, CarryInTy)) {
+ MatchInfo = [=](MachineIRBuilder &B) {
+ auto ZextCarryIn = B.buildZExtOrTrunc(OperandTy, CarryIn);
+ Register ZextCarryInReg = ZextCarryIn.getReg(0);
+ B.buildUAddo(Dst, Carry, LHS, ZextCarryInReg);
+ };
+ return true;
+ }
+ }
+
+ // We lower to 2*addo + 1*or.
+ if (IsSigned &&
+ isLegalOrBeforeLegalizer(
+ {TargetOpcode::G_SADDO, {DstTy, CarryTy, OperandTy}}) &&
+ isLegalOrBeforeLegalizer({TargetOpcode::G_OR, {DstTy}}) &&
+ isZExtOrTruncLegal(OperandTy, CarryInTy)) {
+ MatchInfo = [=](MachineIRBuilder &B) {
+ auto First = B.buildSAddo(DstTy, CarryTy, LHS, RHS);
+ Register FirstResult = First.getReg(0);
+ Register FirstCarry = First.getReg(1);
+ auto ZextCarryIn = B.buildZExtOrTrunc(OperandTy, CarryIn);
+ auto Second = B.buildSAddo(DstTy, CarryTy, FirstResult, ZextCarryIn);
+ Register Result = Second.getReg(0);
+ Register SecondCarry = Second.getReg(1);
+ B.buildCopy(Dst, Result);
+ B.buildOr(Carry, FirstCarry, SecondCarry);
+ };
+ return true;
+ } else if (!IsSigned &&
+ isLegalOrBeforeLegalizer(
+ {TargetOpcode::G_UADDO, {DstTy, CarryTy, OperandTy}}) &&
+ isLegalOrBeforeLegalizer({TargetOpcode::G_OR, {DstTy}}) &&
+ isZExtOrTruncLegal(OperandTy, CarryInTy)) {
+ MatchInfo = [=](MachineIRBuilder &B) {
+ auto First = B.buildUAddo(DstTy, CarryTy, LHS, RHS);
+ Register FirstResult = First.getReg(0);
+ Register FirstCarry = First.getReg(1);
+ auto ZextCarryIn = B.buildZExtOrTrunc(OperandTy, CarryIn);
+ auto Second = B.buildUAddo(DstTy, CarryTy, FirstResult, ZextCarryIn);
+ Register Result = Second.getReg(0);
+ Register SecondCarry = Second.getReg(1);
+ B.buildCopy(Dst, Result);
+ B.buildOr(Carry, FirstCarry, SecondCarry);
+ };
+ return true;
+ }
+
+ return false;
+}
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/combine-adde.mir b/llvm/test/CodeGen/AArch64/GlobalISel/combine-adde.mir
new file mode 100644
index 00000000000000..61c7f56f4b2605
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/combine-adde.mir
@@ -0,0 +1,300 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
+# RUN: llc -debugify-and-strip-all-safe -run-pass=aarch64-prelegalizer-combiner -verify-machineinstrs -mtriple aarch64-unknown-unknown %s -o - | FileCheck %s
+---
+# add, _ = sadde(_, _, In)
+name: carryout_unused
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: carryout_unused
+ ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x3
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x4
+ ; CHECK-NEXT: %carry_in:_(s1) = G_TRUNC [[COPY1]](s64)
+ ; CHECK-NEXT: [[ADD:%[0-9]+]]:_(s64) = G_ADD [[COPY]], [[COPY]]
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT %carry_in(s1)
+ ; CHECK-NEXT: %add:_(s64) = G_ADD [[ADD]], [[ZEXT]]
+ ; CHECK-NEXT: $x0 = COPY %add(s64)
+ %0:_(s64) = COPY $x0
+ %1:_(s64) = COPY $x1
+ %2:_(s64) = COPY $x2
+ %3:_(s64) = COPY $x3
+ %4:_(s64) = COPY $x4
+ %lhs:_(s64) = COPY %3
+ %rhs:_(s64) = COPY %3
+ %carry_in:_(s1) = G_TRUNC %4
+ %add:_(s64), %carry_out:_(s1) = G_SADDE %lhs, %rhs, %carry_in
+ $x0 = COPY %add
+...
+---
+# add, _ = uadde(_, _, In)
+name: carryout_unused_unsigned
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: carryout_unused_unsigned
+ ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x3
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x4
+ ; CHECK-NEXT: %carry_in:_(s1) = G_TRUNC [[COPY1]](s64)
+ ; CHECK-NEXT: %add:_(s64), %carry_out:_(s1) = G_UADDE [[COPY]], [[COPY]], %carry_in
+ ; CHECK-NEXT: $x0 = COPY %add(s64)
+ %0:_(s64) = COPY $x0
+ %1:_(s64) = COPY $x1
+ %2:_(s64) = COPY $x2
+ %3:_(s64) = COPY $x3
+ %4:_(s64) = COPY $x4
+ %lhs:_(s64) = COPY %3
+ %rhs:_(s64) = COPY %3
+ %carry_in:_(s1) = G_TRUNC %4
+ %add:_(s64), %carry_out:_(s1) = G_UADDE %lhs, %rhs, %carry_in
+ $x0 = COPY %add
+...
+---
+# add, multi_c = sadde(L, R, In)
+name: multi_use_unsigned
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: multi_use_unsigned
+ ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x3
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x4
+ ; CHECK-NEXT: %carry_in:_(s1) = G_TRUNC [[COPY1]](s64)
+ ; CHECK-NEXT: %add:_(s64), %carry_out:_(s1) = G_UADDE [[COPY]], [[COPY]], %carry_in
+ ; CHECK-NEXT: %carry_out_ext:_(s64) = G_ANYEXT %carry_out(s1)
+ ; CHECK-NEXT: %carry_out_ext2:_(s64) = G_ANYEXT %carry_out(s1)
+ ; CHECK-NEXT: $x0 = COPY %add(s64)
+ ; CHECK-NEXT: $x1 = COPY %carry_out_ext(s64)
+ ; CHECK-NEXT: $x2 = COPY %carry_out_ext2(s64)
+ %0:_(s64) = COPY $x0
+ %1:_(s64) = COPY $x1
+ %2:_(s64) = COPY $x2
+ %3:_(s64) = COPY $x3
+ %4:_(s64) = COPY $x4
+ %lhs:_(s64) = COPY %3
+ %rhs:_(s64) = COPY %3
+ %carry_in:_(s1) = G_TRUNC %4
+ %add:_(s64), %carry_out:_(s1) = G_UADDE %lhs, %rhs, %carry_in
+ %carry_out_ext:_(s64) = G_ANYEXT %carry_out
+ %carry_out_ext2:_(s64) = G_ANYEXT %carry_out
+ $x0 = COPY %add
+ $x1 = COPY %carry_out_ext
+ $x2 = COPY %carry_out_ext2
+...
+---
+# add, c = sadde(L, R, In)
+name: constant_fold_signed
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: constant_fold_signed
+ ; CHECK: %add:_(s64) = G_CONSTANT i64 29
+ ; CHECK-NEXT: %carry_out_ext:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: $x0 = COPY %add(s64)
+ ; CHECK-NEXT: $x1 = COPY %carry_out_ext(s64)
+ %0:_(s64) = COPY $x0
+ %1:_(s64) = COPY $x1
+ %2:_(s64) = COPY $x2
+ %3:_(s64) = COPY $x3
+ %4:_(s64) = G_CONSTANT i64 1
+ %lhs:_(s64) = G_CONSTANT i64 11
+ %rhs:_(s64) = G_CONSTANT i64 17
+ %carry_in:_(s1) = G_CONSTANT i1 1
+ %add:_(s64), %carry_out:_(s1) = G_SADDE %lhs, %rhs, %carry_in
+ %carry_out_ext:_(s64) = G_ANYEXT %carry_out
+ $x0 = COPY %add
+ $x1 = COPY %carry_out_ext
+...
+---
+# add, c = uadde(L, R, In)
+name: constant_fold_unsigned
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: constant_fold_unsigned
+ ; CHECK: %add:_(s64) = G_CONSTANT i64 27
+ ; CHECK-NEXT: %carry_out_ext:_(s64) = G_CONSTANT i64 0
+ ; CHECK-NEXT: $x0 = COPY %add(s64)
+ ; CHECK-NEXT: $x1 = COPY %carry_out_ext(s64)
+ %0:_(s64) = COPY $x0
+ %1:_(s64) = COPY $x1
+ %2:_(s64) = COPY $x2
+ %3:_(s64) = COPY $x3
+ %4:_(s64) = G_CONSTANT i64 1
+ %lhs:_(s64) = G_CONSTANT i64 19
+ %rhs:_(s64) = G_CONSTANT i64 7
+ %carry_in:_(s1) = G_CONSTANT i1 1
+ %add:_(s64), %carry_out:_(s1) = G_UADDE %lhs, %rhs, %carry_in
+ %carry_out_ext:_(s64) = G_ANYEXT %carry_out
+ $x0 = COPY %add
+ $x1 = COPY %carry_out_ext
+...
+---
+# add, c = uadde(L, R, In)
+name: canonicalize_to_rhs_plus_lower
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: canonicalize_to_rhs_plus_lower
+ ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x3
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x4
+ ; CHECK-NEXT: %lhs:_(s64) = G_CONSTANT i64 19
+ ; CHECK-NEXT: %carry_in:_(s1) = G_TRUNC [[COPY1]](s64)
+ ; CHECK-NEXT: [[UADDO:%[0-9]+]]:_(s64), [[UADDO1:%[0-9]+]]:_(s1) = G_UADDO [[COPY]], %lhs
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT %carry_in(s1)
+ ; CHECK-NEXT: [[UADDO2:%[0-9]+]]:_(s64), [[UADDO3:%[0-9]+]]:_(s1) = G_UADDO [[UADDO]], [[ZEXT]]
+ ; CHECK-NEXT: %carry_out:_(s1) = G_OR [[UADDO1]], [[UADDO3]]
+ ; CHECK-NEXT: %carry_out_ext:_(s64) = G_ANYEXT %carry_out(s1)
+ ; CHECK-NEXT: $x0 = COPY [[UADDO2]](s64)
+ ; CHECK-NEXT: $x1 = COPY %carry_out_ext(s64)
+ %0:_(s64) = COPY $x0
+ %1:_(s64) = COPY $x1
+ %2:_(s64) = COPY $x2
+ %3:_(s64) = COPY $x3
+ %4:_(s64) = COPY $x4
+ %lhs:_(s64) = G_CONSTANT i64 19
+ %rhs:_(s64) = COPY %3
+ %carry_in:_(s1) = G_TRUNC %4
+ %add:_(s64), %carry_out:_(s1) = G_UADDE %lhs, %rhs, %carry_in
+ %carry_out_ext:_(s64) = G_ANYEXT %carry_out
+ $x0 = COPY %add
+ $x1 = COPY %carry_out_ext
+...
+---
+# add, c = sadde(L, R, 0)
+name: fold_to_addo_l_r
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: fold_to_addo_l_r
+ ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x3
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x4
+ ; CHECK-NEXT: %add:_(s64), %carry_out:_(s1) = G_SADDO [[COPY]], [[COPY1]]
+ ; CHECK-NEXT: %carry_out_ext:_(s64) = G_ANYEXT %carry_out(s1)
+ ; CHECK-NEXT: $x0 = COPY %add(s64)
+ ; CHECK-NEXT: $x1 = COPY %carry_out_ext(s64)
+ %0:_(s64) = COPY $x0
+ %1:_(s64) = COPY $x1
+ %2:_(s64) = COPY $x2
+ %3:_(s64) = COPY $x3
+ %4:_(s64) = COPY $x4
+ %lhs:_(s64) = COPY %3
+ %rhs:_(s64) = COPY %4
+ %carry_in:_(s1) = G_CONSTANT i1 0
+ %add:_(s64), %carry_out:_(s1) = G_SADDE %lhs, %rhs, %carry_in
+ %carry_out_ext:_(s64) = G_ANYEXT %carry_out
+ $x0 = COPY %add
+ $x1 = COPY %carry_out_ext
+...
+---
+# add, c = sadde(L, 0, CarryIn)
+name: fold_to_addo_l_carryin
+body: |
+ bb.0.entry:
+ ; CHECK-LABEL: name: fold_to_addo_l_carryin
+ ; CHECK: [[COPY:%[0-9]+]]:_(s64) = COPY $x3
+ ; CHECK-NEXT: [[COPY1:%[0-9]+]]:_(s64) = COPY $x4
+ ; CHECK-NEXT: %carry_in:_(s1) = G_TRUNC [[COPY1]](s64)
+ ; CHECK-NEXT: [[ZEXT:%[0-9]+]]:_(s64) = G_ZEXT %carry_in(s1)
+ ; CHECK-NEXT: %add:_(s64), %carry_out:_(s1) = G_SADDO [[COPY]], [[ZEXT]]
+ ; CHECK-NEXT: %carry_out_ext:_(s64) = G_ANYEXT %carry_out(s1)
+ ; CHECK-NEXT: $x0 = COPY %add(s64)
+ ; CHECK-NEXT: $x1 = COPY %carry_out_ext(s64)
+ %0:_(s64) = COPY $x0
+ %1:_(s64) = COPY $x1
+ %2:_(s64) = COPY $x2
+ %3:_(s64) = COPY $x3
+ %4:_(s64) = COPY $x4
+ %lhs:_(s64) = COPY %3
+ %rhs:_(s64) ...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/82413
More information about the llvm-commits
mailing list