File: SplitLoads.h

package info (click to toggle)
intel-graphics-compiler2 2.16.0-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 106,644 kB
  • sloc: cpp: 805,640; lisp: 287,672; ansic: 16,414; python: 3,952; yacc: 2,588; lex: 1,666; pascal: 313; sh: 186; makefile: 35
file content (150 lines) | stat: -rw-r--r-- 4,770 bytes parent folder | download
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