|
| 1 | +//===--- AIEMultiSlotInstrMaterializer.cpp - -Multi Slot Instr materializer===// |
| 2 | +// |
| 3 | +// This file is licensed under the Apache License v2.0 with LLVM Exceptions. |
| 4 | +// See https://llvm.org/LICENSE.txt for license information. |
| 5 | +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | +// |
| 7 | +// (c) Copyright 2025 Advanced Micro Devices, Inc. or its affiliates |
| 8 | +// |
| 9 | +//===----------------------------------------------------------------------===// |
| 10 | +// |
| 11 | +// \file assigns an issue slot to multi-slot pseudo instructions within a single |
| 12 | +// block loop to help loop pipelining. |
| 13 | +// |
| 14 | +//===----------------------------------------------------------------------===// |
| 15 | + |
| 16 | +#include "AIEMultiSlotInstrMaterializer.h" |
| 17 | +#include "AIEHazardRecognizer.h" |
| 18 | + |
| 19 | +using namespace llvm; |
| 20 | + |
| 21 | +#define DEBUG_TYPE "aie-multi-slot-pseudo" |
| 22 | + |
| 23 | +namespace llvm::AIE { |
| 24 | + |
| 25 | +class SlotMapping { |
| 26 | +public: |
| 27 | + SlotMapping(const AIEBaseInstrInfo *TII) : TII(TII) {} |
| 28 | + |
| 29 | + /// update \p MemBankBits assigned to \p Slot . Create the Slot mapping, if |
| 30 | + /// necessary. |
| 31 | + void update(const MCSlotKind &Slot, const MemoryBankBits MemBankBits) { |
| 32 | + SlotToBanks[Slot] |= MemBankBits; |
| 33 | + } |
| 34 | + |
| 35 | + /// \return first Slot where MemoryBankBits overlap with \p MemBankBits . |
| 36 | + std::optional<MCSlotKind> |
| 37 | + getAssignedSlot(const MemoryBankBits MemBankBits) const { |
| 38 | + auto IT = |
| 39 | + find_if(SlotToBanks, |
| 40 | + [MemBankBits]( |
| 41 | + const std::pair<MCSlotKind, MemoryBankBits> &SlotBankPair) { |
| 42 | + auto [Slot, Banks] = SlotBankPair; |
| 43 | + return (Banks & MemBankBits) != 0; |
| 44 | + }); |
| 45 | + |
| 46 | + if (IT == SlotToBanks.end()) |
| 47 | + return {}; |
| 48 | + |
| 49 | + const auto Slot = IT->first; |
| 50 | + return Slot; |
| 51 | + } |
| 52 | + |
| 53 | + /// \return whether no MemoryBank has multiple Slots assigned to it in the |
| 54 | + /// current mapping. |
| 55 | + bool hasUniqueSlotForBank() const { |
| 56 | + MemoryBankBits AccumulatedBanks = {}; |
| 57 | + for (auto &[Slot, Banks] : SlotToBanks) { |
| 58 | + if (Banks & AccumulatedBanks) { |
| 59 | + LLVM_DEBUG(dbgs() << "Conflict detected at Slot " << Slot << "\n"); |
| 60 | + return false; |
| 61 | + } |
| 62 | + AccumulatedBanks |= Banks; |
| 63 | + } |
| 64 | + return true; |
| 65 | + } |
| 66 | + |
| 67 | + /// \return whether a Slot can be assigned to \b MI and assign it in the |
| 68 | + /// mapping. |
| 69 | + bool assignSlot(const MachineInstr &MI, const AIEHazardRecognizer &HR) { |
| 70 | + auto MemBankBits = HR.getMemoryBanks(&MI); |
| 71 | + LLVM_DEBUG(dbgs() << "Memory Bank: " << MemBankBits << " " << MI); |
| 72 | + if (!MemBankBits) { |
| 73 | + LLVM_DEBUG(dbgs() << "Warning: No MemoryBanks assigned to " << MI); |
| 74 | + return false; |
| 75 | + } |
| 76 | + |
| 77 | + std::optional<MCSlotKind> SelectedSlot = getAssignedSlot(MemBankBits); |
| 78 | + if (!SelectedSlot) |
| 79 | + SelectedSlot = getUnusedLoadSlot(); |
| 80 | + if (!SelectedSlot) { |
| 81 | + LLVM_DEBUG(dbgs() << "Reassigning existing Slot to MemoryBankBits " |
| 82 | + << MemBankBits << "\n"); |
| 83 | + SelectedSlot = getLeastRecentlyUsedSlot(); |
| 84 | + } |
| 85 | + |
| 86 | + update(*SelectedSlot, MemBankBits); |
| 87 | + |
| 88 | + return true; |
| 89 | + } |
| 90 | + |
| 91 | +private: |
| 92 | + /// Mapping between a Slot and the MemoryBanks that occupy the Slot. |
| 93 | + std::map<MCSlotKind, MemoryBankBits> SlotToBanks; |
| 94 | + /// If Slots have to be reassigned (because every Slot has already been |
| 95 | + /// assigned to a Memory Bank), use an Index to cycle through already |
| 96 | + /// used Slots. |
| 97 | + unsigned ReassignIndex = 0; |
| 98 | + const AIEBaseInstrInfo *TII; |
| 99 | + |
| 100 | + /// \return an unused Slot from the mapping. |
| 101 | + std::optional<MCSlotKind> getUnusedLoadSlot() const { |
| 102 | + const SmallVector<MCSlotKind, 2> LoadSlots = |
| 103 | + TII->getFormatInterface()->getLoadSlotKinds(); |
| 104 | + |
| 105 | + for (const auto &Slot : LoadSlots) { |
| 106 | + |
| 107 | + // check if Slot is already used in SlotMemBankBitsMap |
| 108 | + auto FoundSlot = SlotToBanks.find(Slot); |
| 109 | + if (FoundSlot != SlotToBanks.end()) |
| 110 | + continue; |
| 111 | + |
| 112 | + LLVM_DEBUG(dbgs() << " Found Unused Slot " << Slot << "\n"); |
| 113 | + return Slot; |
| 114 | + } |
| 115 | + |
| 116 | + // no slots were assigned yet, assign first Slot. |
| 117 | + // FIXME: use a heuristic that takes Slots utilization and |
| 118 | + // utilization of MemoryBanks into consideration. |
| 119 | + return LoadSlots[0]; |
| 120 | + } |
| 121 | + |
| 122 | + /// Cycle through load Slots and \return an already used Slot |
| 123 | + /// FIXME: use a heuristic that takes utilization into account, instead of |
| 124 | + /// blindly cycling through the Slots. |
| 125 | + std::optional<MCSlotKind> getLeastRecentlyUsedSlot() { |
| 126 | + const auto AvailableSlots = TII->getFormatInterface()->getLoadSlotKinds(); |
| 127 | + |
| 128 | + if (ReassignIndex >= AvailableSlots.size()) |
| 129 | + ReassignIndex = 0; |
| 130 | + |
| 131 | + return AvailableSlots[ReassignIndex++]; |
| 132 | + } |
| 133 | +}; |
| 134 | + |
| 135 | +/// \return a map between Slots and the MemoryBanks that occurs within \p MBB . |
| 136 | +SlotMapping getAssignedSlots(const MachineBasicBlock &MBB, |
| 137 | + const AIEBaseInstrInfo *TII, |
| 138 | + const AIEHazardRecognizer &HR) { |
| 139 | + SlotMapping SlotToBanks(TII); |
| 140 | + |
| 141 | + LLVM_DEBUG(dbgs() << "Collecting any already materialized Slot to MemoryBank " |
| 142 | + "assignments\n"); |
| 143 | + for (const auto &MI : MBB) { |
| 144 | + if (!MI.mayLoad() || TII->isMultiSlotPseudo(MI)) |
| 145 | + continue; |
| 146 | + |
| 147 | + const auto Slot = TII->getSlotKind(MI.getOpcode()); |
| 148 | + const MemoryBankBits MemBankBits = HR.getMemoryBanks(&MI); |
| 149 | + LLVM_DEBUG(dbgs() << "Slot: " << Slot << " MemoryBank: " << MemBankBits |
| 150 | + << " on " << MI); |
| 151 | + |
| 152 | + SlotToBanks.update(Slot, MemBankBits); |
| 153 | + } |
| 154 | + return SlotToBanks; |
| 155 | +} |
| 156 | + |
| 157 | +/// \return whether a valid assignment of Slots to MemoryBankBits is found. |
| 158 | +/// Multi-Slot pseudo load instructions in \p MBB get a Slot assigned, according |
| 159 | +/// to the MemoyBankBits that is attached to the MachineInstr. Existing mappings |
| 160 | +/// in \p SlotToBanks are used and updated. |
| 161 | +bool assignSlots(SlotMapping &SlotToBanks, const MachineBasicBlock &MBB, |
| 162 | + const AIEBaseInstrInfo *TII, const AIEHazardRecognizer &HR) { |
| 163 | + for (const auto &MI : MBB) { |
| 164 | + if (!MI.mayLoad() || !TII->isMultiSlotPseudo(MI)) |
| 165 | + continue; |
| 166 | + |
| 167 | + if (!SlotToBanks.assignSlot(MI, HR)) { |
| 168 | + return false; |
| 169 | + } |
| 170 | + } |
| 171 | + |
| 172 | + return SlotToBanks.hasUniqueSlotForBank(); |
| 173 | +} |
| 174 | + |
| 175 | +/// Materialise \p MI into its slot assigned by \p SlotToBanks . |
| 176 | +void materializeInstr(MachineInstr &MI, const SlotMapping &SlotToBanks, |
| 177 | + const AIEBaseInstrInfo *TII, |
| 178 | + const AIEHazardRecognizer &HR) { |
| 179 | + auto MemBankBits = HR.getMemoryBanks(&MI); |
| 180 | + assert(MemBankBits && "No MemoryBanks attached to MachineInstr."); |
| 181 | + |
| 182 | + const auto Slot = SlotToBanks.getAssignedSlot(MemBankBits); |
| 183 | + assert(Slot && "Could not find Slot for MemoryBank!"); |
| 184 | + |
| 185 | + auto OpCode = TII->getSlotOpcode(*Slot, MI); |
| 186 | + assert(OpCode && "Failed to retrieve a valid Opcode"); |
| 187 | + |
| 188 | + MI.setDesc(TII->get(*OpCode)); |
| 189 | + LLVM_DEBUG(dbgs() << "Assigned " << *Slot << " to " << MI); |
| 190 | +} |
| 191 | + |
| 192 | +/// Materialize multi-slot pseudo instructions in \p MBB according to |
| 193 | +/// overlapping MemoryBankBits between a MachineInstr and the Slot mapping in |
| 194 | +/// \p SlotToBanks . |
| 195 | +void materializeSlots(const SlotMapping &SlotToBanks, MachineBasicBlock &MBB, |
| 196 | + const AIEBaseInstrInfo *TII, |
| 197 | + const AIEHazardRecognizer &HR) { |
| 198 | + LLVM_DEBUG(dbgs() << "\nAssigning Slots to MachineInstr\n"); |
| 199 | + |
| 200 | + for (auto &MI : MBB) { |
| 201 | + if (!MI.mayLoad() || !TII->isMultiSlotPseudo(MI)) |
| 202 | + continue; |
| 203 | + |
| 204 | + materializeInstr(MI, SlotToBanks, TII, HR); |
| 205 | + } |
| 206 | +} |
| 207 | + |
| 208 | +void staticallyMaterializeMultiSlotInstructions(MachineBasicBlock &MBB, |
| 209 | + const AIEHazardRecognizer &HR) { |
| 210 | + LLVM_DEBUG(dbgs() << "Statically Assigning multi slot pseudos for " |
| 211 | + << MBB.getName() << "\n"); |
| 212 | + |
| 213 | + const AIEBaseInstrInfo *TII = static_cast<const AIEBaseInstrInfo *>( |
| 214 | + MBB.getParent()->getSubtarget().getInstrInfo()); |
| 215 | + |
| 216 | + auto SlotToBanks = getAssignedSlots(MBB, TII, HR); |
| 217 | + |
| 218 | + if (!assignSlots(SlotToBanks, MBB, TII, HR)) { |
| 219 | + LLVM_DEBUG( |
| 220 | + dbgs() |
| 221 | + << "Could not find Slot Assignments, Skipping materialization\n"); |
| 222 | + return; |
| 223 | + } |
| 224 | + |
| 225 | + materializeSlots(SlotToBanks, MBB, TII, HR); |
| 226 | +} |
| 227 | +} // namespace llvm::AIE |
| 228 | +// |
0 commit comments