1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
|
/*========================== begin_copyright_notice ============================
Copyright (C) 2025 Intel Corporation
SPDX-License-Identifier: MIT
============================= end_copyright_notice ===========================*/
#pragma once
#include "Compiler/CISACodeGen/IGCLivenessAnalysis.h"
#include "Compiler/CodeGenPublic.h"
#include "GenISAIntrinsics/GenIntrinsicInst.h"
#include "common/LLVMWarningsPush.hpp"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Instruction.h"
#include "llvm/IR/Value.h"
#include "llvm/Pass.h"
#include "common/LLVMWarningsPop.hpp"
#include <memory>
#include <set>
#include <utility>
namespace llvm {
class FunctionPass;
}
namespace IGC {
namespace LS {
/// A `struct` containing two dimensions of a block.
struct Dims {
unsigned grSize, numOfGr;
unsigned size() const { return grSize * numOfGr; }
bool operator<(const Dims &rhs) const {
return grSize < rhs.grSize || (grSize == rhs.grSize && numOfGr < rhs.numOfGr);
}
};
using PossibleDims = std::set<Dims>;
struct Config {
Module *M = nullptr; // for debug info
CodeGenContext *CGC = nullptr;
IGCLivenessAnalysis *RPE = nullptr;
bool isLegitW8 = false;
unsigned sizeOfRegs_B = 0;
unsigned numOfRegs = 0;
unsigned defaultSimd = 0;
unsigned actualSimd = 0;
/// Turns on the splitting pass.
bool enableLoadSplitting = IGC_IS_FLAG_ENABLED(LS_enableLoadSplitting);
/// If `true`, the register pressure data is ignored and the pass splits all
/// loads.
bool ignoreSplitThreshold = IGC_IS_FLAG_ENABLED(LS_ignoreSplitThreshold);
/// Minimal split size in terms of GRFs, used in determination of the possible
/// split dimensions.
unsigned minSplitSize_GRF = IGC_GET_FLAG_VALUE(LS_minSplitSize_GRF);
/// Minimal split size in terms of vector elements (bit width-independent),
/// used in determination of the possible split dimensions.
unsigned minSplitSize_E = IGC_GET_FLAG_VALUE(LS_minSplitSize_E);
/// If `ignoreSplitThreshold = false`, the pass splits loads in a given basic
/// block only if the maximal register pressure exceeds total GRFs by this
/// much.
int splitThresholdDelta_GRF = IGC_GET_FLAG_VALUE(LS_splitThresholdDelta_GRF);
/// Minimal split size in bytes, to be calculated from minSplitSize_GRF.
unsigned minSplitSize_B = 0;
/// Absolute split threshold in bytes.
int splitThreshold_B = 0;
Config(const Config &) = delete;
Config(Config &&) = delete;
/// Value of `SIMD` as reported by metadata.
unsigned SIMD() const { return actualSimd ? actualSimd : defaultSimd; }
static Config &get() {
static Config config;
return config;
}
bool initialize(Function *inF, CodeGenContext *inCGC, IGCLivenessAnalysis *inRPE);
private:
Config() = default;
};
Config &config();
/// The class `LoadSplitter` is responsible for splitting loads in an LLVM
/// function.
class LoadSplitter {
public:
/// @brief Factory function to create an instance of `LoadSplitter`.
/// @param inF LLVM function pointer.
/// @param inCGC The code generation context.
/// @param inRPE The register pressure estimator.
static std::unique_ptr<LoadSplitter> Create(Function *inF, CodeGenContext *inCGC, IGCLivenessAnalysis *inRPE);
LoadSplitter(const LoadSplitter &) = delete;
LoadSplitter &operator=(const LoadSplitter &) = delete;
/// @brief Returns `true` is the register pressure for the basic block exceeds
/// the threshold given by the flag IGS_LS_splitThresholdDelta_GRF. The
/// pressure must also exceed the goal, IGC_LS_goalPressureDelta_GRF.
/// @param BB The basic block to check.
bool isRPHigh(BasicBlock *BB);
/// @brief Returns the set of all possible dimensions in which the load or AP
/// loads can be split into.
/// @param GII The load or the address payload to split. If `GII` is an AP
/// Load, all loads associated with its AP are considered.
PossibleDims possibleDims(GenIntrinsicInst *GII);
/// @brief Splits the block load into the specified dimensions.
/// @param GII The load or the address payload to split. If `GII` is an AP
/// Load, all loads associated with its AP are considered.
/// @param dims Size of the new blocks.
/// @return Returns `true` on success, `false` otherwise.
bool split(GenIntrinsicInst *GII, Dims dims);
/// @brief Splits all loads in the basic block to the smallest size possible.
/// @param BB The basic block.
/// @return Returns `true` on success, `false` otherwise.
bool splitAllToSmallest(BasicBlock *BB);
private:
LoadSplitter() = default;
struct Impl;
std::unique_ptr<Impl> impl;
};
} // namespace LS
FunctionPass *createSplitLoadsPass();
} // namespace IGC
|