[llvm] [SLP] Make getSameOpcode support interchangeable instructions. (PR #127450)
Alexey Bataev via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 17 04:38:48 PST 2025
================
@@ -810,6 +810,207 @@ static std::optional<unsigned> getExtractIndex(Instruction *E) {
namespace {
+/// Base class for representing instructions that can be interchanged with other
+/// equivalent forms. For example, multiplication by a power of 2 can be
+/// interchanged with a left shift.
+///
+/// Derived classes implement specific interchange patterns by overriding the
+/// virtual methods to define their interchange logic.
+///
+/// The class maintains a reference to the main instruction (MainOp) and
+/// provides methods to:
+/// - Check if another instruction is interchangeable (isSame)
+/// - Get the opcode for the interchangeable form
+/// (getInterchangeableInstructionOpcode)
+/// - Get the operands for the interchangeable form
+/// (getInterchangeableInstructionOps)
+class InterchangeableInstruction {
+protected:
+ Instruction *const MainOp;
+
+ /// Return non nullptr if the right operand of I is ConstantInt.
+ static ConstantInt *isBinOpWithConstantInt(Instruction *I) {
+ Constant *C;
+ if (!match(I, m_BinOp(m_Value(), m_Constant(C))))
+ return nullptr;
+ if (auto *CI = dyn_cast<ConstantInt>(C)) {
+ return CI;
+ } else if (auto *CDV = dyn_cast<ConstantDataVector>(C)) {
+ if (auto *CI = dyn_cast_if_present<ConstantInt>(CDV->getSplatValue()))
+ return CI;
+ }
+ return nullptr;
+ }
+
+public:
+ InterchangeableInstruction(Instruction *MainOp) : MainOp(MainOp) {}
+ virtual bool isSame(Instruction *I) {
+ return MainOp->getOpcode() == I->getOpcode();
+ }
+ virtual unsigned getInterchangeableInstructionOpcode() {
+ return MainOp->getOpcode();
+ }
+ virtual SmallVector<Value *>
+ getInterchangeableInstructionOps(Instruction *I) {
+ assert(MainOp->getOpcode() == I->getOpcode());
+ return SmallVector<Value *>(MainOp->operands());
+ }
+ virtual ~InterchangeableInstruction() = default;
+};
+
+class BinOpIsNoOp final : public InterchangeableInstruction {
+ constexpr static std::initializer_list<unsigned> SupportedOp = {
+ Instruction::Add, Instruction::Sub, Instruction::Mul, Instruction::Shl,
+ Instruction::AShr, Instruction::And, Instruction::Or, Instruction::Xor};
+ SmallVector<unsigned> CandidateOp = SupportedOp;
+
+public:
+ using InterchangeableInstruction::InterchangeableInstruction;
+ bool isSame(Instruction *I) override {
+ unsigned Opcode = I->getOpcode();
+ if (!is_contained(SupportedOp, Opcode))
+ return false;
+ ConstantInt *CI = isBinOpWithConstantInt(I);
+ if (CI) {
+ switch (Opcode) {
+ case Instruction::Mul:
+ if (CI->getValue().isOne())
+ return true;
+ break;
+ case Instruction::And:
+ if (CI->getValue().isAllOnes())
+ return true;
+ break;
+ default:
+ if (CI->getValue().isZero())
+ return true;
+ }
+ }
+ if (is_contained(CandidateOp, Opcode)) {
+ CandidateOp = {Opcode};
+ return true;
+ }
+ return false;
+ }
+ unsigned getInterchangeableInstructionOpcode() override {
+ assert(!CandidateOp.empty() && "Cannot find interchangeable instruction.");
+ if (is_contained(CandidateOp, MainOp->getOpcode()))
+ return MainOp->getOpcode();
+ return CandidateOp[0];
+ }
+ SmallVector<Value *>
+ getInterchangeableInstructionOps(Instruction *I) override {
+ assert(is_contained(SupportedOp, I->getOpcode()));
----------------
alexey-bataev wrote:
Add a message
https://github.com/llvm/llvm-project/pull/127450
More information about the llvm-commits
mailing list