10b57cec5SDimitry Andric //=- llvm/CodeGen/DFAPacketizer.cpp - DFA Packetizer for VLIW -*- C++ -*-=====// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // This class implements a deterministic finite automaton (DFA) based 90b57cec5SDimitry Andric // packetizing mechanism for VLIW architectures. It provides APIs to 100b57cec5SDimitry Andric // determine whether there exists a legal mapping of instructions to 110b57cec5SDimitry Andric // functional unit assignments in a packet. The DFA is auto-generated from 120b57cec5SDimitry Andric // the target's Schedule.td file. 130b57cec5SDimitry Andric // 140b57cec5SDimitry Andric // A DFA consists of 3 major elements: states, inputs, and transitions. For 150b57cec5SDimitry Andric // the packetizing mechanism, the input is the set of instruction classes for 160b57cec5SDimitry Andric // a target. The state models all possible combinations of functional unit 170b57cec5SDimitry Andric // consumption for a given set of instructions in a packet. A transition 180b57cec5SDimitry Andric // models the addition of an instruction to a packet. In the DFA constructed 190b57cec5SDimitry Andric // by this class, if an instruction can be added to a packet, then a valid 200b57cec5SDimitry Andric // transition exists from the corresponding state. Invalid transitions 210b57cec5SDimitry Andric // indicate that the instruction cannot be added to the current packet. 220b57cec5SDimitry Andric // 230b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric #include "llvm/CodeGen/DFAPacketizer.h" 268bcb0991SDimitry Andric #include "llvm/ADT/StringExtras.h" 278bcb0991SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h" 280b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 290b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h" 300b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstrBundle.h" 310b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h" 320b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 330b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h" 340b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 350b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h" 360b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 370b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 380b57cec5SDimitry Andric #include <algorithm> 390b57cec5SDimitry Andric #include <cassert> 400b57cec5SDimitry Andric #include <iterator> 410b57cec5SDimitry Andric #include <memory> 420b57cec5SDimitry Andric #include <vector> 430b57cec5SDimitry Andric 440b57cec5SDimitry Andric using namespace llvm; 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric #define DEBUG_TYPE "packets" 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric static cl::opt<unsigned> InstrLimit("dfa-instr-limit", cl::Hidden, 490b57cec5SDimitry Andric cl::init(0), cl::desc("If present, stops packetizing after N instructions")); 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric static unsigned InstrCount = 0; 520b57cec5SDimitry Andric 530b57cec5SDimitry Andric // Check if the resources occupied by a MCInstrDesc are available in the 540b57cec5SDimitry Andric // current state. 550b57cec5SDimitry Andric bool DFAPacketizer::canReserveResources(const MCInstrDesc *MID) { 56480093f4SDimitry Andric unsigned Action = ItinActions[MID->getSchedClass()]; 57480093f4SDimitry Andric if (MID->getSchedClass() == 0 || Action == 0) 58480093f4SDimitry Andric return false; 59480093f4SDimitry Andric return A.canAdd(Action); 600b57cec5SDimitry Andric } 610b57cec5SDimitry Andric 620b57cec5SDimitry Andric // Reserve the resources occupied by a MCInstrDesc and change the current 630b57cec5SDimitry Andric // state to reflect that change. 640b57cec5SDimitry Andric void DFAPacketizer::reserveResources(const MCInstrDesc *MID) { 65480093f4SDimitry Andric unsigned Action = ItinActions[MID->getSchedClass()]; 66480093f4SDimitry Andric if (MID->getSchedClass() == 0 || Action == 0) 67480093f4SDimitry Andric return; 68480093f4SDimitry Andric A.add(Action); 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric // Check if the resources occupied by a machine instruction are available 720b57cec5SDimitry Andric // in the current state. 730b57cec5SDimitry Andric bool DFAPacketizer::canReserveResources(MachineInstr &MI) { 740b57cec5SDimitry Andric const MCInstrDesc &MID = MI.getDesc(); 750b57cec5SDimitry Andric return canReserveResources(&MID); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric // Reserve the resources occupied by a machine instruction and change the 790b57cec5SDimitry Andric // current state to reflect that change. 800b57cec5SDimitry Andric void DFAPacketizer::reserveResources(MachineInstr &MI) { 810b57cec5SDimitry Andric const MCInstrDesc &MID = MI.getDesc(); 820b57cec5SDimitry Andric reserveResources(&MID); 830b57cec5SDimitry Andric } 840b57cec5SDimitry Andric 858bcb0991SDimitry Andric unsigned DFAPacketizer::getUsedResources(unsigned InstIdx) { 868bcb0991SDimitry Andric ArrayRef<NfaPath> NfaPaths = A.getNfaPaths(); 878bcb0991SDimitry Andric assert(!NfaPaths.empty() && "Invalid bundle!"); 888bcb0991SDimitry Andric const NfaPath &RS = NfaPaths.front(); 898bcb0991SDimitry Andric 908bcb0991SDimitry Andric // RS stores the cumulative resources used up to and including the I'th 918bcb0991SDimitry Andric // instruction. The 0th instruction is the base case. 928bcb0991SDimitry Andric if (InstIdx == 0) 938bcb0991SDimitry Andric return RS[0]; 948bcb0991SDimitry Andric // Return the difference between the cumulative resources used by InstIdx and 958bcb0991SDimitry Andric // its predecessor. 968bcb0991SDimitry Andric return RS[InstIdx] ^ RS[InstIdx - 1]; 978bcb0991SDimitry Andric } 988bcb0991SDimitry Andric 990b57cec5SDimitry Andric DefaultVLIWScheduler::DefaultVLIWScheduler(MachineFunction &MF, 1000b57cec5SDimitry Andric MachineLoopInfo &MLI, 1018bcb0991SDimitry Andric AAResults *AA) 1020b57cec5SDimitry Andric : ScheduleDAGInstrs(MF, &MLI), AA(AA) { 1030b57cec5SDimitry Andric CanHandleTerminators = true; 1040b57cec5SDimitry Andric } 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric /// Apply each ScheduleDAGMutation step in order. 10706c3fb27SDimitry Andric void DefaultVLIWScheduler::postProcessDAG() { 1080b57cec5SDimitry Andric for (auto &M : Mutations) 1090b57cec5SDimitry Andric M->apply(this); 1100b57cec5SDimitry Andric } 1110b57cec5SDimitry Andric 1120b57cec5SDimitry Andric void DefaultVLIWScheduler::schedule() { 1130b57cec5SDimitry Andric // Build the scheduling graph. 1140b57cec5SDimitry Andric buildSchedGraph(AA); 11506c3fb27SDimitry Andric postProcessDAG(); 1160b57cec5SDimitry Andric } 1170b57cec5SDimitry Andric 1180b57cec5SDimitry Andric VLIWPacketizerList::VLIWPacketizerList(MachineFunction &mf, 1198bcb0991SDimitry Andric MachineLoopInfo &mli, AAResults *aa) 1200b57cec5SDimitry Andric : MF(mf), TII(mf.getSubtarget().getInstrInfo()), AA(aa) { 1210b57cec5SDimitry Andric ResourceTracker = TII->CreateTargetScheduleState(MF.getSubtarget()); 1228bcb0991SDimitry Andric ResourceTracker->setTrackResources(true); 1230b57cec5SDimitry Andric VLIWScheduler = new DefaultVLIWScheduler(MF, mli, AA); 1240b57cec5SDimitry Andric } 1250b57cec5SDimitry Andric 1260b57cec5SDimitry Andric VLIWPacketizerList::~VLIWPacketizerList() { 1270b57cec5SDimitry Andric delete VLIWScheduler; 1280b57cec5SDimitry Andric delete ResourceTracker; 1290b57cec5SDimitry Andric } 1300b57cec5SDimitry Andric 1310b57cec5SDimitry Andric // End the current packet, bundle packet instructions and reset DFA state. 1320b57cec5SDimitry Andric void VLIWPacketizerList::endPacket(MachineBasicBlock *MBB, 1330b57cec5SDimitry Andric MachineBasicBlock::iterator MI) { 1340b57cec5SDimitry Andric LLVM_DEBUG({ 1350b57cec5SDimitry Andric if (!CurrentPacketMIs.empty()) { 1360b57cec5SDimitry Andric dbgs() << "Finalizing packet:\n"; 1378bcb0991SDimitry Andric unsigned Idx = 0; 1388bcb0991SDimitry Andric for (MachineInstr *MI : CurrentPacketMIs) { 1398bcb0991SDimitry Andric unsigned R = ResourceTracker->getUsedResources(Idx++); 1408bcb0991SDimitry Andric dbgs() << " * [res:0x" << utohexstr(R) << "] " << *MI; 1418bcb0991SDimitry Andric } 1420b57cec5SDimitry Andric } 1430b57cec5SDimitry Andric }); 1440b57cec5SDimitry Andric if (CurrentPacketMIs.size() > 1) { 1450b57cec5SDimitry Andric MachineInstr &MIFirst = *CurrentPacketMIs.front(); 1460b57cec5SDimitry Andric finalizeBundle(*MBB, MIFirst.getIterator(), MI.getInstrIterator()); 1470b57cec5SDimitry Andric } 1480b57cec5SDimitry Andric CurrentPacketMIs.clear(); 1490b57cec5SDimitry Andric ResourceTracker->clearResources(); 1500b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "End packet\n"); 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric // Bundle machine instructions into packets. 1540b57cec5SDimitry Andric void VLIWPacketizerList::PacketizeMIs(MachineBasicBlock *MBB, 1550b57cec5SDimitry Andric MachineBasicBlock::iterator BeginItr, 1560b57cec5SDimitry Andric MachineBasicBlock::iterator EndItr) { 1570b57cec5SDimitry Andric assert(VLIWScheduler && "VLIW Scheduler is not initialized!"); 1580b57cec5SDimitry Andric VLIWScheduler->startBlock(MBB); 1590b57cec5SDimitry Andric VLIWScheduler->enterRegion(MBB, BeginItr, EndItr, 1600b57cec5SDimitry Andric std::distance(BeginItr, EndItr)); 1610b57cec5SDimitry Andric VLIWScheduler->schedule(); 1620b57cec5SDimitry Andric 1630b57cec5SDimitry Andric LLVM_DEBUG({ 1640b57cec5SDimitry Andric dbgs() << "Scheduling DAG of the packetize region\n"; 1650b57cec5SDimitry Andric VLIWScheduler->dump(); 1660b57cec5SDimitry Andric }); 1670b57cec5SDimitry Andric 1680b57cec5SDimitry Andric // Generate MI -> SU map. 1690b57cec5SDimitry Andric MIToSUnit.clear(); 1700b57cec5SDimitry Andric for (SUnit &SU : VLIWScheduler->SUnits) 1710b57cec5SDimitry Andric MIToSUnit[SU.getInstr()] = &SU; 1720b57cec5SDimitry Andric 1730b57cec5SDimitry Andric bool LimitPresent = InstrLimit.getPosition(); 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric // The main packetizer loop. 1760b57cec5SDimitry Andric for (; BeginItr != EndItr; ++BeginItr) { 1770b57cec5SDimitry Andric if (LimitPresent) { 1780b57cec5SDimitry Andric if (InstrCount >= InstrLimit) { 1790b57cec5SDimitry Andric EndItr = BeginItr; 1800b57cec5SDimitry Andric break; 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric InstrCount++; 1830b57cec5SDimitry Andric } 1840b57cec5SDimitry Andric MachineInstr &MI = *BeginItr; 1850b57cec5SDimitry Andric initPacketizerState(); 1860b57cec5SDimitry Andric 1870b57cec5SDimitry Andric // End the current packet if needed. 1880b57cec5SDimitry Andric if (isSoloInstruction(MI)) { 1890b57cec5SDimitry Andric endPacket(MBB, MI); 1900b57cec5SDimitry Andric continue; 1910b57cec5SDimitry Andric } 1920b57cec5SDimitry Andric 1930b57cec5SDimitry Andric // Ignore pseudo instructions. 1940b57cec5SDimitry Andric if (ignorePseudoInstruction(MI, MBB)) 1950b57cec5SDimitry Andric continue; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric SUnit *SUI = MIToSUnit[&MI]; 1980b57cec5SDimitry Andric assert(SUI && "Missing SUnit Info!"); 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric // Ask DFA if machine resource is available for MI. 2010b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Checking resources for adding MI to packet " << MI); 2020b57cec5SDimitry Andric 2030b57cec5SDimitry Andric bool ResourceAvail = ResourceTracker->canReserveResources(MI); 2040b57cec5SDimitry Andric LLVM_DEBUG({ 2050b57cec5SDimitry Andric if (ResourceAvail) 2060b57cec5SDimitry Andric dbgs() << " Resources are available for adding MI to packet\n"; 2070b57cec5SDimitry Andric else 2080b57cec5SDimitry Andric dbgs() << " Resources NOT available\n"; 2090b57cec5SDimitry Andric }); 2100b57cec5SDimitry Andric if (ResourceAvail && shouldAddToPacket(MI)) { 2110b57cec5SDimitry Andric // Dependency check for MI with instructions in CurrentPacketMIs. 212fcaf7f86SDimitry Andric for (auto *MJ : CurrentPacketMIs) { 2130b57cec5SDimitry Andric SUnit *SUJ = MIToSUnit[MJ]; 2140b57cec5SDimitry Andric assert(SUJ && "Missing SUnit Info!"); 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Checking against MJ " << *MJ); 2170b57cec5SDimitry Andric // Is it legal to packetize SUI and SUJ together. 2180b57cec5SDimitry Andric if (!isLegalToPacketizeTogether(SUI, SUJ)) { 2190b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Not legal to add MI, try to prune\n"); 2200b57cec5SDimitry Andric // Allow packetization if dependency can be pruned. 2210b57cec5SDimitry Andric if (!isLegalToPruneDependencies(SUI, SUJ)) { 2220b57cec5SDimitry Andric // End the packet if dependency cannot be pruned. 2230b57cec5SDimitry Andric LLVM_DEBUG(dbgs() 2240b57cec5SDimitry Andric << " Could not prune dependencies for adding MI\n"); 2250b57cec5SDimitry Andric endPacket(MBB, MI); 2260b57cec5SDimitry Andric break; 2270b57cec5SDimitry Andric } 2280b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << " Pruned dependence for adding MI\n"); 2290b57cec5SDimitry Andric } 2300b57cec5SDimitry Andric } 2310b57cec5SDimitry Andric } else { 2320b57cec5SDimitry Andric LLVM_DEBUG(if (ResourceAvail) dbgs() 2330b57cec5SDimitry Andric << "Resources are available, but instruction should not be " 2340b57cec5SDimitry Andric "added to packet\n " 2350b57cec5SDimitry Andric << MI); 2360b57cec5SDimitry Andric // End the packet if resource is not available, or if the instruction 23706c3fb27SDimitry Andric // should not be added to the current packet. 2380b57cec5SDimitry Andric endPacket(MBB, MI); 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric // Add MI to the current packet. 2420b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "* Adding MI to packet " << MI << '\n'); 2430b57cec5SDimitry Andric BeginItr = addToPacket(MI); 2440b57cec5SDimitry Andric } // For all instructions in the packetization range. 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric // End any packet left behind. 2470b57cec5SDimitry Andric endPacket(MBB, EndItr); 2480b57cec5SDimitry Andric VLIWScheduler->exitRegion(); 2490b57cec5SDimitry Andric VLIWScheduler->finishBlock(); 2500b57cec5SDimitry Andric } 2510b57cec5SDimitry Andric 2520b57cec5SDimitry Andric bool VLIWPacketizerList::alias(const MachineMemOperand &Op1, 2530b57cec5SDimitry Andric const MachineMemOperand &Op2, 2540b57cec5SDimitry Andric bool UseTBAA) const { 255*0fca6ea1SDimitry Andric if (!Op1.getValue() || !Op2.getValue() || !Op1.getSize().hasValue() || 256*0fca6ea1SDimitry Andric !Op2.getSize().hasValue()) 2570b57cec5SDimitry Andric return true; 2580b57cec5SDimitry Andric 2590b57cec5SDimitry Andric int64_t MinOffset = std::min(Op1.getOffset(), Op2.getOffset()); 260*0fca6ea1SDimitry Andric int64_t Overlapa = Op1.getSize().getValue() + Op1.getOffset() - MinOffset; 261*0fca6ea1SDimitry Andric int64_t Overlapb = Op2.getSize().getValue() + Op2.getOffset() - MinOffset; 2620b57cec5SDimitry Andric 2630b57cec5SDimitry Andric AliasResult AAResult = 2640b57cec5SDimitry Andric AA->alias(MemoryLocation(Op1.getValue(), Overlapa, 2650b57cec5SDimitry Andric UseTBAA ? Op1.getAAInfo() : AAMDNodes()), 2660b57cec5SDimitry Andric MemoryLocation(Op2.getValue(), Overlapb, 2670b57cec5SDimitry Andric UseTBAA ? Op2.getAAInfo() : AAMDNodes())); 2680b57cec5SDimitry Andric 269fe6060f1SDimitry Andric return AAResult != AliasResult::NoAlias; 2700b57cec5SDimitry Andric } 2710b57cec5SDimitry Andric 2720b57cec5SDimitry Andric bool VLIWPacketizerList::alias(const MachineInstr &MI1, 2730b57cec5SDimitry Andric const MachineInstr &MI2, 2740b57cec5SDimitry Andric bool UseTBAA) const { 2750b57cec5SDimitry Andric if (MI1.memoperands_empty() || MI2.memoperands_empty()) 2760b57cec5SDimitry Andric return true; 2770b57cec5SDimitry Andric 2780b57cec5SDimitry Andric for (const MachineMemOperand *Op1 : MI1.memoperands()) 2790b57cec5SDimitry Andric for (const MachineMemOperand *Op2 : MI2.memoperands()) 2800b57cec5SDimitry Andric if (alias(*Op1, *Op2, UseTBAA)) 2810b57cec5SDimitry Andric return true; 2820b57cec5SDimitry Andric return false; 2830b57cec5SDimitry Andric } 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric // Add a DAG mutation object to the ordered list. 2860b57cec5SDimitry Andric void VLIWPacketizerList::addMutation( 2870b57cec5SDimitry Andric std::unique_ptr<ScheduleDAGMutation> Mutation) { 2880b57cec5SDimitry Andric VLIWScheduler->addMutation(std::move(Mutation)); 2890b57cec5SDimitry Andric } 290