Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions llvm/lib/Target/ARM/ARMISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20065,6 +20065,29 @@ void ARMTargetLowering::computeKnownBitsForTargetNode(const SDValue Op,
Known = KnownOp0.intersectWith(KnownOp1);
break;
}
case ARMISD::VORRIMM:
case ARMISD::VBICIMM: {
unsigned Encoded = Op.getConstantOperandVal(1);
unsigned DecEltBits = 0;
uint64_t DecodedVal = ARM_AM::decodeVMOVModImm(Encoded, DecEltBits);

unsigned EltBits = Op.getScalarValueSizeInBits();
if (EltBits != DecEltBits) {
// Be conservative: only update Known when EltBits == DecEltBits.
// This is believed to always be true for VORRIMM/VBICIMM today, but if
// that changes in the future, doing nothing here is safer than risking
// subtle bugs.
break;
}

KnownBits KnownLHS = DAG.computeKnownBits(Op.getOperand(0), Depth + 1);
bool IsVORR = Op.getOpcode() == ARMISD::VORRIMM;
APInt Imm(DecEltBits, DecodedVal);

Known.One = IsVORR ? (KnownLHS.One | Imm) : (KnownLHS.One & ~Imm);
Known.Zero = IsVORR ? (KnownLHS.Zero & ~Imm) : (KnownLHS.Zero | Imm);
break;
}
}
}

Expand Down
179 changes: 179 additions & 0 deletions llvm/unittests/Target/ARM/ARMSelectionDAGTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
//===----------------------------------------------------------------------===//
// 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 "ARMISelLowering.h"
#include "MCTargetDesc/ARMAddressingModes.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/CodeGen/MachineModuleInfo.h"
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/TargetLowering.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/KnownBits.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Target/TargetMachine.h"
#include "gtest/gtest.h"

namespace llvm {

class ARMSelectionDAGTest : public testing::Test {
protected:
static void SetUpTestCase() {
LLVMInitializeARMTargetInfo();
LLVMInitializeARMTarget();
LLVMInitializeARMTargetMC();
}

void SetUp() override {
StringRef Assembly = "define void @f() { ret void }";

Triple TargetTriple("armv7-unknown-none-eabi");

std::string Error;
const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);

TargetOptions Options;
TM = std::unique_ptr<TargetMachine>(
T->createTargetMachine(TargetTriple,
/*CPU*/ "cortex-a9",
/*Features*/ "+neon", 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("Function 'f' not found");

MachineModuleInfo MMI(TM.get());

MF = std::make_unique<MachineFunction>(*F, *TM, *TM->getSubtargetImpl(*F),
MMI.getContext(), /*FunctionNum*/ 0);

DAG = std::make_unique<SelectionDAG>(*TM, CodeGenOptLevel::None);
if (!DAG)
report_fatal_error("SelectionDAG allocation failed");

OptimizationRemarkEmitter ORE(F);
DAG->init(*MF, ORE, /*LibInfo*/ nullptr, /*AA*/ nullptr,
/*AC*/ nullptr, /*MDT*/ nullptr, /*MSDT*/ 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 = nullptr;
std::unique_ptr<MachineFunction> MF;
std::unique_ptr<SelectionDAG> DAG;
};

/// VORR (immediate): per-lane OR with 32-bit elements.
/// cmode=0x0 puts imm8 in byte0 => per-lane constant = 0x000000AA.
TEST_F(ARMSelectionDAGTest, computeKnownBits_VORRIMM) {
SDLoc DL;
EVT VT = MVT::v4i32;
SDValue LHS = DAG->getRegister(0, VT);

SDValue EncSD =
DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x0, 0xAA), DL, MVT::i32);
SDValue Op = DAG->getNode(ARMISD::VORRIMM, DL, VT, LHS, EncSD);

// LHS(per-lane) = ???????? ???????? ???????? ????????
// Encoded(per-lane) = 00000000 00000000 00000000 10101010 (0x000000AA)
// =>
// Known.One = 00000000 00000000 00000000 10101010 (0x000000AA)
// Known.Zero = 00000000 00000000 00000000 00000000 (0x00000000)
APInt DemandedElts = APInt::getAllOnes(4);
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
EXPECT_EQ(Known.One, APInt(32, 0xAA));
EXPECT_EQ(Known.Zero, APInt(32, 0x0));
}

/// VBIC (immediate): x & ~imm with 32-bit elements.
/// LHS(per-lane)=0xFFFFFFFF; imm per-lane = 0x000000AA => result = 0xFFFFFF55
TEST_F(ARMSelectionDAGTest, computeKnownBits_VBICIMM) {
SDLoc DL;
EVT VT = MVT::v4i32;

SDValue LHS = DAG->getConstant(APInt(32, 0xFFFFFFFF), DL, VT);

SDValue EncSD =
DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x0, 0xAA), DL, MVT::i32);
SDValue Op = DAG->getNode(ARMISD::VBICIMM, DL, VT, LHS, EncSD);

// LHS(per-lane) = 11111111 11111111 11111111 11111111 (0xFFFFFFFF)
// Encoded(per-lane) = 00000000 00000000 00000000 10101010 (0x000000AA)
// =>
// Known.One = 11111111 11111111 11111111 01010101 (0xFFFFFF55)
// Known.Zero = 00000000 00000000 00000000 10101010 (0x000000AA)
APInt DemandedElts = APInt::getAllOnes(4);
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
EXPECT_EQ(Known.One, APInt(32, 0xFFFFFF55));
EXPECT_EQ(Known.Zero, APInt(32, 0x000000AA));
}

/// VORR (immediate): per-lane OR with 32-bit elements.
/// Encoded = 0x2AA (cmode=0x2, imm8=0xAA) => per-lane constant = 0x0000AA00.
TEST_F(ARMSelectionDAGTest, computeKnownBits_VORRIMM_cmode2) {
SDLoc DL;
EVT VT = MVT::v4i32;
SDValue LHS = DAG->getRegister(0, VT);

// Use the exact encoded immediate the reviewer asked for.
SDValue EncSD =
DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x2, 0xAA), DL, MVT::i32);
SDValue Op = DAG->getNode(ARMISD::VORRIMM, DL, VT, LHS, EncSD);

// LHS (per-lane) = ???????? ???????? ???????? ????????
// Encoded (per-lane) = 00000000 00000000 10101010 00000000 (0x0000AA00)
// =>
// Known.One = 00000000 00000000 10101010 00000000 (0x0000AA00)
// Known.Zero = 00000000 00000000 00000000 00000000 (0x00000000)
APInt DemandedElts = APInt::getAllOnes(4);
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
EXPECT_EQ(Known.One, APInt(32, 0x0000AA00));
EXPECT_EQ(Known.Zero, APInt(32, 0x00000000));
}

/// VBIC (immediate) with constant-all-ones LHS:
/// Encoded = 0x2AA => per-lane constant = 0x0000AA00; VBIC = A & ~Imm.
TEST_F(ARMSelectionDAGTest, computeKnownBits_VBICIMM_cmode2_lhs_ones) {
SDLoc DL;
EVT VT = MVT::v4i32;

SDValue LHS = DAG->getConstant(APInt(32, 0xFFFFFFFF), DL, VT);
SDValue EncSD =
DAG->getTargetConstant(ARM_AM::createVMOVModImm(0x2, 0xAA), DL, MVT::i32);
SDValue Op = DAG->getNode(ARMISD::VBICIMM, DL, VT, LHS, EncSD);

// LHS (per-lane) = 11111111 11111111 11111111 11111111
// Encoded (per-lane) = 00000000 00000000 10101010 00000000 (0x0000AA00)
// =>
// Known.One = 11111111 11111111 01010101 11111111 (0xFFFF55FF)
// Known.Zero = 00000000 00000000 10101010 00000000 (0x0000AA00)
APInt DemandedElts = APInt::getAllOnes(4);
KnownBits Known = DAG->computeKnownBits(Op, DemandedElts);
EXPECT_EQ(Known.One, APInt(32, 0xFFFF55FF));
EXPECT_EQ(Known.Zero, APInt(32, 0x0000AA00));
}

} // end namespace llvm
1 change: 1 addition & 0 deletions llvm/unittests/Target/ARM/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,5 @@ set(LLVM_LINK_COMPONENTS
add_llvm_target_unittest(ARMTests
MachineInstrTest.cpp
InstSizes.cpp
ARMSelectionDAGTest.cpp
)
Loading