Skip to content

Commit 86c577a

Browse files
committed
[AIEX][Multi Slot] added Pseudo Materialization
1 parent 0f7b86b commit 86c577a

17 files changed

+682
-63
lines changed

llvm/lib/Target/AIE/AIEBaseInstrInfo.cpp

+17
Original file line numberDiff line numberDiff line change
@@ -1021,6 +1021,23 @@ const MCSlotInfo *AIEBaseInstrInfo::getSlotInfo(const MCSlotKind Kind) const {
10211021
return FormatInterface->getSlotInfo(Kind);
10221022
}
10231023

1024+
bool AIEBaseInstrInfo::isMultiSlotPseudo(const MachineInstr &MI) const {
1025+
return MI.isPseudo() &&
1026+
getFormatInterface()->getAlternateInstsOpcode(MI.getOpcode());
1027+
}
1028+
1029+
std::optional<unsigned>
1030+
AIEBaseInstrInfo::getSlotOpcode(const MCSlotKind Slot,
1031+
const MachineInstr &MI) const {
1032+
assert(isMultiSlotPseudo(MI));
1033+
for (const auto &OpCode :
1034+
*getFormatInterface()->getAlternateInstsOpcode(MI.getOpcode())) {
1035+
if (getSlotKind(OpCode) == Slot)
1036+
return OpCode;
1037+
}
1038+
return {};
1039+
}
1040+
10241041
const PacketFormats &AIEBaseInstrInfo::getPacketFormats() const {
10251042
return FormatInterface->getPacketFormats();
10261043
}

llvm/lib/Target/AIE/AIEBaseInstrInfo.h

+7
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,13 @@ struct AIEBaseInstrInfo : public TargetInstrInfo {
7777
/// slot will be the default one (unknown).
7878
MCSlotKind getSlotKind(unsigned Opcode) const;
7979
virtual const MCSlotInfo *getSlotInfo(const MCSlotKind Kind) const;
80+
/// \return Opcode of multi-slot pseudo \p MI that runs in \p Slot
81+
std::optional<unsigned> getSlotOpcode(const MCSlotKind Slot,
82+
const MachineInstr &MI) const;
83+
84+
/// \return wether \p MI is a multi-slot pseudo instruction
85+
bool isMultiSlotPseudo(const MachineInstr &MI) const;
86+
8087
/// Return the Packet formats for this target
8188
virtual const PacketFormats &getPacketFormats() const;
8289
/// Return a nop of the given byte size, or the smallest if zero.

llvm/lib/Target/AIE/AIEInterBlockScheduling.cpp

+12-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "AIELiveRegs.h"
1919
#include "AIEMachineScheduler.h"
2020
#include "AIEMaxLatencyFinder.h"
21+
#include "AIEMultiSlotInstrMaterializer.h"
2122
#include "Utils/AIELoopUtils.h"
2223
#include "llvm/ADT/PostOrderIterator.h"
2324
#include "llvm/CodeGen/MachineBasicBlock.h"
@@ -60,6 +61,11 @@ static cl::opt<int> PostPipelinerMaxII(
6061
"aie-postpipeliner-maxii", cl::init(40),
6162
cl::desc("[AIE] Maximum II to be tried in the post-ra pipeliner"));
6263

64+
static cl::opt<bool> EnableMultiSlotInstrMaterialization(
65+
"aie-preassign-multi-slot-instr", cl::Hidden, cl::init(false),
66+
cl::desc("Statically materialize Multi-Slot Pseudo Instructions in "
67+
"loops."));
68+
6369
namespace llvm::AIE {
6470

6571
void dumpInterBlock(const InterBlockEdges &Edges) {
@@ -586,7 +592,7 @@ SchedulingStage InterBlockScheduling::updateScheduling(BlockState &BS) {
586592
// But first try SWP
587593
if (BS.getRegions().size() == 1) {
588594
auto &PostSWP = BS.getPostSWP();
589-
if (PostSWP.canAccept(*BS.TheBlock)) {
595+
if (PostSWP.isPostPipelineCandidate(*BS.TheBlock)) {
590596
BS.FixPoint.II = PostSWP.getResMII(*BS.TheBlock);
591597
return BS.FixPoint.Stage = SchedulingStage::Pipelining;
592598
}
@@ -1161,6 +1167,11 @@ void BlockState::initInterBlock(const MachineSchedContext &Context,
11611167
// Don't worry, this just constructs a mostly empty container class
11621168
auto NumInstrs = getTop().getFreeInstructions().size();
11631169
PostSWP = std::make_unique<PostPipeliner>(HR, NumInstrs);
1170+
1171+
// perform static assignment of multi-slot pseudos
1172+
if (EnableMultiSlotInstrMaterialization &&
1173+
PostSWP->isPostPipelineCandidate(*TheBlock))
1174+
staticallyMaterializeMultiSlotInstructions(*TheBlock, HR);
11641175
}
11651176

11661177
// We are called just after the first round of scheduling a block.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
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+
//
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
//===--- AIEMultiSlotInstrMaterializer.h -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+
#include "AIEBaseInstrInfo.h"
16+
17+
namespace llvm {
18+
class AIEHazardRecognizer;
19+
}
20+
21+
namespace llvm::AIE {
22+
23+
/// Statically assign and materialize Slots to multi-slot pseudo MachineInstr in
24+
/// \p MBB .
25+
/// FIXME: Currently we are only handling multi-slot memory load pseudos.
26+
void staticallyMaterializeMultiSlotInstructions(MachineBasicBlock &MBB,
27+
const AIEHazardRecognizer &HR);
28+
29+
} // namespace llvm::AIE

llvm/lib/Target/AIE/AIEPostPipeliner.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ class PostPipelineDumper : public PipelineScheduleVisitor {
6565
PostPipeliner::PostPipeliner(const AIEHazardRecognizer &HR, int NInstr)
6666
: HR(HR), NInstr(NInstr) {}
6767

68-
bool PostPipeliner::canAccept(MachineBasicBlock &LoopBlock) {
68+
bool PostPipeliner::isPostPipelineCandidate(MachineBasicBlock &LoopBlock) {
6969
// We leave the single-block loop criterion to our caller. It is fulfilled
7070
// by being a loopaware scheduling candidate.
7171
// First get us some instruments

llvm/lib/Target/AIE/AIEPostPipeliner.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -233,10 +233,10 @@ class PostPipeliner {
233233

234234
/// Check whether this is a suitable loop for the PostPipeliner. It also
235235
/// leaves some useful information.
236-
bool canAccept(MachineBasicBlock &LoopBlock);
236+
bool isPostPipelineCandidate(MachineBasicBlock &LoopBlock);
237237

238238
/// Get a lowerbound for the II required to accommodate the slots.
239-
/// \pre canAccept has returned true
239+
/// \pre isPostPipelineCandidate has returned true
240240
int getResMII(MachineBasicBlock &LoopBlock);
241241

242242
// Schedule using the given InitiationInterval. Return true when successful.

llvm/lib/Target/AIE/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ add_llvm_target(AIECodeGen
112112
AIEMaxLatencyFinder.cpp
113113
AIEMCInstLower.cpp
114114
AIEMIRFormatter.cpp
115+
AIEMultiSlotInstrMaterializer.cpp
115116
AIEPostPipeliner.cpp
116117
AIEPostSelectOptimize.cpp
117118
AIEPseudoBranchExpansion.cpp

llvm/lib/Target/AIE/MCTargetDesc/AIE2MCFormats.cpp

+4
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,8 @@ const MCFormatDesc *AIE2MCFormats::getMCFormats() const {
3737

3838
const PacketFormats &AIE2MCFormats::getPacketFormats() const { return Formats; }
3939

40+
SmallVector<MCSlotKind, 2> AIE2MCFormats::getLoadSlotKinds() const {
41+
return {AIE2SlotKind::AIE2_SLOT_LDB, AIE2SlotKind::AIE2_SLOT_LDA};
42+
}
43+
4044
} // end namespace llvm

0 commit comments

Comments
 (0)