blob: c74d15782398ac687016993cbb813597b7b57d41 [file] [log] [blame]
//===----------------------------------------------------------------------===//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "AArch64SelectionDAGInfo.h"
#include "llvm/Analysis/MemoryLocation.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/KnownBits.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "gtest/gtest.h"
namespace llvm {
class AArch64SelectionDAGTest : public testing::Test {
protected:
static void SetUpTestCase() {
LLVMInitializeAArch64TargetInfo();
LLVMInitializeAArch64Target();
LLVMInitializeAArch64TargetMC();
}
void SetUp() override {
StringRef Assembly = "define void @f() { ret void }";
Triple TargetTriple("aarch64--");
std::string Error;
const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
TargetOptions Options;
TM = std::unique_ptr<TargetMachine>(
T->createTargetMachine(TargetTriple, "", "+sve", Options, std::nullopt,
std::nullopt, CodeGenOptLevel::Aggressive));
SMDiagnostic SMError;
M = parseAssemblyString(Assembly, SMError, Context);
if (!M)
report_fatal_error(SMError.getMessage());
M->setDataLayout(TM->createDataLayout());
F = M->getFunction("f");
if (!F)
report_fatal_error("F?");
MachineModuleInfo MMI(TM.get());
MF = std::make_unique<MachineFunction>(*F, *TM, *TM->getSubtargetImpl(*F),
MMI.getContext(), 0);
DAG = std::make_unique<SelectionDAG>(*TM, CodeGenOptLevel::None);
if (!DAG)
report_fatal_error("DAG?");
OptimizationRemarkEmitter ORE(F);
DAG->init(*MF, ORE, nullptr, nullptr, nullptr, nullptr, nullptr, MMI,
nullptr);
}
TargetLoweringBase::LegalizeTypeAction getTypeAction(EVT VT) {
return DAG->getTargetLoweringInfo().getTypeAction(Context, VT);
}
EVT getTypeToTransformTo(EVT VT) {
return DAG->getTargetLoweringInfo().getTypeToTransformTo(Context, VT);
}
LLVMContext Context;
std::unique_ptr<TargetMachine> TM;
std::unique_ptr<Module> M;
Function *F;
std::unique_ptr<MachineFunction> MF;
std::unique_ptr<SelectionDAG> DAG;
};
TEST_F(AArch64SelectionDAGTest, computeKnownBits_ZERO_EXTEND_VECTOR_INREG) {
SDLoc Loc;
auto Int8VT = EVT::getIntegerVT(Context, 8);
auto Int16VT = EVT::getIntegerVT(Context, 16);
auto InVecVT = EVT::getVectorVT(Context, Int8VT, 4);
auto OutVecVT = EVT::getVectorVT(Context, Int16VT, 2);
auto InVec = DAG->getConstant(0, Loc, InVecVT);
auto Op = DAG->getNode(ISD::ZERO_EXTEND_VECTOR_INREG, Loc, OutVecVT, InVec);
auto DemandedElts = APInt(2, 3);
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
EXPECT_TRUE(Known.isZero());
}
TEST_F(AArch64SelectionDAGTest, computeKnownBitsSVE_ZERO_EXTEND_VECTOR_INREG) {
SDLoc Loc;
auto Int8VT = EVT::getIntegerVT(Context, 8);
auto Int16VT = EVT::getIntegerVT(Context, 16);
auto InVecVT = EVT::getVectorVT(Context, Int8VT, 4, true);
auto OutVecVT = EVT::getVectorVT(Context, Int16VT, 2, true);
auto InVec = DAG->getConstant(0, Loc, InVecVT);
auto Op = DAG->getNode(ISD::ZERO_EXTEND_VECTOR_INREG, Loc, OutVecVT, InVec);
auto DemandedElts = APInt(2, 3);
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
// We don't know anything for SVE at the moment.
EXPECT_EQ(Known.Zero, APInt(16, 0u));
EXPECT_EQ(Known.One, APInt(16, 0u));
EXPECT_FALSE(Known.isZero());
}
TEST_F(AArch64SelectionDAGTest, computeKnownBits_EXTRACT_SUBVECTOR) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 3);
auto IdxVT = EVT::getIntegerVT(Context, 64);
auto Vec = DAG->getConstant(0, Loc, VecVT);
auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT);
auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, VecVT, Vec, ZeroIdx);
auto DemandedElts = APInt(3, 7);
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
EXPECT_TRUE(Known.isZero());
}
TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_SIGN_EXTEND_VECTOR_INREG) {
SDLoc Loc;
auto Int8VT = EVT::getIntegerVT(Context, 8);
auto Int16VT = EVT::getIntegerVT(Context, 16);
auto InVecVT = EVT::getVectorVT(Context, Int8VT, 4);
auto OutVecVT = EVT::getVectorVT(Context, Int16VT, 2);
auto InVec = DAG->getConstant(1, Loc, InVecVT);
auto Op = DAG->getNode(ISD::SIGN_EXTEND_VECTOR_INREG, Loc, OutVecVT, InVec);
auto DemandedElts = APInt(2, 3);
EXPECT_EQ(DAG->ComputeNumSignBits(Op, DemandedElts), 15u);
}
TEST_F(AArch64SelectionDAGTest,
ComputeNumSignBitsSVE_SIGN_EXTEND_VECTOR_INREG) {
SDLoc Loc;
auto Int8VT = EVT::getIntegerVT(Context, 8);
auto Int16VT = EVT::getIntegerVT(Context, 16);
auto InVecVT = EVT::getVectorVT(Context, Int8VT, 4, /*IsScalable=*/true);
auto OutVecVT = EVT::getVectorVT(Context, Int16VT, 2, /*IsScalable=*/true);
auto InVec = DAG->getConstant(1, Loc, InVecVT);
auto Op = DAG->getNode(ISD::SIGN_EXTEND_VECTOR_INREG, Loc, OutVecVT, InVec);
auto DemandedElts = APInt(2, 3);
EXPECT_EQ(DAG->ComputeNumSignBits(Op, DemandedElts), 1u);
}
TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_EXTRACT_SUBVECTOR) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 3);
auto IdxVT = EVT::getIntegerVT(Context, 64);
auto Vec = DAG->getConstant(1, Loc, VecVT);
auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT);
auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, VecVT, Vec, ZeroIdx);
auto DemandedElts = APInt(3, 7);
EXPECT_EQ(DAG->ComputeNumSignBits(Op, DemandedElts), 7u);
}
TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_VASHR) {
SDLoc Loc;
auto VecVT = MVT::v8i8;
auto Shift = DAG->getConstant(4, Loc, MVT::i32);
auto Vec0 = DAG->getConstant(1, Loc, VecVT);
auto Op1 = DAG->getNode(AArch64ISD::VASHR, Loc, VecVT, Vec0, Shift);
EXPECT_EQ(DAG->ComputeNumSignBits(Op1), 8u);
auto VecA = DAG->getConstant(0xaa, Loc, VecVT);
auto Op2 = DAG->getNode(AArch64ISD::VASHR, Loc, VecVT, VecA, Shift);
EXPECT_EQ(DAG->ComputeNumSignBits(Op2), 5u);
// VASHR can't create undef/poison - FREEZE(VASHR(C1,C2)) -> VASHR(C1,C2).
auto Fr2 = DAG->getFreeze(Op2);
EXPECT_EQ(DAG->ComputeNumSignBits(Fr2), 5u);
}
TEST_F(AArch64SelectionDAGTest, SimplifyDemandedVectorElts_EXTRACT_SUBVECTOR) {
TargetLowering TL(*TM);
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 3);
auto IdxVT = EVT::getIntegerVT(Context, 64);
auto Vec = DAG->getConstant(1, Loc, VecVT);
auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT);
auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, VecVT, Vec, ZeroIdx);
auto DemandedElts = APInt(3, 7);
auto KnownUndef = APInt(3, 0);
auto KnownZero = APInt(3, 0);
TargetLowering::TargetLoweringOpt TLO(*DAG, false, false);
EXPECT_EQ(TL.SimplifyDemandedVectorElts(Op, DemandedElts, KnownUndef,
KnownZero, TLO),
false);
}
TEST_F(AArch64SelectionDAGTest, SimplifyDemandedBitsNEON) {
TargetLowering TL(*TM);
SDLoc Loc;
auto Int8VT = EVT::getIntegerVT(Context, 8);
auto InVecVT = EVT::getVectorVT(Context, Int8VT, 16);
SDValue UnknownOp = DAG->getRegister(0, InVecVT);
SDValue Mask1S = DAG->getConstant(0x8A, Loc, Int8VT);
SDValue Mask1V = DAG->getSplatBuildVector(InVecVT, Loc, Mask1S);
SDValue N0 = DAG->getNode(ISD::AND, Loc, InVecVT, Mask1V, UnknownOp);
SDValue Mask2S = DAG->getConstant(0x55, Loc, Int8VT);
SDValue Mask2V = DAG->getSplatBuildVector(InVecVT, Loc, Mask2S);
SDValue Op = DAG->getNode(ISD::AND, Loc, InVecVT, N0, Mask2V);
// N0 = ?000?0?0
// Mask2V = 01010101
// =>
// Known.Zero = 00100000 (0xAA)
KnownBits Known;
APInt DemandedBits = APInt(8, 0xFF);
TargetLowering::TargetLoweringOpt TLO(*DAG, false, false);
EXPECT_TRUE(TL.SimplifyDemandedBits(Op, DemandedBits, Known, TLO));
EXPECT_EQ(Known.Zero, APInt(8, 0xAA));
}
TEST_F(AArch64SelectionDAGTest, SimplifyDemandedBitsSVE) {
TargetLowering TL(*TM);
SDLoc Loc;
auto Int8VT = EVT::getIntegerVT(Context, 8);
auto InVecVT = EVT::getVectorVT(Context, Int8VT, 16, /*IsScalable=*/true);
SDValue UnknownOp = DAG->getRegister(0, InVecVT);
SDValue Mask1S = DAG->getConstant(0x8A, Loc, Int8VT);
SDValue Mask1V = DAG->getSplatVector(InVecVT, Loc, Mask1S);
SDValue N0 = DAG->getNode(ISD::AND, Loc, InVecVT, Mask1V, UnknownOp);
SDValue Mask2S = DAG->getConstant(0x55, Loc, Int8VT);
SDValue Mask2V = DAG->getSplatVector(InVecVT, Loc, Mask2S);
SDValue Op = DAG->getNode(ISD::AND, Loc, InVecVT, N0, Mask2V);
// N0 = ?000?0?0
// Mask2V = 01010101
// =>
// Known.Zero = 00100000 (0xAA)
KnownBits Known;
APInt DemandedBits = APInt(8, 0xFF);
TargetLowering::TargetLoweringOpt TLO(*DAG, false, false);
EXPECT_TRUE(TL.SimplifyDemandedBits(Op, DemandedBits, Known, TLO));
EXPECT_EQ(Known.Zero, APInt(8, 0xAA));
}
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_ADD) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto UnknownOp = DAG->getRegister(0, IntVT);
auto Mask = DAG->getConstant(0x8A, Loc, IntVT);
auto N0 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp);
auto N1 = DAG->getConstant(0x55, Loc, IntVT);
auto Op = DAG->getNode(ISD::ADD, Loc, IntVT, N0, N1);
// N0 = ?000?0?0
// N1 = 01010101
// =>
// Known.One = 01010101 (0x55)
// Known.Zero = 00100000 (0x20)
KnownBits Known = DAG->computeKnownBits(Op);
EXPECT_EQ(Known.Zero, APInt(8, 0x20));
EXPECT_EQ(Known.One, APInt(8, 0x55));
}
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_UADDO_CARRY) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto UnknownOp = DAG->getRegister(0, IntVT);
auto Mask_Zero = DAG->getConstant(0x28, Loc, IntVT);
auto Mask_One = DAG->getConstant(0x20, Loc, IntVT);
auto N0 = DAG->getNode(ISD::AND, Loc, IntVT, Mask_Zero, UnknownOp);
N0 = DAG->getNode(ISD::OR, Loc, IntVT, Mask_One, N0);
auto N1 = DAG->getConstant(0x65, Loc, IntVT);
KnownBits Known;
auto UnknownBorrow = DAG->getRegister(1, IntVT);
auto OpUnknownBorrow =
DAG->getNode(ISD::UADDO_CARRY, Loc, IntVT, N0, N1, UnknownBorrow);
// N0 = 0010?000
// N1 = 01100101
// B = ?
// =>
// Known.Zero = 01110000 (0x70)
// Known.One = 10000100 (0x84)
Known = DAG->computeKnownBits(OpUnknownBorrow);
EXPECT_EQ(Known.Zero, APInt(8, 0x70));
EXPECT_EQ(Known.One, APInt(8, 0x84));
auto ZeroBorrow = DAG->getConstant(0x0, Loc, IntVT);
auto OpZeroBorrow =
DAG->getNode(ISD::UADDO_CARRY, Loc, IntVT, N0, N1, ZeroBorrow);
// N0 = 0010?000
// N1 = 01100101
// B = 0
// =>
// Known.Zero = 01110010 (0x72)
// Known.One = 10000101 (0x85)
Known = DAG->computeKnownBits(OpZeroBorrow);
EXPECT_EQ(Known.Zero, APInt(8, 0x72));
EXPECT_EQ(Known.One, APInt(8, 0x85));
auto OneBorrow = DAG->getConstant(0x1, Loc, IntVT);
auto OpOneBorrow =
DAG->getNode(ISD::UADDO_CARRY, Loc, IntVT, N0, N1, OneBorrow);
// N0 = 0010?000
// N1 = 01100101
// B = 1
// =>
// Known.Zero = 01110001 (0x71)
// Known.One = 10000110 (0x86)
Known = DAG->computeKnownBits(OpOneBorrow);
EXPECT_EQ(Known.Zero, APInt(8, 0x71));
EXPECT_EQ(Known.One, APInt(8, 0x86));
}
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
// Attempt to FREEZE the MOV/MVN nodes to show that they can still be analysed.
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 FrMOVIedit128 = DAG->getFreeze(OpMOVIedit128);
Known = DAG->computeKnownBits(FrMOVIedit128);
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 FrMOVImsl128 = DAG->getFreeze(OpMOVImsl128);
Known = DAG->computeKnownBits(FrMOVImsl128);
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 FrMVNImsl128 = DAG->getFreeze(OpMVNImsl128);
Known = DAG->computeKnownBits(FrMVNImsl128);
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 FrMOVIshift4Vec32 = DAG->getFreeze(OpMOVIshift4Vec32);
Known = DAG->computeKnownBits(FrMOVIshift4Vec32);
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 FrMVNIshift4Vec32 = DAG->getFreeze(OpMVNIshift4Vec32);
Known = DAG->computeKnownBits(FrMVNIshift4Vec32);
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 FrMOVIshift8Vec16 = DAG->getFreeze(OpMOVIshift8Vec16);
Known = DAG->computeKnownBits(FrMOVIshift8Vec16);
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 FrMVNIshift8Vec16 = DAG->getFreeze(OpMVNIshift8Vec16);
Known = DAG->computeKnownBits(FrMVNIshift8Vec16);
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));
auto FrMOVI16Vec8 = DAG->getFreeze(OpMOVI16Vec8);
Known = DAG->computeKnownBits(FrMOVI16Vec8);
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;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto N0 = DAG->getConstant(0x55, Loc, IntVT);
auto UnknownOp = DAG->getRegister(0, IntVT);
auto Mask = DAG->getConstant(0x2e, Loc, IntVT);
auto N1 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp);
auto Op = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1);
// N0 = 01010101
// N1 = 00?0???0
// =>
// Known.One = 00000001 (0x1)
// Known.Zero = 10000000 (0x80)
KnownBits Known = DAG->computeKnownBits(Op);
EXPECT_EQ(Known.Zero, APInt(8, 0x80));
EXPECT_EQ(Known.One, APInt(8, 0x1));
}
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_USUBO_CARRY) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto N0 = DAG->getConstant(0x5a, Loc, IntVT);
auto UnknownOp = DAG->getRegister(0, IntVT); // ????????
auto Mask1_Zero = DAG->getConstant(0x8, Loc, IntVT); // 00001000
auto Mask1_One = DAG->getConstant(0x20, Loc, IntVT); // 00100000
// N1 = (???????? & 00001000) | 00100000 = 0010?000
auto N1 = DAG->getNode(ISD::AND, Loc, IntVT, Mask1_Zero, UnknownOp);
N1 = DAG->getNode(ISD::OR, Loc, IntVT, Mask1_One, N1);
KnownBits Known;
auto UnknownBorrow = DAG->getRegister(1, IntVT);
auto OpUnknownBorrow =
DAG->getNode(ISD::USUBO_CARRY, Loc, IntVT, N0, N1, UnknownBorrow);
// N0 = 01011010
// N1 = 0010?000
// B = ?
// =>
// Known.Zero = 11000100 (0xc4)
// Known.One = 00110000 (0x30)
Known = DAG->computeKnownBits(OpUnknownBorrow);
EXPECT_EQ(Known.Zero, APInt(8, 0xc4));
EXPECT_EQ(Known.One, APInt(8, 0x30));
auto ZeroBorrow = DAG->getConstant(0x0, Loc, IntVT);
auto OpZeroBorrow =
DAG->getNode(ISD::USUBO_CARRY, Loc, IntVT, N0, N1, ZeroBorrow);
// N0 = 01011010
// N1 = 0010?000
// B = 0
// =>
// Known.Zero = 11000101 (0xc5)
// Known.One = 00110010 (0x32)
Known = DAG->computeKnownBits(OpZeroBorrow);
EXPECT_EQ(Known.Zero, APInt(8, 0xc5));
EXPECT_EQ(Known.One, APInt(8, 0x32));
auto OneBorrow = DAG->getConstant(0x1, Loc, IntVT);
auto OpOneBorrow =
DAG->getNode(ISD::USUBO_CARRY, Loc, IntVT, N0, N1, OneBorrow);
// N0 = 01011010
// N1 = 0010?000
// B = 1
// =>
// Known.Zero = 11000110 (0xc6)
// Known.One = 00110001 (0x31)
Known = DAG->computeKnownBits(OpOneBorrow);
EXPECT_EQ(Known.Zero, APInt(8, 0xc6));
EXPECT_EQ(Known.One, APInt(8, 0x31));
}
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_VASHR) {
SDLoc Loc;
KnownBits Known;
auto VecVT = MVT::v8i8;
auto Shift0 = DAG->getConstant(4, Loc, MVT::i32);
auto Vec0 = DAG->getConstant(0x80, Loc, VecVT);
auto Op0 = DAG->getNode(AArch64ISD::VASHR, Loc, VecVT, Vec0, Shift0);
Known = DAG->computeKnownBits(Op0);
EXPECT_EQ(Known.Zero, APInt(8, 0x07));
EXPECT_EQ(Known.One, APInt(8, 0xF8));
auto Shift1 = DAG->getConstant(7, Loc, MVT::i32);
auto Vec1 = DAG->getConstant(0xF7, Loc, VecVT);
auto Op1 = DAG->getNode(AArch64ISD::VASHR, Loc, VecVT, Vec1, Shift1);
Known = DAG->computeKnownBits(Op1);
EXPECT_EQ(Known.Zero, APInt(8, 0x00));
EXPECT_EQ(Known.One, APInt(8, 0xFF));
auto Fr1 = DAG->getFreeze(Op1);
Known = DAG->computeKnownBits(Fr1);
EXPECT_EQ(Known.Zero, APInt(8, 0x00));
EXPECT_EQ(Known.One, APInt(8, 0xFF));
}
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_VLSHR) {
SDLoc Loc;
KnownBits Known;
auto VecVT = MVT::v8i8;
auto Shift0 = DAG->getConstant(4, Loc, MVT::i32);
auto Vec0 = DAG->getConstant(0x80, Loc, VecVT);
auto Op0 = DAG->getNode(AArch64ISD::VLSHR, Loc, VecVT, Vec0, Shift0);
Known = DAG->computeKnownBits(Op0);
EXPECT_EQ(Known.Zero, APInt(8, 0xF7));
EXPECT_EQ(Known.One, APInt(8, 0x08));
auto Shift1 = DAG->getConstant(7, Loc, MVT::i32);
auto Vec1 = DAG->getConstant(0xF7, Loc, VecVT);
auto Op1 = DAG->getNode(AArch64ISD::VLSHR, Loc, VecVT, Vec1, Shift1);
Known = DAG->computeKnownBits(Op1);
EXPECT_EQ(Known.Zero, APInt(8, 0xFE));
EXPECT_EQ(Known.One, APInt(8, 0x1));
auto Fr1 = DAG->getFreeze(Op1);
Known = DAG->computeKnownBits(Fr1);
EXPECT_EQ(Known.Zero, APInt(8, 0xFE));
EXPECT_EQ(Known.One, APInt(8, 0x1));
}
// Piggy-backing on the AArch64 tests to verify SelectionDAG::computeKnownBits.
TEST_F(AArch64SelectionDAGTest, ComputeKnownBits_VSHL) {
SDLoc Loc;
KnownBits Known;
auto VecVT = MVT::v8i8;
auto Shift0 = DAG->getConstant(4, Loc, MVT::i32);
auto Vec0 = DAG->getConstant(0x02, Loc, VecVT);
auto Op0 = DAG->getNode(AArch64ISD::VSHL, Loc, VecVT, Vec0, Shift0);
Known = DAG->computeKnownBits(Op0);
EXPECT_EQ(Known.Zero, APInt(8, 0xDF));
EXPECT_EQ(Known.One, APInt(8, 0x20));
auto Shift1 = DAG->getConstant(7, Loc, MVT::i32);
auto Vec1 = DAG->getConstant(0xF7, Loc, VecVT);
auto Op1 = DAG->getNode(AArch64ISD::VSHL, Loc, VecVT, Vec1, Shift1);
Known = DAG->computeKnownBits(Op1);
EXPECT_EQ(Known.Zero, APInt(8, 0x7F));
EXPECT_EQ(Known.One, APInt(8, 0x80));
auto Fr1 = DAG->getFreeze(Op1);
Known = DAG->computeKnownBits(Fr1);
EXPECT_EQ(Known.Zero, APInt(8, 0x7F));
EXPECT_EQ(Known.One, APInt(8, 0x80));
}
TEST_F(AArch64SelectionDAGTest, isSplatValue_Fixed_BUILD_VECTOR) {
TargetLowering TL(*TM);
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false);
// Create a BUILD_VECTOR
SDValue Op = DAG->getConstant(1, Loc, VecVT);
EXPECT_EQ(Op->getOpcode(), ISD::BUILD_VECTOR);
EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false));
APInt UndefElts;
APInt DemandedElts;
EXPECT_FALSE(DAG->isSplatValue(Op, DemandedElts, UndefElts));
// Width=16, Mask=3
DemandedElts = APInt(16, 3);
EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts));
}
TEST_F(AArch64SelectionDAGTest, isSplatValue_Fixed_ADD_of_BUILD_VECTOR) {
TargetLowering TL(*TM);
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false);
// Should create BUILD_VECTORs
SDValue Val1 = DAG->getConstant(1, Loc, VecVT);
SDValue Val2 = DAG->getConstant(3, Loc, VecVT);
EXPECT_EQ(Val1->getOpcode(), ISD::BUILD_VECTOR);
SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2);
EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false));
APInt UndefElts;
APInt DemandedElts;
EXPECT_FALSE(DAG->isSplatValue(Op, DemandedElts, UndefElts));
// Width=16, Mask=3
DemandedElts = APInt(16, 3);
EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts));
}
TEST_F(AArch64SelectionDAGTest, isSplatValue_Scalable_SPLAT_VECTOR) {
TargetLowering TL(*TM);
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true);
// Create a SPLAT_VECTOR
SDValue Op = DAG->getConstant(1, Loc, VecVT);
EXPECT_EQ(Op->getOpcode(), ISD::SPLAT_VECTOR);
EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false));
APInt UndefElts;
APInt DemandedElts(1, 1);
EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts));
}
TEST_F(AArch64SelectionDAGTest, isSplatValue_Scalable_ADD_of_SPLAT_VECTOR) {
TargetLowering TL(*TM);
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true);
// Should create SPLAT_VECTORS
SDValue Val1 = DAG->getConstant(1, Loc, VecVT);
SDValue Val2 = DAG->getConstant(3, Loc, VecVT);
EXPECT_EQ(Val1->getOpcode(), ISD::SPLAT_VECTOR);
SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2);
EXPECT_TRUE(DAG->isSplatValue(Op, /*AllowUndefs=*/false));
APInt UndefElts;
APInt DemandedElts(1, 1);
EXPECT_TRUE(DAG->isSplatValue(Op, DemandedElts, UndefElts));
}
TEST_F(AArch64SelectionDAGTest, getSplatSourceVector_Fixed_BUILD_VECTOR) {
TargetLowering TL(*TM);
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false);
// Create a BUILD_VECTOR
SDValue Op = DAG->getConstant(1, Loc, VecVT);
EXPECT_EQ(Op->getOpcode(), ISD::BUILD_VECTOR);
int SplatIdx = -1;
EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op);
EXPECT_EQ(SplatIdx, 0);
}
TEST_F(AArch64SelectionDAGTest,
getSplatSourceVector_Fixed_ADD_of_BUILD_VECTOR) {
TargetLowering TL(*TM);
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 16, false);
// Should create BUILD_VECTORs
SDValue Val1 = DAG->getConstant(1, Loc, VecVT);
SDValue Val2 = DAG->getConstant(3, Loc, VecVT);
EXPECT_EQ(Val1->getOpcode(), ISD::BUILD_VECTOR);
SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2);
int SplatIdx = -1;
EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op);
EXPECT_EQ(SplatIdx, 0);
}
TEST_F(AArch64SelectionDAGTest, getSplatSourceVector_Scalable_SPLAT_VECTOR) {
TargetLowering TL(*TM);
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true);
// Create a SPLAT_VECTOR
SDValue Op = DAG->getConstant(1, Loc, VecVT);
EXPECT_EQ(Op->getOpcode(), ISD::SPLAT_VECTOR);
int SplatIdx = -1;
EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op);
EXPECT_EQ(SplatIdx, 0);
}
TEST_F(AArch64SelectionDAGTest,
getSplatSourceVector_Scalable_ADD_of_SPLAT_VECTOR) {
TargetLowering TL(*TM);
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, IntVT, 16, true);
// Should create SPLAT_VECTORS
SDValue Val1 = DAG->getConstant(1, Loc, VecVT);
SDValue Val2 = DAG->getConstant(3, Loc, VecVT);
EXPECT_EQ(Val1->getOpcode(), ISD::SPLAT_VECTOR);
SDValue Op = DAG->getNode(ISD::ADD, Loc, VecVT, Val1, Val2);
int SplatIdx = -1;
EXPECT_EQ(DAG->getSplatSourceVector(Op, SplatIdx), Op);
EXPECT_EQ(SplatIdx, 0);
}
TEST_F(AArch64SelectionDAGTest, getRepeatedSequence_Patterns) {
TargetLowering TL(*TM);
SDLoc Loc;
unsigned NumElts = 16;
MVT IntVT = MVT::i8;
MVT VecVT = MVT::getVectorVT(IntVT, NumElts);
// Base scalar constants.
SDValue Val0 = DAG->getConstant(0, Loc, IntVT);
SDValue Val1 = DAG->getConstant(1, Loc, IntVT);
SDValue Val2 = DAG->getConstant(2, Loc, IntVT);
SDValue Val3 = DAG->getConstant(3, Loc, IntVT);
SDValue UndefVal = DAG->getUNDEF(IntVT);
// Build some repeating sequences.
SmallVector<SDValue, 16> Pattern1111, Pattern1133, Pattern0123;
for (int I = 0; I != 4; ++I) {
Pattern1111.append(4, Val1);
Pattern1133.append(2, Val1);
Pattern1133.append(2, Val3);
Pattern0123.push_back(Val0);
Pattern0123.push_back(Val1);
Pattern0123.push_back(Val2);
Pattern0123.push_back(Val3);
}
// Build a non-pow2 repeating sequence.
SmallVector<SDValue, 16> Pattern022;
Pattern022.push_back(Val0);
Pattern022.append(2, Val2);
Pattern022.push_back(Val0);
Pattern022.append(2, Val2);
Pattern022.push_back(Val0);
Pattern022.append(2, Val2);
Pattern022.push_back(Val0);
Pattern022.append(2, Val2);
Pattern022.push_back(Val0);
Pattern022.append(2, Val2);
Pattern022.push_back(Val0);
// Build a non-repeating sequence.
SmallVector<SDValue, 16> Pattern1_3;
Pattern1_3.append(8, Val1);
Pattern1_3.append(8, Val3);
// Add some undefs to make it trickier.
Pattern1111[1] = Pattern1111[2] = Pattern1111[15] = UndefVal;
Pattern1133[0] = Pattern1133[2] = UndefVal;
auto *BV1111 =
cast<BuildVectorSDNode>(DAG->getBuildVector(VecVT, Loc, Pattern1111));
auto *BV1133 =
cast<BuildVectorSDNode>(DAG->getBuildVector(VecVT, Loc, Pattern1133));
auto *BV0123 =
cast<BuildVectorSDNode>(DAG->getBuildVector(VecVT, Loc, Pattern0123));
auto *BV022 =
cast<BuildVectorSDNode>(DAG->getBuildVector(VecVT, Loc, Pattern022));
auto *BV1_3 =
cast<BuildVectorSDNode>(DAG->getBuildVector(VecVT, Loc, Pattern1_3));
// Check for sequences.
SmallVector<SDValue, 16> Seq1111, Seq1133, Seq0123, Seq022, Seq1_3;
BitVector Undefs1111, Undefs1133, Undefs0123, Undefs022, Undefs1_3;
EXPECT_TRUE(BV1111->getRepeatedSequence(Seq1111, &Undefs1111));
EXPECT_EQ(Undefs1111.count(), 3u);
EXPECT_EQ(Seq1111.size(), 1u);
EXPECT_EQ(Seq1111[0], Val1);
EXPECT_TRUE(BV1133->getRepeatedSequence(Seq1133, &Undefs1133));
EXPECT_EQ(Undefs1133.count(), 2u);
EXPECT_EQ(Seq1133.size(), 4u);
EXPECT_EQ(Seq1133[0], Val1);
EXPECT_EQ(Seq1133[1], Val1);
EXPECT_EQ(Seq1133[2], Val3);
EXPECT_EQ(Seq1133[3], Val3);
EXPECT_TRUE(BV0123->getRepeatedSequence(Seq0123, &Undefs0123));
EXPECT_EQ(Undefs0123.count(), 0u);
EXPECT_EQ(Seq0123.size(), 4u);
EXPECT_EQ(Seq0123[0], Val0);
EXPECT_EQ(Seq0123[1], Val1);
EXPECT_EQ(Seq0123[2], Val2);
EXPECT_EQ(Seq0123[3], Val3);
EXPECT_FALSE(BV022->getRepeatedSequence(Seq022, &Undefs022));
EXPECT_FALSE(BV1_3->getRepeatedSequence(Seq1_3, &Undefs1_3));
// Try again with DemandedElts masks.
APInt Mask1111_0 = APInt::getOneBitSet(NumElts, 0);
EXPECT_TRUE(BV1111->getRepeatedSequence(Mask1111_0, Seq1111, &Undefs1111));
EXPECT_EQ(Undefs1111.count(), 0u);
EXPECT_EQ(Seq1111.size(), 1u);
EXPECT_EQ(Seq1111[0], Val1);
APInt Mask1111_1 = APInt::getOneBitSet(NumElts, 2);
EXPECT_TRUE(BV1111->getRepeatedSequence(Mask1111_1, Seq1111, &Undefs1111));
EXPECT_EQ(Undefs1111.count(), 1u);
EXPECT_EQ(Seq1111.size(), 1u);
EXPECT_EQ(Seq1111[0], UndefVal);
APInt Mask0123 = APInt(NumElts, 0x7777);
EXPECT_TRUE(BV0123->getRepeatedSequence(Mask0123, Seq0123, &Undefs0123));
EXPECT_EQ(Undefs0123.count(), 0u);
EXPECT_EQ(Seq0123.size(), 4u);
EXPECT_EQ(Seq0123[0], Val0);
EXPECT_EQ(Seq0123[1], Val1);
EXPECT_EQ(Seq0123[2], Val2);
EXPECT_EQ(Seq0123[3], SDValue());
APInt Mask1_3 = APInt::getHighBitsSet(16, 8);
EXPECT_TRUE(BV1_3->getRepeatedSequence(Mask1_3, Seq1_3, &Undefs1_3));
EXPECT_EQ(Undefs1_3.count(), 0u);
EXPECT_EQ(Seq1_3.size(), 1u);
EXPECT_EQ(Seq1_3[0], Val3);
}
TEST_F(AArch64SelectionDAGTest, getTypeConversion_SplitScalableMVT) {
MVT VT = MVT::nxv4i64;
EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypeSplitVector);
ASSERT_TRUE(getTypeToTransformTo(VT).isScalableVector());
}
TEST_F(AArch64SelectionDAGTest, getTypeConversion_PromoteScalableMVT) {
MVT VT = MVT::nxv2i32;
EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypePromoteInteger);
ASSERT_TRUE(getTypeToTransformTo(VT).isScalableVector());
}
TEST_F(AArch64SelectionDAGTest, getTypeConversion_NoScalarizeMVT_nxv1f32) {
MVT VT = MVT::nxv1f32;
EXPECT_NE(getTypeAction(VT), TargetLoweringBase::TypeScalarizeVector);
ASSERT_TRUE(getTypeToTransformTo(VT).isScalableVector());
}
TEST_F(AArch64SelectionDAGTest, getTypeConversion_SplitScalableEVT) {
EVT VT = EVT::getVectorVT(Context, MVT::i64, 256, true);
EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypeSplitVector);
EXPECT_EQ(getTypeToTransformTo(VT), VT.getHalfNumVectorElementsVT(Context));
}
TEST_F(AArch64SelectionDAGTest, getTypeConversion_WidenScalableEVT) {
EVT FromVT = EVT::getVectorVT(Context, MVT::i64, 6, true);
EVT ToVT = EVT::getVectorVT(Context, MVT::i64, 8, true);
EXPECT_EQ(getTypeAction(FromVT), TargetLoweringBase::TypeWidenVector);
EXPECT_EQ(getTypeToTransformTo(FromVT), ToVT);
}
TEST_F(AArch64SelectionDAGTest,
getTypeConversion_ScalarizeScalableEVT_nxv1f128) {
EVT VT = EVT::getVectorVT(Context, MVT::f128, ElementCount::getScalable(1));
EXPECT_EQ(getTypeAction(VT), TargetLoweringBase::TypeScalarizeScalableVector);
EXPECT_EQ(getTypeToTransformTo(VT), MVT::f128);
}
TEST_F(AArch64SelectionDAGTest, TestFold_STEP_VECTOR) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = EVT::getVectorVT(Context, MVT::i8, 16, true);
// Should create SPLAT_VECTOR
SDValue Zero = DAG->getConstant(0, Loc, IntVT);
SDValue Op = DAG->getNode(ISD::STEP_VECTOR, Loc, VecVT, Zero);
EXPECT_EQ(Op.getOpcode(), ISD::SPLAT_VECTOR);
}
TEST_F(AArch64SelectionDAGTest, ReplaceAllUsesWith) {
SDLoc Loc;
EVT IntVT = EVT::getIntegerVT(Context, 8);
SDValue N0 = DAG->getConstant(0x42, Loc, IntVT);
SDValue N1 = DAG->getRegister(0, IntVT);
// Construct node to fill arbitrary ExtraInfo.
SDValue N2 = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1);
EXPECT_FALSE(DAG->getHeapAllocSite(N2.getNode()));
EXPECT_FALSE(DAG->getNoMergeSiteInfo(N2.getNode()));
EXPECT_FALSE(DAG->getPCSections(N2.getNode()));
MDNode *MD = MDNode::get(Context, {});
DAG->addHeapAllocSite(N2.getNode(), MD);
DAG->addNoMergeSiteInfo(N2.getNode(), true);
DAG->addPCSections(N2.getNode(), MD);
EXPECT_EQ(DAG->getHeapAllocSite(N2.getNode()), MD);
EXPECT_TRUE(DAG->getNoMergeSiteInfo(N2.getNode()));
EXPECT_EQ(DAG->getPCSections(N2.getNode()), MD);
SDValue Root = DAG->getNode(ISD::ADD, Loc, IntVT, N2, N2);
EXPECT_EQ(Root->getOperand(0)->getOpcode(), ISD::SUB);
// Create new node and check that ExtraInfo is propagated on RAUW.
SDValue New = DAG->getNode(ISD::ADD, Loc, IntVT, N1, N1);
EXPECT_FALSE(DAG->getHeapAllocSite(New.getNode()));
EXPECT_FALSE(DAG->getNoMergeSiteInfo(New.getNode()));
EXPECT_FALSE(DAG->getPCSections(New.getNode()));
DAG->ReplaceAllUsesWith(N2, New);
EXPECT_EQ(Root->getOperand(0), New);
EXPECT_EQ(DAG->getHeapAllocSite(New.getNode()), MD);
EXPECT_TRUE(DAG->getNoMergeSiteInfo(New.getNode()));
EXPECT_EQ(DAG->getPCSections(New.getNode()), MD);
}
TEST_F(AArch64SelectionDAGTest, computeKnownBits_extload_known01) {
SDLoc Loc;
auto Int8VT = EVT::getIntegerVT(Context, 8);
auto Int32VT = EVT::getIntegerVT(Context, 32);
auto Int64VT = EVT::getIntegerVT(Context, 64);
auto Ptr = DAG->getConstant(0, Loc, Int64VT);
auto PtrInfo =
MachinePointerInfo::getFixedStack(DAG->getMachineFunction(), 0);
AAMDNodes AA;
MDBuilder MDHelper(*DAG->getContext());
MDNode *Range = MDHelper.createRange(APInt(8, 0), APInt(8, 2));
MachineMemOperand *MMO = DAG->getMachineFunction().getMachineMemOperand(
PtrInfo, MachineMemOperand::MOLoad, 8, Align(8), AA, Range);
auto ALoad = DAG->getExtLoad(ISD::EXTLOAD, Loc, Int32VT, DAG->getEntryNode(),
Ptr, Int8VT, MMO);
KnownBits Known = DAG->computeKnownBits(ALoad);
EXPECT_EQ(Known.Zero, APInt(32, 0xfe));
EXPECT_EQ(Known.One, APInt(32, 0));
auto ZLoad = DAG->getExtLoad(ISD::ZEXTLOAD, Loc, Int32VT, DAG->getEntryNode(),
Ptr, Int8VT, MMO);
Known = DAG->computeKnownBits(ZLoad);
EXPECT_EQ(Known.Zero, APInt(32, 0xfffffffe));
EXPECT_EQ(Known.One, APInt(32, 0));
auto SLoad = DAG->getExtLoad(ISD::SEXTLOAD, Loc, Int32VT, DAG->getEntryNode(),
Ptr, Int8VT, MMO);
Known = DAG->computeKnownBits(SLoad);
EXPECT_EQ(Known.Zero, APInt(32, 0xfffffffe));
EXPECT_EQ(Known.One, APInt(32, 0));
}
TEST_F(AArch64SelectionDAGTest, computeKnownBits_extload_knownnegative) {
SDLoc Loc;
auto Int8VT = EVT::getIntegerVT(Context, 8);
auto Int32VT = EVT::getIntegerVT(Context, 32);
auto Int64VT = EVT::getIntegerVT(Context, 64);
auto Ptr = DAG->getConstant(0, Loc, Int64VT);
auto PtrInfo =
MachinePointerInfo::getFixedStack(DAG->getMachineFunction(), 0);
AAMDNodes AA;
MDBuilder MDHelper(*DAG->getContext());
MDNode *Range = MDHelper.createRange(APInt(8, 0xf0), APInt(8, 0xff));
MachineMemOperand *MMO = DAG->getMachineFunction().getMachineMemOperand(
PtrInfo, MachineMemOperand::MOLoad, 8, Align(8), AA, Range);
auto ALoad = DAG->getExtLoad(ISD::EXTLOAD, Loc, Int32VT, DAG->getEntryNode(),
Ptr, Int8VT, MMO);
KnownBits Known = DAG->computeKnownBits(ALoad);
EXPECT_EQ(Known.Zero, APInt(32, 0));
EXPECT_EQ(Known.One, APInt(32, 0xf0));
auto ZLoad = DAG->getExtLoad(ISD::ZEXTLOAD, Loc, Int32VT, DAG->getEntryNode(),
Ptr, Int8VT, MMO);
Known = DAG->computeKnownBits(ZLoad);
EXPECT_EQ(Known.Zero, APInt(32, 0xffffff00));
EXPECT_EQ(Known.One, APInt(32, 0x000000f0));
auto SLoad = DAG->getExtLoad(ISD::SEXTLOAD, Loc, Int32VT, DAG->getEntryNode(),
Ptr, Int8VT, MMO);
Known = DAG->computeKnownBits(SLoad);
EXPECT_EQ(Known.Zero, APInt(32, 0));
EXPECT_EQ(Known.One, APInt(32, 0xfffffff0));
}
TEST_F(AArch64SelectionDAGTest,
computeKnownBits_AVGFLOORU_AVGFLOORS_AVGCEILU_AVGCEILS) {
SDLoc Loc;
auto Int8VT = EVT::getIntegerVT(Context, 8);
auto Int16VT = EVT::getIntegerVT(Context, 16);
auto Int8Vec8VT = EVT::getVectorVT(Context, Int8VT, 8);
auto Int16Vec8VT = EVT::getVectorVT(Context, Int16VT, 8);
SDValue UnknownOp0 = DAG->getRegister(0, Int8Vec8VT);
SDValue UnknownOp1 = DAG->getRegister(1, Int8Vec8VT);
SDValue ZextOp0 =
DAG->getNode(ISD::ZERO_EXTEND, Loc, Int16Vec8VT, UnknownOp0);
SDValue ZextOp1 =
DAG->getNode(ISD::ZERO_EXTEND, Loc, Int16Vec8VT, UnknownOp1);
// ZextOp0 = 00000000????????
// ZextOp1 = 00000000????????
// => (for all AVG* instructions)
// Known.Zero = 1111111100000000 (0xFF00)
// Known.One = 0000000000000000 (0x0000)
auto Zeroes = APInt(16, 0xFF00);
auto Ones = APInt(16, 0x0000);
SDValue AVGFLOORU =
DAG->getNode(ISD::AVGFLOORU, Loc, Int16Vec8VT, ZextOp0, ZextOp1);
KnownBits KnownAVGFLOORU = DAG->computeKnownBits(AVGFLOORU);
EXPECT_EQ(KnownAVGFLOORU.Zero, Zeroes);
EXPECT_EQ(KnownAVGFLOORU.One, Ones);
SDValue AVGFLOORS =
DAG->getNode(ISD::AVGFLOORS, Loc, Int16Vec8VT, ZextOp0, ZextOp1);
KnownBits KnownAVGFLOORS = DAG->computeKnownBits(AVGFLOORS);
EXPECT_EQ(KnownAVGFLOORS.Zero, Zeroes);
EXPECT_EQ(KnownAVGFLOORS.One, Ones);
SDValue AVGCEILU =
DAG->getNode(ISD::AVGCEILU, Loc, Int16Vec8VT, ZextOp0, ZextOp1);
KnownBits KnownAVGCEILU = DAG->computeKnownBits(AVGCEILU);
EXPECT_EQ(KnownAVGCEILU.Zero, Zeroes);
EXPECT_EQ(KnownAVGCEILU.One, Ones);
SDValue AVGCEILS =
DAG->getNode(ISD::AVGCEILS, Loc, Int16Vec8VT, ZextOp0, ZextOp1);
KnownBits KnownAVGCEILS = DAG->computeKnownBits(AVGCEILS);
EXPECT_EQ(KnownAVGCEILS.Zero, Zeroes);
EXPECT_EQ(KnownAVGCEILS.One, Ones);
}
} // end namespace llvm