diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp index 7682af4543b7c..7a7e5e29e1ad0 100644 --- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp +++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.cpp @@ -1808,6 +1808,20 @@ bool HexagonInstrInfo::isPredicable(const MachineInstr &MI) const { return true; } +bool HexagonInstrInfo::isAssociativeAndCommutative(const MachineInstr &Inst, + bool Invert) const { + if (Invert) + return false; + + switch (Inst.getOpcode()) { + // TODO: Add more instructions to be handled by MachineCombiner. + case Hexagon::F2_sfadd: + return Inst.getFlag(MachineInstr::MIFlag::FmReassoc); + default: + return false; + } +} + bool HexagonInstrInfo::isSchedulingBoundary(const MachineInstr &MI, const MachineBasicBlock *MBB, const MachineFunction &MF) const { diff --git a/llvm/lib/Target/Hexagon/HexagonInstrInfo.h b/llvm/lib/Target/Hexagon/HexagonInstrInfo.h index 796b978a2c3f0..29d45fd85ac43 100644 --- a/llvm/lib/Target/Hexagon/HexagonInstrInfo.h +++ b/llvm/lib/Target/Hexagon/HexagonInstrInfo.h @@ -505,6 +505,9 @@ class HexagonInstrInfo : public HexagonGenInstrInfo { bool ToBigInstrs = true) const; void translateInstrsForDup(MachineBasicBlock::instr_iterator MII, bool ToBigInstrs) const; + bool useMachineCombiner() const override { return true; } + bool isAssociativeAndCommutative(const MachineInstr &Inst, + bool Invert) const override; // Addressing mode relations. short changeAddrMode_abs_io(short Opc) const; diff --git a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp index d9824a3154093..70d87a0a62a21 100644 --- a/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp +++ b/llvm/lib/Target/Hexagon/HexagonTargetMachine.cpp @@ -47,6 +47,9 @@ static cl::opt DisableHardwareLoops("disable-hexagon-hwloops", cl::Hidden, cl::desc("Disable Hardware Loops for Hexagon target")); +static cl::opt EnableMCR("hexagon-mcr", cl::Hidden, cl::init(true), + cl::desc("Enable the machine combiner pass")); + static cl::opt DisableAModeOpt("disable-hexagon-amodeopt", cl::Hidden, cl::desc("Disable Hexagon Addressing Mode Optimization")); @@ -309,6 +312,7 @@ class HexagonPassConfig : public TargetPassConfig { void addIRPasses() override; bool addInstSelector() override; + bool addILPOpts() override; void addPreRegAlloc() override; void addPostRegAlloc() override; void addPreSched2() override; @@ -393,6 +397,13 @@ bool HexagonPassConfig::addInstSelector() { return false; } +bool HexagonPassConfig::addILPOpts() { + if (EnableMCR) + addPass(&MachineCombinerID); + + return true; +} + void HexagonPassConfig::addPreRegAlloc() { if (getOptLevel() != CodeGenOptLevel::None) { if (EnableCExtOpt) diff --git a/llvm/test/CodeGen/Hexagon/machine-combiner-reassoc.mir b/llvm/test/CodeGen/Hexagon/machine-combiner-reassoc.mir new file mode 100644 index 0000000000000..275f1e79c8cc4 --- /dev/null +++ b/llvm/test/CodeGen/Hexagon/machine-combiner-reassoc.mir @@ -0,0 +1,65 @@ +# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6 +# RUN: llc -mtriple=hexagon -hexagon-mcr=true -run-pass=machine-combiner\ +# RUN: %s -o - | FileCheck %s --check-prefix=ENABLED +# RUN: llc -mtriple=hexagon -hexagon-mcr=false -run-pass=machine-combiner\ +# RUN: %s -o - | FileCheck %s --check-prefix=DISABLED + +# Test that demonstrates the machine-combiner pass performing reassociation +# to improve instruction-level parallelism (ILP) by breaking dependency chains. + +--- | + define float @test_reassoc_chain(float* nocapture readonly %a) { + ret float 0.0 + } +... + +--- +# Test a longer chain: ((A + B) + C) + D +# Should reassociate to optimize the critical path +# Verify we still have 3 F2_sfadd instructions but in optimized order +# Original chain should be preserved + +name: test_reassoc_chain +tracksRegLiveness: true +body: | + bb.0: + liveins: $r0 + + ; ENABLED-LABEL: name: test_reassoc_chain + ; ENABLED: liveins: $r0 + ; ENABLED-NEXT: {{ $}} + ; ENABLED-NEXT: [[COPY:%[0-9]+]]:intregs = COPY $r0 + ; ENABLED-NEXT: [[L2_loadri_io:%[0-9]+]]:intregs = L2_loadri_io [[COPY]], 0 + ; ENABLED-NEXT: [[L2_loadri_io1:%[0-9]+]]:intregs = L2_loadri_io [[COPY]], 4 + ; ENABLED-NEXT: [[F2_sfadd:%[0-9]+]]:intregs = nnan ninf nsz arcp contract afn reassoc F2_sfadd killed [[L2_loadri_io1]], killed [[L2_loadri_io]], implicit $usr + ; ENABLED-NEXT: [[L2_loadri_io2:%[0-9]+]]:intregs = L2_loadri_io [[COPY]], 8 + ; ENABLED-NEXT: [[L2_loadri_io3:%[0-9]+]]:intregs = L2_loadri_io [[COPY]], 12 + ; ENABLED-NEXT: [[F2_sfadd1:%[0-9]+]]:intregs = nnan ninf nsz arcp contract afn reassoc F2_sfadd killed [[L2_loadri_io2]], killed [[L2_loadri_io3]], implicit $usr + ; ENABLED-NEXT: [[F2_sfadd2:%[0-9]+]]:intregs = nnan ninf nsz arcp contract afn reassoc F2_sfadd killed [[F2_sfadd]], killed [[F2_sfadd1]], implicit $usr + ; ENABLED-NEXT: $r0 = COPY [[F2_sfadd2]] + ; ENABLED-NEXT: PS_jmpret $r31, implicit-def dead $pc, implicit $r0 + ; + ; DISABLED-LABEL: name: test_reassoc_chain + ; DISABLED: liveins: $r0 + ; DISABLED-NEXT: {{ $}} + ; DISABLED-NEXT: [[COPY:%[0-9]+]]:intregs = COPY $r0 + ; DISABLED-NEXT: [[L2_loadri_io:%[0-9]+]]:intregs = L2_loadri_io [[COPY]], 0 + ; DISABLED-NEXT: [[L2_loadri_io1:%[0-9]+]]:intregs = L2_loadri_io [[COPY]], 4 + ; DISABLED-NEXT: [[F2_sfadd:%[0-9]+]]:intregs = nnan ninf nsz arcp contract afn reassoc F2_sfadd killed [[L2_loadri_io1]], killed [[L2_loadri_io]], implicit $usr + ; DISABLED-NEXT: [[L2_loadri_io2:%[0-9]+]]:intregs = L2_loadri_io [[COPY]], 8 + ; DISABLED-NEXT: [[L2_loadri_io3:%[0-9]+]]:intregs = L2_loadri_io [[COPY]], 12 + ; DISABLED-NEXT: [[F2_sfadd1:%[0-9]+]]:intregs = nnan ninf nsz arcp contract afn reassoc F2_sfadd killed [[L2_loadri_io2]], killed [[L2_loadri_io3]], implicit $usr + ; DISABLED-NEXT: [[F2_sfadd2:%[0-9]+]]:intregs = nnan ninf nsz arcp contract afn reassoc F2_sfadd killed [[F2_sfadd]], killed [[F2_sfadd1]], implicit $usr + ; DISABLED-NEXT: $r0 = COPY [[F2_sfadd2]] + ; DISABLED-NEXT: PS_jmpret $r31, implicit-def dead $pc, implicit $r0 + %0:intregs = COPY $r0 + %1:intregs = L2_loadri_io %0:intregs, 0 + %2:intregs = L2_loadri_io %0:intregs, 4 + %3:intregs = nnan ninf nsz arcp contract afn reassoc F2_sfadd killed %2:intregs, killed %1:intregs, implicit $usr + %4:intregs = L2_loadri_io %0:intregs, 8 + %5:intregs = nnan ninf nsz arcp contract afn reassoc F2_sfadd killed %3:intregs, killed %4:intregs, implicit $usr + %6:intregs = L2_loadri_io %0:intregs, 12 + %7:intregs = nnan ninf nsz arcp contract afn reassoc F2_sfadd killed %5:intregs, killed %6:intregs, implicit $usr + $r0 = COPY %7:intregs + PS_jmpret $r31, implicit-def dead $pc, implicit $r0 +...