Files
TheRock/compiler/amd-llvm/llvm/unittests/Target/AArch64/AArch64SelectionDAGTest.cpp
T
derek.holloway 7502bf64a4
CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

1772 lines
66 KiB
C++

//===----------------------------------------------------------------------===//
// 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/KnownFPClass.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:
const TargetSubtargetInfo *STI;
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());
STI = TM->getSubtargetImpl(*F);
MF = std::make_unique<MachineFunction>(*F, *TM, *STI, 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, 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(1, 1);
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(1, 1);
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, ComputeNumSignBitsSVE_EXTRACT_SUBVECTOR) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto ScalableVecVT =
EVT::getVectorVT(Context, IntVT, 16, /*IsScalable=*/true);
auto FixedVecVT = EVT::getVectorVT(Context, IntVT, 16, /*IsScalable=*/false);
auto IdxVT = EVT::getIntegerVT(Context, 64);
auto Vec = DAG->getConstant(1, Loc, ScalableVecVT);
auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT);
auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, FixedVecVT, 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, ComputeNumSignBits_SUB) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto N0 = DAG->getConstant(0x00, Loc, IntVT);
auto N1 = DAG->getConstant(0x01, Loc, IntVT);
auto N5 = DAG->getConstant(0x05, Loc, IntVT);
auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT);
auto UnknownOp = DAG->getRegister(0, IntVT);
auto Mask = DAG->getConstant(0x1e, Loc, IntVT);
auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp);
// RHS early out
// Nsign1 = 01010101
// Nsign3 = 000????0
auto OpRhsEo = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign3, Nsign1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u);
// Neg 0
// N0 = 00000000
auto OpNegZero = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N0);
EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u);
// Neg 1
// N0 = 00000000
// N1 = 00000001
auto OpNegOne = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u);
// Neg 5
// N0 = 00000000
// N5 = 00000101
auto OpNegFive = DAG->getNode(ISD::SUB, Loc, IntVT, N0, N5);
EXPECT_EQ(DAG->ComputeNumSignBits(OpNegFive), 5u);
// Non negative
// N0 = 00000000
// Nsign3 = 000????0
auto OpNonNeg = DAG->getNode(ISD::SUB, Loc, IntVT, N0, Nsign3);
EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u);
// LHS early out
// Nsign1 = 01010101
// Nsign3 = 000????0
auto OpLhsEo = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign1, Nsign3);
EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u);
// Nsign3 = 000????0
// N5 = 00000101
auto Op = DAG->getNode(ISD::SUB, Loc, IntVT, Nsign3, N5);
EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u);
}
TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADD) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto Nneg1 = DAG->getConstant(0xFF, Loc, IntVT);
auto N0 = DAG->getConstant(0x00, Loc, IntVT);
auto N1 = DAG->getConstant(0x01, Loc, IntVT);
auto N5 = DAG->getConstant(0x05, Loc, IntVT);
auto N8 = DAG->getConstant(0x08, Loc, IntVT);
auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT);
auto UnknownOp = DAG->getRegister(0, IntVT);
auto Mask = DAG->getConstant(0x1e, Loc, IntVT);
auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp);
// RHS early out
// Nsign1 = 01010101
// Nsign3 = 000????0
auto OpRhsEo = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, Nsign1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u);
// ADD 0 -1
// N0 = 00000000
// Nneg1 = 11111111
auto OpNegZero = DAG->getNode(ISD::ADD, Loc, IntVT, N0, Nneg1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u);
// ADD 1 -1
// N1 = 00000001
// Nneg1 = 11111111
auto OpNegOne = DAG->getNode(ISD::ADD, Loc, IntVT, N1, Nneg1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u);
// ADD 8 -1
// N8 = 00001000
// Nneg1 = 11111111
auto OpSeven = DAG->getNode(ISD::ADD, Loc, IntVT, N8, Nneg1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpSeven), 5u);
// Non negative
// Nsign3 = 000????0
// Nneg1 = 11111111
auto OpNonNeg = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, Nneg1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u);
// LHS early out
// Nsign1 = 01010101
// Nsign3 = 000????0
auto OpLhsEo = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign1, Nsign3);
EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u);
// Nsign3 = 000????0
// N5 = 00000101
auto Op = DAG->getNode(ISD::ADD, Loc, IntVT, Nsign3, N5);
EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u);
}
TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ADDC) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto Nneg1 = DAG->getConstant(0xFF, Loc, IntVT);
auto N0 = DAG->getConstant(0x00, Loc, IntVT);
auto N1 = DAG->getConstant(0x01, Loc, IntVT);
auto N5 = DAG->getConstant(0x05, Loc, IntVT);
auto N8 = DAG->getConstant(0x08, Loc, IntVT);
auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT);
auto UnknownOp = DAG->getRegister(0, IntVT);
auto Mask = DAG->getConstant(0x1e, Loc, IntVT);
auto Nsign3 = DAG->getNode(ISD::AND, Loc, IntVT, Mask, UnknownOp);
// RHS early out
// Nsign1 = 01010101
// Nsign3 = 000????0
auto OpRhsEo = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, Nsign1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u);
// ADD 0 -1
// N0 = 00000000
// Nneg1 = 11111111
auto OpNegZero = DAG->getNode(ISD::ADDC, Loc, IntVT, N0, Nneg1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpNegZero), 8u);
// ADD 1 -1
// N1 = 00000001
// Nneg1 = 11111111
auto OpNegOne = DAG->getNode(ISD::ADDC, Loc, IntVT, N1, Nneg1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpNegOne), 8u);
// ADD 8 -1
// N8 = 00001000
// Nneg1 = 11111111
auto OpSeven = DAG->getNode(ISD::ADDC, Loc, IntVT, N8, Nneg1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpSeven), 4u);
// Non negative
// Nsign3 = 000????0
// Nneg1 = 11111111
auto OpNonNeg = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, Nneg1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpNonNeg), 3u);
// LHS early out
// Nsign1 = 01010101
// Nsign3 = 000????0
auto OpLhsEo = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign1, Nsign3);
EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u);
// Nsign3 = 000????0
// N5 = 00000101
auto Op = DAG->getNode(ISD::ADDC, Loc, IntVT, Nsign3, N5);
EXPECT_EQ(DAG->ComputeNumSignBits(Op), 2u);
}
TEST_F(AArch64SelectionDAGTest, ComputeNumSignBits_ABDS) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto VecVT = MVT::v8i8;
auto N0 = DAG->getConstant(0x00, Loc, IntVT);
auto V0 = DAG->getConstant(0x00, Loc, VecVT);
auto Nsign1 = DAG->getConstant(0x55, Loc, IntVT);
auto UnknownScalar = DAG->getUNDEF(IntVT);
auto UnknownVec = DAG->getUNDEF(VecVT);
// AssertSext to i4 guarantees 5 sign bits in i8
// Op5Sig = sssss???
auto Op5Sig = DAG->getNode(ISD::AssertSext, Loc, IntVT, UnknownScalar,
DAG->getValueType(MVT::i4));
// Vec5Sig = sssss??? per element
auto Vec5Sig = DAG->getNode(ISD::AssertSext, Loc, VecVT, UnknownVec,
DAG->getValueType(MVT::i4));
// LHS early out
// Nsign1 = 01010101
// N0 = 00000000
auto OpLhsEo = DAG->getNode(ISD::ABDS, Loc, IntVT, Nsign1, N0);
EXPECT_EQ(DAG->ComputeNumSignBits(OpLhsEo), 1u);
// Normal scalar case
// Op5Sig = sssss???
// N0 = 00000000
auto OpScalar = DAG->getNode(ISD::ABDS, Loc, IntVT, Op5Sig, N0);
EXPECT_EQ(DAG->ComputeNumSignBits(OpScalar), 4u);
// Normal vector case
// Vec5Sig = sssss???
// V0 = 00000000
auto OpVec = DAG->getNode(ISD::ABDS, Loc, VecVT, Vec5Sig, V0);
EXPECT_EQ(DAG->ComputeNumSignBits(OpVec), 4u);
// RHS early out
// N0 = 00000000
// Nsign1 = 01010101
auto OpRhsEo = DAG->getNode(ISD::ABDS, Loc, IntVT, N0, Nsign1);
EXPECT_EQ(DAG->ComputeNumSignBits(OpRhsEo), 1u);
// Zero case
// N0 = 00000000
auto OpZero = DAG->getNode(ISD::ABDS, Loc, IntVT, N0, N0);
EXPECT_EQ(DAG->ComputeNumSignBits(OpZero), 8u);
}
TEST_F(AArch64SelectionDAGTest, SimplifyDemandedVectorElts_EXTRACT_SUBVECTOR) {
TargetLowering TL(*TM, *STI);
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, *STI);
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, *STI);
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));
}
// Test that we can compute the known bits of a subvector extract
// from a scalable vector, which requires this knowledge to be known
// for all elements of the scalable source vector.
TEST_F(AArch64SelectionDAGTest, ComputeKnownBitsSVE_EXTRACT_SUBVECTOR) {
SDLoc Loc;
auto IntVT = EVT::getIntegerVT(Context, 8);
auto ScalableVecVT =
EVT::getVectorVT(Context, IntVT, 16, /*IsScalable=*/true);
auto FixedVecVT = EVT::getVectorVT(Context, IntVT, 16, /*IsScalable=*/false);
auto IdxVT = EVT::getIntegerVT(Context, 64);
auto Vec = DAG->getConstant(1, Loc, ScalableVecVT);
auto ZeroIdx = DAG->getConstant(0, Loc, IdxVT);
auto Op = DAG->getNode(ISD::EXTRACT_SUBVECTOR, Loc, FixedVecVT, Vec, ZeroIdx);
KnownBits Known = DAG->computeKnownBits(Op);
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_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));
}
// Piggy-backing on the AArch64 tests to verify
// SelectionDAG::KnownToBeAPowerOfTwo.
TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_Constants) {
SDLoc Loc;
auto Cst0 = DAG->getConstant(0, Loc, MVT::i32);
auto Cst4 = DAG->getConstant(4, Loc, MVT::i32);
auto CstBig = DAG->getConstant(2 << 17, Loc, MVT::i32);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Cst0));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Cst0, /*OrZero=*/true));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Cst4));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(CstBig));
auto VecVT = MVT::v2i16;
auto Vec04 = DAG->getBuildVector(VecVT, Loc, {Cst0, Cst4});
auto Vec44 = DAG->getBuildVector(VecVT, Loc, {Cst4, Cst4});
auto Vec4Big = DAG->getBuildVector(VecVT, Loc, {Cst4, CstBig});
auto Vec0Big = DAG->getBuildVector(VecVT, Loc, {Cst0, CstBig});
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Vec04));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Vec04, /*OrZero=*/true));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Vec44));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Vec44, /*OrZero=*/true));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Vec4Big));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Vec4Big, /*OrZero=*/true));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Vec0Big));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Vec0Big, /*OrZero=*/true));
APInt DemandLo(2, 1);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Vec04, DemandLo));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Vec04, DemandLo, /*OrZero=*/true));
APInt DemandHi(2, 2);
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Vec04, DemandHi));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Vec04, DemandHi, /*OrZero=*/true));
auto SplatVT = MVT::nxv2i16;
auto Splat0 = DAG->getSplat(SplatVT, Loc, Cst0);
auto Splat4 = DAG->getSplat(SplatVT, Loc, Cst4);
auto SplatBig = DAG->getSplat(SplatVT, Loc, CstBig);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Splat0));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Splat4, /*OrZero=*/true));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Splat4));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Splat4, /*OrZero=*/true));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(SplatBig));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(SplatBig, /*OrZero=*/true));
}
TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_SHL) {
SDLoc Loc;
SDValue Cst0 = DAG->getConstant(0, Loc, MVT::i32);
SDValue Cst1 = DAG->getConstant(1, Loc, MVT::i32);
SDValue Cst3 = DAG->getConstant(3, Loc, MVT::i32);
SDValue Cst4 = DAG->getConstant(4, Loc, MVT::i32);
SDValue Cst16 = DAG->getConstant(16, Loc, MVT::i32);
SDValue Cond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc,
Register::index2VirtReg(1), MVT::i32);
SDValue ShlConst1 = DAG->getNode(ISD::SHL, Loc, MVT::i32, Cst1, Cond);
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(ShlConst1));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(ShlConst1, /*OrZero=*/true));
SDValue And16 = DAG->getNode(ISD::AND, Loc, MVT::i32, Cond, Cst16);
SDValue ShlMaybeZero = DAG->getNode(ISD::SHL, Loc, MVT::i32, And16, Cst1);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(ShlMaybeZero));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(ShlMaybeZero, /*OrZero=*/true));
SDValue ShlUnknown = DAG->getNode(ISD::SHL, Loc, MVT::i32, Cond, Cst1);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(ShlUnknown));
SDValue Neg3 = DAG->getNode(ISD::SUB, Loc, MVT::i32, Cst0, Cst3);
SDValue AndPow2 = DAG->getNode(ISD::AND, Loc, MVT::i32, Cst3, Neg3);
SDValue ShlPow2 = DAG->getNode(ISD::SHL, Loc, MVT::i32, AndPow2, Cst1);
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(ShlPow2));
MVT::SimpleValueType VecVT = MVT::v2i32;
SDValue Vec13 = DAG->getBuildVector(VecVT, Loc, {Cst1, Cst3});
SDValue Vec04 = DAG->getBuildVector(VecVT, Loc, {Cst0, Cst4});
SDValue VecShift = DAG->getBuildVector(VecVT, Loc, {Cst1, Cst1});
SDValue VecShl13 = DAG->getNode(ISD::SHL, Loc, VecVT, Vec13, VecShift);
SDValue VecShl04 = DAG->getNode(ISD::SHL, Loc, VecVT, Vec04, VecShift);
APInt DemandLo(2, 1);
APInt DemandHi(2, 2);
APInt DemandAll(2, 3);
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(VecShl13, DemandLo));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VecShl13, DemandHi));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VecShl13, DemandAll));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VecShl04, DemandAll));
EXPECT_TRUE(
DAG->isKnownToBeAPowerOfTwo(VecShl04, DemandAll, /*OrZero=*/true));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(VecShl04, DemandHi));
}
TEST_F(AArch64SelectionDAGTest, KnownToBeAPowerOfTwo_Select) {
SDLoc Loc;
auto Cst0 = DAG->getConstant(0, Loc, MVT::i32);
auto Cst3 = DAG->getConstant(3, Loc, MVT::i32);
auto Cst4 = DAG->getConstant(4, Loc, MVT::i32);
auto CstBig = DAG->getConstant(2 << 17, Loc, MVT::i32);
auto Cond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc,
Register::index2VirtReg(1), MVT::i1);
auto Select40 = DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Cst4, Cst0);
auto Select43 = DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Cst4, Cst3);
auto Select4Big =
DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Cst4, CstBig);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Select40));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Select40, /*OrZero=*/true));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(Select43));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(Select4Big));
auto VecVT = MVT::v2i16;
auto Vec04 = DAG->getBuildVector(VecVT, Loc, {Cst0, Cst4});
auto Vec44 = DAG->getBuildVector(VecVT, Loc, {Cst4, Cst4});
auto Vec4Big = DAG->getBuildVector(VecVT, Loc, {Cst4, CstBig});
auto Vec0Big = DAG->getBuildVector(VecVT, Loc, {Cst0, CstBig});
auto VecCond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc,
Register::index2VirtReg(2), MVT::v2i1);
auto VSelect0444 =
DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec04, Vec44);
auto VSelect4444 =
DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec44, Vec44);
auto VSelect040Big =
DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec04, Vec0Big);
auto VSelect444Big =
DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec44, Vec4Big);
APInt DemandLo(2, 1);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VSelect0444, DemandLo));
EXPECT_TRUE(
DAG->isKnownToBeAPowerOfTwo(VSelect0444, DemandLo, /*OrZero=*/true));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(VSelect444Big, DemandLo));
APInt DemandHi(2, 2);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VSelect444Big, DemandHi));
EXPECT_TRUE(
DAG->isKnownToBeAPowerOfTwo(VSelect444Big, DemandHi, /*OrZero=*/true));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(VSelect0444, DemandHi));
APInt DemandAll(2, 3);
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VSelect0444, DemandAll));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VSelect040Big, DemandAll));
EXPECT_FALSE(DAG->isKnownToBeAPowerOfTwo(VSelect444Big, DemandAll));
EXPECT_TRUE(DAG->isKnownToBeAPowerOfTwo(VSelect4444, DemandAll));
EXPECT_TRUE(
DAG->isKnownToBeAPowerOfTwo(VSelect040Big, DemandAll, /*OrZero=*/true));
EXPECT_TRUE(
DAG->isKnownToBeAPowerOfTwo(VSelect444Big, DemandAll, /*OrZero=*/true));
}
TEST_F(AArch64SelectionDAGTest, isSplatValue_Fixed_BUILD_VECTOR) {
TargetLowering TL(*TM, *STI);
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, *STI);
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, *STI);
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, *STI);
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, *STI);
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, *STI);
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, *STI);
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, *STI);
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, *STI);
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);
}
// Piggy-backing on the AArch64 tests to verify
// SelectionDAG::KnownNeverZero.
TEST_F(AArch64SelectionDAGTest, KnownNeverZero_Constants) {
SDLoc Loc;
auto Cst0 = DAG->getConstant(0, Loc, MVT::i32);
auto Cst4 = DAG->getConstant(4, Loc, MVT::i32);
auto CstBig = DAG->getConstant(2 << 17, Loc, MVT::i32);
EXPECT_FALSE(DAG->isKnownNeverZero(Cst0));
EXPECT_TRUE(DAG->isKnownNeverZero(Cst4));
EXPECT_TRUE(DAG->isKnownNeverZero(CstBig));
auto VecVT = MVT::v2i16;
auto Vec04 = DAG->getBuildVector(VecVT, Loc, {Cst0, Cst4});
auto Vec44 = DAG->getBuildVector(VecVT, Loc, {Cst4, Cst4});
auto Vec4Big = DAG->getBuildVector(VecVT, Loc, {Cst4, CstBig});
auto Vec0Big = DAG->getBuildVector(VecVT, Loc, {Cst0, CstBig});
EXPECT_FALSE(DAG->isKnownNeverZero(Vec04));
EXPECT_TRUE(DAG->isKnownNeverZero(Vec44));
EXPECT_FALSE(DAG->isKnownNeverZero(Vec4Big));
EXPECT_FALSE(DAG->isKnownNeverZero(Vec0Big));
APInt DemandLo(2, 1);
EXPECT_FALSE(DAG->isKnownNeverZero(Vec04, DemandLo));
APInt DemandHi(2, 2);
EXPECT_TRUE(DAG->isKnownNeverZero(Vec04, DemandHi));
auto SplatVT = MVT::nxv2i16;
auto Splat0 = DAG->getSplat(SplatVT, Loc, Cst0);
auto Splat4 = DAG->getSplat(SplatVT, Loc, Cst4);
auto SplatBig = DAG->getSplat(SplatVT, Loc, CstBig);
EXPECT_FALSE(DAG->isKnownNeverZero(Splat0));
EXPECT_TRUE(DAG->isKnownNeverZero(Splat4));
EXPECT_FALSE(DAG->isKnownNeverZero(SplatBig));
}
TEST_F(AArch64SelectionDAGTest, KnownNeverZero_Select) {
SDLoc Loc;
auto Cst0 = DAG->getConstant(0, Loc, MVT::i32);
auto Cst3 = DAG->getConstant(3, Loc, MVT::i32);
auto Cst4 = DAG->getConstant(4, Loc, MVT::i32);
auto CstBig = DAG->getConstant(2 << 17, Loc, MVT::i32);
auto Cond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc,
Register::index2VirtReg(1), MVT::i1);
auto Select40 = DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Cst4, Cst0);
auto Select43 = DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Cst4, Cst3);
auto Select4Big =
DAG->getNode(ISD::SELECT, Loc, MVT::i32, Cond, Cst4, CstBig);
EXPECT_FALSE(DAG->isKnownNeverZero(Select40));
EXPECT_FALSE(DAG->isKnownNeverZero(Select40));
EXPECT_TRUE(DAG->isKnownNeverZero(Select43));
EXPECT_TRUE(DAG->isKnownNeverZero(Select4Big));
auto VecVT = MVT::v2i16;
auto Vec04 = DAG->getBuildVector(VecVT, Loc, {Cst0, Cst4});
auto Vec44 = DAG->getBuildVector(VecVT, Loc, {Cst4, Cst4});
auto Vec4Big = DAG->getBuildVector(VecVT, Loc, {Cst4, CstBig});
auto Vec0Big = DAG->getBuildVector(VecVT, Loc, {Cst0, CstBig});
auto VecCond = DAG->getCopyFromReg(DAG->getEntryNode(), Loc,
Register::index2VirtReg(2), MVT::v2i1);
auto VSelect0444 =
DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec04, Vec44);
auto VSelect4444 =
DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec44, Vec44);
auto VSelect040Big =
DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec04, Vec0Big);
auto VSelect444Big =
DAG->getNode(ISD::VSELECT, Loc, VecVT, VecCond, Vec44, Vec4Big);
APInt DemandLo(2, 1);
EXPECT_FALSE(DAG->isKnownNeverZero(VSelect0444, DemandLo));
EXPECT_TRUE(DAG->isKnownNeverZero(VSelect444Big, DemandLo));
APInt DemandHi(2, 2);
EXPECT_FALSE(DAG->isKnownNeverZero(VSelect444Big, DemandHi));
EXPECT_TRUE(DAG->isKnownNeverZero(VSelect0444, DemandHi));
APInt DemandAll(2, 3);
EXPECT_FALSE(DAG->isKnownNeverZero(VSelect0444, DemandAll));
EXPECT_FALSE(DAG->isKnownNeverZero(VSelect040Big, DemandAll));
EXPECT_FALSE(DAG->isKnownNeverZero(VSelect444Big, DemandAll));
EXPECT_TRUE(DAG->isKnownNeverZero(VSelect4444, DemandAll));
}
TEST_F(AArch64SelectionDAGTest, KnownFPClass_Bitcast) {
SDLoc Loc;
SDValue Cond = DAG->getRegister(1, MVT::i1);
SDValue ConstZeroI32 = DAG->getConstant(0x0000'0000, Loc, MVT::i32);
SDValue ConstFiniteI32 = DAG->getConstant(0xbfff'ffff, Loc, MVT::i32);
SDValue AlwaysFiniteI32 =
DAG->getSelect(Loc, MVT::i32, Cond, ConstZeroI32, ConstFiniteI32);
SDValue AlwaysFiniteF32 = DAG->getBitcast(MVT::f32, AlwaysFiniteI32);
KnownFPClass AlwaysFiniteFPClass =
DAG->computeKnownFPClass(AlwaysFiniteF32, fcAllFlags);
EXPECT_TRUE(AlwaysFiniteFPClass.isKnownNeverInfOrNaN());
SDValue ConstNegInfI32 = DAG->getConstant(0xff80'0000, Loc, MVT::i32);
SDValue NeverNaNI32 =
DAG->getSelect(Loc, MVT::i32, Cond, ConstZeroI32, ConstNegInfI32);
SDValue NeverNaNF32 = DAG->getBitcast(MVT::f32, NeverNaNI32);
KnownFPClass NeverNaNFPClass =
DAG->computeKnownFPClass(NeverNaNF32, fcAllFlags);
EXPECT_FALSE(NeverNaNFPClass.isKnownNeverInfinity());
EXPECT_TRUE(NeverNaNFPClass.isKnownNeverNaN());
SDValue ConstPosNaNI32 = DAG->getConstant(0x7f80'0001, Loc, MVT::i32);
SDValue MaybeNaNI32 =
DAG->getSelect(Loc, MVT::i32, Cond, ConstPosNaNI32, ConstNegInfI32);
SDValue MaybeNaNF32 = DAG->getBitcast(MVT::f32, MaybeNaNI32);
KnownFPClass MaybeNaNFPClass =
DAG->computeKnownFPClass(MaybeNaNF32, fcAllFlags);
EXPECT_FALSE(MaybeNaNFPClass.isKnownNeverNaN());
EXPECT_FALSE(MaybeNaNFPClass.isKnownAlwaysNaN());
SDValue ConstNegNaNI32 = DAG->getConstant(0xffff'ffff, Loc, MVT::i32);
SDValue AlwaysNaNI32 =
DAG->getSelect(Loc, MVT::i32, Cond, ConstPosNaNI32, ConstNegNaNI32);
SDValue AlwaysNaNF32 = DAG->getBitcast(MVT::f32, AlwaysNaNI32);
KnownFPClass AlwaysNaNFPClass =
DAG->computeKnownFPClass(AlwaysNaNF32, fcAllFlags);
EXPECT_TRUE(AlwaysNaNFPClass.isKnownAlwaysNaN());
SDValue AlwaysFiniteSplat = DAG->getSplat(MVT::v2i32, Loc, AlwaysFiniteI32);
SDValue AlwaysFiniteV2F32 = DAG->getBitcast(MVT::v2f32, AlwaysFiniteSplat);
KnownFPClass AlwaysFiniteV2FPClass =
DAG->computeKnownFPClass(AlwaysFiniteV2F32, fcAllFlags);
EXPECT_TRUE(AlwaysFiniteV2FPClass.isKnownNeverInfOrNaN());
SDValue UpperAlwaysNaN =
DAG->getBuildVector(MVT::v2i32, Loc, {NeverNaNI32, AlwaysNaNI32});
SDValue UpperAlwaysNaNV2F32 = DAG->getBitcast(MVT::v2f32, UpperAlwaysNaN);
KnownFPClass UpperAlwaysNaNFullFPClass =
DAG->computeKnownFPClass(UpperAlwaysNaNV2F32, fcAllFlags);
EXPECT_FALSE(UpperAlwaysNaNFullFPClass.isKnownNeverNaN());
APInt DemandLo(2, 1);
KnownFPClass UpperAlwaysNaNLoFPClass =
DAG->computeKnownFPClass(UpperAlwaysNaNV2F32, DemandLo, fcAllFlags);
EXPECT_TRUE(UpperAlwaysNaNLoFPClass.isKnownNeverNaN());
APInt DemandHi(2, 2);
KnownFPClass UpperAlwaysNaNHiFPClass =
DAG->computeKnownFPClass(UpperAlwaysNaNV2F32, DemandHi, fcAllFlags);
EXPECT_TRUE(UpperAlwaysNaNHiFPClass.isKnownAlwaysNaN());
SDValue UpperAlwaysNaNAsF64 = DAG->getBitcast(MVT::f64, UpperAlwaysNaN);
KnownFPClass UpperAlwaysNaNAsF64FPClass =
DAG->computeKnownFPClass(UpperAlwaysNaNAsF64, fcAllFlags);
EXPECT_FALSE(UpperAlwaysNaNAsF64FPClass.isKnownNeverNaN());
EXPECT_FALSE(UpperAlwaysNaNAsF64FPClass.isKnownAlwaysNaN());
}
// tests for SelectionDAG::computeKnownFPClass
TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_ConstantScalar) {
SDLoc Loc;
SDValue PosZero = DAG->getConstantFP(APFloat::getZero(APFloat::IEEEsingle()),
Loc, MVT::f32);
KnownFPClass Known = DAG->computeKnownFPClass(PosZero, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcPosZero);
EXPECT_TRUE(Known.SignBit.has_value());
EXPECT_FALSE(*Known.SignBit);
SDValue NegZero = DAG->getConstantFP(
APFloat::getZero(APFloat::IEEEsingle(), true), Loc, MVT::f32);
Known = DAG->computeKnownFPClass(NegZero, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcNegZero);
EXPECT_TRUE(Known.SignBit.has_value());
EXPECT_TRUE(*Known.SignBit);
SDValue PosInf =
DAG->getConstantFP(APFloat::getInf(APFloat::IEEEsingle()), Loc, MVT::f32);
Known = DAG->computeKnownFPClass(PosInf, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcPosInf);
EXPECT_TRUE(Known.SignBit.has_value());
EXPECT_FALSE(*Known.SignBit);
SDValue QNaN = DAG->getConstantFP(APFloat::getQNaN(APFloat::IEEEsingle()),
Loc, MVT::f32);
Known = DAG->computeKnownFPClass(QNaN, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcQNan);
SDValue One = DAG->getConstantFP(1.0, Loc, MVT::f32);
Known = DAG->computeKnownFPClass(One, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcPosNormal);
EXPECT_TRUE(Known.SignBit.has_value());
EXPECT_FALSE(*Known.SignBit);
}
TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_BuildVector) {
SDLoc Loc;
SDValue PosOne = DAG->getConstantFP(1.0, Loc, MVT::f32);
SDValue PosTwo = DAG->getConstantFP(2.0, Loc, MVT::f32);
SDValue NegOne = DAG->getConstantFP(-1.0, Loc, MVT::f32);
EVT VecVT = MVT::v2f32;
SDValue VecPosPos = DAG->getBuildVector(VecVT, Loc, {PosOne, PosTwo});
KnownFPClass Known = DAG->computeKnownFPClass(VecPosPos, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcPosNormal);
EXPECT_TRUE(Known.SignBit.has_value());
EXPECT_FALSE(*Known.SignBit);
SDValue VecPosNeg = DAG->getBuildVector(VecVT, Loc, {PosOne, NegOne});
Known = DAG->computeKnownFPClass(VecPosNeg, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcPosNormal | fcNegNormal);
EXPECT_FALSE(Known.SignBit.has_value());
}
TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_DemandedElts) {
SDLoc Loc;
SDValue PosOne = DAG->getConstantFP(1.0, Loc, MVT::f32);
SDValue NegOne = DAG->getConstantFP(-1.0, Loc, MVT::f32);
EVT VecVT = MVT::v2f32;
SDValue Vec = DAG->getBuildVector(VecVT, Loc, {PosOne, NegOne});
APInt DemandLo(2, 1);
KnownFPClass Known = DAG->computeKnownFPClass(Vec, DemandLo, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcPosNormal);
EXPECT_TRUE(Known.SignBit.has_value());
EXPECT_FALSE(*Known.SignBit);
APInt DemandHi(2, 2);
Known = DAG->computeKnownFPClass(Vec, DemandHi, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcNegNormal);
EXPECT_TRUE(Known.SignBit.has_value());
EXPECT_TRUE(*Known.SignBit);
APInt DemandAll(2, 3);
Known = DAG->computeKnownFPClass(Vec, DemandAll, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcPosNormal | fcNegNormal);
EXPECT_FALSE(Known.SignBit.has_value());
APInt DemandNone(2, 0);
Known = DAG->computeKnownFPClass(Vec, DemandNone, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcAllFlags);
EXPECT_FALSE(Known.SignBit.has_value());
}
TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_MaxDepth) {
SDLoc Loc;
SDValue PosOne = DAG->getConstantFP(1.0, Loc, MVT::f32);
SDValue PosTwo = DAG->getConstantFP(2.0, Loc, MVT::f32);
EVT VecVT = MVT::v2f32;
SDValue Vec = DAG->getBuildVector(VecVT, Loc, {PosOne, PosTwo});
// At depth 0, BUILD_VECTOR of constants is fully analyzed.
KnownFPClass Known = DAG->computeKnownFPClass(Vec, fcAllFlags, /*Depth=*/0);
EXPECT_EQ(Known.KnownFPClasses, fcPosNormal);
// At MaxRecursionDepth, the non-constant node bails out as unknown.
Known = DAG->computeKnownFPClass(Vec, fcAllFlags,
SelectionDAG::MaxRecursionDepth);
EXPECT_EQ(Known.KnownFPClasses, fcAllFlags);
EXPECT_FALSE(Known.SignBit.has_value());
}
TEST_F(AArch64SelectionDAGTest, ComputeKnownFPClass_UndefAndPoison) {
SDLoc Loc;
// UNDEF is unknown — could be any FP class.
SDValue Undef = DAG->getUNDEF(MVT::f32);
KnownFPClass Known = DAG->computeKnownFPClass(Undef, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcAllFlags);
EXPECT_FALSE(Known.SignBit.has_value());
// POISON is fcNone — can be assumed to never be observed.
SDValue Poison = DAG->getPOISON(MVT::f32);
Known = DAG->computeKnownFPClass(Poison, fcAllFlags);
EXPECT_EQ(Known.KnownFPClasses, fcNone);
EXPECT_TRUE(Known.SignBit.has_value());
EXPECT_FALSE(*Known.SignBit);
}
} // end namespace llvm