| //===-- X86FastTileConfig.cpp - Fast Tile Register Configure---------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| /// \file Pass to config the shape of AMX physical registers | |
| /// AMX register need to be configured before use. Before FastRegAllocation pass | |
| /// the ldtilecfg instruction is inserted, however at that time we don't | |
| /// know the shape of each physical tile registers, because the register | |
| /// allocation is not done yet. This pass runs after register allocation | |
| /// pass. It collects the shape information of each physical tile register | |
| /// and store the shape in the stack slot that is allocated for load config | |
| /// to tile config register. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "X86.h" | |
| #include "X86InstrBuilder.h" | |
| #include "X86MachineFunctionInfo.h" | |
| #include "X86RegisterInfo.h" | |
| #include "X86Subtarget.h" | |
| #include "llvm/CodeGen/MachineFrameInfo.h" | |
| #include "llvm/CodeGen/MachineFunctionPass.h" | |
| #include "llvm/CodeGen/MachineInstr.h" | |
| #include "llvm/CodeGen/MachineRegisterInfo.h" | |
| #include "llvm/CodeGen/Passes.h" | |
| #include "llvm/CodeGen/TargetInstrInfo.h" | |
| #include "llvm/CodeGen/TargetRegisterInfo.h" | |
| #include "llvm/InitializePasses.h" | |
| using namespace llvm; | |
| #define DEBUG_TYPE "fasttileconfig" | |
| namespace { | |
| class X86FastTileConfig : public MachineFunctionPass { | |
| // context | |
| MachineFunction *MF = nullptr; | |
| const TargetInstrInfo *TII = nullptr; | |
| MachineRegisterInfo *MRI = nullptr; | |
| const TargetRegisterInfo *TRI = nullptr; | |
| X86MachineFunctionInfo *X86FI = nullptr; | |
| bool configBasicBlock(MachineBasicBlock &MBB); | |
| public: | |
| X86FastTileConfig() : MachineFunctionPass(ID) {} | |
| /// Return the pass name. | |
| StringRef getPassName() const override { | |
| return "Fast Tile Register Configure"; | |
| } | |
| void getAnalysisUsage(AnalysisUsage &AU) const override { | |
| AU.setPreservesAll(); | |
| MachineFunctionPass::getAnalysisUsage(AU); | |
| } | |
| /// Perform register allocation. | |
| bool runOnMachineFunction(MachineFunction &MFunc) override; | |
| MachineFunctionProperties getRequiredProperties() const override { | |
| return MachineFunctionProperties().set( | |
| MachineFunctionProperties::Property::NoPHIs); | |
| } | |
| static char ID; | |
| }; | |
| } // end anonymous namespace | |
| char X86FastTileConfig::ID = 0; | |
| INITIALIZE_PASS_BEGIN(X86FastTileConfig, DEBUG_TYPE, | |
| "Fast Tile Register Configure", false, false) | |
| INITIALIZE_PASS_END(X86FastTileConfig, DEBUG_TYPE, | |
| "Fast Tile Register Configure", false, false) | |
| static bool isTileDef(MachineRegisterInfo *MRI, MachineInstr &MI) { | |
| // There is no phi instruction after register allocation. | |
| assert(MI.isPHI() == false); | |
| // The instruction must have 3 operands: tile def, row, col. | |
| // It should be AMX pseudo instruction that have shape operand. | |
| if (MI.isDebugInstr() || MI.isCopy() || MI.getNumOperands() < 3 || | |
| !MI.isPseudo()) | |
| return false; | |
| MachineOperand &MO = MI.getOperand(0); | |
| if (MO.isReg()) { | |
| Register Reg = MO.getReg(); | |
| // FIXME it may be used after Greedy RA and the physical | |
| // register is not rewritten yet. | |
| if (Reg.isVirtual() && | |
| MRI->getRegClass(Reg)->getID() == X86::TILERegClassID) | |
| return true; | |
| if (Reg >= X86::TMM0 && Reg <= X86::TMM7) | |
| return true; | |
| } | |
| return false; | |
| } | |
| // PreTileConfig should configure the tile registers based on basic | |
| // block. | |
| bool X86FastTileConfig::configBasicBlock(MachineBasicBlock &MBB) { | |
| bool Change = false; | |
| SmallVector<std::pair<unsigned, ShapeT>, 6> ShapeInfos; | |
| for (MachineInstr &MI : reverse(MBB)) { | |
| if (!isTileDef(MRI, MI) && MI.getOpcode() != X86::PLDTILECFGV) | |
| continue; | |
| // AMX instructions that define tile register. | |
| if (MI.getOpcode() != X86::PLDTILECFGV) { | |
| MachineOperand &Row = MI.getOperand(1); | |
| MachineOperand &Col = MI.getOperand(2); | |
| unsigned TMMIdx = MI.getOperand(0).getReg() - X86::TMM0; | |
| ShapeInfos.push_back({TMMIdx, ShapeT(&Row, &Col)}); | |
| } else { // PLDTILECFGV | |
| // Rewrite the shape information to memory. Stack slot should have | |
| // been initialized to zero in pre config. | |
| int SS = MI.getOperand(0).getIndex(); // tile config stack slot. | |
| for (auto &ShapeInfo : ShapeInfos) { | |
| DebugLoc DL; | |
| unsigned TMMIdx = ShapeInfo.first; | |
| Register RowReg = ShapeInfo.second.getRow()->getReg(); | |
| Register ColReg = ShapeInfo.second.getCol()->getReg(); | |
| // Here is the data format for the tile config. | |
| // 0 palette | |
| // 1 start_row | |
| // 2-15 reserved, must be zero | |
| // 16-17 tile0.colsb Tile 0 bytes per row. | |
| // 18-19 tile1.colsb Tile 1 bytes per row. | |
| // 20-21 tile2.colsb Tile 2 bytes per row. | |
| // ... (sequence continues) | |
| // 30-31 tile7.colsb Tile 7 bytes per row. | |
| // 32-47 reserved, must be zero | |
| // 48 tile0.rows Tile 0 rows. | |
| // 49 tile1.rows Tile 1 rows. | |
| // 50 tile2.rows Tile 2 rows. | |
| // ... (sequence continues) | |
| // 55 tile7.rows Tile 7 rows. | |
| // 56-63 reserved, must be zero | |
| int RowOffset = 48 + TMMIdx; | |
| int ColOffset = 16 + TMMIdx * 2; | |
| Register SubRowReg = TRI->getSubReg(RowReg, X86::sub_8bit); | |
| BuildMI(MBB, MI, DL, TII->get(X86::IMPLICIT_DEF), SubRowReg); | |
| MachineInstrBuilder StoreRow = | |
| BuildMI(MBB, MI, DL, TII->get(X86::MOV8mr)); | |
| addFrameReference(StoreRow, SS, RowOffset).addReg(SubRowReg); | |
| MachineInstrBuilder StoreCol = | |
| BuildMI(MBB, MI, DL, TII->get(X86::MOV16mr)); | |
| addFrameReference(StoreCol, SS, ColOffset).addReg(ColReg); | |
| } | |
| ShapeInfos.clear(); | |
| Change = true; | |
| } | |
| } | |
| if (Change) | |
| X86FI->setHasVirtualTileReg(true); | |
| return Change; | |
| } | |
| bool X86FastTileConfig::runOnMachineFunction(MachineFunction &MFunc) { | |
| MF = &MFunc; | |
| MRI = &MFunc.getRegInfo(); | |
| const TargetSubtargetInfo *ST = &MFunc.getSubtarget<X86Subtarget>(); | |
| TRI = ST->getRegisterInfo(); | |
| TII = MFunc.getSubtarget().getInstrInfo(); | |
| X86FI = MFunc.getInfo<X86MachineFunctionInfo>(); | |
| bool Change = false; | |
| // Loop over all of the basic blocks, eliminating virtual register references | |
| for (MachineBasicBlock &MBB : MFunc) | |
| Change |= configBasicBlock(MBB); | |
| return Change; | |
| } | |
| FunctionPass *llvm::createX86FastTileConfigPass() { | |
| return new X86FastTileConfig(); | |
| } |