Index: llvm/include/llvm/CodeGen/TargetLowering.h =================================================================== --- llvm/include/llvm/CodeGen/TargetLowering.h +++ llvm/include/llvm/CodeGen/TargetLowering.h @@ -2694,6 +2694,8 @@ case ISD::AVGFLOORU: case ISD::AVGCEILS: case ISD::AVGCEILU: + case ISD::ABDS: + case ISD::ABDU: return true; default: return false; } Index: llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ llvm/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -434,6 +434,7 @@ SDValue visitMULHU(SDNode *N); SDValue visitMULHS(SDNode *N); SDValue visitAVG(SDNode *N); + SDValue visitABD(SDNode *N); SDValue visitSMUL_LOHI(SDNode *N); SDValue visitUMUL_LOHI(SDNode *N); SDValue visitMULO(SDNode *N); @@ -1720,6 +1721,8 @@ case ISD::AVGFLOORU: case ISD::AVGCEILS: case ISD::AVGCEILU: return visitAVG(N); + case ISD::ABDS: + case ISD::ABDU: return visitABD(N); case ISD::SMUL_LOHI: return visitSMUL_LOHI(N); case ISD::UMUL_LOHI: return visitUMUL_LOHI(N); case ISD::SMULO: @@ -4891,6 +4894,43 @@ return SDValue(); } +SDValue DAGCombiner::visitABD(SDNode *N) { + unsigned Opcode = N->getOpcode(); + SDValue N0 = N->getOperand(0); + SDValue N1 = N->getOperand(1); + EVT VT = N->getValueType(0); + SDLoc DL(N); + + // fold (abd c1, c2) + if (SDValue C = DAG.FoldConstantArithmetic(Opcode, DL, VT, {N0, N1})) + return C; + + // canonicalize constant to RHS. + if (DAG.isConstantIntBuildVectorOrConstantInt(N0) && + !DAG.isConstantIntBuildVectorOrConstantInt(N1)) + return DAG.getNode(Opcode, DL, N->getVTList(), N1, N0); + + if (VT.isVector()) { + if (SDValue FoldedVOp = SimplifyVBinOp(N, DL)) + return FoldedVOp; + + // fold (abds x, 0) -> abs x + // fold (abdu x, 0) -> x + if (ISD::isConstantSplatVectorAllZeros(N1.getNode())) { + if (Opcode == ISD::ABDS) + return DAG.getNode(ISD::ABS, DL, VT, N0); + if (Opcode == ISD::ABDU) + return N0; + } + } + + // fold (abd x, undef) -> 0 + if (N0.isUndef() || N1.isUndef()) + return DAG.getConstant(0, DL, VT); + + return SDValue(); +} + /// Perform optimizations common to nodes that compute two values. LoOp and HiOp /// give the opcodes for the two computations that are being performed. Return /// true if a simplification was made. Index: llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp =================================================================== --- llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -5723,6 +5723,10 @@ APInt C2Ext = C2.zext(FullWidth); return (C1Ext + C2Ext + 1).extractBits(C1.getBitWidth(), 1); } + case ISD::ABDS: + return APIntOps::smax(C1, C2) - APIntOps::smin(C1, C2); + case ISD::ABDU: + return APIntOps::umax(C1, C2) - APIntOps::umin(C1, C2); } return std::nullopt; } Index: llvm/test/CodeGen/AArch64/abd-combine.ll =================================================================== --- llvm/test/CodeGen/AArch64/abd-combine.ll +++ llvm/test/CodeGen/AArch64/abd-combine.ll @@ -129,7 +129,7 @@ ; CHECK-LABEL: abdu_i_const_lhs: ; CHECK: // %bb.0: ; CHECK-NEXT: movi v1.8h, #1 -; CHECK-NEXT: uabd v0.8h, v1.8h, v0.8h +; CHECK-NEXT: uabd v0.8h, v0.8h, v1.8h ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> , <8 x i16> %src1) ret <8 x i16> %result @@ -138,8 +138,6 @@ define <8 x i16> @abdu_i_const_zero(<8 x i16> %src1) { ; CHECK-LABEL: abdu_i_const_zero: ; CHECK: // %bb.0: -; CHECK-NEXT: movi v1.2d, #0000000000000000 -; CHECK-NEXT: uabd v0.8h, v1.8h, v0.8h ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> , <8 x i16> %src1) ret <8 x i16> %result @@ -148,9 +146,7 @@ define <8 x i16> @abdu_i_const_both() { ; CHECK-LABEL: abdu_i_const_both: ; CHECK: // %bb.0: -; CHECK-NEXT: movi v0.8h, #1 -; CHECK-NEXT: movi v1.8h, #3 -; CHECK-NEXT: uabd v0.8h, v1.8h, v0.8h +; CHECK-NEXT: movi v0.8h, #2 ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> , <8 x i16> ) ret <8 x i16> %result @@ -159,9 +155,7 @@ define <8 x i16> @abdu_i_const_bothhigh() { ; CHECK-LABEL: abdu_i_const_bothhigh: ; CHECK: // %bb.0: -; CHECK-NEXT: movi v0.2d, #0xffffffffffffffff -; CHECK-NEXT: mvni v1.8h, #1 -; CHECK-NEXT: uabd v0.8h, v1.8h, v0.8h +; CHECK-NEXT: movi v0.8h, #1 ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> , <8 x i16> ) ret <8 x i16> %result @@ -170,10 +164,8 @@ define <8 x i16> @abdu_i_const_onehigh() { ; CHECK-LABEL: abdu_i_const_onehigh: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, #32766 -; CHECK-NEXT: movi v0.8h, #1 -; CHECK-NEXT: dup v1.8h, w8 -; CHECK-NEXT: uabd v0.8h, v1.8h, v0.8h +; CHECK-NEXT: mov w8, #32765 +; CHECK-NEXT: dup v0.8h, w8 ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> , <8 x i16> ) ret <8 x i16> %result @@ -182,10 +174,7 @@ define <8 x i16> @abdu_i_const_oneneg() { ; CHECK-LABEL: abdu_i_const_oneneg: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, #32766 -; CHECK-NEXT: mvni v1.8h, #1 -; CHECK-NEXT: dup v0.8h, w8 -; CHECK-NEXT: uabd v0.8h, v0.8h, v1.8h +; CHECK-NEXT: movi v0.8h, #128, lsl #8 ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> , <8 x i16> ) ret <8 x i16> %result @@ -194,8 +183,7 @@ define <8 x i16> @abdu_i_zero(<8 x i16> %t, <8 x i16> %src1) { ; CHECK-LABEL: abdu_i_zero: ; CHECK: // %bb.0: -; CHECK-NEXT: movi v0.2d, #0000000000000000 -; CHECK-NEXT: uabd v0.8h, v0.8h, v1.8h +; CHECK-NEXT: mov v0.16b, v1.16b ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> , <8 x i16> %src1) ret <8 x i16> %result @@ -204,7 +192,7 @@ define <8 x i16> @abdu_i_undef(<8 x i16> %t, <8 x i16> %src1) { ; CHECK-LABEL: abdu_i_undef: ; CHECK: // %bb.0: -; CHECK-NEXT: uabd v0.8h, v0.8h, v1.8h +; CHECK-NEXT: movi v0.2d, #0000000000000000 ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.uabd.v8i16(<8 x i16> undef, <8 x i16> %src1) ret <8 x i16> %result @@ -347,7 +335,7 @@ ; CHECK-LABEL: abds_i_const_lhs: ; CHECK: // %bb.0: ; CHECK-NEXT: movi v1.8h, #1 -; CHECK-NEXT: sabd v0.8h, v1.8h, v0.8h +; CHECK-NEXT: sabd v0.8h, v0.8h, v1.8h ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> , <8 x i16> %src1) ret <8 x i16> %result @@ -356,8 +344,7 @@ define <8 x i16> @abds_i_const_zero(<8 x i16> %src1) { ; CHECK-LABEL: abds_i_const_zero: ; CHECK: // %bb.0: -; CHECK-NEXT: movi v1.2d, #0000000000000000 -; CHECK-NEXT: sabd v0.8h, v1.8h, v0.8h +; CHECK-NEXT: abs v0.8h, v0.8h ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> , <8 x i16> %src1) ret <8 x i16> %result @@ -366,9 +353,7 @@ define <8 x i16> @abds_i_const_both() { ; CHECK-LABEL: abds_i_const_both: ; CHECK: // %bb.0: -; CHECK-NEXT: movi v0.8h, #1 -; CHECK-NEXT: movi v1.8h, #3 -; CHECK-NEXT: sabd v0.8h, v1.8h, v0.8h +; CHECK-NEXT: movi v0.8h, #2 ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> , <8 x i16> ) ret <8 x i16> %result @@ -377,10 +362,7 @@ define <8 x i16> @abds_i_const_bothhigh() { ; CHECK-LABEL: abds_i_const_bothhigh: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, #32766 -; CHECK-NEXT: mvni v1.8h, #128, lsl #8 -; CHECK-NEXT: dup v0.8h, w8 -; CHECK-NEXT: sabd v0.8h, v0.8h, v1.8h +; CHECK-NEXT: movi v0.8h, #1 ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> , <8 x i16> ) ret <8 x i16> %result @@ -389,10 +371,8 @@ define <8 x i16> @abds_i_const_onehigh() { ; CHECK-LABEL: abds_i_const_onehigh: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, #32766 -; CHECK-NEXT: movi v0.8h, #1 -; CHECK-NEXT: dup v1.8h, w8 -; CHECK-NEXT: sabd v0.8h, v1.8h, v0.8h +; CHECK-NEXT: mov w8, #32765 +; CHECK-NEXT: dup v0.8h, w8 ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> , <8 x i16> ) ret <8 x i16> %result @@ -401,10 +381,7 @@ define <8 x i16> @abds_i_const_oneneg() { ; CHECK-LABEL: abds_i_const_oneneg: ; CHECK: // %bb.0: -; CHECK-NEXT: mov w8, #32766 -; CHECK-NEXT: mvni v1.8h, #1 -; CHECK-NEXT: dup v0.8h, w8 -; CHECK-NEXT: sabd v0.8h, v0.8h, v1.8h +; CHECK-NEXT: movi v0.8h, #128, lsl #8 ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> , <8 x i16> ) ret <8 x i16> %result @@ -413,8 +390,7 @@ define <8 x i16> @abds_i_zero(<8 x i16> %t, <8 x i16> %src1) { ; CHECK-LABEL: abds_i_zero: ; CHECK: // %bb.0: -; CHECK-NEXT: movi v0.2d, #0000000000000000 -; CHECK-NEXT: sabd v0.8h, v0.8h, v1.8h +; CHECK-NEXT: abs v0.8h, v1.8h ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> , <8 x i16> %src1) ret <8 x i16> %result @@ -423,7 +399,7 @@ define <8 x i16> @abds_i_undef(<8 x i16> %t, <8 x i16> %src1) { ; CHECK-LABEL: abds_i_undef: ; CHECK: // %bb.0: -; CHECK-NEXT: sabd v0.8h, v0.8h, v1.8h +; CHECK-NEXT: movi v0.2d, #0000000000000000 ; CHECK-NEXT: ret %result = call <8 x i16> @llvm.aarch64.neon.sabd.v8i16(<8 x i16> undef, <8 x i16> %src1) ret <8 x i16> %result Index: llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll =================================================================== --- llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll +++ llvm/test/CodeGen/AArch64/arm64-neon-aba-abd.ll @@ -200,9 +200,7 @@ ; CHECK-LABEL: test_sabd_v2i32_const: ; CHECK: // %bb.0: ; CHECK-NEXT: adrp x8, .LCPI19_0 -; CHECK-NEXT: movi d0, #0x00ffffffff0000 -; CHECK-NEXT: ldr d1, [x8, :lo12:.LCPI19_0] -; CHECK-NEXT: sabd v0.2s, v1.2s, v0.2s +; CHECK-NEXT: ldr d0, [x8, :lo12:.LCPI19_0] ; CHECK-NEXT: ret %1 = tail call <2 x i32> @llvm.aarch64.neon.sabd.v2i32( <2 x i32> , Index: llvm/test/CodeGen/Thumb2/mve-vabdus.ll =================================================================== --- llvm/test/CodeGen/Thumb2/mve-vabdus.ll +++ llvm/test/CodeGen/Thumb2/mve-vabdus.ll @@ -617,9 +617,8 @@ define arm_aapcs_vfpcc <4 x i32> @vabd_v4u32_commutative(<4 x i32> %src1, <4 x i32> %src2) { ; CHECK-LABEL: vabd_v4u32_commutative: ; CHECK: @ %bb.0: -; CHECK-NEXT: vabd.u32 q2, q1, q0 -; CHECK-NEXT: vabd.u32 q0, q0, q1 -; CHECK-NEXT: vadd.i32 q0, q0, q2 +; CHECK-NEXT: vabd.u32 q0, q1, q0 +; CHECK-NEXT: vadd.i32 q0, q0, q0 ; CHECK-NEXT: bx lr %azextsrc1 = zext <4 x i32> %src1 to <4 x i64> %azextsrc2 = zext <4 x i32> %src2 to <4 x i64> @@ -642,15 +641,11 @@ define arm_aapcs_vfpcc <4 x i32> @vabd_v4u32_shuffle(<4 x i32> %src1, <4 x i32> %src2) { ; CHECK-LABEL: vabd_v4u32_shuffle: ; CHECK: @ %bb.0: -; CHECK-NEXT: vmov.f32 s8, s7 -; CHECK-NEXT: vmov.f32 s9, s6 -; CHECK-NEXT: vmov.f32 s10, s5 -; CHECK-NEXT: vmov.f32 s11, s4 -; CHECK-NEXT: vmov.f32 s4, s3 -; CHECK-NEXT: vmov.f32 s5, s2 -; CHECK-NEXT: vmov.f32 s6, s1 -; CHECK-NEXT: vmov.f32 s7, s0 -; CHECK-NEXT: vabd.u32 q0, q1, q2 +; CHECK-NEXT: vabd.u32 q1, q0, q1 +; CHECK-NEXT: vmov.f32 s0, s7 +; CHECK-NEXT: vmov.f32 s1, s6 +; CHECK-NEXT: vmov.f32 s2, s5 +; CHECK-NEXT: vmov.f32 s3, s4 ; CHECK-NEXT: bx lr %s1 = shufflevector <4 x i32> %src1, <4 x i32> undef, <4 x i32> %s2 = shufflevector <4 x i32> %src2, <4 x i32> undef, <4 x i32>