xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/X86/X86FastPreTileConfig.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
181ad6265SDimitry Andric //===-- X86FastPreTileConfig.cpp - Fast Tile Register Configure------------===//
281ad6265SDimitry Andric //
381ad6265SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
481ad6265SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
581ad6265SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
681ad6265SDimitry Andric //
781ad6265SDimitry Andric //===----------------------------------------------------------------------===//
881ad6265SDimitry Andric //
981ad6265SDimitry Andric /// \file Pass to preconfig the shape of physical tile registers
1081ad6265SDimitry Andric /// It inserts ldtilecfg ahead of each group of tile registers. The algorithm
1181ad6265SDimitry Andric /// walk each instruction of basic block in reverse order. All the tile
1281ad6265SDimitry Andric /// registers that live out the basic block would be spilled and reloaded
1381ad6265SDimitry Andric /// before its user. It also check the depenedency of the shape to ensure
1481ad6265SDimitry Andric /// the shape is defined before ldtilecfg.
1581ad6265SDimitry Andric //
1681ad6265SDimitry Andric //===----------------------------------------------------------------------===//
1781ad6265SDimitry Andric 
1881ad6265SDimitry Andric #include "X86.h"
1981ad6265SDimitry Andric #include "X86InstrBuilder.h"
2081ad6265SDimitry Andric #include "X86MachineFunctionInfo.h"
2181ad6265SDimitry Andric #include "X86RegisterInfo.h"
2281ad6265SDimitry Andric #include "X86Subtarget.h"
2381ad6265SDimitry Andric #include "llvm/ADT/PostOrderIterator.h"
2481ad6265SDimitry Andric #include "llvm/ADT/Statistic.h"
2581ad6265SDimitry Andric #include "llvm/CodeGen/MachineFrameInfo.h"
2681ad6265SDimitry Andric #include "llvm/CodeGen/MachineFunctionPass.h"
2781ad6265SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
2881ad6265SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h"
2981ad6265SDimitry Andric #include "llvm/CodeGen/Passes.h"
3081ad6265SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
3181ad6265SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
3281ad6265SDimitry Andric #include "llvm/InitializePasses.h"
3381ad6265SDimitry Andric #include "llvm/Support/Debug.h"
3481ad6265SDimitry Andric 
3581ad6265SDimitry Andric using namespace llvm;
3681ad6265SDimitry Andric 
3781ad6265SDimitry Andric #define DEBUG_TYPE "fastpretileconfig"
3881ad6265SDimitry Andric 
3981ad6265SDimitry Andric STATISTIC(NumStores, "Number of stores added");
4081ad6265SDimitry Andric STATISTIC(NumLoads, "Number of loads added");
4181ad6265SDimitry Andric 
4281ad6265SDimitry Andric namespace {
4381ad6265SDimitry Andric 
4481ad6265SDimitry Andric class X86FastPreTileConfig : public MachineFunctionPass {
4581ad6265SDimitry Andric   MachineFunction *MF = nullptr;
4681ad6265SDimitry Andric   const X86Subtarget *ST = nullptr;
4781ad6265SDimitry Andric   const TargetInstrInfo *TII = nullptr;
4881ad6265SDimitry Andric   MachineRegisterInfo *MRI = nullptr;
4981ad6265SDimitry Andric   X86MachineFunctionInfo *X86FI = nullptr;
5081ad6265SDimitry Andric   MachineFrameInfo *MFI = nullptr;
5181ad6265SDimitry Andric   const TargetRegisterInfo *TRI = nullptr;
5281ad6265SDimitry Andric   MachineBasicBlock *MBB = nullptr;
5381ad6265SDimitry Andric   int CfgSS = -1;
5481ad6265SDimitry Andric   struct PHIInfo {
5581ad6265SDimitry Andric     Register Row;
5681ad6265SDimitry Andric     Register Col;
5781ad6265SDimitry Andric     Register StackAddr;
5881ad6265SDimitry Andric   };
5981ad6265SDimitry Andric   DenseMap<MachineInstr *, struct PHIInfo> VisitedPHIs;
6081ad6265SDimitry Andric 
6181ad6265SDimitry Andric   /// Maps virtual regs to the frame index where these values are spilled.
6281ad6265SDimitry Andric   IndexedMap<int, VirtReg2IndexFunctor> StackSlotForVirtReg;
6381ad6265SDimitry Andric 
6481ad6265SDimitry Andric   /// Has a bit set for tile virtual register for which it was determined
6581ad6265SDimitry Andric   /// that it is alive across blocks.
6681ad6265SDimitry Andric   BitVector MayLiveAcrossBlocks;
6781ad6265SDimitry Andric 
6881ad6265SDimitry Andric   int getStackSpaceFor(Register VirtReg);
6981ad6265SDimitry Andric   void InitializeTileConfigStackSpace();
7081ad6265SDimitry Andric   bool mayLiveOut(Register VirtReg, MachineInstr *CfgMI);
7181ad6265SDimitry Andric   void spill(MachineBasicBlock::iterator Before, Register VirtReg, bool Kill);
7281ad6265SDimitry Andric   void reload(MachineBasicBlock::iterator UseMI, Register VirtReg,
7381ad6265SDimitry Andric               MachineOperand *RowMO, MachineOperand *ColMO);
7481ad6265SDimitry Andric   void canonicalizePHIs(MachineBasicBlock &MBB);
7581ad6265SDimitry Andric   void convertPHI(MachineBasicBlock *MBB, MachineInstr &PHI);
7681ad6265SDimitry Andric   void convertPHIs(MachineBasicBlock &MBB);
7781ad6265SDimitry Andric   bool configBasicBlock(MachineBasicBlock &MBB);
7881ad6265SDimitry Andric 
7981ad6265SDimitry Andric public:
8081ad6265SDimitry Andric   X86FastPreTileConfig() : MachineFunctionPass(ID), StackSlotForVirtReg(-1) {}
8181ad6265SDimitry Andric 
8281ad6265SDimitry Andric   /// Return the pass name.
8381ad6265SDimitry Andric   StringRef getPassName() const override {
8481ad6265SDimitry Andric     return "Fast Tile Register Preconfigure";
8581ad6265SDimitry Andric   }
8681ad6265SDimitry Andric 
8781ad6265SDimitry Andric   /// Perform tile register configure.
8881ad6265SDimitry Andric   bool runOnMachineFunction(MachineFunction &MFunc) override;
8981ad6265SDimitry Andric 
9081ad6265SDimitry Andric   static char ID;
9181ad6265SDimitry Andric };
9281ad6265SDimitry Andric 
9381ad6265SDimitry Andric } // end anonymous namespace
9481ad6265SDimitry Andric 
9581ad6265SDimitry Andric char X86FastPreTileConfig::ID = 0;
9681ad6265SDimitry Andric 
9781ad6265SDimitry Andric INITIALIZE_PASS_BEGIN(X86FastPreTileConfig, DEBUG_TYPE,
9881ad6265SDimitry Andric                       "Fast Tile Register Preconfigure", false, false)
9981ad6265SDimitry Andric INITIALIZE_PASS_END(X86FastPreTileConfig, DEBUG_TYPE,
10081ad6265SDimitry Andric                     "Fast Tile Register Preconfigure", false, false)
10181ad6265SDimitry Andric 
10281ad6265SDimitry Andric static bool dominates(MachineBasicBlock &MBB,
10381ad6265SDimitry Andric                       MachineBasicBlock::const_iterator A,
10481ad6265SDimitry Andric                       MachineBasicBlock::const_iterator B) {
10581ad6265SDimitry Andric   auto MBBEnd = MBB.end();
10681ad6265SDimitry Andric   if (B == MBBEnd)
10781ad6265SDimitry Andric     return true;
10881ad6265SDimitry Andric 
10981ad6265SDimitry Andric   MachineBasicBlock::const_iterator I = MBB.begin();
11081ad6265SDimitry Andric   for (; &*I != A && &*I != B; ++I)
11181ad6265SDimitry Andric     ;
11281ad6265SDimitry Andric 
11381ad6265SDimitry Andric   return &*I == A;
11481ad6265SDimitry Andric }
11581ad6265SDimitry Andric 
11681ad6265SDimitry Andric /// This allocates space for the specified virtual register to be held on the
11781ad6265SDimitry Andric /// stack.
11881ad6265SDimitry Andric int X86FastPreTileConfig::getStackSpaceFor(Register VirtReg) {
11981ad6265SDimitry Andric   // Find the location Reg would belong...
12081ad6265SDimitry Andric   int SS = StackSlotForVirtReg[VirtReg];
12181ad6265SDimitry Andric   // Already has space allocated?
12281ad6265SDimitry Andric   if (SS != -1)
12381ad6265SDimitry Andric     return SS;
12481ad6265SDimitry Andric 
12581ad6265SDimitry Andric   // Allocate a new stack object for this spill location...
12681ad6265SDimitry Andric   const TargetRegisterClass &RC = *MRI->getRegClass(VirtReg);
12781ad6265SDimitry Andric   unsigned Size = TRI->getSpillSize(RC);
12881ad6265SDimitry Andric   Align Alignment = TRI->getSpillAlign(RC);
12981ad6265SDimitry Andric   int FrameIdx = MFI->CreateSpillStackObject(Size, Alignment);
13081ad6265SDimitry Andric 
13181ad6265SDimitry Andric   // Assign the slot.
13281ad6265SDimitry Andric   StackSlotForVirtReg[VirtReg] = FrameIdx;
13381ad6265SDimitry Andric   return FrameIdx;
13481ad6265SDimitry Andric }
13581ad6265SDimitry Andric 
13681ad6265SDimitry Andric /// Returns false if \p VirtReg is known to not live out of the current config.
13781ad6265SDimitry Andric /// If \p VirtReg live out of the current MBB, it must live out of the current
13881ad6265SDimitry Andric /// config
13981ad6265SDimitry Andric bool X86FastPreTileConfig::mayLiveOut(Register VirtReg, MachineInstr *CfgMI) {
14081ad6265SDimitry Andric   if (MayLiveAcrossBlocks.test(Register::virtReg2Index(VirtReg)))
14181ad6265SDimitry Andric     return true;
14281ad6265SDimitry Andric 
14381ad6265SDimitry Andric   for (const MachineInstr &UseInst : MRI->use_nodbg_instructions(VirtReg)) {
14481ad6265SDimitry Andric     if (UseInst.getParent() != MBB) {
14581ad6265SDimitry Andric       MayLiveAcrossBlocks.set(Register::virtReg2Index(VirtReg));
14681ad6265SDimitry Andric       return true;
14781ad6265SDimitry Andric     }
14881ad6265SDimitry Andric 
14981ad6265SDimitry Andric     // The use and def are in the same MBB. If the tile register is
15081ad6265SDimitry Andric     // reconfigured, it is crobbered and we need to spill and reload
15181ad6265SDimitry Andric     // tile register.
15281ad6265SDimitry Andric     if (CfgMI) {
15381ad6265SDimitry Andric       if (dominates(*MBB, *CfgMI, UseInst)) {
15481ad6265SDimitry Andric         MayLiveAcrossBlocks.set(Register::virtReg2Index(VirtReg));
15581ad6265SDimitry Andric         return true;
15681ad6265SDimitry Andric       }
15781ad6265SDimitry Andric     }
15881ad6265SDimitry Andric   }
15981ad6265SDimitry Andric 
16081ad6265SDimitry Andric   return false;
16181ad6265SDimitry Andric }
16281ad6265SDimitry Andric 
16381ad6265SDimitry Andric void X86FastPreTileConfig::InitializeTileConfigStackSpace() {
16481ad6265SDimitry Andric   MachineBasicBlock &MBB = MF->front();
16581ad6265SDimitry Andric   MachineInstr *MI = &*MBB.getFirstNonPHI();
16681ad6265SDimitry Andric   DebugLoc DL;
16781ad6265SDimitry Andric   if (ST->hasAVX512()) {
16881ad6265SDimitry Andric     Register Zmm = MRI->createVirtualRegister(&X86::VR512RegClass);
16981ad6265SDimitry Andric     BuildMI(MBB, MI, DL, TII->get(X86::AVX512_512_SET0), Zmm);
17081ad6265SDimitry Andric     addFrameReference(BuildMI(MBB, MI, DL, TII->get(X86::VMOVUPSZmr)), CfgSS)
17181ad6265SDimitry Andric         .addReg(Zmm);
17281ad6265SDimitry Andric   } else if (ST->hasAVX2()) {
17381ad6265SDimitry Andric     Register Ymm = MRI->createVirtualRegister(&X86::VR256RegClass);
17481ad6265SDimitry Andric     BuildMI(MBB, MI, DL, TII->get(X86::AVX_SET0), Ymm);
17581ad6265SDimitry Andric     addFrameReference(BuildMI(MBB, MI, DL, TII->get(X86::VMOVUPSYmr)), CfgSS)
17681ad6265SDimitry Andric         .addReg(Ymm);
17781ad6265SDimitry Andric     addFrameReference(BuildMI(MBB, MI, DL, TII->get(X86::VMOVUPSYmr)), CfgSS,
17881ad6265SDimitry Andric                       32)
17981ad6265SDimitry Andric         .addReg(Ymm);
18081ad6265SDimitry Andric   } else {
18181ad6265SDimitry Andric     assert(ST->hasSSE2() && "AMX should assume SSE2 enabled");
18281ad6265SDimitry Andric     unsigned StoreOpc = ST->hasAVX() ? X86::VMOVUPSmr : X86::MOVUPSmr;
18381ad6265SDimitry Andric     Register Xmm = MRI->createVirtualRegister(&X86::VR128RegClass);
18481ad6265SDimitry Andric     BuildMI(MBB, MI, DL, TII->get(X86::V_SET0), Xmm);
18581ad6265SDimitry Andric     addFrameReference(BuildMI(MBB, MI, DL, TII->get(StoreOpc)), CfgSS)
18681ad6265SDimitry Andric         .addReg(Xmm);
18781ad6265SDimitry Andric     addFrameReference(BuildMI(MBB, MI, DL, TII->get(StoreOpc)), CfgSS, 16)
18881ad6265SDimitry Andric         .addReg(Xmm);
18981ad6265SDimitry Andric     addFrameReference(BuildMI(MBB, MI, DL, TII->get(StoreOpc)), CfgSS, 32)
19081ad6265SDimitry Andric         .addReg(Xmm);
19181ad6265SDimitry Andric     addFrameReference(BuildMI(MBB, MI, DL, TII->get(StoreOpc)), CfgSS, 48)
19281ad6265SDimitry Andric         .addReg(Xmm);
19381ad6265SDimitry Andric   }
19481ad6265SDimitry Andric   // Fill in the palette first.
19581ad6265SDimitry Andric   addFrameReference(BuildMI(MBB, MI, DL, TII->get(X86::MOV8mi)), CfgSS)
19681ad6265SDimitry Andric       .addImm(1);
19781ad6265SDimitry Andric }
19881ad6265SDimitry Andric 
19981ad6265SDimitry Andric /// Insert spill instruction for \p AssignedReg before \p Before.
20081ad6265SDimitry Andric /// TODO: Update DBG_VALUEs with \p VirtReg operands with the stack slot.
20181ad6265SDimitry Andric void X86FastPreTileConfig::spill(MachineBasicBlock::iterator Before,
20281ad6265SDimitry Andric                                  Register VirtReg, bool Kill) {
20381ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Spilling " << printReg(VirtReg, TRI) << " \n");
20481ad6265SDimitry Andric   int FI = getStackSpaceFor(VirtReg);
20581ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << " to stack slot #" << FI << '\n');
20681ad6265SDimitry Andric 
20781ad6265SDimitry Andric   const TargetRegisterClass &RC = *MRI->getRegClass(VirtReg);
20881ad6265SDimitry Andric   // Don't need shape information for tile store, becasue it is adjacent to
20981ad6265SDimitry Andric   // the tile def instruction.
210bdd1243dSDimitry Andric   TII->storeRegToStackSlot(*MBB, Before, VirtReg, Kill, FI, &RC, TRI,
211bdd1243dSDimitry Andric                            Register());
21281ad6265SDimitry Andric   ++NumStores;
21381ad6265SDimitry Andric 
21481ad6265SDimitry Andric   // TODO: update DBG_VALUEs
21581ad6265SDimitry Andric }
21681ad6265SDimitry Andric 
21781ad6265SDimitry Andric /// Insert reload instruction for \p PhysReg before \p Before.
21881ad6265SDimitry Andric void X86FastPreTileConfig::reload(MachineBasicBlock::iterator UseMI,
21981ad6265SDimitry Andric                                   Register OrigReg, MachineOperand *RowMO,
22081ad6265SDimitry Andric                                   MachineOperand *ColMO) {
22181ad6265SDimitry Andric   int FI = getStackSpaceFor(OrigReg);
22281ad6265SDimitry Andric   const TargetRegisterClass &RC = *MRI->getRegClass(OrigReg);
22381ad6265SDimitry Andric   Register TileReg;
22481ad6265SDimitry Andric   // Fold copy to tileload
22581ad6265SDimitry Andric   // BB1:
22681ad6265SDimitry Andric   // spill src to s
22781ad6265SDimitry Andric   //
22881ad6265SDimitry Andric   // BB2:
22981ad6265SDimitry Andric   // t = copy src
23081ad6265SDimitry Andric   // -->
23181ad6265SDimitry Andric   // t = tileload (s)
23281ad6265SDimitry Andric   if (UseMI->isCopy())
23381ad6265SDimitry Andric     TileReg = UseMI->getOperand(0).getReg();
23481ad6265SDimitry Andric   else
23581ad6265SDimitry Andric     TileReg = MRI->createVirtualRegister(&RC);
23681ad6265SDimitry Andric   // Can't use TII->loadRegFromStackSlot(), because we need the shape
23781ad6265SDimitry Andric   // information for reload.
23881ad6265SDimitry Andric   // tileloadd (%sp, %idx), %tmm
23981ad6265SDimitry Andric   unsigned Opc = X86::PTILELOADDV;
24081ad6265SDimitry Andric   Register StrideReg = MRI->createVirtualRegister(&X86::GR64_NOSPRegClass);
24181ad6265SDimitry Andric   // FIXME: MBB is not the parent of UseMI.
24281ad6265SDimitry Andric   MachineInstr *NewMI = BuildMI(*UseMI->getParent(), UseMI, DebugLoc(),
24381ad6265SDimitry Andric                                 TII->get(X86::MOV64ri), StrideReg)
24481ad6265SDimitry Andric                             .addImm(64);
24581ad6265SDimitry Andric   NewMI = addFrameReference(
24681ad6265SDimitry Andric       BuildMI(*UseMI->getParent(), UseMI, DebugLoc(), TII->get(Opc), TileReg)
24781ad6265SDimitry Andric           .addReg(RowMO->getReg())
24881ad6265SDimitry Andric           .addReg(ColMO->getReg()),
24981ad6265SDimitry Andric       FI);
25081ad6265SDimitry Andric   MachineOperand &MO = NewMI->getOperand(5);
25181ad6265SDimitry Andric   MO.setReg(StrideReg);
25281ad6265SDimitry Andric   MO.setIsKill(true);
25381ad6265SDimitry Andric   RowMO->setIsKill(false);
25481ad6265SDimitry Andric   ColMO->setIsKill(false);
25581ad6265SDimitry Andric   // Erase copy instruction after it is folded.
25681ad6265SDimitry Andric   if (UseMI->isCopy()) {
25781ad6265SDimitry Andric     UseMI->eraseFromParent();
25881ad6265SDimitry Andric   } else {
25981ad6265SDimitry Andric     // Replace the register in the user MI.
26081ad6265SDimitry Andric     for (auto &MO : UseMI->operands()) {
26181ad6265SDimitry Andric       if (MO.isReg() && MO.getReg() == OrigReg)
26281ad6265SDimitry Andric         MO.setReg(TileReg);
26381ad6265SDimitry Andric     }
26481ad6265SDimitry Andric   }
26581ad6265SDimitry Andric 
26681ad6265SDimitry Andric   ++NumLoads;
26781ad6265SDimitry Andric   LLVM_DEBUG(dbgs() << "Reloading " << printReg(OrigReg, TRI) << " into "
26881ad6265SDimitry Andric                     << printReg(TileReg, TRI) << '\n');
26981ad6265SDimitry Andric }
27081ad6265SDimitry Andric 
27181ad6265SDimitry Andric static bool isTileDef(MachineRegisterInfo *MRI, MachineInstr &MI) {
27281ad6265SDimitry Andric   // The instruction must have 3 operands: tile def, row, col.
27381ad6265SDimitry Andric   if (MI.isDebugInstr() || MI.getNumOperands() < 3 || !MI.isPseudo())
27481ad6265SDimitry Andric     return false;
27581ad6265SDimitry Andric   MachineOperand &MO = MI.getOperand(0);
27681ad6265SDimitry Andric 
27781ad6265SDimitry Andric   if (MO.isReg()) {
27881ad6265SDimitry Andric     Register Reg = MO.getReg();
27981ad6265SDimitry Andric     // FIXME it may be used after Greedy RA and the physical
28081ad6265SDimitry Andric     // register is not rewritten yet.
28181ad6265SDimitry Andric     if (Reg.isVirtual() &&
28281ad6265SDimitry Andric         MRI->getRegClass(Reg)->getID() == X86::TILERegClassID)
28381ad6265SDimitry Andric       return true;
28481ad6265SDimitry Andric     if (Reg >= X86::TMM0 && Reg <= X86::TMM7)
28581ad6265SDimitry Andric       return true;
28681ad6265SDimitry Andric   }
28781ad6265SDimitry Andric 
28881ad6265SDimitry Andric   return false;
28981ad6265SDimitry Andric }
29081ad6265SDimitry Andric 
29181ad6265SDimitry Andric static ShapeT getShape(MachineRegisterInfo *MRI, Register TileReg) {
29281ad6265SDimitry Andric   MachineInstr *MI = MRI->getVRegDef(TileReg);
29381ad6265SDimitry Andric   if (isTileDef(MRI, *MI)) {
29481ad6265SDimitry Andric     MachineOperand *RowMO = &MI->getOperand(1);
29581ad6265SDimitry Andric     MachineOperand *ColMO = &MI->getOperand(2);
29681ad6265SDimitry Andric     return ShapeT(RowMO, ColMO, MRI);
29781ad6265SDimitry Andric   } else if (MI->isCopy()) {
29881ad6265SDimitry Andric     TileReg = MI->getOperand(1).getReg();
29981ad6265SDimitry Andric     return getShape(MRI, TileReg);
30081ad6265SDimitry Andric   }
30181ad6265SDimitry Andric 
30281ad6265SDimitry Andric   // The def should not be PHI node, because we walk the MBB in reverse post
30381ad6265SDimitry Andric   // order.
30481ad6265SDimitry Andric   assert(MI->isPHI() && "Unexpected PHI when get shape.");
30581ad6265SDimitry Andric   llvm_unreachable("Unexpected MI when get shape.");
30681ad6265SDimitry Andric }
30781ad6265SDimitry Andric 
30881ad6265SDimitry Andric // BB0:
30981ad6265SDimitry Andric // spill t0 to s0
31081ad6265SDimitry Andric // BB1:
31181ad6265SDimitry Andric // spill t1 to s1
31281ad6265SDimitry Andric //
31381ad6265SDimitry Andric // BB2:
31481ad6265SDimitry Andric // t = phi [t0, bb0] [t1, bb1]
31581ad6265SDimitry Andric // -->
31681ad6265SDimitry Andric // row = phi [r0, bb0] [r1, bb1]
31781ad6265SDimitry Andric // col = phi [c0, bb0] [c1, bb1]
31881ad6265SDimitry Andric //   s = phi [s0, bb0] [s1, bb1]
31981ad6265SDimitry Andric //   t = tileload row, col, s
32081ad6265SDimitry Andric // The new instruction is inserted at the end of the phi node. The order
32181ad6265SDimitry Andric // of the original phi node is not ensured.
32281ad6265SDimitry Andric void X86FastPreTileConfig::convertPHI(MachineBasicBlock *MBB,
32381ad6265SDimitry Andric                                       MachineInstr &PHI) {
32481ad6265SDimitry Andric   // 1. Create instruction to get stack slot address of each incoming block.
32581ad6265SDimitry Andric   // 2. Create PHI node for the stack address.
32681ad6265SDimitry Andric   // 3. Create PHI node for shape. If one of the incoming shape is immediate
32781ad6265SDimitry Andric   //    use the immediate and delete the PHI node.
32881ad6265SDimitry Andric   // 4. Create tileload instruction from the stack address.
32981ad6265SDimitry Andric   Register StackAddrReg = MRI->createVirtualRegister(&X86::GR64_NOSPRegClass);
33081ad6265SDimitry Andric   MachineInstrBuilder AddrPHI = BuildMI(*MBB, ++PHI.getIterator(), DebugLoc(),
33181ad6265SDimitry Andric                                         TII->get(X86::PHI), StackAddrReg);
33281ad6265SDimitry Andric   Register RowReg = MRI->createVirtualRegister(&X86::GR16RegClass);
33381ad6265SDimitry Andric   MachineInstrBuilder RowPHI = BuildMI(*MBB, ++PHI.getIterator(), DebugLoc(),
33481ad6265SDimitry Andric                                        TII->get(X86::PHI), RowReg);
33581ad6265SDimitry Andric   Register ColReg = MRI->createVirtualRegister(&X86::GR16RegClass);
33681ad6265SDimitry Andric   MachineInstrBuilder ColPHI = BuildMI(*MBB, ++PHI.getIterator(), DebugLoc(),
33781ad6265SDimitry Andric                                        TII->get(X86::PHI), ColReg);
33881ad6265SDimitry Andric   // Record the mapping of phi node and its row/column information.
33981ad6265SDimitry Andric   VisitedPHIs[&PHI] = {RowReg, ColReg, StackAddrReg};
34081ad6265SDimitry Andric 
34181ad6265SDimitry Andric   for (unsigned I = 1, E = PHI.getNumOperands(); I != E; I += 2) {
34281ad6265SDimitry Andric     // Get the 2 incoming value of tile register and MBB.
34381ad6265SDimitry Andric     Register InTileReg = PHI.getOperand(I).getReg();
34481ad6265SDimitry Andric     // Mark it as liveout, so that it will be spilled when visit
34581ad6265SDimitry Andric     // the incoming MBB. Otherwise since phi will be deleted, it
34681ad6265SDimitry Andric     // would miss spill when visit incoming MBB.
34781ad6265SDimitry Andric     MayLiveAcrossBlocks.set(Register::virtReg2Index(InTileReg));
34881ad6265SDimitry Andric     MachineBasicBlock *InMBB = PHI.getOperand(I + 1).getMBB();
34981ad6265SDimitry Andric 
35081ad6265SDimitry Andric     MachineInstr *TileDefMI = MRI->getVRegDef(InTileReg);
35181ad6265SDimitry Andric     MachineBasicBlock::iterator InsertPos;
35281ad6265SDimitry Andric     if (TileDefMI->isPHI()) {
35381ad6265SDimitry Andric       InsertPos = TileDefMI->getParent()->getFirstNonPHI();
35481ad6265SDimitry Andric       if (VisitedPHIs.count(TileDefMI)) { // circular phi reference
35581ad6265SDimitry Andric         //        def t1
35681ad6265SDimitry Andric         //       /       \
35781ad6265SDimitry Andric         //  def t2       t3 = phi(t1, t4) <--
35881ad6265SDimitry Andric         //       \       /                  |
35981ad6265SDimitry Andric         //      t4 = phi(t2, t3)-------------
36081ad6265SDimitry Andric         //
36181ad6265SDimitry Andric         // For each (row, column and stack address) append phi incoming value.
36281ad6265SDimitry Andric         // Create r3 = phi(r1, r4)
36381ad6265SDimitry Andric         // Create r4 = phi(r2, r3)
36481ad6265SDimitry Andric         Register InRowReg = VisitedPHIs[TileDefMI].Row;
36581ad6265SDimitry Andric         Register InColReg = VisitedPHIs[TileDefMI].Col;
36681ad6265SDimitry Andric         Register InStackAddrReg = VisitedPHIs[TileDefMI].StackAddr;
36781ad6265SDimitry Andric         RowPHI.addReg(InRowReg).addMBB(InMBB);
36881ad6265SDimitry Andric         ColPHI.addReg(InColReg).addMBB(InMBB);
36981ad6265SDimitry Andric         AddrPHI.addReg(InStackAddrReg).addMBB(InMBB);
37081ad6265SDimitry Andric         continue;
37181ad6265SDimitry Andric       } else {
37281ad6265SDimitry Andric         // Recursively convert PHI to tileload
37381ad6265SDimitry Andric         convertPHI(TileDefMI->getParent(), *TileDefMI);
37481ad6265SDimitry Andric         // The PHI node is coverted to tileload instruction. Get the stack
37581ad6265SDimitry Andric         // address from tileload operands.
37681ad6265SDimitry Andric         MachineInstr *TileLoad = MRI->getVRegDef(InTileReg);
37781ad6265SDimitry Andric         assert(TileLoad && TileLoad->getOpcode() == X86::PTILELOADDV);
37881ad6265SDimitry Andric         Register InRowReg = TileLoad->getOperand(1).getReg();
37981ad6265SDimitry Andric         Register InColReg = TileLoad->getOperand(2).getReg();
38081ad6265SDimitry Andric         Register InStackAddrReg = TileLoad->getOperand(3).getReg();
38181ad6265SDimitry Andric         RowPHI.addReg(InRowReg).addMBB(InMBB);
38281ad6265SDimitry Andric         ColPHI.addReg(InColReg).addMBB(InMBB);
38381ad6265SDimitry Andric         AddrPHI.addReg(InStackAddrReg).addMBB(InMBB);
38481ad6265SDimitry Andric       }
38581ad6265SDimitry Andric     } else {
38681ad6265SDimitry Andric       InsertPos = TileDefMI->getIterator();
38781ad6265SDimitry Andric 
38881ad6265SDimitry Andric       // Fill the incoming operand of row/column phi instruction.
38981ad6265SDimitry Andric       ShapeT Shape = getShape(MRI, InTileReg);
39081ad6265SDimitry Andric       Shape.getRow()->setIsKill(false);
39181ad6265SDimitry Andric       Shape.getCol()->setIsKill(false);
39281ad6265SDimitry Andric       RowPHI.addReg(Shape.getRow()->getReg()).addMBB(InMBB);
39381ad6265SDimitry Andric       ColPHI.addReg(Shape.getCol()->getReg()).addMBB(InMBB);
39481ad6265SDimitry Andric 
39581ad6265SDimitry Andric       // The incoming tile register live out of its def BB, it would be spilled.
39681ad6265SDimitry Andric       // Create MI to get the spill stack slot address for the tile register
39781ad6265SDimitry Andric       int FI = getStackSpaceFor(InTileReg);
39881ad6265SDimitry Andric       Register InStackAddrReg =
39981ad6265SDimitry Andric           MRI->createVirtualRegister(&X86::GR64_NOSPRegClass);
40081ad6265SDimitry Andric       addOffset(BuildMI(*TileDefMI->getParent(), InsertPos, DebugLoc(),
40181ad6265SDimitry Andric                         TII->get(X86::LEA64r), InStackAddrReg)
40281ad6265SDimitry Andric                     .addFrameIndex(FI),
40381ad6265SDimitry Andric                 0);
40481ad6265SDimitry Andric       AddrPHI.addReg(InStackAddrReg).addMBB(InMBB);
40581ad6265SDimitry Andric     }
40681ad6265SDimitry Andric   }
40781ad6265SDimitry Andric 
40881ad6265SDimitry Andric   MachineBasicBlock::iterator InsertPos = MBB->getFirstNonPHI();
40981ad6265SDimitry Andric   Register StrideReg = MRI->createVirtualRegister(&X86::GR64_NOSPRegClass);
41081ad6265SDimitry Andric   BuildMI(*MBB, InsertPos, DebugLoc(), TII->get(X86::MOV64ri), StrideReg)
41181ad6265SDimitry Andric       .addImm(64);
41281ad6265SDimitry Andric   Register TileReg = PHI.getOperand(0).getReg();
41381ad6265SDimitry Andric   MachineInstr *NewMI = addDirectMem(
41481ad6265SDimitry Andric       BuildMI(*MBB, InsertPos, DebugLoc(), TII->get(X86::PTILELOADDV), TileReg)
41581ad6265SDimitry Andric           .addReg(RowReg)
41681ad6265SDimitry Andric           .addReg(ColReg),
41781ad6265SDimitry Andric       StackAddrReg);
41881ad6265SDimitry Andric   MachineOperand &MO = NewMI->getOperand(5);
41981ad6265SDimitry Andric   MO.setReg(StrideReg);
42081ad6265SDimitry Andric   MO.setIsKill(true);
42181ad6265SDimitry Andric   PHI.eraseFromParent();
42281ad6265SDimitry Andric   VisitedPHIs.erase(&PHI);
42381ad6265SDimitry Andric }
42481ad6265SDimitry Andric 
42581ad6265SDimitry Andric static bool isTileRegDef(MachineRegisterInfo *MRI, MachineInstr &MI) {
42681ad6265SDimitry Andric   MachineOperand &MO = MI.getOperand(0);
42781ad6265SDimitry Andric   if (MO.isReg() && MO.getReg().isVirtual() &&
42881ad6265SDimitry Andric       MRI->getRegClass(MO.getReg())->getID() == X86::TILERegClassID)
42981ad6265SDimitry Andric     return true;
43081ad6265SDimitry Andric   return false;
43181ad6265SDimitry Andric }
43281ad6265SDimitry Andric 
43381ad6265SDimitry Andric void X86FastPreTileConfig::canonicalizePHIs(MachineBasicBlock &MBB) {
43481ad6265SDimitry Andric   SmallVector<MachineInstr *, 8> PHIs;
43581ad6265SDimitry Andric 
43681ad6265SDimitry Andric   for (MachineInstr &MI : MBB) {
43781ad6265SDimitry Andric     if (!MI.isPHI())
43881ad6265SDimitry Andric       break;
43981ad6265SDimitry Andric     if (!isTileRegDef(MRI, MI))
44081ad6265SDimitry Andric       continue;
44181ad6265SDimitry Andric     PHIs.push_back(&MI);
44281ad6265SDimitry Andric   }
44381ad6265SDimitry Andric   // Canonicalize the phi node first. One tile phi may depeneds previous
44481ad6265SDimitry Andric   // phi node. For below case, we need convert %t4.
44581ad6265SDimitry Andric   //
44681ad6265SDimitry Andric   // BB0:
44781ad6265SDimitry Andric   // %t3 = phi (t1 BB1, t2 BB0)
44881ad6265SDimitry Andric   // %t4 = phi (t5 BB1, t3 BB0)
44981ad6265SDimitry Andric   // -->
45081ad6265SDimitry Andric   // %t3 = phi (t1 BB1, t2 BB0)
45181ad6265SDimitry Andric   // %t4 = phi (t5 BB1, t2 BB0)
45281ad6265SDimitry Andric   //
45381ad6265SDimitry Andric   while (!PHIs.empty()) {
45481ad6265SDimitry Andric     MachineInstr *PHI = PHIs.pop_back_val();
45581ad6265SDimitry Andric 
45681ad6265SDimitry Andric     // Find the operand that is incoming from the same MBB and the def
45781ad6265SDimitry Andric     // is also phi node.
45881ad6265SDimitry Andric     MachineOperand *InMO = nullptr;
45981ad6265SDimitry Andric     MachineInstr *DefMI = nullptr;
46081ad6265SDimitry Andric     for (unsigned I = 1, E = PHI->getNumOperands(); I != E; I += 2) {
46181ad6265SDimitry Andric       Register InTileReg = PHI->getOperand(I).getReg();
46281ad6265SDimitry Andric       MachineBasicBlock *InMBB = PHI->getOperand(I + 1).getMBB();
46381ad6265SDimitry Andric       DefMI = MRI->getVRegDef(InTileReg);
46481ad6265SDimitry Andric       if (InMBB != &MBB || !DefMI->isPHI())
46581ad6265SDimitry Andric         continue;
46681ad6265SDimitry Andric 
46781ad6265SDimitry Andric       InMO = &PHI->getOperand(I);
46881ad6265SDimitry Andric       break;
46981ad6265SDimitry Andric     }
47081ad6265SDimitry Andric     // If can't find such operand, do nothing.
47181ad6265SDimitry Andric     if (!InMO)
47281ad6265SDimitry Andric       continue;
47381ad6265SDimitry Andric 
47481ad6265SDimitry Andric     // Current phi node depends on previous phi node. Break the
47581ad6265SDimitry Andric     // dependency.
47681ad6265SDimitry Andric     Register DefTileReg;
47781ad6265SDimitry Andric     for (unsigned I = 1, E = DefMI->getNumOperands(); I != E; I += 2) {
47881ad6265SDimitry Andric       MachineBasicBlock *InMBB = PHI->getOperand(I + 1).getMBB();
47981ad6265SDimitry Andric       if (InMBB != &MBB)
48081ad6265SDimitry Andric         continue;
48181ad6265SDimitry Andric       DefTileReg = DefMI->getOperand(I).getReg();
48281ad6265SDimitry Andric       InMO->setReg(DefTileReg);
48381ad6265SDimitry Andric       break;
48481ad6265SDimitry Andric     }
48581ad6265SDimitry Andric   }
48681ad6265SDimitry Andric }
48781ad6265SDimitry Andric 
48881ad6265SDimitry Andric void X86FastPreTileConfig::convertPHIs(MachineBasicBlock &MBB) {
48981ad6265SDimitry Andric   SmallVector<MachineInstr *, 8> PHIs;
49081ad6265SDimitry Andric   for (MachineInstr &MI : MBB) {
49181ad6265SDimitry Andric     if (!MI.isPHI())
49281ad6265SDimitry Andric       break;
49381ad6265SDimitry Andric     if (!isTileRegDef(MRI, MI))
49481ad6265SDimitry Andric       continue;
49581ad6265SDimitry Andric     PHIs.push_back(&MI);
49681ad6265SDimitry Andric   }
49781ad6265SDimitry Andric   while (!PHIs.empty()) {
49881ad6265SDimitry Andric     MachineInstr *MI = PHIs.pop_back_val();
49981ad6265SDimitry Andric     VisitedPHIs.clear();
50081ad6265SDimitry Andric     convertPHI(&MBB, *MI);
50181ad6265SDimitry Andric   }
50281ad6265SDimitry Andric }
50381ad6265SDimitry Andric 
50481ad6265SDimitry Andric // PreTileConfig should configure the tile registers based on basic
50581ad6265SDimitry Andric // block.
50681ad6265SDimitry Andric bool X86FastPreTileConfig::configBasicBlock(MachineBasicBlock &MBB) {
50781ad6265SDimitry Andric   this->MBB = &MBB;
50881ad6265SDimitry Andric   bool Change = false;
50981ad6265SDimitry Andric   MachineInstr *LastShapeMI = nullptr;
51081ad6265SDimitry Andric   MachineInstr *LastTileCfg = nullptr;
51181ad6265SDimitry Andric   bool HasUnconfigTile = false;
51281ad6265SDimitry Andric 
51381ad6265SDimitry Andric   auto Config = [&](MachineInstr &Before) {
51481ad6265SDimitry Andric     if (CfgSS == -1)
51581ad6265SDimitry Andric       CfgSS = MFI->CreateStackObject(ST->getTileConfigSize(),
51681ad6265SDimitry Andric                                      ST->getTileConfigAlignment(), false);
51781ad6265SDimitry Andric     LastTileCfg = addFrameReference(
51881ad6265SDimitry Andric         BuildMI(MBB, Before, DebugLoc(), TII->get(X86::PLDTILECFGV)), CfgSS);
51981ad6265SDimitry Andric     LastShapeMI = nullptr;
52081ad6265SDimitry Andric     Change = true;
52181ad6265SDimitry Andric   };
52281ad6265SDimitry Andric   auto HasTileOperand = [](MachineRegisterInfo *MRI, MachineInstr &MI) {
52381ad6265SDimitry Andric     for (const MachineOperand &MO : MI.operands()) {
52481ad6265SDimitry Andric       if (!MO.isReg())
52581ad6265SDimitry Andric         continue;
52681ad6265SDimitry Andric       Register Reg = MO.getReg();
52781ad6265SDimitry Andric       if (Reg.isVirtual() &&
52881ad6265SDimitry Andric           MRI->getRegClass(Reg)->getID() == X86::TILERegClassID)
52981ad6265SDimitry Andric         return true;
53081ad6265SDimitry Andric     }
53181ad6265SDimitry Andric     return false;
53281ad6265SDimitry Andric   };
53381ad6265SDimitry Andric   for (MachineInstr &MI : reverse(MBB)) {
53481ad6265SDimitry Andric     // We have transformed phi node before configuring BB.
53581ad6265SDimitry Andric     if (MI.isPHI())
53681ad6265SDimitry Andric       break;
53781ad6265SDimitry Andric     // Don't collect the shape of used tile, the tile should be defined
53881ad6265SDimitry Andric     // before the tile use. Spill and reload would happen if there is only
53981ad6265SDimitry Andric     // tile use after ldtilecfg, so the shape can be collected from reload.
54081ad6265SDimitry Andric     // Take below code for example. %t would be reloaded before tilestore
54181ad6265SDimitry Andric     // call
54281ad6265SDimitry Andric     // ....
54381ad6265SDimitry Andric     // tilestore %r, %c, %t
54481ad6265SDimitry Andric     // -->
54581ad6265SDimitry Andric     // call
54681ad6265SDimitry Andric     // ldtilecfg
54781ad6265SDimitry Andric     // %t = tileload %r, %c
54881ad6265SDimitry Andric     // tilestore %r, %c, %t
54981ad6265SDimitry Andric     if (HasTileOperand(MRI, MI))
55081ad6265SDimitry Andric       HasUnconfigTile = true;
55181ad6265SDimitry Andric     // According to AMX ABI, all the tile registers including config register
55281ad6265SDimitry Andric     // are volatile. Caller need to save/restore config register.
55381ad6265SDimitry Andric     if (MI.isCall() && HasUnconfigTile) {
55481ad6265SDimitry Andric       MachineBasicBlock::iterator I;
55581ad6265SDimitry Andric       if (LastShapeMI && dominates(MBB, MI, LastShapeMI))
55681ad6265SDimitry Andric         I = ++LastShapeMI->getIterator();
55781ad6265SDimitry Andric       else
55881ad6265SDimitry Andric         I = ++MI.getIterator();
55981ad6265SDimitry Andric       Config(*I);
56081ad6265SDimitry Andric       HasUnconfigTile = false;
56181ad6265SDimitry Andric       continue;
56281ad6265SDimitry Andric     }
56381ad6265SDimitry Andric     if (!isTileDef(MRI, MI))
56481ad6265SDimitry Andric       continue;
56581ad6265SDimitry Andric     //
56681ad6265SDimitry Andric     //---------------------------------------------------------------------
56781ad6265SDimitry Andric     // Don't handle COPY instruction. If the src and dst of the COPY can be
56881ad6265SDimitry Andric     // in the same config in below case, we just check the shape of t0.
56981ad6265SDimitry Andric     // def row0
57081ad6265SDimitry Andric     // def col0
57181ad6265SDimitry Andric     // ldtilecfg
57281ad6265SDimitry Andric     // t0 = tielzero(row0, col0)
57381ad6265SDimitry Andric     // t1 = copy t0
57481ad6265SDimitry Andric     // ...
57581ad6265SDimitry Andric     // If the src and dst of the COPY can NOT be in the same config in below
57681ad6265SDimitry Andric     // case. Reload would be generated befor the copy instruction.
57781ad6265SDimitry Andric     // def row0
57881ad6265SDimitry Andric     // def col0
57981ad6265SDimitry Andric     // t0 = tielzero(row0, col0)
58081ad6265SDimitry Andric     // spill t0
58181ad6265SDimitry Andric     // ...
58281ad6265SDimitry Andric     // def row1
58381ad6265SDimitry Andric     // def col1
58481ad6265SDimitry Andric     // ldtilecfg
58581ad6265SDimitry Andric     // t1 = tilezero(row1, col1)
58681ad6265SDimitry Andric     // reload t0
58781ad6265SDimitry Andric     // t1 = copy t0
58881ad6265SDimitry Andric     //---------------------------------------------------------------------
58981ad6265SDimitry Andric     //
59081ad6265SDimitry Andric     // If MI dominate the last shape def instruction, we need insert
59181ad6265SDimitry Andric     // ldtilecfg after LastShapeMI now. The config doesn't include
59281ad6265SDimitry Andric     // current MI.
59381ad6265SDimitry Andric     //   def row0
59481ad6265SDimitry Andric     //   def col0
59581ad6265SDimitry Andric     //   tilezero(row0, col0)  <- MI
59681ad6265SDimitry Andric     //   def row1
59781ad6265SDimitry Andric     //   def col1
59881ad6265SDimitry Andric     //   ldtilecfg             <- insert
59981ad6265SDimitry Andric     //   tilezero(row1, col1)
60081ad6265SDimitry Andric     if (LastShapeMI && dominates(MBB, MI, LastShapeMI))
60181ad6265SDimitry Andric       Config(*(++LastShapeMI->getIterator()));
60281ad6265SDimitry Andric     MachineOperand *RowMO = &MI.getOperand(1);
60381ad6265SDimitry Andric     MachineOperand *ColMO = &MI.getOperand(2);
60481ad6265SDimitry Andric     MachineInstr *RowMI = MRI->getVRegDef(RowMO->getReg());
60581ad6265SDimitry Andric     MachineInstr *ColMI = MRI->getVRegDef(ColMO->getReg());
60681ad6265SDimitry Andric     // If the shape is defined in current MBB, check the domination.
60781ad6265SDimitry Andric     // FIXME how about loop?
60881ad6265SDimitry Andric     if (RowMI->getParent() == &MBB) {
60981ad6265SDimitry Andric       if (!LastShapeMI)
61081ad6265SDimitry Andric         LastShapeMI = RowMI;
61181ad6265SDimitry Andric       else if (dominates(MBB, LastShapeMI, RowMI))
61281ad6265SDimitry Andric         LastShapeMI = RowMI;
61381ad6265SDimitry Andric     }
61481ad6265SDimitry Andric     if (ColMI->getParent() == &MBB) {
61581ad6265SDimitry Andric       if (!LastShapeMI)
61681ad6265SDimitry Andric         LastShapeMI = ColMI;
61781ad6265SDimitry Andric       else if (dominates(MBB, LastShapeMI, ColMI))
61881ad6265SDimitry Andric         LastShapeMI = ColMI;
61981ad6265SDimitry Andric     }
62081ad6265SDimitry Andric     // If there is user live out of the tilecfg, spill it and reload in
62181ad6265SDimitry Andric     // before the user.
62281ad6265SDimitry Andric     Register TileReg = MI.getOperand(0).getReg();
62381ad6265SDimitry Andric     if (mayLiveOut(TileReg, LastTileCfg))
62481ad6265SDimitry Andric       spill(++MI.getIterator(), TileReg, false);
62581ad6265SDimitry Andric     for (MachineInstr &UseMI : MRI->use_instructions(TileReg)) {
62681ad6265SDimitry Andric       if (UseMI.getParent() == &MBB) {
62781ad6265SDimitry Andric         // check user should not across ldtilecfg
62881ad6265SDimitry Andric         if (!LastTileCfg || !dominates(MBB, LastTileCfg, UseMI))
62981ad6265SDimitry Andric           continue;
63081ad6265SDimitry Andric         // reload befor UseMI
63181ad6265SDimitry Andric         reload(UseMI.getIterator(), TileReg, RowMO, ColMO);
63281ad6265SDimitry Andric       } else {
63381ad6265SDimitry Andric         // Don't reload for phi instruction, we handle phi reload separately.
63481ad6265SDimitry Andric         // TODO: merge the reload for the same user MBB.
63581ad6265SDimitry Andric         if (!UseMI.isPHI())
63681ad6265SDimitry Andric           reload(UseMI.getIterator(), TileReg, RowMO, ColMO);
63781ad6265SDimitry Andric       }
63881ad6265SDimitry Andric     }
63981ad6265SDimitry Andric   }
64081ad6265SDimitry Andric 
64181ad6265SDimitry Andric   // Configure tile registers at the head of the MBB
64281ad6265SDimitry Andric   if (HasUnconfigTile) {
64381ad6265SDimitry Andric     MachineInstr *Before;
64481ad6265SDimitry Andric     if (LastShapeMI == nullptr || LastShapeMI->isPHI())
64581ad6265SDimitry Andric       Before = &*MBB.getFirstNonPHI();
64681ad6265SDimitry Andric     else
64781ad6265SDimitry Andric       Before = &*(++LastShapeMI->getIterator());
64881ad6265SDimitry Andric 
64981ad6265SDimitry Andric     Config(*Before);
65081ad6265SDimitry Andric   }
65181ad6265SDimitry Andric 
65281ad6265SDimitry Andric   return Change;
65381ad6265SDimitry Andric }
65481ad6265SDimitry Andric 
65581ad6265SDimitry Andric bool X86FastPreTileConfig::runOnMachineFunction(MachineFunction &MFunc) {
656*0fca6ea1SDimitry Andric   X86FI = MFunc.getInfo<X86MachineFunctionInfo>();
657*0fca6ea1SDimitry Andric   // Early exit in the common case of non-AMX code.
658*0fca6ea1SDimitry Andric   if (X86FI->getAMXProgModel() != AMXProgModelEnum::ManagedRA)
659*0fca6ea1SDimitry Andric     return false;
660*0fca6ea1SDimitry Andric 
66181ad6265SDimitry Andric   MF = &MFunc;
66281ad6265SDimitry Andric   MRI = &MFunc.getRegInfo();
66381ad6265SDimitry Andric   ST = &MFunc.getSubtarget<X86Subtarget>();
66481ad6265SDimitry Andric   TII = ST->getInstrInfo();
66581ad6265SDimitry Andric   MFI = &MFunc.getFrameInfo();
66681ad6265SDimitry Andric   TRI = ST->getRegisterInfo();
66781ad6265SDimitry Andric   CfgSS = -1;
66881ad6265SDimitry Andric 
66981ad6265SDimitry Andric   unsigned NumVirtRegs = MRI->getNumVirtRegs();
67081ad6265SDimitry Andric 
67181ad6265SDimitry Andric   StackSlotForVirtReg.resize(NumVirtRegs);
67281ad6265SDimitry Andric   MayLiveAcrossBlocks.clear();
67381ad6265SDimitry Andric   // We will create register during config. *3 is to make sure
67481ad6265SDimitry Andric   // the virtual register number doesn't exceed the size of
67581ad6265SDimitry Andric   // the bit vector.
67681ad6265SDimitry Andric   MayLiveAcrossBlocks.resize(NumVirtRegs * 3);
67781ad6265SDimitry Andric   bool Change = false;
67881ad6265SDimitry Andric   assert(MRI->isSSA());
67981ad6265SDimitry Andric 
68081ad6265SDimitry Andric   // Canonicalize the phi node first.
68181ad6265SDimitry Andric   for (MachineBasicBlock &MBB : MFunc)
68281ad6265SDimitry Andric     canonicalizePHIs(MBB);
68381ad6265SDimitry Andric 
68481ad6265SDimitry Andric   // Loop over all of the basic blocks in reverse post order and insert
68581ad6265SDimitry Andric   // ldtilecfg for tile registers. The reserse post order is to facilitate
68681ad6265SDimitry Andric   // PHI node convert.
68781ad6265SDimitry Andric   ReversePostOrderTraversal<MachineFunction *> RPOT(MF);
68881ad6265SDimitry Andric   for (MachineBasicBlock *MBB : RPOT) {
68981ad6265SDimitry Andric     convertPHIs(*MBB);
69081ad6265SDimitry Andric     Change |= configBasicBlock(*MBB);
69181ad6265SDimitry Andric   }
69281ad6265SDimitry Andric 
69381ad6265SDimitry Andric   if (Change)
69481ad6265SDimitry Andric     InitializeTileConfigStackSpace();
69581ad6265SDimitry Andric 
69681ad6265SDimitry Andric   StackSlotForVirtReg.clear();
69781ad6265SDimitry Andric   return Change;
69881ad6265SDimitry Andric }
69981ad6265SDimitry Andric 
70081ad6265SDimitry Andric FunctionPass *llvm::createX86FastPreTileConfigPass() {
70181ad6265SDimitry Andric   return new X86FastPreTileConfig();
70281ad6265SDimitry Andric }
703