summaryrefslogtreecommitdiff
path: root/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Lanai/LanaiSetflagAluCombiner.cpp')
-rw-r--r--lib/Target/Lanai/LanaiSetflagAluCombiner.cpp327
1 files changed, 327 insertions, 0 deletions
diff --git a/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp b/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp
new file mode 100644
index 00000000000..973025da1fc
--- /dev/null
+++ b/lib/Target/Lanai/LanaiSetflagAluCombiner.cpp
@@ -0,0 +1,327 @@
+//===-- LanaiSetflagAluCombiner.cpp - Pass to combine set flag & ALU ops --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Lanai.h"
+#include "LanaiTargetMachine.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/RegisterScavenging.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Target/TargetInstrInfo.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "lanai-setflag-alu-combiner"
+
+STATISTIC(NumSetflagAluCombined,
+ "Number of SET_FLAG and ALU instructions combined");
+
+static llvm::cl::opt<bool> DisableSetflagAluCombiner(
+ "disable-lanai-setflag-alu-combiner", llvm::cl::init(false),
+ llvm::cl::desc("Do not combine SET_FLAG and ALU operators"),
+ llvm::cl::Hidden);
+
+namespace llvm {
+void initializeLanaiSetflagAluCombinerPass(PassRegistry &);
+} // namespace llvm
+
+namespace {
+typedef MachineBasicBlock::iterator MbbIterator;
+typedef MachineFunction::iterator MfIterator;
+
+class LanaiSetflagAluCombiner : public MachineFunctionPass {
+public:
+ static char ID;
+ LanaiSetflagAluCombiner() : MachineFunctionPass(ID) {
+ initializeLanaiSetflagAluCombinerPass(*PassRegistry::getPassRegistry());
+ }
+
+ const char *getPassName() const override {
+ return "Lanai SET_FLAG ALU combiner pass";
+ }
+
+ bool runOnMachineFunction(MachineFunction &F) override;
+
+private:
+ bool CombineSetflagAluInBasicBlock(MachineFunction *MF,
+ MachineBasicBlock *BB);
+};
+} // namespace
+
+char LanaiSetflagAluCombiner::ID = 0;
+
+INITIALIZE_PASS(LanaiSetflagAluCombiner, DEBUG_TYPE,
+ "Lanai SET_FLAG ALU combiner pass", false, false);
+
+namespace {
+
+const unsigned kInvalid = -1;
+
+static unsigned flagSettingOpcodeVariant(unsigned OldOpcode) {
+ switch (OldOpcode) {
+ case Lanai::ADD_I_HI:
+ return Lanai::ADD_F_I_HI;
+ case Lanai::ADD_I_LO:
+ return Lanai::ADD_F_I_LO;
+ case Lanai::ADD_R:
+ return Lanai::ADD_F_R;
+ case Lanai::ADD_R_CC:
+ return Lanai::ADD_F_R_CC;
+ case Lanai::ADDC_I_HI:
+ return Lanai::ADDC_F_I_HI;
+ case Lanai::ADDC_I_LO:
+ return Lanai::ADDC_F_I_LO;
+ case Lanai::ADDC_R:
+ return Lanai::ADDC_F_R;
+ case Lanai::ADDC_R_CC:
+ return Lanai::ADDC_F_R_CC;
+ case Lanai::AND_I_HI:
+ return Lanai::AND_F_I_HI;
+ case Lanai::AND_I_LO:
+ return Lanai::AND_F_I_LO;
+ case Lanai::AND_R:
+ return Lanai::AND_F_R;
+ case Lanai::AND_R_CC:
+ return Lanai::AND_F_R_CC;
+ case Lanai::OR_I_HI:
+ return Lanai::OR_F_I_HI;
+ case Lanai::OR_I_LO:
+ return Lanai::OR_F_I_LO;
+ case Lanai::OR_R:
+ return Lanai::OR_F_R;
+ case Lanai::OR_R_CC:
+ return Lanai::OR_F_R_CC;
+ case Lanai::SL_I:
+ return Lanai::SL_F_I;
+ case Lanai::SRL_R:
+ return Lanai::SRL_F_R;
+ case Lanai::SA_I:
+ return Lanai::SA_F_I;
+ case Lanai::SRA_R:
+ return Lanai::SRA_F_R;
+ case Lanai::SUB_I_HI:
+ return Lanai::SUB_F_I_HI;
+ case Lanai::SUB_I_LO:
+ return Lanai::SUB_F_I_LO;
+ case Lanai::SUB_R:
+ return Lanai::SUB_F_R;
+ case Lanai::SUB_R_CC:
+ return Lanai::SUB_F_R_CC;
+ case Lanai::SUBB_I_HI:
+ return Lanai::SUBB_F_I_HI;
+ case Lanai::SUBB_I_LO:
+ return Lanai::SUBB_F_I_LO;
+ case Lanai::SUBB_R:
+ return Lanai::SUBB_F_R;
+ case Lanai::SUBB_R_CC:
+ return Lanai::SUBB_F_R_CC;
+ case Lanai::XOR_I_HI:
+ return Lanai::XOR_F_I_HI;
+ case Lanai::XOR_I_LO:
+ return Lanai::XOR_F_I_LO;
+ case Lanai::XOR_R:
+ return Lanai::XOR_F_R;
+ case Lanai::XOR_R_CC:
+ return Lanai::XOR_F_R_CC;
+ default:
+ return kInvalid;
+ }
+}
+
+// Returns whether opcode corresponds to instruction that sets flags.
+static bool isFlagSettingInstruction(unsigned Opcode) {
+ switch (Opcode) {
+ case Lanai::ADDC_F_I_HI:
+ case Lanai::ADDC_F_I_LO:
+ case Lanai::ADDC_F_R:
+ case Lanai::ADDC_F_R_CC:
+ case Lanai::ADD_F_I_HI:
+ case Lanai::ADD_F_I_LO:
+ case Lanai::ADD_F_R:
+ case Lanai::ADD_F_R_CC:
+ case Lanai::AND_F_I_HI:
+ case Lanai::AND_F_I_LO:
+ case Lanai::AND_F_R:
+ case Lanai::AND_F_R_CC:
+ case Lanai::OR_F_I_HI:
+ case Lanai::OR_F_I_LO:
+ case Lanai::OR_F_R:
+ case Lanai::OR_F_R_CC:
+ case Lanai::SFSUB_F_RI:
+ case Lanai::SFSUB_F_RR:
+ case Lanai::SA_F_I:
+ case Lanai::SL_F_I:
+ case Lanai::SHL_F_R:
+ case Lanai::SRA_F_R:
+ case Lanai::SRL_F_R:
+ case Lanai::SUBB_F_I_HI:
+ case Lanai::SUBB_F_I_LO:
+ case Lanai::SUBB_F_R:
+ case Lanai::SUBB_F_R_CC:
+ case Lanai::SUB_F_I_HI:
+ case Lanai::SUB_F_I_LO:
+ case Lanai::SUB_F_R:
+ case Lanai::SUB_F_R_CC:
+ case Lanai::XOR_F_I_HI:
+ case Lanai::XOR_F_I_LO:
+ case Lanai::XOR_F_R:
+ case Lanai::XOR_F_R_CC:
+ return true;
+ default:
+ return false;
+ }
+}
+
+// Return the Conditional Code operand for a given instruction kind. For
+// example, operand at index 1 of a BRIND_CC instruction is the conditional code
+// (eq, ne, etc.). Returns -1 if the instruction does not have a conditional
+// code.
+static int getCCOperandPosition(unsigned Opcode) {
+ switch (Opcode) {
+ case Lanai::BRIND_CC:
+ case Lanai::BRIND_CCA:
+ case Lanai::BRR:
+ case Lanai::BRCC:
+ case Lanai::SCC:
+ return 1;
+ case Lanai::SELECT:
+ case Lanai::ADDC_F_R_CC:
+ case Lanai::ADDC_R_CC:
+ case Lanai::ADD_F_R_CC:
+ case Lanai::ADD_R_CC:
+ case Lanai::AND_F_R_CC:
+ case Lanai::AND_R_CC:
+ case Lanai::OR_F_R_CC:
+ case Lanai::OR_R_CC:
+ case Lanai::SUBB_F_R_CC:
+ case Lanai::SUBB_R_CC:
+ case Lanai::SUB_F_R_CC:
+ case Lanai::SUB_R_CC:
+ case Lanai::XOR_F_R_CC:
+ case Lanai::XOR_R_CC:
+ return 3;
+ default:
+ return -1;
+ }
+}
+
+// Returns true if instruction is a lowered SET_FLAG instruction with 0/R0 as
+// the first operand and whose conditional code is such that it can be merged
+// (i.e., EQ, NE, PL and MI).
+static bool isSuitableSetflag(MbbIterator Instruction, MbbIterator End) {
+ unsigned Opcode = Instruction->getOpcode();
+ if (Opcode == Lanai::SFSUB_F_RI || Opcode == Lanai::SFSUB_F_RR) {
+ const MachineOperand &Operand = Instruction->getOperand(1);
+ if (Operand.isReg() && Operand.getReg() != Lanai::R0)
+ return false;
+ if (Operand.isImm() && Operand.getImm() != 0)
+ return false;
+
+ MbbIterator SCCUserIter = Instruction;
+ while (SCCUserIter != End) {
+ ++SCCUserIter;
+ // Early exit when encountering flag setting instruction.
+ if (isFlagSettingInstruction(SCCUserIter->getOpcode()))
+ break;
+ int CCIndex = getCCOperandPosition(SCCUserIter->getOpcode());
+ if (CCIndex != -1) {
+ LPCC::CondCode CC = static_cast<LPCC::CondCode>(
+ SCCUserIter->getOperand(CCIndex).getImm());
+ if (CC != LPCC::ICC_EQ && CC != LPCC::ICC_NE && CC != LPCC::ICC_PL &&
+ CC != LPCC::ICC_MI)
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+// Combines a SET_FLAG instruction comparing a register with 0 and an ALU
+// operation that sets the same register used in the comparison into a single
+// flag setting ALU instruction (both instructions combined are removed and new
+// flag setting ALU operation inserted where ALU instruction was).
+bool LanaiSetflagAluCombiner::CombineSetflagAluInBasicBlock(
+ MachineFunction *MF, MachineBasicBlock *BB) {
+ bool Modified = false;
+ const TargetInstrInfo *TII =
+ MF->getSubtarget<LanaiSubtarget>().getInstrInfo();
+
+ MbbIterator SetflagIter = BB->begin();
+ MbbIterator End = BB->end();
+ MbbIterator Begin = BB->begin();
+ while (SetflagIter != End) {
+ bool Replaced = false;
+ if (isSuitableSetflag(SetflagIter, End)) {
+ MbbIterator AluIter = SetflagIter;
+ while (AluIter != Begin) {
+ --AluIter;
+ // Skip debug instructions. Debug instructions don't affect codegen.
+ if (AluIter->isDebugValue()) {
+ continue;
+ }
+ // Early exit when encountering flag setting instruction.
+ if (isFlagSettingInstruction(AluIter->getOpcode())) {
+ break;
+ }
+ // Check that output of AluIter is equal to input of SetflagIter.
+ if (AluIter->getNumOperands() > 1 && AluIter->getOperand(0).isReg() &&
+ (AluIter->getOperand(0).getReg() ==
+ SetflagIter->getOperand(0).getReg())) {
+ unsigned NewOpc = flagSettingOpcodeVariant(AluIter->getOpcode());
+ if (NewOpc == kInvalid)
+ break;
+
+ // Change the ALU instruction to the flag setting variant.
+ AluIter->setDesc(TII->get(NewOpc));
+ AluIter->addImplicitDefUseOperands(*MF);
+
+ Replaced = true;
+ ++NumSetflagAluCombined;
+ break;
+ }
+ }
+ // Erase the setflag instruction if merged.
+ if (Replaced) {
+ BB->erase(SetflagIter++);
+ }
+ }
+
+ Modified |= Replaced;
+ if (SetflagIter == End)
+ break;
+ if (!Replaced)
+ ++SetflagIter;
+ }
+
+ return Modified;
+}
+
+// Driver function that iterates over the machine basic building blocks of a
+// machine function
+bool LanaiSetflagAluCombiner::runOnMachineFunction(MachineFunction &MF) {
+ if (DisableSetflagAluCombiner)
+ return false;
+
+ bool Modified = false;
+ MfIterator End = MF.end();
+ for (MfIterator MFI = MF.begin(); MFI != End; ++MFI) {
+ Modified |= CombineSetflagAluInBasicBlock(&MF, &*MFI);
+ }
+ return Modified;
+}
+} // namespace
+
+FunctionPass *llvm::createLanaiSetflagAluCombinerPass() {
+ return new LanaiSetflagAluCombiner();
+}