[llvm] Reland "[AArch64] AArch64TargetLowering::computeKnownBitsForTargetNode - add support for AArch64ISD::MOV/MVN constants" (PR #155696)
Yatao Wang via llvm-commits
llvm-commits at lists.llvm.org
Wed Aug 27 14:13:04 PDT 2025
https://github.com/ningxinr created https://github.com/llvm/llvm-project/pull/155696
Reland #155503
Per suggestion by @davemgreen, add mask on the shift amount to prevent shifting more than the bitwidth. This change is confirmed to fix the lit tests failures on x86 sanitizer bots.
WIP for reproducing the aarch64 sanitizer bots failures.
Also, I think that ideally I should add some tests to catch these failures in pre-commit unit tests and/or lit tests, but right now I am still investigating how to do that.
>From 24df1988c46331600254bf633c14eae755ab76f5 Mon Sep 17 00:00:00 2001
From: ningxinr <ningxinr at live.cn>
Date: Wed, 27 Aug 2025 10:58:44 -0700
Subject: [PATCH 1/2] Reland "[AArch64]
AArch64TargetLowering::computeKnownBitsForTargetNode - add support for
AArch64ISD::MOV/MVN constants" (#155503)"
This reverts commit 7d26150c2a1ce481d0dad25460b4cadcd8945af9.
---
.../Target/AArch64/AArch64ISelLowering.cpp | 36 ++++++
.../AArch64/AArch64SelectionDAGTest.cpp | 114 ++++++++++++++++++
2 files changed, 150 insertions(+)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index b8335113e4687..0bfb29f688678 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -2626,6 +2626,32 @@ void AArch64TargetLowering::computeKnownBitsForTargetNode(
<< Op->getConstantOperandVal(1)));
break;
}
+ case AArch64ISD::MOVImsl: {
+ Known = KnownBits::makeConstant(
+ APInt(Known.getBitWidth(), ~(~Op->getConstantOperandVal(0)
+ << Op->getConstantOperandVal(1))));
+ break;
+ }
+ case AArch64ISD::MOVIedit: {
+ Known = KnownBits::makeConstant(APInt(
+ Known.getBitWidth(),
+ AArch64_AM::decodeAdvSIMDModImmType10(Op->getConstantOperandVal(0))));
+ break;
+ }
+ case AArch64ISD::MVNIshift: {
+ Known = KnownBits::makeConstant(
+ APInt(Known.getBitWidth(),
+ ~(Op->getConstantOperandVal(0) << Op->getConstantOperandVal(1)),
+ /*isSigned*/ false, /*implicitTrunc*/ true));
+ break;
+ }
+ case AArch64ISD::MVNImsl: {
+ Known = KnownBits::makeConstant(
+ APInt(Known.getBitWidth(),
+ (~Op->getConstantOperandVal(0) << Op->getConstantOperandVal(1)),
+ /*isSigned*/ false, /*implicitTrunc*/ true));
+ break;
+ }
case AArch64ISD::LOADgot:
case AArch64ISD::ADDlow: {
if (!Subtarget->isTargetILP32())
@@ -30639,6 +30665,16 @@ bool AArch64TargetLowering::isTargetCanonicalConstantNode(SDValue Op) const {
return Op.getOpcode() == AArch64ISD::DUP ||
Op.getOpcode() == AArch64ISD::MOVI ||
Op.getOpcode() == AArch64ISD::MOVIshift ||
+ Op.getOpcode() == AArch64ISD::MOVImsl ||
+ Op.getOpcode() == AArch64ISD::MOVIedit ||
+ Op.getOpcode() == AArch64ISD::MVNIshift ||
+ Op.getOpcode() == AArch64ISD::MVNImsl ||
+ // Ignoring fneg(movi(0)), because if it is folded to FPConstant(-0.0),
+ // ISel will select fmov(mov i64 0x8000000000000000), resulting in a
+ // fmov from fpr to gpr, which is more expensive than fneg(movi(0))
+ (Op.getOpcode() == ISD::FNEG &&
+ Op.getOperand(0).getOpcode() == AArch64ISD::MOVIedit &&
+ Op.getOperand(0).getConstantOperandVal(0) == 0) ||
(Op.getOpcode() == ISD::EXTRACT_SUBVECTOR &&
Op.getOperand(0).getOpcode() == AArch64ISD::DUP) ||
TargetLowering::isTargetCanonicalConstantNode(Op);
diff --git a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
index f06f03bb35a5d..675fdc7b0db3b 100644
--- a/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
+++ b/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
@@ -318,6 +318,120 @@ TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_UADDO_CARRY) {
EXPECT_EQ(Known.One, APInt(8, 0x86));
}
+// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
+TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_MOVI) {
+ SDLoc Loc;
+ auto IntSca32VT = MVT::i32;
+ auto Int8Vec8VT = MVT::v8i8;
+ auto Int16Vec8VT = MVT::v16i8;
+ auto Int4Vec16VT = MVT::v4i16;
+ auto Int8Vec16VT = MVT::v8i16;
+ auto Int2Vec32VT = MVT::v2i32;
+ auto Int4Vec32VT = MVT::v4i32;
+ auto IntVec64VT = MVT::v1i64;
+ auto Int2Vec64VT = MVT::v2i64;
+ auto N165 = DAG->getConstant(0x000000A5, Loc, IntSca32VT);
+ KnownBits Known;
+
+ auto OpMOVIedit64 = DAG->getNode(AArch64ISD::MOVIedit, Loc, IntVec64VT, N165);
+ Known = DAG->computeKnownBits(OpMOVIedit64);
+ EXPECT_EQ(Known.Zero, APInt(64, 0x00FF00FFFF00FF00));
+ EXPECT_EQ(Known.One, APInt(64, 0xFF00FF0000FF00FF));
+
+ auto OpMOVIedit128 =
+ DAG->getNode(AArch64ISD::MOVIedit, Loc, Int2Vec64VT, N165);
+ Known = DAG->computeKnownBits(OpMOVIedit128);
+ EXPECT_EQ(Known.Zero, APInt(64, 0x00FF00FFFF00FF00));
+ EXPECT_EQ(Known.One, APInt(64, 0xFF00FF0000FF00FF));
+
+ auto N264 = DAG->getConstant(264, Loc, IntSca32VT);
+ auto OpMOVImsl64 =
+ DAG->getNode(AArch64ISD::MOVImsl, Loc, Int2Vec32VT, N165, N264);
+ Known = DAG->computeKnownBits(OpMOVImsl64);
+ EXPECT_EQ(Known.Zero, APInt(32, 0xFFFF5A00));
+ EXPECT_EQ(Known.One, APInt(32, 0x0000A5FF));
+
+ auto N272 = DAG->getConstant(272, Loc, IntSca32VT);
+ auto OpMOVImsl128 =
+ DAG->getNode(AArch64ISD::MOVImsl, Loc, Int4Vec32VT, N165, N272);
+ Known = DAG->computeKnownBits(OpMOVImsl128);
+ EXPECT_EQ(Known.Zero, APInt(32, 0xFF5A0000));
+ EXPECT_EQ(Known.One, APInt(32, 0x00A5FFFF));
+
+ auto OpMVNImsl64 =
+ DAG->getNode(AArch64ISD::MVNImsl, Loc, Int2Vec32VT, N165, N272);
+ Known = DAG->computeKnownBits(OpMVNImsl64);
+ EXPECT_EQ(Known.Zero, APInt(32, 0x00A5FFFF));
+ EXPECT_EQ(Known.One, APInt(32, 0xFF5A0000));
+
+ auto OpMVNImsl128 =
+ DAG->getNode(AArch64ISD::MVNImsl, Loc, Int4Vec32VT, N165, N264);
+ Known = DAG->computeKnownBits(OpMVNImsl128);
+ EXPECT_EQ(Known.Zero, APInt(32, 0x0000A5FF));
+ EXPECT_EQ(Known.One, APInt(32, 0xFFFF5A00));
+
+ auto N0 = DAG->getConstant(0, Loc, IntSca32VT);
+ auto OpMOVIshift2Vec32 =
+ DAG->getNode(AArch64ISD::MOVIshift, Loc, Int2Vec32VT, N165, N0);
+ Known = DAG->computeKnownBits(OpMOVIshift2Vec32);
+ EXPECT_EQ(Known.Zero, APInt(32, 0xFFFFFF5A));
+ EXPECT_EQ(Known.One, APInt(32, 0x000000A5));
+
+ auto N24 = DAG->getConstant(24, Loc, IntSca32VT);
+ auto OpMOVIshift4Vec32 =
+ DAG->getNode(AArch64ISD::MOVIshift, Loc, Int4Vec32VT, N165, N24);
+ Known = DAG->computeKnownBits(OpMOVIshift4Vec32);
+ EXPECT_EQ(Known.Zero, APInt(32, 0x5AFFFFFF));
+ EXPECT_EQ(Known.One, APInt(32, 0xA5000000));
+
+ auto OpMVNIshift2Vec32 =
+ DAG->getNode(AArch64ISD::MVNIshift, Loc, Int2Vec32VT, N165, N24);
+ Known = DAG->computeKnownBits(OpMVNIshift2Vec32);
+ EXPECT_EQ(Known.Zero, APInt(32, 0xA5000000));
+ EXPECT_EQ(Known.One, APInt(32, 0x5AFFFFFF));
+
+ auto OpMVNIshift4Vec32 =
+ DAG->getNode(AArch64ISD::MVNIshift, Loc, Int4Vec32VT, N165, N0);
+ Known = DAG->computeKnownBits(OpMVNIshift4Vec32);
+ EXPECT_EQ(Known.Zero, APInt(32, 0x000000A5));
+ EXPECT_EQ(Known.One, APInt(32, 0xFFFFFF5A));
+
+ auto N8 = DAG->getConstant(8, Loc, IntSca32VT);
+ auto OpMOVIshift4Vec16 =
+ DAG->getNode(AArch64ISD::MOVIshift, Loc, Int4Vec16VT, N165, N0);
+ Known = DAG->computeKnownBits(OpMOVIshift4Vec16);
+ EXPECT_EQ(Known.Zero, APInt(16, 0xFF5A));
+ EXPECT_EQ(Known.One, APInt(16, 0x00A5));
+
+ auto OpMOVIshift8Vec16 =
+ DAG->getNode(AArch64ISD::MOVIshift, Loc, Int8Vec16VT, N165, N8);
+ Known = DAG->computeKnownBits(OpMOVIshift8Vec16);
+ EXPECT_EQ(Known.Zero, APInt(16, 0x5AFF));
+ EXPECT_EQ(Known.One, APInt(16, 0xA500));
+
+ auto OpMVNIshift4Vec16 =
+ DAG->getNode(AArch64ISD::MVNIshift, Loc, Int4Vec16VT, N165, N8);
+ Known = DAG->computeKnownBits(OpMVNIshift4Vec16);
+ EXPECT_EQ(Known.Zero, APInt(16, 0xA500));
+ EXPECT_EQ(Known.One, APInt(16, 0x5AFF));
+
+ auto OpMVNIshift8Vec16 =
+ DAG->getNode(AArch64ISD::MVNIshift, Loc, Int8Vec16VT, N165, N0);
+ Known = DAG->computeKnownBits(OpMVNIshift8Vec16);
+ EXPECT_EQ(Known.Zero, APInt(16, 0x00A5));
+ EXPECT_EQ(Known.One, APInt(16, 0xFF5A));
+
+ auto OpMOVI8Vec8 = DAG->getNode(AArch64ISD::MOVI, Loc, Int8Vec8VT, N165);
+ Known = DAG->computeKnownBits(OpMOVI8Vec8);
+ EXPECT_EQ(Known.Zero, APInt(8, 0x5A));
+ EXPECT_EQ(Known.One, APInt(8, 0xA5));
+
+ auto OpMOVI16Vec8 = DAG->getNode(AArch64ISD::MOVI, Loc, Int16Vec8VT, N165);
+ Known = DAG->computeKnownBits(OpMOVI16Vec8);
+ EXPECT_EQ(Known.Zero, APInt(8, 0x5A));
+ EXPECT_EQ(Known.One, APInt(8, 0xA5));
+}
+
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_SUB) {
SDLoc Loc;
>From ffa37943f71acf7fa25ee5831f9bc87d42d6e321 Mon Sep 17 00:00:00 2001
From: ningxinr <ningxinr at live.cn>
Date: Wed, 27 Aug 2025 14:01:48 -0700
Subject: [PATCH 2/2] Fix x86 sanitizer bot failures
---
llvm/lib/Target/AArch64/AArch64ISelLowering.cpp | 12 ++++++++----
1 file changed, 8 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 0bfb29f688678..726515429fdcf 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -2621,15 +2621,17 @@ void AArch64TargetLowering::computeKnownBitsForTargetNode(
break;
}
case AArch64ISD::MOVIshift: {
+ auto ShiftAmt = AArch64_AM::getShiftValue(Op->getConstantOperandVal(1));
Known = KnownBits::makeConstant(
APInt(Known.getBitWidth(), Op->getConstantOperandVal(0)
- << Op->getConstantOperandVal(1)));
+ << ShiftAmt));
break;
}
case AArch64ISD::MOVImsl: {
+ auto ShiftAmt = AArch64_AM::getShiftValue(Op->getConstantOperandVal(1));
Known = KnownBits::makeConstant(
APInt(Known.getBitWidth(), ~(~Op->getConstantOperandVal(0)
- << Op->getConstantOperandVal(1))));
+ << ShiftAmt)));
break;
}
case AArch64ISD::MOVIedit: {
@@ -2639,16 +2641,18 @@ void AArch64TargetLowering::computeKnownBitsForTargetNode(
break;
}
case AArch64ISD::MVNIshift: {
+ auto ShiftAmt = AArch64_AM::getShiftValue(Op->getConstantOperandVal(1));
Known = KnownBits::makeConstant(
APInt(Known.getBitWidth(),
- ~(Op->getConstantOperandVal(0) << Op->getConstantOperandVal(1)),
+ ~(Op->getConstantOperandVal(0) << ShiftAmt),
/*isSigned*/ false, /*implicitTrunc*/ true));
break;
}
case AArch64ISD::MVNImsl: {
+ auto ShiftAmt = AArch64_AM::getShiftValue(Op->getConstantOperandVal(1));
Known = KnownBits::makeConstant(
APInt(Known.getBitWidth(),
- (~Op->getConstantOperandVal(0) << Op->getConstantOperandVal(1)),
+ (~Op->getConstantOperandVal(0) << ShiftAmt),
/*isSigned*/ false, /*implicitTrunc*/ true));
break;
}
More information about the llvm-commits
mailing list