135 lines · cpp
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-exception5//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 25namespace llvm {26 27class RISCVSelectionDAGTest : public testing::Test {28 29protected: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 Right82TEST_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 %x86 // %b = lshr i32 %a, %y87 // %c = zext i32 %b to i64 ; makes the most significant 32 bits 088 // ret i64 %c89 // }90 // The Optimized SelectionDAG as show by llc -mtriple="riscv64"91 // -debug-only=isel-dump is:92 // t0: ch,glue = EntryToken93 // t2: i64,ch = CopyFromReg t0, Register:i64 %094 // t18: i64 = and t2, Constant:i64<2147483647>95 // t4: i64,ch = CopyFromReg t0, Register:i64 %196 // t20: i64 = RISCVISD::SRLW t18, t497 // t22: i64 = and t20, Constant:i64<4294967295>98 // t13: ch,glue = CopyToReg t0, Register:i64 $x10, t2299 // t14: ch = RISCVISD::RET_GLUE t13, Register:i64 $x10, t13:1100 //101 // The DAG created below is derived from this102 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 & 0x7FFFFFFF112 // 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, Qx116 // SRLW performs a 32-bit logical right shift and then sign-extends the117 // 32-bit result to 64 bits. Because we know N1's bit 31 is 0, the118 // 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 & 0xFFFFFFFF122 // This second AND is part of the canonical pattern to clear the upper123 // 32 bits, explicitly performing the zero-extension. From a KnownBits124 // 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 effective127 // 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 llvm135