Skip to content

Commit 20b4f59

Browse files
bojletoppercRKSimon
authored
[RISCV] add computeKnownBitsForTargetNode for RISCVISD::SRLW (#155995)
I've added support for computeKnownBitsForTargetNode for the SRLW instruction. A test has been included which uses the snippet of IR as suggested by topperc. Fixed #154913 --------- Signed-off-by: Shreeyash Pandey <[email protected]> Co-authored-by: Craig Topper <[email protected]> Co-authored-by: Simon Pilgrim <[email protected]>
1 parent 6bbf0c3 commit 20b4f59

File tree

3 files changed

+144
-0
lines changed

3 files changed

+144
-0
lines changed

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21490,6 +21490,15 @@ void RISCVTargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
2149021490
Known = Known.sext(BitWidth);
2149121491
break;
2149221492
}
21493+
case RISCVISD::SRLW: {
21494+
KnownBits Known2;
21495+
Known = DAG.computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);
21496+
Known2 = DAG.computeKnownBits(Op.getOperand(1), DemandedElts, Depth + 1);
21497+
Known = KnownBits::lshr(Known.trunc(32), Known2.trunc(5).zext(32));
21498+
// Restore the original width by sign extending.
21499+
Known = Known.sext(BitWidth);
21500+
break;
21501+
}
2149321502
case RISCVISD::SRAW: {
2149421503
KnownBits Known2;
2149521504
Known = DAG.computeKnownBits(Op.getOperand(0), DemandedElts, Depth + 1);

llvm/unittests/Target/RISCV/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ set(LLVM_LINK_COMPONENTS
1919
add_llvm_target_unittest(RISCVTests
2020
MCInstrAnalysisTest.cpp
2121
RISCVInstrInfoTest.cpp
22+
RISCVSelectionDAGTest.cpp
2223
)
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
//===----------------------------------------------------------------------===//
2+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3+
// See https://llvm.org/LICENSE.txt for license information.
4+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
//
6+
//===----------------------------------------------------------------------===//
7+
8+
#include "RISCVISelLowering.h"
9+
#include "RISCVSelectionDAGInfo.h"
10+
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
11+
#include "llvm/AsmParser/Parser.h"
12+
#include "llvm/CodeGen/MachineModuleInfo.h"
13+
#include "llvm/CodeGen/SelectionDAG.h"
14+
#include "llvm/CodeGen/TargetLowering.h"
15+
#include "llvm/IR/MDBuilder.h"
16+
#include "llvm/IR/Module.h"
17+
#include "llvm/MC/TargetRegistry.h"
18+
#include "llvm/Support/KnownBits.h"
19+
#include "llvm/Support/SourceMgr.h"
20+
#include "llvm/Support/TargetSelect.h"
21+
#include "llvm/Support/raw_ostream.h"
22+
#include "llvm/Target/TargetMachine.h"
23+
#include "gtest/gtest.h"
24+
25+
namespace llvm {
26+
27+
class RISCVSelectionDAGTest : public testing::Test {
28+
29+
protected:
30+
static void SetUpTestCase() {
31+
LLVMInitializeRISCVTargetInfo();
32+
LLVMInitializeRISCVTarget();
33+
LLVMInitializeRISCVTargetMC();
34+
}
35+
36+
void SetUp() override {
37+
StringRef Assembly = "define void @f() { ret void }";
38+
39+
Triple TargetTriple("riscv64", "unknown", "linux");
40+
41+
std::string Error;
42+
const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
43+
44+
TargetOptions Options;
45+
TM = std::unique_ptr<TargetMachine>(T->createTargetMachine(
46+
TargetTriple, "generic", "", Options, std::nullopt, std::nullopt,
47+
CodeGenOptLevel::Default));
48+
49+
SMDiagnostic SMError;
50+
M = parseAssemblyString(Assembly, SMError, Context);
51+
if (!M)
52+
report_fatal_error(SMError.getMessage());
53+
M->setDataLayout(TM->createDataLayout());
54+
55+
F = M->getFunction("f");
56+
if (!F)
57+
report_fatal_error("Function 'f' not found");
58+
59+
MachineModuleInfo MMI(TM.get());
60+
61+
MF = std::make_unique<MachineFunction>(*F, *TM, *TM->getSubtargetImpl(*F),
62+
MMI.getContext(), /*FunctionNum*/ 0);
63+
64+
DAG = std::make_unique<SelectionDAG>(*TM, CodeGenOptLevel::None);
65+
if (!DAG)
66+
report_fatal_error("SelectionDAG allocation failed");
67+
68+
OptimizationRemarkEmitter ORE(F);
69+
DAG->init(*MF, ORE, /*LibInfo*/ nullptr, /*AA*/ nullptr,
70+
/*AC*/ nullptr, /*MDT*/ nullptr, /*MSDT*/ nullptr, MMI, nullptr);
71+
}
72+
73+
LLVMContext Context;
74+
std::unique_ptr<TargetMachine> TM;
75+
std::unique_ptr<Module> M;
76+
Function *F = nullptr;
77+
std::unique_ptr<MachineFunction> MF;
78+
std::unique_ptr<SelectionDAG> DAG;
79+
};
80+
81+
/// SRLW: Logical Shift Right
82+
TEST_F(RISCVSelectionDAGTest, computeKnownBits_SRLW) {
83+
// Given the following IR snippet:
84+
// define i64 @f(i32 %x, i32 %y) {
85+
// %a = and i32 %x, 2147483647 ; zeros the MSB for %x
86+
// %b = lshr i32 %a, %y
87+
// %c = zext i32 %b to i64 ; makes the most significant 32 bits 0
88+
// ret i64 %c
89+
// }
90+
// The Optimized SelectionDAG as show by llc -mtriple="riscv64"
91+
// -debug-only=isel-dump is:
92+
// t0: ch,glue = EntryToken
93+
// t2: i64,ch = CopyFromReg t0, Register:i64 %0
94+
// t18: i64 = and t2, Constant:i64<2147483647>
95+
// t4: i64,ch = CopyFromReg t0, Register:i64 %1
96+
// t20: i64 = RISCVISD::SRLW t18, t4
97+
// t22: i64 = and t20, Constant:i64<4294967295>
98+
// t13: ch,glue = CopyToReg t0, Register:i64 $x10, t22
99+
// t14: ch = RISCVISD::RET_GLUE t13, Register:i64 $x10, t13:1
100+
//
101+
// The DAG created below is derived from this
102+
SDLoc Loc;
103+
auto Int64VT = EVT::getIntegerVT(Context, 64);
104+
auto Px = DAG->getRegister(0, Int64VT);
105+
auto Py = DAG->getConstant(2147483647, Loc, Int64VT);
106+
auto N1 = DAG->getNode(ISD::AND, Loc, Int64VT, Px, Py);
107+
auto Qx = DAG->getRegister(0, Int64VT);
108+
auto N2 = DAG->getNode(RISCVISD::SRLW, Loc, Int64VT, N1, Qx);
109+
auto Py2 = DAG->getConstant(4294967295, Loc, Int64VT);
110+
auto N3 = DAG->getNode(ISD::AND, Loc, Int64VT, N2, Py2);
111+
// N1 = Px & 0x7FFFFFFF
112+
// The first AND ensures that the input to the shift has bit 31 cleared.
113+
// This means bits [63:31] of N1 are known to be zero.
114+
//
115+
// N2 = SRLW N1, Qx
116+
// SRLW performs a 32-bit logical right shift and then sign-extends the
117+
// 32-bit result to 64 bits. Because we know N1's bit 31 is 0, the
118+
// 32-bit result of the shift will also have its sign bit (bit 31) as 0.
119+
// Therefore, the sign-extension is guaranteed to be a zero-extension.
120+
//
121+
// N3 = N2 & 0xFFFFFFFF
122+
// This second AND is part of the canonical pattern to clear the upper
123+
// 32 bits, explicitly performing the zero-extension. From a KnownBits
124+
// perspective, it's redundant, as N2's upper bits are already known zero.
125+
//
126+
// As a result, for N3, we know the upper 32 bits are zero (from the effective
127+
// zero-extension) and we also know bit 31 is zero (from the initial AND).
128+
// This gives us 33 known most-significant zero bits.
129+
KnownBits Known = DAG->computeKnownBits(N3);
130+
EXPECT_EQ(Known.Zero, APInt(64, -2147483648));
131+
EXPECT_EQ(Known.One, APInt(64, 0));
132+
}
133+
134+
} // end namespace llvm

0 commit comments

Comments
 (0)