238 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			238 lines
		
	
	
		
			7.7 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===----- HexagonMCShuffler.cpp - MC bundle shuffling --------------------===//
 | |
| //
 | |
| //                     The LLVM Compiler Infrastructure
 | |
| //
 | |
| // This file is distributed under the University of Illinois Open Source
 | |
| // License. See LICENSE.TXT for details.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This implements the shuffling of insns inside a bundle according to the
 | |
| // packet formation rules of the Hexagon ISA.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #define DEBUG_TYPE "hexagon-shuffle"
 | |
| 
 | |
| #include "Hexagon.h"
 | |
| #include "MCTargetDesc/HexagonMCInstrInfo.h"
 | |
| #include "MCTargetDesc/HexagonMCShuffler.h"
 | |
| #include "MCTargetDesc/HexagonMCTargetDesc.h"
 | |
| #include "llvm/Support/CommandLine.h"
 | |
| #include "llvm/Support/Debug.h"
 | |
| #include "llvm/Support/raw_ostream.h"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| static cl::opt<bool>
 | |
|     DisableShuffle("disable-hexagon-shuffle", cl::Hidden, cl::init(false),
 | |
|                    cl::desc("Disable Hexagon instruction shuffling"));
 | |
| 
 | |
| void HexagonMCShuffler::init(MCInst &MCB) {
 | |
|   if (HexagonMCInstrInfo::isBundle(MCB)) {
 | |
|     MCInst const *Extender = nullptr;
 | |
|     // Copy the bundle for the shuffling.
 | |
|     for (const auto &I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
 | |
|       assert(!HexagonMCInstrInfo::getDesc(MCII, *I.getInst()).isPseudo());
 | |
|       MCInst *MI = const_cast<MCInst *>(I.getInst());
 | |
| 
 | |
|       if (!HexagonMCInstrInfo::isImmext(*MI)) {
 | |
|         append(MI, Extender, HexagonMCInstrInfo::getUnits(MCII, STI, *MI),
 | |
|                false);
 | |
|         Extender = nullptr;
 | |
|       } else
 | |
|         Extender = MI;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   BundleFlags = MCB.getOperand(0).getImm();
 | |
| }
 | |
| 
 | |
| void HexagonMCShuffler::init(MCInst &MCB, MCInst const *AddMI,
 | |
|                              bool bInsertAtFront) {
 | |
|   if (HexagonMCInstrInfo::isBundle(MCB)) {
 | |
|     if (bInsertAtFront && AddMI)
 | |
|       append(AddMI, nullptr, HexagonMCInstrInfo::getUnits(MCII, STI, *AddMI),
 | |
|              false);
 | |
|     MCInst const *Extender = nullptr;
 | |
|     // Copy the bundle for the shuffling.
 | |
|     for (auto const &I : HexagonMCInstrInfo::bundleInstructions(MCB)) {
 | |
|       assert(!HexagonMCInstrInfo::getDesc(MCII, *I.getInst()).isPseudo());
 | |
|       MCInst *MI = const_cast<MCInst *>(I.getInst());
 | |
|       if (!HexagonMCInstrInfo::isImmext(*MI)) {
 | |
|         append(MI, Extender, HexagonMCInstrInfo::getUnits(MCII, STI, *MI),
 | |
|                false);
 | |
|         Extender = nullptr;
 | |
|       } else
 | |
|         Extender = MI;
 | |
|     }
 | |
|     if (!bInsertAtFront && AddMI)
 | |
|       append(AddMI, nullptr, HexagonMCInstrInfo::getUnits(MCII, STI, *AddMI),
 | |
|              false);
 | |
|   }
 | |
| 
 | |
|   BundleFlags = MCB.getOperand(0).getImm();
 | |
| }
 | |
| 
 | |
| void HexagonMCShuffler::copyTo(MCInst &MCB) {
 | |
|   MCB.clear();
 | |
|   MCB.addOperand(MCOperand::createImm(BundleFlags));
 | |
|   // Copy the results into the bundle.
 | |
|   for (HexagonShuffler::iterator I = begin(); I != end(); ++I) {
 | |
| 
 | |
|     MCInst const *MI = I->getDesc();
 | |
|     MCInst const *Extender = I->getExtender();
 | |
|     if (Extender)
 | |
|       MCB.addOperand(MCOperand::createInst(Extender));
 | |
|     MCB.addOperand(MCOperand::createInst(MI));
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool HexagonMCShuffler::reshuffleTo(MCInst &MCB) {
 | |
|   if (shuffle()) {
 | |
|     // Copy the results into the bundle.
 | |
|     copyTo(MCB);
 | |
|   } else
 | |
|     DEBUG(MCB.dump());
 | |
| 
 | |
|   return (!getError());
 | |
| }
 | |
| 
 | |
| bool llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
 | |
|                             MCInst &MCB) {
 | |
|   HexagonMCShuffler MCS(MCII, STI, MCB);
 | |
| 
 | |
|   if (DisableShuffle)
 | |
|     // Ignore if user chose so.
 | |
|     return false;
 | |
| 
 | |
|   if (!HexagonMCInstrInfo::bundleSize(MCB)) {
 | |
|     // There once was a bundle:
 | |
|     //    BUNDLE %D2<imp-def>, %R4<imp-def>, %R5<imp-def>, %D7<imp-def>, ...
 | |
|     //      * %D2<def> = IMPLICIT_DEF; flags:
 | |
|     //      * %D7<def> = IMPLICIT_DEF; flags:
 | |
|     // After the IMPLICIT_DEFs were removed by the asm printer, the bundle
 | |
|     // became empty.
 | |
|     DEBUG(dbgs() << "Skipping empty bundle");
 | |
|     return false;
 | |
|   } else if (!HexagonMCInstrInfo::isBundle(MCB)) {
 | |
|     DEBUG(dbgs() << "Skipping stand-alone insn");
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   // Reorder the bundle and copy the result.
 | |
|   if (!MCS.reshuffleTo(MCB)) {
 | |
|     // Unless there is any error, which should not happen at this point.
 | |
|     unsigned shuffleError = MCS.getError();
 | |
|     switch (shuffleError) {
 | |
|     default:
 | |
|       llvm_unreachable("unknown error");
 | |
|     case HexagonShuffler::SHUFFLE_ERROR_INVALID:
 | |
|       llvm_unreachable("invalid packet");
 | |
|     case HexagonShuffler::SHUFFLE_ERROR_STORES:
 | |
|       llvm_unreachable("too many stores");
 | |
|     case HexagonShuffler::SHUFFLE_ERROR_LOADS:
 | |
|       llvm_unreachable("too many loads");
 | |
|     case HexagonShuffler::SHUFFLE_ERROR_BRANCHES:
 | |
|       llvm_unreachable("too many branches");
 | |
|     case HexagonShuffler::SHUFFLE_ERROR_NOSLOTS:
 | |
|       llvm_unreachable("no suitable slot");
 | |
|     case HexagonShuffler::SHUFFLE_ERROR_SLOTS:
 | |
|       llvm_unreachable("over-subscribed slots");
 | |
|     case HexagonShuffler::SHUFFLE_SUCCESS: // Single instruction case.
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| unsigned
 | |
| llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
 | |
|                        MCContext &Context, MCInst &MCB,
 | |
|                        SmallVector<DuplexCandidate, 8> possibleDuplexes) {
 | |
| 
 | |
|   if (DisableShuffle)
 | |
|     return HexagonShuffler::SHUFFLE_SUCCESS;
 | |
| 
 | |
|   if (!HexagonMCInstrInfo::bundleSize(MCB)) {
 | |
|     // There once was a bundle:
 | |
|     //    BUNDLE %D2<imp-def>, %R4<imp-def>, %R5<imp-def>, %D7<imp-def>, ...
 | |
|     //      * %D2<def> = IMPLICIT_DEF; flags:
 | |
|     //      * %D7<def> = IMPLICIT_DEF; flags:
 | |
|     // After the IMPLICIT_DEFs were removed by the asm printer, the bundle
 | |
|     // became empty.
 | |
|     DEBUG(dbgs() << "Skipping empty bundle");
 | |
|     return HexagonShuffler::SHUFFLE_SUCCESS;
 | |
|   } else if (!HexagonMCInstrInfo::isBundle(MCB)) {
 | |
|     DEBUG(dbgs() << "Skipping stand-alone insn");
 | |
|     return HexagonShuffler::SHUFFLE_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   bool doneShuffling = false;
 | |
|   unsigned shuffleError;
 | |
|   while (possibleDuplexes.size() > 0 && (!doneShuffling)) {
 | |
|     // case of Duplex Found
 | |
|     DuplexCandidate duplexToTry = possibleDuplexes.pop_back_val();
 | |
|     MCInst Attempt(MCB);
 | |
|     HexagonMCInstrInfo::replaceDuplex(Context, Attempt, duplexToTry);
 | |
|     HexagonMCShuffler MCS(MCII, STI, Attempt); // copy packet to the shuffler
 | |
|     if (MCS.size() == 1) {                     // case of one duplex
 | |
|       // copy the created duplex in the shuffler to the bundle
 | |
|       MCS.copyTo(MCB);
 | |
|       doneShuffling = true;
 | |
|       return HexagonShuffler::SHUFFLE_SUCCESS;
 | |
|     }
 | |
|     // try shuffle with this duplex
 | |
|     doneShuffling = MCS.reshuffleTo(MCB);
 | |
|     shuffleError = MCS.getError();
 | |
| 
 | |
|     if (doneShuffling)
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   if (doneShuffling == false) {
 | |
|     HexagonMCShuffler MCS(MCII, STI, MCB);
 | |
|     doneShuffling = MCS.reshuffleTo(MCB); // shuffle
 | |
|     shuffleError = MCS.getError();
 | |
|   }
 | |
|   if (!doneShuffling)
 | |
|     return shuffleError;
 | |
| 
 | |
|   return HexagonShuffler::SHUFFLE_SUCCESS;
 | |
| }
 | |
| 
 | |
| bool llvm::HexagonMCShuffle(MCInstrInfo const &MCII, MCSubtargetInfo const &STI,
 | |
|                             MCInst &MCB, MCInst const *AddMI, int fixupCount) {
 | |
|   if (!HexagonMCInstrInfo::isBundle(MCB) || !AddMI)
 | |
|     return false;
 | |
| 
 | |
|   // if fixups present, make sure we don't insert too many nops that would
 | |
|   // later prevent an extender from being inserted.
 | |
|   unsigned int bundleSize = HexagonMCInstrInfo::bundleSize(MCB);
 | |
|   if (bundleSize >= HEXAGON_PACKET_SIZE)
 | |
|     return false;
 | |
|   if (fixupCount >= 2) {
 | |
|     return false;
 | |
|   } else {
 | |
|     if (bundleSize == HEXAGON_PACKET_SIZE - 1 && fixupCount)
 | |
|       return false;
 | |
|   }
 | |
| 
 | |
|   if (DisableShuffle)
 | |
|     return false;
 | |
| 
 | |
|   HexagonMCShuffler MCS(MCII, STI, MCB, AddMI);
 | |
|   if (!MCS.reshuffleTo(MCB)) {
 | |
|     unsigned shuffleError = MCS.getError();
 | |
|     switch (shuffleError) {
 | |
|     default:
 | |
|       return false;
 | |
|     case HexagonShuffler::SHUFFLE_SUCCESS: // single instruction case
 | |
|       return true;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 |