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
1772 lines
66 KiB
C++
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
|