blob: 2a20cd13791deb517031d1e1f554cb092c7b6483 [file] [log] [blame]
//===-- 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();
}