summaryrefslogtreecommitdiff
path: root/lib/Target/Hexagon/HexagonOptimizeConstExt.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/Hexagon/HexagonOptimizeConstExt.cpp')
-rw-r--r--lib/Target/Hexagon/HexagonOptimizeConstExt.cpp261
1 files changed, 261 insertions, 0 deletions
diff --git a/lib/Target/Hexagon/HexagonOptimizeConstExt.cpp b/lib/Target/Hexagon/HexagonOptimizeConstExt.cpp
new file mode 100644
index 0000000000..91987a0d81
--- /dev/null
+++ b/lib/Target/Hexagon/HexagonOptimizeConstExt.cpp
@@ -0,0 +1,261 @@
+//===---- HexagonOptimizeConstExt.cpp - Optimize Constant Extender Use ----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass traverses through all the basic blocks in a functions and replaces
+// constant extended instruction with their register equivalent if the same
+// constant is being used by more than two instructions.
+//===----------------------------------------------------------------------===//
+
+#define DEBUG_TYPE "xfer"
+#include "llvm/CodeGen/MachineDominators.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "HexagonTargetMachine.h"
+#include "HexagonConstExtInfo.h"
+#include "llvm/CodeGen/MachineFunctionAnalysis.h"
+#include "llvm/Support/CommandLine.h"
+#define DEBUG_TYPE "xfer"
+
+using namespace llvm;
+
+namespace {
+
+class HexagonOptimizeConstExt : public MachineFunctionPass {
+ HexagonTargetMachine& QTM;
+ const HexagonSubtarget &QST;
+
+public:
+ static char ID;
+ HexagonOptimizeConstExt(HexagonTargetMachine& TM)
+ : MachineFunctionPass(ID), QTM(TM), QST(*TM.getSubtargetImpl()) {}
+
+ const char *getPassName() const {
+ return "Remove sub-optimal uses of constant extenders";
+ }
+
+ void getAnalysisUsage(AnalysisUsage &AU) const {
+ MachineFunctionPass::getAnalysisUsage(AU);
+ AU.addRequired<MachineDominatorTree>();
+ AU.addPreserved<MachineDominatorTree>();
+ }
+
+ bool runOnMachineFunction(MachineFunction &Fn);
+ void removeConstExtFromMI (const HexagonInstrInfo *TII, MachineInstr* oldMI,
+ unsigned DestReg);
+};
+
+char HexagonOptimizeConstExt::ID = 0;
+
+// Remove constant extended instructions with the corresponding non-extended
+// instruction.
+void HexagonOptimizeConstExt::removeConstExtFromMI (const HexagonInstrInfo *TII,
+ MachineInstr* oldMI,
+ unsigned DestReg) {
+ assert(HexagonConstExt::NonExtEquivalentExists(oldMI->getOpcode()) &&
+ "Non-extended equivalent instruction doesn't exist");
+ MachineBasicBlock *MBB = oldMI->getParent ();
+ int oldOpCode = oldMI->getOpcode();
+ unsigned short CExtOpNum = HexagonConstExt::getCExtOpNum(oldOpCode);
+ unsigned numOperands = oldMI->getNumOperands();
+ MachineInstrBuilder MIB = BuildMI(*MBB, oldMI, oldMI->getDebugLoc(),
+ TII->get(HexagonConstExt::getNonExtOpcode(oldMI->getOpcode())));
+
+ for (unsigned i = 0; i < numOperands; ++i) {
+ if (i == CExtOpNum) {
+ MIB.addReg(DestReg);
+ if (oldMI->getDesc().mayLoad()) {
+ // As of now, only absolute addressing mode instructions can load from
+ // global addresses. Other addressing modes allow only constant
+ // literals. Load with absolute addressing mode gets replaced with the
+ // corresponding base+offset load.
+ if (oldMI->getOperand(i).isGlobal()) {
+ MIB.addImm(oldMI->getOperand(i).getOffset());
+ }
+ else
+ MIB.addImm(0);
+ }
+ else if (oldMI->getDesc().mayStore()){
+ if (oldMI->getOperand(i).isGlobal()) {
+ // If stored value is a global address and is extended, it is required
+ // to have 0 offset.
+ if (CExtOpNum == (numOperands-1))
+ assert((oldMI->getOperand(i).getOffset()==0) && "Invalid Offset");
+ else
+ MIB.addImm(oldMI->getOperand(i).getOffset());
+ }
+ else if (CExtOpNum != (numOperands-1))
+ MIB.addImm(0);
+ }
+ }
+ else {
+ const MachineOperand &op = oldMI->getOperand(i);
+ MIB.addOperand(op);
+ }
+ }
+ DEBUG(dbgs () << "Removing old instr: " << *oldMI << "\n");
+ DEBUG(dbgs() << "New instr: " << (*MIB) << "\n");
+ oldMI->eraseFromParent();
+}
+
+// Returns false for the following instructions, since it may not be profitable
+// to convert these instructions into a non-extended instruction if the offset
+// is non-zero.
+static bool canHaveAnyOffset(MachineInstr* MI) {
+ switch (MI->getOpcode()) {
+ case Hexagon::STriw_offset_ext_V4:
+ case Hexagon::STrih_offset_ext_V4:
+ return false;
+ default:
+ return true;
+ }
+}
+
+bool HexagonOptimizeConstExt::runOnMachineFunction(MachineFunction &Fn) {
+
+ const HexagonInstrInfo *TII = QTM.getInstrInfo();
+ MachineDominatorTree &MDT = getAnalysis<MachineDominatorTree>();
+
+ // CExtMap maintains a list of instructions for each constant extended value.
+ // It also keeps a flag for the value to indicate if it's a global address
+ // or a constant literal.
+ StringMap<std::pair<SmallVector<MachineInstr*, 8>, bool > > CExtMap;
+
+ // Loop over all the basic blocks
+ for (MachineFunction::iterator MBBb = Fn.begin(), MBBe = Fn.end();
+ MBBb != MBBe; ++MBBb) {
+ MachineBasicBlock* MBB = MBBb;
+
+ // Traverse the basic block and update a map of (ImmValue->MI)
+ MachineBasicBlock::iterator MII = MBB->begin();
+ MachineBasicBlock::iterator MIE = MBB->end ();
+
+ while (MII != MIE) {
+ MachineInstr *MI = MII;
+ // Check if the instruction has any constant extended operand and also has
+ // a non-extended equivalent.
+ if (TII->isConstExtended(MI) &&
+ HexagonConstExt::NonExtEquivalentExists(MI->getOpcode())) {
+ short ExtOpNum = HexagonConstExt::getCExtOpNum(MI->getOpcode());
+ SmallString<256> TmpData;
+ if (MI->getOperand(ExtOpNum).isImm()) {
+ DEBUG(dbgs() << "Selected for replacement : " << *MI << "\n");
+ int ImmValue = MI->getOperand(ExtOpNum).getImm();
+ StringRef ExtValue = Twine(ImmValue).toStringRef(TmpData);
+ CExtMap[ExtValue].first.push_back(MI);
+ CExtMap[ExtValue].second = false;
+ }
+ else if (MI->getOperand(ExtOpNum).isGlobal()) {
+ StringRef ExtValue = MI->getOperand(ExtOpNum).getGlobal()->getName();
+ // If stored value is constant extended and has an offset, it's not
+ // profitable to replace these instructions with the non-extended
+ // version.
+ if (MI->getOperand(ExtOpNum).getOffset() == 0
+ || canHaveAnyOffset(MI)) {
+ DEBUG(dbgs() << "Selected for replacement : " << *MI << "\n");
+ CExtMap[ExtValue].first.push_back(MI);
+ CExtMap[ExtValue].second = true;
+ }
+ }
+ }
+ ++MII;
+ } // While ends
+ }
+
+ enum OpType {imm, GlobalAddr};
+ // Process the constants that have been extended.
+ for (StringMap<std::pair<SmallVector<MachineInstr*, 8>, bool> >::iterator II=
+ CExtMap.begin(), IE = CExtMap.end(); II != IE; ++II) {
+
+ SmallVector<MachineInstr*, 8> &MIList = (*II).second.first;
+
+ // Replace the constant extended instructions with the non-extended
+ // equivalent if more than 2 instructions extend the same constant value.
+ if (MIList.size() <= 2)
+ continue;
+
+ bool ExtOpType = (*II).second.second;
+ StringRef ExtValue = (*II).getKeyData();
+ const GlobalValue *GV = NULL;
+ unsigned char TargetFlags=0;
+ int ExtOpNum = HexagonConstExt::getCExtOpNum(MIList[0]->getOpcode());
+ SmallVector<MachineBasicBlock*, 8> MachineBlocks;
+
+ if (ExtOpType == GlobalAddr) {
+ GV = MIList[0]->getOperand(ExtOpNum).getGlobal();
+ TargetFlags = MIList[0]->getOperand(ExtOpNum).getTargetFlags();
+ }
+
+ // For each instruction in the list, record the block it belongs to.
+ for (SmallVector<MachineInstr*, 8>::iterator LB = MIList.begin(),
+ LE = MIList.end(); LB != LE; ++LB) {
+ MachineInstr *MI = (*LB);
+ MachineBlocks.push_back (MI->getParent());
+ }
+
+ MachineBasicBlock* CommDomBlock = MachineBlocks[0];
+ MachineBasicBlock* oldCommDomBlock = NULL;
+ // replaceMIs is the list of instructions to be replaced with a
+ // non-extended equivalent instruction.
+ // The idea here is that not all the instructions in the MIList will
+ // be replaced with a register.
+ SmallVector<MachineInstr*, 8> replaceMIs;
+ replaceMIs.push_back(MIList[0]);
+
+ for (unsigned i= 1; i < MachineBlocks.size(); ++i) {
+ oldCommDomBlock = CommDomBlock;
+ MachineBasicBlock *BB = MachineBlocks[i];
+ CommDomBlock = MDT.findNearestCommonDominator(&(*CommDomBlock),
+ &(*BB));
+ if (!CommDomBlock) {
+ CommDomBlock = oldCommDomBlock;
+ break;
+ }
+ replaceMIs.push_back(MIList[i]);
+ }
+
+ // Insert into CommDomBlock.
+ if (CommDomBlock) {
+ unsigned DestReg = TII->createVR (CommDomBlock->getParent(), MVT::i32);
+ MachineInstr *firstMI = CommDomBlock->getFirstNonPHI();
+ if (ExtOpType == imm) {
+ int ImmValue = 0;
+ ExtValue.getAsInteger(10,ImmValue);
+ BuildMI (*CommDomBlock, firstMI, firstMI->getDebugLoc(),
+ TII->get(Hexagon::TFRI), DestReg)
+ .addImm(ImmValue);
+ }
+ else {
+ BuildMI (*CommDomBlock, firstMI, firstMI->getDebugLoc(),
+ TII->get(Hexagon::TFRI_V4), DestReg)
+ .addGlobalAddress(GV, 0, TargetFlags);
+ }
+ for (unsigned i= 0; i < replaceMIs.size(); i++) {
+ MachineInstr *oldMI = replaceMIs[i];
+ removeConstExtFromMI(TII, oldMI, DestReg);
+ }
+ replaceMIs.clear();
+ }
+ }
+ return true;
+}
+}
+
+//===----------------------------------------------------------------------===//
+// Public Constructor Functions
+//===----------------------------------------------------------------------===//
+
+FunctionPass *
+llvm::createHexagonOptimizeConstExt(HexagonTargetMachine &TM) {
+ return new HexagonOptimizeConstExt(TM);
+}
+